blob: d9c60f80aa0d20958c647a86310b29701b4bcdcc [file] [log] [blame]
Peter Zijlstraac199db2009-03-19 20:26:15 +01001/*
2 * trace event based perf counter profiling
3 *
4 * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
5 *
6 */
7
Li Zefan558e6542009-08-24 12:19:47 +08008#include <linux/module.h>
Peter Zijlstraac199db2009-03-19 20:26:15 +01009#include "trace.h"
10
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020011
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010012char *perf_trace_buf;
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010013EXPORT_SYMBOL_GPL(perf_trace_buf);
Peter Zijlstra05bafda2009-09-20 12:34:38 +020014
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010015char *perf_trace_buf_nmi;
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010016EXPORT_SYMBOL_GPL(perf_trace_buf_nmi);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020017
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010018typedef typeof(char [FTRACE_MAX_PROFILE_SIZE]) perf_trace_t ;
19
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020020/* Count the events in use (per event id, not per instance) */
21static int total_profile_count;
22
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020023static int ftrace_profile_enable_event(struct ftrace_event_call *event)
24{
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010025 char *buf;
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020026 int ret = -ENOMEM;
27
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020028 if (atomic_inc_return(&event->profile_count))
29 return 0;
30
Frederic Weisbeckerfe8e5b52009-10-03 14:55:18 +020031 if (!total_profile_count) {
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010032 buf = (char *)alloc_percpu(perf_trace_t);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020033 if (!buf)
34 goto fail_buf;
35
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010036 rcu_assign_pointer(perf_trace_buf, buf);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020037
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010038 buf = (char *)alloc_percpu(perf_trace_t);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020039 if (!buf)
40 goto fail_buf_nmi;
41
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010042 rcu_assign_pointer(perf_trace_buf_nmi, buf);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020043 }
44
Frederic Weisbeckerd7a4b412009-09-23 23:08:43 +020045 ret = event->profile_enable(event);
Frederic Weisbeckerfe8e5b52009-10-03 14:55:18 +020046 if (!ret) {
47 total_profile_count++;
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020048 return 0;
Frederic Weisbeckerfe8e5b52009-10-03 14:55:18 +020049 }
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020050
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020051fail_buf_nmi:
Frederic Weisbeckerfe8e5b52009-10-03 14:55:18 +020052 if (!total_profile_count) {
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010053 free_percpu(perf_trace_buf_nmi);
54 free_percpu(perf_trace_buf);
55 perf_trace_buf_nmi = NULL;
56 perf_trace_buf = NULL;
Frederic Weisbeckerfe8e5b52009-10-03 14:55:18 +020057 }
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020058fail_buf:
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020059 atomic_dec(&event->profile_count);
60
61 return ret;
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020062}
63
Peter Zijlstraac199db2009-03-19 20:26:15 +010064int ftrace_profile_enable(int event_id)
65{
66 struct ftrace_event_call *event;
Li Zefan20c89282009-05-06 10:33:45 +080067 int ret = -EINVAL;
Peter Zijlstraac199db2009-03-19 20:26:15 +010068
Li Zefan20c89282009-05-06 10:33:45 +080069 mutex_lock(&event_mutex);
Steven Rostedta59fd602009-04-10 13:52:20 -040070 list_for_each_entry(event, &ftrace_events, list) {
Li Zefan558e6542009-08-24 12:19:47 +080071 if (event->id == event_id && event->profile_enable &&
72 try_module_get(event->mod)) {
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020073 ret = ftrace_profile_enable_event(event);
Li Zefan20c89282009-05-06 10:33:45 +080074 break;
75 }
Peter Zijlstraac199db2009-03-19 20:26:15 +010076 }
Li Zefan20c89282009-05-06 10:33:45 +080077 mutex_unlock(&event_mutex);
Peter Zijlstraac199db2009-03-19 20:26:15 +010078
Li Zefan20c89282009-05-06 10:33:45 +080079 return ret;
Peter Zijlstraac199db2009-03-19 20:26:15 +010080}
81
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020082static void ftrace_profile_disable_event(struct ftrace_event_call *event)
83{
Frederic Weisbeckerce71b9d2009-11-22 05:26:55 +010084 char *buf, *nmi_buf;
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020085
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +020086 if (!atomic_add_negative(-1, &event->profile_count))
87 return;
88
Frederic Weisbeckerd7a4b412009-09-23 23:08:43 +020089 event->profile_disable(event);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020090
91 if (!--total_profile_count) {
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010092 buf = perf_trace_buf;
93 rcu_assign_pointer(perf_trace_buf, NULL);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020094
Frederic Weisbecker444a2a32009-11-06 04:13:05 +010095 nmi_buf = perf_trace_buf_nmi;
96 rcu_assign_pointer(perf_trace_buf_nmi, NULL);
Frederic Weisbecker20ab44252009-09-18 06:10:28 +020097
98 /*
99 * Ensure every events in profiling have finished before
100 * releasing the buffers
101 */
102 synchronize_sched();
103
104 free_percpu(buf);
105 free_percpu(nmi_buf);
106 }
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +0200107}
108
Peter Zijlstraac199db2009-03-19 20:26:15 +0100109void ftrace_profile_disable(int event_id)
110{
111 struct ftrace_event_call *event;
112
Li Zefan20c89282009-05-06 10:33:45 +0800113 mutex_lock(&event_mutex);
Steven Rostedta59fd602009-04-10 13:52:20 -0400114 list_for_each_entry(event, &ftrace_events, list) {
Li Zefan20c89282009-05-06 10:33:45 +0800115 if (event->id == event_id) {
Frederic Weisbeckere5e25cf2009-09-18 00:54:43 +0200116 ftrace_profile_disable_event(event);
Li Zefan558e6542009-08-24 12:19:47 +0800117 module_put(event->mod);
Li Zefan20c89282009-05-06 10:33:45 +0800118 break;
119 }
Peter Zijlstraac199db2009-03-19 20:26:15 +0100120 }
Li Zefan20c89282009-05-06 10:33:45 +0800121 mutex_unlock(&event_mutex);
Peter Zijlstraac199db2009-03-19 20:26:15 +0100122}