diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched.c | 14 | ||||
-rw-r--r-- | kernel/trace/trace.h | 20 | ||||
-rw-r--r-- | kernel/trace/trace_sched_switch.c | 171 | ||||
-rw-r--r-- | kernel/trace/trace_sched_wakeup.c | 106 |
4 files changed, 255 insertions, 56 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index ad95cca4e42e..e2e985eeee78 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -2500,7 +2500,9 @@ out_activate: | |||
2500 | success = 1; | 2500 | success = 1; |
2501 | 2501 | ||
2502 | out_running: | 2502 | out_running: |
2503 | ftrace_wake_up_task(rq, p, rq->curr); | 2503 | trace_mark(kernel_sched_wakeup, |
2504 | "pid %d state %ld ## rq %p task %p rq->curr %p", | ||
2505 | p->pid, p->state, rq, p, rq->curr); | ||
2504 | check_preempt_curr(rq, p); | 2506 | check_preempt_curr(rq, p); |
2505 | 2507 | ||
2506 | p->state = TASK_RUNNING; | 2508 | p->state = TASK_RUNNING; |
@@ -2631,7 +2633,9 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags) | |||
2631 | p->sched_class->task_new(rq, p); | 2633 | p->sched_class->task_new(rq, p); |
2632 | inc_nr_running(rq); | 2634 | inc_nr_running(rq); |
2633 | } | 2635 | } |
2634 | ftrace_wake_up_task(rq, p, rq->curr); | 2636 | trace_mark(kernel_sched_wakeup_new, |
2637 | "pid %d state %ld ## rq %p task %p rq->curr %p", | ||
2638 | p->pid, p->state, rq, p, rq->curr); | ||
2635 | check_preempt_curr(rq, p); | 2639 | check_preempt_curr(rq, p); |
2636 | #ifdef CONFIG_SMP | 2640 | #ifdef CONFIG_SMP |
2637 | if (p->sched_class->task_wake_up) | 2641 | if (p->sched_class->task_wake_up) |
@@ -2804,7 +2808,11 @@ context_switch(struct rq *rq, struct task_struct *prev, | |||
2804 | struct mm_struct *mm, *oldmm; | 2808 | struct mm_struct *mm, *oldmm; |
2805 | 2809 | ||
2806 | prepare_task_switch(rq, prev, next); | 2810 | prepare_task_switch(rq, prev, next); |
2807 | ftrace_ctx_switch(rq, prev, next); | 2811 | trace_mark(kernel_sched_schedule, |
2812 | "prev_pid %d next_pid %d prev_state %ld " | ||
2813 | "## rq %p prev %p next %p", | ||
2814 | prev->pid, next->pid, prev->state, | ||
2815 | rq, prev, next); | ||
2808 | mm = next->mm; | 2816 | mm = next->mm; |
2809 | oldmm = prev->active_mm; | 2817 | oldmm = prev->active_mm; |
2810 | /* | 2818 | /* |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 8845033ab49d..f5de0601b408 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -234,25 +234,10 @@ void update_max_tr_single(struct trace_array *tr, | |||
234 | 234 | ||
235 | extern cycle_t ftrace_now(int cpu); | 235 | extern cycle_t ftrace_now(int cpu); |
236 | 236 | ||
237 | #ifdef CONFIG_SCHED_TRACER | ||
238 | extern void | ||
239 | wakeup_sched_switch(struct task_struct *prev, struct task_struct *next); | ||
240 | extern void | ||
241 | wakeup_sched_wakeup(struct task_struct *wakee, struct task_struct *curr); | ||
242 | #else | ||
243 | static inline void | ||
244 | wakeup_sched_switch(struct task_struct *prev, struct task_struct *next) | ||
245 | { | ||
246 | } | ||
247 | static inline void | ||
248 | wakeup_sched_wakeup(struct task_struct *wakee, struct task_struct *curr) | ||
249 | { | ||
250 | } | ||
251 | #endif | ||
252 | |||
253 | #ifdef CONFIG_CONTEXT_SWITCH_TRACER | 237 | #ifdef CONFIG_CONTEXT_SWITCH_TRACER |
254 | typedef void | 238 | typedef void |
255 | (*tracer_switch_func_t)(void *private, | 239 | (*tracer_switch_func_t)(void *private, |
240 | void *__rq, | ||
256 | struct task_struct *prev, | 241 | struct task_struct *prev, |
257 | struct task_struct *next); | 242 | struct task_struct *next); |
258 | 243 | ||
@@ -262,9 +247,6 @@ struct tracer_switch_ops { | |||
262 | struct tracer_switch_ops *next; | 247 | struct tracer_switch_ops *next; |
263 | }; | 248 | }; |
264 | 249 | ||
265 | extern int register_tracer_switch(struct tracer_switch_ops *ops); | ||
266 | extern int unregister_tracer_switch(struct tracer_switch_ops *ops); | ||
267 | |||
268 | #endif /* CONFIG_CONTEXT_SWITCH_TRACER */ | 250 | #endif /* CONFIG_CONTEXT_SWITCH_TRACER */ |
269 | 251 | ||
270 | #ifdef CONFIG_DYNAMIC_FTRACE | 252 | #ifdef CONFIG_DYNAMIC_FTRACE |
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 | ||
17 | static struct trace_array *ctx_trace; | 17 | static struct trace_array *ctx_trace; |
18 | static int __read_mostly tracer_enabled; | 18 | static int __read_mostly tracer_enabled; |
19 | static atomic_t sched_ref; | ||
19 | 20 | ||
20 | static void | 21 | static void |
21 | ctx_switch_func(void *__rq, struct task_struct *prev, struct task_struct *next) | 22 | sched_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 | ||
47 | static notrace void | ||
48 | sched_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 | |||
44 | static void | 75 | static void |
45 | wakeup_func(void *__rq, struct task_struct *wakee, struct task_struct *curr) | 76 | wakeup_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 | ||
70 | void | 103 | static notrace void |
71 | ftrace_ctx_switch(void *__rq, struct task_struct *prev, | 104 | wake_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 | ||
89 | void | 122 | tracing_record_cmdline(task); |
90 | ftrace_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 | ||
101 | void | 128 | void |
@@ -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 | ||
162 | static 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; | ||
198 | fail_deprobe_wake_new: | ||
199 | marker_probe_unregister("kernel_sched_wakeup_new", | ||
200 | wake_up_callback, | ||
201 | &ctx_trace); | ||
202 | fail_deprobe: | ||
203 | marker_probe_unregister("kernel_sched_wakeup", | ||
204 | wake_up_callback, | ||
205 | &ctx_trace); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | static 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 | |||
222 | void 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 | |||
231 | void 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 | |||
135 | static void start_sched_trace(struct trace_array *tr) | 240 | static 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 | ||
142 | static void stop_sched_trace(struct trace_array *tr) | 248 | static 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 | } |
186 | device_initcall(init_sched_switch_trace); | 301 | device_initcall(init_sched_switch_trace); |
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 5948011006bc..5d2fb48e47f8 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/kallsyms.h> | 15 | #include <linux/kallsyms.h> |
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/ftrace.h> | 17 | #include <linux/ftrace.h> |
18 | #include <linux/marker.h> | ||
18 | 19 | ||
19 | #include "trace.h" | 20 | #include "trace.h" |
20 | 21 | ||
@@ -44,11 +45,13 @@ static int report_latency(cycle_t delta) | |||
44 | return 1; | 45 | return 1; |
45 | } | 46 | } |
46 | 47 | ||
47 | void | 48 | static void notrace |
48 | wakeup_sched_switch(struct task_struct *prev, struct task_struct *next) | 49 | wakeup_sched_switch(void *private, void *rq, struct task_struct *prev, |
50 | struct task_struct *next) | ||
49 | { | 51 | { |
50 | unsigned long latency = 0, t0 = 0, t1 = 0; | 52 | unsigned long latency = 0, t0 = 0, t1 = 0; |
51 | struct trace_array *tr = wakeup_trace; | 53 | struct trace_array **ptr = private; |
54 | struct trace_array *tr = *ptr; | ||
52 | struct trace_array_cpu *data; | 55 | struct trace_array_cpu *data; |
53 | cycle_t T0, T1, delta; | 56 | cycle_t T0, T1, delta; |
54 | unsigned long flags; | 57 | unsigned long flags; |
@@ -113,6 +116,31 @@ out: | |||
113 | atomic_dec(&tr->data[cpu]->disabled); | 116 | atomic_dec(&tr->data[cpu]->disabled); |
114 | } | 117 | } |
115 | 118 | ||
119 | static notrace void | ||
120 | sched_switch_callback(void *probe_data, void *call_data, | ||
121 | const char *format, va_list *args) | ||
122 | { | ||
123 | struct task_struct *prev; | ||
124 | struct task_struct *next; | ||
125 | struct rq *__rq; | ||
126 | |||
127 | /* skip prev_pid %d next_pid %d prev_state %ld */ | ||
128 | (void)va_arg(*args, int); | ||
129 | (void)va_arg(*args, int); | ||
130 | (void)va_arg(*args, long); | ||
131 | __rq = va_arg(*args, typeof(__rq)); | ||
132 | prev = va_arg(*args, typeof(prev)); | ||
133 | next = va_arg(*args, typeof(next)); | ||
134 | |||
135 | tracing_record_cmdline(prev); | ||
136 | |||
137 | /* | ||
138 | * If tracer_switch_func only points to the local | ||
139 | * switch func, it still needs the ptr passed to it. | ||
140 | */ | ||
141 | wakeup_sched_switch(probe_data, __rq, prev, next); | ||
142 | } | ||
143 | |||
116 | static void __wakeup_reset(struct trace_array *tr) | 144 | static void __wakeup_reset(struct trace_array *tr) |
117 | { | 145 | { |
118 | struct trace_array_cpu *data; | 146 | struct trace_array_cpu *data; |
@@ -188,19 +216,68 @@ out: | |||
188 | atomic_dec(&tr->data[cpu]->disabled); | 216 | atomic_dec(&tr->data[cpu]->disabled); |
189 | } | 217 | } |
190 | 218 | ||
191 | void wakeup_sched_wakeup(struct task_struct *wakee, struct task_struct *curr) | 219 | static notrace void |
220 | wake_up_callback(void *probe_data, void *call_data, | ||
221 | const char *format, va_list *args) | ||
192 | { | 222 | { |
223 | struct trace_array **ptr = probe_data; | ||
224 | struct trace_array *tr = *ptr; | ||
225 | struct task_struct *curr; | ||
226 | struct task_struct *task; | ||
227 | struct rq *__rq; | ||
228 | |||
193 | if (likely(!tracer_enabled)) | 229 | if (likely(!tracer_enabled)) |
194 | return; | 230 | return; |
195 | 231 | ||
232 | /* Skip pid %d state %ld */ | ||
233 | (void)va_arg(*args, int); | ||
234 | (void)va_arg(*args, long); | ||
235 | /* now get the meat: "rq %p task %p rq->curr %p" */ | ||
236 | __rq = va_arg(*args, typeof(__rq)); | ||
237 | task = va_arg(*args, typeof(task)); | ||
238 | curr = va_arg(*args, typeof(curr)); | ||
239 | |||
240 | tracing_record_cmdline(task); | ||
196 | tracing_record_cmdline(curr); | 241 | tracing_record_cmdline(curr); |
197 | tracing_record_cmdline(wakee); | ||
198 | 242 | ||
199 | wakeup_check_start(wakeup_trace, wakee, curr); | 243 | wakeup_check_start(tr, task, curr); |
200 | } | 244 | } |
201 | 245 | ||
202 | static void start_wakeup_tracer(struct trace_array *tr) | 246 | static void start_wakeup_tracer(struct trace_array *tr) |
203 | { | 247 | { |
248 | int ret; | ||
249 | |||
250 | ret = marker_probe_register("kernel_sched_wakeup", | ||
251 | "pid %d state %ld ## rq %p task %p rq->curr %p", | ||
252 | wake_up_callback, | ||
253 | &wakeup_trace); | ||
254 | if (ret) { | ||
255 | pr_info("wakeup trace: Couldn't add marker" | ||
256 | " probe to kernel_sched_wakeup\n"); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | ret = marker_probe_register("kernel_sched_wakeup_new", | ||
261 | "pid %d state %ld ## rq %p task %p rq->curr %p", | ||
262 | wake_up_callback, | ||
263 | &wakeup_trace); | ||
264 | if (ret) { | ||
265 | pr_info("wakeup trace: Couldn't add marker" | ||
266 | " probe to kernel_sched_wakeup_new\n"); | ||
267 | goto fail_deprobe; | ||
268 | } | ||
269 | |||
270 | ret = marker_probe_register("kernel_sched_schedule", | ||
271 | "prev_pid %d next_pid %d prev_state %ld " | ||
272 | "## rq %p prev %p next %p", | ||
273 | sched_switch_callback, | ||
274 | &wakeup_trace); | ||
275 | if (ret) { | ||
276 | pr_info("sched trace: Couldn't add marker" | ||
277 | " probe to kernel_sched_schedule\n"); | ||
278 | goto fail_deprobe_wake_new; | ||
279 | } | ||
280 | |||
204 | wakeup_reset(tr); | 281 | wakeup_reset(tr); |
205 | 282 | ||
206 | /* | 283 | /* |
@@ -215,11 +292,28 @@ static void start_wakeup_tracer(struct trace_array *tr) | |||
215 | tracer_enabled = 1; | 292 | tracer_enabled = 1; |
216 | 293 | ||
217 | return; | 294 | return; |
295 | fail_deprobe_wake_new: | ||
296 | marker_probe_unregister("kernel_sched_wakeup_new", | ||
297 | wake_up_callback, | ||
298 | &wakeup_trace); | ||
299 | fail_deprobe: | ||
300 | marker_probe_unregister("kernel_sched_wakeup", | ||
301 | wake_up_callback, | ||
302 | &wakeup_trace); | ||
218 | } | 303 | } |
219 | 304 | ||
220 | static void stop_wakeup_tracer(struct trace_array *tr) | 305 | static void stop_wakeup_tracer(struct trace_array *tr) |
221 | { | 306 | { |
222 | tracer_enabled = 0; | 307 | tracer_enabled = 0; |
308 | marker_probe_unregister("kernel_sched_schedule", | ||
309 | sched_switch_callback, | ||
310 | &wakeup_trace); | ||
311 | marker_probe_unregister("kernel_sched_wakeup_new", | ||
312 | wake_up_callback, | ||
313 | &wakeup_trace); | ||
314 | marker_probe_unregister("kernel_sched_wakeup", | ||
315 | wake_up_callback, | ||
316 | &wakeup_trace); | ||
223 | } | 317 | } |
224 | 318 | ||
225 | static void wakeup_tracer_init(struct trace_array *tr) | 319 | static void wakeup_tracer_init(struct trace_array *tr) |