aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/vmlinux.lds.h11
-rw-r--r--include/linux/compiler.h38
-rw-r--r--kernel/trace/Kconfig16
-rw-r--r--kernel/trace/trace_branch.c33
4 files changed, 93 insertions, 5 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8bccb49981e5..eba835a2c2cd 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -53,6 +53,14 @@
53#define LIKELY_PROFILE() 53#define LIKELY_PROFILE()
54#endif 54#endif
55 55
56#ifdef CONFIG_PROFILE_ALL_BRANCHES
57#define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \
58 *(_ftrace_branch) \
59 VMLINUX_SYMBOL(__stop_branch_profile) = .;
60#else
61#define BRANCH_PROFILE()
62#endif
63
56/* .data section */ 64/* .data section */
57#define DATA_DATA \ 65#define DATA_DATA \
58 *(.data) \ 66 *(.data) \
@@ -72,7 +80,8 @@
72 VMLINUX_SYMBOL(__start___tracepoints) = .; \ 80 VMLINUX_SYMBOL(__start___tracepoints) = .; \
73 *(__tracepoints) \ 81 *(__tracepoints) \
74 VMLINUX_SYMBOL(__stop___tracepoints) = .; \ 82 VMLINUX_SYMBOL(__stop___tracepoints) = .; \
75 LIKELY_PROFILE() 83 LIKELY_PROFILE() \
84 BRANCH_PROFILE()
76 85
77#define RO_DATA(align) \ 86#define RO_DATA(align) \
78 . = ALIGN((align)); \ 87 . = ALIGN((align)); \
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 0628a2013fae..ea7c6be354b7 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -63,8 +63,16 @@ struct ftrace_branch_data {
63 const char *func; 63 const char *func;
64 const char *file; 64 const char *file;
65 unsigned line; 65 unsigned line;
66 unsigned long correct; 66 union {
67 unsigned long incorrect; 67 struct {
68 unsigned long correct;
69 unsigned long incorrect;
70 };
71 struct {
72 unsigned long miss;
73 unsigned long hit;
74 };
75 };
68}; 76};
69 77
70/* 78/*
@@ -103,6 +111,32 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
103# ifndef unlikely 111# ifndef unlikely
104# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0)) 112# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
105# endif 113# endif
114
115#ifdef CONFIG_PROFILE_ALL_BRANCHES
116/*
117 * "Define 'is'", Bill Clinton
118 * "Define 'if'", Steven Rostedt
119 */
120#define if(cond) if (__builtin_constant_p((cond)) ? !!(cond) : \
121 ({ \
122 int ______r; \
123 static struct ftrace_branch_data \
124 __attribute__((__aligned__(4))) \
125 __attribute__((section("_ftrace_branch"))) \
126 ______f = { \
127 .func = __func__, \
128 .file = __FILE__, \
129 .line = __LINE__, \
130 }; \
131 ______r = !!(cond); \
132 if (______r) \
133 ______f.hit++; \
134 else \
135 ______f.miss++; \
136 ______r; \
137 }))
138#endif /* CONFIG_PROFILE_ALL_BRANCHES */
139
106#else 140#else
107# define likely(x) __builtin_expect(!!(x), 1) 141# define likely(x) __builtin_expect(!!(x), 1)
108# define unlikely(x) __builtin_expect(!!(x), 0) 142# define unlikely(x) __builtin_expect(!!(x), 0)
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 7e3548705708..61e8cca6ff45 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -173,6 +173,22 @@ config TRACE_BRANCH_PROFILING
173 173
174 Say N if unsure. 174 Say N if unsure.
175 175
176config PROFILE_ALL_BRANCHES
177 bool "Profile all if conditionals"
178 depends on TRACE_BRANCH_PROFILING
179 help
180 This tracer profiles all branch conditions. Every if ()
181 taken in the kernel is recorded whether it hit or miss.
182 The results will be displayed in:
183
184 /debugfs/tracing/profile_branch
185
186 This configuration, when enabled, will impose a great overhead
187 on the system. This should only be enabled when the system
188 is to be analyzed
189
190 Say N if unsure.
191
176config TRACING_BRANCHES 192config TRACING_BRANCHES
177 bool 193 bool
178 help 194 help
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 142acb3b4e00..85792aec64d2 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -185,6 +185,7 @@ EXPORT_SYMBOL(ftrace_likely_update);
185struct ftrace_pointer { 185struct ftrace_pointer {
186 void *start; 186 void *start;
187 void *stop; 187 void *stop;
188 int hit;
188}; 189};
189 190
190static void * 191static void *
@@ -223,13 +224,17 @@ static void t_stop(struct seq_file *m, void *p)
223 224
224static int t_show(struct seq_file *m, void *v) 225static int t_show(struct seq_file *m, void *v)
225{ 226{
227 struct ftrace_pointer *fp = m->private;
226 struct ftrace_branch_data *p = v; 228 struct ftrace_branch_data *p = v;
227 const char *f; 229 const char *f;
228 long percent; 230 long percent;
229 231
230 if (v == (void *)1) { 232 if (v == (void *)1) {
231 seq_printf(m, " correct incorrect %% " 233 if (fp->hit)
232 " Function " 234 seq_printf(m, " miss hit %% ");
235 else
236 seq_printf(m, " correct incorrect %% ");
237 seq_printf(m, " Function "
233 " File Line\n" 238 " File Line\n"
234 " ------- --------- - " 239 " ------- --------- - "
235 " -------- " 240 " -------- "
@@ -243,6 +248,9 @@ static int t_show(struct seq_file *m, void *v)
243 f--; 248 f--;
244 f++; 249 f++;
245 250
251 /*
252 * The miss is overlayed on correct, and hit on incorrect.
253 */
246 if (p->correct) { 254 if (p->correct) {
247 percent = p->incorrect * 100; 255 percent = p->incorrect * 100;
248 percent /= p->correct + p->incorrect; 256 percent /= p->correct + p->incorrect;
@@ -284,6 +292,18 @@ static const struct file_operations tracing_branch_fops = {
284 .llseek = seq_lseek, 292 .llseek = seq_lseek,
285}; 293};
286 294
295#ifdef CONFIG_PROFILE_ALL_BRANCHES
296extern unsigned long __start_branch_profile[];
297extern unsigned long __stop_branch_profile[];
298
299static struct ftrace_pointer ftrace_branch_pos = {
300 .start = __start_branch_profile,
301 .stop = __stop_branch_profile,
302 .hit = 1,
303};
304
305#endif /* CONFIG_PROFILE_ALL_BRANCHES */
306
287extern unsigned long __start_annotated_branch_profile[]; 307extern unsigned long __start_annotated_branch_profile[];
288extern unsigned long __stop_annotated_branch_profile[]; 308extern unsigned long __stop_annotated_branch_profile[];
289 309
@@ -306,6 +326,15 @@ static __init int ftrace_branch_init(void)
306 pr_warning("Could not create debugfs " 326 pr_warning("Could not create debugfs "
307 "'profile_annotatet_branch' entry\n"); 327 "'profile_annotatet_branch' entry\n");
308 328
329#ifdef CONFIG_PROFILE_ALL_BRANCHES
330 entry = debugfs_create_file("profile_branch", 0444, d_tracer,
331 &ftrace_branch_pos,
332 &tracing_branch_fops);
333 if (!entry)
334 pr_warning("Could not create debugfs"
335 " 'profile_branch' entry\n");
336#endif
337
309 return 0; 338 return 0;
310} 339}
311 340