aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-02-28 02:41:25 -0500
committerSteven Rostedt <srostedt@redhat.com>2009-02-28 04:04:03 -0500
commitfd99498989f3b3feeab89dcadf537138ba136d24 (patch)
tree9470e9b4e886466511d47a70281e77e5a8c674ff /kernel/trace/trace_events.c
parentc32e827b25054cb17b79cf97fb5e63ae4ce2223c (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.c199
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
47static 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
47static int ftrace_set_clr_event(char *buf, int set) 77static 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
339static ssize_t
340event_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
356static ssize_t
357event_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
424static ssize_t
425event_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
330static const struct seq_operations show_event_seq_ops = { 440static 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
475static const struct file_operations ftrace_type_fops = {
476 .open = tracing_open_generic,
477 .read = event_type_read,
478 .write = event_type_write,
479};
480
481static const struct file_operations ftrace_available_types_fops = {
482 .open = tracing_open_generic,
483 .read = event_available_types_read,
484};
485
365static struct dentry *event_trace_events_dir(void) 486static 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
427event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) 548event_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