trace: profile all if conditionals
Impact: feature to profile if statements This patch adds a branch profiler for all if () statements. The results will be found in: /debugfs/tracing/profile_branch For example: miss hit % Function File Line ------- --------- - -------- ---- ---- 0 1 100 x86_64_start_reservations head64.c 127 0 1 100 copy_bootdata head64.c 69 1 0 0 x86_64_start_kernel head64.c 111 32 0 0 set_intr_gate desc.h 319 1 0 0 reserve_ebda_region head.c 51 1 0 0 reserve_ebda_region head.c 47 0 1 100 reserve_ebda_region head.c 42 0 0 X maxcpus main.c 165 Miss means the branch was not taken. Hit means the branch was taken. The percent is the percentage the branch was taken. This adds a significant amount of overhead and should only be used by those analyzing their system. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
bac28bfe42
commit
2bcd521a68
@ -53,6 +53,14 @@
|
|||||||
#define LIKELY_PROFILE()
|
#define LIKELY_PROFILE()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||||
|
#define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \
|
||||||
|
*(_ftrace_branch) \
|
||||||
|
VMLINUX_SYMBOL(__stop_branch_profile) = .;
|
||||||
|
#else
|
||||||
|
#define BRANCH_PROFILE()
|
||||||
|
#endif
|
||||||
|
|
||||||
/* .data section */
|
/* .data section */
|
||||||
#define DATA_DATA \
|
#define DATA_DATA \
|
||||||
*(.data) \
|
*(.data) \
|
||||||
@ -72,7 +80,8 @@
|
|||||||
VMLINUX_SYMBOL(__start___tracepoints) = .; \
|
VMLINUX_SYMBOL(__start___tracepoints) = .; \
|
||||||
*(__tracepoints) \
|
*(__tracepoints) \
|
||||||
VMLINUX_SYMBOL(__stop___tracepoints) = .; \
|
VMLINUX_SYMBOL(__stop___tracepoints) = .; \
|
||||||
LIKELY_PROFILE()
|
LIKELY_PROFILE() \
|
||||||
|
BRANCH_PROFILE()
|
||||||
|
|
||||||
#define RO_DATA(align) \
|
#define RO_DATA(align) \
|
||||||
. = ALIGN((align)); \
|
. = ALIGN((align)); \
|
||||||
|
@ -63,8 +63,16 @@ struct ftrace_branch_data {
|
|||||||
const char *func;
|
const char *func;
|
||||||
const char *file;
|
const char *file;
|
||||||
unsigned line;
|
unsigned line;
|
||||||
unsigned long correct;
|
union {
|
||||||
unsigned long incorrect;
|
struct {
|
||||||
|
unsigned long correct;
|
||||||
|
unsigned long incorrect;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
unsigned long miss;
|
||||||
|
unsigned long hit;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -103,6 +111,32 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
|
|||||||
# ifndef unlikely
|
# ifndef unlikely
|
||||||
# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
|
# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||||
|
/*
|
||||||
|
* "Define 'is'", Bill Clinton
|
||||||
|
* "Define 'if'", Steven Rostedt
|
||||||
|
*/
|
||||||
|
#define if(cond) if (__builtin_constant_p((cond)) ? !!(cond) : \
|
||||||
|
({ \
|
||||||
|
int ______r; \
|
||||||
|
static struct ftrace_branch_data \
|
||||||
|
__attribute__((__aligned__(4))) \
|
||||||
|
__attribute__((section("_ftrace_branch"))) \
|
||||||
|
______f = { \
|
||||||
|
.func = __func__, \
|
||||||
|
.file = __FILE__, \
|
||||||
|
.line = __LINE__, \
|
||||||
|
}; \
|
||||||
|
______r = !!(cond); \
|
||||||
|
if (______r) \
|
||||||
|
______f.hit++; \
|
||||||
|
else \
|
||||||
|
______f.miss++; \
|
||||||
|
______r; \
|
||||||
|
}))
|
||||||
|
#endif /* CONFIG_PROFILE_ALL_BRANCHES */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define likely(x) __builtin_expect(!!(x), 1)
|
# define likely(x) __builtin_expect(!!(x), 1)
|
||||||
# define unlikely(x) __builtin_expect(!!(x), 0)
|
# define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
@ -173,6 +173,22 @@ config TRACE_BRANCH_PROFILING
|
|||||||
|
|
||||||
Say N if unsure.
|
Say N if unsure.
|
||||||
|
|
||||||
|
config PROFILE_ALL_BRANCHES
|
||||||
|
bool "Profile all if conditionals"
|
||||||
|
depends on TRACE_BRANCH_PROFILING
|
||||||
|
help
|
||||||
|
This tracer profiles all branch conditions. Every if ()
|
||||||
|
taken in the kernel is recorded whether it hit or miss.
|
||||||
|
The results will be displayed in:
|
||||||
|
|
||||||
|
/debugfs/tracing/profile_branch
|
||||||
|
|
||||||
|
This configuration, when enabled, will impose a great overhead
|
||||||
|
on the system. This should only be enabled when the system
|
||||||
|
is to be analyzed
|
||||||
|
|
||||||
|
Say N if unsure.
|
||||||
|
|
||||||
config TRACING_BRANCHES
|
config TRACING_BRANCHES
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
@ -185,6 +185,7 @@ EXPORT_SYMBOL(ftrace_likely_update);
|
|||||||
struct ftrace_pointer {
|
struct ftrace_pointer {
|
||||||
void *start;
|
void *start;
|
||||||
void *stop;
|
void *stop;
|
||||||
|
int hit;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@ -223,13 +224,17 @@ static void t_stop(struct seq_file *m, void *p)
|
|||||||
|
|
||||||
static int t_show(struct seq_file *m, void *v)
|
static int t_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
|
struct ftrace_pointer *fp = m->private;
|
||||||
struct ftrace_branch_data *p = v;
|
struct ftrace_branch_data *p = v;
|
||||||
const char *f;
|
const char *f;
|
||||||
long percent;
|
long percent;
|
||||||
|
|
||||||
if (v == (void *)1) {
|
if (v == (void *)1) {
|
||||||
seq_printf(m, " correct incorrect %% "
|
if (fp->hit)
|
||||||
" Function "
|
seq_printf(m, " miss hit %% ");
|
||||||
|
else
|
||||||
|
seq_printf(m, " correct incorrect %% ");
|
||||||
|
seq_printf(m, " Function "
|
||||||
" File Line\n"
|
" File Line\n"
|
||||||
" ------- --------- - "
|
" ------- --------- - "
|
||||||
" -------- "
|
" -------- "
|
||||||
@ -243,6 +248,9 @@ static int t_show(struct seq_file *m, void *v)
|
|||||||
f--;
|
f--;
|
||||||
f++;
|
f++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The miss is overlayed on correct, and hit on incorrect.
|
||||||
|
*/
|
||||||
if (p->correct) {
|
if (p->correct) {
|
||||||
percent = p->incorrect * 100;
|
percent = p->incorrect * 100;
|
||||||
percent /= p->correct + p->incorrect;
|
percent /= p->correct + p->incorrect;
|
||||||
@ -284,6 +292,18 @@ static const struct file_operations tracing_branch_fops = {
|
|||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||||
|
extern unsigned long __start_branch_profile[];
|
||||||
|
extern unsigned long __stop_branch_profile[];
|
||||||
|
|
||||||
|
static struct ftrace_pointer ftrace_branch_pos = {
|
||||||
|
.start = __start_branch_profile,
|
||||||
|
.stop = __stop_branch_profile,
|
||||||
|
.hit = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_PROFILE_ALL_BRANCHES */
|
||||||
|
|
||||||
extern unsigned long __start_annotated_branch_profile[];
|
extern unsigned long __start_annotated_branch_profile[];
|
||||||
extern unsigned long __stop_annotated_branch_profile[];
|
extern unsigned long __stop_annotated_branch_profile[];
|
||||||
|
|
||||||
@ -306,6 +326,15 @@ static __init int ftrace_branch_init(void)
|
|||||||
pr_warning("Could not create debugfs "
|
pr_warning("Could not create debugfs "
|
||||||
"'profile_annotatet_branch' entry\n");
|
"'profile_annotatet_branch' entry\n");
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||||
|
entry = debugfs_create_file("profile_branch", 0444, d_tracer,
|
||||||
|
&ftrace_branch_pos,
|
||||||
|
&tracing_branch_fops);
|
||||||
|
if (!entry)
|
||||||
|
pr_warning("Could not create debugfs"
|
||||||
|
" 'profile_branch' entry\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user