xref: /OK3568_Linux_fs/kernel/kernel/trace/trace_branch.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * unlikely profiler
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun #include <linux/kallsyms.h>
8*4882a593Smuzhiyun #include <linux/seq_file.h>
9*4882a593Smuzhiyun #include <linux/spinlock.h>
10*4882a593Smuzhiyun #include <linux/irqflags.h>
11*4882a593Smuzhiyun #include <linux/uaccess.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/ftrace.h>
14*4882a593Smuzhiyun #include <linux/hash.h>
15*4882a593Smuzhiyun #include <linux/fs.h>
16*4882a593Smuzhiyun #include <asm/local.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "trace.h"
19*4882a593Smuzhiyun #include "trace_stat.h"
20*4882a593Smuzhiyun #include "trace_output.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #ifdef CONFIG_BRANCH_TRACER
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static struct tracer branch_trace;
25*4882a593Smuzhiyun static int branch_tracing_enabled __read_mostly;
26*4882a593Smuzhiyun static DEFINE_MUTEX(branch_tracing_mutex);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static struct trace_array *branch_tracer;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static void
probe_likely_condition(struct ftrace_likely_data * f,int val,int expect)31*4882a593Smuzhiyun probe_likely_condition(struct ftrace_likely_data *f, int val, int expect)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct trace_event_call *call = &event_branch;
34*4882a593Smuzhiyun 	struct trace_array *tr = branch_tracer;
35*4882a593Smuzhiyun 	struct trace_buffer *buffer;
36*4882a593Smuzhiyun 	struct trace_array_cpu *data;
37*4882a593Smuzhiyun 	struct ring_buffer_event *event;
38*4882a593Smuzhiyun 	struct trace_branch *entry;
39*4882a593Smuzhiyun 	unsigned long flags;
40*4882a593Smuzhiyun 	int pc;
41*4882a593Smuzhiyun 	const char *p;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (current->trace_recursion & TRACE_BRANCH_BIT)
44*4882a593Smuzhiyun 		return;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/*
47*4882a593Smuzhiyun 	 * I would love to save just the ftrace_likely_data pointer, but
48*4882a593Smuzhiyun 	 * this code can also be used by modules. Ugly things can happen
49*4882a593Smuzhiyun 	 * if the module is unloaded, and then we go and read the
50*4882a593Smuzhiyun 	 * pointer.  This is slower, but much safer.
51*4882a593Smuzhiyun 	 */
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (unlikely(!tr))
54*4882a593Smuzhiyun 		return;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	raw_local_irq_save(flags);
57*4882a593Smuzhiyun 	current->trace_recursion |= TRACE_BRANCH_BIT;
58*4882a593Smuzhiyun 	data = this_cpu_ptr(tr->array_buffer.data);
59*4882a593Smuzhiyun 	if (atomic_read(&data->disabled))
60*4882a593Smuzhiyun 		goto out;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	pc = preempt_count();
63*4882a593Smuzhiyun 	buffer = tr->array_buffer.buffer;
64*4882a593Smuzhiyun 	event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
65*4882a593Smuzhiyun 					  sizeof(*entry), flags, pc);
66*4882a593Smuzhiyun 	if (!event)
67*4882a593Smuzhiyun 		goto out;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	entry	= ring_buffer_event_data(event);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/* Strip off the path, only save the file */
72*4882a593Smuzhiyun 	p = f->data.file + strlen(f->data.file);
73*4882a593Smuzhiyun 	while (p >= f->data.file && *p != '/')
74*4882a593Smuzhiyun 		p--;
75*4882a593Smuzhiyun 	p++;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	strncpy(entry->func, f->data.func, TRACE_FUNC_SIZE);
78*4882a593Smuzhiyun 	strncpy(entry->file, p, TRACE_FILE_SIZE);
79*4882a593Smuzhiyun 	entry->func[TRACE_FUNC_SIZE] = 0;
80*4882a593Smuzhiyun 	entry->file[TRACE_FILE_SIZE] = 0;
81*4882a593Smuzhiyun 	entry->constant = f->constant;
82*4882a593Smuzhiyun 	entry->line = f->data.line;
83*4882a593Smuzhiyun 	entry->correct = val == expect;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!call_filter_check_discard(call, entry, buffer, event))
86*4882a593Smuzhiyun 		trace_buffer_unlock_commit_nostack(buffer, event);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun  out:
89*4882a593Smuzhiyun 	current->trace_recursion &= ~TRACE_BRANCH_BIT;
90*4882a593Smuzhiyun 	raw_local_irq_restore(flags);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static inline
trace_likely_condition(struct ftrace_likely_data * f,int val,int expect)94*4882a593Smuzhiyun void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	if (!branch_tracing_enabled)
97*4882a593Smuzhiyun 		return;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	probe_likely_condition(f, val, expect);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
enable_branch_tracing(struct trace_array * tr)102*4882a593Smuzhiyun int enable_branch_tracing(struct trace_array *tr)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	mutex_lock(&branch_tracing_mutex);
105*4882a593Smuzhiyun 	branch_tracer = tr;
106*4882a593Smuzhiyun 	/*
107*4882a593Smuzhiyun 	 * Must be seen before enabling. The reader is a condition
108*4882a593Smuzhiyun 	 * where we do not need a matching rmb()
109*4882a593Smuzhiyun 	 */
110*4882a593Smuzhiyun 	smp_wmb();
111*4882a593Smuzhiyun 	branch_tracing_enabled++;
112*4882a593Smuzhiyun 	mutex_unlock(&branch_tracing_mutex);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
disable_branch_tracing(void)117*4882a593Smuzhiyun void disable_branch_tracing(void)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	mutex_lock(&branch_tracing_mutex);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (!branch_tracing_enabled)
122*4882a593Smuzhiyun 		goto out_unlock;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	branch_tracing_enabled--;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun  out_unlock:
127*4882a593Smuzhiyun 	mutex_unlock(&branch_tracing_mutex);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
branch_trace_init(struct trace_array * tr)130*4882a593Smuzhiyun static int branch_trace_init(struct trace_array *tr)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	return enable_branch_tracing(tr);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
branch_trace_reset(struct trace_array * tr)135*4882a593Smuzhiyun static void branch_trace_reset(struct trace_array *tr)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	disable_branch_tracing();
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
trace_branch_print(struct trace_iterator * iter,int flags,struct trace_event * event)140*4882a593Smuzhiyun static enum print_line_t trace_branch_print(struct trace_iterator *iter,
141*4882a593Smuzhiyun 					    int flags, struct trace_event *event)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	struct trace_branch *field;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	trace_assign_type(field, iter->ent);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
148*4882a593Smuzhiyun 			 field->correct ? "  ok  " : " MISS ",
149*4882a593Smuzhiyun 			 field->func,
150*4882a593Smuzhiyun 			 field->file,
151*4882a593Smuzhiyun 			 field->line);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return trace_handle_return(&iter->seq);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
branch_print_header(struct seq_file * s)156*4882a593Smuzhiyun static void branch_print_header(struct seq_file *s)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	seq_puts(s, "#           TASK-PID    CPU#    TIMESTAMP  CORRECT"
159*4882a593Smuzhiyun 		    "  FUNC:FILE:LINE\n"
160*4882a593Smuzhiyun 		    "#              | |       |          |         |   "
161*4882a593Smuzhiyun 		    "    |\n");
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static struct trace_event_functions trace_branch_funcs = {
165*4882a593Smuzhiyun 	.trace		= trace_branch_print,
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static struct trace_event trace_branch_event = {
169*4882a593Smuzhiyun 	.type		= TRACE_BRANCH,
170*4882a593Smuzhiyun 	.funcs		= &trace_branch_funcs,
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static struct tracer branch_trace __read_mostly =
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	.name		= "branch",
176*4882a593Smuzhiyun 	.init		= branch_trace_init,
177*4882a593Smuzhiyun 	.reset		= branch_trace_reset,
178*4882a593Smuzhiyun #ifdef CONFIG_FTRACE_SELFTEST
179*4882a593Smuzhiyun 	.selftest	= trace_selftest_startup_branch,
180*4882a593Smuzhiyun #endif /* CONFIG_FTRACE_SELFTEST */
181*4882a593Smuzhiyun 	.print_header	= branch_print_header,
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun 
init_branch_tracer(void)184*4882a593Smuzhiyun __init static int init_branch_tracer(void)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	int ret;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ret = register_trace_event(&trace_branch_event);
189*4882a593Smuzhiyun 	if (!ret) {
190*4882a593Smuzhiyun 		printk(KERN_WARNING "Warning: could not register "
191*4882a593Smuzhiyun 				    "branch events\n");
192*4882a593Smuzhiyun 		return 1;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 	return register_tracer(&branch_trace);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun core_initcall(init_branch_tracer);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun #else
199*4882a593Smuzhiyun static inline
trace_likely_condition(struct ftrace_likely_data * f,int val,int expect)200*4882a593Smuzhiyun void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun #endif /* CONFIG_BRANCH_TRACER */
204*4882a593Smuzhiyun 
ftrace_likely_update(struct ftrace_likely_data * f,int val,int expect,int is_constant)205*4882a593Smuzhiyun void ftrace_likely_update(struct ftrace_likely_data *f, int val,
206*4882a593Smuzhiyun 			  int expect, int is_constant)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	unsigned long flags = user_access_save();
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* A constant is always correct */
211*4882a593Smuzhiyun 	if (is_constant) {
212*4882a593Smuzhiyun 		f->constant++;
213*4882a593Smuzhiyun 		val = expect;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 	/*
216*4882a593Smuzhiyun 	 * I would love to have a trace point here instead, but the
217*4882a593Smuzhiyun 	 * trace point code is so inundated with unlikely and likely
218*4882a593Smuzhiyun 	 * conditions that the recursive nightmare that exists is too
219*4882a593Smuzhiyun 	 * much to try to get working. At least for now.
220*4882a593Smuzhiyun 	 */
221*4882a593Smuzhiyun 	trace_likely_condition(f, val, expect);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/* FIXME: Make this atomic! */
224*4882a593Smuzhiyun 	if (val == expect)
225*4882a593Smuzhiyun 		f->data.correct++;
226*4882a593Smuzhiyun 	else
227*4882a593Smuzhiyun 		f->data.incorrect++;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	user_access_restore(flags);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun EXPORT_SYMBOL(ftrace_likely_update);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun extern unsigned long __start_annotated_branch_profile[];
234*4882a593Smuzhiyun extern unsigned long __stop_annotated_branch_profile[];
235*4882a593Smuzhiyun 
annotated_branch_stat_headers(struct seq_file * m)236*4882a593Smuzhiyun static int annotated_branch_stat_headers(struct seq_file *m)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun 	seq_puts(m, " correct incorrect  % "
239*4882a593Smuzhiyun 		    "       Function                "
240*4882a593Smuzhiyun 		    "  File              Line\n"
241*4882a593Smuzhiyun 		    " ------- ---------  - "
242*4882a593Smuzhiyun 		    "       --------                "
243*4882a593Smuzhiyun 		    "  ----              ----\n");
244*4882a593Smuzhiyun 	return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
get_incorrect_percent(const struct ftrace_branch_data * p)247*4882a593Smuzhiyun static inline long get_incorrect_percent(const struct ftrace_branch_data *p)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	long percent;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (p->correct) {
252*4882a593Smuzhiyun 		percent = p->incorrect * 100;
253*4882a593Smuzhiyun 		percent /= p->correct + p->incorrect;
254*4882a593Smuzhiyun 	} else
255*4882a593Smuzhiyun 		percent = p->incorrect ? 100 : -1;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return percent;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
branch_stat_process_file(struct ftrace_branch_data * p)260*4882a593Smuzhiyun static const char *branch_stat_process_file(struct ftrace_branch_data *p)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	const char *f;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* Only print the file, not the path */
265*4882a593Smuzhiyun 	f = p->file + strlen(p->file);
266*4882a593Smuzhiyun 	while (f >= p->file && *f != '/')
267*4882a593Smuzhiyun 		f--;
268*4882a593Smuzhiyun 	return ++f;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
branch_stat_show(struct seq_file * m,struct ftrace_branch_data * p,const char * f)271*4882a593Smuzhiyun static void branch_stat_show(struct seq_file *m,
272*4882a593Smuzhiyun 			     struct ftrace_branch_data *p, const char *f)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	long percent;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	/*
277*4882a593Smuzhiyun 	 * The miss is overlayed on correct, and hit on incorrect.
278*4882a593Smuzhiyun 	 */
279*4882a593Smuzhiyun 	percent = get_incorrect_percent(p);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (percent < 0)
282*4882a593Smuzhiyun 		seq_puts(m, "  X ");
283*4882a593Smuzhiyun 	else
284*4882a593Smuzhiyun 		seq_printf(m, "%3ld ", percent);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
branch_stat_show_normal(struct seq_file * m,struct ftrace_branch_data * p,const char * f)289*4882a593Smuzhiyun static int branch_stat_show_normal(struct seq_file *m,
290*4882a593Smuzhiyun 				   struct ftrace_branch_data *p, const char *f)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	seq_printf(m, "%8lu %8lu ",  p->correct, p->incorrect);
293*4882a593Smuzhiyun 	branch_stat_show(m, p, f);
294*4882a593Smuzhiyun 	return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
annotate_branch_stat_show(struct seq_file * m,void * v)297*4882a593Smuzhiyun static int annotate_branch_stat_show(struct seq_file *m, void *v)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct ftrace_likely_data *p = v;
300*4882a593Smuzhiyun 	const char *f;
301*4882a593Smuzhiyun 	int l;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	f = branch_stat_process_file(&p->data);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	if (!p->constant)
306*4882a593Smuzhiyun 		return branch_stat_show_normal(m, &p->data, f);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	l = snprintf(NULL, 0, "/%lu", p->constant);
309*4882a593Smuzhiyun 	l = l > 8 ? 0 : 8 - l;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	seq_printf(m, "%8lu/%lu %*lu ",
312*4882a593Smuzhiyun 		   p->data.correct, p->constant, l, p->data.incorrect);
313*4882a593Smuzhiyun 	branch_stat_show(m, &p->data, f);
314*4882a593Smuzhiyun 	return 0;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
annotated_branch_stat_start(struct tracer_stat * trace)317*4882a593Smuzhiyun static void *annotated_branch_stat_start(struct tracer_stat *trace)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	return __start_annotated_branch_profile;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun static void *
annotated_branch_stat_next(void * v,int idx)323*4882a593Smuzhiyun annotated_branch_stat_next(void *v, int idx)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct ftrace_likely_data *p = v;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	++p;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if ((void *)p >= (void *)__stop_annotated_branch_profile)
330*4882a593Smuzhiyun 		return NULL;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	return p;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
annotated_branch_stat_cmp(const void * p1,const void * p2)335*4882a593Smuzhiyun static int annotated_branch_stat_cmp(const void *p1, const void *p2)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	const struct ftrace_branch_data *a = p1;
338*4882a593Smuzhiyun 	const struct ftrace_branch_data *b = p2;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	long percent_a, percent_b;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	percent_a = get_incorrect_percent(a);
343*4882a593Smuzhiyun 	percent_b = get_incorrect_percent(b);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	if (percent_a < percent_b)
346*4882a593Smuzhiyun 		return -1;
347*4882a593Smuzhiyun 	if (percent_a > percent_b)
348*4882a593Smuzhiyun 		return 1;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (a->incorrect < b->incorrect)
351*4882a593Smuzhiyun 		return -1;
352*4882a593Smuzhiyun 	if (a->incorrect > b->incorrect)
353*4882a593Smuzhiyun 		return 1;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/*
356*4882a593Smuzhiyun 	 * Since the above shows worse (incorrect) cases
357*4882a593Smuzhiyun 	 * first, we continue that by showing best (correct)
358*4882a593Smuzhiyun 	 * cases last.
359*4882a593Smuzhiyun 	 */
360*4882a593Smuzhiyun 	if (a->correct > b->correct)
361*4882a593Smuzhiyun 		return -1;
362*4882a593Smuzhiyun 	if (a->correct < b->correct)
363*4882a593Smuzhiyun 		return 1;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun static struct tracer_stat annotated_branch_stats = {
369*4882a593Smuzhiyun 	.name = "branch_annotated",
370*4882a593Smuzhiyun 	.stat_start = annotated_branch_stat_start,
371*4882a593Smuzhiyun 	.stat_next = annotated_branch_stat_next,
372*4882a593Smuzhiyun 	.stat_cmp = annotated_branch_stat_cmp,
373*4882a593Smuzhiyun 	.stat_headers = annotated_branch_stat_headers,
374*4882a593Smuzhiyun 	.stat_show = annotate_branch_stat_show
375*4882a593Smuzhiyun };
376*4882a593Smuzhiyun 
init_annotated_branch_stats(void)377*4882a593Smuzhiyun __init static int init_annotated_branch_stats(void)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	int ret;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	ret = register_stat_tracer(&annotated_branch_stats);
382*4882a593Smuzhiyun 	if (!ret) {
383*4882a593Smuzhiyun 		printk(KERN_WARNING "Warning: could not register "
384*4882a593Smuzhiyun 				    "annotated branches stats\n");
385*4882a593Smuzhiyun 		return 1;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 	return 0;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun fs_initcall(init_annotated_branch_stats);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun #ifdef CONFIG_PROFILE_ALL_BRANCHES
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun extern unsigned long __start_branch_profile[];
394*4882a593Smuzhiyun extern unsigned long __stop_branch_profile[];
395*4882a593Smuzhiyun 
all_branch_stat_headers(struct seq_file * m)396*4882a593Smuzhiyun static int all_branch_stat_headers(struct seq_file *m)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	seq_puts(m, "   miss      hit    % "
399*4882a593Smuzhiyun 		    "       Function                "
400*4882a593Smuzhiyun 		    "  File              Line\n"
401*4882a593Smuzhiyun 		    " ------- ---------  - "
402*4882a593Smuzhiyun 		    "       --------                "
403*4882a593Smuzhiyun 		    "  ----              ----\n");
404*4882a593Smuzhiyun 	return 0;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
all_branch_stat_start(struct tracer_stat * trace)407*4882a593Smuzhiyun static void *all_branch_stat_start(struct tracer_stat *trace)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	return __start_branch_profile;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun static void *
all_branch_stat_next(void * v,int idx)413*4882a593Smuzhiyun all_branch_stat_next(void *v, int idx)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	struct ftrace_branch_data *p = v;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	++p;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if ((void *)p >= (void *)__stop_branch_profile)
420*4882a593Smuzhiyun 		return NULL;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return p;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
all_branch_stat_show(struct seq_file * m,void * v)425*4882a593Smuzhiyun static int all_branch_stat_show(struct seq_file *m, void *v)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	struct ftrace_branch_data *p = v;
428*4882a593Smuzhiyun 	const char *f;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	f = branch_stat_process_file(p);
431*4882a593Smuzhiyun 	return branch_stat_show_normal(m, p, f);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static struct tracer_stat all_branch_stats = {
435*4882a593Smuzhiyun 	.name = "branch_all",
436*4882a593Smuzhiyun 	.stat_start = all_branch_stat_start,
437*4882a593Smuzhiyun 	.stat_next = all_branch_stat_next,
438*4882a593Smuzhiyun 	.stat_headers = all_branch_stat_headers,
439*4882a593Smuzhiyun 	.stat_show = all_branch_stat_show
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun 
all_annotated_branch_stats(void)442*4882a593Smuzhiyun __init static int all_annotated_branch_stats(void)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	int ret;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	ret = register_stat_tracer(&all_branch_stats);
447*4882a593Smuzhiyun 	if (!ret) {
448*4882a593Smuzhiyun 		printk(KERN_WARNING "Warning: could not register "
449*4882a593Smuzhiyun 				    "all branches stats\n");
450*4882a593Smuzhiyun 		return 1;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 	return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun fs_initcall(all_annotated_branch_stats);
455*4882a593Smuzhiyun #endif /* CONFIG_PROFILE_ALL_BRANCHES */
456