]> sourceware.org Git - systemtap.git/blame - tapset-timers.cxx
Ensure use of the function argument values from function entry in lwtools
[systemtap.git] / tapset-timers.cxx
CommitLineData
912e8c59 1// tapset for timers
f66bb29a 2// Copyright (C) 2005-2011 Red Hat Inc.
912e8c59 3// Copyright (C) 2005-2007 Intel Corporation.
912e8c59
JS
4//
5// This file is part of systemtap, and is free software. You can
6// redistribute it and/or modify it under the terms of the GNU General
7// Public License (GPL); either version 2, or (at your option) any
8// later version.
9
10
11#include "session.h"
12#include "tapsets.h"
13#include "translate.h"
14#include "util.h"
15
16#include <cstring>
17#include <string>
18
19
20using namespace std;
21using namespace __gnu_cxx;
22
23
4627ed58 24static const string TOK_TIMER("timer");
912e8c59
JS
25
26
27// ------------------------------------------------------------------------
28// timer derived probes
29// ------------------------------------------------------------------------
30
31
32struct timer_derived_probe: public derived_probe
33{
34 int64_t interval, randomize;
35 bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead
36 timer_derived_probe (probe* p, probe_point* l,
37 int64_t i, int64_t r, bool ms=false);
38 virtual void join_group (systemtap_session& s);
2865d17a
DB
39
40 // No assertion need be emitted, since this probe is allowed for unprivileged
41 // users.
42e38653 42 void emit_privilege_assertion (translator_output*) {}
8f6d8c2b 43 void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
912e8c59
JS
44};
45
46
47struct timer_derived_probe_group: public generic_dpg<timer_derived_probe>
48{
49 void emit_interval (translator_output* o);
50public:
51 void emit_module_decls (systemtap_session& s);
52 void emit_module_init (systemtap_session& s);
53 void emit_module_exit (systemtap_session& s);
54};
55
56
57timer_derived_probe::timer_derived_probe (probe* p, probe_point* l,
58 int64_t i, int64_t r, bool ms):
59 derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms)
60{
61 if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
ce0f6648 62 //TRANSLATORS: 'timer' is the name of a probe point
dc09353a 63 throw SEMANTIC_ERROR (_("invalid interval for jiffies timer"));
912e8c59
JS
64 // randomize = 0 means no randomization
65 if (randomize < 0 || randomize > interval)
ce0f6648 66 //TRANSLATORS: 'randomize' is a key word
dc09353a 67 throw SEMANTIC_ERROR (_("invalid randomize for jiffies timer"));
912e8c59
JS
68
69 if (locations.size() != 1)
dc09353a 70 throw SEMANTIC_ERROR (_("only expect one probe point"));
912e8c59
JS
71 // so we don't have to loop over them in the other functions
72}
73
74
75void
76timer_derived_probe::join_group (systemtap_session& s)
77{
78 if (! s.timer_derived_probes)
79 s.timer_derived_probes = new timer_derived_probe_group ();
80 s.timer_derived_probes->enroll (this);
ca6d3b0f 81 this->group = s.timer_derived_probes;
912e8c59
JS
82}
83
84
85void
86timer_derived_probe_group::emit_interval (translator_output* o)
87{
88 o->line() << "({";
89 o->newline(1) << "unsigned i = stp->intrv;";
90 o->newline() << "if (stp->rnd != 0)";
91 o->newline(1) << "i += _stp_random_pm(stp->rnd);";
92 o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
93 o->newline(-1) << "})";
94}
95
96
97void
98timer_derived_probe_group::emit_module_decls (systemtap_session& s)
99{
100 if (probes.empty()) return;
101
102 s.op->newline() << "/* ---- timer probes ---- */";
103
104 s.op->newline() << "static struct stap_timer_probe {";
105 s.op->newline(1) << "struct timer_list timer_list;";
7c3e97f4 106 s.op->newline() << "const struct stap_probe * const probe;";
912e8c59
JS
107 s.op->newline() << "unsigned intrv, ms, rnd;";
108 s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {";
109 s.op->indent(1);
110 for (unsigned i=0; i < probes.size(); i++)
111 {
112 s.op->newline () << "{";
faea5e16 113 s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
912e8c59
JS
114 s.op->line() << " .intrv=" << probes[i]->interval << ",";
115 s.op->line() << " .ms=" << probes[i]->time_is_msecs << ",";
116 s.op->line() << " .rnd=" << probes[i]->randomize;
117 s.op->line() << " },";
118 }
119 s.op->newline(-1) << "};";
120 s.op->newline();
121
122 s.op->newline() << "static void enter_timer_probe (unsigned long val) {";
123 s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
065d5567
JS
124 s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
125 s.op->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING))";
912e8c59
JS
126 s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
127 emit_interval (s.op);
128 s.op->line() << ");";
129 s.op->newline(-1) << "{";
130 s.op->indent(1);
71db462b 131 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
cda141c2 132 "stp_probe_type_timer");
26e63673 133 s.op->newline() << "(*stp->probe->ph) (c);";
ef1337ee 134 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
912e8c59
JS
135 s.op->newline(-1) << "}";
136 s.op->newline(-1) << "}";
137}
138
139
140void
141timer_derived_probe_group::emit_module_init (systemtap_session& s)
142{
143 if (probes.empty()) return;
144
145 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
146 s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
26e63673 147 s.op->newline() << "probe_point = stp->probe->pp;";
912e8c59
JS
148 s.op->newline() << "init_timer (& stp->timer_list);";
149 s.op->newline() << "stp->timer_list.function = & enter_timer_probe;";
150 s.op->newline() << "stp->timer_list.data = i;"; // NB: important!
151 // copy timer renew calculations from above :-(
152 s.op->newline() << "stp->timer_list.expires = jiffies + ";
153 emit_interval (s.op);
154 s.op->line() << ";";
155 s.op->newline() << "add_timer (& stp->timer_list);";
156 // note: no partial failure rollback is needed: add_timer cannot fail.
157 s.op->newline(-1) << "}"; // for loop
158}
159
160
161void
162timer_derived_probe_group::emit_module_exit (systemtap_session& s)
163{
164 if (probes.empty()) return;
165
166 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
167 s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
168 s.op->indent(-1);
169}
170
171
172
173// ------------------------------------------------------------------------
174// hrtimer derived probes
175// ------------------------------------------------------------------------
176// This is a new timer interface that provides more flexibility in specifying
177// intervals, and uses the hrtimer APIs when available for greater precision.
178// While hrtimers were added in 2.6.16, the API's weren't exported until
179// 2.6.17, so we must check this kernel version before attempting to use
180// hrtimers.
181//
182// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
183
184
185struct hrtimer_derived_probe: public derived_probe
186{
187 // set a (generous) maximum of one day in ns
188 static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
189
190 // 100us seems like a reasonable minimum
191 static const int64_t min_ns_interval = 100000LL;
192
193 int64_t interval, randomize;
194
195 hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r,
196 int64_t scale):
197 derived_probe (p, l), interval (i), randomize (r)
198 {
199 if ((i < min_ns_interval) || (i > max_ns_interval))
dc09353a 200 throw SEMANTIC_ERROR(_F("interval value out of range (%s, %s)",
b530b5b3
LB
201 (lex_cast(scale < min_ns_interval ? min_ns_interval/scale : 1).c_str()),
202 lex_cast(max_ns_interval/scale).c_str()));
912e8c59
JS
203
204 // randomize = 0 means no randomization
205 if ((r < 0) || (r > i))
dc09353a 206 throw SEMANTIC_ERROR(_("randomization value out of range"));
912e8c59
JS
207 }
208
209 void join_group (systemtap_session& s);
2865d17a
DB
210
211 // No assertion need be emitted, since these probes are allowed for
212 // unprivileged users.
42e38653 213 void emit_privilege_assertion (translator_output*) {}
8f6d8c2b 214 void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
912e8c59
JS
215};
216
217
218struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
219{
912e8c59
JS
220public:
221 void emit_module_decls (systemtap_session& s);
222 void emit_module_init (systemtap_session& s);
039546fa 223 void emit_module_refresh (systemtap_session& s);
912e8c59 224 void emit_module_exit (systemtap_session& s);
ca6d3b0f
JL
225
226 bool otf_supported (systemtap_session& s)
227 { return !s.runtime_usermode_p(); }
228
229 // workqueue manipulation is safe in hrtimers
230 bool otf_safe_context (systemtap_session& s)
231 { return otf_supported(s); }
912e8c59
JS
232};
233
234
235void
236hrtimer_derived_probe::join_group (systemtap_session& s)
237{
238 if (! s.hrtimer_derived_probes)
239 s.hrtimer_derived_probes = new hrtimer_derived_probe_group ();
240 s.hrtimer_derived_probes->enroll (this);
ca6d3b0f 241 this->group = s.hrtimer_derived_probes;
912e8c59
JS
242}
243
244
912e8c59
JS
245void
246hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
247{
248 if (probes.empty()) return;
249
250 s.op->newline() << "/* ---- hrtimer probes ---- */";
2b5ecafd
DS
251 s.op->newline() << "#include \"timer.c\"";
252 s.op->newline() << "static struct stap_hrtimer_probe stap_hrtimer_probes [" << probes.size() << "] = {";
912e8c59 253
912e8c59
JS
254 s.op->indent(1);
255 for (unsigned i=0; i < probes.size(); i++)
256 {
257 s.op->newline () << "{";
faea5e16 258 s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
912e8c59
JS
259 s.op->line() << " .intrv=" << probes[i]->interval << "LL,";
260 s.op->line() << " .rnd=" << probes[i]->randomize << "LL";
261 s.op->line() << " },";
262 }
263 s.op->newline(-1) << "};";
264 s.op->newline();
265
2b5ecafd
DS
266 if (!s.runtime_usermode_p())
267 {
6b378b7c 268 s.op->newline() << "static hrtimer_return_t _stp_hrtimer_notify_function (struct hrtimer *timer) {";
2b5ecafd
DS
269
270 s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
271 s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
272
273 // Update the timer with the next trigger time
065d5567
JS
274 s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
275 s.op->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
2b5ecafd
DS
276 s.op->newline(1) << "_stp_hrtimer_update(stp);";
277 s.op->newline() << "rc = HRTIMER_RESTART;";
278 s.op->newline(-1) << "}";
279
280 s.op->newline() << "{";
281 s.op->indent(1);
282 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
283 "stp_probe_type_hrtimer");
284 s.op->newline() << "(*stp->probe->ph) (c);";
ef1337ee 285 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
2b5ecafd
DS
286 s.op->newline(-1) << "}";
287 s.op->newline() << "return rc;";
288 s.op->newline(-1) << "}";
289 }
290 else
291 {
6b378b7c 292 s.op->newline() << "static void _stp_hrtimer_notify_function (sigval_t value)";
2b5ecafd
DS
293 s.op->newline(1) << "{";
294 s.op->newline() << "struct stap_hrtimer_probe *stp = value.sival_ptr;";
295
296 // Update the timer with the next trigger time
065d5567
JS
297 s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
298 s.op->newline() << " (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
2b5ecafd
DS
299 s.op->newline(1) << "_stp_hrtimer_update(stp);";
300 s.op->newline(-1) << "}";
301
302 s.op->newline() << "{";
303 s.op->indent(1);
304 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
305 "stp_probe_type_hrtimer");
306 s.op->newline() << "(*stp->probe->ph) (c);";
ef1337ee 307 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
2b5ecafd
DS
308 s.op->newline(-1) << "}";
309 s.op->newline(-1) << "}";
310 }
912e8c59
JS
311}
312
313
314void
315hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
316{
317 if (probes.empty()) return;
318
039546fa
JL
319 s.op->newline( 0) << "_stp_hrtimer_init();";
320 s.op->newline( 0) << "for (i=0; i<" << probes.size() << "; i++) {";
321 s.op->newline(+1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
322 s.op->newline( 0) << "probe_point = stp->probe->pp;";
2b5ecafd
DS
323
324 // Note: no partial failure rollback is needed for kernel hrtimer
325 // probes (hrtimer_start only "fails" if the timer was already
326 // active, which cannot be). But, stapdyn timer probes need a
327 // rollback, and it won't hurt the kernel hrtimers.
039546fa
JL
328 s.op->newline( 0) << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
329 s.op->newline( 0) << "if (rc) {";
330 s.op->newline(+1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
331 s.op->newline(+1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
4bf3d59d
JL
332 if (!s.runtime_usermode_p())
333 s.op->newline( 0) << "stap_hrtimer_probes[j].enabled = 0;";
039546fa
JL
334 s.op->newline(-1) << "}";
335 s.op->newline( 0) << "break;"; // don't attempt to register any more
336 s.op->newline(-1) << "}";
337
4bf3d59d
JL
338 // If not in kernel mode, then we always want to start the timer because
339 // on-the-fly starting/stopping is not supported.
340 if (!s.runtime_usermode_p())
341 {
342 // If the probe condition is off, then don't bother starting the timer
343 s.op->newline( 0) << "if (!stp->probe->cond_enabled) {";
344 s.op->newline(+1) << "dbug_otf(\"not starting (hrtimer) pidx %zu\\n\",";
345 s.op->newline( 0) << "stp->probe->index);";
346 s.op->newline( 0) << "continue;";
347 s.op->newline(-1) << "}";
348 }
039546fa
JL
349
350 // Start the timer (with rollback on failure)
351 s.op->newline( 0) << "rc = _stp_hrtimer_start(stp);";
352 s.op->newline( 0) << "if (rc) {";
353 s.op->newline(+1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
354 s.op->newline(+1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
4bf3d59d
JL
355 if (!s.runtime_usermode_p())
356 s.op->newline( 0) << "stap_hrtimer_probes[j].enabled = 0;";
039546fa
JL
357 s.op->newline(-1) << "}";
358 s.op->newline( 0) << "break;"; // don't attempt to register any more
359 s.op->newline(-1) << "}";
360
361 // Mark as enabled since we successfully started the timer
4bf3d59d
JL
362 if (!s.runtime_usermode_p())
363 s.op->newline( 0) << "stp->enabled = 1;";
364
039546fa
JL
365 s.op->newline(-1) << "}"; // for loop
366}
367
368
369void
370hrtimer_derived_probe_group::emit_module_refresh (systemtap_session& s)
371{
4bf3d59d 372 if (probes.empty() || s.runtime_usermode_p()) return;
039546fa
JL
373
374 // Check if we need to enable/disable any timers
039546fa
JL
375 s.op->newline( 0) << "for (i=0; i <" << probes.size() << "; i++) {";
376 s.op->newline(+1) << "struct stap_hrtimer_probe* stp = &stap_hrtimer_probes[i];";
377 // timer disabled, but condition says enabled?
378 s.op->newline( 0) << "if (!stp->enabled && stp->probe->cond_enabled) {";
379 s.op->newline(+1) << "dbug_otf(\"enabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
380 s.op->newline( 0) << "_stp_hrtimer_start(stp);";
381 // timer enabled, but condition says disabled?
382 s.op->newline(-1) << "} else if (stp->enabled && !stp->probe->cond_enabled) {";
383 s.op->newline(+1) << "dbug_otf(\"disabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
384 s.op->newline( 0) << "_stp_hrtimer_cancel(stp);";
385 s.op->newline(-1) << "}";
386 s.op->newline( 0) << "stp->enabled = stp->probe->cond_enabled;";
2b5ecafd 387 s.op->newline(-1) << "}";
912e8c59
JS
388}
389
390
391void
392hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
393{
394 if (probes.empty()) return;
395
396 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
2b5ecafd 397 s.op->indent(1);
039546fa 398 s.op->newline() << "_stp_hrtimer_delete(& stap_hrtimer_probes[i]);";
912e8c59
JS
399 s.op->indent(-1);
400}
401
402
403
404// ------------------------------------------------------------------------
405// profile derived probes
406// ------------------------------------------------------------------------
407// On kernels < 2.6.10, this uses the register_profile_notifier API to
408// generate the timed events for profiling; on kernels >= 2.6.10 this
409// uses the register_timer_hook API. The latter doesn't currently allow
410// simultaneous users, so insertion will fail if the profiler is busy.
411// (Conflicting users may include OProfile, other SystemTap probes, etc.)
412
413
414struct profile_derived_probe: public derived_probe
415{
416 profile_derived_probe (systemtap_session &s, probe* p, probe_point* l);
417 void join_group (systemtap_session& s);
418};
419
420
421struct profile_derived_probe_group: public generic_dpg<profile_derived_probe>
422{
423public:
424 void emit_module_decls (systemtap_session& s);
425 void emit_module_init (systemtap_session& s);
426 void emit_module_exit (systemtap_session& s);
427};
428
429
430profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l):
431 derived_probe(p, l)
432{
433}
434
435
436void
437profile_derived_probe::join_group (systemtap_session& s)
438{
439 if (! s.profile_derived_probes)
440 s.profile_derived_probes = new profile_derived_probe_group ();
441 s.profile_derived_probes->enroll (this);
ca6d3b0f 442 this->group = s.profile_derived_probes;
912e8c59
JS
443}
444
445
912e8c59
JS
446// timer.profile probe handlers are hooked up in an entertaining way
447// to the underlying kernel facility. The fact that 2.6.11+ era
448// "register_timer_hook" API allows only one consumer *system-wide*
449// will give a hint. We will have a single entry function (and thus
450// trivial registration / unregistration), and it will call all probe
451// handler functions in sequence.
452
453void
454profile_derived_probe_group::emit_module_decls (systemtap_session& s)
455{
456 if (probes.empty()) return;
457
458 // kernels < 2.6.10: use register_profile_notifier API
459 // kernels >= 2.6.10: use register_timer_hook API
460 s.op->newline() << "/* ---- profile probes ---- */";
461
462 // This function calls all the profiling probe handlers in sequence.
463 // The only tricky thing is that the context will be reused amongst
464 // them. While a simple sequence of calls to the individual probe
465 // handlers is unlikely to go terribly wrong (with c->last_error
466 // being set causing an early return), but for extra assurance, we
467 // open-code the same logic here.
468
469 s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
7c3e97f4 470 s.op->newline(1) << "const struct stap_probe * probe = "
faea5e16 471 << common_probe_init (probes[0]) << ";";
71db462b 472 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "probe",
cda141c2 473 "stp_probe_type_profile_timer");
97cd9334
MW
474 // Timer interrupts save all registers, so if the interrupt happened
475 // in user space we can rely on it being the full user pt_regs.
d9aed31e 476 s.op->newline() << "if (user_mode(regs)) {";
e04b5d74 477 s.op->newline(1) << "c->user_mode_p = 1;";
d9aed31e
MW
478 s.op->newline() << "c->uregs = regs;";
479 s.op->newline(-1) << "} else {";
480 s.op->newline(1) << "c->kregs = regs;";
481 s.op->newline(-1) << "}";
912e8c59
JS
482
483 for (unsigned i=0; i<probes.size(); i++)
484 {
485 if (i > 0)
486 {
487 // Some lightweight inter-probe context resetting
488 // XXX: not quite right: MAXERRORS not respected
26e63673
JS
489 // XXX: STP_TIMING stats are also not correct
490 s.op->newline() << "probe = " << common_probe_init (probes[i]) << ";";
491 s.op->newline() << "#ifdef STP_NEED_PROBE_NAME";
492 s.op->newline() << "c->probe_name = probe->pn;";
493 s.op->newline() << "#endif";
152fa051
LB
494 if(!s.suppress_time_limits)
495 {
496 s.op->newline() << "c->actionremaining = MAXACTION;";
497 }
912e8c59 498 }
26e63673 499 s.op->newline() << "if (c->last_error == NULL) probe->ph (c);";
912e8c59 500 }
ef1337ee 501 common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
912e8c59
JS
502 s.op->newline(-1) << "}";
503
504 s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
505
506 s.op->newline() << "static int enter_profile_probes (struct notifier_block *self,"
507 << " unsigned long val, void *data) {";
508 s.op->newline(1) << "(void) self; (void) val;";
509 s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
510 s.op->newline() << "return 0;";
511 s.op->newline(-1) << "}";
512 s.op->newline() << "struct notifier_block stap_profile_notifier = {"
513 << " .notifier_call = & enter_profile_probes };";
514
515 s.op->newline() << "#else";
516
517 s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
518 s.op->newline(1) << "enter_all_profile_probes (regs);";
519 s.op->newline() << "return 0;";
520 s.op->newline(-1) << "}";
521
522 s.op->newline() << "#endif";
523}
524
525
526void
527profile_derived_probe_group::emit_module_init (systemtap_session& s)
528{
529 if (probes.empty()) return;
530
531 s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
532 s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
533 s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
534 s.op->newline() << "#else";
535 s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);";
536 s.op->newline() << "#endif";
537}
538
539
540void
541profile_derived_probe_group::emit_module_exit (systemtap_session& s)
542{
543 if (probes.empty()) return;
544
f755cab3 545 s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
912e8c59
JS
546 s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
547 s.op->newline() << "#else";
548 s.op->newline() << "unregister_timer_hook (& enter_profile_probes);";
549 s.op->newline() << "#endif";
912e8c59
JS
550}
551
552
553
554// ------------------------------------------------------------------------
555// unified probe builder for timer probes
556// ------------------------------------------------------------------------
557
558
559struct timer_builder: public derived_probe_builder
560{
561 virtual void build(systemtap_session & sess,
562 probe * base, probe_point * location,
563 literal_map_t const & parameters,
564 vector<derived_probe *> & finished_results);
565
566 static void register_patterns(systemtap_session& s);
567};
568
569void
570timer_builder::build(systemtap_session & sess,
571 probe * base,
572 probe_point * location,
573 literal_map_t const & parameters,
574 vector<derived_probe *> & finished_results)
575{
576 int64_t scale=1, period, rand=0;
577
1abafad4
JS
578 if (has_null_param(parameters, "profile"))
579 {
2b5ecafd 580 if (sess.runtime_usermode_p())
dc09353a 581 throw SEMANTIC_ERROR (_("profile timer probes not available with the dyninst runtime"));
2b5ecafd 582
08357f6b
SM
583 /* As the latest mechanism for timer hook support has been
584 removed, we need to bail explicitly if the corresponding
585 symbols are missing: */
586 if ((sess.kernel_exports.find("register_timer_hook") == sess.kernel_exports.end()
587 || sess.kernel_exports.find("unregister_timer_hook") == sess.kernel_exports.end())
588 && (sess.kernel_exports.find("register_profile_notifier") == sess.kernel_exports.end()
589 || sess.kernel_exports.find("unregister_profile_notifier") == sess.kernel_exports.end()))
dc09353a 590 throw SEMANTIC_ERROR (_("profiling timer support (register_timer_hook) not found in kernel!"));
08357f6b 591
1abafad4
JS
592 sess.unwindsym_modules.insert ("kernel");
593 finished_results.push_back
594 (new profile_derived_probe(sess, base, location));
595 return;
596 }
597
912e8c59
JS
598 if (!get_param(parameters, "randomize", rand))
599 rand = 0;
600
601 if (get_param(parameters, "jiffies", period))
602 {
2b5ecafd 603 if (sess.runtime_usermode_p())
dc09353a 604 throw SEMANTIC_ERROR (_("jiffies timer probes not available with the dyninst runtime"));
2b5ecafd 605
912e8c59
JS
606 // always use basic timers for jiffies
607 finished_results.push_back
608 (new timer_derived_probe(base, location, period, rand, false));
609 return;
610 }
611 else if (get_param(parameters, "hz", period))
612 {
613 if (period <= 0)
dc09353a 614 throw SEMANTIC_ERROR (_("frequency must be greater than 0"));
912e8c59
JS
615 period = (1000000000 + period - 1)/period;
616 }
617 else if (get_param(parameters, "s", period) ||
618 get_param(parameters, "sec", period))
619 {
620 scale = 1000000000;
621 period *= scale;
622 rand *= scale;
623 }
624 else if (get_param(parameters, "ms", period) ||
625 get_param(parameters, "msec", period))
626 {
627 scale = 1000000;
628 period *= scale;
629 rand *= scale;
630 }
631 else if (get_param(parameters, "us", period) ||
632 get_param(parameters, "usec", period))
633 {
634 scale = 1000;
635 period *= scale;
636 rand *= scale;
637 }
638 else if (get_param(parameters, "ns", period) ||
639 get_param(parameters, "nsec", period))
640 {
641 // ok
642 }
643 else
dc09353a 644 throw SEMANTIC_ERROR (_("unrecognized timer variant"));
912e8c59
JS
645
646 // Redirect wallclock-time based probes to hrtimer code on recent
647 // enough kernels.
648 if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
649 {
650 // hrtimers didn't exist, so use the old-school timers
651 period = (period + 1000000 - 1)/1000000;
652 rand = (rand + 1000000 - 1)/1000000;
653
654 finished_results.push_back
655 (new timer_derived_probe(base, location, period, rand, true));
656 }
657 else
658 finished_results.push_back
659 (new hrtimer_derived_probe(base, location, period, rand, scale));
660}
661
662void
663register_tapset_timers(systemtap_session& s)
664{
665 match_node* root = s.pattern_root;
666 derived_probe_builder *builder = new timer_builder();
667
668 root = root->bind(TOK_TIMER);
669
b12c8986 670 root->bind_num("s")
f66bb29a 671 ->bind_privilege(pr_all)
b12c8986
DB
672 ->bind(builder);
673 root->bind_num("s")->bind_num("randomize")
f66bb29a 674 ->bind_privilege(pr_all)
b12c8986
DB
675 ->bind(builder);
676 root->bind_num("sec")
f66bb29a 677 ->bind_privilege(pr_all)
b12c8986
DB
678 ->bind(builder);
679 root->bind_num("sec")->bind_num("randomize")
f66bb29a 680 ->bind_privilege(pr_all)
b12c8986
DB
681 ->bind(builder);
682
683 root->bind_num("ms")
f66bb29a 684 ->bind_privilege(pr_all)
b12c8986
DB
685 ->bind(builder);
686 root->bind_num("ms")->bind_num("randomize")
f66bb29a 687 ->bind_privilege(pr_all)
b12c8986
DB
688 ->bind(builder);
689 root->bind_num("msec")
f66bb29a 690 ->bind_privilege(pr_all)
b12c8986
DB
691 ->bind(builder);
692 root->bind_num("msec")->bind_num("randomize")
f66bb29a 693 ->bind_privilege(pr_all)
b12c8986
DB
694 ->bind(builder);
695
696 root->bind_num("us")
f66bb29a 697 ->bind_privilege(pr_all)
b12c8986
DB
698 ->bind(builder);
699 root->bind_num("us")->bind_num("randomize")
f66bb29a 700 ->bind_privilege(pr_all)
b12c8986
DB
701 ->bind(builder);
702 root->bind_num("usec")
f66bb29a 703 ->bind_privilege(pr_all)
b12c8986
DB
704 ->bind(builder);
705 root->bind_num("usec")->bind_num("randomize")
f66bb29a 706 ->bind_privilege(pr_all)
b12c8986
DB
707 ->bind(builder);
708
709 root->bind_num("ns")
f66bb29a 710 ->bind_privilege(pr_all)
b12c8986
DB
711 ->bind(builder);
712 root->bind_num("ns")->bind_num("randomize")
f66bb29a 713 ->bind_privilege(pr_all)
b12c8986
DB
714 ->bind(builder);
715 root->bind_num("nsec")
f66bb29a 716 ->bind_privilege(pr_all)
b12c8986
DB
717 ->bind(builder);
718 root->bind_num("nsec")->bind_num("randomize")
f66bb29a 719 ->bind_privilege(pr_all)
b12c8986
DB
720 ->bind(builder);
721
722 root->bind_num("jiffies")
f66bb29a 723 ->bind_privilege(pr_all)
b12c8986
DB
724 ->bind(builder);
725 root->bind_num("jiffies")->bind_num("randomize")
f66bb29a 726 ->bind_privilege(pr_all)
b12c8986
DB
727 ->bind(builder);
728
729 root->bind_num("hz")
f66bb29a 730 ->bind_privilege(pr_all)
b12c8986
DB
731 ->bind(builder);
732
2b5ecafd
DS
733 // Not ok for unprivileged users, because register_timer_hook only
734 // allows a single attached callback. No resource-sharing -> no
735 // unprivileged access.
736 //
737 // Sigh, but for dyninst users, we want a semantic error that
738 // profile probes aren't supported (which will come from
739 // timer_builder::build()), not a privilege error. So, we'll fake
740 // it so that profile probes are allowed for all.
741 if (!s.runtime_usermode_p()) {
742 root->bind("profile")
08357f6b 743 ->bind("tick")
2b5ecafd
DS
744 ->bind(builder);
745 }
746 else {
747 root->bind("profile")
08357f6b 748 ->bind("tick")
2b5ecafd
DS
749 ->bind_privilege(pr_all)
750 ->bind(builder);
751 }
912e8c59
JS
752}
753
754
755
756/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.232012 seconds and 5 git commands to generate.