aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_sched_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_sched_switch.c')
-rw-r--r--kernel/trace/trace_sched_switch.c171
1 files changed, 143 insertions, 28 deletions
diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index a3376478fc2c..d25ffa5eaf2b 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -16,11 +16,14 @@
16 16
17static struct trace_array *ctx_trace; 17static struct trace_array *ctx_trace;
18static int __read_mostly tracer_enabled; 18static int __read_mostly tracer_enabled;
19static atomic_t sched_ref;
19 20
20static void 21static void
21ctx_switch_func(void *__rq, struct task_struct *prev, struct task_struct *next) 22sched_switch_func(void *private, void *__rq, struct task_struct *prev,
23 struct task_struct *next)
22{ 24{
23 struct trace_array *tr = ctx_trace; 25 struct trace_array **ptr = private;
26 struct trace_array *tr = *ptr;
24 struct trace_array_cpu *data; 27 struct trace_array_cpu *data;
25 unsigned long flags; 28 unsigned long flags;
26 long disabled; 29 long disabled;
@@ -41,10 +44,40 @@ ctx_switch_func(void *__rq, struct task_struct *prev, struct task_struct *next)
41 local_irq_restore(flags); 44 local_irq_restore(flags);
42} 45}
43 46
47static notrace void
48sched_switch_callback(void *probe_data, void *call_data,
49 const char *format, va_list *args)
50{
51 struct task_struct *prev;
52 struct task_struct *next;
53 struct rq *__rq;
54
55 if (!atomic_read(&sched_ref))
56 return;
57
58 /* skip prev_pid %d next_pid %d prev_state %ld */
59 (void)va_arg(*args, int);
60 (void)va_arg(*args, int);
61 (void)va_arg(*args, long);
62 __rq = va_arg(*args, typeof(__rq));
63 prev = va_arg(*args, typeof(prev));
64 next = va_arg(*args, typeof(next));
65
66 tracing_record_cmdline(prev);
67
68 /*
69 * If tracer_switch_func only points to the local
70 * switch func, it still needs the ptr passed to it.
71 */
72 sched_switch_func(probe_data, __rq, prev, next);
73}
74
44static void 75static void
45wakeup_func(void *__rq, struct task_struct *wakee, struct task_struct *curr) 76wakeup_func(void *private, void *__rq, struct task_struct *wakee, struct
77 task_struct *curr)
46{ 78{
47 struct trace_array *tr = ctx_trace; 79 struct trace_array **ptr = private;
80 struct trace_array *tr = *ptr;
48 struct trace_array_cpu *data; 81 struct trace_array_cpu *data;
49 unsigned long flags; 82 unsigned long flags;
50 long disabled; 83 long disabled;
@@ -67,35 +100,29 @@ wakeup_func(void *__rq, struct task_struct *wakee, struct task_struct *curr)
67 local_irq_restore(flags); 100 local_irq_restore(flags);
68} 101}
69 102
70void 103static notrace void
71ftrace_ctx_switch(void *__rq, struct task_struct *prev, 104wake_up_callback(void *probe_data, void *call_data,
72 struct task_struct *next) 105 const char *format, va_list *args)
73{ 106{
74 if (unlikely(atomic_read(&trace_record_cmdline_enabled))) 107 struct task_struct *curr;
75 tracing_record_cmdline(prev); 108 struct task_struct *task;
109 struct rq *__rq;
76 110
77 /* 111 if (likely(!tracer_enabled))
78 * If tracer_switch_func only points to the local 112 return;
79 * switch func, it still needs the ptr passed to it.
80 */
81 ctx_switch_func(__rq, prev, next);
82 113
83 /* 114 /* Skip pid %d state %ld */
84 * Chain to the wakeup tracer (this is a NOP if disabled): 115 (void)va_arg(*args, int);
85 */ 116 (void)va_arg(*args, long);
86 wakeup_sched_switch(prev, next); 117 /* now get the meat: "rq %p task %p rq->curr %p" */
87} 118 __rq = va_arg(*args, typeof(__rq));
119 task = va_arg(*args, typeof(task));
120 curr = va_arg(*args, typeof(curr));
88 121
89void 122 tracing_record_cmdline(task);
90ftrace_wake_up_task(void *__rq, struct task_struct *wakee, 123 tracing_record_cmdline(curr);
91 struct task_struct *curr)
92{
93 wakeup_func(__rq, wakee, curr);
94 124
95 /* 125 wakeup_func(probe_data, __rq, task, curr);
96 * Chain to the wakeup tracer (this is a NOP if disabled):
97 */
98 wakeup_sched_wakeup(wakee, curr);
99} 126}
100 127
101void 128void
@@ -132,15 +159,95 @@ static void sched_switch_reset(struct trace_array *tr)
132 tracing_reset(tr->data[cpu]); 159 tracing_reset(tr->data[cpu]);
133} 160}
134 161
162static int tracing_sched_register(void)
163{
164 int ret;
165
166 ret = marker_probe_register("kernel_sched_wakeup",
167 "pid %d state %ld ## rq %p task %p rq->curr %p",
168 wake_up_callback,
169 &ctx_trace);
170 if (ret) {
171 pr_info("wakeup trace: Couldn't add marker"
172 " probe to kernel_sched_wakeup\n");
173 return ret;
174 }
175
176 ret = marker_probe_register("kernel_sched_wakeup_new",
177 "pid %d state %ld ## rq %p task %p rq->curr %p",
178 wake_up_callback,
179 &ctx_trace);
180 if (ret) {
181 pr_info("wakeup trace: Couldn't add marker"
182 " probe to kernel_sched_wakeup_new\n");
183 goto fail_deprobe;
184 }
185
186 ret = marker_probe_register("kernel_sched_schedule",
187 "prev_pid %d next_pid %d prev_state %ld "
188 "## rq %p prev %p next %p",
189 sched_switch_callback,
190 &ctx_trace);
191 if (ret) {
192 pr_info("sched trace: Couldn't add marker"
193 " probe to kernel_sched_schedule\n");
194 goto fail_deprobe_wake_new;
195 }
196
197 return ret;
198fail_deprobe_wake_new:
199 marker_probe_unregister("kernel_sched_wakeup_new",
200 wake_up_callback,
201 &ctx_trace);
202fail_deprobe:
203 marker_probe_unregister("kernel_sched_wakeup",
204 wake_up_callback,
205 &ctx_trace);
206 return ret;
207}
208
209static void tracing_sched_unregister(void)
210{
211 marker_probe_unregister("kernel_sched_schedule",
212 sched_switch_callback,
213 &ctx_trace);
214 marker_probe_unregister("kernel_sched_wakeup_new",
215 wake_up_callback,
216 &ctx_trace);
217 marker_probe_unregister("kernel_sched_wakeup",
218 wake_up_callback,
219 &ctx_trace);
220}
221
222void tracing_start_sched_switch(void)
223{
224 long ref;
225
226 ref = atomic_inc_return(&sched_ref);
227 if (ref == 1)
228 tracing_sched_register();
229}
230
231void tracing_stop_sched_switch(void)
232{
233 long ref;
234
235 ref = atomic_dec_and_test(&sched_ref);
236 if (ref)
237 tracing_sched_unregister();
238}
239
135static void start_sched_trace(struct trace_array *tr) 240static void start_sched_trace(struct trace_array *tr)
136{ 241{
137 sched_switch_reset(tr); 242 sched_switch_reset(tr);
138 atomic_inc(&trace_record_cmdline_enabled); 243 atomic_inc(&trace_record_cmdline_enabled);
139 tracer_enabled = 1; 244 tracer_enabled = 1;
245 tracing_start_sched_switch();
140} 246}
141 247
142static void stop_sched_trace(struct trace_array *tr) 248static void stop_sched_trace(struct trace_array *tr)
143{ 249{
250 tracing_stop_sched_switch();
144 atomic_dec(&trace_record_cmdline_enabled); 251 atomic_dec(&trace_record_cmdline_enabled);
145 tracer_enabled = 0; 252 tracer_enabled = 0;
146} 253}
@@ -181,6 +288,14 @@ static struct tracer sched_switch_trace __read_mostly =
181 288
182__init static int init_sched_switch_trace(void) 289__init static int init_sched_switch_trace(void)
183{ 290{
291 int ret = 0;
292
293 if (atomic_read(&sched_ref))
294 ret = tracing_sched_register();
295 if (ret) {
296 pr_info("error registering scheduler trace\n");
297 return ret;
298 }
184 return register_tracer(&sched_switch_trace); 299 return register_tracer(&sched_switch_trace);
185} 300}
186device_initcall(init_sched_switch_trace); 301device_initcall(init_sched_switch_trace);