aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_branch.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_branch.c')
-rw-r--r--kernel/trace/trace_branch.c286
1 files changed, 166 insertions, 120 deletions
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 6c00feb3bac7..8333715e4066 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -14,12 +14,17 @@
14#include <linux/hash.h> 14#include <linux/hash.h>
15#include <linux/fs.h> 15#include <linux/fs.h>
16#include <asm/local.h> 16#include <asm/local.h>
17
17#include "trace.h" 18#include "trace.h"
19#include "trace_stat.h"
20#include "trace_output.h"
18 21
19#ifdef CONFIG_BRANCH_TRACER 22#ifdef CONFIG_BRANCH_TRACER
20 23
24static struct tracer branch_trace;
21static int branch_tracing_enabled __read_mostly; 25static int branch_tracing_enabled __read_mostly;
22static DEFINE_MUTEX(branch_tracing_mutex); 26static DEFINE_MUTEX(branch_tracing_mutex);
27
23static struct trace_array *branch_tracer; 28static struct trace_array *branch_tracer;
24 29
25static void 30static void
@@ -28,7 +33,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
28 struct trace_array *tr = branch_tracer; 33 struct trace_array *tr = branch_tracer;
29 struct ring_buffer_event *event; 34 struct ring_buffer_event *event;
30 struct trace_branch *entry; 35 struct trace_branch *entry;
31 unsigned long flags, irq_flags; 36 unsigned long flags;
32 int cpu, pc; 37 int cpu, pc;
33 const char *p; 38 const char *p;
34 39
@@ -47,15 +52,13 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
47 if (atomic_inc_return(&tr->data[cpu]->disabled) != 1) 52 if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
48 goto out; 53 goto out;
49 54
50 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), 55 pc = preempt_count();
51 &irq_flags); 56 event = trace_buffer_lock_reserve(tr, TRACE_BRANCH,
57 sizeof(*entry), flags, pc);
52 if (!event) 58 if (!event)
53 goto out; 59 goto out;
54 60
55 pc = preempt_count();
56 entry = ring_buffer_event_data(event); 61 entry = ring_buffer_event_data(event);
57 tracing_generic_entry_update(&entry->ent, flags, pc);
58 entry->ent.type = TRACE_BRANCH;
59 62
60 /* Strip off the path, only save the file */ 63 /* Strip off the path, only save the file */
61 p = f->file + strlen(f->file); 64 p = f->file + strlen(f->file);
@@ -70,7 +73,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
70 entry->line = f->line; 73 entry->line = f->line;
71 entry->correct = val == expect; 74 entry->correct = val == expect;
72 75
73 ring_buffer_unlock_commit(tr->buffer, event, irq_flags); 76 ring_buffer_unlock_commit(tr->buffer, event);
74 77
75 out: 78 out:
76 atomic_dec(&tr->data[cpu]->disabled); 79 atomic_dec(&tr->data[cpu]->disabled);
@@ -88,8 +91,6 @@ void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
88 91
89int enable_branch_tracing(struct trace_array *tr) 92int enable_branch_tracing(struct trace_array *tr)
90{ 93{
91 int ret = 0;
92
93 mutex_lock(&branch_tracing_mutex); 94 mutex_lock(&branch_tracing_mutex);
94 branch_tracer = tr; 95 branch_tracer = tr;
95 /* 96 /*
@@ -100,7 +101,7 @@ int enable_branch_tracing(struct trace_array *tr)
100 branch_tracing_enabled++; 101 branch_tracing_enabled++;
101 mutex_unlock(&branch_tracing_mutex); 102 mutex_unlock(&branch_tracing_mutex);
102 103
103 return ret; 104 return 0;
104} 105}
105 106
106void disable_branch_tracing(void) 107void disable_branch_tracing(void)
@@ -128,11 +129,6 @@ static void stop_branch_trace(struct trace_array *tr)
128 129
129static int branch_trace_init(struct trace_array *tr) 130static int branch_trace_init(struct trace_array *tr)
130{ 131{
131 int cpu;
132
133 for_each_online_cpu(cpu)
134 tracing_reset(tr, cpu);
135
136 start_branch_trace(tr); 132 start_branch_trace(tr);
137 return 0; 133 return 0;
138} 134}
@@ -142,22 +138,61 @@ static void branch_trace_reset(struct trace_array *tr)
142 stop_branch_trace(tr); 138 stop_branch_trace(tr);
143} 139}
144 140
145struct tracer branch_trace __read_mostly = 141static enum print_line_t trace_branch_print(struct trace_iterator *iter,
142 int flags)
143{
144 struct trace_branch *field;
145
146 trace_assign_type(field, iter->ent);
147
148 if (trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
149 field->correct ? " ok " : " MISS ",
150 field->func,
151 field->file,
152 field->line))
153 return TRACE_TYPE_PARTIAL_LINE;
154
155 return TRACE_TYPE_HANDLED;
156}
157
158static void branch_print_header(struct seq_file *s)
159{
160 seq_puts(s, "# TASK-PID CPU# TIMESTAMP CORRECT"
161 " FUNC:FILE:LINE\n");
162 seq_puts(s, "# | | | | | "
163 " |\n");
164}
165
166static struct trace_event trace_branch_event = {
167 .type = TRACE_BRANCH,
168 .trace = trace_branch_print,
169};
170
171static struct tracer branch_trace __read_mostly =
146{ 172{
147 .name = "branch", 173 .name = "branch",
148 .init = branch_trace_init, 174 .init = branch_trace_init,
149 .reset = branch_trace_reset, 175 .reset = branch_trace_reset,
150#ifdef CONFIG_FTRACE_SELFTEST 176#ifdef CONFIG_FTRACE_SELFTEST
151 .selftest = trace_selftest_startup_branch, 177 .selftest = trace_selftest_startup_branch,
152#endif 178#endif /* CONFIG_FTRACE_SELFTEST */
179 .print_header = branch_print_header,
153}; 180};
154 181
155__init static int init_branch_trace(void) 182__init static int init_branch_tracer(void)
156{ 183{
184 int ret;
185
186 ret = register_ftrace_event(&trace_branch_event);
187 if (!ret) {
188 printk(KERN_WARNING "Warning: could not register "
189 "branch events\n");
190 return 1;
191 }
157 return register_tracer(&branch_trace); 192 return register_tracer(&branch_trace);
158} 193}
194device_initcall(init_branch_tracer);
159 195
160device_initcall(init_branch_trace);
161#else 196#else
162static inline 197static inline
163void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) 198void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect)
@@ -183,66 +218,39 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect)
183} 218}
184EXPORT_SYMBOL(ftrace_likely_update); 219EXPORT_SYMBOL(ftrace_likely_update);
185 220
186struct ftrace_pointer { 221extern unsigned long __start_annotated_branch_profile[];
187 void *start; 222extern unsigned long __stop_annotated_branch_profile[];
188 void *stop;
189 int hit;
190};
191 223
192static void * 224static int annotated_branch_stat_headers(struct seq_file *m)
193t_next(struct seq_file *m, void *v, loff_t *pos)
194{ 225{
195 const struct ftrace_pointer *f = m->private; 226 seq_printf(m, " correct incorrect %% ");
196 struct ftrace_branch_data *p = v; 227 seq_printf(m, " Function "
197 228 " File Line\n"
198 (*pos)++; 229 " ------- --------- - "
199 230 " -------- "
200 if (v == (void *)1) 231 " ---- ----\n");
201 return f->start; 232 return 0;
202
203 ++p;
204
205 if ((void *)p >= (void *)f->stop)
206 return NULL;
207
208 return p;
209} 233}
210 234
211static void *t_start(struct seq_file *m, loff_t *pos) 235static inline long get_incorrect_percent(struct ftrace_branch_data *p)
212{ 236{
213 void *t = (void *)1; 237 long percent;
214 loff_t l = 0;
215
216 for (; t && l < *pos; t = t_next(m, t, &l))
217 ;
218 238
219 return t; 239 if (p->correct) {
220} 240 percent = p->incorrect * 100;
241 percent /= p->correct + p->incorrect;
242 } else
243 percent = p->incorrect ? 100 : -1;
221 244
222static void t_stop(struct seq_file *m, void *p) 245 return percent;
223{
224} 246}
225 247
226static int t_show(struct seq_file *m, void *v) 248static int branch_stat_show(struct seq_file *m, void *v)
227{ 249{
228 const struct ftrace_pointer *fp = m->private;
229 struct ftrace_branch_data *p = v; 250 struct ftrace_branch_data *p = v;
230 const char *f; 251 const char *f;
231 long percent; 252 long percent;
232 253
233 if (v == (void *)1) {
234 if (fp->hit)
235 seq_printf(m, " miss hit %% ");
236 else
237 seq_printf(m, " correct incorrect %% ");
238 seq_printf(m, " Function "
239 " File Line\n"
240 " ------- --------- - "
241 " -------- "
242 " ---- ----\n");
243 return 0;
244 }
245
246 /* Only print the file, not the path */ 254 /* Only print the file, not the path */
247 f = p->file + strlen(p->file); 255 f = p->file + strlen(p->file);
248 while (f >= p->file && *f != '/') 256 while (f >= p->file && *f != '/')
@@ -252,11 +260,7 @@ static int t_show(struct seq_file *m, void *v)
252 /* 260 /*
253 * The miss is overlayed on correct, and hit on incorrect. 261 * The miss is overlayed on correct, and hit on incorrect.
254 */ 262 */
255 if (p->correct) { 263 percent = get_incorrect_percent(p);
256 percent = p->incorrect * 100;
257 percent /= p->correct + p->incorrect;
258 } else
259 percent = p->incorrect ? 100 : -1;
260 264
261 seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect); 265 seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect);
262 if (percent < 0) 266 if (percent < 0)
@@ -267,76 +271,118 @@ static int t_show(struct seq_file *m, void *v)
267 return 0; 271 return 0;
268} 272}
269 273
270static struct seq_operations tracing_likely_seq_ops = { 274static void *annotated_branch_stat_start(void)
271 .start = t_start, 275{
272 .next = t_next, 276 return __start_annotated_branch_profile;
273 .stop = t_stop, 277}
274 .show = t_show, 278
279static void *
280annotated_branch_stat_next(void *v, int idx)
281{
282 struct ftrace_branch_data *p = v;
283
284 ++p;
285
286 if ((void *)p >= (void *)__stop_annotated_branch_profile)
287 return NULL;
288
289 return p;
290}
291
292static int annotated_branch_stat_cmp(void *p1, void *p2)
293{
294 struct ftrace_branch_data *a = p1;
295 struct ftrace_branch_data *b = p2;
296
297 long percent_a, percent_b;
298
299 percent_a = get_incorrect_percent(a);
300 percent_b = get_incorrect_percent(b);
301
302 if (percent_a < percent_b)
303 return -1;
304 if (percent_a > percent_b)
305 return 1;
306 else
307 return 0;
308}
309
310static struct tracer_stat annotated_branch_stats = {
311 .name = "branch_annotated",
312 .stat_start = annotated_branch_stat_start,
313 .stat_next = annotated_branch_stat_next,
314 .stat_cmp = annotated_branch_stat_cmp,
315 .stat_headers = annotated_branch_stat_headers,
316 .stat_show = branch_stat_show
275}; 317};
276 318
277static int tracing_branch_open(struct inode *inode, struct file *file) 319__init static int init_annotated_branch_stats(void)
278{ 320{
279 int ret; 321 int ret;
280 322
281 ret = seq_open(file, &tracing_likely_seq_ops); 323 ret = register_stat_tracer(&annotated_branch_stats);
282 if (!ret) { 324 if (!ret) {
283 struct seq_file *m = file->private_data; 325 printk(KERN_WARNING "Warning: could not register "
284 m->private = (void *)inode->i_private; 326 "annotated branches stats\n");
327 return 1;
285 } 328 }
286 329 return 0;
287 return ret;
288} 330}
289 331fs_initcall(init_annotated_branch_stats);
290static const struct file_operations tracing_branch_fops = {
291 .open = tracing_branch_open,
292 .read = seq_read,
293 .llseek = seq_lseek,
294};
295 332
296#ifdef CONFIG_PROFILE_ALL_BRANCHES 333#ifdef CONFIG_PROFILE_ALL_BRANCHES
334
297extern unsigned long __start_branch_profile[]; 335extern unsigned long __start_branch_profile[];
298extern unsigned long __stop_branch_profile[]; 336extern unsigned long __stop_branch_profile[];
299 337
300static const struct ftrace_pointer ftrace_branch_pos = { 338static int all_branch_stat_headers(struct seq_file *m)
301 .start = __start_branch_profile, 339{
302 .stop = __stop_branch_profile, 340 seq_printf(m, " miss hit %% ");
303 .hit = 1, 341 seq_printf(m, " Function "
304}; 342 " File Line\n"
343 " ------- --------- - "
344 " -------- "
345 " ---- ----\n");
346 return 0;
347}
305 348
306#endif /* CONFIG_PROFILE_ALL_BRANCHES */ 349static void *all_branch_stat_start(void)
350{
351 return __start_branch_profile;
352}
307 353
308extern unsigned long __start_annotated_branch_profile[]; 354static void *
309extern unsigned long __stop_annotated_branch_profile[]; 355all_branch_stat_next(void *v, int idx)
356{
357 struct ftrace_branch_data *p = v;
310 358
311static const struct ftrace_pointer ftrace_annotated_branch_pos = { 359 ++p;
312 .start = __start_annotated_branch_profile,
313 .stop = __stop_annotated_branch_profile,
314};
315 360
316static __init int ftrace_branch_init(void) 361 if ((void *)p >= (void *)__stop_branch_profile)
317{ 362 return NULL;
318 struct dentry *d_tracer;
319 struct dentry *entry;
320 363
321 d_tracer = tracing_init_dentry(); 364 return p;
365}
322 366
323 entry = debugfs_create_file("profile_annotated_branch", 0444, d_tracer, 367static struct tracer_stat all_branch_stats = {
324 (void *)&ftrace_annotated_branch_pos, 368 .name = "branch_all",
325 &tracing_branch_fops); 369 .stat_start = all_branch_stat_start,
326 if (!entry) 370 .stat_next = all_branch_stat_next,
327 pr_warning("Could not create debugfs " 371 .stat_headers = all_branch_stat_headers,
328 "'profile_annotatet_branch' entry\n"); 372 .stat_show = branch_stat_show
373};
329 374
330#ifdef CONFIG_PROFILE_ALL_BRANCHES 375__init static int all_annotated_branch_stats(void)
331 entry = debugfs_create_file("profile_branch", 0444, d_tracer, 376{
332 (void *)&ftrace_branch_pos, 377 int ret;
333 &tracing_branch_fops);
334 if (!entry)
335 pr_warning("Could not create debugfs"
336 " 'profile_branch' entry\n");
337#endif
338 378
379 ret = register_stat_tracer(&all_branch_stats);
380 if (!ret) {
381 printk(KERN_WARNING "Warning: could not register "
382 "all branches stats\n");
383 return 1;
384 }
339 return 0; 385 return 0;
340} 386}
341 387fs_initcall(all_annotated_branch_stats);
342device_initcall(ftrace_branch_init); 388#endif /* CONFIG_PROFILE_ALL_BRANCHES */