diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-28 02:41:25 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-28 04:04:03 -0500 |
commit | fd99498989f3b3feeab89dcadf537138ba136d24 (patch) | |
tree | 9470e9b4e886466511d47a70281e77e5a8c674ff /kernel/trace/trace_events.c | |
parent | c32e827b25054cb17b79cf97fb5e63ae4ce2223c (diff) |
tracing: add raw fast tracing interface for trace events
This patch adds the interface to enable the C style trace points.
In the directory /debugfs/tracing/events/subsystem/event
We now have three files:
enable : values 0 or 1 to enable or disable the trace event.
available_types: values 'raw' and 'printf' which indicate the tracing
types available for the trace point. If a developer does not
use the TRACE_EVENT_FORMAT macro and just uses the TRACE_FORMAT
macro, then only 'printf' will be available. This file is
read only.
type: values 'raw' or 'printf'. This indicates which type of tracing
is active for that trace point. 'printf' is the default and
if 'raw' is not available, this file is read only.
# echo raw > /debug/tracing/events/sched/sched_wakeup/type
# echo 1 > /debug/tracing/events/sched/sched_wakeup/enable
Will enable the C style tracing for the sched_wakeup trace point.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r-- | kernel/trace/trace_events.c | 199 |
1 files changed, 174 insertions, 25 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 77a5c02bd634..1d07f800a9ce 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -44,6 +44,36 @@ static void ftrace_clear_events(void) | |||
44 | } | 44 | } |
45 | } | 45 | } |
46 | 46 | ||
47 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, | ||
48 | int enable) | ||
49 | { | ||
50 | |||
51 | switch (enable) { | ||
52 | case 0: | ||
53 | if (call->enabled) { | ||
54 | call->enabled = 0; | ||
55 | call->unregfunc(); | ||
56 | } | ||
57 | if (call->raw_enabled) { | ||
58 | call->raw_enabled = 0; | ||
59 | call->raw_unreg(); | ||
60 | } | ||
61 | break; | ||
62 | case 1: | ||
63 | if (!call->enabled && | ||
64 | (call->type & TRACE_EVENT_TYPE_PRINTF)) { | ||
65 | call->enabled = 1; | ||
66 | call->regfunc(); | ||
67 | } | ||
68 | if (!call->raw_enabled && | ||
69 | (call->type & TRACE_EVENT_TYPE_RAW)) { | ||
70 | call->raw_enabled = 1; | ||
71 | call->raw_reg(); | ||
72 | } | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
47 | static int ftrace_set_clr_event(char *buf, int set) | 77 | static int ftrace_set_clr_event(char *buf, int set) |
48 | { | 78 | { |
49 | struct ftrace_event_call *call = __start_ftrace_events; | 79 | struct ftrace_event_call *call = __start_ftrace_events; |
@@ -90,19 +120,8 @@ static int ftrace_set_clr_event(char *buf, int set) | |||
90 | if (event && strcmp(event, call->name) != 0) | 120 | if (event && strcmp(event, call->name) != 0) |
91 | continue; | 121 | continue; |
92 | 122 | ||
93 | if (set) { | 123 | ftrace_event_enable_disable(call, set); |
94 | /* Already set? */ | 124 | |
95 | if (call->enabled) | ||
96 | return 0; | ||
97 | call->enabled = 1; | ||
98 | call->regfunc(); | ||
99 | } else { | ||
100 | /* Already cleared? */ | ||
101 | if (!call->enabled) | ||
102 | return 0; | ||
103 | call->enabled = 0; | ||
104 | call->unregfunc(); | ||
105 | } | ||
106 | ret = 0; | 125 | ret = 0; |
107 | } | 126 | } |
108 | return ret; | 127 | return ret; |
@@ -273,7 +292,7 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
273 | struct ftrace_event_call *call = filp->private_data; | 292 | struct ftrace_event_call *call = filp->private_data; |
274 | char *buf; | 293 | char *buf; |
275 | 294 | ||
276 | if (call->enabled) | 295 | if (call->enabled || call->raw_enabled) |
277 | buf = "1\n"; | 296 | buf = "1\n"; |
278 | else | 297 | else |
279 | buf = "0\n"; | 298 | buf = "0\n"; |
@@ -304,18 +323,8 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
304 | 323 | ||
305 | switch (val) { | 324 | switch (val) { |
306 | case 0: | 325 | case 0: |
307 | if (!call->enabled) | ||
308 | break; | ||
309 | |||
310 | call->enabled = 0; | ||
311 | call->unregfunc(); | ||
312 | break; | ||
313 | case 1: | 326 | case 1: |
314 | if (call->enabled) | 327 | ftrace_event_enable_disable(call, val); |
315 | break; | ||
316 | |||
317 | call->enabled = 1; | ||
318 | call->regfunc(); | ||
319 | break; | 328 | break; |
320 | 329 | ||
321 | default: | 330 | default: |
@@ -327,6 +336,107 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
327 | return cnt; | 336 | return cnt; |
328 | } | 337 | } |
329 | 338 | ||
339 | static ssize_t | ||
340 | event_type_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
341 | loff_t *ppos) | ||
342 | { | ||
343 | struct ftrace_event_call *call = filp->private_data; | ||
344 | char buf[16]; | ||
345 | int r = 0; | ||
346 | |||
347 | if (call->type & TRACE_EVENT_TYPE_PRINTF) | ||
348 | r += sprintf(buf, "printf\n"); | ||
349 | |||
350 | if (call->type & TRACE_EVENT_TYPE_RAW) | ||
351 | r += sprintf(buf+r, "raw\n"); | ||
352 | |||
353 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
354 | } | ||
355 | |||
356 | static ssize_t | ||
357 | event_type_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
358 | loff_t *ppos) | ||
359 | { | ||
360 | struct ftrace_event_call *call = filp->private_data; | ||
361 | char buf[64]; | ||
362 | |||
363 | /* | ||
364 | * If there's only one type, we can't change it. | ||
365 | * And currently we always have printf type, and we | ||
366 | * may or may not have raw type. | ||
367 | * | ||
368 | * This is a redundant check, the file should be read | ||
369 | * only if this is the case anyway. | ||
370 | */ | ||
371 | |||
372 | if (!call->raw_init) | ||
373 | return -EPERM; | ||
374 | |||
375 | if (cnt >= sizeof(buf)) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (copy_from_user(&buf, ubuf, cnt)) | ||
379 | return -EFAULT; | ||
380 | |||
381 | buf[cnt] = 0; | ||
382 | |||
383 | if (!strncmp(buf, "printf", 6) && | ||
384 | (!buf[6] || isspace(buf[6]))) { | ||
385 | |||
386 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
387 | |||
388 | /* | ||
389 | * If raw enabled, the disable it and enable | ||
390 | * printf type. | ||
391 | */ | ||
392 | if (call->raw_enabled) { | ||
393 | call->raw_enabled = 0; | ||
394 | call->raw_unreg(); | ||
395 | |||
396 | call->enabled = 1; | ||
397 | call->regfunc(); | ||
398 | } | ||
399 | |||
400 | } else if (!strncmp(buf, "raw", 3) && | ||
401 | (!buf[3] || isspace(buf[3]))) { | ||
402 | |||
403 | call->type = TRACE_EVENT_TYPE_RAW; | ||
404 | |||
405 | /* | ||
406 | * If printf enabled, the disable it and enable | ||
407 | * raw type. | ||
408 | */ | ||
409 | if (call->enabled) { | ||
410 | call->enabled = 0; | ||
411 | call->unregfunc(); | ||
412 | |||
413 | call->raw_enabled = 1; | ||
414 | call->raw_reg(); | ||
415 | } | ||
416 | } else | ||
417 | return -EINVAL; | ||
418 | |||
419 | *ppos += cnt; | ||
420 | |||
421 | return cnt; | ||
422 | } | ||
423 | |||
424 | static ssize_t | ||
425 | event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
426 | loff_t *ppos) | ||
427 | { | ||
428 | struct ftrace_event_call *call = filp->private_data; | ||
429 | char buf[16]; | ||
430 | int r = 0; | ||
431 | |||
432 | r += sprintf(buf, "printf\n"); | ||
433 | |||
434 | if (call->raw_init) | ||
435 | r += sprintf(buf+r, "raw\n"); | ||
436 | |||
437 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
438 | } | ||
439 | |||
330 | static const struct seq_operations show_event_seq_ops = { | 440 | static const struct seq_operations show_event_seq_ops = { |
331 | .start = t_start, | 441 | .start = t_start, |
332 | .next = t_next, | 442 | .next = t_next, |
@@ -362,6 +472,17 @@ static const struct file_operations ftrace_enable_fops = { | |||
362 | .write = event_enable_write, | 472 | .write = event_enable_write, |
363 | }; | 473 | }; |
364 | 474 | ||
475 | static const struct file_operations ftrace_type_fops = { | ||
476 | .open = tracing_open_generic, | ||
477 | .read = event_type_read, | ||
478 | .write = event_type_write, | ||
479 | }; | ||
480 | |||
481 | static const struct file_operations ftrace_available_types_fops = { | ||
482 | .open = tracing_open_generic, | ||
483 | .read = event_available_types_read, | ||
484 | }; | ||
485 | |||
365 | static struct dentry *event_trace_events_dir(void) | 486 | static struct dentry *event_trace_events_dir(void) |
366 | { | 487 | { |
367 | static struct dentry *d_tracer; | 488 | static struct dentry *d_tracer; |
@@ -427,6 +548,7 @@ static int | |||
427 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | 548 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) |
428 | { | 549 | { |
429 | struct dentry *entry; | 550 | struct dentry *entry; |
551 | int ret; | ||
430 | 552 | ||
431 | /* | 553 | /* |
432 | * If the trace point header did not define TRACE_SYSTEM | 554 | * If the trace point header did not define TRACE_SYSTEM |
@@ -435,6 +557,18 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
435 | if (strcmp(call->system, "TRACE_SYSTEM") != 0) | 557 | if (strcmp(call->system, "TRACE_SYSTEM") != 0) |
436 | d_events = event_subsystem_dir(call->system, d_events); | 558 | d_events = event_subsystem_dir(call->system, d_events); |
437 | 559 | ||
560 | if (call->raw_init) { | ||
561 | ret = call->raw_init(); | ||
562 | if (ret < 0) { | ||
563 | pr_warning("Could not initialize trace point" | ||
564 | " events/%s\n", call->name); | ||
565 | return ret; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | /* default the output to printf */ | ||
570 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
571 | |||
438 | call->dir = debugfs_create_dir(call->name, d_events); | 572 | call->dir = debugfs_create_dir(call->name, d_events); |
439 | if (!call->dir) { | 573 | if (!call->dir) { |
440 | pr_warning("Could not create debugfs " | 574 | pr_warning("Could not create debugfs " |
@@ -448,6 +582,21 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
448 | pr_warning("Could not create debugfs " | 582 | pr_warning("Could not create debugfs " |
449 | "'%s/enable' entry\n", call->name); | 583 | "'%s/enable' entry\n", call->name); |
450 | 584 | ||
585 | /* Only let type be writable, if we can change it */ | ||
586 | entry = debugfs_create_file("type", | ||
587 | call->raw_init ? 0644 : 0444, | ||
588 | call->dir, call, | ||
589 | &ftrace_type_fops); | ||
590 | if (!entry) | ||
591 | pr_warning("Could not create debugfs " | ||
592 | "'%s/type' entry\n", call->name); | ||
593 | |||
594 | entry = debugfs_create_file("available_types", 0444, call->dir, call, | ||
595 | &ftrace_available_types_fops); | ||
596 | if (!entry) | ||
597 | pr_warning("Could not create debugfs " | ||
598 | "'%s/type' available_types\n", call->name); | ||
599 | |||
451 | return 0; | 600 | return 0; |
452 | } | 601 | } |
453 | 602 | ||