cregit-Linux how code gets into the kernel

Release 4.15 kernel/trace/trace_branch.c

Directory: kernel/trace
// SPDX-License-Identifier: GPL-2.0
/*
 * 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_likely_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->data.file + strlen(f->data.file); while (p >= f->data.file && *p != '/') p--; p++; strncpy(entry->func, f->data.func, TRACE_FUNC_SIZE); strncpy(entry->file, p, TRACE_FILE_SIZE); entry->func[TRACE_FUNC_SIZE] = 0; entry->file[TRACE_FILE_SIZE] = 0; entry->constant = f->constant; entry->line = f->data.line; entry->correct = val == expect; if (!call_filter_check_discard(call, entry, buffer, event)) trace_buffer_unlock_commit_nostack(buffer, event); out: current->trace_recursion &= ~TRACE_BRANCH_BIT; raw_local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt27589.00%964.29%
Tom Zanussi216.80%321.43%
Arnaldo Carvalho de Melo123.88%17.14%
Zhenwen Xu10.32%17.14%
Total309100.00%14100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt33100.00%3100.00%
Total33100.00%3100.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 Rostedt3597.22%266.67%
Wenji 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 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 Rostedt1376.47%133.33%
Frédéric Weisbecker211.76%133.33%
Dmitry Safonov211.76%133.33%
Total17100.00%3100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt1285.71%150.00%
Dmitry 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 Rostedt6284.93%360.00%
Arnaldo 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 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
Frédéric Weisbecker4397.73%150.00%
Steven Rostedt12.27%150.00%
Total44100.00%2100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt17100.00%2100.00%
Total17100.00%2100.00%

#endif /* CONFIG_BRANCH_TRACER */
void ftrace_likely_update(struct ftrace_likely_data *f, int val, int expect, int is_constant) { /* A constant is always correct */ if (is_constant) { f->constant++; val = 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->data.correct++; else f->data.incorrect++; }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt67100.00%4100.00%
Total67100.00%4100.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
Frédéric Weisbecker1557.69%133.33%
Steven Rostedt934.62%133.33%
Rasmus 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
Frédéric Weisbecker4071.43%133.33%
Steven Rostedt1628.57%266.67%
Total56100.00%3100.00%


static const char *branch_stat_process_file(struct ftrace_branch_data *p) { const char *f; /* Only print the file, not the path */ f = p->file + strlen(p->file); while (f >= p->file && *f != '/') f--; return ++f; }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt4994.23%266.67%
Frédéric Weisbecker35.77%133.33%
Total52100.00%3100.00%


static void branch_stat_show(struct seq_file *m, struct ftrace_branch_data *p, const char *f) { long percent; /* * The miss is overlayed on correct, and hit on incorrect. */ percent = get_incorrect_percent(p); 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); }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt6894.44%466.67%
Frédéric Weisbecker34.17%116.67%
Rasmus Villemoes11.39%116.67%
Total72100.00%6100.00%


static int branch_stat_show_normal(struct seq_file *m, struct ftrace_branch_data *p, const char *f) { seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); branch_stat_show(m, p, f); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt48100.00%1100.00%
Total48100.00%1100.00%


static int annotate_branch_stat_show(struct seq_file *m, void *v) { struct ftrace_likely_data *p = v; const char *f; int l; f = branch_stat_process_file(&p->data); if (!p->constant) return branch_stat_show_normal(m, &p->data, f); l = snprintf(NULL, 0, "/%lu", p->constant); l = l > 8 ? 0 : 8 - l; seq_printf(m, "%8lu/%lu %*lu ", p->data.correct, p->constant, l, p->data.incorrect); branch_stat_show(m, &p->data, f); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt127100.00%2100.00%
Total127100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Frédéric Weisbecker960.00%133.33%
Steven Rostedt640.00%266.67%
Total15100.00%3100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Frédéric Weisbecker2659.09%133.33%
Steven Rostedt1840.91%266.67%
Total44100.00%3100.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
Frédéric Weisbecker6552.42%133.33%
Steven Rostedt5947.58%266.67%
Total124100.00%3100.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 = annotate_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
Frédéric 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
Frédéric Weisbecker2180.77%133.33%
Steven Rostedt311.54%133.33%
Rasmus 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 Rostedt853.33%266.67%
Frédéric 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
Frédéric Weisbecker3579.55%133.33%
Steven Rostedt920.45%266.67%
Total44100.00%3100.00%


static int all_branch_stat_show(struct seq_file *m, void *v) { struct ftrace_branch_data *p = v; const char *f; f = branch_stat_process_file(p); return branch_stat_show_normal(m, p, f); }

Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt44100.00%1100.00%
Total44100.00%1100.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 = all_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
Frédéric Weisbecker2767.50%250.00%
Steven Rostedt1332.50%250.00%
Total40100.00%4100.00%

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

Overall Contributors

PersonTokensPropCommitsCommitProp
Steven Rostedt113466.90%2458.54%
Frédéric Weisbecker47928.26%512.20%
Zhao Lei261.53%12.44%
Arnaldo Carvalho de Melo231.36%37.32%
Tom Zanussi211.24%37.32%
Rasmus Villemoes50.29%12.44%
Dmitry Safonov40.24%12.44%
Zhenwen Xu10.06%12.44%
Wenji Huang10.06%12.44%
Greg Kroah-Hartman10.06%12.44%
Total1695100.00%41100.00%
Directory: kernel/trace
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.