]> sourceware.org Git - systemtap.git/commitdiff
2006-03-29 Josh Stone <joshua.i.stone@intel.com>
authorjistone <jistone>
Thu, 30 Mar 2006 00:00:29 +0000 (00:00 +0000)
committerjistone <jistone>
Thu, 30 Mar 2006 00:00:29 +0000 (00:00 +0000)
* tapsets.cxx (hrtimer_derived_probe::*): creates a probe point
based on the hrtimer APIs.
* tapsets.cxx (hrtimer_builder::*):  parses the user's time-spec
into a 64-bit nanosecond value, and calls the appropriate
derived_probe.
* tapsets.cxx (register_standard_tapsets): add hrtimer bindings
* translate.cxx (translate_pass): add linux/random.h include,
used for generating 64-bit random numbers for hrtimers.

ChangeLog
tapsets.cxx
translate.cxx

index c6cb75e0927dd15350fb1532bea54f322f38ffc6..e8c9fbd3a9dd79e18f2505318a610e955f2c8aac 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2006-03-29  Josh Stone  <joshua.i.stone@intel.com>
+
+       * tapsets.cxx (hrtimer_derived_probe::*): creates a probe point
+       based on the hrtimer APIs.
+       * tapsets.cxx (hrtimer_builder::*):  parses the user's time-spec
+       into a 64-bit nanosecond value, and calls the appropriate
+       derived_probe.
+       * tapsets.cxx (register_standard_tapsets): add hrtimer bindings
+       * translate.cxx (translate_pass): add linux/random.h include,
+       used for generating 64-bit random numbers for hrtimers.
+
 2006-03-28  Martin Hunt  <hunt@redhat.com>
 
        * testsuite/buildok/syscall.stp: Update so
index 8337eff763103e712393e3695ec7c3f8451a584e..5991b0ea1015adf98a8c8af541e349da94b33c74 100644 (file)
@@ -3436,6 +3436,246 @@ struct profile_builder: public derived_probe_builder
 };
 
 
+// ------------------------------------------------------------------------
+// hrtimer derived probes
+// ------------------------------------------------------------------------
+// This is a new timer interface that provides more flexibility in specifying
+// intervals, and uses the hrtimer APIs when available for greater precision.
+// As of 2.6.16, these APIs don't have the needed EXPORT_SYMBOL_GPL, so we
+// can't make use of them yet.
+//
+// There are two classes defined below:
+// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
+// * hrtimer_builder: parses the user's time-spec into a 64-bit nanosecond
+//   value, and calls the appropriate derived_probe.
+
+
+struct hrtimer_derived_probe: public derived_probe
+{
+  // set a (generous) maximum of one day in ns
+  static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
+
+  // 100us seems like a reasonable minimum
+  static const int64_t min_ns_interval = 100000LL;
+
+  int64_t interval, randomize;
+
+  hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r):
+    derived_probe (p, l), interval (i), randomize (r)
+  {
+    if ((i < min_ns_interval) || (i > max_ns_interval))
+      throw semantic_error("interval value out of range");
+
+    // randomize = 0 means no randomization
+    if ((r < 0) || (r > i))
+      throw semantic_error("randomization value out of range");
+
+    if (locations.size() != 1)
+      throw semantic_error ("expect single probe point");
+    // so we don't have to loop over them in the other functions
+  }
+
+  virtual void emit_interval (translator_output * o);
+
+  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);
+};
+
+
+void
+hrtimer_derived_probe::emit_interval (translator_output* o)
+{
+  o->line() << "({";
+  o->newline(1) << "DEFINE_KTIME(kt);";
+  o->newline() << "int64_t i = " << interval << "LL;";
+  if (randomize != 0)
+    { 
+      o->newline() << "int64_t r;";
+      o->newline() << "get_random_bytes(&r, sizeof(r));";
+      o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;";
+      o->newline() << "r = _stp_mod64(NULL, r, " << (2*randomize + 1) << "LL);";
+      o->newline() << "r -= " << randomize << "LL;";
+      o->newline() << "i += r;";
+      o->newline() << "if (unlikely(i < " << min_ns_interval << "LL))";
+      o->newline(1) << "i = " << min_ns_interval << "LL;";
+      o->indent(-1);
+    }
+  o->newline() << "ktime_add_ns(kt, i);";
+  o->newline(-1) << "})";
+}
+
+
+void
+hrtimer_derived_probe::emit_registrations (translator_output* o, unsigned j)
+{
+  o->newline() << "hrtimer_init (& timer_" << j
+    << ", CLOCK_MONOTONIC, HRTIMER_REL);";
+  o->newline() << "timer_" << j << ".function = enter_" << j << ";";
+  o->newline() << "hrtimer_start (& timer_" << j << ", ";
+  emit_interval(o);
+  o->line() << ", HRTIMER_REL);";
+}
+
+
+void
+hrtimer_derived_probe::emit_deregistrations (translator_output* o, unsigned j)
+{
+  o->newline() << "hrtimer_cancel (& timer_" << j << ");";
+}
+
+
+void
+hrtimer_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
+{
+  o->newline() << "static int enter_" << j << " (void *data);";
+  o->newline() << "static struct hrtimer timer_" << j << ";";
+
+  o->newline() << "int enter_" << j << " (void *data) {";
+  o->indent(1);
+  o->newline() << "const char* probe_point = "
+              << lex_cast_qstring(*locations[0]) << ";";
+  emit_probe_prologue (o, "STAP_SESSION_RUNNING");
+
+  o->newline() << "(void) data;";
+
+  o->newline() << "hrtimer_forward (& timer_" << j << ", ";
+  emit_interval(o);
+  o->line() << ");";
+
+  // NB: locals are initialized by probe function itself
+  o->newline() << "probe_" << j << " (c);";
+
+  emit_probe_epilogue (o);
+  o->newline() << "return HRTIMER_RESTART;";
+  o->newline(-1) << "}\n";
+}
+
+
+struct hrtimer_builder: public derived_probe_builder
+{
+  hrtimer_builder() {}
+  static int64_t convert_to_ns(const string &time);
+  virtual void build(systemtap_session & sess,
+                    probe * base,
+                    probe_point * location,
+                    std::map<std::string, literal *> const & parameters,
+                    vector<derived_probe *> & finished_results)
+  {
+    string interval, randomize;
+    int64_t i_ns, r_ns;
+
+    if (!get_param (parameters, "hrtimer", interval))
+      throw semantic_error("timer requires an interval");
+    i_ns = convert_to_ns(interval);
+    if (sess.verbose > 1)
+      clog << "parsed timer interval '" << interval
+          << "' to " << i_ns << " ns. "<< endl;
+
+    if (get_param (parameters, "randomize", randomize))
+      {
+       r_ns = convert_to_ns(randomize);
+       if (sess.verbose > 1)
+         clog << "parsed timer randomization '" << randomize
+              << "' to " << r_ns << " ns. "<< endl;
+      }
+    else
+      r_ns = 0;
+
+    string target_kernel_v;
+
+    /*
+     * When hrtimers are finally exported from the kernel, we can do a version
+     * check against sess.kernel_release to enable them.  Until then, just use
+     * the "legacy" flavor.
+     */
+    if (0)
+      finished_results.push_back(
+         new hrtimer_derived_probe(base, location, i_ns, r_ns));
+    else
+      {
+       int64_t i_ms = (i_ns + 999999) / 1000000;
+       int64_t r_ms = (r_ns + 999999) / 1000000;
+
+       if (sess.verbose > 2)
+         {
+           clog << "rounded timer interval from "
+             << i_ns << " ns to " << i_ms <<" ms. "<< endl;
+           clog << "rounded timer randomization from "
+             << i_ns << " ns to " << i_ms <<" ms. "<< endl;
+         }
+           
+       finished_results.push_back(
+           new timer_derived_probe(base, location, i_ms, r_ms, true));
+      }
+  }
+};
+
+
+int64_t
+hrtimer_builder::convert_to_ns(const string &time)
+{
+  int64_t ns;
+  int64_t num;
+  string unit;
+  istringstream iss(time);
+
+  iss >> num >> unit;
+  if (iss.fail() || num==0) goto bad_time;
+
+  if ((unit == "hz") || (unit == "hertz"))
+    {
+      ns = 1000000000/num;
+      iss >> unit;
+      if (!iss.fail()) goto bad_time;
+      return ns;
+    }
+
+  ns = 0;
+  do
+    {
+      if ((unit == "ns") || (unit == "nsec"))
+       goto unit_parsed;
+
+      num *= 1000;
+      if ((unit == "us") || (unit == "usec"))
+       goto unit_parsed;
+
+      num *= 1000;
+      if ((unit == "ms") || (unit == "msec"))
+       goto unit_parsed;
+
+      num *= 1000;
+      if ((unit == "s") || (unit == "sec"))
+       goto unit_parsed;
+
+      num *= 60;
+      if ((unit == "m") || (unit == "min"))
+       goto unit_parsed;
+
+      num *= 60;
+      if ((unit == "h") || (unit == "hour"))
+       goto unit_parsed;
+
+      goto bad_time;
+
+unit_parsed:
+      ns += num;
+
+      iss >> num;
+      if (iss.fail()) break;
+      iss >> unit;
+      if (iss.fail() || num==0) goto bad_time;
+    }
+  while (1);
+
+  return ns;
+
+bad_time:
+  throw semantic_error("bad time parameter: '" + time + "'");
+}
+
+
 
 // ------------------------------------------------------------------------
 //  Standard tapset registry.
@@ -3452,6 +3692,8 @@ register_standard_tapsets(systemtap_session & s)
   s.pattern_root->bind("timer")->bind_num("ms")->bind(new timer_builder(true));
   s.pattern_root->bind("timer")->bind_num("ms")->bind_num("randomize")->bind(new timer_builder(true));
   s.pattern_root->bind("timer")->bind("profile")->bind(new profile_builder());
+  s.pattern_root->bind_str("hrtimer")->bind(new hrtimer_builder());
+  s.pattern_root->bind_str("hrtimer")->bind_str("randomize")->bind(new hrtimer_builder());
 
   // kernel/module parts
   dwarf_derived_probe::register_patterns(s.pattern_root);
index 94c6147a8853b624b9356fb663db1b3ec972bbb0..35a17c237eb16555f48449c8746f110b7cc0650c 100644 (file)
@@ -3788,6 +3788,7 @@ translate_pass (systemtap_session& s)
       s.op->newline() << "#include <linux/timer.h>";
       s.op->newline() << "#include <linux/delay.h>";
       s.op->newline() << "#include <linux/profile.h>";
+      s.op->newline() << "#include <linux/random.h>";
       s.op->newline() << "#include \"loc2c-runtime.h\" ";
       
       // XXX: old 2.6 kernel hack
This page took 0.052134 seconds and 5 git commands to generate.