summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buildrun.cxx1
-rw-r--r--coveragedb.h11
-rw-r--r--dwflpp.cxx46
-rw-r--r--dwflpp.h2
-rw-r--r--elaborate.cxx24
-rw-r--r--includes/sys/sdt.h16
-rw-r--r--parse.cxx223
-rw-r--r--parse.h15
-rw-r--r--runtime/autoconf-ring_buffer-flags.c6
-rw-r--r--runtime/transport/ring_buffer.c136
-rw-r--r--tapset/signal.stp54
-rw-r--r--tapsets.cxx2
-rwxr-xr-xtestsuite/buildok/fortysix.stp3
-rw-r--r--testsuite/lib/systemtap.exp11
-rw-r--r--testsuite/systemtap.examples/index.html3
-rw-r--r--testsuite/systemtap.examples/index.txt11
-rw-r--r--testsuite/systemtap.examples/keyword-index.html11
-rw-r--r--testsuite/systemtap.examples/keyword-index.txt24
-rw-r--r--testsuite/systemtap.examples/memory/numa_faults.meta13
-rwxr-xr-xtestsuite/systemtap.examples/memory/numa_faults.stp38
20 files changed, 403 insertions, 247 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index effc6cd8..d24a2be4 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -171,6 +171,7 @@ compile_pass (systemtap_session& s)
"STAPCONF_KERNEL_STACKTRACE", NULL);
output_autoconf(s, o, "autoconf-asm-syscall.c",
"STAPCONF_ASM_SYSCALL_H", NULL);
+ output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL);
o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
diff --git a/coveragedb.h b/coveragedb.h
index 3675e3b4..f0f071c4 100644
--- a/coveragedb.h
+++ b/coveragedb.h
@@ -10,6 +10,7 @@
#define COVERAGEDB_H
#include "session.h"
+#include "staptree.h"
#include <string>
@@ -62,12 +63,12 @@ public:
int compiled;
int executed;
- coverage_element() { line = 0; col = 0;
- compiled = 0; executed = 0; }
+ coverage_element():
+ line(0), col(0), compiled(0), executed(0) {}
- coverage_element(source_loc &place) {
- file = place.file; line = place.line; col = place.column;
- compiled = 0; executed = 0; }
+ coverage_element(source_loc &place):
+ file(place.file->name), line(place.line), col(place.column),
+ compiled(0), executed(0) {}
};
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 17bce608..8fa31c6a 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -205,7 +205,7 @@ dwflpp::module_name_matches(const string& pattern)
bool
-dwflpp::name_has_wildcard(const string& pattern)
+dwflpp::name_has_wildcard (const string& pattern)
{
return (pattern.find('*') != string::npos ||
pattern.find('?') != string::npos ||
@@ -258,19 +258,34 @@ static int dwfl_report_offline_predicate (const char* modname, const char* filen
if (pending_interrupts)
return -1;
- if (offline_search_match_p)
- return -1;
-
assert (offline_search_modname);
- /* Reject mismatching module names */
- if (strcmp(modname, offline_search_modname))
+ // elfutils sends us NULL filenames sometimes if it can't find dwarf
+ if (filename == NULL)
return 0;
- else
- {
+
+ if (dwflpp::name_has_wildcard (offline_search_modname)) {
+ int match_p = !fnmatch(offline_search_modname, modname, 0);
+ // In the wildcard case, we don't short-circuit (return -1) upon
+ // offline_search_match_p, analogously to dwflpp::module_name_final_match().
+
+ if (match_p)
offline_search_match_p ++;
- return 1;
- }
+
+ return match_p;
+ } else { /* non-wildcard mode */
+ if (offline_search_match_p)
+ return -1;
+
+ /* Reject mismatching module names */
+ if (strcmp(modname, offline_search_modname))
+ return 0;
+ else
+ {
+ offline_search_match_p ++;
+ return 1;
+ }
+ }
}
@@ -339,17 +354,6 @@ dwflpp::setup_kernel(const string& name, bool debuginfo_needed)
sess.kernel_build_tree + string("'"));
}
- // XXX: it would be nice if we could do a single
- // ..._report_offline call for an entire systemtap script, so
- // that a selection predicate would filter out modules outside
- // the union of all the requested wildcards. But we build
- // derived_probes one-by-one and we don't have lookahead.
- // PR 3498.
-
- // XXX: a special case: if we have only kernel.* probe points,
- // we shouldn't waste time looking for module debug-info (and
- // vice versa).
-
// NB: the result of an _offline call is the assignment of
// virtualized addresses to relocatable objects such as
// modules. These have to be converted to real addresses at
diff --git a/dwflpp.h b/dwflpp.h
index d6d97cd0..e0098b9b 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -178,7 +178,7 @@ struct dwflpp
Dwarf_Die *query_cu_containing_address(Dwarf_Addr a);
bool module_name_matches(const std::string& pattern);
- bool name_has_wildcard(const std::string& pattern);
+ static bool name_has_wildcard(const std::string& pattern);
bool module_name_final_match(const std::string& pattern);
bool function_name_matches_pattern(const std::string& name, const std::string& pattern);
diff --git a/elaborate.cxx b/elaborate.cxx
index e7ea7b23..88c5deb9 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1512,9 +1512,9 @@ systemtap_session::print_token (ostream& o, const token* tok)
tmpo << *tok;
string ts = tmpo.str();
// search & replace the file name with nothing
- size_t idx = ts.find (tok->location.file);
+ size_t idx = ts.find (tok->location.file->name);
if (idx != string::npos)
- ts.replace (idx, tok->location.file.size(), "");
+ ts.replace (idx, tok->location.file->name.size(), "");
o << ts;
}
@@ -1581,16 +1581,16 @@ systemtap_session::print_error_source (std::ostream& message,
std::string& align, const token* tok)
{
unsigned i = 0;
- unsigned line = tok->location.line;
- unsigned col = tok->location.column;
- string file_contents;
assert (tok);
- if (tok->location.stap_file)
- file_contents = tok->location.stap_file->file_contents;
- else
+ if (!tok->location.file)
//No source to print, silently exit
return;
+
+ unsigned line = tok->location.line;
+ unsigned col = tok->location.column;
+ const string &file_contents = tok->location.file->file_contents;
+
size_t start_pos = 0, end_pos = 0;
//Navigate to the appropriate line
while (i != line && end_pos != std::string::npos)
@@ -1958,7 +1958,7 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
functiondecl* fd = it->second;
if (ftv.traversed.find(fd) == ftv.traversed.end())
{
- if (fd->tok->location.file == s.user_file->name && // !tapset
+ if (fd->tok->location.file->name == s.user_file->name && // !tapset
! s.suppress_warnings)
s.print_warning ("eliding unused function '" + fd->name + "'", fd->tok);
else if (s.verbose>2)
@@ -2014,7 +2014,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati
if (vut.read.find (l) == vut.read.end() &&
vut.written.find (l) == vut.written.end())
{
- if (l->tok->location.file == s.user_file->name && // !tapset
+ if (l->tok->location.file->name == s.user_file->name && // !tapset
! s.suppress_warnings)
s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
@@ -2058,7 +2058,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati
if (vut.read.find (l) == vut.read.end() &&
vut.written.find (l) == vut.written.end())
{
- if (l->tok->location.file == s.user_file->name && // !tapset
+ if (l->tok->location.file->name == s.user_file->name && // !tapset
! s.suppress_warnings)
s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
@@ -2104,7 +2104,7 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p, unsigned iterati
if (vut.read.find (l) == vut.read.end() &&
vut.written.find (l) == vut.written.end())
{
- if (l->tok->location.file == s.user_file->name && // !tapset
+ if (l->tok->location.file->name == s.user_file->name && // !tapset
! s.suppress_warnings)
s.print_warning ("eliding unused variable '" + l->name + "'", l->tok);
else if (s.verbose>2)
diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h
index 07ece7c1..3b788b88 100644
--- a/includes/sys/sdt.h
+++ b/includes/sys/sdt.h
@@ -1,10 +1,6 @@
/* Copyright (C) 2005-2009 Red Hat Inc.
- Copyright (C) 2006 Intel Corporation.
- This file is part of systemtap, and is free software. You can
- redistribute it and/or modify it under the terms of the GNU General
- Public License (GPL); either version 2, or (at your option) any
- later version.
+ This file is part of systemtap, and is free software in the public domain.
*/
#ifndef _SYS_SDT_H
@@ -21,9 +17,17 @@
#define STAP_PROBE_ADDR "\t.long "
#endif
+/* Allocated section needs to be writable when creating pic shared objects
+ because we store relocatable addresses in them. */
+#ifdef __PIC__
+#define ALLOCSEC "\"aw\""
+#else
+#define ALLOCSEC "\"a\""
+#endif
+
/* An allocated section .probes that holds the probe names and addrs. */
#define STAP_PROBE_DATA_(probe,guard,arg) \
- __asm__ volatile (".section .probes, \"a\"\n" \
+ __asm__ volatile (".section .probes," ALLOCSEC "\n" \
"\t.align 8\n" \
"1:\n\t.asciz " #probe "\n" \
"\t.align 4\n" \
diff --git a/parse.cxx b/parse.cxx
index a26d594c..cfa33cb4 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -583,47 +583,68 @@ parser::peek_kw (std::string const & kw)
-lexer::lexer (istream& i, const string& in, systemtap_session& s):
- input (i), input_name (in), input_contents (""),
- input_pointer (0), cursor_suspend_count(0),
- cursor_line (1), cursor_column (1), session(s),
- current_file (0)
+lexer::lexer (istream& input, const string& in, systemtap_session& s):
+ input_name (in), input_pointer (0), input_end (0),
+ cursor_suspend_count(0), cursor_line (1), cursor_column (1),
+ session(s), current_file (0)
{
- char c;
- while(input.get(c))
- input_contents.push_back(c);
-}
+ getline(input, input_contents, '\0');
-std::string
-lexer::get_input_contents ()
-{
- return input_contents;
+ input_pointer = input_contents.data();
+ input_end = input_contents.data() + input_contents.size();
+
+ if (keywords.empty())
+ {
+ keywords.insert("probe");
+ keywords.insert("global");
+ keywords.insert("function");
+ keywords.insert("if");
+ keywords.insert("else");
+ keywords.insert("for");
+ keywords.insert("foreach");
+ keywords.insert("in");
+ keywords.insert("limit");
+ keywords.insert("return");
+ keywords.insert("delete");
+ keywords.insert("while");
+ keywords.insert("break");
+ keywords.insert("continue");
+ keywords.insert("next");
+ keywords.insert("string");
+ keywords.insert("long");
+ }
}
+set<string> lexer::keywords;
+
void
lexer::set_current_file (stapfile* f)
{
current_file = f;
+ if (f)
+ {
+ f->file_contents = input_contents;
+ f->name = input_name;
+ }
}
int
lexer::input_peek (unsigned n)
{
- if (input_contents.size() > (input_pointer + n))
- return (int)(unsigned char)input_contents[input_pointer+n];
- else
- return -1;
+ if (input_pointer + n >= input_end)
+ return -1; // EOF
+ return (unsigned char)*(input_pointer + n);
}
int
lexer::input_get ()
{
- int c = input_peek (0);
- input_pointer ++;
-
+ int c = input_peek();
if (c < 0) return c; // EOF
+ ++input_pointer;
+
if (cursor_suspend_count)
// Track effect of input_put: preserve previous cursor/line_column
// until all of its characters are consumed.
@@ -648,9 +669,12 @@ lexer::input_get ()
void
lexer::input_put (const string& chars)
{
- // clog << "[put:" << chars << " @" << input_pointer << "]";
- input_contents.insert (input_contents.begin() + input_pointer, chars.begin(), chars.end());
+ size_t pos = input_pointer - input_contents.data();
+ // clog << "[put:" << chars << " @" << pos << "]";
+ input_contents.insert (pos, chars);
cursor_suspend_count += chars.size();
+ input_pointer = input_contents.data() + pos;
+ input_end = input_contents.data() + input_contents.size();
}
@@ -658,9 +682,7 @@ token*
lexer::scan (bool wildcard)
{
token* n = new token;
- n->location.file = input_name;
- if (current_file)
- n->location.stap_file = current_file;
+ n->location.file = current_file;
unsigned semiskipped_p = 0;
@@ -676,7 +698,6 @@ lexer::scan (bool wildcard)
}
int c = input_get();
- int c2 = input_peek ();
// clog << "{" << (char)c << (char)c2 << "}";
if (c < 0)
{
@@ -687,6 +708,8 @@ lexer::scan (bool wildcard)
if (isspace (c))
goto skip;
+ int c2 = input_peek ();
+
// Paste command line arguments as character streams into
// the beginning of a token. $1..$999 go through as raw
// characters; @1..@999 are quoted/escaped as strings.
@@ -740,23 +763,7 @@ lexer::scan (bool wildcard)
c2 = input_peek ();
}
- if (n->content == "probe"
- || n->content == "global"
- || n->content == "function"
- || n->content == "if"
- || n->content == "else"
- || n->content == "for"
- || n->content == "foreach"
- || n->content == "in"
- || n->content == "limit"
- || n->content == "return"
- || n->content == "delete"
- || n->content == "while"
- || n->content == "break"
- || n->content == "continue"
- || n->content == "next"
- || n->content == "string"
- || n->content == "long")
+ if (keywords.count(n->content))
n->type = tok_keyword;
return n;
@@ -767,23 +774,15 @@ lexer::scan (bool wildcard)
n->type = tok_number;
n->content = (char) c;
- while (1)
+ while (isalnum (c2))
{
- int c2 = input_peek ();
- if (c2 < 0)
- break;
-
// NB: isalnum is very permissive. We rely on strtol, called in
// parser::parse_literal below, to confirm that the number string
// is correctly formatted and in range.
- if (isalnum (c2))
- {
- n->content.push_back (c2);
- input_get ();
- }
- else
- break;
+ input_get ();
+ n->content.push_back (c2);
+ c2 = input_peek ();
}
return n;
}
@@ -835,25 +834,21 @@ lexer::scan (bool wildcard)
else if (ispunct (c))
{
- int c2 = input_peek ();
int c3 = input_peek (1);
- string s1 = string("") + (char) c;
- string s2 = (c2 > 0 ? s1 + (char) c2 : s1);
- string s3 = (c3 > 0 ? s2 + (char) c3 : s2);
// NB: if we were to recognize negative numeric literals here,
// we'd introduce another grammar ambiguity:
// 1-1 would be parsed as tok_number(1) and tok_number(-1)
// instead of tok_number(1) tok_operator('-') tok_number(1)
- if (s1 == "#") // shell comment
+ if (c == '#') // shell comment
{
unsigned this_line = cursor_line;
do { c = input_get (); }
while (c >= 0 && cursor_line == this_line);
goto skip;
}
- else if (s2 == "//") // C++ comment
+ else if ((c == '/' && c2 == '/')) // C++ comment
{
unsigned this_line = cursor_line;
do { c = input_get (); }
@@ -862,15 +857,15 @@ lexer::scan (bool wildcard)
}
else if (c == '/' && c2 == '*') // C comment
{
+ (void) input_get (); // swallow '*' already in c2
+ c = input_get ();
c2 = input_get ();
- unsigned chars = 0;
while (c2 >= 0)
{
- chars ++; // track this to prevent "/*/" from being accepted
+ if (c == '*' && c2 == '/')
+ break;
c = c2;
c2 = input_get ();
- if (chars > 1 && c == '*' && c2 == '/')
- break;
}
goto skip;
}
@@ -878,73 +873,63 @@ lexer::scan (bool wildcard)
{
n->type = tok_embedded;
(void) input_get (); // swallow '{' already in c2
- while (true)
+ c = input_get ();
+ c2 = input_get ();
+ while (c2 >= 0)
{
- c = input_get ();
- if (c < 0) // EOF
- {
- n->type = tok_junk;
- break;
- }
- if (c == '%')
- {
- c2 = input_peek ();
- if (c2 == '}')
- {
- (void) input_get (); // swallow '}' too
- break;
- }
- }
+ if (c == '%' && c2 == '}')
+ return n;
n->content += c;
+ c = c2;
+ c2 = input_get ();
}
+ n->type = tok_junk;
return n;
}
// We're committed to recognizing at least the first character
// as an operator.
n->type = tok_operator;
+ n->content = c;
// match all valid operators, in decreasing size order
- if (s3 == "<<<" ||
- s3 == "<<=" ||
- s3 == ">>=")
+ if ((c == '<' && c2 == '<' && c3 == '<') ||
+ (c == '<' && c2 == '<' && c3 == '=') ||
+ (c == '>' && c2 == '>' && c3 == '='))
{
- n->content = s3;
+ n->content += c2;
+ n->content += c3;
input_get (); input_get (); // swallow other two characters
}
- else if (s2 == "==" ||
- s2 == "!=" ||
- s2 == "<=" ||
- s2 == ">=" ||
- s2 == "+=" ||
- s2 == "-=" ||
- s2 == "*=" ||
- s2 == "/=" ||
- s2 == "%=" ||
- s2 == "&=" ||
- s2 == "^=" ||
- s2 == "|=" ||
- s2 == ".=" ||
- s2 == "&&" ||
- s2 == "||" ||
- s2 == "++" ||
- s2 == "--" ||
- s2 == "->" ||
- s2 == "<<" ||
- s2 == ">>" ||
+ else if ((c == '=' && c2 == '=') ||
+ (c == '!' && c2 == '=') ||
+ (c == '<' && c2 == '=') ||
+ (c == '>' && c2 == '=') ||
+ (c == '+' && c2 == '=') ||
+ (c == '-' && c2 == '=') ||
+ (c == '*' && c2 == '=') ||
+ (c == '/' && c2 == '=') ||
+ (c == '%' && c2 == '=') ||
+ (c == '&' && c2 == '=') ||
+ (c == '^' && c2 == '=') ||
+ (c == '|' && c2 == '=') ||
+ (c == '.' && c2 == '=') ||
+ (c == '&' && c2 == '&') ||
+ (c == '|' && c2 == '|') ||
+ (c == '+' && c2 == '+') ||
+ (c == '-' && c2 == '-') ||
+ (c == '-' && c2 == '>') ||
+ (c == '<' && c2 == '<') ||
+ (c == '>' && c2 == '>') ||
// preprocessor tokens
- s2 == "%(" ||
- s2 == "%?" ||
- s2 == "%:" ||
- s2 == "%)")
+ (c == '%' && c2 == '(') ||
+ (c == '%' && c2 == '?') ||
+ (c == '%' && c2 == ':') ||
+ (c == '%' && c2 == ')'))
{
- n->content = s2;
+ n->content += c2;
input_get (); // swallow other character
}
- else
- {
- n->content = s1;
- }
return n;
}
@@ -965,8 +950,6 @@ parser::parse ()
{
stapfile* f = new stapfile;
input.set_current_file (f);
- f->file_contents = input.get_input_contents ();
- f->name = input_name;
bool empty = true;
@@ -1034,18 +1017,16 @@ parser::parse ()
{
cerr << "Input file '" << input_name << "' is empty or missing." << endl;
delete f;
- input.set_current_file (0);
- return 0;
+ f = 0;
}
else if (num_errors > 0)
{
cerr << num_errors << " parse error(s)." << endl;
delete f;
- input.set_current_file (0);
- return 0;
+ f = 0;
}
- input.set_current_file (0);
+ input.set_current_file(0);
return f;
}
diff --git a/parse.h b/parse.h
index 59046bf3..cae49b65 100644
--- a/parse.h
+++ b/parse.h
@@ -15,6 +15,7 @@
#include <fstream>
#include <iostream>
#include <vector>
+#include <set>
#include <stdexcept>
#include <stdint.h>
@@ -22,10 +23,9 @@ struct stapfile;
struct source_loc
{
- std::string file;
+ stapfile* file;
unsigned line;
unsigned column;
- stapfile* stap_file;
};
std::ostream& operator << (std::ostream& o, const source_loc& loc);
@@ -74,23 +74,22 @@ class lexer
public:
token* scan (bool wildcard=false);
lexer (std::istream&, const std::string&, systemtap_session&);
- std::string get_input_contents ();
void set_current_file (stapfile* f);
private:
- int input_get ();
- void input_put (int);
+ inline int input_get ();
+ inline int input_peek (unsigned n=0);
void input_put (const std::string&);
- int input_peek (unsigned n=0);
- std::istream& input;
std::string input_name;
std::string input_contents;
- int input_pointer; // index into input_contents
+ const char *input_pointer; // index into input_contents
+ const char *input_end;
unsigned cursor_suspend_count;
unsigned cursor_line;
unsigned cursor_column;
systemtap_session& session;
stapfile* current_file;
+ static std::set<std::string> keywords;
};
struct probe;
diff --git a/runtime/autoconf-ring_buffer-flags.c b/runtime/autoconf-ring_buffer-flags.c
new file mode 100644
index 00000000..7d7b8df0
--- /dev/null
+++ b/runtime/autoconf-ring_buffer-flags.c
@@ -0,0 +1,6 @@
+#include <linux/ring_buffer.h>
+
+void ___autoconf_func(void)
+{
+ (void)ring_buffer_lock_reserve(NULL, 0, 0);
+}
diff --git a/runtime/transport/ring_buffer.c b/runtime/transport/ring_buffer.c
index 0b73d4b4..fe63bc83 100644
--- a/runtime/transport/ring_buffer.c
+++ b/runtime/transport/ring_buffer.c
@@ -4,6 +4,11 @@
#include <linux/poll.h>
#include <linux/cpumask.h>
+#ifndef STP_RELAY_TIMER_INTERVAL
+/* Wakeup timer interval in jiffies (default 10 ms) */
+#define STP_RELAY_TIMER_INTERVAL ((HZ + 99) / 100)
+#endif
+
struct _stp_data_entry {
size_t len;
unsigned char buf[];
@@ -23,6 +28,8 @@ struct _stp_relay_data_type {
struct ring_buffer *rb;
struct _stp_ring_buffer_data rb_data;
cpumask_var_t trace_reader_cpumask;
+ struct timer_list timer;
+ int overwrite_flag;
};
static struct _stp_relay_data_type _stp_relay_data;
@@ -134,48 +141,33 @@ _stp_event_to_user(struct ring_buffer_event *event, char __user *ubuf,
return cnt;
}
-static ssize_t tracing_wait_pipe(struct file *filp)
+static ssize_t _stp_tracing_wait_pipe(struct file *filp)
{
- while (ring_buffer_empty(_stp_relay_data.rb)) {
-
+ if (ring_buffer_empty(_stp_relay_data.rb)) {
if ((filp->f_flags & O_NONBLOCK)) {
dbug_trans(1, "returning -EAGAIN\n");
return -EAGAIN;
}
- /*
- * This is a make-shift waitqueue. The reason we don't use
- * an actual wait queue is because:
- * 1) we only ever have one waiter
- * 2) the tracing, traces all functions, we don't want
- * the overhead of calling wake_up and friends
- * (and tracing them too)
- * Anyway, this is really very primitive wakeup.
- */
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* sleep for 100 msecs, and try again. */
- schedule_timeout(HZ/10);
-
if (signal_pending(current)) {
dbug_trans(1, "returning -EINTR\n");
return -EINTR;
}
+ dbug_trans(1, "returning 0\n");
+ return 0;
}
dbug_trans(1, "returning 1\n");
return 1;
}
-static struct ring_buffer_event *
-peek_next_event(int cpu, u64 *ts)
+static struct ring_buffer_event *_stp_peek_next_event(int cpu, u64 *ts)
{
return ring_buffer_peek(_stp_relay_data.rb, cpu, ts);
}
/* Find the next real event */
-static struct ring_buffer_event *
-_stp_find_next_event(long cpu_file)
+static struct ring_buffer_event *_stp_find_next_event(long cpu_file)
{
struct ring_buffer_event *event;
@@ -186,7 +178,7 @@ _stp_find_next_event(long cpu_file)
*/
if (ring_buffer_empty_cpu(_stp_relay_data.rb, (int)cpu_file))
return NULL;
- event = peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts);
+ event = _stp_peek_next_event(cpu_file, &_stp_relay_data.rb_data.ts);
_stp_relay_data.rb_data.cpu = cpu_file;
return event;
@@ -201,7 +193,7 @@ _stp_find_next_event(long cpu_file)
if (ring_buffer_empty_cpu(_stp_relay_data.rb, cpu))
continue;
- event = peek_next_event(cpu, &ts);
+ event = _stp_peek_next_event(cpu, &ts);
/*
* Pick the event with the smallest timestamp:
@@ -234,8 +226,8 @@ _stp_data_read_trace(struct file *filp, char __user *ubuf,
dbug_trans(1, "%lu\n", (unsigned long)cnt);
- sret = tracing_wait_pipe(filp);
- dbug_trans(1, "tracing_wait_pipe returned %ld\n", sret);
+ sret = _stp_tracing_wait_pipe(filp);
+ dbug_trans(1, "_stp_tracing_wait_pipe returned %ld\n", sret);
if (sret <= 0)
goto out;
@@ -291,9 +283,6 @@ static struct file_operations __stp_data_fops = {
.release = _stp_data_release_trace,
.poll = _stp_data_poll_trace,
.read = _stp_data_read_trace,
-#if 0
- .splice_read = tracing_splice_read_pipe,
-#endif
};
/*
@@ -331,13 +320,56 @@ _stp_data_write_reserve(size_t size_request, void **entry)
size_request = __STP_MAX_RESERVE_SIZE;
}
+#ifdef STAPCONF_RING_BUFFER_FLAGS
+ event = ring_buffer_lock_reserve(_stp_relay_data.rb,
+ (sizeof(struct _stp_data_entry)
+ + size_request), 0);
+#else
event = ring_buffer_lock_reserve(_stp_relay_data.rb,
- sizeof(struct _stp_data_entry) + size_request,
- 0);
+ (sizeof(struct _stp_data_entry)
+ + size_request));
+#endif
if (unlikely(! event)) {
- dbug_trans(1, "event = NULL (%p)?\n", event);
- entry = NULL;
- return 0;
+ int cpu;
+
+ dbug_trans(0, "event = NULL (%p)?\n", event);
+ if (! _stp_relay_data.overwrite_flag) {
+ entry = NULL;
+ return 0;
+ }
+
+ /* If we're in overwrite mode and all the buffers are
+ * full, take a event out of the buffer and consume it
+ * (throw it away). This should make room for the new
+ * data. */
+ cpu = raw_smp_processor_id();
+ event = _stp_find_next_event(cpu);
+ if (event) {
+ ssize_t len;
+
+ sde = (struct _stp_data_entry *)ring_buffer_event_data(event);
+ if (sde->len < size_request)
+ size_request = sde->len;
+ ring_buffer_consume(_stp_relay_data.rb, cpu,
+ &_stp_relay_data.rb_data.ts);
+ _stp_relay_data.rb_data.cpu = cpu;
+
+ /* Try to reserve again. */
+#ifdef STAPCONF_RING_BUFFER_FLAGS
+ event = ring_buffer_lock_reserve(_stp_relay_data.rb,
+ sizeof(struct _stp_data_entry) + size_request,
+ 0);
+#else
+ event = ring_buffer_lock_reserve(_stp_relay_data.rb,
+ sizeof(struct _stp_data_entry) + size_request);
+#endif
+ dbug_trans(0, "overwritten event = 0x%p\n", event);
+ }
+
+ if (unlikely(! event)) {
+ entry = NULL;
+ return 0;
+ }
}
sde = (struct _stp_data_entry *)ring_buffer_event_data(event);
@@ -361,7 +393,6 @@ static unsigned char *_stp_data_entry_data(void *entry)
static int _stp_data_write_commit(void *entry)
{
- int ret;
struct ring_buffer_event *event = (struct ring_buffer_event *)entry;
if (unlikely(! entry)) {
@@ -369,14 +400,35 @@ static int _stp_data_write_commit(void *entry)
return -EINVAL;
}
- ret = ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0);
- dbug_trans(1, "after commit, empty returns %d\n",
- ring_buffer_empty(_stp_relay_data.rb));
+#ifdef STAPCONF_RING_BUFFER_FLAGS
+ return ring_buffer_unlock_commit(_stp_relay_data.rb, event, 0);
+#else
+ return ring_buffer_unlock_commit(_stp_relay_data.rb, event);
+#endif
+}
+
+static void __stp_relay_wakeup_timer(unsigned long val)
+{
+ if (waitqueue_active(&_stp_poll_wait)
+ && ! ring_buffer_empty(_stp_relay_data.rb))
+ wake_up_interruptible(&_stp_poll_wait);
+ mod_timer(&_stp_relay_data.timer, jiffies + STP_RELAY_TIMER_INTERVAL);
+}
- wake_up_interruptible(&_stp_poll_wait);
- return ret;
+static void __stp_relay_timer_start(void)
+{
+ init_timer(&_stp_relay_data.timer);
+ _stp_relay_data.timer.expires = jiffies + STP_RELAY_TIMER_INTERVAL;
+ _stp_relay_data.timer.function = __stp_relay_wakeup_timer;
+ _stp_relay_data.timer.data = 0;
+ add_timer(&_stp_relay_data.timer);
+ smp_mb();
}
+static void __stp_relay_timer_stop(void)
+{
+ del_timer_sync(&_stp_relay_data.timer);
+}
static struct dentry *__stp_entry[NR_CPUS] = { NULL };
@@ -422,6 +474,7 @@ static int _stp_transport_data_fs_init(void)
__stp_entry[cpu]->d_inode->i_uid = _stp_uid;
__stp_entry[cpu]->d_inode->i_gid = _stp_gid;
+ __stp_entry[cpu]->d_inode->i_private = (void *)cpu;
#ifndef STP_BULKMODE
if (cpu != 0)
@@ -437,6 +490,7 @@ static int _stp_transport_data_fs_init(void)
static void _stp_transport_data_fs_start(void)
{
if (_stp_relay_data.transport_state == STP_TRANSPORT_INITIALIZED) {
+ __stp_relay_timer_start();
_stp_relay_data.transport_state = STP_TRANSPORT_RUNNING;
}
}
@@ -444,6 +498,7 @@ static void _stp_transport_data_fs_start(void)
static void _stp_transport_data_fs_stop(void)
{
if (_stp_relay_data.transport_state == STP_TRANSPORT_RUNNING) {
+ __stp_relay_timer_stop();
_stp_relay_data.transport_state = STP_TRANSPORT_STOPPED;
}
}
@@ -468,5 +523,6 @@ static enum _stp_transport_state _stp_transport_get_state(void)
static void _stp_transport_data_fs_overwrite(int overwrite)
{
- /* FIXME: Just a place holder for now. */
+ dbug_trans(0, "setting ovewrite to %d\n", overwrite);
+ _stp_relay_data.overwrite_flag = overwrite;
}
diff --git a/tapset/signal.stp b/tapset/signal.stp
index e8470a9c..02c761c3 100644
--- a/tapset/signal.stp
+++ b/tapset/signal.stp
@@ -1,7 +1,7 @@
// Signal tapset
// Copyright (C) 2006 IBM Corp.
// Copyright (C) 2006 Intel Corporation.
-// Copyright (C) 2008 Red Hat, Inc.
+// Copyright (C) 2008-2009 Red Hat, Inc.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
@@ -17,7 +17,7 @@
// (if sig==2) or for a particular process (if pid_name==stap).
// </tapsetdescription>
-/**
+/**
* probe signal.send - Signal being sent to a process
* Arguments:
* @sig: The number of the signal
@@ -83,7 +83,9 @@ probe _signal.send.part4 = kernel.function("specific_send_sig_info")
%)
%( kernel_v > "2.6.25" %?
-probe _signal.send.part1 = kernel.function("send_signal")
+probe _signal.send.part1 =
+ kernel.function("__send_signal") !,
+ kernel.function("send_signal")
{
if ($group == 1) {
name = "__group_send_sig_info"
@@ -128,7 +130,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue")
* Context:
* The signal's sender. <remark>(correct?)</remark>
*
- * Possible <command>__group_send_sig_info</command> and
+ * Possible <command>__group_send_sig_info</command> and
* <command>specific_send_sig_info</command> return values are as follows;
*
* <command>0</command> -- The signal is sucessfully sent to a process,
@@ -137,11 +139,11 @@ probe _signal.send.part3 = kernel.function("send_sigqueue")
* <2> this is a non-RT signal and the system already has one queued, and
* <3> the signal was successfully added to the <command>sigqueue</command> of the receiving process.
*
- * <command>-EAGAIN</command> -- The <command>sigqueue</command> of the receiving process is
- * overflowing, the signal was RT, and the signal was sent by a user using something other
- * than <command>kill()</command>.
+ * <command>-EAGAIN</command> -- The <command>sigqueue</command> of the receiving process is
+ * overflowing, the signal was RT, and the signal was sent by a user using something other
+ * than <command>kill()</command>.
*
- * Possible <command>send_group_sigqueue</command> and
+ * Possible <command>send_group_sigqueue</command> and
* <command>send_sigqueue</command> return values are as follows;
*
* <command>0</command> -- The signal was either sucessfully added into the
@@ -152,7 +154,7 @@ probe _signal.send.part3 = kernel.function("send_sigqueue")
*
* <command>-1</command> -- (<command>send_sigqueue</command> only) The task was marked
* <command>exiting</command>, allowing * <command>posix_timer_event</command> to redirect it to the group
- * leader.
+ * leader.
*
*/
probe signal.send.return = _signal.send.*.return
@@ -302,7 +304,7 @@ probe signal.wakeup = kernel.function("signal_wake_up")
/**
* probe signal.check_ignored - Checking to see signal is ignored
- * @sig_pid: The PID of the process receiving the signal
+ * @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
* @sig_name: A string representation of the signal
@@ -350,7 +352,7 @@ probe signal.handle_stop = kernel.function("handle_stop_signal")
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
- * @sig_name: A string representation of the signal
+ * @sig_name: A string representation of the signal
*/
probe signal.force_segv = _signal.force_segv.*
{
@@ -404,7 +406,7 @@ probe signal.syskill.return = syscall.kill.return
{
}
-/**
+/**
* probe signal.sys_tkill - Sending a kill signal to a thread
* @pid: The PID of the process receiving the kill signal
* @sig: The specific signal sent to the process
@@ -413,7 +415,7 @@ probe signal.syskill.return = syscall.kill.return
* The <command>tkill</command> call is analogous to <command>kill(2)</command>,
* except that it also allows a process within a specific thread group to
* be targetted. Such processes are targetted through their unique
- * thread IDs (TID).
+ * thread IDs (TID).
*/
probe signal.systkill = syscall.tkill
{
@@ -434,9 +436,9 @@ probe signal.systkill.return = syscall.tkill.return
* @sig: The specific kill signal sent to the process
* @sig_name: A string representation of the signal
*
- * The <command>tgkill</command> call is similar to <command>tkill</command>,
- * except that it also allows the caller to specify the thread group ID of
- * the thread to be signalled. This protects against TID reuse.
+ * The <command>tgkill</command> call is similar to <command>tkill</command>,
+ * except that it also allows the caller to specify the thread group ID of
+ * the thread to be signalled. This protects against TID reuse.
*/
probe signal.systgkill = syscall.tgkill
{
@@ -481,14 +483,14 @@ probe signal.send_sig_queue.return =
}
-/**
+/**
* probe signal.pending - Examining pending signal
* @sigset_add: The address of the user-space signal set
* (<command>sigset_t</command>)
* @sigset_size: The size of the user-space signal set
- *
- * This probe is used to examine a set of signals pending for delivery
- * to a specific thread. This normally occurs when the
+ *
+ * This probe is used to examine a set of signals pending for delivery
+ * to a specific thread. This normally occurs when the
* <command>do_sigpending</command> kernel function is executed.
*/
probe signal.pending = kernel.function("do_sigpending")
@@ -497,7 +499,7 @@ probe signal.pending = kernel.function("do_sigpending")
sigset_size=$sigsetsize
}
-/**
+/**
* probe signal.pending.return - Examination of pending signal completed
* @retstr: Return value as a string
*/
@@ -515,7 +517,7 @@ probe signal.pending.return = kernel.function("do_sigpending").return
* <command>siginfo</command> signal
* @ka_addr: The address of the <command>k_sigaction</command> table
* associated with the signal
- * @oldset_addr: The address of the bitmask array of blocked signals
+ * @oldset_addr: The address of the bitmask array of blocked signals
* @regs: The address of the kernel-mode stack area
* @sig_mode: Indicates whether the signal was a user-mode or kernel-mode signal
*/
@@ -593,9 +595,9 @@ function __get_action_mask:long(act:long) %{ /* pure */
/**
* probe signal.procmask - Examining or changing blocked signals
- * @how: Indicates how to change the blocked signals; possible values are
- * <command>SIG_BLOCK=0</command> (for blocking signals),
- * <command>SIG_UNBLOCK=1</command> (for unblocking signals), and
+ * @how: Indicates how to change the blocked signals; possible values are
+ * <command>SIG_BLOCK=0</command> (for blocking signals),
+ * <command>SIG_UNBLOCK=1</command> (for unblocking signals), and
* <command>SIG_SETMASK=2</command> for setting the signal mask.
* @sigset_addr: The address of the signal set (<command>sigset_t</command>)
* to be implemented
@@ -635,7 +637,7 @@ probe signal.procmask.return = kernel.function("sigprocmask").return
* @sig_pid: The PID of the process associated with the task
* performing the flush
* @pid_name: The name of the process associated with the task
- * performing the flush
+ * performing the flush
*/
probe signal.flush = kernel.function("flush_signals")
{
diff --git a/tapsets.cxx b/tapsets.cxx
index 6ef1e188..d7fc79ac 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -592,7 +592,7 @@ struct dwarf_query : public base_query
struct dwarf_builder: public derived_probe_builder
{
- map <string,dwflpp*> kern_dw;
+ map <string,dwflpp*> kern_dw; /* NB: key string could be a wildcard */
map <string,dwflpp*> user_dw;
dwarf_builder() {}
diff --git a/testsuite/buildok/fortysix.stp b/testsuite/buildok/fortysix.stp
new file mode 100755
index 00000000..013ca5bc
--- /dev/null
+++ b/testsuite/buildok/fortysix.stp
@@ -0,0 +1,3 @@
+#! stap -p4
+// PR 3498 + wildcarded modules
+probe module("*scsi*").function("*").call { }
diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp
index e04fe837..76fd57bd 100644
--- a/testsuite/lib/systemtap.exp
+++ b/testsuite/lib/systemtap.exp
@@ -53,7 +53,7 @@ proc print_systemtap_version {} {
proc setup_systemtap_environment {} {
- global srcdir env
+ global srcdir env server_pid net_path
# need an absolute SRCDIR for the top-level src/ tree
# XXX: or, we could change nearby uses of ${SRCDIR}/testsuite to ${SRCDIR}
@@ -68,6 +68,8 @@ proc setup_systemtap_environment {} {
set env(SYSTEMTAP_DIR) [exec pwd]/.systemtap-[exec whoami]
# Find or start a systemtap server, if requested.
+ set net_path ""
+ set server_pid 0
if {[use_server_p]} then {
if {! [setup_server]} then {
return 0
@@ -151,6 +153,7 @@ proc shutdown_server {} {
if { $server_pid != 0 } then {
print "Stopping the systemtap server with PID==$server_pid"
exec stap-stop-server $server_pid
+ set server_pid 0
}
# Remove the temporary stap script
@@ -198,11 +201,9 @@ get_system_info
proc systemtap_init {args} {}
proc systemtap_version {} {}
-proc systemtap_exit {} {
+proc cleanup {} {
# Stop the stap server, if we started it.
- if {[use_server_p]} then {
- shutdown_server
- }
+ shutdown_server
}
diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html
index 5435829f..e186b615 100644
--- a/testsuite/systemtap.examples/index.html
+++ b/testsuite/systemtap.examples/index.html
@@ -94,6 +94,9 @@ keywords: <a href="keyword-index.html#LOCKING">LOCKING</a> <br>
<li><a href="memory/kmalloc-top">memory/kmalloc-top</a> - Show Paths to Kernel Malloc (kmalloc) Invocations<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The kmalloc-top perl program runs a small systemtap script to collect stack traces for each call to the kmalloc function and counts the time that each stack trace is observed. When kmalloc-top exits it prints out sorted list. The output can be be filtered to print only only the first stack traces (-t) stack traces with more a minimum counts (-m), or exclude certain stack traces (-e).</p></li>
+<li><a href="memory/numa_faults.stp">memory/numa_faults.stp</a> - Summarize Process Misses across NUMA Nodes<br>
+keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <a href="keyword-index.html#NUMA">NUMA</a> <br>
+<p>The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.</p></li>
<li><a href="memory/pfaults.stp">memory/pfaults.stp</a> - Generate Log of Major and Minor Page Faults<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.</p></li>
diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt
index 53270b01..35decb82 100644
--- a/testsuite/systemtap.examples/index.txt
+++ b/testsuite/systemtap.examples/index.txt
@@ -175,6 +175,17 @@ keywords: memory
counts (-m), or exclude certain stack traces (-e).
+memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
+keywords: memory numa
+
+ The numa_faults.stp script tracks the read and write pages faults for
+ each process. When the script exits it prints out the total read and
+ write pages faults for each process. The script also providea a break
+ down of page faults per node for each process. This script is useful
+ for determining whether the program has good locality (page faults
+ limited to a single node) on a NUMA computer.
+
+
memory/pfaults.stp - Generate Log of Major and Minor Page Faults
keywords: memory
diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html
index f3db1429..4de28426 100644
--- a/testsuite/systemtap.examples/keyword-index.html
+++ b/testsuite/systemtap.examples/keyword-index.html
@@ -39,7 +39,7 @@
</ul>
<h2>Examples by Keyword</h2>
-<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#BUFFER">BUFFER</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FORMAT">FORMAT</a> <a href="#FREE">FREE</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#MONITOR">MONITOR</a> <a href="#NETWORK">NETWORK</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROCESS">PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRACEPOINT">TRACEPOINT</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#TTY">TTY</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
+<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#BUFFER">BUFFER</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FORMAT">FORMAT</a> <a href="#FREE">FREE</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#MONITOR">MONITOR</a> <a href="#NETWORK">NETWORK</a> <a href="#NUMA">NUMA</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROCESS">PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRACEPOINT">TRACEPOINT</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#TTY">TTY</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
<h3><a name="BACKTRACE">BACKTRACE</a></h3>
<ul>
<li><a href="interrupt/scf.stp">interrupt/scf.stp</a> - Tally Backtraces for Inter-Processor Interrupt (IPI)<br>
@@ -168,6 +168,9 @@ keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-inde
<li><a href="memory/kmalloc-top">memory/kmalloc-top</a> - Show Paths to Kernel Malloc (kmalloc) Invocations<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The kmalloc-top perl program runs a small systemtap script to collect stack traces for each call to the kmalloc function and counts the time that each stack trace is observed. When kmalloc-top exits it prints out sorted list. The output can be be filtered to print only only the first stack traces (-t) stack traces with more a minimum counts (-m), or exclude certain stack traces (-e).</p></li>
+<li><a href="memory/numa_faults.stp">memory/numa_faults.stp</a> - Summarize Process Misses across NUMA Nodes<br>
+keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <a href="keyword-index.html#NUMA">NUMA</a> <br>
+<p>The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.</p></li>
<li><a href="memory/pfaults.stp">memory/pfaults.stp</a> - Generate Log of Major and Minor Page Faults<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.</p></li>
@@ -202,6 +205,12 @@ keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-inde
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <br>
<p>The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.</p></li>
</ul>
+<h3><a name="NUMA">NUMA</a></h3>
+<ul>
+<li><a href="memory/numa_faults.stp">memory/numa_faults.stp</a> - Summarize Process Misses across NUMA Nodes<br>
+keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <a href="keyword-index.html#NUMA">NUMA</a> <br>
+<p>The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.</p></li>
+</ul>
<h3><a name="PER-PROCESS">PER-PROCESS</a></h3>
<ul>
<li><a href="io/ttyspy.stp">io/ttyspy.stp</a> - Monitor tty typing.<br>
diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt
index d3d66fe2..bbee341f 100644
--- a/testsuite/systemtap.examples/keyword-index.txt
+++ b/testsuite/systemtap.examples/keyword-index.txt
@@ -299,6 +299,17 @@ keywords: memory
counts (-m), or exclude certain stack traces (-e).
+memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
+keywords: memory numa
+
+ The numa_faults.stp script tracks the read and write pages faults for
+ each process. When the script exits it prints out the total read and
+ write pages faults for each process. The script also providea a break
+ down of page faults per node for each process. This script is useful
+ for determining whether the program has good locality (page faults
+ limited to a single node) on a NUMA computer.
+
+
memory/pfaults.stp - Generate Log of Major and Minor Page Faults
keywords: memory
@@ -386,6 +397,19 @@ keywords: network traffic
source and destination ports, and flags.
+= NUMA =
+
+memory/numa_faults.stp - Summarize Process Misses across NUMA Nodes
+keywords: memory numa
+
+ The numa_faults.stp script tracks the read and write pages faults for
+ each process. When the script exits it prints out the total read and
+ write pages faults for each process. The script also providea a break
+ down of page faults per node for each process. This script is useful
+ for determining whether the program has good locality (page faults
+ limited to a single node) on a NUMA computer.
+
+
= PER-PROCESS =
io/ttyspy.stp - Monitor tty typing.
diff --git a/testsuite/systemtap.examples/memory/numa_faults.meta b/testsuite/systemtap.examples/memory/numa_faults.meta
new file mode 100644
index 00000000..34034bef
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/numa_faults.meta
@@ -0,0 +1,13 @@
+title: Summarize Process Misses across NUMA Nodes
+name: numa_faults.stp
+version: 1.0
+author: IBM
+keywords: memory numa
+subsystem: memory
+status: production
+exit: user-controlled
+output: list
+scope: system-wide
+description: The numa_faults.stp script tracks the read and write pages faults for each process. When the script exits it prints out the total read and write pages faults for each process. The script also providea a break down of page faults per node for each process. This script is useful for determining whether the program has good locality (page faults limited to a single node) on a NUMA computer.
+test_check: stap -p4 numa_faults.stp
+test_installcheck: stap numa_faults.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/memory/numa_faults.stp b/testsuite/systemtap.examples/memory/numa_faults.stp
new file mode 100755
index 00000000..34a0ace7
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/numa_faults.stp
@@ -0,0 +1,38 @@
+#! /usr/bin/env stap
+
+global execnames, page_faults, node_faults, nodes
+
+probe vm.pagefault {
+ p = pid(); n=addr_to_node(address)
+ execnames[p] = execname()
+ page_faults[p, write_access ? 1 : 0] <<< 1
+ node_faults[p, n] <<< 1
+ nodes[n] <<< 1
+}
+
+function print_pf () {
+ printf ("\n")
+ printf ("%-16s %-6s %10s %10s %-20s\n",
+ "Execname", "PID", "RD Faults", "WR Faults", "Node:Faults")
+ print ("======================= ========== ========== =============\n")
+ foreach (pid in execnames) {
+ printf ("%-16s %6d %10d %10d ", execnames[pid], pid,
+ @count(page_faults[pid,0]), @count(page_faults[pid,1]))
+ foreach ([node+] in nodes) {
+ if ([pid, node] in node_faults)
+ printf ("%d:%d ", node, @count(node_faults[pid, node]))
+ }
+ printf ("\n")
+ }
+ printf("\n")
+}
+
+probe begin {
+ printf("Starting pagefault counters \n")
+}
+
+probe end {
+ printf("Printing counters: \n")
+ print_pf ()
+ printf("Done\n")
+}