diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | stapprobes.5.in | 8 | ||||
-rw-r--r-- | tapsets.cxx | 132 | ||||
-rwxr-xr-x | testsuite/buildok/fourteen.stp | 1 |
4 files changed, 144 insertions, 6 deletions
@@ -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)) } |