aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-11-05 16:05:44 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-06 01:51:03 -0500
commit9036990d462e09366f7297a2d1da6582c3e6b1d3 (patch)
treee110393aad12177cb17fa68cb3fefb18ae2f1037
parent0f04870148ecb825133bc2733f473b1c5773ac0b (diff)
ftrace: restructure tracing start/stop infrastructure
Impact: change where tracing is started up and stopped Currently, when a new tracer is selected via echo'ing a tracer name into the current_tracer file, the startup is only done if tracing_enabled is set to one. If tracing_enabled is changed to zero (by echo'ing 0 into the tracing_enabled file) a full shutdown is performed. The full startup and shutdown of a tracer can be expensive and the user can lose out traces when echo'ing in 0 to the tracing_enabled file, because the process takes too long. There can also be places that the user would like to start and stop the tracer several times and doing the full startup and shutdown of a tracer might be too expensive. This patch performs the full startup and shutdown when a tracer is selected. It also adds a way to do a quick start or stop of a tracer. The quick version is just a flag that prevents the tracing from taking place, but the overhead of the code is still there. For example, the startup of a tracer may enable tracepoints, or enable the function tracer. The stop and start will just set a flag to have the tracer ignore the calls when the tracepoint or function trace is called. The overhead of the tracer may still be present when the tracer is stopped, but no tracing will occur. Setting the tracer to the 'nop' tracer (or any other tracer) will perform the shutdown of the tracer which will disable the tracepoint or disable the function tracer. The tracing_enabled file will simply start or stop tracing. This change is all internal. The end result for the user should be the same as before. If tracing_enabled is not set, no trace will happen. If tracing_enabled is set, then the trace will happen. The tracing_enabled variable is static between tracers. Enabling tracing_enabled and going to another tracer will keep tracing_enabled enabled. Same is true with disabling tracing_enabled. This patch will now provide a fast start/stop method to the users for enabling or disabling tracing. Note: There were two methods to the struct tracer that were never used: The methods start and stop. These were to be used as a hook to the reading of the trace output, but ended up not being necessary. These two methods are now used to enable the start and stop of each tracer, in case the tracer needs to do more than just not write into the buffer. For example, the irqsoff tracer must stop recording max latencies when tracing is stopped. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/trace/trace.c64
-rw-r--r--kernel/trace/trace.h5
-rw-r--r--kernel/trace/trace_functions.c6
-rw-r--r--kernel/trace/trace_irqsoff.c41
-rw-r--r--kernel/trace/trace_sched_switch.c13
-rw-r--r--kernel/trace/trace_sched_wakeup.c39
6 files changed, 120 insertions, 48 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 113aea9447ec..ff1e9ed9b587 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -150,6 +150,19 @@ static DEFINE_PER_CPU(struct trace_array_cpu, max_data);
150/* tracer_enabled is used to toggle activation of a tracer */ 150/* tracer_enabled is used to toggle activation of a tracer */
151static int tracer_enabled = 1; 151static int tracer_enabled = 1;
152 152
153/**
154 * tracing_is_enabled - return tracer_enabled status
155 *
156 * This function is used by other tracers to know the status
157 * of the tracer_enabled flag. Tracers may use this function
158 * to know if it should enable their features when starting
159 * up. See irqsoff tracer for an example (start_irqsoff_tracer).
160 */
161int tracing_is_enabled(void)
162{
163 return tracer_enabled;
164}
165
153/* function tracing enabled */ 166/* function tracing enabled */
154int ftrace_function_enabled; 167int ftrace_function_enabled;
155 168
@@ -1041,8 +1054,7 @@ void tracing_start_function_trace(void)
1041 trace_ops.func = function_trace_call; 1054 trace_ops.func = function_trace_call;
1042 1055
1043 register_ftrace_function(&trace_ops); 1056 register_ftrace_function(&trace_ops);
1044 if (tracer_enabled) 1057 ftrace_function_enabled = 1;
1045 ftrace_function_enabled = 1;
1046} 1058}
1047 1059
1048void tracing_stop_function_trace(void) 1060void tracing_stop_function_trace(void)
@@ -1189,10 +1201,6 @@ static void *s_start(struct seq_file *m, loff_t *pos)
1189 1201
1190 atomic_inc(&trace_record_cmdline_disabled); 1202 atomic_inc(&trace_record_cmdline_disabled);
1191 1203
1192 /* let the tracer grab locks here if needed */
1193 if (current_trace->start)
1194 current_trace->start(iter);
1195
1196 if (*pos != iter->pos) { 1204 if (*pos != iter->pos) {
1197 iter->ent = NULL; 1205 iter->ent = NULL;
1198 iter->cpu = 0; 1206 iter->cpu = 0;
@@ -1219,14 +1227,7 @@ static void *s_start(struct seq_file *m, loff_t *pos)
1219 1227
1220static void s_stop(struct seq_file *m, void *p) 1228static void s_stop(struct seq_file *m, void *p)
1221{ 1229{
1222 struct trace_iterator *iter = m->private;
1223
1224 atomic_dec(&trace_record_cmdline_disabled); 1230 atomic_dec(&trace_record_cmdline_disabled);
1225
1226 /* let the tracer release locks here if needed */
1227 if (current_trace && current_trace == iter->trace && iter->trace->stop)
1228 iter->trace->stop(iter);
1229
1230 mutex_unlock(&trace_types_lock); 1231 mutex_unlock(&trace_types_lock);
1231} 1232}
1232 1233
@@ -2056,10 +2057,7 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
2056 m->private = iter; 2057 m->private = iter;
2057 2058
2058 /* stop the trace while dumping */ 2059 /* stop the trace while dumping */
2059 if (iter->tr->ctrl) { 2060 tracing_stop();
2060 tracer_enabled = 0;
2061 ftrace_function_enabled = 0;
2062 }
2063 2061
2064 if (iter->trace && iter->trace->open) 2062 if (iter->trace && iter->trace->open)
2065 iter->trace->open(iter); 2063 iter->trace->open(iter);
@@ -2104,14 +2102,7 @@ int tracing_release(struct inode *inode, struct file *file)
2104 iter->trace->close(iter); 2102 iter->trace->close(iter);
2105 2103
2106 /* reenable tracing if it was previously enabled */ 2104 /* reenable tracing if it was previously enabled */
2107 if (iter->tr->ctrl) { 2105 tracing_start();
2108 tracer_enabled = 1;
2109 /*
2110 * It is safe to enable function tracing even if it
2111 * isn't used
2112 */
2113 ftrace_function_enabled = 1;
2114 }
2115 mutex_unlock(&trace_types_lock); 2106 mutex_unlock(&trace_types_lock);
2116 2107
2117 seq_release(inode, file); 2108 seq_release(inode, file);
@@ -2449,11 +2440,10 @@ static ssize_t
2449tracing_ctrl_read(struct file *filp, char __user *ubuf, 2440tracing_ctrl_read(struct file *filp, char __user *ubuf,
2450 size_t cnt, loff_t *ppos) 2441 size_t cnt, loff_t *ppos)
2451{ 2442{
2452 struct trace_array *tr = filp->private_data;
2453 char buf[64]; 2443 char buf[64];
2454 int r; 2444 int r;
2455 2445
2456 r = sprintf(buf, "%ld\n", tr->ctrl); 2446 r = sprintf(buf, "%u\n", tracer_enabled);
2457 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); 2447 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
2458} 2448}
2459 2449
@@ -2481,16 +2471,18 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf,
2481 val = !!val; 2471 val = !!val;
2482 2472
2483 mutex_lock(&trace_types_lock); 2473 mutex_lock(&trace_types_lock);
2484 if (tr->ctrl ^ val) { 2474 if (tracer_enabled ^ val) {
2485 if (val) 2475 if (val) {
2486 tracer_enabled = 1; 2476 tracer_enabled = 1;
2487 else 2477 if (current_trace->start)
2478 current_trace->start(tr);
2479 tracing_start();
2480 } else {
2488 tracer_enabled = 0; 2481 tracer_enabled = 0;
2489 2482 tracing_stop();
2490 tr->ctrl = val; 2483 if (current_trace->stop)
2491 2484 current_trace->stop(tr);
2492 if (current_trace && current_trace->ctrl_update) 2485 }
2493 current_trace->ctrl_update(tr);
2494 } 2486 }
2495 mutex_unlock(&trace_types_lock); 2487 mutex_unlock(&trace_types_lock);
2496 2488
@@ -3372,7 +3364,7 @@ __init static int tracer_alloc_buffers(void)
3372#endif 3364#endif
3373 3365
3374 /* All seems OK, enable tracing */ 3366 /* All seems OK, enable tracing */
3375 global_trace.ctrl = tracer_enabled; 3367 global_trace.ctrl = 1;
3376 tracing_disabled = 0; 3368 tracing_disabled = 0;
3377 3369
3378 atomic_notifier_chain_register(&panic_notifier_list, 3370 atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index cc14a6bc1094..3422489fad5e 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -237,11 +237,11 @@ struct tracer {
237 const char *name; 237 const char *name;
238 void (*init)(struct trace_array *tr); 238 void (*init)(struct trace_array *tr);
239 void (*reset)(struct trace_array *tr); 239 void (*reset)(struct trace_array *tr);
240 void (*start)(struct trace_array *tr);
241 void (*stop)(struct trace_array *tr);
240 void (*open)(struct trace_iterator *iter); 242 void (*open)(struct trace_iterator *iter);
241 void (*pipe_open)(struct trace_iterator *iter); 243 void (*pipe_open)(struct trace_iterator *iter);
242 void (*close)(struct trace_iterator *iter); 244 void (*close)(struct trace_iterator *iter);
243 void (*start)(struct trace_iterator *iter);
244 void (*stop)(struct trace_iterator *iter);
245 ssize_t (*read)(struct trace_iterator *iter, 245 ssize_t (*read)(struct trace_iterator *iter,
246 struct file *filp, char __user *ubuf, 246 struct file *filp, char __user *ubuf,
247 size_t cnt, loff_t *ppos); 247 size_t cnt, loff_t *ppos);
@@ -282,6 +282,7 @@ struct trace_iterator {
282 long idx; 282 long idx;
283}; 283};
284 284
285int tracing_is_enabled(void);
285void trace_wake_up(void); 286void trace_wake_up(void);
286void tracing_reset(struct trace_array *tr, int cpu); 287void tracing_reset(struct trace_array *tr, int cpu);
287int tracing_open_generic(struct inode *inode, struct file *filp); 288int tracing_open_generic(struct inode *inode, struct file *filp);
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 0f85a64003d3..9f1b0de71284 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -62,11 +62,17 @@ static void function_trace_ctrl_update(struct trace_array *tr)
62 stop_function_trace(tr); 62 stop_function_trace(tr);
63} 63}
64 64
65static void function_trace_start(struct trace_array *tr)
66{
67 function_reset(tr);
68}
69
65static struct tracer function_trace __read_mostly = 70static struct tracer function_trace __read_mostly =
66{ 71{
67 .name = "function", 72 .name = "function",
68 .init = function_trace_init, 73 .init = function_trace_init,
69 .reset = function_trace_reset, 74 .reset = function_trace_reset,
75 .start = function_trace_start,
70 .ctrl_update = function_trace_ctrl_update, 76 .ctrl_update = function_trace_ctrl_update,
71#ifdef CONFIG_FTRACE_SELFTEST 77#ifdef CONFIG_FTRACE_SELFTEST
72 .selftest = trace_selftest_startup_function, 78 .selftest = trace_selftest_startup_function,
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 9c74071c10e0..a87a20fa3fc6 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -353,15 +353,28 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
353} 353}
354#endif /* CONFIG_PREEMPT_TRACER */ 354#endif /* CONFIG_PREEMPT_TRACER */
355 355
356/*
357 * save_tracer_enabled is used to save the state of the tracer_enabled
358 * variable when we disable it when we open a trace output file.
359 */
360static int save_tracer_enabled;
361
356static void start_irqsoff_tracer(struct trace_array *tr) 362static void start_irqsoff_tracer(struct trace_array *tr)
357{ 363{
358 register_ftrace_function(&trace_ops); 364 register_ftrace_function(&trace_ops);
359 tracer_enabled = 1; 365 if (tracing_is_enabled()) {
366 tracer_enabled = 1;
367 save_tracer_enabled = 1;
368 } else {
369 tracer_enabled = 0;
370 save_tracer_enabled = 0;
371 }
360} 372}
361 373
362static void stop_irqsoff_tracer(struct trace_array *tr) 374static void stop_irqsoff_tracer(struct trace_array *tr)
363{ 375{
364 tracer_enabled = 0; 376 tracer_enabled = 0;
377 save_tracer_enabled = 0;
365 unregister_ftrace_function(&trace_ops); 378 unregister_ftrace_function(&trace_ops);
366} 379}
367 380
@@ -389,17 +402,29 @@ static void irqsoff_tracer_ctrl_update(struct trace_array *tr)
389 stop_irqsoff_tracer(tr); 402 stop_irqsoff_tracer(tr);
390} 403}
391 404
405static void irqsoff_tracer_start(struct trace_array *tr)
406{
407 irqsoff_tracer_reset(tr);
408 tracer_enabled = 1;
409 save_tracer_enabled = 1;
410}
411
412static void irqsoff_tracer_stop(struct trace_array *tr)
413{
414 tracer_enabled = 0;
415 save_tracer_enabled = 0;
416}
417
392static void irqsoff_tracer_open(struct trace_iterator *iter) 418static void irqsoff_tracer_open(struct trace_iterator *iter)
393{ 419{
394 /* stop the trace while dumping */ 420 /* stop the trace while dumping */
395 if (iter->tr->ctrl) 421 tracer_enabled = 0;
396 stop_irqsoff_tracer(iter->tr);
397} 422}
398 423
399static void irqsoff_tracer_close(struct trace_iterator *iter) 424static void irqsoff_tracer_close(struct trace_iterator *iter)
400{ 425{
401 if (iter->tr->ctrl) 426 /* restart tracing */
402 start_irqsoff_tracer(iter->tr); 427 tracer_enabled = save_tracer_enabled;
403} 428}
404 429
405#ifdef CONFIG_IRQSOFF_TRACER 430#ifdef CONFIG_IRQSOFF_TRACER
@@ -414,6 +439,8 @@ static struct tracer irqsoff_tracer __read_mostly =
414 .name = "irqsoff", 439 .name = "irqsoff",
415 .init = irqsoff_tracer_init, 440 .init = irqsoff_tracer_init,
416 .reset = irqsoff_tracer_reset, 441 .reset = irqsoff_tracer_reset,
442 .start = irqsoff_tracer_start,
443 .stop = irqsoff_tracer_stop,
417 .open = irqsoff_tracer_open, 444 .open = irqsoff_tracer_open,
418 .close = irqsoff_tracer_close, 445 .close = irqsoff_tracer_close,
419 .ctrl_update = irqsoff_tracer_ctrl_update, 446 .ctrl_update = irqsoff_tracer_ctrl_update,
@@ -440,6 +467,8 @@ static struct tracer preemptoff_tracer __read_mostly =
440 .name = "preemptoff", 467 .name = "preemptoff",
441 .init = preemptoff_tracer_init, 468 .init = preemptoff_tracer_init,
442 .reset = irqsoff_tracer_reset, 469 .reset = irqsoff_tracer_reset,
470 .start = irqsoff_tracer_start,
471 .stop = irqsoff_tracer_stop,
443 .open = irqsoff_tracer_open, 472 .open = irqsoff_tracer_open,
444 .close = irqsoff_tracer_close, 473 .close = irqsoff_tracer_close,
445 .ctrl_update = irqsoff_tracer_ctrl_update, 474 .ctrl_update = irqsoff_tracer_ctrl_update,
@@ -468,6 +497,8 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
468 .name = "preemptirqsoff", 497 .name = "preemptirqsoff",
469 .init = preemptirqsoff_tracer_init, 498 .init = preemptirqsoff_tracer_init,
470 .reset = irqsoff_tracer_reset, 499 .reset = irqsoff_tracer_reset,
500 .start = irqsoff_tracer_start,
501 .stop = irqsoff_tracer_stop,
471 .open = irqsoff_tracer_open, 502 .open = irqsoff_tracer_open,
472 .close = irqsoff_tracer_close, 503 .close = irqsoff_tracer_close,
473 .ctrl_update = irqsoff_tracer_ctrl_update, 504 .ctrl_update = irqsoff_tracer_ctrl_update,
diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index 888944d3409d..91c699be8c87 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -186,11 +186,24 @@ static void sched_switch_trace_ctrl_update(struct trace_array *tr)
186 stop_sched_trace(tr); 186 stop_sched_trace(tr);
187} 187}
188 188
189static void sched_switch_trace_start(struct trace_array *tr)
190{
191 sched_switch_reset(tr);
192 tracing_start_sched_switch();
193}
194
195static void sched_switch_trace_stop(struct trace_array *tr)
196{
197 tracing_stop_sched_switch();
198}
199
189struct tracer sched_switch_trace __read_mostly = 200struct tracer sched_switch_trace __read_mostly =
190{ 201{
191 .name = "sched_switch", 202 .name = "sched_switch",
192 .init = sched_switch_trace_init, 203 .init = sched_switch_trace_init,
193 .reset = sched_switch_trace_reset, 204 .reset = sched_switch_trace_reset,
205 .start = sched_switch_trace_start,
206 .stop = sched_switch_trace_stop,
194 .ctrl_update = sched_switch_trace_ctrl_update, 207 .ctrl_update = sched_switch_trace_ctrl_update,
195#ifdef CONFIG_FTRACE_SELFTEST 208#ifdef CONFIG_FTRACE_SELFTEST
196 .selftest = trace_selftest_startup_sched_switch, 209 .selftest = trace_selftest_startup_sched_switch,
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 7bc4abf6fca8..240577bc8ba5 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -262,6 +262,12 @@ out:
262 atomic_dec(&wakeup_trace->data[cpu]->disabled); 262 atomic_dec(&wakeup_trace->data[cpu]->disabled);
263} 263}
264 264
265/*
266 * save_tracer_enabled is used to save the state of the tracer_enabled
267 * variable when we disable it when we open a trace output file.
268 */
269static int save_tracer_enabled;
270
265static void start_wakeup_tracer(struct trace_array *tr) 271static void start_wakeup_tracer(struct trace_array *tr)
266{ 272{
267 int ret; 273 int ret;
@@ -300,7 +306,13 @@ static void start_wakeup_tracer(struct trace_array *tr)
300 306
301 register_ftrace_function(&trace_ops); 307 register_ftrace_function(&trace_ops);
302 308
303 tracer_enabled = 1; 309 if (tracing_is_enabled()) {
310 tracer_enabled = 1;
311 save_tracer_enabled = 1;
312 } else {
313 tracer_enabled = 0;
314 save_tracer_enabled = 0;
315 }
304 316
305 return; 317 return;
306fail_deprobe_wake_new: 318fail_deprobe_wake_new:
@@ -312,6 +324,7 @@ fail_deprobe:
312static void stop_wakeup_tracer(struct trace_array *tr) 324static void stop_wakeup_tracer(struct trace_array *tr)
313{ 325{
314 tracer_enabled = 0; 326 tracer_enabled = 0;
327 save_tracer_enabled = 0;
315 unregister_ftrace_function(&trace_ops); 328 unregister_ftrace_function(&trace_ops);
316 unregister_trace_sched_switch(probe_wakeup_sched_switch); 329 unregister_trace_sched_switch(probe_wakeup_sched_switch);
317 unregister_trace_sched_wakeup_new(probe_wakeup); 330 unregister_trace_sched_wakeup_new(probe_wakeup);
@@ -343,18 +356,32 @@ static void wakeup_tracer_ctrl_update(struct trace_array *tr)
343 stop_wakeup_tracer(tr); 356 stop_wakeup_tracer(tr);
344} 357}
345 358
359static void wakeup_tracer_start(struct trace_array *tr)
360{
361 wakeup_reset(tr);
362 tracer_enabled = 1;
363 save_tracer_enabled = 1;
364}
365
366static void wakeup_tracer_stop(struct trace_array *tr)
367{
368 tracer_enabled = 0;
369 save_tracer_enabled = 0;
370}
371
346static void wakeup_tracer_open(struct trace_iterator *iter) 372static void wakeup_tracer_open(struct trace_iterator *iter)
347{ 373{
348 /* stop the trace while dumping */ 374 /* stop the trace while dumping */
349 if (iter->tr->ctrl) 375 tracer_enabled = 0;
350 stop_wakeup_tracer(iter->tr);
351} 376}
352 377
353static void wakeup_tracer_close(struct trace_iterator *iter) 378static void wakeup_tracer_close(struct trace_iterator *iter)
354{ 379{
355 /* forget about any processes we were recording */ 380 /* forget about any processes we were recording */
356 if (iter->tr->ctrl) 381 if (save_tracer_enabled) {
357 start_wakeup_tracer(iter->tr); 382 wakeup_reset(iter->tr);
383 tracer_enabled = 1;
384 }
358} 385}
359 386
360static struct tracer wakeup_tracer __read_mostly = 387static struct tracer wakeup_tracer __read_mostly =
@@ -362,6 +389,8 @@ static struct tracer wakeup_tracer __read_mostly =
362 .name = "wakeup", 389 .name = "wakeup",
363 .init = wakeup_tracer_init, 390 .init = wakeup_tracer_init,
364 .reset = wakeup_tracer_reset, 391 .reset = wakeup_tracer_reset,
392 .start = wakeup_tracer_start,
393 .stop = wakeup_tracer_stop,
365 .open = wakeup_tracer_open, 394 .open = wakeup_tracer_open,
366 .close = wakeup_tracer_close, 395 .close = wakeup_tracer_close,
367 .ctrl_update = wakeup_tracer_ctrl_update, 396 .ctrl_update = wakeup_tracer_ctrl_update,