diff options
| author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-03-19 15:26:15 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-03-20 05:17:07 -0400 |
| commit | ac199db0189c091f2863312061c0575937f68810 (patch) | |
| tree | 0068aaa77ca00102ca60754eb32329f06821bba0 | |
| parent | 28bea271e58e429eccfad3d7ee2ad12d6ee015bf (diff) | |
ftrace: event profile hooks
Impact: new tracing infrastructure feature
Provide infrastructure to generate software perf counter events
from tracepoints.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20090319194233.557364871@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | kernel/trace/Makefile | 1 | ||||
| -rw-r--r-- | kernel/trace/events.c | 1 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 11 | ||||
| -rw-r--r-- | kernel/trace/trace_event_profile.c | 31 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 9 | ||||
| -rw-r--r-- | kernel/trace/trace_events_stage_3.h | 44 |
6 files changed, 89 insertions, 8 deletions
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index c3feea01c3e0..0e45c206c2f9 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
| @@ -44,5 +44,6 @@ obj-$(CONFIG_EVENT_TRACER) += trace_events.o | |||
| 44 | obj-$(CONFIG_EVENT_TRACER) += events.o | 44 | obj-$(CONFIG_EVENT_TRACER) += events.o |
| 45 | obj-$(CONFIG_EVENT_TRACER) += trace_export.o | 45 | obj-$(CONFIG_EVENT_TRACER) += trace_export.o |
| 46 | obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o | 46 | obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o |
| 47 | obj-$(CONFIG_EVENT_PROFILE) += trace_event_profile.o | ||
| 47 | 48 | ||
| 48 | libftrace-y := ftrace.o | 49 | libftrace-y := ftrace.o |
diff --git a/kernel/trace/events.c b/kernel/trace/events.c index 9fc918da404f..246f2aa6dc46 100644 --- a/kernel/trace/events.c +++ b/kernel/trace/events.c | |||
| @@ -12,4 +12,3 @@ | |||
| 12 | #include "trace_events_stage_2.h" | 12 | #include "trace_events_stage_2.h" |
| 13 | #include "trace_events_stage_3.h" | 13 | #include "trace_events_stage_3.h" |
| 14 | 14 | ||
| 15 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 7c9a0cbf5dca..7cfb741be200 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -785,12 +785,23 @@ struct ftrace_event_call { | |||
| 785 | int id; | 785 | int id; |
| 786 | int (*raw_init)(void); | 786 | int (*raw_init)(void); |
| 787 | int (*show_format)(struct trace_seq *s); | 787 | int (*show_format)(struct trace_seq *s); |
| 788 | |||
| 789 | #ifdef CONFIG_EVENT_PROFILE | ||
| 790 | atomic_t profile_count; | ||
| 791 | int (*profile_enable)(struct ftrace_event_call *); | ||
| 792 | void (*profile_disable)(struct ftrace_event_call *); | ||
| 793 | #endif | ||
| 788 | }; | 794 | }; |
| 789 | 795 | ||
| 790 | void event_trace_printk(unsigned long ip, const char *fmt, ...); | 796 | void event_trace_printk(unsigned long ip, const char *fmt, ...); |
| 791 | extern struct ftrace_event_call __start_ftrace_events[]; | 797 | extern struct ftrace_event_call __start_ftrace_events[]; |
| 792 | extern struct ftrace_event_call __stop_ftrace_events[]; | 798 | extern struct ftrace_event_call __stop_ftrace_events[]; |
| 793 | 799 | ||
| 800 | #define for_each_event(event) \ | ||
| 801 | for (event = __start_ftrace_events; \ | ||
| 802 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | ||
| 803 | event++) | ||
| 804 | |||
| 794 | extern const char *__start___trace_bprintk_fmt[]; | 805 | extern const char *__start___trace_bprintk_fmt[]; |
| 795 | extern const char *__stop___trace_bprintk_fmt[]; | 806 | extern const char *__stop___trace_bprintk_fmt[]; |
| 796 | 807 | ||
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c new file mode 100644 index 000000000000..22cba9970776 --- /dev/null +++ b/kernel/trace/trace_event_profile.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * trace event based perf counter profiling | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com> | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "trace.h" | ||
| 9 | |||
| 10 | int ftrace_profile_enable(int event_id) | ||
| 11 | { | ||
| 12 | struct ftrace_event_call *event; | ||
| 13 | |||
| 14 | for_each_event(event) { | ||
| 15 | if (event->id == event_id) | ||
| 16 | return event->profile_enable(event); | ||
| 17 | } | ||
| 18 | |||
| 19 | return -EINVAL; | ||
| 20 | } | ||
| 21 | |||
| 22 | void ftrace_profile_disable(int event_id) | ||
| 23 | { | ||
| 24 | struct ftrace_event_call *event; | ||
| 25 | |||
| 26 | for_each_event(event) { | ||
| 27 | if (event->id == event_id) | ||
| 28 | return event->profile_disable(event); | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 7763db8fd0b3..3047b56f6637 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -19,11 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | static DEFINE_MUTEX(event_mutex); | 20 | static DEFINE_MUTEX(event_mutex); |
| 21 | 21 | ||
| 22 | #define events_for_each(event) \ | ||
| 23 | for (event = __start_ftrace_events; \ | ||
| 24 | (unsigned long)event < (unsigned long)__stop_ftrace_events; \ | ||
| 25 | event++) | ||
| 26 | |||
| 27 | static void ftrace_clear_events(void) | 22 | static void ftrace_clear_events(void) |
| 28 | { | 23 | { |
| 29 | struct ftrace_event_call *call = (void *)__start_ftrace_events; | 24 | struct ftrace_event_call *call = (void *)__start_ftrace_events; |
| @@ -90,7 +85,7 @@ static int ftrace_set_clr_event(char *buf, int set) | |||
| 90 | } | 85 | } |
| 91 | 86 | ||
| 92 | mutex_lock(&event_mutex); | 87 | mutex_lock(&event_mutex); |
| 93 | events_for_each(call) { | 88 | for_each_event(call) { |
| 94 | 89 | ||
| 95 | if (!call->name || !call->regfunc) | 90 | if (!call->name || !call->regfunc) |
| 96 | continue; | 91 | continue; |
| @@ -628,7 +623,7 @@ static __init int event_trace_init(void) | |||
| 628 | if (!d_events) | 623 | if (!d_events) |
| 629 | return 0; | 624 | return 0; |
| 630 | 625 | ||
| 631 | events_for_each(call) { | 626 | for_each_event(call) { |
| 632 | /* The linker may leave blanks */ | 627 | /* The linker may leave blanks */ |
| 633 | if (!call->name) | 628 | if (!call->name) |
| 634 | continue; | 629 | continue; |
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h index 4c26d97b4508..6b3261ca988c 100644 --- a/kernel/trace/trace_events_stage_3.h +++ b/kernel/trace/trace_events_stage_3.h | |||
| @@ -109,6 +109,40 @@ | |||
| 109 | #undef TP_FMT | 109 | #undef TP_FMT |
| 110 | #define TP_FMT(fmt, args...) fmt "\n", ##args | 110 | #define TP_FMT(fmt, args...) fmt "\n", ##args |
| 111 | 111 | ||
| 112 | #ifdef CONFIG_EVENT_PROFILE | ||
| 113 | #define _TRACE_PROFILE(call, proto, args) \ | ||
| 114 | static void ftrace_profile_##call(proto) \ | ||
| 115 | { \ | ||
| 116 | extern void perf_tpcounter_event(int); \ | ||
| 117 | perf_tpcounter_event(event_##call.id); \ | ||
| 118 | } \ | ||
| 119 | \ | ||
| 120 | static int ftrace_profile_enable_##call(struct ftrace_event_call *call) \ | ||
| 121 | { \ | ||
| 122 | int ret = 0; \ | ||
| 123 | \ | ||
| 124 | if (!atomic_inc_return(&call->profile_count)) \ | ||
| 125 | ret = register_trace_##call(ftrace_profile_##call); \ | ||
| 126 | \ | ||
| 127 | return ret; \ | ||
| 128 | } \ | ||
| 129 | \ | ||
| 130 | static void ftrace_profile_disable_##call(struct ftrace_event_call *call) \ | ||
| 131 | { \ | ||
| 132 | if (atomic_add_negative(-1, &call->profile_count)) \ | ||
| 133 | unregister_trace_##call(ftrace_profile_##call); \ | ||
| 134 | } | ||
| 135 | |||
| 136 | #define _TRACE_PROFILE_INIT(call) \ | ||
| 137 | .profile_count = ATOMIC_INIT(-1), \ | ||
| 138 | .profile_enable = ftrace_profile_enable_##call, \ | ||
| 139 | .profile_disable = ftrace_profile_disable_##call, | ||
| 140 | |||
| 141 | #else | ||
| 142 | #define _TRACE_PROFILE(call, proto, args) | ||
| 143 | #define _TRACE_PROFILE_INIT(call) | ||
| 144 | #endif | ||
| 145 | |||
| 112 | #define _TRACE_FORMAT(call, proto, args, fmt) \ | 146 | #define _TRACE_FORMAT(call, proto, args, fmt) \ |
| 113 | static void ftrace_event_##call(proto) \ | 147 | static void ftrace_event_##call(proto) \ |
| 114 | { \ | 148 | { \ |
| @@ -147,6 +181,7 @@ static int ftrace_init_event_##call(void) \ | |||
| 147 | #undef TRACE_FORMAT | 181 | #undef TRACE_FORMAT |
| 148 | #define TRACE_FORMAT(call, proto, args, fmt) \ | 182 | #define TRACE_FORMAT(call, proto, args, fmt) \ |
| 149 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ | 183 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ |
| 184 | _TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ | ||
| 150 | static struct ftrace_event_call __used \ | 185 | static struct ftrace_event_call __used \ |
| 151 | __attribute__((__aligned__(4))) \ | 186 | __attribute__((__aligned__(4))) \ |
| 152 | __attribute__((section("_ftrace_events"))) event_##call = { \ | 187 | __attribute__((section("_ftrace_events"))) event_##call = { \ |
| @@ -155,6 +190,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 155 | .raw_init = ftrace_init_event_##call, \ | 190 | .raw_init = ftrace_init_event_##call, \ |
| 156 | .regfunc = ftrace_reg_event_##call, \ | 191 | .regfunc = ftrace_reg_event_##call, \ |
| 157 | .unregfunc = ftrace_unreg_event_##call, \ | 192 | .unregfunc = ftrace_unreg_event_##call, \ |
| 193 | _TRACE_PROFILE_INIT(call) \ | ||
| 158 | } | 194 | } |
| 159 | 195 | ||
| 160 | #undef __entry | 196 | #undef __entry |
| @@ -162,6 +198,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 162 | 198 | ||
| 163 | #undef TRACE_EVENT | 199 | #undef TRACE_EVENT |
| 164 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ | 200 | #define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ |
| 201 | _TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \ | ||
| 165 | \ | 202 | \ |
| 166 | static struct ftrace_event_call event_##call; \ | 203 | static struct ftrace_event_call event_##call; \ |
| 167 | \ | 204 | \ |
| @@ -227,4 +264,11 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 227 | .regfunc = ftrace_raw_reg_event_##call, \ | 264 | .regfunc = ftrace_raw_reg_event_##call, \ |
| 228 | .unregfunc = ftrace_raw_unreg_event_##call, \ | 265 | .unregfunc = ftrace_raw_unreg_event_##call, \ |
| 229 | .show_format = ftrace_format_##call, \ | 266 | .show_format = ftrace_format_##call, \ |
| 267 | _TRACE_PROFILE_INIT(call) \ | ||
| 230 | } | 268 | } |
| 269 | |||
| 270 | #include <trace/trace_event_types.h> | ||
| 271 | |||
| 272 | #undef _TRACE_PROFILE | ||
| 273 | #undef _TRACE_PROFILE_INIT | ||
| 274 | |||
