1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
294b80ffdSSteven Rostedt /*
394b80ffdSSteven Rostedt * unlikely profiler
494b80ffdSSteven Rostedt *
594b80ffdSSteven Rostedt * Copyright (C) 2008 Steven Rostedt <[email protected]>
694b80ffdSSteven Rostedt */
794b80ffdSSteven Rostedt #include <linux/kallsyms.h>
894b80ffdSSteven Rostedt #include <linux/seq_file.h>
994b80ffdSSteven Rostedt #include <linux/spinlock.h>
1065c6dc6aSFrederic Weisbecker #include <linux/irqflags.h>
1194b80ffdSSteven Rostedt #include <linux/uaccess.h>
1294b80ffdSSteven Rostedt #include <linux/module.h>
1394b80ffdSSteven Rostedt #include <linux/ftrace.h>
1494b80ffdSSteven Rostedt #include <linux/hash.h>
1594b80ffdSSteven Rostedt #include <linux/fs.h>
1694b80ffdSSteven Rostedt #include <asm/local.h>
17f633cef0SSteven Rostedt
1894b80ffdSSteven Rostedt #include "trace.h"
19002bb86dSFrederic Weisbecker #include "trace_stat.h"
20f633cef0SSteven Rostedt #include "trace_output.h"
2194b80ffdSSteven Rostedt
2294b80ffdSSteven Rostedt #ifdef CONFIG_BRANCH_TRACER
2394b80ffdSSteven Rostedt
24002bb86dSFrederic Weisbecker static struct tracer branch_trace;
2594b80ffdSSteven Rostedt static int branch_tracing_enabled __read_mostly;
2694b80ffdSSteven Rostedt static DEFINE_MUTEX(branch_tracing_mutex);
27e302cf3fSFrederic Weisbecker
2894b80ffdSSteven Rostedt static struct trace_array *branch_tracer;
2994b80ffdSSteven Rostedt
3094b80ffdSSteven Rostedt static void
probe_likely_condition(struct ftrace_likely_data * f,int val,int expect)31068f530bSSteven Rostedt (VMware) probe_likely_condition(struct ftrace_likely_data *f, int val, int expect)
3294b80ffdSSteven Rostedt {
3394b80ffdSSteven Rostedt struct trace_array *tr = branch_tracer;
3413292494SSteven Rostedt (VMware) struct trace_buffer *buffer;
35a7603ff4SSteven Rostedt struct trace_array_cpu *data;
3694b80ffdSSteven Rostedt struct ring_buffer_event *event;
3794b80ffdSSteven Rostedt struct trace_branch *entry;
380a987751SArnaldo Carvalho de Melo unsigned long flags;
3936590c50SSebastian Andrzej Siewior unsigned int trace_ctx;
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;
571c5eb448SSteven Rostedt (VMware) data = this_cpu_ptr(tr->array_buffer.data);
586224beb1SSteven Rostedt (Red Hat) if (atomic_read(&data->disabled))
5994b80ffdSSteven Rostedt goto out;
6094b80ffdSSteven Rostedt
6136590c50SSebastian Andrzej Siewior trace_ctx = tracing_gen_ctx_flags(flags);
621c5eb448SSteven Rostedt (VMware) buffer = tr->array_buffer.buffer;
638f6e8a31SSteven Rostedt event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
6436590c50SSebastian Andrzej Siewior sizeof(*entry), trace_ctx);
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 */
71068f530bSSteven Rostedt (VMware) p = f->data.file + strlen(f->data.file);
72068f530bSSteven Rostedt (VMware) while (p >= f->data.file && *p != '/')
7394b80ffdSSteven Rostedt p--;
7494b80ffdSSteven Rostedt p++;
7594b80ffdSSteven Rostedt
76*2aa746ecSJustin Stitt strscpy(entry->func, f->data.func);
77*2aa746ecSJustin Stitt strscpy(entry->file, p);
78068f530bSSteven Rostedt (VMware) entry->constant = f->constant;
79068f530bSSteven Rostedt (VMware) entry->line = f->data.line;
8094b80ffdSSteven Rostedt entry->correct = val == expect;
8194b80ffdSSteven Rostedt
8252ffabe3SSteven Rostedt (Red Hat) trace_buffer_unlock_commit_nostack(buffer, event);
8394b80ffdSSteven Rostedt
8494b80ffdSSteven Rostedt out:
856224beb1SSteven Rostedt (Red Hat) current->trace_recursion &= ~TRACE_BRANCH_BIT;
866224beb1SSteven Rostedt (Red Hat) raw_local_irq_restore(flags);
8794b80ffdSSteven Rostedt }
8894b80ffdSSteven Rostedt
8994b80ffdSSteven Rostedt static inline
trace_likely_condition(struct ftrace_likely_data * f,int val,int expect)90068f530bSSteven Rostedt (VMware) void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect)
9194b80ffdSSteven Rostedt {
9294b80ffdSSteven Rostedt if (!branch_tracing_enabled)
9394b80ffdSSteven Rostedt return;
9494b80ffdSSteven Rostedt
9594b80ffdSSteven Rostedt probe_likely_condition(f, val, expect);
9694b80ffdSSteven Rostedt }
9794b80ffdSSteven Rostedt
enable_branch_tracing(struct trace_array * tr)9894b80ffdSSteven Rostedt int enable_branch_tracing(struct trace_array *tr)
9994b80ffdSSteven Rostedt {
10094b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex);
10194b80ffdSSteven Rostedt branch_tracer = tr;
10294b80ffdSSteven Rostedt /*
10394b80ffdSSteven Rostedt * Must be seen before enabling. The reader is a condition
10494b80ffdSSteven Rostedt * where we do not need a matching rmb()
10594b80ffdSSteven Rostedt */
10694b80ffdSSteven Rostedt smp_wmb();
10794b80ffdSSteven Rostedt branch_tracing_enabled++;
10894b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex);
10994b80ffdSSteven Rostedt
110f54fc98aSWenji Huang return 0;
11194b80ffdSSteven Rostedt }
11294b80ffdSSteven Rostedt
disable_branch_tracing(void)11394b80ffdSSteven Rostedt void disable_branch_tracing(void)
11494b80ffdSSteven Rostedt {
11594b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex);
11694b80ffdSSteven Rostedt
11794b80ffdSSteven Rostedt if (!branch_tracing_enabled)
11894b80ffdSSteven Rostedt goto out_unlock;
11994b80ffdSSteven Rostedt
12094b80ffdSSteven Rostedt branch_tracing_enabled--;
12194b80ffdSSteven Rostedt
12294b80ffdSSteven Rostedt out_unlock:
12394b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex);
12494b80ffdSSteven Rostedt }
12594b80ffdSSteven Rostedt
branch_trace_init(struct trace_array * tr)1261c80025aSFrederic Weisbecker static int branch_trace_init(struct trace_array *tr)
12794b80ffdSSteven Rostedt {
12830616929SDmitry Safonov return enable_branch_tracing(tr);
12994b80ffdSSteven Rostedt }
13094b80ffdSSteven Rostedt
branch_trace_reset(struct trace_array * tr)13194b80ffdSSteven Rostedt static void branch_trace_reset(struct trace_array *tr)
13294b80ffdSSteven Rostedt {
13330616929SDmitry Safonov disable_branch_tracing();
13494b80ffdSSteven Rostedt }
13594b80ffdSSteven Rostedt
trace_branch_print(struct trace_iterator * iter,int flags,struct trace_event * event)136ae7462b4SArnaldo Carvalho de Melo static enum print_line_t trace_branch_print(struct trace_iterator *iter,
137a9a57763SSteven Rostedt int flags, struct trace_event *event)
138f633cef0SSteven Rostedt {
139f633cef0SSteven Rostedt struct trace_branch *field;
140f633cef0SSteven Rostedt
1412c9b238eSArnaldo Carvalho de Melo trace_assign_type(field, iter->ent);
142f633cef0SSteven Rostedt
1437d40f671SSteven Rostedt (Red Hat) trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
144f633cef0SSteven Rostedt field->correct ? " ok " : " MISS ",
145f633cef0SSteven Rostedt field->func,
146f633cef0SSteven Rostedt field->file,
1477d40f671SSteven Rostedt (Red Hat) field->line);
148f633cef0SSteven Rostedt
1497d40f671SSteven Rostedt (Red Hat) return trace_handle_return(&iter->seq);
150f633cef0SSteven Rostedt }
151f633cef0SSteven Rostedt
branch_print_header(struct seq_file * s)152557055beSZhaolei static void branch_print_header(struct seq_file *s)
153557055beSZhaolei {
154557055beSZhaolei seq_puts(s, "# TASK-PID CPU# TIMESTAMP CORRECT"
155d79ac28fSRasmus Villemoes " FUNC:FILE:LINE\n"
156d79ac28fSRasmus Villemoes "# | | | | | "
157557055beSZhaolei " |\n");
158557055beSZhaolei }
159e302cf3fSFrederic Weisbecker
160a9a57763SSteven Rostedt static struct trace_event_functions trace_branch_funcs = {
161a9a57763SSteven Rostedt .trace = trace_branch_print,
162a9a57763SSteven Rostedt };
163a9a57763SSteven Rostedt
164f633cef0SSteven Rostedt static struct trace_event trace_branch_event = {
165f633cef0SSteven Rostedt .type = TRACE_BRANCH,
166a9a57763SSteven Rostedt .funcs = &trace_branch_funcs,
167f633cef0SSteven Rostedt };
168f633cef0SSteven Rostedt
169002bb86dSFrederic Weisbecker static struct tracer branch_trace __read_mostly =
170002bb86dSFrederic Weisbecker {
171002bb86dSFrederic Weisbecker .name = "branch",
172002bb86dSFrederic Weisbecker .init = branch_trace_init,
173002bb86dSFrederic Weisbecker .reset = branch_trace_reset,
174002bb86dSFrederic Weisbecker #ifdef CONFIG_FTRACE_SELFTEST
175002bb86dSFrederic Weisbecker .selftest = trace_selftest_startup_branch,
176002bb86dSFrederic Weisbecker #endif /* CONFIG_FTRACE_SELFTEST */
177557055beSZhaolei .print_header = branch_print_header,
178002bb86dSFrederic Weisbecker };
179002bb86dSFrederic Weisbecker
init_branch_tracer(void)180002bb86dSFrederic Weisbecker __init static int init_branch_tracer(void)
181002bb86dSFrederic Weisbecker {
182002bb86dSFrederic Weisbecker int ret;
183002bb86dSFrederic Weisbecker
1849023c930SSteven Rostedt (Red Hat) ret = register_trace_event(&trace_branch_event);
185002bb86dSFrederic Weisbecker if (!ret) {
186002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register "
187002bb86dSFrederic Weisbecker "branch events\n");
188002bb86dSFrederic Weisbecker return 1;
189002bb86dSFrederic Weisbecker }
190002bb86dSFrederic Weisbecker return register_tracer(&branch_trace);
191002bb86dSFrederic Weisbecker }
1926f415672SSteven Rostedt core_initcall(init_branch_tracer);
193002bb86dSFrederic Weisbecker
19494b80ffdSSteven Rostedt #else
19594b80ffdSSteven Rostedt static inline
trace_likely_condition(struct ftrace_likely_data * f,int val,int expect)196068f530bSSteven Rostedt (VMware) void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect)
19794b80ffdSSteven Rostedt {
19894b80ffdSSteven Rostedt }
19994b80ffdSSteven Rostedt #endif /* CONFIG_BRANCH_TRACER */
20094b80ffdSSteven Rostedt
ftrace_likely_update(struct ftrace_likely_data * f,int val,int expect,int is_constant)201134e6a03SSteven Rostedt (VMware) void ftrace_likely_update(struct ftrace_likely_data *f, int val,
202d45ae1f7SSteven Rostedt (VMware) int expect, int is_constant)
20394b80ffdSSteven Rostedt {
2044a6c91fbSPeter Zijlstra unsigned long flags = user_access_save();
2054a6c91fbSPeter Zijlstra
206d45ae1f7SSteven Rostedt (VMware) /* A constant is always correct */
207134e6a03SSteven Rostedt (VMware) if (is_constant) {
208134e6a03SSteven Rostedt (VMware) f->constant++;
209d45ae1f7SSteven Rostedt (VMware) val = expect;
210134e6a03SSteven Rostedt (VMware) }
21194b80ffdSSteven Rostedt /*
21294b80ffdSSteven Rostedt * I would love to have a trace point here instead, but the
21394b80ffdSSteven Rostedt * trace point code is so inundated with unlikely and likely
21494b80ffdSSteven Rostedt * conditions that the recursive nightmare that exists is too
21594b80ffdSSteven Rostedt * much to try to get working. At least for now.
21694b80ffdSSteven Rostedt */
217068f530bSSteven Rostedt (VMware) trace_likely_condition(f, val, expect);
21894b80ffdSSteven Rostedt
21994b80ffdSSteven Rostedt /* FIXME: Make this atomic! */
22094b80ffdSSteven Rostedt if (val == expect)
221134e6a03SSteven Rostedt (VMware) f->data.correct++;
22294b80ffdSSteven Rostedt else
223134e6a03SSteven Rostedt (VMware) f->data.incorrect++;
2244a6c91fbSPeter Zijlstra
2254a6c91fbSPeter Zijlstra user_access_restore(flags);
22694b80ffdSSteven Rostedt }
22794b80ffdSSteven Rostedt EXPORT_SYMBOL(ftrace_likely_update);
22894b80ffdSSteven Rostedt
229e302cf3fSFrederic Weisbecker extern unsigned long __start_annotated_branch_profile[];
230e302cf3fSFrederic Weisbecker extern unsigned long __stop_annotated_branch_profile[];
23194b80ffdSSteven Rostedt
annotated_branch_stat_headers(struct seq_file * m)232e302cf3fSFrederic Weisbecker static int annotated_branch_stat_headers(struct seq_file *m)
23394b80ffdSSteven Rostedt {
234d79ac28fSRasmus Villemoes seq_puts(m, " correct incorrect % "
235d79ac28fSRasmus Villemoes " Function "
23694b80ffdSSteven Rostedt " File Line\n"
23794b80ffdSSteven Rostedt " ------- --------- - "
23894b80ffdSSteven Rostedt " -------- "
23994b80ffdSSteven Rostedt " ---- ----\n");
24094b80ffdSSteven Rostedt return 0;
24194b80ffdSSteven Rostedt }
24294b80ffdSSteven Rostedt
get_incorrect_percent(const struct ftrace_branch_data * p)24380042c8fSAndy Shevchenko static inline long get_incorrect_percent(const struct ftrace_branch_data *p)
244e302cf3fSFrederic Weisbecker {
245e302cf3fSFrederic Weisbecker long percent;
246e302cf3fSFrederic Weisbecker
247e302cf3fSFrederic Weisbecker if (p->correct) {
248e302cf3fSFrederic Weisbecker percent = p->incorrect * 100;
249e302cf3fSFrederic Weisbecker percent /= p->correct + p->incorrect;
250e302cf3fSFrederic Weisbecker } else
251e302cf3fSFrederic Weisbecker percent = p->incorrect ? 100 : -1;
252e302cf3fSFrederic Weisbecker
253e302cf3fSFrederic Weisbecker return percent;
254e302cf3fSFrederic Weisbecker }
255e302cf3fSFrederic Weisbecker
branch_stat_process_file(struct ftrace_branch_data * p)256134e6a03SSteven Rostedt (VMware) static const char *branch_stat_process_file(struct ftrace_branch_data *p)
257e302cf3fSFrederic Weisbecker {
258e302cf3fSFrederic Weisbecker const char *f;
259e302cf3fSFrederic Weisbecker
26094b80ffdSSteven Rostedt /* Only print the file, not the path */
26194b80ffdSSteven Rostedt f = p->file + strlen(p->file);
26294b80ffdSSteven Rostedt while (f >= p->file && *f != '/')
26394b80ffdSSteven Rostedt f--;
264134e6a03SSteven Rostedt (VMware) return ++f;
265134e6a03SSteven Rostedt (VMware) }
266134e6a03SSteven Rostedt (VMware)
branch_stat_show(struct seq_file * m,struct ftrace_branch_data * p,const char * f)267134e6a03SSteven Rostedt (VMware) static void branch_stat_show(struct seq_file *m,
268134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p, const char *f)
269134e6a03SSteven Rostedt (VMware) {
270134e6a03SSteven Rostedt (VMware) long percent;
27194b80ffdSSteven Rostedt
2722bcd521aSSteven Rostedt /*
2732bcd521aSSteven Rostedt * The miss is overlayed on correct, and hit on incorrect.
2742bcd521aSSteven Rostedt */
275e302cf3fSFrederic Weisbecker percent = get_incorrect_percent(p);
27694b80ffdSSteven Rostedt
277bac28bfeSSteven Rostedt if (percent < 0)
278fa6f0cc7SRasmus Villemoes seq_puts(m, " X ");
279bac28bfeSSteven Rostedt else
280bac28bfeSSteven Rostedt seq_printf(m, "%3ld ", percent);
281134e6a03SSteven Rostedt (VMware)
28294b80ffdSSteven Rostedt seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line);
283134e6a03SSteven Rostedt (VMware) }
284134e6a03SSteven Rostedt (VMware)
branch_stat_show_normal(struct seq_file * m,struct ftrace_branch_data * p,const char * f)285134e6a03SSteven Rostedt (VMware) static int branch_stat_show_normal(struct seq_file *m,
286134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p, const char *f)
287134e6a03SSteven Rostedt (VMware) {
288134e6a03SSteven Rostedt (VMware) seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect);
289134e6a03SSteven Rostedt (VMware) branch_stat_show(m, p, f);
290134e6a03SSteven Rostedt (VMware) return 0;
291134e6a03SSteven Rostedt (VMware) }
292134e6a03SSteven Rostedt (VMware)
annotate_branch_stat_show(struct seq_file * m,void * v)293134e6a03SSteven Rostedt (VMware) static int annotate_branch_stat_show(struct seq_file *m, void *v)
294134e6a03SSteven Rostedt (VMware) {
295134e6a03SSteven Rostedt (VMware) struct ftrace_likely_data *p = v;
296134e6a03SSteven Rostedt (VMware) const char *f;
297134e6a03SSteven Rostedt (VMware) int l;
298134e6a03SSteven Rostedt (VMware)
299134e6a03SSteven Rostedt (VMware) f = branch_stat_process_file(&p->data);
300134e6a03SSteven Rostedt (VMware)
301134e6a03SSteven Rostedt (VMware) if (!p->constant)
302134e6a03SSteven Rostedt (VMware) return branch_stat_show_normal(m, &p->data, f);
303134e6a03SSteven Rostedt (VMware)
304134e6a03SSteven Rostedt (VMware) l = snprintf(NULL, 0, "/%lu", p->constant);
305134e6a03SSteven Rostedt (VMware) l = l > 8 ? 0 : 8 - l;
306134e6a03SSteven Rostedt (VMware)
307134e6a03SSteven Rostedt (VMware) seq_printf(m, "%8lu/%lu %*lu ",
308134e6a03SSteven Rostedt (VMware) p->data.correct, p->constant, l, p->data.incorrect);
309134e6a03SSteven Rostedt (VMware) branch_stat_show(m, &p->data, f);
31094b80ffdSSteven Rostedt return 0;
31194b80ffdSSteven Rostedt }
31294b80ffdSSteven Rostedt
annotated_branch_stat_start(struct tracer_stat * trace)31342548008SSteven Rostedt static void *annotated_branch_stat_start(struct tracer_stat *trace)
31494b80ffdSSteven Rostedt {
315e302cf3fSFrederic Weisbecker return __start_annotated_branch_profile;
31694b80ffdSSteven Rostedt }
31794b80ffdSSteven Rostedt
318e302cf3fSFrederic Weisbecker static void *
annotated_branch_stat_next(void * v,int idx)319e302cf3fSFrederic Weisbecker annotated_branch_stat_next(void *v, int idx)
320e302cf3fSFrederic Weisbecker {
321134e6a03SSteven Rostedt (VMware) struct ftrace_likely_data *p = v;
322e302cf3fSFrederic Weisbecker
323e302cf3fSFrederic Weisbecker ++p;
324e302cf3fSFrederic Weisbecker
325e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_annotated_branch_profile)
326e302cf3fSFrederic Weisbecker return NULL;
327e302cf3fSFrederic Weisbecker
328e302cf3fSFrederic Weisbecker return p;
32994b80ffdSSteven Rostedt }
33094b80ffdSSteven Rostedt
annotated_branch_stat_cmp(const void * p1,const void * p2)33180042c8fSAndy Shevchenko static int annotated_branch_stat_cmp(const void *p1, const void *p2)
33294b80ffdSSteven Rostedt {
33380042c8fSAndy Shevchenko const struct ftrace_branch_data *a = p1;
33480042c8fSAndy Shevchenko const struct ftrace_branch_data *b = p2;
33594b80ffdSSteven Rostedt
336e302cf3fSFrederic Weisbecker long percent_a, percent_b;
33794b80ffdSSteven Rostedt
338e302cf3fSFrederic Weisbecker percent_a = get_incorrect_percent(a);
339e302cf3fSFrederic Weisbecker percent_b = get_incorrect_percent(b);
34094b80ffdSSteven Rostedt
341e302cf3fSFrederic Weisbecker if (percent_a < percent_b)
342e302cf3fSFrederic Weisbecker return -1;
343e302cf3fSFrederic Weisbecker if (percent_a > percent_b)
344e302cf3fSFrederic Weisbecker return 1;
345ede55c9dSSteven Rostedt
346ede55c9dSSteven Rostedt if (a->incorrect < b->incorrect)
347ede55c9dSSteven Rostedt return -1;
348ede55c9dSSteven Rostedt if (a->incorrect > b->incorrect)
349ede55c9dSSteven Rostedt return 1;
350ede55c9dSSteven Rostedt
351ede55c9dSSteven Rostedt /*
352ede55c9dSSteven Rostedt * Since the above shows worse (incorrect) cases
353ede55c9dSSteven Rostedt * first, we continue that by showing best (correct)
354ede55c9dSSteven Rostedt * cases last.
355ede55c9dSSteven Rostedt */
356ede55c9dSSteven Rostedt if (a->correct > b->correct)
357ede55c9dSSteven Rostedt return -1;
358ede55c9dSSteven Rostedt if (a->correct < b->correct)
359ede55c9dSSteven Rostedt return 1;
360ede55c9dSSteven Rostedt
36194b80ffdSSteven Rostedt return 0;
36294b80ffdSSteven Rostedt }
36394b80ffdSSteven Rostedt
364002bb86dSFrederic Weisbecker static struct tracer_stat annotated_branch_stats = {
365002bb86dSFrederic Weisbecker .name = "branch_annotated",
366002bb86dSFrederic Weisbecker .stat_start = annotated_branch_stat_start,
367002bb86dSFrederic Weisbecker .stat_next = annotated_branch_stat_next,
368002bb86dSFrederic Weisbecker .stat_cmp = annotated_branch_stat_cmp,
369002bb86dSFrederic Weisbecker .stat_headers = annotated_branch_stat_headers,
370134e6a03SSteven Rostedt (VMware) .stat_show = annotate_branch_stat_show
371002bb86dSFrederic Weisbecker };
372002bb86dSFrederic Weisbecker
init_annotated_branch_stats(void)373002bb86dSFrederic Weisbecker __init static int init_annotated_branch_stats(void)
374002bb86dSFrederic Weisbecker {
375002bb86dSFrederic Weisbecker int ret;
376002bb86dSFrederic Weisbecker
377002bb86dSFrederic Weisbecker ret = register_stat_tracer(&annotated_branch_stats);
378002bb86dSFrederic Weisbecker if (!ret) {
379002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register "
380002bb86dSFrederic Weisbecker "annotated branches stats\n");
381002bb86dSFrederic Weisbecker return 1;
382002bb86dSFrederic Weisbecker }
383002bb86dSFrederic Weisbecker return 0;
384002bb86dSFrederic Weisbecker }
385002bb86dSFrederic Weisbecker fs_initcall(init_annotated_branch_stats);
386002bb86dSFrederic Weisbecker
387e302cf3fSFrederic Weisbecker #ifdef CONFIG_PROFILE_ALL_BRANCHES
388e302cf3fSFrederic Weisbecker
389e302cf3fSFrederic Weisbecker extern unsigned long __start_branch_profile[];
390e302cf3fSFrederic Weisbecker extern unsigned long __stop_branch_profile[];
391e302cf3fSFrederic Weisbecker
all_branch_stat_headers(struct seq_file * m)392e302cf3fSFrederic Weisbecker static int all_branch_stat_headers(struct seq_file *m)
393e302cf3fSFrederic Weisbecker {
394d79ac28fSRasmus Villemoes seq_puts(m, " miss hit % "
395d79ac28fSRasmus Villemoes " Function "
396e302cf3fSFrederic Weisbecker " File Line\n"
397e302cf3fSFrederic Weisbecker " ------- --------- - "
398e302cf3fSFrederic Weisbecker " -------- "
399e302cf3fSFrederic Weisbecker " ---- ----\n");
400e302cf3fSFrederic Weisbecker return 0;
401e302cf3fSFrederic Weisbecker }
402e302cf3fSFrederic Weisbecker
all_branch_stat_start(struct tracer_stat * trace)40342548008SSteven Rostedt static void *all_branch_stat_start(struct tracer_stat *trace)
404e302cf3fSFrederic Weisbecker {
405e302cf3fSFrederic Weisbecker return __start_branch_profile;
406e302cf3fSFrederic Weisbecker }
407e302cf3fSFrederic Weisbecker
408e302cf3fSFrederic Weisbecker static void *
all_branch_stat_next(void * v,int idx)409e302cf3fSFrederic Weisbecker all_branch_stat_next(void *v, int idx)
410e302cf3fSFrederic Weisbecker {
411e302cf3fSFrederic Weisbecker struct ftrace_branch_data *p = v;
412e302cf3fSFrederic Weisbecker
413e302cf3fSFrederic Weisbecker ++p;
414e302cf3fSFrederic Weisbecker
415e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_branch_profile)
416e302cf3fSFrederic Weisbecker return NULL;
417e302cf3fSFrederic Weisbecker
418e302cf3fSFrederic Weisbecker return p;
419e302cf3fSFrederic Weisbecker }
420e302cf3fSFrederic Weisbecker
all_branch_stat_show(struct seq_file * m,void * v)421134e6a03SSteven Rostedt (VMware) static int all_branch_stat_show(struct seq_file *m, void *v)
422134e6a03SSteven Rostedt (VMware) {
423134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p = v;
424134e6a03SSteven Rostedt (VMware) const char *f;
425134e6a03SSteven Rostedt (VMware)
426134e6a03SSteven Rostedt (VMware) f = branch_stat_process_file(p);
427134e6a03SSteven Rostedt (VMware) return branch_stat_show_normal(m, p, f);
428134e6a03SSteven Rostedt (VMware) }
429134e6a03SSteven Rostedt (VMware)
430002bb86dSFrederic Weisbecker static struct tracer_stat all_branch_stats = {
431002bb86dSFrederic Weisbecker .name = "branch_all",
432034939b6SFrederic Weisbecker .stat_start = all_branch_stat_start,
433034939b6SFrederic Weisbecker .stat_next = all_branch_stat_next,
434034939b6SFrederic Weisbecker .stat_headers = all_branch_stat_headers,
435134e6a03SSteven Rostedt (VMware) .stat_show = all_branch_stat_show
436034939b6SFrederic Weisbecker };
437034939b6SFrederic Weisbecker
all_annotated_branch_stats(void)438002bb86dSFrederic Weisbecker __init static int all_annotated_branch_stats(void)
439e302cf3fSFrederic Weisbecker {
440e302cf3fSFrederic Weisbecker int ret;
441002bb86dSFrederic Weisbecker
442002bb86dSFrederic Weisbecker ret = register_stat_tracer(&all_branch_stats);
443e302cf3fSFrederic Weisbecker if (!ret) {
444002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register "
445002bb86dSFrederic Weisbecker "all branches stats\n");
446e302cf3fSFrederic Weisbecker return 1;
447e302cf3fSFrederic Weisbecker }
448002bb86dSFrederic Weisbecker return 0;
449e302cf3fSFrederic Weisbecker }
450002bb86dSFrederic Weisbecker fs_initcall(all_annotated_branch_stats);
451002bb86dSFrederic Weisbecker #endif /* CONFIG_PROFILE_ALL_BRANCHES */
452