cregit-Linux how code gets into the kernel

Release 4.7 kernel/trace/trace_branch.c

Directory: kernel/trace
/*
 * unlikely profiler
 *
 * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
 */
#include <linux/kallsyms.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/irqflags.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/ftrace.h>
#include <linux/hash.h>
#include <linux/fs.h>
#include <asm/local.h>

#include "trace.h"
#include "trace_stat.h"
#include "trace_output.h"

#ifdef CONFIG_BRANCH_TRACER


static struct tracer branch_trace;

static int branch_tracing_enabled __read_mostly;
static DEFINE_MUTEX(branch_tracing_mutex);


static struct trace_array *branch_tracer;


static void probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) { struct trace_event_call *call = &event_branch; struct trace_array *tr = branch_tracer; struct trace_array_cpu *data; struct ring_buffer_event *event; struct trace_branch *entry; struct ring_buffer *buffer; unsigned long flags; int pc; const char *p; if (current->trace_recursion & TRACE_BRANCH_BIT) return; /* * I would love to save just the ftrace_likely_data pointer, but * this code can also be used by modules. Ugly things can happen * if the module is unloaded, and then we go and read the * pointer. This is slower, but much safer. */ if (unlikely(!tr)) return; raw_local_irq_save(flags); current->trace_recursion |= TRACE_BRANCH_BIT; data = this_cpu_ptr(tr->trace_buffer.data); if (atomic_read(&data->disabled)) goto out; pc = preempt_count(); buffer = tr->trace_buffer.buffer; event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH, sizeof(*entry), flags, pc); if (!event) goto out; entry = ring_buffer_event_data(event); /* Strip off the path, only save the file */ p = f->file + strlen(f->file); while (p >= f->file && *p != '/') p--; p++; strncpy(entry->func, f->func, TRACE_FUNC_SIZE); strncpy(entry->file, p, TRACE_FILE_SIZE); entry->func[TRACE_FUNC_SIZE] = 0; entry->file[TRACE_FILE_SIZE] = 0; entry->line = f->line; entry->correct = val == expect; if (!call_filter_check_discard(call, entry, buffer, event)) __buffer_unlock_commit(buffer, event); out: current->trace_recursion &= ~TRACE_BRANCH_BIT; raw_local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt25788.32%861.54%
tom zanussitom zanussi217.22%323.08%
arnaldo carvalho de meloarnaldo carvalho de melo124.12%17.69%
zhenwen xuzhenwen xu10.34%17.69%
Total291100.00%13100.00%


static inline void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) { if (!branch_tracing_enabled) return; probe_likely_condition(f, val, expect); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt33100.00%2100.00%
Total33100.00%2100.00%


int enable_branch_tracing(struct trace_array *tr) { mutex_lock(&branch_tracing_mutex); branch_tracer = tr; /* * Must be seen before enabling. The reader is a condition * where we do not need a matching rmb() */ smp_wmb(); branch_tracing_enabled++; mutex_unlock(&branch_tracing_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt3597.22%266.67%
wenji huangwenji huang12.78%133.33%
Total36100.00%3100.00%


void disable_branch_tracing(void) { mutex_lock(&branch_tracing_mutex); if (!branch_tracing_enabled) goto out_unlock; branch_tracing_enabled--; out_unlock: mutex_unlock(&branch_tracing_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt32100.00%2100.00%
Total32100.00%2100.00%


static int branch_trace_init(struct trace_array *tr) { return enable_branch_tracing(tr); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt1376.47%133.33%
frederic weisbeckerfrederic weisbecker211.76%133.33%
dmitry safonovdmitry safonov211.76%133.33%
Total17100.00%3100.00%


static void branch_trace_reset(struct trace_array *tr) { disable_branch_tracing(); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt1285.71%150.00%
dmitry safonovdmitry safonov214.29%150.00%
Total14100.00%2100.00%


static enum print_line_t trace_branch_print(struct trace_iterator *iter, int flags, struct trace_event *event) { struct trace_branch *field; trace_assign_type(field, iter->ent); trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n", field->correct ? " ok " : " MISS ", field->func, field->file, field->line); return trace_handle_return(&iter->seq); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt6284.93%360.00%
arnaldo carvalho de meloarnaldo carvalho de melo1115.07%240.00%
Total73100.00%5100.00%


static void branch_print_header(struct seq_file *s) { seq_puts(s, "# TASK-PID CPU# TIMESTAMP CORRECT" " FUNC:FILE:LINE\n" "# | | | | | " " |\n"); }

Contributors

PersonTokensPropCommitsCommitProp
zhao leizhao lei21100.00%1100.00%
Total21100.00%1100.00%

static struct trace_event_functions trace_branch_funcs = { .trace = trace_branch_print, }; static struct trace_event trace_branch_event = { .type = TRACE_BRANCH, .funcs = &trace_branch_funcs, }; static struct tracer branch_trace __read_mostly = { .name = "branch", .init = branch_trace_init, .reset = branch_trace_reset, #ifdef CONFIG_FTRACE_SELFTEST .selftest = trace_selftest_startup_branch, #endif /* CONFIG_FTRACE_SELFTEST */ .print_header = branch_print_header, };
__init static int init_branch_tracer(void) { int ret; ret = register_trace_event(&trace_branch_event); if (!ret) { printk(KERN_WARNING "Warning: could not register " "branch events\n"); return 1; } return register_tracer(&branch_trace); }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker4397.73%150.00%
steven rostedtsteven rostedt12.27%150.00%
Total44100.00%2100.00%

core_initcall(init_branch_tracer); #else
static inline void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) { }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt17100.00%2100.00%
Total17100.00%2100.00%

#endif /* CONFIG_BRANCH_TRACER */
void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect) { /* * I would love to have a trace point here instead, but the * trace point code is so inundated with unlikely and likely * conditions that the recursive nightmare that exists is too * much to try to get working. At least for now. */ trace_likely_condition(f, val, expect); /* FIXME: Make this atomic! */ if (val == expect) f->correct++; else f->incorrect++; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt44100.00%3100.00%
Total44100.00%3100.00%

EXPORT_SYMBOL(ftrace_likely_update); extern unsigned long __start_annotated_branch_profile[]; extern unsigned long __stop_annotated_branch_profile[];
static int annotated_branch_stat_headers(struct seq_file *m) { seq_puts(m, " correct incorrect % " " Function " " File Line\n" " ------- --------- - " " -------- " " ---- ----\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker1557.69%133.33%
steven rostedtsteven rostedt934.62%133.33%
rasmus villemoesrasmus villemoes27.69%133.33%
Total26100.00%3100.00%


static inline long get_incorrect_percent(struct ftrace_branch_data *p) { long percent; if (p->correct) { percent = p->incorrect * 100; percent /= p->correct + p->incorrect; } else percent = p->incorrect ? 100 : -1; return percent; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker4071.43%133.33%
steven rostedtsteven rostedt1628.57%266.67%
Total56100.00%3100.00%


static int branch_stat_show(struct seq_file *m, void *v) { struct ftrace_branch_data *p = v; const char *f; long percent; /* Only print the file, not the path */ f = p->file + strlen(p->file); while (f >= p->file && *f != '/') f--; f++; /* * The miss is overlayed on correct, and hit on incorrect. */ percent = get_incorrect_percent(p); seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); if (percent < 0) seq_puts(m, " X "); else seq_printf(m, "%3ld ", percent); seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt11387.60%360.00%
frederic weisbeckerfrederic weisbecker1511.63%120.00%
rasmus villemoesrasmus villemoes10.78%120.00%
Total129100.00%5100.00%


static void *annotated_branch_stat_start(struct tracer_stat *trace) { return __start_annotated_branch_profile; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker960.00%133.33%
steven rostedtsteven rostedt640.00%266.67%
Total15100.00%3100.00%


static void * annotated_branch_stat_next(void *v, int idx) { struct ftrace_branch_data *p = v; ++p; if ((void *)p >= (void *)__stop_annotated_branch_profile) return NULL; return p; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker2761.36%150.00%
steven rostedtsteven rostedt1738.64%150.00%
Total44100.00%2100.00%


static int annotated_branch_stat_cmp(void *p1, void *p2) { struct ftrace_branch_data *a = p1; struct ftrace_branch_data *b = p2; long percent_a, percent_b; percent_a = get_incorrect_percent(a); percent_b = get_incorrect_percent(b); if (percent_a < percent_b) return -1; if (percent_a > percent_b) return 1; if (a->incorrect < b->incorrect) return -1; if (a->incorrect > b->incorrect) return 1; /* * Since the above shows worse (incorrect) cases * first, we continue that by showing best (correct) * cases last. */ if (a->correct > b->correct) return -1; if (a->correct < b->correct) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker6350.81%125.00%
steven rostedtsteven rostedt6149.19%375.00%
Total124100.00%4100.00%

static struct tracer_stat annotated_branch_stats = { .name = "branch_annotated", .stat_start = annotated_branch_stat_start, .stat_next = annotated_branch_stat_next, .stat_cmp = annotated_branch_stat_cmp, .stat_headers = annotated_branch_stat_headers, .stat_show = branch_stat_show };
__init static int init_annotated_branch_stats(void) { int ret; ret = register_stat_tracer(&annotated_branch_stats); if (!ret) { printk(KERN_WARNING "Warning: could not register " "annotated branches stats\n"); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker40100.00%1100.00%
Total40100.00%1100.00%

fs_initcall(init_annotated_branch_stats); #ifdef CONFIG_PROFILE_ALL_BRANCHES extern unsigned long __start_branch_profile[]; extern unsigned long __stop_branch_profile[];
static int all_branch_stat_headers(struct seq_file *m) { seq_puts(m, " miss hit % " " Function " " File Line\n" " ------- --------- - " " -------- " " ---- ----\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker2180.77%133.33%
steven rostedtsteven rostedt311.54%133.33%
rasmus villemoesrasmus villemoes27.69%133.33%
Total26100.00%3100.00%


static void *all_branch_stat_start(struct tracer_stat *trace) { return __start_branch_profile; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt853.33%266.67%
frederic weisbeckerfrederic weisbecker746.67%133.33%
Total15100.00%3100.00%


static void * all_branch_stat_next(void *v, int idx) { struct ftrace_branch_data *p = v; ++p; if ((void *)p >= (void *)__stop_branch_profile) return NULL; return p; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker3579.55%133.33%
steven rostedtsteven rostedt920.45%266.67%
Total44100.00%3100.00%

static struct tracer_stat all_branch_stats = { .name = "branch_all", .stat_start = all_branch_stat_start, .stat_next = all_branch_stat_next, .stat_headers = all_branch_stat_headers, .stat_show = branch_stat_show };
__init static int all_annotated_branch_stats(void) { int ret; ret = register_stat_tracer(&all_branch_stats); if (!ret) { printk(KERN_WARNING "Warning: could not register " "all branches stats\n"); return 1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
frederic weisbeckerfrederic weisbecker2767.50%250.00%
steven rostedtsteven rostedt1332.50%250.00%
Total40100.00%4100.00%

fs_initcall(all_annotated_branch_stats); #endif /* CONFIG_PROFILE_ALL_BRANCHES */

Overall Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt86860.32%2156.76%
frederic weisbeckerfrederic weisbecker49034.05%513.51%
zhao leizhao lei261.81%12.70%
arnaldo carvalho de meloarnaldo carvalho de melo231.60%38.11%
tom zanussitom zanussi211.46%38.11%
rasmus villemoesrasmus villemoes50.35%12.70%
dmitry safonovdmitry safonov40.28%12.70%
wenji huangwenji huang10.07%12.70%
zhenwen xuzhenwen xu10.07%12.70%
Total1439100.00%37100.00%
Directory: kernel/trace
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}