Commit | Line | Data |
---|---|---|
1f0d69a9 SR |
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); |