2 * trace event based perf counter profiling
4 * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
8 #include <linux/module.h>
12 * We can't use a size but a type in alloc_percpu()
13 * So let's create a dummy type that matches the desired size
15 typedef struct {char buf
[FTRACE_MAX_PROFILE_SIZE
];} profile_buf_t
;
17 char *trace_profile_buf
;
18 EXPORT_SYMBOL_GPL(trace_profile_buf
);
20 char *trace_profile_buf_nmi
;
21 EXPORT_SYMBOL_GPL(trace_profile_buf_nmi
);
23 /* Count the events in use (per event id, not per instance) */
24 static int total_profile_count
;
26 static int ftrace_profile_enable_event(struct ftrace_event_call
*event
)
31 if (atomic_inc_return(&event
->profile_count
))
34 if (!total_profile_count
++) {
35 buf
= (char *)alloc_percpu(profile_buf_t
);
39 rcu_assign_pointer(trace_profile_buf
, buf
);
41 buf
= (char *)alloc_percpu(profile_buf_t
);
45 rcu_assign_pointer(trace_profile_buf_nmi
, buf
);
48 ret
= event
->profile_enable();
52 kfree(trace_profile_buf_nmi
);
54 kfree(trace_profile_buf
);
56 total_profile_count
--;
57 atomic_dec(&event
->profile_count
);
62 int ftrace_profile_enable(int event_id
)
64 struct ftrace_event_call
*event
;
67 mutex_lock(&event_mutex
);
68 list_for_each_entry(event
, &ftrace_events
, list
) {
69 if (event
->id
== event_id
&& event
->profile_enable
&&
70 try_module_get(event
->mod
)) {
71 ret
= ftrace_profile_enable_event(event
);
75 mutex_unlock(&event_mutex
);
80 static void ftrace_profile_disable_event(struct ftrace_event_call
*event
)
84 if (!atomic_add_negative(-1, &event
->profile_count
))
87 event
->profile_disable();
89 if (!--total_profile_count
) {
90 buf
= trace_profile_buf
;
91 rcu_assign_pointer(trace_profile_buf
, NULL
);
93 nmi_buf
= trace_profile_buf_nmi
;
94 rcu_assign_pointer(trace_profile_buf_nmi
, NULL
);
97 * Ensure every events in profiling have finished before
98 * releasing the buffers
103 free_percpu(nmi_buf
);
107 void ftrace_profile_disable(int event_id
)
109 struct ftrace_event_call
*event
;
111 mutex_lock(&event_mutex
);
112 list_for_each_entry(event
, &ftrace_events
, list
) {
113 if (event
->id
== event_id
) {
114 ftrace_profile_disable_event(event
);
115 module_put(event
->mod
);
119 mutex_unlock(&event_mutex
);