ftrace: start stop infrastructure changes
Subsystems (4)
Steven Rostedt
maintainercover ftrace: start stop infrastructure changes
[
Note, I'm now trying to learn to use git. I am experimenting with using a combination of quilt and git. I set up a git repo at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
This series is in the tip/devel branch.
I'll put my changes in that branch and then send out the patches as I have always done. But the introduction will list the shortlog of the changes, then followed by the patches themselves.
I do this by using git format-patch and then having quilt send out the queue that was produced.
I plan on automating a lot of this, but for this run, it was done manually.
]
Ingo,
The following patches are in
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
branch: tip/devel
Steven Rostedt (3):
ftrace: add quick function trace stop
ftrace: soft tracing stop and start
ftrace: restructure tracing start/stop infrastructure
The first two should be fine, but the last one changed the infrastructure a bit, and will need a bit of testing.
-- Steve
Steven Rostedt
maintainerPATCH 1/3 ftrace: add quick function trace stop
Impact: quick start and stop of function tracer
This patch adds a way to disable the function tracer quickly without the need to run kstop_machine. It adds a new variable called function_trace_stop which will stop the calls to functions from mcount when set. This is just an on/off switch and does not handle recursion like preempt_disable().
It's main purpose is to help other tracers/debuggers start and stop tracing fuctions without the need to call kstop_machine.
The config option HAVE_FUNCTION_TRACE_MCOUNT_TEST is added for archs that implement the testing of the function_trace_stop in the mcount arch dependent code. Otherwise, the test is done in the C code.
x86 is the only arch at the moment that supports this.
--- arch/x86/Kconfig | 1 + arch/x86/kernel/entry_32.S | 6 +++++ arch/x86/kernel/entry_64.S | 5 ++++ include/linux/ftrace.h | 30 ++++++++++++++++++++++++++++ kernel/trace/Kconfig | 7 ++++++ kernel/trace/ftrace.c | 47 ++++++++++++++++++++++++++++++++++--------- 6 files changed, 86 insertions(+), 10 deletions(-)
arch/x86/Kconfig +1 -0
@@ -29,6 +29,7 @@ config X86 select HAVE_FTRACE_MCOUNT_RECORD select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) select HAVE_ARCH_KGDB if !X86_VOYAGER select HAVE_ARCH_TRACEHOOK
arch/x86/kernel/entry_32.S +6 -0
@@ -1157,6 +1157,9 @@ ENTRY(mcount) END(mcount) ENTRY(ftrace_caller) + cmpl $0, function_trace_stop + jne ftrace_stub + pushl %eax pushl %ecx pushl %edx
@@ -1180,6 +1183,9 @@ END(ftrace_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount) + cmpl $0, function_trace_stop + jne ftrace_stub + cmpl $ftrace_stub, ftrace_trace_function jnz trace .globl ftrace_stub
arch/x86/kernel/entry_64.S +5 -0
@@ -68,6 +68,8 @@ ENTRY(mcount) END(mcount) ENTRY(ftrace_caller) + cmpl $0, function_trace_stop + jne ftrace_stub /* taken from glibc */ subq $0x38, %rsp
@@ -103,6 +105,9 @@ END(ftrace_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ ENTRY(mcount) + cmpl $0, function_trace_stop + jne ftrace_stub + cmpq $ftrace_stub, ftrace_trace_function jnz trace .globl ftrace_stub
include/linux/ftrace.h +30 -0
@@ -23,6 +23,34 @@ struct ftrace_ops {struct ftrace_ops *next; }; +extern int function_trace_stop; + +/** +* ftrace_stop - stop function tracer. +* +* A quick way to stop the function tracer. Note this an on off switch, +* it is not something that is recursive like preempt_disable. +* This does not disable the calling of mcount, it only stops the +* calling of functions from mcount. +*/ +static inline void ftrace_stop (void ) +{ + function_trace_stop =1 ; +} + +/** +* ftrace_start - start the function tracer. +* +* This function is the inverse of ftrace_stop. This does not enable +* the function tracing if the function tracer is disabled. This only +* sets the function tracer flag to continue calling the functions +* from mcount. +*/ +static inline void ftrace_start (void ) +{ + function_trace_stop =0 ; +} +/* * The ftrace_ops must be a static and should also * be read_mostly. These functions do modify read_mostly variables
@@ -41,6 +69,8 @@ extern void ftrace_stub(unsigned long a0, unsigned long a1);# define unregister_ftrace_function (ops) do { } while (0)# define clear_ftrace_function (ops) do { } while (0)static inline void ftrace_kill (void ) { } +static inline void ftrace_stop (void ) { } +static inline void ftrace_start (void ) { }#endif /* CONFIG_FUNCTION_TRACER */ #ifdef CONFIG_DYNAMIC_FTRACE
kernel/trace/Kconfig +7 -0
@@ -9,6 +9,13 @@ config NOP_TRACER config HAVE_FUNCTION_TRACER bool +config HAVE_FUNCTION_TRACE_MCOUNT_TEST + bool + help + This gets selected when the arch tests the function_trace_stop + variable at the mcount call site. Otherwise, this variable + is tested by the called function. + config HAVE_DYNAMIC_FTRACE bool
kernel/trace/ftrace.c +37 -10
113 lines not on this page · raw message
Signature · 3 lines
1.5.6.5 --
Steven Rostedt
maintainerPATCH 2/3 ftrace: soft tracing stop and start
In reply to Steven RostedtImpact: add way to quickly start stop tracing from the kernel
This patch adds a soft stop and start to the trace. This simply disables function tracing via the ftrace_disabled flag, and disables the trace buffers to prevent recording. The tracing code may still be executed, but the trace will not be recorded.
--- include/linux/ftrace.h | 5 +++ kernel/trace/trace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-)
include/linux/ftrace.h +5 -0
@@ -219,6 +219,9 @@ static inline void __ftrace_enabled_restore(int enabled)#ifdef CONFIG_TRACING extern int ftrace_dump_on_oops; +extern void tracing_start (void ); +extern void tracing_stop (void ); +extern void ftrace_special (unsigned long arg1,unsigned long arg2,unsigned long arg3);
@@ -249,6 +252,8 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3) { }static inline int ftrace_printk (const char *fmt, ...) __attribute__ ((format (printf,1 ,0 ))); +static inline void tracing_start (void ) { } +static inline void tracing_stop (void ) { }static inline int ftrace_printk (const char *fmt, ...) {
kernel/trace/trace.c +79 -2
99 lines not on this page · raw message
Signature · 3 lines
1.5.6.5 --
Steven Rostedt
maintainerPATCH 3/3 ftrace: restructure tracing start/stop infrastructure
In reply to Steven RostedtImpact: 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.
--- kernel/trace/trace.c | 64 ++++++++++++++++--------------------- kernel/trace/trace.h | 5 ++- kernel/trace/trace_functions.c | 6 +++ kernel/trace/trace_irqsoff.c | 41 +++++++++++++++++++++--- kernel/trace/trace_sched_switch.c | 13 +++++++ kernel/trace/trace_sched_wakeup.c | 39 +++++++++++++++++++--- 6 files changed, 120 insertions(+), 48 deletions(-)
kernel/trace/trace.c +28 -36
@@ -150,6 +150,19 @@ static DEFINE_PER_CPU(struct trace_array_cpu, max_data);/* tracer_enabled is used to toggle activation of a tracer */ static int tracer_enabled =1 ; +/** +* tracing_is_enabled - return tracer_enabled status +* +* This function is used by other tracers to know the status +* of the tracer_enabled flag. Tracers may use this function +* to know if it should enable their features when starting +* up. See irqsoff tracer for an example (start_irqsoff_tracer). +*/ +int tracing_is_enabled (void ) +{ +return tracer_enabled; +} +/* function tracing enabled */ int ftrace_function_enabled;
@@ -1041,8 +1054,7 @@ void tracing_start_function_trace(void) trace_ops.func = function_trace_call;register_ftrace_function (&trace_ops); -if (tracer_enabled) - ftrace_function_enabled =1 ; + ftrace_function_enabled =1 ; }void tracing_stop_function_trace (void )
@@ -1189,10 +1201,6 @@ static void *s_start(struct seq_file *m, loff_t *pos)atomic_inc (&trace_record_cmdline_disabled); -/* let the tracer grab locks here if needed */ -if (current_trace->start) - current_trace->start (iter); -if (*pos != iter->pos) { iter->ent =NULL ; iter->cpu =0 ;
@@ -1219,14 +1227,7 @@ static void *s_start(struct seq_file *m, loff_t *pos)static void s_stop (struct seq_file *m,void *p) { -struct trace_iterator *iter = m->private; -atomic_dec (&trace_record_cmdline_disabled); - -/* let the tracer release locks here if needed */ -if (current_trace && current_trace == iter->trace && iter->trace->stop) - iter->trace->stop (iter); -mutex_unlock (&trace_types_lock); }
@@ -2059,10 +2060,7 @@ __tracing_open(struct inode *inode, struct file *file, int *ret) m->private = iter;/* stop the trace while dumping */ -if (iter->tr->ctrl) { - tracer_enabled =0 ; - ftrace_function_enabled =0 ; - } +tracing_stop ();if (iter->trace && iter->trace->open) iter->trace->open (iter);
@@ -2107,14 +2105,7 @@ int tracing_release(struct inode *inode, struct file *file) iter->trace->close (iter);/* reenable tracing if it was previously enabled */ -if (iter->tr->ctrl) { - tracer_enabled =1 ; -/* -* It is safe to enable function tracing even if it -* isn't used -*/ - ftrace_function_enabled =1 ; - } +tracing_start ();mutex_unlock (&trace_types_lock);seq_release (inode, file);
@@ -2452,11 +2443,10 @@ static ssize_t tracing_ctrl_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { - struct trace_array *tr = filp->private_data; char buf[64];int r; - r =sprintf (buf,"%ld\n" , tr->ctrl); + r =sprintf (buf,"%u\n" , tracer_enabled);return simple_read_from_buffer (ubuf, cnt, ppos, buf, r); }
@@ -2484,16 +2474,18 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf, val = !!val;mutex_lock (&trace_types_lock); -if (tr->ctrl ^ val) { -if (val) +if (tracer_enabled ^ val) { +if (val) { tracer_enabled =1 ; -else +if (current_trace->start) + current_trace->start (tr); +tracing_start (); + }else { tracer_enabled =0 ; - - tr->ctrl = val; - -if (current_trace && current_trace->ctrl_update) - current_trace->ctrl_update (tr); +tracing_stop (); +if (current_trace->stop) + current_trace->stop (tr); + } }mutex_unlock (&trace_types_lock);
@@ -3375,7 +3367,7 @@ __init static int tracer_alloc_buffers(void)#endif /* All seems OK, enable tracing */ - global_trace.ctrl = tracer_enabled; + global_trace.ctrl =1 ; tracing_disabled =0 ; atomic_notifier_chain_register(&panic_notifier_list,
kernel/trace/trace.h +3 -2
@@ -237,11 +237,11 @@ struct tracer {const char *name;void (*init)(struct trace_array *tr);void (*reset)(struct trace_array *tr); +void (*start)(struct trace_array *tr); +void (*stop)(struct trace_array *tr);void (*open)(struct trace_iterator *iter);void (*pipe_open)(struct trace_iterator *iter);void (*close)(struct trace_iterator *iter); -void (*start)(struct trace_iterator *iter); -void (*stop)(struct trace_iterator *iter);ssize_t (*read)(struct trace_iterator *iter,struct file *filp,char __user *ubuf,size_t cnt,loff_t *ppos);
@@ -282,6 +282,7 @@ struct trace_iterator {long idx; }; +int tracing_is_enabled (void );void trace_wake_up (void );void tracing_reset (struct trace_array *tr,int cpu);int tracing_open_generic (struct inode *inode,struct file *filp);
kernel/trace/trace_functions.c +6 -0
@@ -62,11 +62,17 @@ static void function_trace_ctrl_update(struct trace_array *tr)stop_function_trace (tr); } +static void function_trace_start (struct trace_array *tr) +{ +function_reset (tr); +} +static struct tracer function_trace__read_mostly = { .name ="function" , .init = function_trace_init, .reset = function_trace_reset, + .start = function_trace_start, .ctrl_update = function_trace_ctrl_update, #ifdef CONFIG_FTRACE_SELFTEST .selftest = trace_selftest_startup_function,
kernel/trace/trace_irqsoff.c +36 -5
86 lines not on this page · raw message
kernel/trace/trace_sched_switch.c +13 -0
@@ -186,11 +186,24 @@ static void sched_switch_trace_ctrl_update(struct trace_array *tr)stop_sched_trace (tr); } +static void sched_switch_trace_start (struct trace_array *tr) +{ +sched_switch_reset (tr); +tracing_start_sched_switch (); +} + +static void sched_switch_trace_stop (struct trace_array *tr) +{ +tracing_stop_sched_switch (); +} +struct tracer sched_switch_trace__read_mostly = { .name ="sched_switch" , .init = sched_switch_trace_init, .reset = sched_switch_trace_reset, + .start = sched_switch_trace_start, + .stop = sched_switch_trace_stop, .ctrl_update = sched_switch_trace_ctrl_update, #ifdef CONFIG_FTRACE_SELFTEST .selftest = trace_selftest_startup_sched_switch,
kernel/trace/trace_sched_wakeup.c +34 -5
@@ -262,6 +262,12 @@ out:atomic_dec (&wakeup_trace->data[cpu]->disabled); } +/* +* save_tracer_enabled is used to save the state of the tracer_enabled +* variable when we disable it when we open a trace output file. +*/ +static int save_tracer_enabled; +static void start_wakeup_tracer (struct trace_array *tr) {int ret;
@@ -300,7 +306,13 @@ static void start_wakeup_tracer(struct trace_array *tr)register_ftrace_function (&trace_ops); - tracer_enabled =1 ; +if (tracing_is_enabled ()) { + tracer_enabled =1 ; + save_tracer_enabled =1 ; + }else { + tracer_enabled =0 ; + save_tracer_enabled =0 ; + }return ; fail_deprobe_wake_new:
@@ -312,6 +324,7 @@ fail_deprobe:static void stop_wakeup_tracer (struct trace_array *tr) { tracer_enabled =0 ; + save_tracer_enabled =0 ;unregister_ftrace_function (&trace_ops);unregister_trace_sched_switch (probe_wakeup_sched_switch);unregister_trace_sched_wakeup_new (probe_wakeup);
@@ -343,18 +356,32 @@ static void wakeup_tracer_ctrl_update(struct trace_array *tr)stop_wakeup_tracer (tr); } +static void wakeup_tracer_start (struct trace_array *tr) +{ +wakeup_reset (tr); + tracer_enabled =1 ; + save_tracer_enabled =1 ; +} + +static void wakeup_tracer_stop (struct trace_array *tr) +{ + tracer_enabled =0 ; + save_tracer_enabled =0 ; +} +static void wakeup_tracer_open (struct trace_iterator *iter) {/* stop the trace while dumping */ -if (iter->tr->ctrl) -stop_wakeup_tracer (iter->tr); + tracer_enabled =0 ; }static void wakeup_tracer_close (struct trace_iterator *iter) {/* forget about any processes we were recording */ -if (iter->tr->ctrl) -start_wakeup_tracer (iter->tr); +if (save_tracer_enabled) { +wakeup_reset (iter->tr); + tracer_enabled =1 ; + } } static struct tracer wakeup_tracer __read_mostly =
@@ -362,6 +389,8 @@ static struct tracer wakeup_tracer __read_mostly = .name = "wakeup", .init = wakeup_tracer_init, .reset = wakeup_tracer_reset, + .start = wakeup_tracer_start, + .stop = wakeup_tracer_stop, .open = wakeup_tracer_open, .close = wakeup_tracer_close, .ctrl_update = wakeup_tracer_ctrl_update,
Signature · 3 lines
1.5.6.5 --
Quoted 11 lines · Steven Rostedt
Note, I'm now trying to learn to use git. I am experimenting with using a combination of quilt and git. I set up a git repo at:
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.gitThis series is in the tip/devel branch.
I'll put my changes in that branch and then send out the patches as I have always done. But the introduction will list the shortlog of the changes, then followed by the patches themselves.
Quoted 5 lines
I do this by using git format-patch and then having quilt send out the queue that was produced.
I plan on automating a lot of this, but for this run, it was done manually.
Worked fine on my side - and it's easier than processing patches in
email: the ordering and dependencies are more obvious.
The only flip side is that it's harder to fix small details in commit logs in an ad-hoc way. So be prepared to see more nitpicking from me for such details :-)
Ingo