summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2005-11-30 22:19:03 +0000
committerfche <fche>2005-11-30 22:19:03 +0000
commit39e57ce01790506b9e6a85cc126c032907fd9197 (patch)
tree76c327ae943a1be6508b2cf06b231ed435b20a3c
parentfe5679e9bab7ee97b4dc541aaf17d461c520dd02 (diff)
downloadsystemtap-steved-39e57ce01790506b9e6a85cc126c032907fd9197.tar.gz
systemtap-steved-39e57ce01790506b9e6a85cc126c032907fd9197.tar.xz
systemtap-steved-39e57ce01790506b9e6a85cc126c032907fd9197.zip
2005-11-30 Frank Ch. Eigler <fche@redhat.com>
PR 1276 From Josh Stone <joshua.i.stone@intel.com>: * tapsets.cxx (profile_derived_probe, profile_builder, register_standard_tapsets): Support timer.profile variety. * stapprobes.5.in: Document it. * testsuite/builok/fourteen.stp: Test its buildability.
-rw-r--r--ChangeLog9
-rw-r--r--stapprobes.5.in8
-rw-r--r--tapsets.cxx132
-rwxr-xr-xtestsuite/buildok/fourteen.stp1
4 files changed, 144 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 353c8e6b..aca98f51 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-11-30 Frank Ch. Eigler <fche@redhat.com>
+
+ PR 1276
+ From Josh Stone <joshua.i.stone@intel.com>:
+ * tapsets.cxx (profile_derived_probe, profile_builder,
+ register_standard_tapsets): Support timer.profile variety.
+ * stapprobes.5.in: Document it.
+ * testsuite/builok/fourteen.stp: Test its buildability.
+
2005-11-28 Graydon Hoare <graydon@redhat.com>
* translate.cxx (var::assert_hist_compatible): New method.
diff --git a/stapprobes.5.in b/stapprobes.5.in
index 2db9cf1f..a268abd7 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -80,6 +80,14 @@ 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.
+.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.
+.SAMPLE
+timer.profile
+.ESAMPLE
+Full context information of the interrupted process is available, making
+this probe suitable for a time-based sampling profiler.
.SS DWARF
diff --git a/tapsets.cxx b/tapsets.cxx
index f07a368c..a2e885df 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -3048,12 +3048,6 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
o->newline() << "c->last_error = 0;";
o->newline() << "c->nesting = 0;";
o->newline() << "c->regs = 0;";
-
- o->newline() << "#ifdef __i386__"; // task_pt_regs is i386-only
- o->newline() << "if (! in_interrupt())";
- o->newline(1) << "c->regs = task_pt_regs (current);";
- o->newline(-1) << "#endif";
-
o->newline() << "c->actioncount = 0;";
// NB: locals are initialized by probe function itself
@@ -3092,6 +3086,131 @@ struct timer_builder: public derived_probe_builder
};
+// ------------------------------------------------------------------------
+// profile derived probes
+// ------------------------------------------------------------------------
+// On kernels < 2.6.10, this uses the register_profile_notifier API to
+// generate the timed events for profiling; on kernels >= 2.6.10 this
+// uses the register_timer_hook API. The latter doesn't currently allow
+// simultaneous users, so insertion will fail if the profiler is busy.
+// (Conflicting users may include OProfile, other SystemTap probes, etc.)
+
+
+struct profile_derived_probe: public derived_probe
+{
+ profile_derived_probe (probe* p, probe_point* l): derived_probe(p, l) {}
+
+ 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
+profile_derived_probe::emit_registrations (translator_output* o, unsigned j)
+{
+ // kernels < 2.6.10: use register_profile_notifier API
+ o->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)";
+ o->newline() << "rc = register_profile_notifier(&profile_" << j << ");";
+
+ // kernels >= 2.6.10: use register_timer_hook API
+ o->newline() << "#else";
+ o->newline() << "rc = register_timer_hook(enter_" << j << ");";
+
+ o->newline() << "#endif";
+}
+
+
+void
+profile_derived_probe::emit_deregistrations (translator_output* o, unsigned j)
+{
+ // kernels < 2.6.10: use register_profile_notifier API
+ o->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)";
+ o->newline() << "unregister_profile_notifier(&profile_" << j << ");";
+
+ // kernels >= 2.6.10: use register_timer_hook API
+ o->newline() << "#else";
+ o->newline() << "unregister_timer_hook(enter_" << j << ");";
+
+ o->newline() << "#endif";
+}
+
+
+void
+profile_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
+{
+ // kernels < 2.6.10: use register_profile_notifier API
+ o->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)";
+ o->newline() << "static int enter_" << j
+ << " (struct notifier_block *self, unsigned long val, void *data);";
+ o->newline() << "static struct notifier_block profile_" << j << " = {";
+ o->newline(1) << ".notifier_call = enter_" << j << ",";
+ o->newline(-1) << "};";
+ o->newline() << "int enter_" << j
+ << " (struct notifier_block *self, unsigned long val, void *data) {";
+ o->newline(1) << "struct pt_regs *regs = (struct pt_regs *)data;";
+
+ // kernels >= 2.6.10: use register_timer_hook API
+ o->newline(-1) << "#else";
+ o->newline() << "static int enter_" << j << " (struct pt_regs *regs);";
+ o->newline() << "int enter_" << j << " (struct pt_regs *regs) {";
+ o->newline(1) << "unsigned long val = 0;";
+ o->newline(-1) << "#endif";
+
+ o->newline(1) << "struct context* c = per_cpu_ptr (contexts, smp_processor_id());";
+ o->newline() << "const char* probe_point = "
+ << lex_cast_qstring(*locations[0]) << ";";
+
+ // 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() << "(void) val;";
+ o->newline() << "if (atomic_read (&session_state) != STAP_SESSION_RUNNING)";
+ o->newline(1) << "return 0;";
+
+ o->newline(-1) << "if (atomic_inc_return (&c->busy) != 1) {";
+ o->newline(1) << "_stp_warn (\"probe reentrancy (%s vs %s)\\n\", "
+ << "c->probe_point, probe_point);";
+ o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ o->newline() << "atomic_dec (&c->busy);";
+ o->newline() << "return 0;";
+ o->newline(-1) << "}";
+ o->newline();
+
+ o->newline() << "c->probe_point = probe_point;";
+ o->newline() << "c->last_error = 0;";
+ o->newline() << "c->nesting = 0;";
+ o->newline() << "c->regs = regs;";
+ o->newline() << "c->actioncount = 0;";
+
+ // NB: locals are initialized by probe function itself
+ o->newline() << "probe_" << j << " (c);";
+
+ o->newline() << "if (c->last_error && c->last_error[0]) {";
+ o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);";
+ o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ o->newline(-1) << "}";
+
+ o->newline() << "atomic_dec (&c->busy);";
+ o->newline() << "return 0;";
+ o->newline(-1) << "}" << endl;
+}
+
+
+struct profile_builder: public derived_probe_builder
+{
+ profile_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 profile_derived_probe(base, location));
+ }
+};
+
+
// ------------------------------------------------------------------------
// Standard tapset registry.
@@ -3107,6 +3226,7 @@ register_standard_tapsets(systemtap_session & s)
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));
+ s.pattern_root->bind("timer")->bind("profile")->bind(new profile_builder());
// kernel/module parts
dwarf_derived_probe::register_patterns(s.pattern_root);
diff --git a/testsuite/buildok/fourteen.stp b/testsuite/buildok/fourteen.stp
index 4490052f..b7f68afe 100755
--- a/testsuite/buildok/fourteen.stp
+++ b/testsuite/buildok/fourteen.stp
@@ -5,4 +5,5 @@ probe timer.jiffies(100) { i++ }
probe timer.jiffies(100).randomize(100) { j++ }
probe timer.ms(100) { i++ }
probe timer.ms(100).randomize(100) { j++ }
+probe timer.profile { i++ }
probe end { log ("i=" . string(i) . " j=" . string(j)) }