Commit 77fd5c15 authored by Steven Rostedt (Red Hat)'s avatar Steven Rostedt (Red Hat) Committed by Steven Rostedt

tracing: Add snapshot trigger to function probes

 echo 'schedule:snapshot:1' > /debug/tracing/set_ftrace_filter

This will cause the scheduler to trigger a snapshot the next time
it's called (you can use any function that's not called by NMI).

Even though it triggers only once, you still need to remove it with:

 echo '!schedule:snapshot:0' > /debug/tracing/set_ftrace_filter

The :1 can be left off for the first command:

 echo 'schedule:snapshot' > /debug/tracing/set_ftrace_filter

But this will cause all calls to schedule to trigger a snapshot.
This must be removed without the ':0'

 echo '!schedule:snapshot' > /debug/tracing/set_ftrace_filter

As adding a "count" is a different operation (internally).
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 3209cff4
...@@ -5086,7 +5086,114 @@ static const struct file_operations tracing_dyn_info_fops = { ...@@ -5086,7 +5086,114 @@ static const struct file_operations tracing_dyn_info_fops = {
.read = tracing_read_dyn_info, .read = tracing_read_dyn_info,
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
#endif #endif /* CONFIG_DYNAMIC_FTRACE */
#if defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE)
static void
ftrace_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
{
tracing_snapshot();
}
static void
ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
{
unsigned long *count = (long *)data;
if (!*count)
return;
if (*count != -1)
(*count)--;
tracing_snapshot();
}
static int
ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
struct ftrace_probe_ops *ops, void *data)
{
long count = (long)data;
seq_printf(m, "%ps:", (void *)ip);
seq_printf(m, "snapshot");
if (count == -1)
seq_printf(m, ":unlimited\n");
else
seq_printf(m, ":count=%ld\n", count);
return 0;
}
static struct ftrace_probe_ops snapshot_probe_ops = {
.func = ftrace_snapshot,
.print = ftrace_snapshot_print,
};
static struct ftrace_probe_ops snapshot_count_probe_ops = {
.func = ftrace_count_snapshot,
.print = ftrace_snapshot_print,
};
static int
ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
char *glob, char *cmd, char *param, int enable)
{
struct ftrace_probe_ops *ops;
void *count = (void *)-1;
char *number;
int ret;
/* hash funcs only work with set_ftrace_filter */
if (!enable)
return -EINVAL;
ops = param ? &snapshot_count_probe_ops : &snapshot_probe_ops;
if (glob[0] == '!') {
unregister_ftrace_function_probe_func(glob+1, ops);
return 0;
}
if (!param)
goto out_reg;
number = strsep(&param, ":");
if (!strlen(number))
goto out_reg;
/*
* We use the callback data field (which is a pointer)
* as our counter.
*/
ret = kstrtoul(number, 0, (unsigned long *)&count);
if (ret)
return ret;
out_reg:
ret = register_ftrace_function_probe(glob, ops, count);
if (ret >= 0)
alloc_snapshot(&global_trace);
return ret < 0 ? ret : 0;
}
static struct ftrace_func_command ftrace_snapshot_cmd = {
.name = "snapshot",
.func = ftrace_trace_snapshot_callback,
};
static int register_snapshot_cmd(void)
{
return register_ftrace_command(&ftrace_snapshot_cmd);
}
#else
static inline int register_snapshot_cmd(void) { return 0; }
#endif /* defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE) */
struct dentry *tracing_init_dentry_tr(struct trace_array *tr) struct dentry *tracing_init_dentry_tr(struct trace_array *tr)
{ {
...@@ -6076,6 +6183,8 @@ __init static int tracer_alloc_buffers(void) ...@@ -6076,6 +6183,8 @@ __init static int tracer_alloc_buffers(void)
trace_set_options(&global_trace, option); trace_set_options(&global_trace, option);
} }
register_snapshot_cmd();
return 0; return 0;
out_free_cpumask: out_free_cpumask:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment