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