aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-03-12 11:49:18 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:36:01 -0400
commit77fd5c15e3216b901be69047ca43b05ae9099951 (patch)
tree1790b9bacd1d371cf03902efaf99cdc9d08abdec /kernel/trace/trace.c
parent3209cff4490bee55fd2bc1d087cb8ecf2a686a88 (diff)
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: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c111
1 files changed, 110 insertions, 1 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 906049c0af90..c5b844621562 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5086,7 +5086,114 @@ static const struct file_operations tracing_dyn_info_fops = {
5086 .read = tracing_read_dyn_info, 5086 .read = tracing_read_dyn_info,
5087 .llseek = generic_file_llseek, 5087 .llseek = generic_file_llseek,
5088}; 5088};
5089#endif 5089#endif /* CONFIG_DYNAMIC_FTRACE */
5090
5091#if defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE)
5092static void
5093ftrace_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
5094{
5095 tracing_snapshot();
5096}
5097
5098static void
5099ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
5100{
5101 unsigned long *count = (long *)data;
5102
5103 if (!*count)
5104 return;
5105
5106 if (*count != -1)
5107 (*count)--;
5108
5109 tracing_snapshot();
5110}
5111
5112static int
5113ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
5114 struct ftrace_probe_ops *ops, void *data)
5115{
5116 long count = (long)data;
5117
5118 seq_printf(m, "%ps:", (void *)ip);
5119
5120 seq_printf(m, "snapshot");
5121
5122 if (count == -1)
5123 seq_printf(m, ":unlimited\n");
5124 else
5125 seq_printf(m, ":count=%ld\n", count);
5126
5127 return 0;
5128}
5129
5130static struct ftrace_probe_ops snapshot_probe_ops = {
5131 .func = ftrace_snapshot,
5132 .print = ftrace_snapshot_print,
5133};
5134
5135static struct ftrace_probe_ops snapshot_count_probe_ops = {
5136 .func = ftrace_count_snapshot,
5137 .print = ftrace_snapshot_print,
5138};
5139
5140static int
5141ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
5142 char *glob, char *cmd, char *param, int enable)
5143{
5144 struct ftrace_probe_ops *ops;
5145 void *count = (void *)-1;
5146 char *number;
5147 int ret;
5148
5149 /* hash funcs only work with set_ftrace_filter */
5150 if (!enable)
5151 return -EINVAL;
5152
5153 ops = param ? &snapshot_count_probe_ops : &snapshot_probe_ops;
5154
5155 if (glob[0] == '!') {
5156 unregister_ftrace_function_probe_func(glob+1, ops);
5157 return 0;
5158 }
5159
5160 if (!param)
5161 goto out_reg;
5162
5163 number = strsep(&param, ":");
5164
5165 if (!strlen(number))
5166 goto out_reg;
5167
5168 /*
5169 * We use the callback data field (which is a pointer)
5170 * as our counter.
5171 */
5172 ret = kstrtoul(number, 0, (unsigned long *)&count);
5173 if (ret)
5174 return ret;
5175
5176 out_reg:
5177 ret = register_ftrace_function_probe(glob, ops, count);
5178
5179 if (ret >= 0)
5180 alloc_snapshot(&global_trace);
5181
5182 return ret < 0 ? ret : 0;
5183}
5184
5185static struct ftrace_func_command ftrace_snapshot_cmd = {
5186 .name = "snapshot",
5187 .func = ftrace_trace_snapshot_callback,
5188};
5189
5190static int register_snapshot_cmd(void)
5191{
5192 return register_ftrace_command(&ftrace_snapshot_cmd);
5193}
5194#else
5195static inline int register_snapshot_cmd(void) { return 0; }
5196#endif /* defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE) */
5090 5197
5091struct dentry *tracing_init_dentry_tr(struct trace_array *tr) 5198struct dentry *tracing_init_dentry_tr(struct trace_array *tr)
5092{ 5199{
@@ -6076,6 +6183,8 @@ __init static int tracer_alloc_buffers(void)
6076 trace_set_options(&global_trace, option); 6183 trace_set_options(&global_trace, option);
6077 } 6184 }
6078 6185
6186 register_snapshot_cmd();
6187
6079 return 0; 6188 return 0;
6080 6189
6081out_free_cpumask: 6190out_free_cpumask: