4 * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
6 #include <linux/kallsyms.h>
7 #include <linux/seq_file.h>
8 #include <linux/spinlock.h>
9 #include <linux/debugfs.h>
10 #include <linux/uaccess.h>
11 #include <linux/module.h>
12 #include <linux/ftrace.h>
13 #include <linux/hash.h>
15 #include <asm/local.h>
18 #ifdef CONFIG_BRANCH_TRACER
20 static int branch_tracing_enabled __read_mostly
;
21 static DEFINE_MUTEX(branch_tracing_mutex
);
22 static struct trace_array
*branch_tracer
;
25 probe_likely_condition(struct ftrace_branch_data
*f
, int val
, int expect
)
27 struct trace_array
*tr
= branch_tracer
;
28 struct ring_buffer_event
*event
;
29 struct trace_branch
*entry
;
30 unsigned long flags
, irq_flags
;
35 * I would love to save just the ftrace_likely_data pointer, but
36 * this code can also be used by modules. Ugly things can happen
37 * if the module is unloaded, and then we go and read the
38 * pointer. This is slower, but much safer.
44 raw_local_irq_save(flags
);
45 cpu
= raw_smp_processor_id();
46 if (atomic_inc_return(&tr
->data
[cpu
]->disabled
) != 1)
49 event
= ring_buffer_lock_reserve(tr
->buffer
, sizeof(*entry
),
55 entry
= ring_buffer_event_data(event
);
56 tracing_generic_entry_update(&entry
->ent
, flags
, pc
);
57 entry
->ent
.type
= TRACE_BRANCH
;
59 /* Strip off the path, only save the file */
60 p
= f
->file
+ strlen(f
->file
);
61 while (p
>= f
->file
&& *p
!= '/')
65 strncpy(entry
->func
, f
->func
, TRACE_FUNC_SIZE
);
66 strncpy(entry
->file
, p
, TRACE_FILE_SIZE
);
67 entry
->func
[TRACE_FUNC_SIZE
] = 0;
68 entry
->file
[TRACE_FILE_SIZE
] = 0;
69 entry
->line
= f
->line
;
70 entry
->correct
= val
== expect
;
72 ring_buffer_unlock_commit(tr
->buffer
, event
, irq_flags
);
75 atomic_dec(&tr
->data
[cpu
]->disabled
);
76 raw_local_irq_restore(flags
);
80 void trace_likely_condition(struct ftrace_branch_data
*f
, int val
, int expect
)
82 if (!branch_tracing_enabled
)
85 probe_likely_condition(f
, val
, expect
);
88 int enable_branch_tracing(struct trace_array
*tr
)
92 mutex_lock(&branch_tracing_mutex
);
95 * Must be seen before enabling. The reader is a condition
96 * where we do not need a matching rmb()
99 branch_tracing_enabled
++;
100 mutex_unlock(&branch_tracing_mutex
);
105 void disable_branch_tracing(void)
107 mutex_lock(&branch_tracing_mutex
);
109 if (!branch_tracing_enabled
)
112 branch_tracing_enabled
--;
115 mutex_unlock(&branch_tracing_mutex
);
118 static void start_branch_trace(struct trace_array
*tr
)
120 enable_branch_tracing(tr
);
123 static void stop_branch_trace(struct trace_array
*tr
)
125 disable_branch_tracing();
128 static int branch_trace_init(struct trace_array
*tr
)
132 for_each_online_cpu(cpu
)
133 tracing_reset(tr
, cpu
);
135 start_branch_trace(tr
);
139 static void branch_trace_reset(struct trace_array
*tr
)
141 stop_branch_trace(tr
);
144 struct tracer branch_trace __read_mostly
=
147 .init
= branch_trace_init
,
148 .reset
= branch_trace_reset
,
149 #ifdef CONFIG_FTRACE_SELFTEST
150 .selftest
= trace_selftest_startup_branch
,
154 __init
static int init_branch_trace(void)
156 return register_tracer(&branch_trace
);
159 device_initcall(init_branch_trace
);
162 void trace_likely_condition(struct ftrace_branch_data
*f
, int val
, int expect
)
165 #endif /* CONFIG_BRANCH_TRACER */
167 void ftrace_likely_update(struct ftrace_branch_data
*f
, int val
, int expect
)
170 * I would love to have a trace point here instead, but the
171 * trace point code is so inundated with unlikely and likely
172 * conditions that the recursive nightmare that exists is too
173 * much to try to get working. At least for now.
175 trace_likely_condition(f
, val
, expect
);
177 /* FIXME: Make this atomic! */
183 EXPORT_SYMBOL(ftrace_likely_update
);
185 struct ftrace_pointer
{
192 t_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
194 const struct ftrace_pointer
*f
= m
->private;
195 struct ftrace_branch_data
*p
= v
;
204 if ((void *)p
>= (void *)f
->stop
)
210 static void *t_start(struct seq_file
*m
, loff_t
*pos
)
215 for (; t
&& l
< *pos
; t
= t_next(m
, t
, &l
))
221 static void t_stop(struct seq_file
*m
, void *p
)
225 static int t_show(struct seq_file
*m
, void *v
)
227 const struct ftrace_pointer
*fp
= m
->private;
228 struct ftrace_branch_data
*p
= v
;
232 if (v
== (void *)1) {
234 seq_printf(m
, " miss hit %% ");
236 seq_printf(m
, " correct incorrect %% ");
237 seq_printf(m
, " Function "
239 " ------- --------- - "
245 /* Only print the file, not the path */
246 f
= p
->file
+ strlen(p
->file
);
247 while (f
>= p
->file
&& *f
!= '/')
252 * The miss is overlayed on correct, and hit on incorrect.
255 percent
= p
->incorrect
* 100;
256 percent
/= p
->correct
+ p
->incorrect
;
258 percent
= p
->incorrect
? 100 : -1;
260 seq_printf(m
, "%8lu %8lu ", p
->correct
, p
->incorrect
);
262 seq_printf(m
, " X ");
264 seq_printf(m
, "%3ld ", percent
);
265 seq_printf(m
, "%-30.30s %-20.20s %d\n", p
->func
, f
, p
->line
);
269 static struct seq_operations tracing_likely_seq_ops
= {
276 static int tracing_branch_open(struct inode
*inode
, struct file
*file
)
280 ret
= seq_open(file
, &tracing_likely_seq_ops
);
282 struct seq_file
*m
= file
->private_data
;
283 m
->private = (void *)inode
->i_private
;
289 static const struct file_operations tracing_branch_fops
= {
290 .open
= tracing_branch_open
,
295 #ifdef CONFIG_PROFILE_ALL_BRANCHES
296 extern unsigned long __start_branch_profile
[];
297 extern unsigned long __stop_branch_profile
[];
299 static const struct ftrace_pointer ftrace_branch_pos
= {
300 .start
= __start_branch_profile
,
301 .stop
= __stop_branch_profile
,
305 #endif /* CONFIG_PROFILE_ALL_BRANCHES */
307 extern unsigned long __start_annotated_branch_profile
[];
308 extern unsigned long __stop_annotated_branch_profile
[];
310 static const struct ftrace_pointer ftrace_annotated_branch_pos
= {
311 .start
= __start_annotated_branch_profile
,
312 .stop
= __stop_annotated_branch_profile
,
315 static __init
int ftrace_branch_init(void)
317 struct dentry
*d_tracer
;
318 struct dentry
*entry
;
320 d_tracer
= tracing_init_dentry();
322 entry
= debugfs_create_file("profile_annotated_branch", 0444, d_tracer
,
323 (void *)&ftrace_annotated_branch_pos
,
324 &tracing_branch_fops
);
326 pr_warning("Could not create debugfs "
327 "'profile_annotatet_branch' entry\n");
329 #ifdef CONFIG_PROFILE_ALL_BRANCHES
330 entry
= debugfs_create_file("profile_branch", 0444, d_tracer
,
331 (void *)&ftrace_branch_pos
,
332 &tracing_branch_fops
);
334 pr_warning("Could not create debugfs"
335 " 'profile_branch' entry\n");
341 device_initcall(ftrace_branch_init
);