]> sourceware.org Git - systemtap.git/commitdiff
2005-08-19 Frank Ch. Eigler <fche@elastic.org>
authorfche <fche>
Fri, 19 Aug 2005 21:50:42 +0000 (21:50 +0000)
committerfche <fche>
Fri, 19 Aug 2005 21:50:42 +0000 (21:50 +0000)
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>

* arith.c (_stp_random_pm): New function.

ChangeLog
elaborate.cxx
elaborate.h
runtime/ChangeLog
runtime/arith.c
stap.1.in
tapsets.cxx
tapsets.h
testsuite/buildok/fourteen.stp [new file with mode: 0755]
translate.cxx

index a2efec67818f3c258fcddad9e25b3200e98a3f71..66d14e223d6f0b0897d481186631673608fd2a7a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+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.
index 0d4796bd37dc865d5432e03c3141e2d30ff41b84..53cab841a44811e38c7b521a3cfec28d424acdd8 100644 (file)
@@ -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)
index b4180c316963da57c6f31b6e53855d2c9be56567..c3c35fee631f0853e8367dacf9127f472137365f 100644 (file)
@@ -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);
 };
 
 
index 05367f27703d21c9397b3a5e21ac4148ad3e14ed..f4f791dde0f24358c52a362f31c1d702295733e5 100644 (file)
@@ -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.
index 175cc4e8e64d52a8e380a1893b2db94197e6edb7..0200afa637d9acd1f1ed01b475ab57a06b1a6fbc 100644 (file)
@@ -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_ */
index afaf0c72304d256a0018681c8d5d50cfcb4799ea..cf89758f7d520483a9b3f549f2614869d2d9dc60 100644 (file)
--- 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
index 88369d5575f8b9b3e023f63b20bcece9ca7e3c9f..45a77a8ad165ad95be8c1f508d61867bf95442ce 100644 (file)
@@ -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);
index 694829db47dae0d3aa8333a9e8bb927cee718a17..45be2c3b90880fd8645df42f64a7397e9270bcd5 100644 (file)
--- 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 (executable)
index 0000000..dd23169
--- /dev/null
@@ -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)) }
index c2425b842a4571a3ecaee7e5274d18298831d1ee..1a8e23b161eb7e81449aefeea8d83e541972a98d 100644 (file)
@@ -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";
This page took 0.056824 seconds and 5 git commands to generate.