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 /kernel | |
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>
Diffstat (limited to 'kernel')
-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 | |||