aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_branch.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-12-27 17:25:38 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-29 06:55:46 -0500
commite302cf3f961ceb54c1dd0aff7ba8531df83be07a (patch)
tree090e3ebba0745f59709f06d15c5ae7a235fd1840 /kernel/trace/trace_branch.c
parentdbd0b4b33074aa6b7832a9d9a5bd985eca5c1aa2 (diff)
tracing/branch-tracer: adapt to the stat tracing API
Impact: refactor the branch tracer This patch adapts the branch tracer to the tracing API. This is a proof of concept because the branch tracer implements two "stat tracing" that were split in two files. So I added an option to the branch tracer: stat_all_branch. If it is set, then trace_stat will output all of the branches entries stats. Otherwise, it will print the annotated branches. Its is a kind of quick trick, waiting for a better solution. By default, the annotated branches stat are sorted by incorrect branch prediction percentage. Ie: correct incorrect % Function File Line ------- --------- - -------- ---- ---- 0 1 100 native_smp_prepare_cpus smpboot.c 1228 0 1 100 hpet_rtc_timer_reinit hpet.c 1057 0 18032 100 sched_info_queued sched_stats.h 223 0 684 100 yield_task_fair sched_fair.c 984 0 282 100 pre_schedule_rt sched_rt.c 1263 0 13414 100 sched_info_dequeued sched_stats.h 178 0 21724 100 sched_info_switch sched_stats.h 270 0 1 100 get_signal_to_deliver signal.c 1820 0 8 100 __cancel_work_timer workqueue.c 560 0 212 100 verify_export_symbols module.c 1509 0 17 100 __rmqueue_fallback page_alloc.c 793 0 43 100 clear_page_mlock internal.h 129 0 124 100 try_to_unmap_anon rmap.c 1021 0 53 100 try_to_unmap_anon rmap.c 1013 0 6 100 vma_address rmap.c 232 0 3301 100 try_to_unmap_file rmap.c 1082 0 466 100 try_to_unmap_file rmap.c 1077 0 1 100 mem_cgroup_create memcontrol.c 1090 0 3 100 inotify_find_update_watch inotify.c 726 2 30163 99 perf_counter_task_sched_out perf_counter.c 385 1 2935 99 percpu_free allocpercpu.c 138 1544 297672 99 dentry_lru_del_init dcache.c 153 8 1074 99 input_pass_event input.c 86 1390 76781 98 mapping_unevictable pagemap.h 50 280 6665 95 pick_next_task_rt sched_rt.c 889 750 4826 86 next_pidmap pid.c 194 2 8 80 blocking_notifier_chain_regist notifier.c 220 36 130 78 ioremap_pte_range ioremap.c 22 1093 3247 74 IS_ERR err.h 34 1023 2908 73 sched_slice sched_fair.c 445 22 60 73 disk_put_part genhd.h 206 [...] It enables a developer to quickly address the source of incorrect branch predictions. Note that this sorting would be better with a second sort on the number of incorrect predictions. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_branch.c')
-rw-r--r--kernel/trace/trace_branch.c268
1 files changed, 142 insertions, 126 deletions
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index c15222a01073..4785a3b9bc4a 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -18,10 +18,13 @@
18#include "trace.h" 18#include "trace.h"
19#include "trace_output.h" 19#include "trace_output.h"
20 20
21static struct tracer branch_trace;
22
21#ifdef CONFIG_BRANCH_TRACER 23#ifdef CONFIG_BRANCH_TRACER
22 24
23static int branch_tracing_enabled __read_mostly; 25static int branch_tracing_enabled __read_mostly;
24static DEFINE_MUTEX(branch_tracing_mutex); 26static DEFINE_MUTEX(branch_tracing_mutex);
27
25static struct trace_array *branch_tracer; 28static struct trace_array *branch_tracer;
26 29
27static void 30static void
@@ -178,6 +181,7 @@ trace_branch_print(struct trace_seq *s, struct trace_entry *entry, int flags)
178 return 0; 181 return 0;
179} 182}
180 183
184
181static struct trace_event trace_branch_event = { 185static struct trace_event trace_branch_event = {
182 .type = TRACE_BRANCH, 186 .type = TRACE_BRANCH,
183 .trace = trace_branch_print, 187 .trace = trace_branch_print,
@@ -187,30 +191,6 @@ static struct trace_event trace_branch_event = {
187 .binary = trace_nop_print, 191 .binary = trace_nop_print,
188}; 192};
189 193
190struct tracer branch_trace __read_mostly =
191{
192 .name = "branch",
193 .init = branch_trace_init,
194 .reset = branch_trace_reset,
195#ifdef CONFIG_FTRACE_SELFTEST
196 .selftest = trace_selftest_startup_branch,
197#endif
198};
199
200__init static int init_branch_trace(void)
201{
202 int ret;
203
204 ret = register_ftrace_event(&trace_branch_event);
205 if (!ret) {
206 printk(KERN_WARNING "Warning: could not register branch events\n");
207 return 1;
208 }
209
210 return register_tracer(&branch_trace);
211}
212
213device_initcall(init_branch_trace);
214#else 194#else
215static inline 195static inline
216void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) 196void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
@@ -236,66 +216,39 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect)
236} 216}
237EXPORT_SYMBOL(ftrace_likely_update); 217EXPORT_SYMBOL(ftrace_likely_update);
238 218
239struct ftrace_pointer { 219extern unsigned long __start_annotated_branch_profile[];
240 void *start; 220extern unsigned long __stop_annotated_branch_profile[];
241 void *stop;
242 int hit;
243};
244 221
245static void * 222static int annotated_branch_stat_headers(struct seq_file *m)
246t_next(struct seq_file *m, void *v, loff_t *pos)
247{ 223{
248 const struct ftrace_pointer *f = m->private; 224 seq_printf(m, " correct incorrect %% ");
249 struct ftrace_branch_data *p = v; 225 seq_printf(m, " Function "
250 226 " File Line\n"
251 (*pos)++; 227 " ------- --------- - "
252 228 " -------- "
253 if (v == (void *)1) 229 " ---- ----\n");
254 return f->start; 230 return 0;
255
256 ++p;
257
258 if ((void *)p >= (void *)f->stop)
259 return NULL;
260
261 return p;
262} 231}
263 232
264static void *t_start(struct seq_file *m, loff_t *pos) 233static inline long get_incorrect_percent(struct ftrace_branch_data *p)
265{ 234{
266 void *t = (void *)1; 235 long percent;
267 loff_t l = 0;
268
269 for (; t && l < *pos; t = t_next(m, t, &l))
270 ;
271 236
272 return t; 237 if (p->correct) {
273} 238 percent = p->incorrect * 100;
239 percent /= p->correct + p->incorrect;
240 } else
241 percent = p->incorrect ? 100 : -1;
274 242
275static void t_stop(struct seq_file *m, void *p) 243 return percent;
276{
277} 244}
278 245
279static int t_show(struct seq_file *m, void *v) 246static int branch_stat_show(struct seq_file *m, void *v)
280{ 247{
281 const struct ftrace_pointer *fp = m->private;
282 struct ftrace_branch_data *p = v; 248 struct ftrace_branch_data *p = v;
283 const char *f; 249 const char *f;
284 long percent; 250 long percent;
285 251
286 if (v == (void *)1) {
287 if (fp->hit)
288 seq_printf(m, " miss hit %% ");
289 else
290 seq_printf(m, " correct incorrect %% ");
291 seq_printf(m, " Function "
292 " File Line\n"
293 " ------- --------- - "
294 " -------- "
295 " ---- ----\n");
296 return 0;
297 }
298
299 /* Only print the file, not the path */ 252 /* Only print the file, not the path */
300 f = p->file + strlen(p->file); 253 f = p->file + strlen(p->file);
301 while (f >= p->file && *f != '/') 254 while (f >= p->file && *f != '/')
@@ -305,11 +258,7 @@ static int t_show(struct seq_file *m, void *v)
305 /* 258 /*
306 * The miss is overlayed on correct, and hit on incorrect. 259 * The miss is overlayed on correct, and hit on incorrect.
307 */ 260 */
308 if (p->correct) { 261 percent = get_incorrect_percent(p);
309 percent = p->incorrect * 100;
310 percent /= p->correct + p->incorrect;
311 } else
312 percent = p->incorrect ? 100 : -1;
313 262
314 seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); 263 seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect);
315 if (percent < 0) 264 if (percent < 0)
@@ -320,76 +269,143 @@ static int t_show(struct seq_file *m, void *v)
320 return 0; 269 return 0;
321} 270}
322 271
323static struct seq_operations tracing_likely_seq_ops = { 272static void *annotated_branch_stat_start(void)
324 .start = t_start, 273{
325 .next = t_next, 274 return __start_annotated_branch_profile;
326 .stop = t_stop, 275}
327 .show = t_show,
328};
329 276
330static int tracing_branch_open(struct inode *inode, struct file *file) 277static void *
278annotated_branch_stat_next(void *v, int idx)
331{ 279{
332 int ret; 280 struct ftrace_branch_data *p = v;
333 281
334 ret = seq_open(file, &tracing_likely_seq_ops); 282 ++p;
335 if (!ret) {
336 struct seq_file *m = file->private_data;
337 m->private = (void *)inode->i_private;
338 }
339 283
340 return ret; 284 if ((void *)p >= (void *)__stop_annotated_branch_profile)
285 return NULL;
286
287 return p;
341} 288}
342 289
343static const struct file_operations tracing_branch_fops = { 290static int annotated_branch_stat_cmp(void *p1, void *p2)
344 .open = tracing_branch_open, 291{
345 .read = seq_read, 292 struct ftrace_branch_data *a = p1;
346 .llseek = seq_lseek, 293 struct ftrace_branch_data *b = p2;
347}; 294
295 long percent_a, percent_b;
296
297 percent_a = get_incorrect_percent(a);
298 percent_b = get_incorrect_percent(b);
299
300 if (percent_a < percent_b)
301 return -1;
302 if (percent_a > percent_b)
303 return 1;
304 else
305 return 0;
306}
348 307
349#ifdef CONFIG_PROFILE_ALL_BRANCHES 308#ifdef CONFIG_PROFILE_ALL_BRANCHES
350extern unsigned long __start_branch_profile[]; 309enum {
351extern unsigned long __stop_branch_profile[]; 310 TRACE_BRANCH_OPT_ALL = 0x1
311};
352 312
353static const struct ftrace_pointer ftrace_branch_pos = { 313static struct tracer_opt branch_opts[] = {
354 .start = __start_branch_profile, 314 { TRACER_OPT(stat_all_branch, TRACE_BRANCH_OPT_ALL) },
355 .stop = __stop_branch_profile, 315 { }
356 .hit = 1,
357}; 316};
358 317
359#endif /* CONFIG_PROFILE_ALL_BRANCHES */ 318static struct tracer_flags branch_flags = {
319 .val = 0,
320 .opts = branch_opts
321};
360 322
361extern unsigned long __start_annotated_branch_profile[]; 323extern unsigned long __start_branch_profile[];
362extern unsigned long __stop_annotated_branch_profile[]; 324extern unsigned long __stop_branch_profile[];
363 325
364static const struct ftrace_pointer ftrace_annotated_branch_pos = { 326static int all_branch_stat_headers(struct seq_file *m)
365 .start = __start_annotated_branch_profile, 327{
366 .stop = __stop_annotated_branch_profile, 328 seq_printf(m, " miss hit %% ");
367}; 329 seq_printf(m, " Function "
330 " File Line\n"
331 " ------- --------- - "
332 " -------- "
333 " ---- ----\n");
334 return 0;
335}
368 336
369static __init int ftrace_branch_init(void) 337static void *all_branch_stat_start(void)
370{ 338{
371 struct dentry *d_tracer; 339 return __start_branch_profile;
372 struct dentry *entry; 340}
341
342static void *
343all_branch_stat_next(void *v, int idx)
344{
345 struct ftrace_branch_data *p = v;
373 346
374 d_tracer = tracing_init_dentry(); 347 ++p;
375 348
376 entry = debugfs_create_file("profile_annotated_branch", 0444, d_tracer, 349 if ((void *)p >= (void *)__stop_branch_profile)
377 (void *)&ftrace_annotated_branch_pos, 350 return NULL;
378 &tracing_branch_fops);
379 if (!entry)
380 pr_warning("Could not create debugfs "
381 "'profile_annotatet_branch' entry\n");
382 351
383#ifdef CONFIG_PROFILE_ALL_BRANCHES 352 return p;
384 entry = debugfs_create_file("profile_branch", 0444, d_tracer, 353}
385 (void *)&ftrace_branch_pos,
386 &tracing_branch_fops);
387 if (!entry)
388 pr_warning("Could not create debugfs"
389 " 'profile_branch' entry\n");
390#endif
391 354
355static int branch_set_flag(u32 old_flags, u32 bit, int set)
356{
357 if (bit == TRACE_BRANCH_OPT_ALL) {
358 if (set) {
359 branch_trace.stat_headers = all_branch_stat_headers;
360 branch_trace.stat_start = all_branch_stat_start;
361 branch_trace.stat_next = all_branch_stat_next;
362 branch_trace.stat_cmp = NULL;
363 } else {
364 branch_trace.stat_headers =
365 annotated_branch_stat_headers;
366 branch_trace.stat_start = annotated_branch_stat_start;
367 branch_trace.stat_next = annotated_branch_stat_next;
368 branch_trace.stat_cmp = annotated_branch_stat_cmp;
369 }
370 init_tracer_stat(&branch_trace);
371 }
392 return 0; 372 return 0;
393} 373}
394 374
395device_initcall(ftrace_branch_init); 375#endif /* CONFIG_PROFILE_ALL_BRANCHES */
376
377static struct tracer branch_trace __read_mostly =
378{
379 .name = "branch",
380#ifdef CONFIG_BRANCH_TRACER
381 .init = branch_trace_init,
382 .reset = branch_trace_reset,
383#ifdef CONFIG_FTRACE_SELFTEST
384 .selftest = trace_selftest_startup_branch,
385#endif /* CONFIG_FTRACE_SELFTEST */
386#endif /* CONFIG_BRANCH_TRACER */
387 .stat_start = annotated_branch_stat_start,
388 .stat_next = annotated_branch_stat_next,
389 .stat_show = branch_stat_show,
390 .stat_headers = annotated_branch_stat_headers,
391 .stat_cmp = annotated_branch_stat_cmp,
392#ifdef CONFIG_PROFILE_ALL_BRANCHES
393 .flags = &branch_flags,
394 .set_flag = branch_set_flag,
395#endif
396};
397
398__init static int init_branch_trace(void)
399{
400#ifdef CONFIG_BRANCH_TRACER
401 int ret;
402 ret = register_ftrace_event(&trace_branch_event);
403 if (!ret) {
404 printk(KERN_WARNING "Warning: could not register branch events\n");
405 return 1;
406 }
407#endif
408
409 return register_tracer(&branch_trace);
410}
411device_initcall(init_branch_trace);