Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60a11774 authored by Steven Rostedt's avatar Steven Rostedt Committed by Thomas Gleixner
Browse files

ftrace: add self-tests



Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent e1c08bdd
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -105,3 +105,16 @@ config DYNAMIC_FTRACE
	 wakes up once a second and checks to see if any ftrace calls
	 were made. If so, it runs stop_machine (stops all CPUS)
	 and modifies the code to jump over the call to ftrace.

config FTRACE_SELFTEST
	bool

config FTRACE_STARTUP_TEST
	bool "Perform a startup test on ftrace"
	depends on TRACING
	select FTRACE_SELFTEST
	help
	  This option performs a series of startup tests on ftrace. On bootup
	  a series of tests are made to verify that the tracer is
	  functioning properly. It will do tests on all the configured
	  tracers of ftrace.
+61 −2
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
unsigned long __read_mostly	tracing_max_latency = (cycle_t)ULONG_MAX;
unsigned long __read_mostly	tracing_thresh;

static int tracing_disabled = 1;

static long notrace
ns2usecs(cycle_t nsec)
{
@@ -217,11 +219,48 @@ int register_tracer(struct tracer *type)
		}
	}

#ifdef CONFIG_FTRACE_STARTUP_TEST
	if (type->selftest) {
		struct tracer *saved_tracer = current_trace;
		struct trace_array_cpu *data;
		struct trace_array *tr = &global_trace;
		int saved_ctrl = tr->ctrl;
		int i;
		/*
		 * Run a selftest on this tracer.
		 * Here we reset the trace buffer, and set the current
		 * tracer to be this tracer. The tracer can then run some
		 * internal tracing to verify that everything is in order.
		 * If we fail, we do not register this tracer.
		 */
		for_each_possible_cpu(i) {
			if (!data->trace)
				continue;
			data = tr->data[i];
			tracing_reset(data);
		}
		current_trace = type;
		tr->ctrl = 0;
		/* the test is responsible for initializing and enabling */
		pr_info("Testing tracer %s: ", type->name);
		ret = type->selftest(type, tr);
		/* the test is responsible for resetting too */
		current_trace = saved_tracer;
		tr->ctrl = saved_ctrl;
		if (ret) {
			printk(KERN_CONT "FAILED!\n");
			goto out;
		}
		printk(KERN_CONT "PASSED\n");
	}
#endif

	type->next = trace_types;
	trace_types = type;
	len = strlen(type->name);
	if (len > max_tracer_type_len)
		max_tracer_type_len = len;

 out:
	mutex_unlock(&trace_types_lock);

@@ -985,6 +1024,11 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
{
	struct trace_iterator *iter;

	if (tracing_disabled) {
		*ret = -ENODEV;
		return NULL;
	}

	iter = kzalloc(sizeof(*iter), GFP_KERNEL);
	if (!iter) {
		*ret = -ENOMEM;
@@ -1023,6 +1067,9 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)

int tracing_open_generic(struct inode *inode, struct file *filp)
{
	if (tracing_disabled)
		return -ENODEV;

	filp->private_data = inode->i_private;
	return 0;
}
@@ -1128,6 +1175,9 @@ static int show_traces_open(struct inode *inode, struct file *file)
{
	int ret;

	if (tracing_disabled)
		return -ENODEV;

	ret = seq_open(file, &show_traces_seq_ops);
	if (!ret) {
		struct seq_file *m = file->private_data;
@@ -1452,6 +1502,11 @@ struct dentry *tracing_init_dentry(void)
	return d_tracer;
}

#ifdef CONFIG_FTRACE_SELFTEST
/* Let selftest have access to static functions in this file */
#include "trace_selftest.c"
#endif

static __init void tracer_init_debugfs(void)
{
	struct dentry *d_tracer;
@@ -1585,6 +1640,7 @@ __init static int tracer_alloc_buffers(void)
	void *array;
	struct page *page;
	int pages = 0;
	int ret = -ENOMEM;
	int i;

	/* Allocate the first page for all buffers */
@@ -1650,6 +1706,9 @@ __init static int tracer_alloc_buffers(void)
	register_tracer(&no_tracer);
	current_trace = &no_tracer;

	/* All seems OK, enable tracing */
	tracing_disabled = 0;

	return 0;

 free_buffers:
@@ -1678,7 +1737,7 @@ __init static int tracer_alloc_buffers(void)
		}
#endif
	}
	return -ENOMEM;
	return ret;
}

device_initcall(tracer_alloc_buffers);
fs_initcall(tracer_alloc_buffers);
+31 −0
Original line number Diff line number Diff line
@@ -99,6 +99,10 @@ struct tracer {
	void			(*start)(struct trace_iterator *iter);
	void			(*stop)(struct trace_iterator *iter);
	void			(*ctrl_update)(struct trace_array *tr);
#ifdef CONFIG_FTRACE_STARTUP_TEST
	int			(*selftest)(struct tracer *trace,
					    struct trace_array *tr);
#endif
	struct tracer		*next;
	int			print_max;
};
@@ -185,4 +189,31 @@ extern int unregister_tracer_switch(struct tracer_switch_ops *ops);
extern unsigned long ftrace_update_tot_cnt;
#endif

#ifdef CONFIG_FTRACE_STARTUP_TEST
#ifdef CONFIG_FTRACE
extern int trace_selftest_startup_function(struct tracer *trace,
					   struct trace_array *tr);
#endif
#ifdef CONFIG_IRQSOFF_TRACER
extern int trace_selftest_startup_irqsoff(struct tracer *trace,
					  struct trace_array *tr);
#endif
#ifdef CONFIG_PREEMPT_TRACER
extern int trace_selftest_startup_preemptoff(struct tracer *trace,
					     struct trace_array *tr);
#endif
#if defined(CONFIG_IRQSOFF_TRACER) && defined(CONFIG_PREEMPT_TRACER)
extern int trace_selftest_startup_preemptirqsoff(struct tracer *trace,
						 struct trace_array *tr);
#endif
#ifdef CONFIG_SCHED_TRACER
extern int trace_selftest_startup_wakeup(struct tracer *trace,
					 struct trace_array *tr);
#endif
#ifdef CONFIG_CONTEXT_SWITCH_TRACER
extern int trace_selftest_startup_sched_switch(struct tracer *trace,
					       struct trace_array *tr);
#endif
#endif /* CONFIG_FTRACE_STARTUP_TEST */

#endif /* _LINUX_KERNEL_TRACE_H */
+3 −0
Original line number Diff line number Diff line
@@ -63,6 +63,9 @@ static struct tracer function_trace __read_mostly =
	.init	     = function_trace_init,
	.reset	     = function_trace_reset,
	.ctrl_update = function_trace_ctrl_update,
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_function,
#endif
};

static __init int init_function_trace(void)
+9 −0
Original line number Diff line number Diff line
@@ -432,6 +432,9 @@ static struct tracer irqsoff_tracer __read_mostly =
	.close		= irqsoff_tracer_close,
	.ctrl_update	= irqsoff_tracer_ctrl_update,
	.print_max	= 1,
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_irqsoff,
#endif
};
# define register_irqsoff(trace) register_tracer(&trace)
#else
@@ -455,6 +458,9 @@ static struct tracer preemptoff_tracer __read_mostly =
	.close		= irqsoff_tracer_close,
	.ctrl_update	= irqsoff_tracer_ctrl_update,
	.print_max	= 1,
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_preemptoff,
#endif
};
# define register_preemptoff(trace) register_tracer(&trace)
#else
@@ -480,6 +486,9 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
	.close		= irqsoff_tracer_close,
	.ctrl_update	= irqsoff_tracer_ctrl_update,
	.print_max	= 1,
#ifdef CONFIG_FTRACE_SELFTEST
	.selftest    = trace_selftest_startup_preemptirqsoff,
#endif
};

# define register_preemptirqsoff(trace) register_tracer(&trace)
Loading