ftrace: Add self-tests for multiple function trace users
authorSteven Rostedt <srostedt@redhat.com>
Fri, 6 May 2011 04:08:51 +0000 (00:08 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Wed, 18 May 2011 23:24:51 +0000 (19:24 -0400)
Add some basic sanity tests for multiple users of the function
tracer at startup.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/trace/trace.h
kernel/trace/trace_selftest.c
kernel/trace/trace_selftest_dynamic.c

index 5e9dfc6286dd0eafed900906cccee1c83cf4f28c..6b69c4bd306f72cbbce93b9fe94827a8696c0fba 100644 (file)
@@ -419,6 +419,8 @@ extern void trace_find_cmdline(int pid, char comm[]);
 extern unsigned long ftrace_update_tot_cnt;
 #define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
 extern int DYN_FTRACE_TEST_NAME(void);
+#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
+extern int DYN_FTRACE_TEST_NAME2(void);
 #endif
 
 extern int ring_buffer_expanded;
index 0fa2db305b7cb060d95b33379b66267a5fc66d67..288541f977fb7f3b41e747a6b7c2de9e4ea0e1e9 100644 (file)
@@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
+static int trace_selftest_test_probe1_cnt;
+static void trace_selftest_test_probe1_func(unsigned long ip,
+                                           unsigned long pip)
+{
+       trace_selftest_test_probe1_cnt++;
+}
+
+static int trace_selftest_test_probe2_cnt;
+static void trace_selftest_test_probe2_func(unsigned long ip,
+                                           unsigned long pip)
+{
+       trace_selftest_test_probe2_cnt++;
+}
+
+static int trace_selftest_test_probe3_cnt;
+static void trace_selftest_test_probe3_func(unsigned long ip,
+                                           unsigned long pip)
+{
+       trace_selftest_test_probe3_cnt++;
+}
+
+static int trace_selftest_test_global_cnt;
+static void trace_selftest_test_global_func(unsigned long ip,
+                                           unsigned long pip)
+{
+       trace_selftest_test_global_cnt++;
+}
+
+static int trace_selftest_test_dyn_cnt;
+static void trace_selftest_test_dyn_func(unsigned long ip,
+                                        unsigned long pip)
+{
+       trace_selftest_test_dyn_cnt++;
+}
+
+static struct ftrace_ops test_probe1 = {
+       .func                   = trace_selftest_test_probe1_func,
+};
+
+static struct ftrace_ops test_probe2 = {
+       .func                   = trace_selftest_test_probe2_func,
+};
+
+static struct ftrace_ops test_probe3 = {
+       .func                   = trace_selftest_test_probe3_func,
+};
+
+static struct ftrace_ops test_global = {
+       .func                   = trace_selftest_test_global_func,
+       .flags                  = FTRACE_OPS_FL_GLOBAL,
+};
+
+static void print_counts(void)
+{
+       printk("(%d %d %d %d %d) ",
+              trace_selftest_test_probe1_cnt,
+              trace_selftest_test_probe2_cnt,
+              trace_selftest_test_probe3_cnt,
+              trace_selftest_test_global_cnt,
+              trace_selftest_test_dyn_cnt);
+}
+
+static void reset_counts(void)
+{
+       trace_selftest_test_probe1_cnt = 0;
+       trace_selftest_test_probe2_cnt = 0;
+       trace_selftest_test_probe3_cnt = 0;
+       trace_selftest_test_global_cnt = 0;
+       trace_selftest_test_dyn_cnt = 0;
+}
+
+static int trace_selftest_ops(int cnt)
+{
+       int save_ftrace_enabled = ftrace_enabled;
+       struct ftrace_ops *dyn_ops;
+       char *func1_name;
+       char *func2_name;
+       int len1;
+       int len2;
+       int ret = -1;
+
+       printk(KERN_CONT "PASSED\n");
+       pr_info("Testing dynamic ftrace ops #%d: ", cnt);
+
+       ftrace_enabled = 1;
+       reset_counts();
+
+       /* Handle PPC64 '.' name */
+       func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
+       func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2);
+       len1 = strlen(func1_name);
+       len2 = strlen(func2_name);
+
+       /*
+        * Probe 1 will trace function 1.
+        * Probe 2 will trace function 2.
+        * Probe 3 will trace functions 1 and 2.
+        */
+       ftrace_set_filter(&test_probe1, func1_name, len1, 1);
+       ftrace_set_filter(&test_probe2, func2_name, len2, 1);
+       ftrace_set_filter(&test_probe3, func1_name, len1, 1);
+       ftrace_set_filter(&test_probe3, func2_name, len2, 0);
+
+       register_ftrace_function(&test_probe1);
+       register_ftrace_function(&test_probe2);
+       register_ftrace_function(&test_probe3);
+       register_ftrace_function(&test_global);
+
+       DYN_FTRACE_TEST_NAME();
+
+       print_counts();
+
+       if (trace_selftest_test_probe1_cnt != 1)
+               goto out;
+       if (trace_selftest_test_probe2_cnt != 0)
+               goto out;
+       if (trace_selftest_test_probe3_cnt != 1)
+               goto out;
+       if (trace_selftest_test_global_cnt == 0)
+               goto out;
+
+       DYN_FTRACE_TEST_NAME2();
+
+       print_counts();
+
+       if (trace_selftest_test_probe1_cnt != 1)
+               goto out;
+       if (trace_selftest_test_probe2_cnt != 1)
+               goto out;
+       if (trace_selftest_test_probe3_cnt != 2)
+               goto out;
+
+       /* Add a dynamic probe */
+       dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL);
+       if (!dyn_ops) {
+               printk("MEMORY ERROR ");
+               goto out;
+       }
+
+       dyn_ops->func = trace_selftest_test_dyn_func;
+
+       register_ftrace_function(dyn_ops);
+
+       trace_selftest_test_global_cnt = 0;
+
+       DYN_FTRACE_TEST_NAME();
+
+       print_counts();
+
+       if (trace_selftest_test_probe1_cnt != 2)
+               goto out_free;
+       if (trace_selftest_test_probe2_cnt != 1)
+               goto out_free;
+       if (trace_selftest_test_probe3_cnt != 3)
+               goto out_free;
+       if (trace_selftest_test_global_cnt == 0)
+               goto out;
+       if (trace_selftest_test_dyn_cnt == 0)
+               goto out_free;
+
+       DYN_FTRACE_TEST_NAME2();
+
+       print_counts();
+
+       if (trace_selftest_test_probe1_cnt != 2)
+               goto out_free;
+       if (trace_selftest_test_probe2_cnt != 2)
+               goto out_free;
+       if (trace_selftest_test_probe3_cnt != 4)
+               goto out_free;
+
+       ret = 0;
+ out_free:
+       unregister_ftrace_function(dyn_ops);
+       kfree(dyn_ops);
+
+ out:
+       /* Purposely unregister in the same order */
+       unregister_ftrace_function(&test_probe1);
+       unregister_ftrace_function(&test_probe2);
+       unregister_ftrace_function(&test_probe3);
+       unregister_ftrace_function(&test_global);
+
+       /* Make sure everything is off */
+       reset_counts();
+       DYN_FTRACE_TEST_NAME();
+       DYN_FTRACE_TEST_NAME();
+
+       if (trace_selftest_test_probe1_cnt ||
+           trace_selftest_test_probe2_cnt ||
+           trace_selftest_test_probe3_cnt ||
+           trace_selftest_test_global_cnt ||
+           trace_selftest_test_dyn_cnt)
+               ret = -1;
+
+       ftrace_enabled = save_ftrace_enabled;
+
+       return ret;
+}
+
 /* Test dynamic code modification and ftrace filters */
 int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
                                           struct trace_array *tr,
@@ -166,16 +366,20 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 
        /* check the trace buffer */
        ret = trace_test_buffer(tr, &count);
-       trace->reset(tr);
        tracing_start();
 
        /* we should only have one item */
        if (!ret && count != 1) {
+               trace->reset(tr);
                printk(KERN_CONT ".. filter failed count=%ld ..", count);
                ret = -1;
                goto out;
        }
 
+       /* Test the ops with global tracing running */
+       ret = trace_selftest_ops(1);
+       trace->reset(tr);
+
  out:
        ftrace_enabled = save_ftrace_enabled;
        tracer_enabled = save_tracer_enabled;
@@ -183,6 +387,10 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
        /* Enable tracing on all functions again */
        ftrace_set_global_filter(NULL, 0, 1);
 
+       /* Test the ops with global tracing off */
+       if (!ret)
+               ret = trace_selftest_ops(2);
+
        return ret;
 }
 #else
index 54dd77cce5bfec6aa956c635f50f1061bea96a8a..b4c475a0a48b8932c2f659beec75ae7d73b1726d 100644 (file)
@@ -5,3 +5,9 @@ int DYN_FTRACE_TEST_NAME(void)
        /* used to call mcount */
        return 0;
 }
+
+int DYN_FTRACE_TEST_NAME2(void)
+{
+       /* used to call mcount */
+       return 0;
+}