diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-03-02 16:38:31 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-02 16:38:31 -0500 |
| commit | ed662d9b2a6cb26e1399f57b88b565c0a68c60d4 (patch) | |
| tree | 4cca36ab5aa5aa08b799c8f9bbe3888b55682694 /kernel | |
| parent | fdfa66ab455c79d699833c43ac0e09900133fd7c (diff) | |
| parent | 96ccd21cd13140221bda74a4fc4e53ffeba7c7d4 (diff) | |
Merge branch 'tip/tracing/ftrace' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into tracing/ftrace
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace.c | 17 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 9 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 94 | ||||
| -rw-r--r-- | kernel/trace/trace_events_stage_1.h | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_events_stage_2.h | 58 | ||||
| -rw-r--r-- | kernel/trace/trace_events_stage_3.h | 16 |
6 files changed, 182 insertions, 14 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c5e39cd7310d..ea055aa21cd9 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -342,13 +342,6 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu) | |||
| 342 | tracing_record_cmdline(tsk); | 342 | tracing_record_cmdline(tsk); |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | static void | ||
| 346 | trace_seq_reset(struct trace_seq *s) | ||
| 347 | { | ||
| 348 | s->len = 0; | ||
| 349 | s->readpos = 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) | 345 | ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) |
| 353 | { | 346 | { |
| 354 | int len; | 347 | int len; |
| @@ -395,7 +388,7 @@ trace_print_seq(struct seq_file *m, struct trace_seq *s) | |||
| 395 | s->buffer[len] = 0; | 388 | s->buffer[len] = 0; |
| 396 | seq_puts(m, s->buffer); | 389 | seq_puts(m, s->buffer); |
| 397 | 390 | ||
| 398 | trace_seq_reset(s); | 391 | trace_seq_init(s); |
| 399 | } | 392 | } |
| 400 | 393 | ||
| 401 | /** | 394 | /** |
| @@ -2620,7 +2613,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf, | |||
| 2620 | if (sret != -EBUSY) | 2613 | if (sret != -EBUSY) |
| 2621 | return sret; | 2614 | return sret; |
| 2622 | 2615 | ||
| 2623 | trace_seq_reset(&iter->seq); | 2616 | trace_seq_init(&iter->seq); |
| 2624 | 2617 | ||
| 2625 | /* copy the tracer to avoid using a global lock all around */ | 2618 | /* copy the tracer to avoid using a global lock all around */ |
| 2626 | mutex_lock(&trace_types_lock); | 2619 | mutex_lock(&trace_types_lock); |
| @@ -2682,7 +2675,7 @@ waitagain: | |||
| 2682 | /* Now copy what we have to the user */ | 2675 | /* Now copy what we have to the user */ |
| 2683 | sret = trace_seq_to_user(&iter->seq, ubuf, cnt); | 2676 | sret = trace_seq_to_user(&iter->seq, ubuf, cnt); |
| 2684 | if (iter->seq.readpos >= iter->seq.len) | 2677 | if (iter->seq.readpos >= iter->seq.len) |
| 2685 | trace_seq_reset(&iter->seq); | 2678 | trace_seq_init(&iter->seq); |
| 2686 | 2679 | ||
| 2687 | /* | 2680 | /* |
| 2688 | * If there was nothing to send to user, inspite of consuming trace | 2681 | * If there was nothing to send to user, inspite of consuming trace |
| @@ -2819,7 +2812,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp, | |||
| 2819 | partial[i].offset = 0; | 2812 | partial[i].offset = 0; |
| 2820 | partial[i].len = iter->seq.len; | 2813 | partial[i].len = iter->seq.len; |
| 2821 | 2814 | ||
| 2822 | trace_seq_reset(&iter->seq); | 2815 | trace_seq_init(&iter->seq); |
| 2823 | } | 2816 | } |
| 2824 | 2817 | ||
| 2825 | mutex_unlock(&iter->mutex); | 2818 | mutex_unlock(&iter->mutex); |
| @@ -3631,7 +3624,7 @@ trace_printk_seq(struct trace_seq *s) | |||
| 3631 | 3624 | ||
| 3632 | printk(KERN_TRACE "%s", s->buffer); | 3625 | printk(KERN_TRACE "%s", s->buffer); |
| 3633 | 3626 | ||
| 3634 | trace_seq_reset(s); | 3627 | trace_seq_init(s); |
| 3635 | } | 3628 | } |
| 3636 | 3629 | ||
| 3637 | void ftrace_dump(void) | 3630 | void ftrace_dump(void) |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index f6fa0b9f83a8..e606633fb498 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -395,6 +395,14 @@ struct trace_seq { | |||
| 395 | unsigned int readpos; | 395 | unsigned int readpos; |
| 396 | }; | 396 | }; |
| 397 | 397 | ||
| 398 | static inline void | ||
| 399 | trace_seq_init(struct trace_seq *s) | ||
| 400 | { | ||
| 401 | s->len = 0; | ||
| 402 | s->readpos = 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | |||
| 398 | #define TRACE_PIPE_ALL_CPU -1 | 406 | #define TRACE_PIPE_ALL_CPU -1 |
| 399 | 407 | ||
| 400 | /* | 408 | /* |
| @@ -746,6 +754,7 @@ struct ftrace_event_call { | |||
| 746 | int (*raw_init)(void); | 754 | int (*raw_init)(void); |
| 747 | int (*raw_reg)(void); | 755 | int (*raw_reg)(void); |
| 748 | void (*raw_unreg)(void); | 756 | void (*raw_unreg)(void); |
| 757 | int (*show_format)(struct trace_seq *s); | ||
| 749 | }; | 758 | }; |
| 750 | 759 | ||
| 751 | void event_trace_printk(unsigned long ip, const char *fmt, ...); | 760 | void event_trace_printk(unsigned long ip, const char *fmt, ...); |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 1d07f800a9ce..210e71ff82db 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -3,6 +3,9 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | 4 | * Copyright (C) 2008 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> |
| 5 | * | 5 | * |
| 6 | * - Added format output of fields of the trace point. | ||
| 7 | * This was based off of work by Tom Zanussi <tzanussi@gmail.com>. | ||
| 8 | * | ||
| 6 | */ | 9 | */ |
| 7 | 10 | ||
| 8 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
| @@ -10,10 +13,12 @@ | |||
| 10 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 11 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
| 12 | 15 | ||
| 13 | #include "trace.h" | 16 | #include "trace_output.h" |
| 14 | 17 | ||
| 15 | #define TRACE_SYSTEM "TRACE_SYSTEM" | 18 | #define TRACE_SYSTEM "TRACE_SYSTEM" |
| 16 | 19 | ||
| 20 | static DEFINE_MUTEX(event_mutex); | ||
| 21 | |||
| 17 | #define events_for_each(event) \ | 22 | #define events_for_each(event) \ |
| 18 | for (event = __start_ftrace_events; \ | 23 | for (event = __start_ftrace_events; \ |
| 19 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | 24 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ |
| @@ -104,6 +109,7 @@ static int ftrace_set_clr_event(char *buf, int set) | |||
| 104 | event = NULL; | 109 | event = NULL; |
| 105 | } | 110 | } |
| 106 | 111 | ||
| 112 | mutex_lock(&event_mutex); | ||
| 107 | events_for_each(call) { | 113 | events_for_each(call) { |
| 108 | 114 | ||
| 109 | if (!call->name) | 115 | if (!call->name) |
| @@ -124,6 +130,8 @@ static int ftrace_set_clr_event(char *buf, int set) | |||
| 124 | 130 | ||
| 125 | ret = 0; | 131 | ret = 0; |
| 126 | } | 132 | } |
| 133 | mutex_unlock(&event_mutex); | ||
| 134 | |||
| 127 | return ret; | 135 | return ret; |
| 128 | } | 136 | } |
| 129 | 137 | ||
| @@ -324,7 +332,9 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
| 324 | switch (val) { | 332 | switch (val) { |
| 325 | case 0: | 333 | case 0: |
| 326 | case 1: | 334 | case 1: |
| 335 | mutex_lock(&event_mutex); | ||
| 327 | ftrace_event_enable_disable(call, val); | 336 | ftrace_event_enable_disable(call, val); |
| 337 | mutex_unlock(&event_mutex); | ||
| 328 | break; | 338 | break; |
| 329 | 339 | ||
| 330 | default: | 340 | default: |
| @@ -437,6 +447,71 @@ event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
| 437 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | 447 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
| 438 | } | 448 | } |
| 439 | 449 | ||
| 450 | #undef FIELD | ||
| 451 | #define FIELD(type, name) \ | ||
| 452 | #type, #name, offsetof(typeof(field), name), sizeof(field.name) | ||
| 453 | |||
| 454 | static int trace_write_header(struct trace_seq *s) | ||
| 455 | { | ||
| 456 | struct trace_entry field; | ||
| 457 | |||
| 458 | /* struct trace_entry */ | ||
| 459 | return trace_seq_printf(s, | ||
| 460 | "\tfield:%s %s;\toffset:%lu;\tsize:%lu;\n" | ||
| 461 | "\tfield:%s %s;\toffset:%lu;\tsize:%lu;\n" | ||
| 462 | "\tfield:%s %s;\toffset:%lu;\tsize:%lu;\n" | ||
| 463 | "\tfield:%s %s;\toffset:%lu;\tsize:%lu;\n" | ||
| 464 | "\tfield:%s %s;\toffset:%lu;\tsize:%lu;\n" | ||
| 465 | "\n", | ||
| 466 | FIELD(unsigned char, type), | ||
| 467 | FIELD(unsigned char, flags), | ||
| 468 | FIELD(unsigned char, preempt_count), | ||
| 469 | FIELD(int, pid), | ||
| 470 | FIELD(int, tgid)); | ||
| 471 | } | ||
| 472 | static ssize_t | ||
| 473 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
| 474 | loff_t *ppos) | ||
| 475 | { | ||
| 476 | struct ftrace_event_call *call = filp->private_data; | ||
| 477 | struct trace_seq *s; | ||
| 478 | char *buf; | ||
| 479 | int r; | ||
| 480 | |||
| 481 | s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
| 482 | if (!s) | ||
| 483 | return -ENOMEM; | ||
| 484 | |||
| 485 | trace_seq_init(s); | ||
| 486 | |||
| 487 | if (*ppos) | ||
| 488 | return 0; | ||
| 489 | |||
| 490 | /* If any of the first writes fail, so will the show_format. */ | ||
| 491 | |||
| 492 | trace_seq_printf(s, "name: %s\n", call->name); | ||
| 493 | trace_seq_printf(s, "ID: %d\n", call->id); | ||
| 494 | trace_seq_printf(s, "format:\n"); | ||
| 495 | trace_write_header(s); | ||
| 496 | |||
| 497 | r = call->show_format(s); | ||
| 498 | if (!r) { | ||
| 499 | /* | ||
| 500 | * ug! The format output is bigger than a PAGE!! | ||
| 501 | */ | ||
| 502 | buf = "FORMAT TOO BIG\n"; | ||
| 503 | r = simple_read_from_buffer(ubuf, cnt, ppos, | ||
| 504 | buf, strlen(buf)); | ||
| 505 | goto out; | ||
| 506 | } | ||
| 507 | |||
| 508 | r = simple_read_from_buffer(ubuf, cnt, ppos, | ||
| 509 | s->buffer, s->len); | ||
| 510 | out: | ||
| 511 | kfree(s); | ||
| 512 | return r; | ||
| 513 | } | ||
| 514 | |||
| 440 | static const struct seq_operations show_event_seq_ops = { | 515 | static const struct seq_operations show_event_seq_ops = { |
| 441 | .start = t_start, | 516 | .start = t_start, |
| 442 | .next = t_next, | 517 | .next = t_next, |
| @@ -483,6 +558,11 @@ static const struct file_operations ftrace_available_types_fops = { | |||
| 483 | .read = event_available_types_read, | 558 | .read = event_available_types_read, |
| 484 | }; | 559 | }; |
| 485 | 560 | ||
| 561 | static const struct file_operations ftrace_event_format_fops = { | ||
| 562 | .open = tracing_open_generic, | ||
| 563 | .read = event_format_read, | ||
| 564 | }; | ||
| 565 | |||
| 486 | static struct dentry *event_trace_events_dir(void) | 566 | static struct dentry *event_trace_events_dir(void) |
| 487 | { | 567 | { |
| 488 | static struct dentry *d_tracer; | 568 | static struct dentry *d_tracer; |
| @@ -595,7 +675,17 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
| 595 | &ftrace_available_types_fops); | 675 | &ftrace_available_types_fops); |
| 596 | if (!entry) | 676 | if (!entry) |
| 597 | pr_warning("Could not create debugfs " | 677 | pr_warning("Could not create debugfs " |
| 598 | "'%s/type' available_types\n", call->name); | 678 | "'%s/available_types' entry\n", call->name); |
| 679 | |||
| 680 | /* A trace may not want to export its format */ | ||
| 681 | if (!call->show_format) | ||
| 682 | return 0; | ||
| 683 | |||
| 684 | entry = debugfs_create_file("format", 0444, call->dir, call, | ||
| 685 | &ftrace_event_format_fops); | ||
| 686 | if (!entry) | ||
| 687 | pr_warning("Could not create debugfs " | ||
| 688 | "'%s/format' entry\n", call->name); | ||
| 599 | 689 | ||
| 600 | return 0; | 690 | return 0; |
| 601 | } | 691 | } |
diff --git a/kernel/trace/trace_events_stage_1.h b/kernel/trace/trace_events_stage_1.h index fd3bf9382d37..3830a731424c 100644 --- a/kernel/trace/trace_events_stage_1.h +++ b/kernel/trace/trace_events_stage_1.h | |||
| @@ -30,5 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | #define TRACE_FIELD(type, item, assign) \ | 31 | #define TRACE_FIELD(type, item, assign) \ |
| 32 | type item; | 32 | type item; |
| 33 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
| 34 | type_item; | ||
| 33 | 35 | ||
| 34 | #include <trace/trace_event_types.h> | 36 | #include <trace/trace_event_types.h> |
diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h index 3eaaef5f19e1..b1cebba1d9b4 100644 --- a/kernel/trace/trace_events_stage_2.h +++ b/kernel/trace/trace_events_stage_2.h | |||
| @@ -39,6 +39,10 @@ | |||
| 39 | #define TRACE_FIELD(type, item, assign) \ | 39 | #define TRACE_FIELD(type, item, assign) \ |
| 40 | field->item, | 40 | field->item, |
| 41 | 41 | ||
| 42 | #undef TRACE_FIELD_SPECIAL | ||
| 43 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
| 44 | field->item, | ||
| 45 | |||
| 42 | 46 | ||
| 43 | #undef TPRAWFMT | 47 | #undef TPRAWFMT |
| 44 | #define TPRAWFMT(args...) args | 48 | #define TPRAWFMT(args...) args |
| @@ -70,3 +74,57 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | |||
| 70 | } | 74 | } |
| 71 | 75 | ||
| 72 | #include <trace/trace_event_types.h> | 76 | #include <trace/trace_event_types.h> |
| 77 | |||
| 78 | /* | ||
| 79 | * Setup the showing format of trace point. | ||
| 80 | * | ||
| 81 | * int | ||
| 82 | * ftrace_format_##call(struct trace_seq *s) | ||
| 83 | * { | ||
| 84 | * struct ftrace_raw_##call field; | ||
| 85 | * int ret; | ||
| 86 | * | ||
| 87 | * ret = trace_seq_printf(s, #type " " #item ";" | ||
| 88 | * " size:%d; offset:%d;\n", | ||
| 89 | * sizeof(field.type), | ||
| 90 | * offsetof(struct ftrace_raw_##call, | ||
| 91 | * item)); | ||
| 92 | * | ||
| 93 | * } | ||
| 94 | */ | ||
| 95 | |||
| 96 | #undef TRACE_FIELD | ||
| 97 | #define TRACE_FIELD(type, item, assign) \ | ||
| 98 | ret = trace_seq_printf(s, "\tfield:" #type " " #item ";\t" \ | ||
| 99 | "offset:%lu;\tsize:%lu;\n", \ | ||
| 100 | offsetof(typeof(field), item), \ | ||
| 101 | sizeof(field.item)); \ | ||
| 102 | if (!ret) \ | ||
| 103 | return 0; | ||
| 104 | |||
| 105 | |||
| 106 | #undef TRACE_FIELD_SPECIAL | ||
| 107 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
| 108 | ret = trace_seq_printf(s, "\tfield special:" #type_item ";\t" \ | ||
| 109 | "offset:%lu;\tsize:%lu;\n", \ | ||
| 110 | offsetof(typeof(field), item), \ | ||
| 111 | sizeof(field.item)); \ | ||
| 112 | if (!ret) \ | ||
| 113 | return 0; | ||
| 114 | |||
| 115 | #undef TRACE_EVENT_FORMAT | ||
| 116 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
| 117 | int \ | ||
| 118 | ftrace_format_##call(struct trace_seq *s) \ | ||
| 119 | { \ | ||
| 120 | struct ftrace_raw_##call field; \ | ||
| 121 | int ret; \ | ||
| 122 | \ | ||
| 123 | tstruct; \ | ||
| 124 | \ | ||
| 125 | trace_seq_printf(s, "\nprint fmt: \"%s\"\n", tpfmt); \ | ||
| 126 | \ | ||
| 127 | return ret; \ | ||
| 128 | } | ||
| 129 | |||
| 130 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h index 7a161c49deb4..c62a4d2a5283 100644 --- a/kernel/trace/trace_events_stage_3.h +++ b/kernel/trace/trace_events_stage_3.h | |||
| @@ -101,6 +101,7 @@ | |||
| 101 | * .raw_init = ftrace_raw_init_event_<call>, | 101 | * .raw_init = ftrace_raw_init_event_<call>, |
| 102 | * .raw_reg = ftrace_raw_reg_event_<call>, | 102 | * .raw_reg = ftrace_raw_reg_event_<call>, |
| 103 | * .raw_unreg = ftrace_raw_unreg_event_<call>, | 103 | * .raw_unreg = ftrace_raw_unreg_event_<call>, |
| 104 | * .show_format = ftrace_format_<call>, | ||
| 104 | * } | 105 | * } |
| 105 | * | 106 | * |
| 106 | */ | 107 | */ |
| @@ -147,6 +148,20 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 147 | #define TRACE_FIELD(type, item, assign)\ | 148 | #define TRACE_FIELD(type, item, assign)\ |
| 148 | entry->item = assign; | 149 | entry->item = assign; |
| 149 | 150 | ||
| 151 | #undef TRACE_FIELD | ||
| 152 | #define TRACE_FIELD(type, item, assign)\ | ||
| 153 | entry->item = assign; | ||
| 154 | |||
| 155 | #undef TPCMD | ||
| 156 | #define TPCMD(cmd...) cmd | ||
| 157 | |||
| 158 | #undef TRACE_ENTRY | ||
| 159 | #define TRACE_ENTRY entry | ||
| 160 | |||
| 161 | #undef TRACE_FIELD_SPECIAL | ||
| 162 | #define TRACE_FIELD_SPECIAL(type_item, item, cmd) \ | ||
| 163 | cmd; | ||
| 164 | |||
| 150 | #undef TRACE_EVENT_FORMAT | 165 | #undef TRACE_EVENT_FORMAT |
| 151 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | 166 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ |
| 152 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ | 167 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ |
| @@ -216,4 +231,5 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 216 | .raw_init = ftrace_raw_init_event_##call, \ | 231 | .raw_init = ftrace_raw_init_event_##call, \ |
| 217 | .raw_reg = ftrace_raw_reg_event_##call, \ | 232 | .raw_reg = ftrace_raw_reg_event_##call, \ |
| 218 | .raw_unreg = ftrace_raw_unreg_event_##call, \ | 233 | .raw_unreg = ftrace_raw_unreg_event_##call, \ |
| 234 | .show_format = ftrace_format_##call, \ | ||
| 219 | } | 235 | } |
