summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--elaborate.cxx44
-rw-r--r--elaborate.h8
-rw-r--r--runtime/ChangeLog4
-rw-r--r--runtime/arith.c24
-rw-r--r--stap.1.in12
-rw-r--r--tapsets.cxx184
-rw-r--r--tapsets.h11
-rwxr-xr-xtestsuite/buildok/fourteen.stp6
-rw-r--r--translate.cxx1
10 files changed, 257 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index a2efec67..66d14e22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2005-08-19 Frank Ch. Eigler <fche@elastic.org>
+ PR systemtap/1209
+ * tapsets.cxx
+ * elaborate.cxx (derived_probe_builder): Add get_param function.
+ * elaborate.h: Declare them.
+ * tapsets.cxx (dwarf_query::get_*_param): Call them.
+ (timer_derived_probe, timer_builder): New classes.
+ (register_standard_tapsets): Register timer.jiffies(N) and friend.
+ * translate.cxx (translate_pass): #include <linux/timers.h>.
+ * stap.1.in: Document timer.jiffies(N) probe points.
+ * testsuite/buildok/fourteen.stp: New test.
+
+2005-08-19 Frank Ch. Eigler <fche@elastic.org>
+
* elaborate.cxx (find_var): Remove $pid/$tid builtin logic.
2005-08-19 Martin Hunt <hunt@redhat.com>
diff --git a/elaborate.cxx b/elaborate.cxx
index 0d4796bd..53cab841 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -50,8 +50,46 @@ derived_probe::derived_probe (probe *p, probe_point *l):
}
}
+
// ------------------------------------------------------------------------
+// Members of derived_probe_builder
+
+bool
+derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
+ const std::string& key,
+ std::string& value)
+{
+ map<string, literal *>::const_iterator i = params.find (key);
+ if (i == params.end())
+ return false;
+ literal_string * ls = dynamic_cast<literal_string *>(i->second);
+ if (!ls)
+ return false;
+ value = ls->value;
+ return true;
+}
+
+bool
+derived_probe_builder::get_param (std::map<std::string, literal*> const & params,
+ const std::string& key,
+ int64_t& value)
+{
+ map<string, literal *>::const_iterator i = params.find (key);
+ if (i == params.end())
+ return false;
+ if (i->second == NULL)
+ return false;
+ literal_number * ln = dynamic_cast<literal_number *>(i->second);
+ if (!ln)
+ return false;
+ value = ln->value;
+ return true;
+}
+
+
+
+// ------------------------------------------------------------------------
// Members of match_key.
match_key::match_key(string const & n)
@@ -173,18 +211,18 @@ match_node::find_builder(vector<probe_point::component *> const & components,
// an entry in the sub table, and its value matches the rest
// of the probe_point.
match_key k(*components[pos]);
- if (0) // session.verbose
+ if (0)
clog << "searching for component " << k.str() << endl;
map<match_key, match_node *>::const_iterator i = sub.find(k);
if (i == sub.end())
{
- if (0) // session.verbose
+ if (0)
clog << "no match found" << endl;
return NULL;
}
else
{
- if (0) // session.verbose
+ if (0)
clog << "matched " << k.str() << endl;
derived_probe_builder * builder = NULL;
if (k.have_parameter)
diff --git a/elaborate.h b/elaborate.h
index b4180c31..c3c35fee 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -137,8 +137,7 @@ struct derived_probe: public probe
// ------------------------------------------------------------------------
-struct
-derived_probe_builder
+struct derived_probe_builder
{
virtual void build(systemtap_session & sess,
probe* base,
@@ -147,6 +146,11 @@ derived_probe_builder
std::vector<probe*> & results_to_expand_further,
std::vector<derived_probe*> & finished_results) = 0;
virtual ~derived_probe_builder() {}
+
+ static bool get_param (std::map<std::string, literal*> const & parameters,
+ const std::string& key, std::string& value);
+ static bool get_param (std::map<std::string, literal*> const & parameters,
+ const std::string& key, int64_t& value);
};
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index 05367f27..f4f791dd 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,7 @@
+2005-08-19 Frank Ch. Eigler <fche@elastic.org>
+
+ * arith.c (_stp_random_pm): New function.
+
2005-08-19 Martin Hunt <hunt@redhat.com>
* print.c: Change ifdefs to STP_RELAYFS.
diff --git a/runtime/arith.c b/runtime/arith.c
index 175cc4e8..0200afa6 100644
--- a/runtime/arith.c
+++ b/runtime/arith.c
@@ -2,9 +2,10 @@
#define _ARITH_C_
/** @file arith.
- * @brief Implements 64-bit signed division/multiplication.
+ * @brief Implements various arithmetic-related helper functions
*/
+
struct context;
void _stp_divmod64 (unsigned *errorcount, int64_t x, int64_t y,
int64_t *quo, int64_t *rem);
@@ -75,5 +76,26 @@ void _stp_divmod64 (unsigned *errorcount, int64_t x, int64_t y,
}
+/** Return a random integer between -n and n.
+ * @param n how far from zero to go. Make it positive but less than a million or so.
+ */
+int _stp_random_pm (int n)
+{
+ static unsigned long seed;
+ static int initialized_p = 0;
+
+ if (unlikely (! initialized_p))
+ {
+ seed = (unsigned long) jiffies;
+ initialized_p = 1;
+ }
+
+ /* from glibc rand man page */
+ seed = seed * 1103515245 + 12345;
+
+ return (seed % (2*n+1)-n);
+}
+
+
#endif /* _ARITH_C_ */
diff --git a/stap.1.in b/stap.1.in
index afaf0c72..cf89758f 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -1,3 +1,4 @@
+.\" -*- nroff -*-
.TH STAP 1 @DATE@ "Red Hat"
.SH NAME
stap \- systemtap script translator/driver
@@ -281,6 +282,10 @@ module(MPATTERN).function(PATTERN).return
kernel.statement(PATTERN)
.br
module(MPATTERN).statement(PATTERN)
+.br
+timer.jiffies(NUM)
+.br
+timer.jiffies(NUM).randomize(RAND)
.fi
.RE
.PP
@@ -300,6 +305,10 @@ and identifies the line number in the source file, preceded by a ":".
As an alternative, PATTERN may be a numeric constant, indicating an
(module-relative or kernel-absolute) address.
.PP
+The timer-based asynchronous probe points run the given handler every
+NUM jiffies. If given, the random value in the range [-RAND..RAND] is
+added to NUM every time the handler is run.
+.PP
Here are some example probe points:
.TP
kernel.function("*init*"), kernel.function("*exit*")
@@ -316,6 +325,9 @@ name in any of the USB drivers.
kernel.statement(0xc0044852)
refers to the first byte of the statement whose compiled instructions
include the given address in the kernel.
+.TP
+timer.jiffies(1000).randomize(200)
+refers to a periodic interrupt, every 1000 +/- 200 jiffies.
.PP
When any matching event occurs, the probe handler is run within that
diff --git a/tapsets.cxx b/tapsets.cxx
index 88369d55..45a77a8a 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -53,9 +53,8 @@ struct be_derived_probe: public derived_probe
void emit_probe_entries (translator_output* o, unsigned i);
};
-struct
-be_builder
- : public derived_probe_builder
+
+struct be_builder: public derived_probe_builder
{
bool begin;
be_builder(bool b) : begin(b) {}
@@ -68,7 +67,6 @@ be_builder
{
finished_results.push_back(new be_derived_probe(base, location, begin));
}
- virtual ~be_builder() {}
};
@@ -919,7 +917,6 @@ struct dwarf_derived_probe : public derived_probe
virtual void emit_registrations (translator_output * o, unsigned i);
virtual void emit_deregistrations (translator_output * o, unsigned i);
virtual void emit_probe_entries (translator_output * o, unsigned i);
- virtual ~dwarf_derived_probe() {}
};
// Helper struct to thread through the dwfl callbacks.
@@ -987,9 +984,8 @@ dwarf_query
dwflpp & dw;
};
-struct
-dwarf_builder
- : public derived_probe_builder
+
+struct dwarf_builder: public derived_probe_builder
{
dwarf_builder() {}
virtual void build(systemtap_session & sess,
@@ -998,7 +994,6 @@ dwarf_builder
std::map<std::string, literal *> const & parameters,
vector<probe *> & results_to_expand_further,
vector<derived_probe *> & finished_results);
- virtual ~dwarf_builder() {}
};
bool
@@ -1015,46 +1010,27 @@ bool
dwarf_query::get_string_param(map<string, literal *> const & params,
string const & k, string & v)
{
- map<string, literal *>::const_iterator i = params.find(k);
- if (i == params.end())
- return false;
- literal_string * ls = dynamic_cast<literal_string *>(i->second);
- if (!ls)
- return false;
- v = ls->value;
- return true;
+ return derived_probe_builder::get_param (params, k, v);
}
bool
dwarf_query::get_number_param(map<string, literal *> const & params,
string const & k, long & v)
{
- map<string, literal *>::const_iterator i = params.find(k);
- if (i == params.end())
- return false;
- if (i->second == NULL)
- return false;
- literal_number * ln = dynamic_cast<literal_number *>(i->second);
- if (!ln)
- return false;
- v = ln->value;
- return true;
+ int64_t value;
+ bool present = derived_probe_builder::get_param (params, k, value);
+ v = (long) value;
+ return present;
}
bool
dwarf_query::get_number_param(map<string, literal *> const & params,
string const & k, Dwarf_Addr & v)
{
- map<string, literal *>::const_iterator i = params.find(k);
- if (i == params.end())
- return false;
- if (i->second == NULL)
- return false;
- literal_number * ln = dynamic_cast<literal_number *>(i->second);
- if (!ln)
- return false;
- v = static_cast<Dwarf_Addr>(ln->value);
- return true;
+ int64_t value;
+ bool present = derived_probe_builder::get_param (params, k, value);
+ v = (Dwarf_Addr) value;
+ return present;
}
@@ -1819,6 +1795,138 @@ dwarf_builder::build(systemtap_session & sess,
}
+
+// ------------------------------------------------------------------------
+// timer derived probes
+// ------------------------------------------------------------------------
+
+
+struct timer_derived_probe: public derived_probe
+{
+ int64_t interval, randomize;
+
+ timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r);
+
+ virtual void emit_registrations (translator_output * o, unsigned i);
+ virtual void emit_deregistrations (translator_output * o, unsigned i);
+ virtual void emit_probe_entries (translator_output * o, unsigned i);
+};
+
+
+timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r):
+ derived_probe (p, l), interval (i), randomize (r)
+{
+ if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
+ throw semantic_error ("invalid interval for jiffies timer");
+ // randomize = 0 means no randomization
+ if (randomize < 0 || randomize > interval)
+ throw semantic_error ("invalid randomize for jiffies timer");
+
+ if (locations.size() != 1)
+ throw semantic_error ("expect single probe point");
+ // so we don't have to loop over them in the other functions
+}
+
+
+void
+timer_derived_probe::emit_registrations (translator_output* o, unsigned j)
+{
+ o->newline() << "init_timer (& timer_" << j << ");";
+ o->newline() << "timer_" << j << ".expires = jiffies + " << interval << ";";
+ o->newline() << "timer_" << j << ".function = & enter_" << j << ";";
+ o->newline() << "add_timer (& timer_" << j << ");";
+}
+
+
+void
+timer_derived_probe::emit_deregistrations (translator_output* o, unsigned j)
+{
+ o->newline() << "del_timer_sync (& timer_" << j << ");";
+}
+
+
+void
+timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
+{
+ o->newline() << "static struct timer_list timer_" << j << ";";
+
+ o->newline() << "void enter_" << j << " (unsigned long val) {";
+ o->newline(1) << "struct context* c = & contexts [smp_processor_id()];";
+
+ o->newline() << "(void) val;";
+
+ // A precondition for running a probe handler is that we're in
+ // RUNNING state (not ERROR), and that no one else is already using
+ // this context.
+ o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)";
+ o->newline(1) << "return;";
+
+ o->newline(-1) << "if (c->busy) {";
+ o->newline(1) << "printk (KERN_ERR \"probe reentrancy\");";
+ o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ o->newline() << "return;";
+ o->newline(-1) << "}";
+ o->newline();
+
+ o->newline() << "mod_timer (& timer_" << j << ", "
+ << "jiffies + " << interval;
+ if (randomize)
+ o->line() << " + _stp_random_pm(" << randomize << ")";
+ o->line() << ");";
+
+ o->newline() << "c->busy ++;";
+ o->newline() << "mb ();"; // for smp
+ o->newline() << "c->errorcount = 0;";
+ o->newline() << "c->actioncount = 0;";
+ o->newline() << "c->nesting = 0;";
+
+ o->newline() << "if (! in_interrupt())";
+ o->newline(1) << "c->regs = 0;";
+ o->newline(-1) << "else";
+ o->newline(1) << "c->regs = task_pt_regs (current);";
+ o->indent(-1);
+
+ // NB: locals are initialized by probe function itself
+ o->newline() << "probe_" << j << " (c);";
+
+ // see translate.cxx: visit_functioncall and elsewhere to see all the
+ // possible context indications that a probe exited prematurely
+ o->newline() << "if (c->errorcount || c->actioncount > MAXACTION"
+ << " || c->nesting+2 >= MAXNESTING) {";
+ o->newline(1) << "printk (KERN_ERR \"probe execution failure (e%d,n%d,a%d)\",";
+ o->newline(1) << "c->errorcount, c->nesting, c->actioncount);";
+ o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ o->newline(-1) << "}";
+
+ o->newline() << "c->busy --;";
+ o->newline() << "mb ();";
+ o->newline(-1) << "}" << endl;
+}
+
+
+struct timer_builder: public derived_probe_builder
+{
+ timer_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ std::map<std::string, literal *> const & parameters,
+ vector<probe *> &,
+ vector<derived_probe *> & finished_results)
+ {
+ int64_t jn, rn;
+ bool jn_p, rn_p;
+
+ jn_p = get_param (parameters, "jiffies", jn);
+ rn_p = get_param (parameters, "randomize", rn);
+
+ finished_results.push_back(new timer_derived_probe(base, location,
+ jn, rn_p ? rn : 0));
+ }
+};
+
+
+
// ------------------------------------------------------------------------
// Standard tapset registry.
// ------------------------------------------------------------------------
@@ -1829,6 +1937,8 @@ register_standard_tapsets(systemtap_session & s)
// Rudimentary binders for begin and end targets
s.pattern_root->bind("begin")->bind(new be_builder(true));
s.pattern_root->bind("end")->bind(new be_builder(false));
+ s.pattern_root->bind("timer")->bind_num("jiffies")->bind(new timer_builder());
+ s.pattern_root->bind("timer")->bind_num("jiffies")->bind_num("randomize")->bind(new timer_builder());
// kernel/module parts
dwarf_derived_probe::register_patterns(s.pattern_root);
diff --git a/tapsets.h b/tapsets.h
index 694829db..45be2c3b 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -1,6 +1,3 @@
-#ifndef TAPSETS_H
-#define TAPSETS_H
-
// -*- C++ -*-
// Copyright (C) 2005 Red Hat Inc.
//
@@ -9,13 +6,13 @@
// Public License (GPL); either version 2, or (at your option) any
// later version.
+#ifndef TAPSETS_H
+#define TAPSETS_H
+
#include "config.h"
#include "staptree.h"
#include "elaborate.h"
-
-void
-register_standard_tapsets(systemtap_session & sess);
-
+void register_standard_tapsets(systemtap_session & sess);
#endif // TAPSETS_H
diff --git a/testsuite/buildok/fourteen.stp b/testsuite/buildok/fourteen.stp
new file mode 100755
index 00000000..dd231696
--- /dev/null
+++ b/testsuite/buildok/fourteen.stp
@@ -0,0 +1,6 @@
+#! stap -p4
+
+global i, j
+probe timer.jiffies(100) { i++ }
+probe timer.jiffies(100).randomize(100) { j++ }
+probe end { log ("i=" . string(i) . " j=" . string(j)) }
diff --git a/translate.cxx b/translate.cxx
index c2425b84..1a8e23b1 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -2165,6 +2165,7 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#else";
s.op->newline() << "#include \"runtime.h\"";
s.op->newline() << "#include <linux/string.h>";
+ s.op->newline() << "#include <linux/timer.h>";
// XXX
s.op->newline() << "#define KALLSYMS_LOOKUP_NAME \"\"";
s.op->newline() << "#define KALLSYMS_LOOKUP 0";