summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog26
-rw-r--r--main.cxx7
-rw-r--r--parse.cxx6
-rw-r--r--session.h1
-rw-r--r--stapprobes.5.in18
-rw-r--r--tapsets.cxx265
-rw-r--r--testsuite/ChangeLog4
-rwxr-xr-xtestsuite/buildok/fourteen.stp15
8 files changed, 177 insertions, 165 deletions
diff --git a/ChangeLog b/ChangeLog
index c04bbcd4..4dc7836c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2006-09-27 Josh Stone <joshua.i.stone@intel.com>
+
+ * session.h (struct systemtap_session): Add kernel_base_release
+ to store the kernel version without the -NNN suffix.
+ * main.cxx (main): Generate and use kernel_base_release.
+ * parse.cxx (eval_pp_conditional): Use kernel_base_release.
+ * tapsets.cxx (profile_derived_probe::profile_derived_probe):
+ Use kernel_base_release.
+
+ * tapsets.cxx (timer_builder::build): Support a wide variety of
+ timer varients -- jiffies, s/sec, ms/msec, us/usec, ns/nsec, and
+ hz. Use hrtimers automatically on kernels that have it.
+ (timer_builder::register_patterns): Bind all of the new timer
+ varients in one easy place.
+ (register_standard_tapsets): Call timer_builder::register_patterns.
+ (struct hrtimer_builder): Removed since timer_builder is generic.
+ * stapprobes.5.in: Document new timer.* functionality.
+
+ * tapsets.cxx (hrtimer_derived_probe_group::emit_probes): Add a
+ shared global for the actual hrtimer resolution, _stp_hrtimer_res.
+ (hrtimer_derived_probe_group::emit_module): Init _stp_hrtimer_res.
+ (hrtimer_derived_probe::emit_interval): Limit intervals at a
+ minimum to the hrtimer's actual resolution.
+ (hrtimer_derived_probe::emit_probe_entries): Forward timers
+ based on previous expiration instead of restarting relative.
+
2006-09-26 David Smith <dsmith@redhat.com>
* .cvsignore: Changed 'stpd' reference to 'staprun'.
diff --git a/main.cxx b/main.cxx
index 8f084024..12cca4c7 100644
--- a/main.cxx
+++ b/main.cxx
@@ -311,6 +311,8 @@ main (int argc, char * const argv [])
<< e << endl;
}
+ s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
+
// arguments parsed; get down to business
@@ -366,9 +368,8 @@ main (int argc, char * const argv [])
version_suffixes.push_back ("/" + kvr + "/" + arch);
version_suffixes.push_back ("/" + kvr);
// add kernel version (2.6.NN) + arch
- string::size_type dash_index = kvr.find ('-');
- if (dash_index > 0 && dash_index != string::npos) {
- kvr.erase(dash_index);
+ if (kvr != s.kernel_base_release) {
+ kvr = s.kernel_base_release;
version_suffixes.push_back ("/" + kvr + "/" + arch);
version_suffixes.push_back ("/" + kvr);
}
diff --git a/parse.cxx b/parse.cxx
index a61edc08..2d31e334 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -162,11 +162,7 @@ bool eval_pp_conditional (systemtap_session& s,
l->content == "kernel_vr"))
{
string target_kernel_vr = s.kernel_release;
- string target_kernel_v = target_kernel_vr;
- // cut off any release code suffix
- string::size_type dr = target_kernel_vr.find ('-');
- if (dr > 0 && dr != string::npos)
- target_kernel_v = target_kernel_vr.substr (0, dr);
+ string target_kernel_v = s.kernel_base_release;
if (! (r->type == tok_string))
throw parse_error ("expected string literal", r);
diff --git a/session.h b/session.h
index 9627925e..fa8d375a 100644
--- a/session.h
+++ b/session.h
@@ -63,6 +63,7 @@ struct systemtap_session
std::vector<std::string> macros;
std::vector<std::string> args;
std::string kernel_release;
+ std::string kernel_base_release;
std::string architecture;
std::string runtime_path;
std::string module_name;
diff --git a/stapprobes.5.in b/stapprobes.5.in
index 67070928..b40f21ae 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -95,16 +95,24 @@ smaller than N. There are no target variables provided in either
context. It is possible for such probes to be run concurrently on
a multi-processor computer.
.PP
-Alternatively, intervals may be specified in units of milliseconds.
+Alternatively, intervals may be specified in units of time.
There are two probe point variants similar to the jiffies timer:
.SAMPLE
timer.ms(N)
timer.ms(N).randomize(M)
.ESAMPLE
-Here, N and M are specified in milliseconds. The probe intervals will be
-rounded up to the nearest jiffies interval for the actual timer. If the
-"randomize" component is given, then the random value will be added to the
-interval before the conversion to jiffies.
+Here, N and M are specified in milliseconds, but the full options for units
+are seconds (s/sec), milliseconds (ms/msec), microseconds (us/usec),
+nanoseconds (ns/nsec), and hertz (hz). Randomization is not supported for
+hertz timers.
+
+The actual resolution of the timers depends on the target kernel. For
+kernels prior to 2.6.17, timers are limited to jiffies resolution, so
+intervals are rounded up to the nearest jiffies interval. After 2.6.17,
+the implementation uses hrtimers for tighter precision, though the actual
+resolution will be arch-dependent. In either case, if the "randomize"
+component is given, then the random value will be added to the interval
+before any rounding occurs.
.PP
Profiling timers are also available to provide probes that execute on all
CPUs at the rate of the system tick. This probe takes no parameters.
diff --git a/tapsets.cxx b/tapsets.cxx
index d0792362..ed747cf7 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -3881,29 +3881,6 @@ timer_derived_probe_group::emit_module_init (translator_output* o)
}
-struct timer_builder: public derived_probe_builder
-{
- bool time_is_msecs;
- timer_builder(bool ms=false): time_is_msecs(ms) {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- std::map<std::string, literal *> const & parameters,
- vector<derived_probe *> & finished_results)
- {
- int64_t jn, rn;
- bool jn_p, rn_p;
-
- jn_p = get_param (parameters, time_is_msecs ? "ms" : "jiffies", jn);
- rn_p = get_param (parameters, "randomize", rn);
-
- finished_results.push_back(new timer_derived_probe(base, location,
- jn, rn_p ? rn : 0,
- time_is_msecs));
- }
-};
-
-
// ------------------------------------------------------------------------
// profile derived probes
// ------------------------------------------------------------------------
@@ -3934,16 +3911,7 @@ struct profile_derived_probe: public derived_probe
profile_derived_probe::profile_derived_probe (systemtap_session &s, probe* p, probe_point* l):
derived_probe(p, l)
{
- string target_kernel_v;
-
- // cut off any release code suffix
- string::size_type dash_index = s.kernel_release.find ('-');
- if (dash_index > 0 && dash_index != string::npos)
- target_kernel_v = s.kernel_release.substr (0, dash_index);
- else
- target_kernel_v = s.kernel_release;
-
- using_rpn = (strverscmp(target_kernel_v.c_str(), "2.6.10") < 0);
+ using_rpn = (strverscmp(s.kernel_base_release.c_str(), "2.6.10") < 0);
}
@@ -4703,14 +4671,17 @@ hrtimer_derived_probe::emit_interval (translator_output* o)
{
o->newline() << "int64_t r;";
o->newline() << "get_random_bytes(&r, sizeof(r));";
+
+ // ensure that r is positive
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() << "if (unlikely(i < _stp_hrtimer_res))";
+ o->newline(1) << "i = _stp_hrtimer_res;";
+ o->indent(-1);
o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);";
o->newline() << "ktime_set(i, nsecs);";
o->newline(-1) << "})";
@@ -4759,17 +4730,20 @@ hrtimer_derived_probe::emit_probe_entries (translator_output* o)
o->newline() << "(void) timer;";
- o->newline() << "hrtimer_start (& timer_" << name << ", ";
+ // hrtimer_forward would be preferable, but it's not exported. We already
+ // guarantee that the interval is >= the timer resolution though, so this is
+ // essentially the same.
+ o->newline() << "timer_" << name << ".expires = ktime_add(timer_"
+ << name << ".expires, ";
emit_interval(o);
- o->line() << ", HRTIMER_REL);";
+ o->line() << ");";
// NB: locals are initialized by probe function itself
o->newline() << name << " (c);";
emit_probe_epilogue (o);
- // Return NORESTART, because we already requeued the timer above
- o->newline() << "return HRTIMER_NORESTART;";
+ o->newline() << "return HRTIMER_RESTART;";
o->newline(-1) << "}\n";
}
@@ -4791,6 +4765,11 @@ public:
void
hrtimer_derived_probe_group::emit_probes (translator_output* op, unparser* up)
{
+ if (probes.size () == 0)
+ return;
+
+ op->newline();
+ op->newline() << "static int64_t _stp_hrtimer_res;";
for (unsigned i=0; i < probes.size(); i++)
{
op->newline ();
@@ -4807,7 +4786,10 @@ hrtimer_derived_probe_group::emit_module_init (translator_output* o)
// Output the hrtimer probes create function
o->newline() << "static int register_hrtimer_probes (void) {";
- o->indent(1);
+ o->newline(1) << "struct timespec res;";
+ o->newline() << "hrtimer_get_res(CLOCK_MONOTONIC, &res);";
+ o->newline() << "_stp_hrtimer_res = timespec_to_ns(&res);";
+ o->newline();
for (unsigned i=0; i < probes.size (); i++)
{
@@ -4831,130 +4813,113 @@ hrtimer_derived_probe_group::emit_module_init (translator_output* o)
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;
-
- // cut off any release code suffix
- string::size_type dash_index = sess.kernel_release.find ('-');
- if (dash_index > 0 && dash_index != string::npos)
- target_kernel_v = sess.kernel_release.substr (0, dash_index);
- else
- target_kernel_v = sess.kernel_release;
-
- // hrtimers are only exported starting in 2.6.17
- if (strverscmp(target_kernel_v.c_str(), "2.6.17") >= 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;
- }
+struct timer_builder: public derived_probe_builder
+{
+ virtual void build(systemtap_session & sess,
+ probe * base, probe_point * location,
+ std::map<std::string, literal *> const & parameters,
+ vector<derived_probe *> & finished_results);
- finished_results.push_back(
- new timer_derived_probe(base, location, i_ms, r_ms, true));
- }
- }
+ static void register_patterns(match_node *root);
};
-
-int64_t
-hrtimer_builder::convert_to_ns(const string &time)
+void
+timer_builder::build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ std::map<std::string, literal *> const & parameters,
+ vector<derived_probe *> & finished_results)
{
- int64_t ns;
- int64_t num;
- string unit;
- istringstream iss(time);
+ int64_t period, rand=0;
- iss >> num >> unit;
- if (iss.fail() || num==0) goto bad_time;
+ if (!get_param(parameters, "randomize", rand))
+ rand = 0;
- if ((unit == "hz") || (unit == "hertz"))
+ if (get_param(parameters, "jiffies", period))
{
- ns = 1000000000/num;
- iss >> unit;
- if (!iss.fail()) goto bad_time;
- return ns;
+ // always use basic timers for jiffies
+ finished_results.push_back(
+ new timer_derived_probe(base, location, period, rand, false));
+ return;
}
-
- ns = 0;
- do
+ else if (get_param(parameters, "hz", period))
{
- if ((unit == "ns") || (unit == "nsec"))
- goto unit_parsed;
-
- num *= 1000;
- if ((unit == "us") || (unit == "usec"))
- goto unit_parsed;
+ if (period <= 0)
+ throw semantic_error ("frequency must be greater than 0");
+ period = (1000000000 + period - 1)/period;
+ }
+ else if (get_param(parameters, "s", period)
+ || get_param(parameters, "sec", period))
+ {
+ period *= 1000000000;
+ rand *= 1000000000;
+ }
+ else if (get_param(parameters, "ms", period)
+ || get_param(parameters, "msec", period))
+ {
+ period *= 1000000;
+ rand *= 1000000;
+ }
+ else if (get_param(parameters, "us", period)
+ || get_param(parameters, "usec", period))
+ {
+ period *= 1000;
+ rand *= 1000;
+ }
+ else if (get_param(parameters, "ns", period)
+ || get_param(parameters, "nsec", period))
+ {
+ // ok
+ }
+ else
+ throw semantic_error ("unrecognized timer variant");
- num *= 1000;
- if ((unit == "ms") || (unit == "msec"))
- goto unit_parsed;
+ if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
+ {
+ // hrtimers didn't exist, so use the old-school timers
+ period = (period + 1000000 - 1)/1000000;
+ rand = (rand + 1000000 - 1)/1000000;
- num *= 1000;
- if ((unit == "s") || (unit == "sec"))
- goto unit_parsed;
+ finished_results.push_back(
+ new timer_derived_probe(base, location, period, rand, true));
+ }
+ else
+ finished_results.push_back(
+ new hrtimer_derived_probe(base, location, period, rand));
+}
- num *= 60;
- if ((unit == "m") || (unit == "min"))
- goto unit_parsed;
+void
+timer_builder::register_patterns(match_node *root)
+{
+ derived_probe_builder *builder = new timer_builder();
- num *= 60;
- if ((unit == "h") || (unit == "hour"))
- goto unit_parsed;
+ root = root->bind("timer");
- goto bad_time;
+ root->bind_num("s")->bind(builder);
+ root->bind_num("s")->bind_num("randomize")->bind(builder);
+ root->bind_num("sec")->bind(builder);
+ root->bind_num("sec")->bind_num("randomize")->bind(builder);
-unit_parsed:
- ns += num;
+ root->bind_num("ms")->bind(builder);
+ root->bind_num("ms")->bind_num("randomize")->bind(builder);
+ root->bind_num("msec")->bind(builder);
+ root->bind_num("msec")->bind_num("randomize")->bind(builder);
- iss >> num;
- if (iss.fail()) break;
- iss >> unit;
- if (iss.fail() || num==0) goto bad_time;
- }
- while (1);
+ root->bind_num("us")->bind(builder);
+ root->bind_num("us")->bind_num("randomize")->bind(builder);
+ root->bind_num("usec")->bind(builder);
+ root->bind_num("usec")->bind_num("randomize")->bind(builder);
- return ns;
+ root->bind_num("ns")->bind(builder);
+ root->bind_num("ns")->bind_num("randomize")->bind(builder);
+ root->bind_num("nsec")->bind(builder);
+ root->bind_num("nsec")->bind_num("randomize")->bind(builder);
-bad_time:
- throw semantic_error("bad time parameter: '" + time + "'");
+ root->bind_num("jiffies")->bind(builder);
+ root->bind_num("jiffies")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("hz")->bind(builder);
}
@@ -5381,13 +5346,9 @@ register_standard_tapsets(systemtap_session & s)
s.pattern_root->bind("never")->bind(new never_builder());
- 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());
- 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));
+ timer_builder::register_patterns(s.pattern_root);
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());
+
s.pattern_root->bind("perfmon")->bind_str("counter")->bind(new perfmon_builder());
// dwarf-based kernel/module parts
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index 203c85dd..d77fee48 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2006-09-27 Josh Stone <joshua.i.stone@intel.com>
+
+ * buildok/fourteen.stp: Test new timer functionality.
+
2006-09-26 David Smith <dsmith@redhat.com>
* systemtap.samples/args.exp: Looks for 'staprun' instead of
diff --git a/testsuite/buildok/fourteen.stp b/testsuite/buildok/fourteen.stp
index 8eab2480..86b3dad2 100755
--- a/testsuite/buildok/fourteen.stp
+++ b/testsuite/buildok/fourteen.stp
@@ -3,7 +3,22 @@
global i, j
probe timer.jiffies(100) { i++ }
probe timer.jiffies(100).randomize(100) { j++ }
+probe timer.s(100) { i++ }
+probe timer.s(100).randomize(100) { j++ }
+probe timer.sec(100) { i++ }
+probe timer.sec(100).randomize(100) { j++ }
probe timer.ms(100) { i++ }
probe timer.ms(100).randomize(100) { j++ }
+probe timer.msec(100) { i++ }
+probe timer.msec(100).randomize(100) { j++ }
+probe timer.us(100) { i++ }
+probe timer.us(100).randomize(100) { j++ }
+probe timer.usec(100) { i++ }
+probe timer.usec(100).randomize(100) { j++ }
+probe timer.ns(100000) { i++ }
+probe timer.ns(100000).randomize(100) { j++ }
+probe timer.nsec(100000) { i++ }
+probe timer.nsec(100000).randomize(100) { j++ }
+probe timer.hz(100) { i++ }
probe timer.profile { i++ }
probe end { printf("i=%d j=%d\n", i, j) }