xref: /openbmc/linux/kernel/trace/trace_branch.c (revision 30616929)
194b80ffdSSteven Rostedt /*
294b80ffdSSteven Rostedt  * unlikely profiler
394b80ffdSSteven Rostedt  *
494b80ffdSSteven Rostedt  * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
594b80ffdSSteven Rostedt  */
694b80ffdSSteven Rostedt #include <linux/kallsyms.h>
794b80ffdSSteven Rostedt #include <linux/seq_file.h>
894b80ffdSSteven Rostedt #include <linux/spinlock.h>
965c6dc6aSFrederic Weisbecker #include <linux/irqflags.h>
1094b80ffdSSteven Rostedt #include <linux/uaccess.h>
1194b80ffdSSteven Rostedt #include <linux/module.h>
1294b80ffdSSteven Rostedt #include <linux/ftrace.h>
1394b80ffdSSteven Rostedt #include <linux/hash.h>
1494b80ffdSSteven Rostedt #include <linux/fs.h>
1594b80ffdSSteven Rostedt #include <asm/local.h>
16f633cef0SSteven Rostedt 
1794b80ffdSSteven Rostedt #include "trace.h"
18002bb86dSFrederic Weisbecker #include "trace_stat.h"
19f633cef0SSteven Rostedt #include "trace_output.h"
2094b80ffdSSteven Rostedt 
2194b80ffdSSteven Rostedt #ifdef CONFIG_BRANCH_TRACER
2294b80ffdSSteven Rostedt 
23002bb86dSFrederic Weisbecker static struct tracer branch_trace;
2494b80ffdSSteven Rostedt static int branch_tracing_enabled __read_mostly;
2594b80ffdSSteven Rostedt static DEFINE_MUTEX(branch_tracing_mutex);
26e302cf3fSFrederic Weisbecker 
2794b80ffdSSteven Rostedt static struct trace_array *branch_tracer;
2894b80ffdSSteven Rostedt 
2994b80ffdSSteven Rostedt static void
3094b80ffdSSteven Rostedt probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
3194b80ffdSSteven Rostedt {
322425bcb9SSteven Rostedt (Red Hat) 	struct trace_event_call *call = &event_branch;
3394b80ffdSSteven Rostedt 	struct trace_array *tr = branch_tracer;
34a7603ff4SSteven Rostedt 	struct trace_array_cpu *data;
3594b80ffdSSteven Rostedt 	struct ring_buffer_event *event;
3694b80ffdSSteven Rostedt 	struct trace_branch *entry;
378f6e8a31SSteven Rostedt 	struct ring_buffer *buffer;
380a987751SArnaldo Carvalho de Melo 	unsigned long flags;
396224beb1SSteven Rostedt (Red Hat) 	int pc;
4094b80ffdSSteven Rostedt 	const char *p;
4194b80ffdSSteven Rostedt 
426224beb1SSteven Rostedt (Red Hat) 	if (current->trace_recursion & TRACE_BRANCH_BIT)
436224beb1SSteven Rostedt (Red Hat) 		return;
446224beb1SSteven Rostedt (Red Hat) 
4594b80ffdSSteven Rostedt 	/*
4694b80ffdSSteven Rostedt 	 * I would love to save just the ftrace_likely_data pointer, but
4794b80ffdSSteven Rostedt 	 * this code can also be used by modules. Ugly things can happen
4894b80ffdSSteven Rostedt 	 * if the module is unloaded, and then we go and read the
4994b80ffdSSteven Rostedt 	 * pointer.  This is slower, but much safer.
5094b80ffdSSteven Rostedt 	 */
5194b80ffdSSteven Rostedt 
5294b80ffdSSteven Rostedt 	if (unlikely(!tr))
5394b80ffdSSteven Rostedt 		return;
5494b80ffdSSteven Rostedt 
556224beb1SSteven Rostedt (Red Hat) 	raw_local_irq_save(flags);
566224beb1SSteven Rostedt (Red Hat) 	current->trace_recursion |= TRACE_BRANCH_BIT;
576224beb1SSteven Rostedt (Red Hat) 	data = this_cpu_ptr(tr->trace_buffer.data);
586224beb1SSteven Rostedt (Red Hat) 	if (atomic_read(&data->disabled))
5994b80ffdSSteven Rostedt 		goto out;
6094b80ffdSSteven Rostedt 
6151a763ddSArnaldo Carvalho de Melo 	pc = preempt_count();
62153e8ed9SSteven Rostedt (Red Hat) 	buffer = tr->trace_buffer.buffer;
638f6e8a31SSteven Rostedt 	event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
6451a763ddSArnaldo Carvalho de Melo 					  sizeof(*entry), flags, pc);
6594b80ffdSSteven Rostedt 	if (!event)
6694b80ffdSSteven Rostedt 		goto out;
6794b80ffdSSteven Rostedt 
6894b80ffdSSteven Rostedt 	entry	= ring_buffer_event_data(event);
6994b80ffdSSteven Rostedt 
7094b80ffdSSteven Rostedt 	/* Strip off the path, only save the file */
7194b80ffdSSteven Rostedt 	p = f->file + strlen(f->file);
7294b80ffdSSteven Rostedt 	while (p >= f->file && *p != '/')
7394b80ffdSSteven Rostedt 		p--;
7494b80ffdSSteven Rostedt 	p++;
7594b80ffdSSteven Rostedt 
7694b80ffdSSteven Rostedt 	strncpy(entry->func, f->func, TRACE_FUNC_SIZE);
7794b80ffdSSteven Rostedt 	strncpy(entry->file, p, TRACE_FILE_SIZE);
7894b80ffdSSteven Rostedt 	entry->func[TRACE_FUNC_SIZE] = 0;
7994b80ffdSSteven Rostedt 	entry->file[TRACE_FILE_SIZE] = 0;
8094b80ffdSSteven Rostedt 	entry->line = f->line;
8194b80ffdSSteven Rostedt 	entry->correct = val == expect;
8294b80ffdSSteven Rostedt 
83f306cc82STom Zanussi 	if (!call_filter_check_discard(call, entry, buffer, event))
847ffbd48dSSteven Rostedt 		__buffer_unlock_commit(buffer, event);
8594b80ffdSSteven Rostedt 
8694b80ffdSSteven Rostedt  out:
876224beb1SSteven Rostedt (Red Hat) 	current->trace_recursion &= ~TRACE_BRANCH_BIT;
886224beb1SSteven Rostedt (Red Hat) 	raw_local_irq_restore(flags);
8994b80ffdSSteven Rostedt }
9094b80ffdSSteven Rostedt 
9194b80ffdSSteven Rostedt static inline
9294b80ffdSSteven Rostedt void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
9394b80ffdSSteven Rostedt {
9494b80ffdSSteven Rostedt 	if (!branch_tracing_enabled)
9594b80ffdSSteven Rostedt 		return;
9694b80ffdSSteven Rostedt 
9794b80ffdSSteven Rostedt 	probe_likely_condition(f, val, expect);
9894b80ffdSSteven Rostedt }
9994b80ffdSSteven Rostedt 
10094b80ffdSSteven Rostedt int enable_branch_tracing(struct trace_array *tr)
10194b80ffdSSteven Rostedt {
10294b80ffdSSteven Rostedt 	mutex_lock(&branch_tracing_mutex);
10394b80ffdSSteven Rostedt 	branch_tracer = tr;
10494b80ffdSSteven Rostedt 	/*
10594b80ffdSSteven Rostedt 	 * Must be seen before enabling. The reader is a condition
10694b80ffdSSteven Rostedt 	 * where we do not need a matching rmb()
10794b80ffdSSteven Rostedt 	 */
10894b80ffdSSteven Rostedt 	smp_wmb();
10994b80ffdSSteven Rostedt 	branch_tracing_enabled++;
11094b80ffdSSteven Rostedt 	mutex_unlock(&branch_tracing_mutex);
11194b80ffdSSteven Rostedt 
112f54fc98aSWenji Huang 	return 0;
11394b80ffdSSteven Rostedt }
11494b80ffdSSteven Rostedt 
11594b80ffdSSteven Rostedt void disable_branch_tracing(void)
11694b80ffdSSteven Rostedt {
11794b80ffdSSteven Rostedt 	mutex_lock(&branch_tracing_mutex);
11894b80ffdSSteven Rostedt 
11994b80ffdSSteven Rostedt 	if (!branch_tracing_enabled)
12094b80ffdSSteven Rostedt 		goto out_unlock;
12194b80ffdSSteven Rostedt 
12294b80ffdSSteven Rostedt 	branch_tracing_enabled--;
12394b80ffdSSteven Rostedt 
12494b80ffdSSteven Rostedt  out_unlock:
12594b80ffdSSteven Rostedt 	mutex_unlock(&branch_tracing_mutex);
12694b80ffdSSteven Rostedt }
12794b80ffdSSteven Rostedt 
1281c80025aSFrederic Weisbecker static int branch_trace_init(struct trace_array *tr)
12994b80ffdSSteven Rostedt {
13030616929SDmitry Safonov 	return enable_branch_tracing(tr);
13194b80ffdSSteven Rostedt }
13294b80ffdSSteven Rostedt 
13394b80ffdSSteven Rostedt static void branch_trace_reset(struct trace_array *tr)
13494b80ffdSSteven Rostedt {
13530616929SDmitry Safonov 	disable_branch_tracing();
13694b80ffdSSteven Rostedt }
13794b80ffdSSteven Rostedt 
138ae7462b4SArnaldo Carvalho de Melo static enum print_line_t trace_branch_print(struct trace_iterator *iter,
139a9a57763SSteven Rostedt 					    int flags, struct trace_event *event)
140f633cef0SSteven Rostedt {
141f633cef0SSteven Rostedt 	struct trace_branch *field;
142f633cef0SSteven Rostedt 
1432c9b238eSArnaldo Carvalho de Melo 	trace_assign_type(field, iter->ent);
144f633cef0SSteven Rostedt 
1457d40f671SSteven Rostedt (Red Hat) 	trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
146f633cef0SSteven Rostedt 			 field->correct ? "  ok  " : " MISS ",
147f633cef0SSteven Rostedt 			 field->func,
148f633cef0SSteven Rostedt 			 field->file,
1497d40f671SSteven Rostedt (Red Hat) 			 field->line);
150f633cef0SSteven Rostedt 
1517d40f671SSteven Rostedt (Red Hat) 	return trace_handle_return(&iter->seq);
152f633cef0SSteven Rostedt }
153f633cef0SSteven Rostedt 
154557055beSZhaolei static void branch_print_header(struct seq_file *s)
155557055beSZhaolei {
156557055beSZhaolei 	seq_puts(s, "#           TASK-PID    CPU#    TIMESTAMP  CORRECT"
157d79ac28fSRasmus Villemoes 		    "  FUNC:FILE:LINE\n"
158d79ac28fSRasmus Villemoes 		    "#              | |       |          |         |   "
159557055beSZhaolei 		    "    |\n");
160557055beSZhaolei }
161e302cf3fSFrederic Weisbecker 
162a9a57763SSteven Rostedt static struct trace_event_functions trace_branch_funcs = {
163a9a57763SSteven Rostedt 	.trace		= trace_branch_print,
164a9a57763SSteven Rostedt };
165a9a57763SSteven Rostedt 
166f633cef0SSteven Rostedt static struct trace_event trace_branch_event = {
167f633cef0SSteven Rostedt 	.type		= TRACE_BRANCH,
168a9a57763SSteven Rostedt 	.funcs		= &trace_branch_funcs,
169f633cef0SSteven Rostedt };
170f633cef0SSteven Rostedt 
171002bb86dSFrederic Weisbecker static struct tracer branch_trace __read_mostly =
172002bb86dSFrederic Weisbecker {
173002bb86dSFrederic Weisbecker 	.name		= "branch",
174002bb86dSFrederic Weisbecker 	.init		= branch_trace_init,
175002bb86dSFrederic Weisbecker 	.reset		= branch_trace_reset,
176002bb86dSFrederic Weisbecker #ifdef CONFIG_FTRACE_SELFTEST
177002bb86dSFrederic Weisbecker 	.selftest	= trace_selftest_startup_branch,
178002bb86dSFrederic Weisbecker #endif /* CONFIG_FTRACE_SELFTEST */
179557055beSZhaolei 	.print_header	= branch_print_header,
180002bb86dSFrederic Weisbecker };
181002bb86dSFrederic Weisbecker 
182002bb86dSFrederic Weisbecker __init static int init_branch_tracer(void)
183002bb86dSFrederic Weisbecker {
184002bb86dSFrederic Weisbecker 	int ret;
185002bb86dSFrederic Weisbecker 
1869023c930SSteven Rostedt (Red Hat) 	ret = register_trace_event(&trace_branch_event);
187002bb86dSFrederic Weisbecker 	if (!ret) {
188002bb86dSFrederic Weisbecker 		printk(KERN_WARNING "Warning: could not register "
189002bb86dSFrederic Weisbecker 				    "branch events\n");
190002bb86dSFrederic Weisbecker 		return 1;
191002bb86dSFrederic Weisbecker 	}
192002bb86dSFrederic Weisbecker 	return register_tracer(&branch_trace);
193002bb86dSFrederic Weisbecker }
1946f415672SSteven Rostedt core_initcall(init_branch_tracer);
195002bb86dSFrederic Weisbecker 
19694b80ffdSSteven Rostedt #else
19794b80ffdSSteven Rostedt static inline
19894b80ffdSSteven Rostedt void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
19994b80ffdSSteven Rostedt {
20094b80ffdSSteven Rostedt }
20194b80ffdSSteven Rostedt #endif /* CONFIG_BRANCH_TRACER */
20294b80ffdSSteven Rostedt 
20394b80ffdSSteven Rostedt void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect)
20494b80ffdSSteven Rostedt {
20594b80ffdSSteven Rostedt 	/*
20694b80ffdSSteven Rostedt 	 * I would love to have a trace point here instead, but the
20794b80ffdSSteven Rostedt 	 * trace point code is so inundated with unlikely and likely
20894b80ffdSSteven Rostedt 	 * conditions that the recursive nightmare that exists is too
20994b80ffdSSteven Rostedt 	 * much to try to get working. At least for now.
21094b80ffdSSteven Rostedt 	 */
21194b80ffdSSteven Rostedt 	trace_likely_condition(f, val, expect);
21294b80ffdSSteven Rostedt 
21394b80ffdSSteven Rostedt 	/* FIXME: Make this atomic! */
21494b80ffdSSteven Rostedt 	if (val == expect)
21594b80ffdSSteven Rostedt 		f->correct++;
21694b80ffdSSteven Rostedt 	else
21794b80ffdSSteven Rostedt 		f->incorrect++;
21894b80ffdSSteven Rostedt }
21994b80ffdSSteven Rostedt EXPORT_SYMBOL(ftrace_likely_update);
22094b80ffdSSteven Rostedt 
221e302cf3fSFrederic Weisbecker extern unsigned long __start_annotated_branch_profile[];
222e302cf3fSFrederic Weisbecker extern unsigned long __stop_annotated_branch_profile[];
22394b80ffdSSteven Rostedt 
224e302cf3fSFrederic Weisbecker static int annotated_branch_stat_headers(struct seq_file *m)
22594b80ffdSSteven Rostedt {
226d79ac28fSRasmus Villemoes 	seq_puts(m, " correct incorrect  % "
227d79ac28fSRasmus Villemoes 		    "       Function                "
22894b80ffdSSteven Rostedt 		    "  File              Line\n"
22994b80ffdSSteven Rostedt 		    " ------- ---------  - "
23094b80ffdSSteven Rostedt 		    "       --------                "
23194b80ffdSSteven Rostedt 		    "  ----              ----\n");
23294b80ffdSSteven Rostedt 	return 0;
23394b80ffdSSteven Rostedt }
23494b80ffdSSteven Rostedt 
235e302cf3fSFrederic Weisbecker static inline long get_incorrect_percent(struct ftrace_branch_data *p)
236e302cf3fSFrederic Weisbecker {
237e302cf3fSFrederic Weisbecker 	long percent;
238e302cf3fSFrederic Weisbecker 
239e302cf3fSFrederic Weisbecker 	if (p->correct) {
240e302cf3fSFrederic Weisbecker 		percent = p->incorrect * 100;
241e302cf3fSFrederic Weisbecker 		percent /= p->correct + p->incorrect;
242e302cf3fSFrederic Weisbecker 	} else
243e302cf3fSFrederic Weisbecker 		percent = p->incorrect ? 100 : -1;
244e302cf3fSFrederic Weisbecker 
245e302cf3fSFrederic Weisbecker 	return percent;
246e302cf3fSFrederic Weisbecker }
247e302cf3fSFrederic Weisbecker 
248e302cf3fSFrederic Weisbecker static int branch_stat_show(struct seq_file *m, void *v)
249e302cf3fSFrederic Weisbecker {
250e302cf3fSFrederic Weisbecker 	struct ftrace_branch_data *p = v;
251e302cf3fSFrederic Weisbecker 	const char *f;
252e302cf3fSFrederic Weisbecker 	long percent;
253e302cf3fSFrederic Weisbecker 
25494b80ffdSSteven Rostedt 	/* Only print the file, not the path */
25594b80ffdSSteven Rostedt 	f = p->file + strlen(p->file);
25694b80ffdSSteven Rostedt 	while (f >= p->file && *f != '/')
25794b80ffdSSteven Rostedt 		f--;
25894b80ffdSSteven Rostedt 	f++;
25994b80ffdSSteven Rostedt 
2602bcd521aSSteven Rostedt 	/*
2612bcd521aSSteven Rostedt 	 * The miss is overlayed on correct, and hit on incorrect.
2622bcd521aSSteven Rostedt 	 */
263e302cf3fSFrederic Weisbecker 	percent = get_incorrect_percent(p);
26494b80ffdSSteven Rostedt 
265bac28bfeSSteven Rostedt 	seq_printf(m, "%8lu %8lu ",  p->correct, p->incorrect);
266bac28bfeSSteven Rostedt 	if (percent < 0)
267fa6f0cc7SRasmus Villemoes 		seq_puts(m, "  X ");
268bac28bfeSSteven Rostedt 	else
269bac28bfeSSteven Rostedt 		seq_printf(m, "%3ld ", percent);
27094b80ffdSSteven Rostedt 	seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line);
27194b80ffdSSteven Rostedt 	return 0;
27294b80ffdSSteven Rostedt }
27394b80ffdSSteven Rostedt 
27442548008SSteven Rostedt static void *annotated_branch_stat_start(struct tracer_stat *trace)
27594b80ffdSSteven Rostedt {
276e302cf3fSFrederic Weisbecker 	return __start_annotated_branch_profile;
27794b80ffdSSteven Rostedt }
27894b80ffdSSteven Rostedt 
279e302cf3fSFrederic Weisbecker static void *
280e302cf3fSFrederic Weisbecker annotated_branch_stat_next(void *v, int idx)
281e302cf3fSFrederic Weisbecker {
282e302cf3fSFrederic Weisbecker 	struct ftrace_branch_data *p = v;
283e302cf3fSFrederic Weisbecker 
284e302cf3fSFrederic Weisbecker 	++p;
285e302cf3fSFrederic Weisbecker 
286e302cf3fSFrederic Weisbecker 	if ((void *)p >= (void *)__stop_annotated_branch_profile)
287e302cf3fSFrederic Weisbecker 		return NULL;
288e302cf3fSFrederic Weisbecker 
289e302cf3fSFrederic Weisbecker 	return p;
29094b80ffdSSteven Rostedt }
29194b80ffdSSteven Rostedt 
292e302cf3fSFrederic Weisbecker static int annotated_branch_stat_cmp(void *p1, void *p2)
29394b80ffdSSteven Rostedt {
294e302cf3fSFrederic Weisbecker 	struct ftrace_branch_data *a = p1;
295e302cf3fSFrederic Weisbecker 	struct ftrace_branch_data *b = p2;
29694b80ffdSSteven Rostedt 
297e302cf3fSFrederic Weisbecker 	long percent_a, percent_b;
29894b80ffdSSteven Rostedt 
299e302cf3fSFrederic Weisbecker 	percent_a = get_incorrect_percent(a);
300e302cf3fSFrederic Weisbecker 	percent_b = get_incorrect_percent(b);
30194b80ffdSSteven Rostedt 
302e302cf3fSFrederic Weisbecker 	if (percent_a < percent_b)
303e302cf3fSFrederic Weisbecker 		return -1;
304e302cf3fSFrederic Weisbecker 	if (percent_a > percent_b)
305e302cf3fSFrederic Weisbecker 		return 1;
306ede55c9dSSteven Rostedt 
307ede55c9dSSteven Rostedt 	if (a->incorrect < b->incorrect)
308ede55c9dSSteven Rostedt 		return -1;
309ede55c9dSSteven Rostedt 	if (a->incorrect > b->incorrect)
310ede55c9dSSteven Rostedt 		return 1;
311ede55c9dSSteven Rostedt 
312ede55c9dSSteven Rostedt 	/*
313ede55c9dSSteven Rostedt 	 * Since the above shows worse (incorrect) cases
314ede55c9dSSteven Rostedt 	 * first, we continue that by showing best (correct)
315ede55c9dSSteven Rostedt 	 * cases last.
316ede55c9dSSteven Rostedt 	 */
317ede55c9dSSteven Rostedt 	if (a->correct > b->correct)
318ede55c9dSSteven Rostedt 		return -1;
319ede55c9dSSteven Rostedt 	if (a->correct < b->correct)
320ede55c9dSSteven Rostedt 		return 1;
321ede55c9dSSteven Rostedt 
32294b80ffdSSteven Rostedt 	return 0;
32394b80ffdSSteven Rostedt }
32494b80ffdSSteven Rostedt 
325002bb86dSFrederic Weisbecker static struct tracer_stat annotated_branch_stats = {
326002bb86dSFrederic Weisbecker 	.name = "branch_annotated",
327002bb86dSFrederic Weisbecker 	.stat_start = annotated_branch_stat_start,
328002bb86dSFrederic Weisbecker 	.stat_next = annotated_branch_stat_next,
329002bb86dSFrederic Weisbecker 	.stat_cmp = annotated_branch_stat_cmp,
330002bb86dSFrederic Weisbecker 	.stat_headers = annotated_branch_stat_headers,
331002bb86dSFrederic Weisbecker 	.stat_show = branch_stat_show
332002bb86dSFrederic Weisbecker };
333002bb86dSFrederic Weisbecker 
334002bb86dSFrederic Weisbecker __init static int init_annotated_branch_stats(void)
335002bb86dSFrederic Weisbecker {
336002bb86dSFrederic Weisbecker 	int ret;
337002bb86dSFrederic Weisbecker 
338002bb86dSFrederic Weisbecker 	ret = register_stat_tracer(&annotated_branch_stats);
339002bb86dSFrederic Weisbecker 	if (!ret) {
340002bb86dSFrederic Weisbecker 		printk(KERN_WARNING "Warning: could not register "
341002bb86dSFrederic Weisbecker 				    "annotated branches stats\n");
342002bb86dSFrederic Weisbecker 		return 1;
343002bb86dSFrederic Weisbecker 	}
344002bb86dSFrederic Weisbecker 	return 0;
345002bb86dSFrederic Weisbecker }
346002bb86dSFrederic Weisbecker fs_initcall(init_annotated_branch_stats);
347002bb86dSFrederic Weisbecker 
348e302cf3fSFrederic Weisbecker #ifdef CONFIG_PROFILE_ALL_BRANCHES
349e302cf3fSFrederic Weisbecker 
350e302cf3fSFrederic Weisbecker extern unsigned long __start_branch_profile[];
351e302cf3fSFrederic Weisbecker extern unsigned long __stop_branch_profile[];
352e302cf3fSFrederic Weisbecker 
353e302cf3fSFrederic Weisbecker static int all_branch_stat_headers(struct seq_file *m)
354e302cf3fSFrederic Weisbecker {
355d79ac28fSRasmus Villemoes 	seq_puts(m, "   miss      hit    % "
356d79ac28fSRasmus Villemoes 		    "       Function                "
357e302cf3fSFrederic Weisbecker 		    "  File              Line\n"
358e302cf3fSFrederic Weisbecker 		    " ------- ---------  - "
359e302cf3fSFrederic Weisbecker 		    "       --------                "
360e302cf3fSFrederic Weisbecker 		    "  ----              ----\n");
361e302cf3fSFrederic Weisbecker 	return 0;
362e302cf3fSFrederic Weisbecker }
363e302cf3fSFrederic Weisbecker 
36442548008SSteven Rostedt static void *all_branch_stat_start(struct tracer_stat *trace)
365e302cf3fSFrederic Weisbecker {
366e302cf3fSFrederic Weisbecker 	return __start_branch_profile;
367e302cf3fSFrederic Weisbecker }
368e302cf3fSFrederic Weisbecker 
369e302cf3fSFrederic Weisbecker static void *
370e302cf3fSFrederic Weisbecker all_branch_stat_next(void *v, int idx)
371e302cf3fSFrederic Weisbecker {
372e302cf3fSFrederic Weisbecker 	struct ftrace_branch_data *p = v;
373e302cf3fSFrederic Weisbecker 
374e302cf3fSFrederic Weisbecker 	++p;
375e302cf3fSFrederic Weisbecker 
376e302cf3fSFrederic Weisbecker 	if ((void *)p >= (void *)__stop_branch_profile)
377e302cf3fSFrederic Weisbecker 		return NULL;
378e302cf3fSFrederic Weisbecker 
379e302cf3fSFrederic Weisbecker 	return p;
380e302cf3fSFrederic Weisbecker }
381e302cf3fSFrederic Weisbecker 
382002bb86dSFrederic Weisbecker static struct tracer_stat all_branch_stats = {
383002bb86dSFrederic Weisbecker 	.name = "branch_all",
384034939b6SFrederic Weisbecker 	.stat_start = all_branch_stat_start,
385034939b6SFrederic Weisbecker 	.stat_next = all_branch_stat_next,
386034939b6SFrederic Weisbecker 	.stat_headers = all_branch_stat_headers,
387002bb86dSFrederic Weisbecker 	.stat_show = branch_stat_show
388034939b6SFrederic Weisbecker };
389034939b6SFrederic Weisbecker 
390002bb86dSFrederic Weisbecker __init static int all_annotated_branch_stats(void)
391e302cf3fSFrederic Weisbecker {
392e302cf3fSFrederic Weisbecker 	int ret;
393002bb86dSFrederic Weisbecker 
394002bb86dSFrederic Weisbecker 	ret = register_stat_tracer(&all_branch_stats);
395e302cf3fSFrederic Weisbecker 	if (!ret) {
396002bb86dSFrederic Weisbecker 		printk(KERN_WARNING "Warning: could not register "
397002bb86dSFrederic Weisbecker 				    "all branches stats\n");
398e302cf3fSFrederic Weisbecker 		return 1;
399e302cf3fSFrederic Weisbecker 	}
400002bb86dSFrederic Weisbecker 	return 0;
401e302cf3fSFrederic Weisbecker }
402002bb86dSFrederic Weisbecker fs_initcall(all_annotated_branch_stats);
403002bb86dSFrederic Weisbecker #endif /* CONFIG_PROFILE_ALL_BRANCHES */
404