From: fche Date: Fri, 19 Aug 2005 21:50:42 +0000 (+0000) Subject: 2005-08-19 Frank Ch. Eigler X-Git-Tag: release-0.3~42 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=98afd80eb5038542fa3a98c75528524b5d4287b6;p=systemtap.git 2005-08-19 Frank Ch. Eigler 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 . * stap.1.in: Document timer.jiffies(N) probe points. * testsuite/buildok/fourteen.stp: New test. 2005-08-19 Frank Ch. Eigler * arith.c (_stp_random_pm): New function. --- diff --git a/ChangeLog b/ChangeLog index a2efec678..66d14e223 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-08-19 Frank Ch. Eigler + + 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 . + * stap.1.in: Document timer.jiffies(N) probe points. + * testsuite/buildok/fourteen.stp: New test. + 2005-08-19 Frank Ch. Eigler * elaborate.cxx (find_var): Remove $pid/$tid builtin logic. diff --git a/elaborate.cxx b/elaborate.cxx index 0d4796bd3..53cab841a 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 const & params, + const std::string& key, + std::string& value) +{ + map::const_iterator i = params.find (key); + if (i == params.end()) + return false; + literal_string * ls = dynamic_cast(i->second); + if (!ls) + return false; + value = ls->value; + return true; +} + +bool +derived_probe_builder::get_param (std::map const & params, + const std::string& key, + int64_t& value) +{ + map::const_iterator i = params.find (key); + if (i == params.end()) + return false; + if (i->second == NULL) + return false; + literal_number * ln = dynamic_cast(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 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::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 b4180c316..c3c35fee6 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 & results_to_expand_further, std::vector & finished_results) = 0; virtual ~derived_probe_builder() {} + + static bool get_param (std::map const & parameters, + const std::string& key, std::string& value); + static bool get_param (std::map const & parameters, + const std::string& key, int64_t& value); }; diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 05367f277..f4f791dde 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,7 @@ +2005-08-19 Frank Ch. Eigler + + * arith.c (_stp_random_pm): New function. + 2005-08-19 Martin Hunt * print.c: Change ifdefs to STP_RELAYFS. diff --git a/runtime/arith.c b/runtime/arith.c index 175cc4e8e..0200afa63 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 afaf0c723..cf89758f7 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 88369d557..45a77a8ad 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 const & parameters, vector & results_to_expand_further, vector & finished_results); - virtual ~dwarf_builder() {} }; bool @@ -1015,46 +1010,27 @@ bool dwarf_query::get_string_param(map const & params, string const & k, string & v) { - map::const_iterator i = params.find(k); - if (i == params.end()) - return false; - literal_string * ls = dynamic_cast(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 const & params, string const & k, long & v) { - map::const_iterator i = params.find(k); - if (i == params.end()) - return false; - if (i->second == NULL) - return false; - literal_number * ln = dynamic_cast(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 const & params, string const & k, Dwarf_Addr & v) { - map::const_iterator i = params.find(k); - if (i == params.end()) - return false; - if (i->second == NULL) - return false; - literal_number * ln = dynamic_cast(i->second); - if (!ln) - return false; - v = static_cast(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 const & parameters, + vector &, + vector & 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 694829db4..45be2c3b9 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 000000000..dd2316964 --- /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 c2425b842..1a8e23b16 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 "; + s.op->newline() << "#include "; // XXX s.op->newline() << "#define KALLSYMS_LOOKUP_NAME \"\""; s.op->newline() << "#define KALLSYMS_LOOKUP 0";