diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-06-06 14:33:43 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-06 14:33:43 -0400 |
commit | 864709302a80f26fa9da3be5b47304f0b8bae192 (patch) | |
tree | 8c2bab78f141fe43a38914bd3e3aae0a88f958e5 /tools/perf/util/parse-events.c | |
parent | 75b5032212641f6d38ac041416945e70da833b68 (diff) |
perf_counter tools: Move from Documentation/perf_counter/ to tools/perf/
Several people have suggested that 'perf' has become a full-fledged
tool that should be moved out of Documentation/. Move it to the
(new) tools/ directory.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/parse-events.c')
-rw-r--r-- | tools/perf/util/parse-events.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c new file mode 100644 index 000000000000..e0820b4388ae --- /dev/null +++ b/tools/perf/util/parse-events.c | |||
@@ -0,0 +1,316 @@ | |||
1 | |||
2 | #include "../perf.h" | ||
3 | #include "util.h" | ||
4 | #include "parse-options.h" | ||
5 | #include "parse-events.h" | ||
6 | #include "exec_cmd.h" | ||
7 | #include "string.h" | ||
8 | |||
9 | extern char *strcasestr(const char *haystack, const char *needle); | ||
10 | |||
11 | int nr_counters; | ||
12 | |||
13 | struct perf_counter_attr attrs[MAX_COUNTERS]; | ||
14 | |||
15 | struct event_symbol { | ||
16 | __u8 type; | ||
17 | __u64 config; | ||
18 | char *symbol; | ||
19 | }; | ||
20 | |||
21 | #define C(x, y) .type = PERF_TYPE_##x, .config = PERF_COUNT_##y | ||
22 | #define CR(x, y) .type = PERF_TYPE_##x, .config = y | ||
23 | |||
24 | static struct event_symbol event_symbols[] = { | ||
25 | { C(HARDWARE, CPU_CYCLES), "cpu-cycles", }, | ||
26 | { C(HARDWARE, CPU_CYCLES), "cycles", }, | ||
27 | { C(HARDWARE, INSTRUCTIONS), "instructions", }, | ||
28 | { C(HARDWARE, CACHE_REFERENCES), "cache-references", }, | ||
29 | { C(HARDWARE, CACHE_MISSES), "cache-misses", }, | ||
30 | { C(HARDWARE, BRANCH_INSTRUCTIONS), "branch-instructions", }, | ||
31 | { C(HARDWARE, BRANCH_INSTRUCTIONS), "branches", }, | ||
32 | { C(HARDWARE, BRANCH_MISSES), "branch-misses", }, | ||
33 | { C(HARDWARE, BUS_CYCLES), "bus-cycles", }, | ||
34 | |||
35 | { C(SOFTWARE, CPU_CLOCK), "cpu-clock", }, | ||
36 | { C(SOFTWARE, TASK_CLOCK), "task-clock", }, | ||
37 | { C(SOFTWARE, PAGE_FAULTS), "page-faults", }, | ||
38 | { C(SOFTWARE, PAGE_FAULTS), "faults", }, | ||
39 | { C(SOFTWARE, PAGE_FAULTS_MIN), "minor-faults", }, | ||
40 | { C(SOFTWARE, PAGE_FAULTS_MAJ), "major-faults", }, | ||
41 | { C(SOFTWARE, CONTEXT_SWITCHES), "context-switches", }, | ||
42 | { C(SOFTWARE, CONTEXT_SWITCHES), "cs", }, | ||
43 | { C(SOFTWARE, CPU_MIGRATIONS), "cpu-migrations", }, | ||
44 | { C(SOFTWARE, CPU_MIGRATIONS), "migrations", }, | ||
45 | }; | ||
46 | |||
47 | #define __PERF_COUNTER_FIELD(config, name) \ | ||
48 | ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) | ||
49 | |||
50 | #define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) | ||
51 | #define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) | ||
52 | #define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) | ||
53 | #define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) | ||
54 | |||
55 | static char *hw_event_names[] = { | ||
56 | "cycles", | ||
57 | "instructions", | ||
58 | "cache-references", | ||
59 | "cache-misses", | ||
60 | "branches", | ||
61 | "branch-misses", | ||
62 | "bus-cycles", | ||
63 | }; | ||
64 | |||
65 | static char *sw_event_names[] = { | ||
66 | "cpu-clock-ticks", | ||
67 | "task-clock-ticks", | ||
68 | "page-faults", | ||
69 | "context-switches", | ||
70 | "CPU-migrations", | ||
71 | "minor-faults", | ||
72 | "major-faults", | ||
73 | }; | ||
74 | |||
75 | #define MAX_ALIASES 8 | ||
76 | |||
77 | static char *hw_cache [][MAX_ALIASES] = { | ||
78 | { "L1-data" , "l1-d", "l1d", "l1" }, | ||
79 | { "L1-instruction" , "l1-i", "l1i" }, | ||
80 | { "L2" , "l2" }, | ||
81 | { "Data-TLB" , "dtlb", "d-tlb" }, | ||
82 | { "Instruction-TLB" , "itlb", "i-tlb" }, | ||
83 | { "Branch" , "bpu" , "btb", "bpc" }, | ||
84 | }; | ||
85 | |||
86 | static char *hw_cache_op [][MAX_ALIASES] = { | ||
87 | { "Load" , "read" }, | ||
88 | { "Store" , "write" }, | ||
89 | { "Prefetch" , "speculative-read", "speculative-load" }, | ||
90 | }; | ||
91 | |||
92 | static char *hw_cache_result [][MAX_ALIASES] = { | ||
93 | { "Reference" , "ops", "access" }, | ||
94 | { "Miss" }, | ||
95 | }; | ||
96 | |||
97 | char *event_name(int counter) | ||
98 | { | ||
99 | __u64 config = attrs[counter].config; | ||
100 | int type = attrs[counter].type; | ||
101 | static char buf[32]; | ||
102 | |||
103 | if (attrs[counter].type == PERF_TYPE_RAW) { | ||
104 | sprintf(buf, "raw 0x%llx", config); | ||
105 | return buf; | ||
106 | } | ||
107 | |||
108 | switch (type) { | ||
109 | case PERF_TYPE_HARDWARE: | ||
110 | if (config < PERF_HW_EVENTS_MAX) | ||
111 | return hw_event_names[config]; | ||
112 | return "unknown-hardware"; | ||
113 | |||
114 | case PERF_TYPE_HW_CACHE: { | ||
115 | __u8 cache_type, cache_op, cache_result; | ||
116 | static char name[100]; | ||
117 | |||
118 | cache_type = (config >> 0) & 0xff; | ||
119 | if (cache_type > PERF_COUNT_HW_CACHE_MAX) | ||
120 | return "unknown-ext-hardware-cache-type"; | ||
121 | |||
122 | cache_op = (config >> 8) & 0xff; | ||
123 | if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX) | ||
124 | return "unknown-ext-hardware-cache-op"; | ||
125 | |||
126 | cache_result = (config >> 16) & 0xff; | ||
127 | if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
128 | return "unknown-ext-hardware-cache-result"; | ||
129 | |||
130 | sprintf(name, "%s-Cache-%s-%ses", | ||
131 | hw_cache[cache_type][0], | ||
132 | hw_cache_op[cache_op][0], | ||
133 | hw_cache_result[cache_result][0]); | ||
134 | |||
135 | return name; | ||
136 | } | ||
137 | |||
138 | case PERF_TYPE_SOFTWARE: | ||
139 | if (config < PERF_SW_EVENTS_MAX) | ||
140 | return sw_event_names[config]; | ||
141 | return "unknown-software"; | ||
142 | |||
143 | default: | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | return "unknown"; | ||
148 | } | ||
149 | |||
150 | static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size) | ||
151 | { | ||
152 | int i, j; | ||
153 | |||
154 | for (i = 0; i < size; i++) { | ||
155 | for (j = 0; j < MAX_ALIASES; j++) { | ||
156 | if (!names[i][j]) | ||
157 | break; | ||
158 | if (strcasestr(str, names[i][j])) | ||
159 | return i; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr) | ||
167 | { | ||
168 | __u8 cache_type = -1, cache_op = 0, cache_result = 0; | ||
169 | |||
170 | cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX); | ||
171 | /* | ||
172 | * No fallback - if we cannot get a clear cache type | ||
173 | * then bail out: | ||
174 | */ | ||
175 | if (cache_type == -1) | ||
176 | return -EINVAL; | ||
177 | |||
178 | cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX); | ||
179 | /* | ||
180 | * Fall back to reads: | ||
181 | */ | ||
182 | if (cache_type == -1) | ||
183 | cache_type = PERF_COUNT_HW_CACHE_OP_READ; | ||
184 | |||
185 | cache_result = parse_aliases(str, hw_cache_result, | ||
186 | PERF_COUNT_HW_CACHE_RESULT_MAX); | ||
187 | /* | ||
188 | * Fall back to accesses: | ||
189 | */ | ||
190 | if (cache_result == -1) | ||
191 | cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS; | ||
192 | |||
193 | attr->config = cache_type | (cache_op << 8) | (cache_result << 16); | ||
194 | attr->type = PERF_TYPE_HW_CACHE; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Each event can have multiple symbolic names. | ||
201 | * Symbolic names are (almost) exactly matched. | ||
202 | */ | ||
203 | static int parse_event_symbols(const char *str, struct perf_counter_attr *attr) | ||
204 | { | ||
205 | __u64 config, id; | ||
206 | int type; | ||
207 | unsigned int i; | ||
208 | const char *sep, *pstr; | ||
209 | |||
210 | if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) { | ||
211 | attr->type = PERF_TYPE_RAW; | ||
212 | attr->config = config; | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | pstr = str; | ||
218 | sep = strchr(pstr, ':'); | ||
219 | if (sep) { | ||
220 | type = atoi(pstr); | ||
221 | pstr = sep + 1; | ||
222 | id = atoi(pstr); | ||
223 | sep = strchr(pstr, ':'); | ||
224 | if (sep) { | ||
225 | pstr = sep + 1; | ||
226 | if (strchr(pstr, 'k')) | ||
227 | attr->exclude_user = 1; | ||
228 | if (strchr(pstr, 'u')) | ||
229 | attr->exclude_kernel = 1; | ||
230 | } | ||
231 | attr->type = type; | ||
232 | attr->config = id; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++) { | ||
238 | if (!strncmp(str, event_symbols[i].symbol, | ||
239 | strlen(event_symbols[i].symbol))) { | ||
240 | |||
241 | attr->type = event_symbols[i].type; | ||
242 | attr->config = event_symbols[i].config; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | return parse_generic_hw_symbols(str, attr); | ||
249 | } | ||
250 | |||
251 | int parse_events(const struct option *opt, const char *str, int unset) | ||
252 | { | ||
253 | struct perf_counter_attr attr; | ||
254 | int ret; | ||
255 | |||
256 | memset(&attr, 0, sizeof(attr)); | ||
257 | again: | ||
258 | if (nr_counters == MAX_COUNTERS) | ||
259 | return -1; | ||
260 | |||
261 | ret = parse_event_symbols(str, &attr); | ||
262 | if (ret < 0) | ||
263 | return ret; | ||
264 | |||
265 | attrs[nr_counters] = attr; | ||
266 | nr_counters++; | ||
267 | |||
268 | str = strstr(str, ","); | ||
269 | if (str) { | ||
270 | str++; | ||
271 | goto again; | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static const char * const event_type_descriptors[] = { | ||
278 | "", | ||
279 | "Hardware event", | ||
280 | "Software event", | ||
281 | "Tracepoint event", | ||
282 | "Hardware cache event", | ||
283 | }; | ||
284 | |||
285 | /* | ||
286 | * Print the help text for the event symbols: | ||
287 | */ | ||
288 | void print_events(void) | ||
289 | { | ||
290 | struct event_symbol *syms = event_symbols; | ||
291 | unsigned int i, type, prev_type = -1; | ||
292 | |||
293 | fprintf(stderr, "\n"); | ||
294 | fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
297 | type = syms->type + 1; | ||
298 | if (type > ARRAY_SIZE(event_type_descriptors)) | ||
299 | type = 0; | ||
300 | |||
301 | if (type != prev_type) | ||
302 | fprintf(stderr, "\n"); | ||
303 | |||
304 | fprintf(stderr, " %-30s [%s]\n", syms->symbol, | ||
305 | event_type_descriptors[type]); | ||
306 | |||
307 | prev_type = type; | ||
308 | } | ||
309 | |||
310 | fprintf(stderr, "\n"); | ||
311 | fprintf(stderr, " %-30s [raw hardware event descriptor]\n", | ||
312 | "rNNN"); | ||
313 | fprintf(stderr, "\n"); | ||
314 | |||
315 | exit(129); | ||
316 | } | ||