aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-03-09 17:14:30 -0400
committerSteven Rostedt <srostedt@redhat.com>2009-03-10 00:35:07 -0400
commitda4d03020c2af32f73e8bfbab0a66620d85bb9bb (patch)
tree3ee6d7d69754df7910454315a6011c14d8664d01 /kernel/trace/trace_events.c
parent9cc26a261d43e5898287a1f5808132f8f05ceb1c (diff)
tracing: new format for specialized trace points
Impact: clean up and enhancement The TRACE_EVENT_FORMAT macro looks quite ugly and is limited in its ability to save data as well as to print the record out. Working with Ingo Molnar, we came up with a new format that is much more pleasing to the eye of C developers. This new macro is more C style than the old macro, and is more obvious to what it does. Here's the example. The only updated macro in this patch is the sched_switch trace point. The old method looked like this: TRACE_EVENT_FORMAT(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next), TP_ARGS(rq, prev, next), TP_FMT("task %s:%d ==> %s:%d", prev->comm, prev->pid, next->comm, next->pid), TRACE_STRUCT( TRACE_FIELD(pid_t, prev_pid, prev->pid) TRACE_FIELD(int, prev_prio, prev->prio) TRACE_FIELD_SPECIAL(char next_comm[TASK_COMM_LEN], next_comm, TP_CMD(memcpy(TRACE_ENTRY->next_comm, next->comm, TASK_COMM_LEN))) TRACE_FIELD(pid_t, next_pid, next->pid) TRACE_FIELD(int, next_prio, next->prio) ), TP_RAW_FMT("prev %d:%d ==> next %s:%d:%d") ); The above method is hard to read and requires two format fields. The new method: /* * Tracepoint for task switches, performed by the scheduler: * * (NOTE: the 'rq' argument is not used by generic trace events, * but used by the latency tracer plugin. ) */ TRACE_EVENT(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next), TP_ARGS(rq, prev, next), TP_STRUCT__entry( __array( char, prev_comm, TASK_COMM_LEN ) __field( pid_t, prev_pid ) __field( int, prev_prio ) __array( char, next_comm, TASK_COMM_LEN ) __field( pid_t, next_pid ) __field( int, next_prio ) ), TP_printk("task %s:%d [%d] ==> %s:%d [%d]", __entry->prev_comm, __entry->prev_pid, __entry->prev_prio, __entry->next_comm, __entry->next_pid, __entry->next_prio), TP_fast_assign( memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN); __entry->prev_pid = prev->pid; __entry->prev_prio = prev->prio; memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN); __entry->next_pid = next->pid; __entry->next_prio = next->prio; ) ); This macro is called TRACE_EVENT, it is broken up into 5 parts: TP_PROTO: the proto type of the trace point TP_ARGS: the arguments of the trace point TP_STRUCT_entry: the structure layout of the entry in the ring buffer TP_printk: the printk format TP_fast_assign: the method used to write the entry into the ring buffer The structure is the definition of how the event will be saved in the ring buffer. The printk is used by the internal tracing in case of an oops, and the kernel needs to print out the format of the record to the console. This the TP_printk gives a means to show the records in a human readable format. It is also used to print out the data from the trace file. The TP_fast_assign is executed directly. It is basically like a C function, where the __entry is the handle to the record. Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c159
1 files changed, 3 insertions, 156 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index fa32ca320767..1880a6438097 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -59,22 +59,12 @@ static void ftrace_event_enable_disable(struct ftrace_event_call *call,
59 call->enabled = 0; 59 call->enabled = 0;
60 call->unregfunc(); 60 call->unregfunc();
61 } 61 }
62 if (call->raw_enabled) {
63 call->raw_enabled = 0;
64 call->raw_unreg();
65 }
66 break; 62 break;
67 case 1: 63 case 1:
68 if (!call->enabled && 64 if (!call->enabled) {
69 (call->type & TRACE_EVENT_TYPE_PRINTF)) {
70 call->enabled = 1; 65 call->enabled = 1;
71 call->regfunc(); 66 call->regfunc();
72 } 67 }
73 if (!call->raw_enabled &&
74 (call->type & TRACE_EVENT_TYPE_RAW)) {
75 call->raw_enabled = 1;
76 call->raw_reg();
77 }
78 break; 68 break;
79 } 69 }
80} 70}
@@ -300,7 +290,7 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
300 struct ftrace_event_call *call = filp->private_data; 290 struct ftrace_event_call *call = filp->private_data;
301 char *buf; 291 char *buf;
302 292
303 if (call->enabled || call->raw_enabled) 293 if (call->enabled)
304 buf = "1\n"; 294 buf = "1\n";
305 else 295 else
306 buf = "0\n"; 296 buf = "0\n";
@@ -346,107 +336,6 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
346 return cnt; 336 return cnt;
347} 337}
348 338
349static ssize_t
350event_type_read(struct file *filp, char __user *ubuf, size_t cnt,
351 loff_t *ppos)
352{
353 struct ftrace_event_call *call = filp->private_data;
354 char buf[16];
355 int r = 0;
356
357 if (call->type & TRACE_EVENT_TYPE_PRINTF)
358 r += sprintf(buf, "printf\n");
359
360 if (call->type & TRACE_EVENT_TYPE_RAW)
361 r += sprintf(buf+r, "raw\n");
362
363 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
364}
365
366static ssize_t
367event_type_write(struct file *filp, const char __user *ubuf, size_t cnt,
368 loff_t *ppos)
369{
370 struct ftrace_event_call *call = filp->private_data;
371 char buf[64];
372
373 /*
374 * If there's only one type, we can't change it.
375 * And currently we always have printf type, and we
376 * may or may not have raw type.
377 *
378 * This is a redundant check, the file should be read
379 * only if this is the case anyway.
380 */
381
382 if (!call->raw_init)
383 return -EPERM;
384
385 if (cnt >= sizeof(buf))
386 return -EINVAL;
387
388 if (copy_from_user(&buf, ubuf, cnt))
389 return -EFAULT;
390
391 buf[cnt] = 0;
392
393 if (!strncmp(buf, "printf", 6) &&
394 (!buf[6] || isspace(buf[6]))) {
395
396 call->type = TRACE_EVENT_TYPE_PRINTF;
397
398 /*
399 * If raw enabled, the disable it and enable
400 * printf type.
401 */
402 if (call->raw_enabled) {
403 call->raw_enabled = 0;
404 call->raw_unreg();
405
406 call->enabled = 1;
407 call->regfunc();
408 }
409
410 } else if (!strncmp(buf, "raw", 3) &&
411 (!buf[3] || isspace(buf[3]))) {
412
413 call->type = TRACE_EVENT_TYPE_RAW;
414
415 /*
416 * If printf enabled, the disable it and enable
417 * raw type.
418 */
419 if (call->enabled) {
420 call->enabled = 0;
421 call->unregfunc();
422
423 call->raw_enabled = 1;
424 call->raw_reg();
425 }
426 } else
427 return -EINVAL;
428
429 *ppos += cnt;
430
431 return cnt;
432}
433
434static ssize_t
435event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt,
436 loff_t *ppos)
437{
438 struct ftrace_event_call *call = filp->private_data;
439 char buf[16];
440 int r = 0;
441
442 r += sprintf(buf, "printf\n");
443
444 if (call->raw_init)
445 r += sprintf(buf+r, "raw\n");
446
447 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
448}
449
450#undef FIELD 339#undef FIELD
451#define FIELD(type, name) \ 340#define FIELD(type, name) \
452 #type, #name, (unsigned int)offsetof(typeof(field), name), \ 341 #type, #name, (unsigned int)offsetof(typeof(field), name), \
@@ -470,6 +359,7 @@ static int trace_write_header(struct trace_seq *s)
470 FIELD(int, pid), 359 FIELD(int, pid),
471 FIELD(int, tgid)); 360 FIELD(int, tgid));
472} 361}
362
473static ssize_t 363static ssize_t
474event_format_read(struct file *filp, char __user *ubuf, size_t cnt, 364event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
475 loff_t *ppos) 365 loff_t *ppos)
@@ -527,13 +417,6 @@ static const struct seq_operations show_set_event_seq_ops = {
527 .stop = t_stop, 417 .stop = t_stop,
528}; 418};
529 419
530static const struct file_operations ftrace_avail_fops = {
531 .open = ftrace_event_seq_open,
532 .read = seq_read,
533 .llseek = seq_lseek,
534 .release = seq_release,
535};
536
537static const struct file_operations ftrace_set_event_fops = { 420static const struct file_operations ftrace_set_event_fops = {
538 .open = ftrace_event_seq_open, 421 .open = ftrace_event_seq_open,
539 .read = seq_read, 422 .read = seq_read,
@@ -548,17 +431,6 @@ static const struct file_operations ftrace_enable_fops = {
548 .write = event_enable_write, 431 .write = event_enable_write,
549}; 432};
550 433
551static const struct file_operations ftrace_type_fops = {
552 .open = tracing_open_generic,
553 .read = event_type_read,
554 .write = event_type_write,
555};
556
557static const struct file_operations ftrace_available_types_fops = {
558 .open = tracing_open_generic,
559 .read = event_available_types_read,
560};
561
562static const struct file_operations ftrace_event_format_fops = { 434static const struct file_operations ftrace_event_format_fops = {
563 .open = tracing_open_generic, 435 .open = tracing_open_generic,
564 .read = event_format_read, 436 .read = event_format_read,
@@ -647,9 +519,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
647 } 519 }
648 } 520 }
649 521
650 /* default the output to printf */
651 call->type = TRACE_EVENT_TYPE_PRINTF;
652
653 call->dir = debugfs_create_dir(call->name, d_events); 522 call->dir = debugfs_create_dir(call->name, d_events);
654 if (!call->dir) { 523 if (!call->dir) {
655 pr_warning("Could not create debugfs " 524 pr_warning("Could not create debugfs "
@@ -665,21 +534,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events)
665 "'%s/enable' entry\n", call->name); 534 "'%s/enable' entry\n", call->name);
666 } 535 }
667 536
668 /* Only let type be writable, if we can change it */
669 entry = debugfs_create_file("type",
670 call->raw_init ? 0644 : 0444,
671 call->dir, call,
672 &ftrace_type_fops);
673 if (!entry)
674 pr_warning("Could not create debugfs "
675 "'%s/type' entry\n", call->name);
676
677 entry = debugfs_create_file("available_types", 0444, call->dir, call,
678 &ftrace_available_types_fops);
679 if (!entry)
680 pr_warning("Could not create debugfs "
681 "'%s/available_types' entry\n", call->name);
682
683 /* A trace may not want to export its format */ 537 /* A trace may not want to export its format */
684 if (!call->show_format) 538 if (!call->show_format)
685 return 0; 539 return 0;
@@ -704,13 +558,6 @@ static __init int event_trace_init(void)
704 if (!d_tracer) 558 if (!d_tracer)
705 return 0; 559 return 0;
706 560
707 entry = debugfs_create_file("available_events", 0444, d_tracer,
708 (void *)&show_event_seq_ops,
709 &ftrace_avail_fops);
710 if (!entry)
711 pr_warning("Could not create debugfs "
712 "'available_events' entry\n");
713
714 entry = debugfs_create_file("set_event", 0644, d_tracer, 561 entry = debugfs_create_file("set_event", 0644, d_tracer,
715 (void *)&show_set_event_seq_ops, 562 (void *)&show_set_event_seq_ops,
716 &ftrace_set_event_fops); 563 &ftrace_set_event_fops);