diff options
Diffstat (limited to 'kernel/trace/trace_unlikely.c')
-rw-r--r-- | kernel/trace/trace_unlikely.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/kernel/trace/trace_unlikely.c b/kernel/trace/trace_unlikely.c new file mode 100644 index 000000000000..94932696069f --- /dev/null +++ b/kernel/trace/trace_unlikely.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * unlikely profiler | ||
3 | * | ||
4 | * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com> | ||
5 | */ | ||
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> | ||
14 | #include <linux/fs.h> | ||
15 | #include <asm/local.h> | ||
16 | #include "trace.h" | ||
17 | |||
18 | void ftrace_likely_update(struct ftrace_likely_data *f, int val, int expect) | ||
19 | { | ||
20 | /* FIXME: Make this atomic! */ | ||
21 | if (val == expect) | ||
22 | f->correct++; | ||
23 | else | ||
24 | f->incorrect++; | ||
25 | } | ||
26 | EXPORT_SYMBOL(ftrace_likely_update); | ||
27 | |||
28 | struct ftrace_pointer { | ||
29 | void *start; | ||
30 | void *stop; | ||
31 | }; | ||
32 | |||
33 | static void * | ||
34 | t_next(struct seq_file *m, void *v, loff_t *pos) | ||
35 | { | ||
36 | struct ftrace_pointer *f = m->private; | ||
37 | struct ftrace_likely_data *p = v; | ||
38 | |||
39 | (*pos)++; | ||
40 | |||
41 | if (v == (void *)1) | ||
42 | return f->start; | ||
43 | |||
44 | ++p; | ||
45 | |||
46 | if ((void *)p >= (void *)f->stop) | ||
47 | return NULL; | ||
48 | |||
49 | return p; | ||
50 | } | ||
51 | |||
52 | static void *t_start(struct seq_file *m, loff_t *pos) | ||
53 | { | ||
54 | void *t = (void *)1; | ||
55 | loff_t l = 0; | ||
56 | |||
57 | for (; t && l < *pos; t = t_next(m, t, &l)) | ||
58 | ; | ||
59 | |||
60 | return t; | ||
61 | } | ||
62 | |||
63 | static void t_stop(struct seq_file *m, void *p) | ||
64 | { | ||
65 | } | ||
66 | |||
67 | static int t_show(struct seq_file *m, void *v) | ||
68 | { | ||
69 | struct ftrace_likely_data *p = v; | ||
70 | const char *f; | ||
71 | unsigned long percent; | ||
72 | |||
73 | if (v == (void *)1) { | ||
74 | seq_printf(m, " correct incorrect %% " | ||
75 | " Function " | ||
76 | " File Line\n" | ||
77 | " ------- --------- - " | ||
78 | " -------- " | ||
79 | " ---- ----\n"); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | /* Only print the file, not the path */ | ||
84 | f = p->file + strlen(p->file); | ||
85 | while (f >= p->file && *f != '/') | ||
86 | f--; | ||
87 | f++; | ||
88 | |||
89 | if (p->correct) { | ||
90 | percent = p->incorrect * 100; | ||
91 | percent /= p->correct + p->incorrect; | ||
92 | } else | ||
93 | percent = p->incorrect ? 100 : 0; | ||
94 | |||
95 | seq_printf(m, "%8lu %8lu %3lu ", p->correct, p->incorrect, percent); | ||
96 | seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static struct seq_operations tracing_likely_seq_ops = { | ||
101 | .start = t_start, | ||
102 | .next = t_next, | ||
103 | .stop = t_stop, | ||
104 | .show = t_show, | ||
105 | }; | ||
106 | |||
107 | static int tracing_likely_open(struct inode *inode, struct file *file) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | ret = seq_open(file, &tracing_likely_seq_ops); | ||
112 | if (!ret) { | ||
113 | struct seq_file *m = file->private_data; | ||
114 | m->private = (void *)inode->i_private; | ||
115 | } | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static struct file_operations tracing_likely_fops = { | ||
121 | .open = tracing_likely_open, | ||
122 | .read = seq_read, | ||
123 | .llseek = seq_lseek, | ||
124 | }; | ||
125 | |||
126 | extern unsigned long __start_likely_profile[]; | ||
127 | extern unsigned long __stop_likely_profile[]; | ||
128 | extern unsigned long __start_unlikely_profile[]; | ||
129 | extern unsigned long __stop_unlikely_profile[]; | ||
130 | |||
131 | static struct ftrace_pointer ftrace_likely_pos = { | ||
132 | .start = __start_likely_profile, | ||
133 | .stop = __stop_likely_profile, | ||
134 | }; | ||
135 | |||
136 | static struct ftrace_pointer ftrace_unlikely_pos = { | ||
137 | .start = __start_unlikely_profile, | ||
138 | .stop = __stop_unlikely_profile, | ||
139 | }; | ||
140 | |||
141 | static __init int ftrace_unlikely_init(void) | ||
142 | { | ||
143 | struct dentry *d_tracer; | ||
144 | struct dentry *entry; | ||
145 | |||
146 | d_tracer = tracing_init_dentry(); | ||
147 | |||
148 | entry = debugfs_create_file("profile_likely", 0444, d_tracer, | ||
149 | &ftrace_likely_pos, | ||
150 | &tracing_likely_fops); | ||
151 | if (!entry) | ||
152 | pr_warning("Could not create debugfs 'profile_likely' entry\n"); | ||
153 | |||
154 | entry = debugfs_create_file("profile_unlikely", 0444, d_tracer, | ||
155 | &ftrace_unlikely_pos, | ||
156 | &tracing_likely_fops); | ||
157 | if (!entry) | ||
158 | pr_warning("Could not create debugfs" | ||
159 | " 'profile_unlikely' entry\n"); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | device_initcall(ftrace_unlikely_init); | ||