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/debugfs.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 3194b80ffdSSteven Rostedt probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) 3294b80ffdSSteven Rostedt { 3394b80ffdSSteven Rostedt struct trace_array *tr = branch_tracer; 3494b80ffdSSteven Rostedt struct ring_buffer_event *event; 3594b80ffdSSteven Rostedt struct trace_branch *entry; 3694b80ffdSSteven Rostedt unsigned long flags, irq_flags; 3794b80ffdSSteven Rostedt int cpu, pc; 3894b80ffdSSteven Rostedt const char *p; 3994b80ffdSSteven Rostedt 4094b80ffdSSteven Rostedt /* 4194b80ffdSSteven Rostedt * I would love to save just the ftrace_likely_data pointer, but 4294b80ffdSSteven Rostedt * this code can also be used by modules. Ugly things can happen 4394b80ffdSSteven Rostedt * if the module is unloaded, and then we go and read the 4494b80ffdSSteven Rostedt * pointer. This is slower, but much safer. 4594b80ffdSSteven Rostedt */ 4694b80ffdSSteven Rostedt 4794b80ffdSSteven Rostedt if (unlikely(!tr)) 4894b80ffdSSteven Rostedt return; 4994b80ffdSSteven Rostedt 50a5e25883SSteven Rostedt local_irq_save(flags); 5194b80ffdSSteven Rostedt cpu = raw_smp_processor_id(); 5294b80ffdSSteven Rostedt if (atomic_inc_return(&tr->data[cpu]->disabled) != 1) 5394b80ffdSSteven Rostedt goto out; 5494b80ffdSSteven Rostedt 5594b80ffdSSteven Rostedt event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), 5694b80ffdSSteven Rostedt &irq_flags); 5794b80ffdSSteven Rostedt if (!event) 5894b80ffdSSteven Rostedt goto out; 5994b80ffdSSteven Rostedt 6094b80ffdSSteven Rostedt pc = preempt_count(); 6194b80ffdSSteven Rostedt entry = ring_buffer_event_data(event); 6294b80ffdSSteven Rostedt tracing_generic_entry_update(&entry->ent, flags, pc); 6394b80ffdSSteven Rostedt entry->ent.type = TRACE_BRANCH; 6494b80ffdSSteven Rostedt 6594b80ffdSSteven Rostedt /* Strip off the path, only save the file */ 6694b80ffdSSteven Rostedt p = f->file + strlen(f->file); 6794b80ffdSSteven Rostedt while (p >= f->file && *p != '/') 6894b80ffdSSteven Rostedt p--; 6994b80ffdSSteven Rostedt p++; 7094b80ffdSSteven Rostedt 7194b80ffdSSteven Rostedt strncpy(entry->func, f->func, TRACE_FUNC_SIZE); 7294b80ffdSSteven Rostedt strncpy(entry->file, p, TRACE_FILE_SIZE); 7394b80ffdSSteven Rostedt entry->func[TRACE_FUNC_SIZE] = 0; 7494b80ffdSSteven Rostedt entry->file[TRACE_FILE_SIZE] = 0; 7594b80ffdSSteven Rostedt entry->line = f->line; 7694b80ffdSSteven Rostedt entry->correct = val == expect; 7794b80ffdSSteven Rostedt 7894b80ffdSSteven Rostedt ring_buffer_unlock_commit(tr->buffer, event, irq_flags); 7994b80ffdSSteven Rostedt 8094b80ffdSSteven Rostedt out: 8194b80ffdSSteven Rostedt atomic_dec(&tr->data[cpu]->disabled); 82a5e25883SSteven Rostedt local_irq_restore(flags); 8394b80ffdSSteven Rostedt } 8494b80ffdSSteven Rostedt 8594b80ffdSSteven Rostedt static inline 8694b80ffdSSteven Rostedt void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) 8794b80ffdSSteven Rostedt { 8894b80ffdSSteven Rostedt if (!branch_tracing_enabled) 8994b80ffdSSteven Rostedt return; 9094b80ffdSSteven Rostedt 9194b80ffdSSteven Rostedt probe_likely_condition(f, val, expect); 9294b80ffdSSteven Rostedt } 9394b80ffdSSteven Rostedt 9494b80ffdSSteven Rostedt int enable_branch_tracing(struct trace_array *tr) 9594b80ffdSSteven Rostedt { 9694b80ffdSSteven Rostedt int ret = 0; 9794b80ffdSSteven Rostedt 9894b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex); 9994b80ffdSSteven Rostedt branch_tracer = tr; 10094b80ffdSSteven Rostedt /* 10194b80ffdSSteven Rostedt * Must be seen before enabling. The reader is a condition 10294b80ffdSSteven Rostedt * where we do not need a matching rmb() 10394b80ffdSSteven Rostedt */ 10494b80ffdSSteven Rostedt smp_wmb(); 10594b80ffdSSteven Rostedt branch_tracing_enabled++; 10694b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex); 10794b80ffdSSteven Rostedt 10894b80ffdSSteven Rostedt return ret; 10994b80ffdSSteven Rostedt } 11094b80ffdSSteven Rostedt 11194b80ffdSSteven Rostedt void disable_branch_tracing(void) 11294b80ffdSSteven Rostedt { 11394b80ffdSSteven Rostedt mutex_lock(&branch_tracing_mutex); 11494b80ffdSSteven Rostedt 11594b80ffdSSteven Rostedt if (!branch_tracing_enabled) 11694b80ffdSSteven Rostedt goto out_unlock; 11794b80ffdSSteven Rostedt 11894b80ffdSSteven Rostedt branch_tracing_enabled--; 11994b80ffdSSteven Rostedt 12094b80ffdSSteven Rostedt out_unlock: 12194b80ffdSSteven Rostedt mutex_unlock(&branch_tracing_mutex); 12294b80ffdSSteven Rostedt } 12394b80ffdSSteven Rostedt 12494b80ffdSSteven Rostedt static void start_branch_trace(struct trace_array *tr) 12594b80ffdSSteven Rostedt { 12694b80ffdSSteven Rostedt enable_branch_tracing(tr); 12794b80ffdSSteven Rostedt } 12894b80ffdSSteven Rostedt 12994b80ffdSSteven Rostedt static void stop_branch_trace(struct trace_array *tr) 13094b80ffdSSteven Rostedt { 13194b80ffdSSteven Rostedt disable_branch_tracing(); 13294b80ffdSSteven Rostedt } 13394b80ffdSSteven Rostedt 1341c80025aSFrederic Weisbecker static int branch_trace_init(struct trace_array *tr) 13594b80ffdSSteven Rostedt { 136f04109bfSArnaldo Carvalho de Melo tracing_reset_online_cpus(tr); 13794b80ffdSSteven Rostedt start_branch_trace(tr); 1381c80025aSFrederic Weisbecker return 0; 13994b80ffdSSteven Rostedt } 14094b80ffdSSteven Rostedt 14194b80ffdSSteven Rostedt static void branch_trace_reset(struct trace_array *tr) 14294b80ffdSSteven Rostedt { 14394b80ffdSSteven Rostedt stop_branch_trace(tr); 14494b80ffdSSteven Rostedt } 14594b80ffdSSteven Rostedt 146f633cef0SSteven Rostedt static int 147f633cef0SSteven Rostedt trace_print_print(struct trace_seq *s, struct trace_entry *entry, int flags) 148f633cef0SSteven Rostedt { 149f633cef0SSteven Rostedt struct print_entry *field; 150f633cef0SSteven Rostedt 151f633cef0SSteven Rostedt trace_assign_type(field, entry); 152f633cef0SSteven Rostedt 153f633cef0SSteven Rostedt if (seq_print_ip_sym(s, field->ip, flags)) 154f633cef0SSteven Rostedt goto partial; 155f633cef0SSteven Rostedt 156f633cef0SSteven Rostedt if (trace_seq_printf(s, ": %s", field->buf)) 157f633cef0SSteven Rostedt goto partial; 158f633cef0SSteven Rostedt 159f633cef0SSteven Rostedt partial: 160f633cef0SSteven Rostedt return TRACE_TYPE_PARTIAL_LINE; 161f633cef0SSteven Rostedt } 162f633cef0SSteven Rostedt 163f633cef0SSteven Rostedt static int 164f633cef0SSteven Rostedt trace_branch_print(struct trace_seq *s, struct trace_entry *entry, int flags) 165f633cef0SSteven Rostedt { 166f633cef0SSteven Rostedt struct trace_branch *field; 167f633cef0SSteven Rostedt 168f633cef0SSteven Rostedt trace_assign_type(field, entry); 169f633cef0SSteven Rostedt 170f633cef0SSteven Rostedt if (trace_seq_printf(s, "[%s] %s:%s:%d\n", 171f633cef0SSteven Rostedt field->correct ? " ok " : " MISS ", 172f633cef0SSteven Rostedt field->func, 173f633cef0SSteven Rostedt field->file, 174f633cef0SSteven Rostedt field->line)) 175f633cef0SSteven Rostedt return TRACE_TYPE_PARTIAL_LINE; 176f633cef0SSteven Rostedt 177f633cef0SSteven Rostedt return 0; 178f633cef0SSteven Rostedt } 179f633cef0SSteven Rostedt 180e302cf3fSFrederic Weisbecker 181f633cef0SSteven Rostedt static struct trace_event trace_branch_event = { 182f633cef0SSteven Rostedt .type = TRACE_BRANCH, 183f633cef0SSteven Rostedt .trace = trace_branch_print, 184f633cef0SSteven Rostedt .latency_trace = trace_branch_print, 185f633cef0SSteven Rostedt .raw = trace_nop_print, 186f633cef0SSteven Rostedt .hex = trace_nop_print, 187f633cef0SSteven Rostedt .binary = trace_nop_print, 188f633cef0SSteven Rostedt }; 189f633cef0SSteven Rostedt 190002bb86dSFrederic Weisbecker static struct tracer branch_trace __read_mostly = 191002bb86dSFrederic Weisbecker { 192002bb86dSFrederic Weisbecker .name = "branch", 193002bb86dSFrederic Weisbecker .init = branch_trace_init, 194002bb86dSFrederic Weisbecker .reset = branch_trace_reset, 195002bb86dSFrederic Weisbecker #ifdef CONFIG_FTRACE_SELFTEST 196002bb86dSFrederic Weisbecker .selftest = trace_selftest_startup_branch, 197002bb86dSFrederic Weisbecker #endif /* CONFIG_FTRACE_SELFTEST */ 198002bb86dSFrederic Weisbecker }; 199002bb86dSFrederic Weisbecker 200002bb86dSFrederic Weisbecker __init static int init_branch_tracer(void) 201002bb86dSFrederic Weisbecker { 202002bb86dSFrederic Weisbecker int ret; 203002bb86dSFrederic Weisbecker 204002bb86dSFrederic Weisbecker ret = register_ftrace_event(&trace_branch_event); 205002bb86dSFrederic Weisbecker if (!ret) { 206002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 207002bb86dSFrederic Weisbecker "branch events\n"); 208002bb86dSFrederic Weisbecker return 1; 209002bb86dSFrederic Weisbecker } 210002bb86dSFrederic Weisbecker return register_tracer(&branch_trace); 211002bb86dSFrederic Weisbecker } 212002bb86dSFrederic Weisbecker device_initcall(init_branch_tracer); 213002bb86dSFrederic Weisbecker 21494b80ffdSSteven Rostedt #else 21594b80ffdSSteven Rostedt static inline 21694b80ffdSSteven Rostedt void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) 21794b80ffdSSteven Rostedt { 21894b80ffdSSteven Rostedt } 21994b80ffdSSteven Rostedt #endif /* CONFIG_BRANCH_TRACER */ 22094b80ffdSSteven Rostedt 22194b80ffdSSteven Rostedt void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect) 22294b80ffdSSteven Rostedt { 22394b80ffdSSteven Rostedt /* 22494b80ffdSSteven Rostedt * I would love to have a trace point here instead, but the 22594b80ffdSSteven Rostedt * trace point code is so inundated with unlikely and likely 22694b80ffdSSteven Rostedt * conditions that the recursive nightmare that exists is too 22794b80ffdSSteven Rostedt * much to try to get working. At least for now. 22894b80ffdSSteven Rostedt */ 22994b80ffdSSteven Rostedt trace_likely_condition(f, val, expect); 23094b80ffdSSteven Rostedt 23194b80ffdSSteven Rostedt /* FIXME: Make this atomic! */ 23294b80ffdSSteven Rostedt if (val == expect) 23394b80ffdSSteven Rostedt f->correct++; 23494b80ffdSSteven Rostedt else 23594b80ffdSSteven Rostedt f->incorrect++; 23694b80ffdSSteven Rostedt } 23794b80ffdSSteven Rostedt EXPORT_SYMBOL(ftrace_likely_update); 23894b80ffdSSteven Rostedt 239e302cf3fSFrederic Weisbecker extern unsigned long __start_annotated_branch_profile[]; 240e302cf3fSFrederic Weisbecker extern unsigned long __stop_annotated_branch_profile[]; 24194b80ffdSSteven Rostedt 242e302cf3fSFrederic Weisbecker static int annotated_branch_stat_headers(struct seq_file *m) 24394b80ffdSSteven Rostedt { 2442bcd521aSSteven Rostedt seq_printf(m, " correct incorrect %% "); 2452bcd521aSSteven Rostedt seq_printf(m, " Function " 24694b80ffdSSteven Rostedt " File Line\n" 24794b80ffdSSteven Rostedt " ------- --------- - " 24894b80ffdSSteven Rostedt " -------- " 24994b80ffdSSteven Rostedt " ---- ----\n"); 25094b80ffdSSteven Rostedt return 0; 25194b80ffdSSteven Rostedt } 25294b80ffdSSteven Rostedt 253e302cf3fSFrederic Weisbecker static inline long get_incorrect_percent(struct ftrace_branch_data *p) 254e302cf3fSFrederic Weisbecker { 255e302cf3fSFrederic Weisbecker long percent; 256e302cf3fSFrederic Weisbecker 257e302cf3fSFrederic Weisbecker if (p->correct) { 258e302cf3fSFrederic Weisbecker percent = p->incorrect * 100; 259e302cf3fSFrederic Weisbecker percent /= p->correct + p->incorrect; 260e302cf3fSFrederic Weisbecker } else 261e302cf3fSFrederic Weisbecker percent = p->incorrect ? 100 : -1; 262e302cf3fSFrederic Weisbecker 263e302cf3fSFrederic Weisbecker return percent; 264e302cf3fSFrederic Weisbecker } 265e302cf3fSFrederic Weisbecker 266e302cf3fSFrederic Weisbecker static int branch_stat_show(struct seq_file *m, void *v) 267e302cf3fSFrederic Weisbecker { 268e302cf3fSFrederic Weisbecker struct ftrace_branch_data *p = v; 269e302cf3fSFrederic Weisbecker const char *f; 270e302cf3fSFrederic Weisbecker long percent; 271e302cf3fSFrederic Weisbecker 27294b80ffdSSteven Rostedt /* Only print the file, not the path */ 27394b80ffdSSteven Rostedt f = p->file + strlen(p->file); 27494b80ffdSSteven Rostedt while (f >= p->file && *f != '/') 27594b80ffdSSteven Rostedt f--; 27694b80ffdSSteven Rostedt f++; 27794b80ffdSSteven Rostedt 2782bcd521aSSteven Rostedt /* 2792bcd521aSSteven Rostedt * The miss is overlayed on correct, and hit on incorrect. 2802bcd521aSSteven Rostedt */ 281e302cf3fSFrederic Weisbecker percent = get_incorrect_percent(p); 28294b80ffdSSteven Rostedt 283bac28bfeSSteven Rostedt seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); 284bac28bfeSSteven Rostedt if (percent < 0) 285bac28bfeSSteven Rostedt seq_printf(m, " X "); 286bac28bfeSSteven Rostedt else 287bac28bfeSSteven Rostedt seq_printf(m, "%3ld ", percent); 28894b80ffdSSteven Rostedt seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line); 28994b80ffdSSteven Rostedt return 0; 29094b80ffdSSteven Rostedt } 29194b80ffdSSteven Rostedt 292e302cf3fSFrederic Weisbecker static void *annotated_branch_stat_start(void) 29394b80ffdSSteven Rostedt { 294e302cf3fSFrederic Weisbecker return __start_annotated_branch_profile; 29594b80ffdSSteven Rostedt } 29694b80ffdSSteven Rostedt 297e302cf3fSFrederic Weisbecker static void * 298e302cf3fSFrederic Weisbecker annotated_branch_stat_next(void *v, int idx) 299e302cf3fSFrederic Weisbecker { 300e302cf3fSFrederic Weisbecker struct ftrace_branch_data *p = v; 301e302cf3fSFrederic Weisbecker 302e302cf3fSFrederic Weisbecker ++p; 303e302cf3fSFrederic Weisbecker 304e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_annotated_branch_profile) 305e302cf3fSFrederic Weisbecker return NULL; 306e302cf3fSFrederic Weisbecker 307e302cf3fSFrederic Weisbecker return p; 30894b80ffdSSteven Rostedt } 30994b80ffdSSteven Rostedt 310e302cf3fSFrederic Weisbecker static int annotated_branch_stat_cmp(void *p1, void *p2) 31194b80ffdSSteven Rostedt { 312e302cf3fSFrederic Weisbecker struct ftrace_branch_data *a = p1; 313e302cf3fSFrederic Weisbecker struct ftrace_branch_data *b = p2; 31494b80ffdSSteven Rostedt 315e302cf3fSFrederic Weisbecker long percent_a, percent_b; 31694b80ffdSSteven Rostedt 317e302cf3fSFrederic Weisbecker percent_a = get_incorrect_percent(a); 318e302cf3fSFrederic Weisbecker percent_b = get_incorrect_percent(b); 31994b80ffdSSteven Rostedt 320e302cf3fSFrederic Weisbecker if (percent_a < percent_b) 321e302cf3fSFrederic Weisbecker return -1; 322e302cf3fSFrederic Weisbecker if (percent_a > percent_b) 323e302cf3fSFrederic Weisbecker return 1; 324e302cf3fSFrederic Weisbecker else 32594b80ffdSSteven Rostedt return 0; 32694b80ffdSSteven Rostedt } 32794b80ffdSSteven Rostedt 328002bb86dSFrederic Weisbecker static struct tracer_stat annotated_branch_stats = { 329002bb86dSFrederic Weisbecker .name = "branch_annotated", 330002bb86dSFrederic Weisbecker .stat_start = annotated_branch_stat_start, 331002bb86dSFrederic Weisbecker .stat_next = annotated_branch_stat_next, 332002bb86dSFrederic Weisbecker .stat_cmp = annotated_branch_stat_cmp, 333002bb86dSFrederic Weisbecker .stat_headers = annotated_branch_stat_headers, 334002bb86dSFrederic Weisbecker .stat_show = branch_stat_show 335002bb86dSFrederic Weisbecker }; 336002bb86dSFrederic Weisbecker 337002bb86dSFrederic Weisbecker __init static int init_annotated_branch_stats(void) 338002bb86dSFrederic Weisbecker { 339002bb86dSFrederic Weisbecker int ret; 340002bb86dSFrederic Weisbecker 341002bb86dSFrederic Weisbecker ret = register_stat_tracer(&annotated_branch_stats); 342002bb86dSFrederic Weisbecker if (!ret) { 343002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 344002bb86dSFrederic Weisbecker "annotated branches stats\n"); 345002bb86dSFrederic Weisbecker return 1; 346002bb86dSFrederic Weisbecker } 347002bb86dSFrederic Weisbecker return 0; 348002bb86dSFrederic Weisbecker } 349002bb86dSFrederic Weisbecker fs_initcall(init_annotated_branch_stats); 350002bb86dSFrederic Weisbecker 351e302cf3fSFrederic Weisbecker #ifdef CONFIG_PROFILE_ALL_BRANCHES 352e302cf3fSFrederic Weisbecker 353e302cf3fSFrederic Weisbecker extern unsigned long __start_branch_profile[]; 354e302cf3fSFrederic Weisbecker extern unsigned long __stop_branch_profile[]; 355e302cf3fSFrederic Weisbecker 356e302cf3fSFrederic Weisbecker static int all_branch_stat_headers(struct seq_file *m) 357e302cf3fSFrederic Weisbecker { 358e302cf3fSFrederic Weisbecker seq_printf(m, " miss hit %% "); 359e302cf3fSFrederic Weisbecker seq_printf(m, " Function " 360e302cf3fSFrederic Weisbecker " File Line\n" 361e302cf3fSFrederic Weisbecker " ------- --------- - " 362e302cf3fSFrederic Weisbecker " -------- " 363e302cf3fSFrederic Weisbecker " ---- ----\n"); 364e302cf3fSFrederic Weisbecker return 0; 365e302cf3fSFrederic Weisbecker } 366e302cf3fSFrederic Weisbecker 367e302cf3fSFrederic Weisbecker static void *all_branch_stat_start(void) 368e302cf3fSFrederic Weisbecker { 369e302cf3fSFrederic Weisbecker return __start_branch_profile; 370e302cf3fSFrederic Weisbecker } 371e302cf3fSFrederic Weisbecker 372e302cf3fSFrederic Weisbecker static void * 373e302cf3fSFrederic Weisbecker all_branch_stat_next(void *v, int idx) 374e302cf3fSFrederic Weisbecker { 375e302cf3fSFrederic Weisbecker struct ftrace_branch_data *p = v; 376e302cf3fSFrederic Weisbecker 377e302cf3fSFrederic Weisbecker ++p; 378e302cf3fSFrederic Weisbecker 379e302cf3fSFrederic Weisbecker if ((void *)p >= (void *)__stop_branch_profile) 380e302cf3fSFrederic Weisbecker return NULL; 381e302cf3fSFrederic Weisbecker 382e302cf3fSFrederic Weisbecker return p; 383e302cf3fSFrederic Weisbecker } 384e302cf3fSFrederic Weisbecker 385002bb86dSFrederic Weisbecker static struct tracer_stat all_branch_stats = { 386002bb86dSFrederic Weisbecker .name = "branch_all", 387034939b6SFrederic Weisbecker .stat_start = all_branch_stat_start, 388034939b6SFrederic Weisbecker .stat_next = all_branch_stat_next, 389034939b6SFrederic Weisbecker .stat_headers = all_branch_stat_headers, 390002bb86dSFrederic Weisbecker .stat_show = branch_stat_show 391034939b6SFrederic Weisbecker }; 392034939b6SFrederic Weisbecker 393002bb86dSFrederic Weisbecker __init static int all_annotated_branch_stats(void) 394e302cf3fSFrederic Weisbecker { 395e302cf3fSFrederic Weisbecker int ret; 396002bb86dSFrederic Weisbecker 397002bb86dSFrederic Weisbecker ret = register_stat_tracer(&all_branch_stats); 398e302cf3fSFrederic Weisbecker if (!ret) { 399002bb86dSFrederic Weisbecker printk(KERN_WARNING "Warning: could not register " 400002bb86dSFrederic Weisbecker "all branches stats\n"); 401e302cf3fSFrederic Weisbecker return 1; 402e302cf3fSFrederic Weisbecker } 403002bb86dSFrederic Weisbecker return 0; 404e302cf3fSFrederic Weisbecker } 405002bb86dSFrederic Weisbecker fs_initcall(all_annotated_branch_stats); 406002bb86dSFrederic Weisbecker #endif /* CONFIG_PROFILE_ALL_BRANCHES */ 407