1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 294b80ffdSSteven Rostedt /* 394b80ffdSSteven Rostedt * unlikely profiler 494b80ffdSSteven Rostedt * 594b80ffdSSteven Rostedt * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com> 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 31068f530bSSteven Rostedt (VMware) probe_likely_condition(struct ftrace_likely_data *f, int val, int expect) 3294b80ffdSSteven Rostedt { 332425bcb9SSteven Rostedt (Red Hat) struct trace_event_call *call = &event_branch; 3494b80ffdSSteven Rostedt struct trace_array *tr = branch_tracer; 35a7603ff4SSteven Rostedt struct trace_array_cpu *data; 3694b80ffdSSteven Rostedt struct ring_buffer_event *event; 3794b80ffdSSteven Rostedt struct trace_branch *entry; 388f6e8a31SSteven Rostedt struct ring_buffer *buffer; 390a987751SArnaldo Carvalho de Melo unsigned long flags; 406224beb1SSteven Rostedt (Red Hat) int pc; 4194b80ffdSSteven Rostedt const char *p; 4294b80ffdSSteven Rostedt 436224beb1SSteven Rostedt (Red Hat) if (current->trace_recursion & TRACE_BRANCH_BIT) 446224beb1SSteven Rostedt (Red Hat) return; 456224beb1SSteven Rostedt (Red Hat) 4694b80ffdSSteven Rostedt /* 4794b80ffdSSteven Rostedt * I would love to save just the ftrace_likely_data pointer, but 4894b80ffdSSteven Rostedt * this code can also be used by modules. Ugly things can happen 4994b80ffdSSteven Rostedt * if the module is unloaded, and then we go and read the 5094b80ffdSSteven Rostedt * pointer. This is slower, but much safer. 5194b80ffdSSteven Rostedt */ 5294b80ffdSSteven Rostedt 5394b80ffdSSteven Rostedt if (unlikely(!tr)) 5494b80ffdSSteven Rostedt return; 5594b80ffdSSteven Rostedt 566224beb1SSteven Rostedt (Red Hat) raw_local_irq_save(flags); 576224beb1SSteven Rostedt (Red Hat) current->trace_recursion |= TRACE_BRANCH_BIT; 586224beb1SSteven Rostedt (Red Hat) data = this_cpu_ptr(tr->trace_buffer.data); 596224beb1SSteven Rostedt (Red Hat) if (atomic_read(&data->disabled)) 6094b80ffdSSteven Rostedt goto out; 6194b80ffdSSteven Rostedt 6251a763ddSArnaldo Carvalho de Melo pc = preempt_count(); 63153e8ed9SSteven Rostedt (Red Hat) buffer = tr->trace_buffer.buffer; 648f6e8a31SSteven Rostedt event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH, 6551a763ddSArnaldo Carvalho de Melo sizeof(*entry), flags, pc); 6694b80ffdSSteven Rostedt if (!event) 6794b80ffdSSteven Rostedt goto out; 6894b80ffdSSteven Rostedt 6994b80ffdSSteven Rostedt entry = ring_buffer_event_data(event); 7094b80ffdSSteven Rostedt 7194b80ffdSSteven Rostedt /* Strip off the path, only save the file */ 72068f530bSSteven Rostedt (VMware) p = f->data.file + strlen(f->data.file); 73068f530bSSteven Rostedt (VMware) while (p >= f->data.file && *p != '/') 7494b80ffdSSteven Rostedt p--; 7594b80ffdSSteven Rostedt p++; 7694b80ffdSSteven Rostedt 77068f530bSSteven Rostedt (VMware) strncpy(entry->func, f->data.func, TRACE_FUNC_SIZE); 7894b80ffdSSteven Rostedt strncpy(entry->file, p, TRACE_FILE_SIZE); 7994b80ffdSSteven Rostedt entry->func[TRACE_FUNC_SIZE] = 0; 8094b80ffdSSteven Rostedt entry->file[TRACE_FILE_SIZE] = 0; 81068f530bSSteven Rostedt (VMware) entry->constant = f->constant; 82068f530bSSteven Rostedt (VMware) entry->line = f->data.line; 8394b80ffdSSteven Rostedt entry->correct = val == expect; 8494b80ffdSSteven Rostedt 85f306cc82STom Zanussi if (!call_filter_check_discard(call, entry, buffer, event)) 8652ffabe3SSteven Rostedt (Red Hat) trace_buffer_unlock_commit_nostack(buffer, event); 8794b80ffdSSteven Rostedt 8894b80ffdSSteven Rostedt out: 896224beb1SSteven Rostedt (Red Hat) current->trace_recursion &= ~TRACE_BRANCH_BIT; 906224beb1SSteven Rostedt (Red Hat) raw_local_irq_restore(flags); 9194b80ffdSSteven Rostedt } 9294b80ffdSSteven Rostedt 9394b80ffdSSteven Rostedt static inline 94068f530bSSteven Rostedt (VMware) void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect) 9594b80ffdSSteven Rostedt { 9694b80ffdSSteven Rostedt if (!branch_tracing_enabled) 9794b80ffdSSteven Rostedt return; 9894b80ffdSSteven Rostedt 9994b80ffdSSteven Rostedt probe_likely_condition(f, val, expect); 10094b80ffdSSteven Rostedt } 10194b80ffdSSteven Rostedt 10294b80ffdSSteven Rostedt int enable_branch_tracing(struct trace_array *tr) 10394b80ffdSSteven Rostedt { 10494b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex); 10594b80ffdSSteven Rostedt branch_tracer = tr; 10694b80ffdSSteven Rostedt /* 10794b80ffdSSteven Rostedt * Must be seen before enabling. The reader is a condition 10894b80ffdSSteven Rostedt * where we do not need a matching rmb() 10994b80ffdSSteven Rostedt */ 11094b80ffdSSteven Rostedt smp_wmb(); 11194b80ffdSSteven Rostedt branch_tracing_enabled++; 11294b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex); 11394b80ffdSSteven Rostedt 114f54fc98aSWenji Huang return 0; 11594b80ffdSSteven Rostedt } 11694b80ffdSSteven Rostedt 11794b80ffdSSteven Rostedt void disable_branch_tracing(void) 11894b80ffdSSteven Rostedt { 11994b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex); 12094b80ffdSSteven Rostedt 12194b80ffdSSteven Rostedt if (!branch_tracing_enabled) 12294b80ffdSSteven Rostedt goto out_unlock; 12394b80ffdSSteven Rostedt 12494b80ffdSSteven Rostedt branch_tracing_enabled--; 12594b80ffdSSteven Rostedt 12694b80ffdSSteven Rostedt out_unlock: 12794b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex); 12894b80ffdSSteven Rostedt } 12994b80ffdSSteven Rostedt 1301c80025aSFrederic Weisbecker static int branch_trace_init(struct trace_array *tr) 13194b80ffdSSteven Rostedt { 13230616929SDmitry Safonov return enable_branch_tracing(tr); 13394b80ffdSSteven Rostedt } 13494b80ffdSSteven Rostedt 13594b80ffdSSteven Rostedt static void branch_trace_reset(struct trace_array *tr) 13694b80ffdSSteven Rostedt { 13730616929SDmitry Safonov disable_branch_tracing(); 13894b80ffdSSteven Rostedt } 13994b80ffdSSteven Rostedt 140ae7462b4SArnaldo Carvalho de Melo static enum print_line_t trace_branch_print(struct trace_iterator *iter, 141a9a57763SSteven Rostedt int flags, struct trace_event *event) 142f633cef0SSteven Rostedt { 143f633cef0SSteven Rostedt struct trace_branch *field; 144f633cef0SSteven Rostedt 1452c9b238eSArnaldo Carvalho de Melo trace_assign_type(field, iter->ent); 146f633cef0SSteven Rostedt 1477d40f671SSteven Rostedt (Red Hat) trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n", 148f633cef0SSteven Rostedt field->correct ? " ok " : " MISS ", 149f633cef0SSteven Rostedt field->func, 150f633cef0SSteven Rostedt field->file, 1517d40f671SSteven Rostedt (Red Hat) field->line); 152f633cef0SSteven Rostedt 1537d40f671SSteven Rostedt (Red Hat) return trace_handle_return(&iter->seq); 154f633cef0SSteven Rostedt } 155f633cef0SSteven Rostedt 156557055beSZhaolei static void branch_print_header(struct seq_file *s) 157557055beSZhaolei { 158557055beSZhaolei seq_puts(s, "# TASK-PID CPU# TIMESTAMP CORRECT" 159d79ac28fSRasmus Villemoes " FUNC:FILE:LINE\n" 160d79ac28fSRasmus Villemoes "# | | | | | " 161557055beSZhaolei " |\n"); 162557055beSZhaolei } 163e302cf3fSFrederic Weisbecker 164a9a57763SSteven Rostedt static struct trace_event_functions trace_branch_funcs = { 165a9a57763SSteven Rostedt .trace = trace_branch_print, 166a9a57763SSteven Rostedt }; 167a9a57763SSteven Rostedt 168f633cef0SSteven Rostedt static struct trace_event trace_branch_event = { 169f633cef0SSteven Rostedt .type = TRACE_BRANCH, 170a9a57763SSteven Rostedt .funcs = &trace_branch_funcs, 171f633cef0SSteven Rostedt }; 172f633cef0SSteven Rostedt 173002bb86dSFrederic Weisbecker static struct tracer branch_trace __read_mostly = 174002bb86dSFrederic Weisbecker { 175002bb86dSFrederic Weisbecker .name = "branch", 176002bb86dSFrederic Weisbecker .init = branch_trace_init, 177002bb86dSFrederic Weisbecker .reset = branch_trace_reset, 178002bb86dSFrederic Weisbecker #ifdef CONFIG_FTRACE_SELFTEST 179002bb86dSFrederic Weisbecker .selftest = trace_selftest_startup_branch, 180002bb86dSFrederic Weisbecker #endif /* CONFIG_FTRACE_SELFTEST */ 181557055beSZhaolei .print_header = branch_print_header, 182002bb86dSFrederic Weisbecker }; 183002bb86dSFrederic Weisbecker 184002bb86dSFrederic Weisbecker __init static int init_branch_tracer(void) 185002bb86dSFrederic Weisbecker { 186002bb86dSFrederic Weisbecker int ret; 187002bb86dSFrederic Weisbecker 1889023c930SSteven Rostedt (Red Hat) ret = register_trace_event(&trace_branch_event); 189002bb86dSFrederic Weisbecker if (!ret) { 190002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 191002bb86dSFrederic Weisbecker "branch events\n"); 192002bb86dSFrederic Weisbecker return 1; 193002bb86dSFrederic Weisbecker } 194002bb86dSFrederic Weisbecker return register_tracer(&branch_trace); 195002bb86dSFrederic Weisbecker } 1966f415672SSteven Rostedt core_initcall(init_branch_tracer); 197002bb86dSFrederic Weisbecker 19894b80ffdSSteven Rostedt #else 19994b80ffdSSteven Rostedt static inline 200068f530bSSteven Rostedt (VMware) void trace_likely_condition(struct ftrace_likely_data *f, int val, int expect) 20194b80ffdSSteven Rostedt { 20294b80ffdSSteven Rostedt } 20394b80ffdSSteven Rostedt #endif /* CONFIG_BRANCH_TRACER */ 20494b80ffdSSteven Rostedt 205134e6a03SSteven Rostedt (VMware) void ftrace_likely_update(struct ftrace_likely_data *f, int val, 206d45ae1f7SSteven Rostedt (VMware) int expect, int is_constant) 20794b80ffdSSteven Rostedt { 2084a6c91fbSPeter Zijlstra unsigned long flags = user_access_save(); 2094a6c91fbSPeter Zijlstra 210d45ae1f7SSteven Rostedt (VMware) /* A constant is always correct */ 211134e6a03SSteven Rostedt (VMware) if (is_constant) { 212134e6a03SSteven Rostedt (VMware) f->constant++; 213d45ae1f7SSteven Rostedt (VMware) val = expect; 214134e6a03SSteven Rostedt (VMware) } 21594b80ffdSSteven Rostedt /* 21694b80ffdSSteven Rostedt * I would love to have a trace point here instead, but the 21794b80ffdSSteven Rostedt * trace point code is so inundated with unlikely and likely 21894b80ffdSSteven Rostedt * conditions that the recursive nightmare that exists is too 21994b80ffdSSteven Rostedt * much to try to get working. At least for now. 22094b80ffdSSteven Rostedt */ 221068f530bSSteven Rostedt (VMware) trace_likely_condition(f, val, expect); 22294b80ffdSSteven Rostedt 22394b80ffdSSteven Rostedt /* FIXME: Make this atomic! */ 22494b80ffdSSteven Rostedt if (val == expect) 225134e6a03SSteven Rostedt (VMware) f->data.correct++; 22694b80ffdSSteven Rostedt else 227134e6a03SSteven Rostedt (VMware) f->data.incorrect++; 2284a6c91fbSPeter Zijlstra 2294a6c91fbSPeter Zijlstra user_access_restore(flags); 23094b80ffdSSteven Rostedt } 23194b80ffdSSteven Rostedt EXPORT_SYMBOL(ftrace_likely_update); 23294b80ffdSSteven Rostedt 233e302cf3fSFrederic Weisbecker extern unsigned long __start_annotated_branch_profile[]; 234e302cf3fSFrederic Weisbecker extern unsigned long __stop_annotated_branch_profile[]; 23594b80ffdSSteven Rostedt 236e302cf3fSFrederic Weisbecker static int annotated_branch_stat_headers(struct seq_file *m) 23794b80ffdSSteven Rostedt { 238d79ac28fSRasmus Villemoes seq_puts(m, " correct incorrect % " 239d79ac28fSRasmus Villemoes " Function " 24094b80ffdSSteven Rostedt " File Line\n" 24194b80ffdSSteven Rostedt " ------- --------- - " 24294b80ffdSSteven Rostedt " -------- " 24394b80ffdSSteven Rostedt " ---- ----\n"); 24494b80ffdSSteven Rostedt return 0; 24594b80ffdSSteven Rostedt } 24694b80ffdSSteven Rostedt 247e302cf3fSFrederic Weisbecker static inline long get_incorrect_percent(struct ftrace_branch_data *p) 248e302cf3fSFrederic Weisbecker { 249e302cf3fSFrederic Weisbecker long percent; 250e302cf3fSFrederic Weisbecker 251e302cf3fSFrederic Weisbecker if (p->correct) { 252e302cf3fSFrederic Weisbecker percent = p->incorrect * 100; 253e302cf3fSFrederic Weisbecker percent /= p->correct + p->incorrect; 254e302cf3fSFrederic Weisbecker } else 255e302cf3fSFrederic Weisbecker percent = p->incorrect ? 100 : -1; 256e302cf3fSFrederic Weisbecker 257e302cf3fSFrederic Weisbecker return percent; 258e302cf3fSFrederic Weisbecker } 259e302cf3fSFrederic Weisbecker 260134e6a03SSteven Rostedt (VMware) static const char *branch_stat_process_file(struct ftrace_branch_data *p) 261e302cf3fSFrederic Weisbecker { 262e302cf3fSFrederic Weisbecker const char *f; 263e302cf3fSFrederic Weisbecker 26494b80ffdSSteven Rostedt /* Only print the file, not the path */ 26594b80ffdSSteven Rostedt f = p->file + strlen(p->file); 26694b80ffdSSteven Rostedt while (f >= p->file && *f != '/') 26794b80ffdSSteven Rostedt f--; 268134e6a03SSteven Rostedt (VMware) return ++f; 269134e6a03SSteven Rostedt (VMware) } 270134e6a03SSteven Rostedt (VMware) 271134e6a03SSteven Rostedt (VMware) static void branch_stat_show(struct seq_file *m, 272134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p, const char *f) 273134e6a03SSteven Rostedt (VMware) { 274134e6a03SSteven Rostedt (VMware) long percent; 27594b80ffdSSteven Rostedt 2762bcd521aSSteven Rostedt /* 2772bcd521aSSteven Rostedt * The miss is overlayed on correct, and hit on incorrect. 2782bcd521aSSteven Rostedt */ 279e302cf3fSFrederic Weisbecker percent = get_incorrect_percent(p); 28094b80ffdSSteven Rostedt 281bac28bfeSSteven Rostedt if (percent < 0) 282fa6f0cc7SRasmus Villemoes seq_puts(m, " X "); 283bac28bfeSSteven Rostedt else 284bac28bfeSSteven Rostedt seq_printf(m, "%3ld ", percent); 285134e6a03SSteven Rostedt (VMware) 28694b80ffdSSteven Rostedt seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line); 287134e6a03SSteven Rostedt (VMware) } 288134e6a03SSteven Rostedt (VMware) 289134e6a03SSteven Rostedt (VMware) static int branch_stat_show_normal(struct seq_file *m, 290134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p, const char *f) 291134e6a03SSteven Rostedt (VMware) { 292134e6a03SSteven Rostedt (VMware) seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); 293134e6a03SSteven Rostedt (VMware) branch_stat_show(m, p, f); 294134e6a03SSteven Rostedt (VMware) return 0; 295134e6a03SSteven Rostedt (VMware) } 296134e6a03SSteven Rostedt (VMware) 297134e6a03SSteven Rostedt (VMware) static int annotate_branch_stat_show(struct seq_file *m, void *v) 298134e6a03SSteven Rostedt (VMware) { 299134e6a03SSteven Rostedt (VMware) struct ftrace_likely_data *p = v; 300134e6a03SSteven Rostedt (VMware) const char *f; 301134e6a03SSteven Rostedt (VMware) int l; 302134e6a03SSteven Rostedt (VMware) 303134e6a03SSteven Rostedt (VMware) f = branch_stat_process_file(&p->data); 304134e6a03SSteven Rostedt (VMware) 305134e6a03SSteven Rostedt (VMware) if (!p->constant) 306134e6a03SSteven Rostedt (VMware) return branch_stat_show_normal(m, &p->data, f); 307134e6a03SSteven Rostedt (VMware) 308134e6a03SSteven Rostedt (VMware) l = snprintf(NULL, 0, "/%lu", p->constant); 309134e6a03SSteven Rostedt (VMware) l = l > 8 ? 0 : 8 - l; 310134e6a03SSteven Rostedt (VMware) 311134e6a03SSteven Rostedt (VMware) seq_printf(m, "%8lu/%lu %*lu ", 312134e6a03SSteven Rostedt (VMware) p->data.correct, p->constant, l, p->data.incorrect); 313134e6a03SSteven Rostedt (VMware) branch_stat_show(m, &p->data, f); 31494b80ffdSSteven Rostedt return 0; 31594b80ffdSSteven Rostedt } 31694b80ffdSSteven Rostedt 31742548008SSteven Rostedt static void *annotated_branch_stat_start(struct tracer_stat *trace) 31894b80ffdSSteven Rostedt { 319e302cf3fSFrederic Weisbecker return __start_annotated_branch_profile; 32094b80ffdSSteven Rostedt } 32194b80ffdSSteven Rostedt 322e302cf3fSFrederic Weisbecker static void * 323e302cf3fSFrederic Weisbecker annotated_branch_stat_next(void *v, int idx) 324e302cf3fSFrederic Weisbecker { 325134e6a03SSteven Rostedt (VMware) struct ftrace_likely_data *p = v; 326e302cf3fSFrederic Weisbecker 327e302cf3fSFrederic Weisbecker ++p; 328e302cf3fSFrederic Weisbecker 329e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_annotated_branch_profile) 330e302cf3fSFrederic Weisbecker return NULL; 331e302cf3fSFrederic Weisbecker 332e302cf3fSFrederic Weisbecker return p; 33394b80ffdSSteven Rostedt } 33494b80ffdSSteven Rostedt 335e302cf3fSFrederic Weisbecker static int annotated_branch_stat_cmp(void *p1, void *p2) 33694b80ffdSSteven Rostedt { 337e302cf3fSFrederic Weisbecker struct ftrace_branch_data *a = p1; 338e302cf3fSFrederic Weisbecker struct ftrace_branch_data *b = p2; 33994b80ffdSSteven Rostedt 340e302cf3fSFrederic Weisbecker long percent_a, percent_b; 34194b80ffdSSteven Rostedt 342e302cf3fSFrederic Weisbecker percent_a = get_incorrect_percent(a); 343e302cf3fSFrederic Weisbecker percent_b = get_incorrect_percent(b); 34494b80ffdSSteven Rostedt 345e302cf3fSFrederic Weisbecker if (percent_a < percent_b) 346e302cf3fSFrederic Weisbecker return -1; 347e302cf3fSFrederic Weisbecker if (percent_a > percent_b) 348e302cf3fSFrederic Weisbecker return 1; 349ede55c9dSSteven Rostedt 350ede55c9dSSteven Rostedt if (a->incorrect < b->incorrect) 351ede55c9dSSteven Rostedt return -1; 352ede55c9dSSteven Rostedt if (a->incorrect > b->incorrect) 353ede55c9dSSteven Rostedt return 1; 354ede55c9dSSteven Rostedt 355ede55c9dSSteven Rostedt /* 356ede55c9dSSteven Rostedt * Since the above shows worse (incorrect) cases 357ede55c9dSSteven Rostedt * first, we continue that by showing best (correct) 358ede55c9dSSteven Rostedt * cases last. 359ede55c9dSSteven Rostedt */ 360ede55c9dSSteven Rostedt if (a->correct > b->correct) 361ede55c9dSSteven Rostedt return -1; 362ede55c9dSSteven Rostedt if (a->correct < b->correct) 363ede55c9dSSteven Rostedt return 1; 364ede55c9dSSteven Rostedt 36594b80ffdSSteven Rostedt return 0; 36694b80ffdSSteven Rostedt } 36794b80ffdSSteven Rostedt 368002bb86dSFrederic Weisbecker static struct tracer_stat annotated_branch_stats = { 369002bb86dSFrederic Weisbecker .name = "branch_annotated", 370002bb86dSFrederic Weisbecker .stat_start = annotated_branch_stat_start, 371002bb86dSFrederic Weisbecker .stat_next = annotated_branch_stat_next, 372002bb86dSFrederic Weisbecker .stat_cmp = annotated_branch_stat_cmp, 373002bb86dSFrederic Weisbecker .stat_headers = annotated_branch_stat_headers, 374134e6a03SSteven Rostedt (VMware) .stat_show = annotate_branch_stat_show 375002bb86dSFrederic Weisbecker }; 376002bb86dSFrederic Weisbecker 377002bb86dSFrederic Weisbecker __init static int init_annotated_branch_stats(void) 378002bb86dSFrederic Weisbecker { 379002bb86dSFrederic Weisbecker int ret; 380002bb86dSFrederic Weisbecker 381002bb86dSFrederic Weisbecker ret = register_stat_tracer(&annotated_branch_stats); 382002bb86dSFrederic Weisbecker if (!ret) { 383002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 384002bb86dSFrederic Weisbecker "annotated branches stats\n"); 385002bb86dSFrederic Weisbecker return 1; 386002bb86dSFrederic Weisbecker } 387002bb86dSFrederic Weisbecker return 0; 388002bb86dSFrederic Weisbecker } 389002bb86dSFrederic Weisbecker fs_initcall(init_annotated_branch_stats); 390002bb86dSFrederic Weisbecker 391e302cf3fSFrederic Weisbecker #ifdef CONFIG_PROFILE_ALL_BRANCHES 392e302cf3fSFrederic Weisbecker 393e302cf3fSFrederic Weisbecker extern unsigned long __start_branch_profile[]; 394e302cf3fSFrederic Weisbecker extern unsigned long __stop_branch_profile[]; 395e302cf3fSFrederic Weisbecker 396e302cf3fSFrederic Weisbecker static int all_branch_stat_headers(struct seq_file *m) 397e302cf3fSFrederic Weisbecker { 398d79ac28fSRasmus Villemoes seq_puts(m, " miss hit % " 399d79ac28fSRasmus Villemoes " Function " 400e302cf3fSFrederic Weisbecker " File Line\n" 401e302cf3fSFrederic Weisbecker " ------- --------- - " 402e302cf3fSFrederic Weisbecker " -------- " 403e302cf3fSFrederic Weisbecker " ---- ----\n"); 404e302cf3fSFrederic Weisbecker return 0; 405e302cf3fSFrederic Weisbecker } 406e302cf3fSFrederic Weisbecker 40742548008SSteven Rostedt static void *all_branch_stat_start(struct tracer_stat *trace) 408e302cf3fSFrederic Weisbecker { 409e302cf3fSFrederic Weisbecker return __start_branch_profile; 410e302cf3fSFrederic Weisbecker } 411e302cf3fSFrederic Weisbecker 412e302cf3fSFrederic Weisbecker static void * 413e302cf3fSFrederic Weisbecker all_branch_stat_next(void *v, int idx) 414e302cf3fSFrederic Weisbecker { 415e302cf3fSFrederic Weisbecker struct ftrace_branch_data *p = v; 416e302cf3fSFrederic Weisbecker 417e302cf3fSFrederic Weisbecker ++p; 418e302cf3fSFrederic Weisbecker 419e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_branch_profile) 420e302cf3fSFrederic Weisbecker return NULL; 421e302cf3fSFrederic Weisbecker 422e302cf3fSFrederic Weisbecker return p; 423e302cf3fSFrederic Weisbecker } 424e302cf3fSFrederic Weisbecker 425134e6a03SSteven Rostedt (VMware) static int all_branch_stat_show(struct seq_file *m, void *v) 426134e6a03SSteven Rostedt (VMware) { 427134e6a03SSteven Rostedt (VMware) struct ftrace_branch_data *p = v; 428134e6a03SSteven Rostedt (VMware) const char *f; 429134e6a03SSteven Rostedt (VMware) 430134e6a03SSteven Rostedt (VMware) f = branch_stat_process_file(p); 431134e6a03SSteven Rostedt (VMware) return branch_stat_show_normal(m, p, f); 432134e6a03SSteven Rostedt (VMware) } 433134e6a03SSteven Rostedt (VMware) 434002bb86dSFrederic Weisbecker static struct tracer_stat all_branch_stats = { 435002bb86dSFrederic Weisbecker .name = "branch_all", 436034939b6SFrederic Weisbecker .stat_start = all_branch_stat_start, 437034939b6SFrederic Weisbecker .stat_next = all_branch_stat_next, 438034939b6SFrederic Weisbecker .stat_headers = all_branch_stat_headers, 439134e6a03SSteven Rostedt (VMware) .stat_show = all_branch_stat_show 440034939b6SFrederic Weisbecker }; 441034939b6SFrederic Weisbecker 442002bb86dSFrederic Weisbecker __init static int all_annotated_branch_stats(void) 443e302cf3fSFrederic Weisbecker { 444e302cf3fSFrederic Weisbecker int ret; 445002bb86dSFrederic Weisbecker 446002bb86dSFrederic Weisbecker ret = register_stat_tracer(&all_branch_stats); 447e302cf3fSFrederic Weisbecker if (!ret) { 448002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 449002bb86dSFrederic Weisbecker "all branches stats\n"); 450e302cf3fSFrederic Weisbecker return 1; 451e302cf3fSFrederic Weisbecker } 452002bb86dSFrederic Weisbecker return 0; 453e302cf3fSFrederic Weisbecker } 454002bb86dSFrederic Weisbecker fs_initcall(all_annotated_branch_stats); 455002bb86dSFrederic Weisbecker #endif /* CONFIG_PROFILE_ALL_BRANCHES */ 456