perf_counter tools: Define separate declarations for H/W and S/W events
[linux-2.6.git] / tools / perf / util / parse-events.c
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 CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
22 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
23
24 static struct event_symbol event_symbols[] = {
25   { CHW(CPU_CYCLES),            "cpu-cycles",           },
26   { CHW(CPU_CYCLES),            "cycles",               },
27   { CHW(INSTRUCTIONS),          "instructions",         },
28   { CHW(CACHE_REFERENCES),      "cache-references",     },
29   { CHW(CACHE_MISSES),          "cache-misses",         },
30   { CHW(BRANCH_INSTRUCTIONS),   "branch-instructions",  },
31   { CHW(BRANCH_INSTRUCTIONS),   "branches",             },
32   { CHW(BRANCH_MISSES),         "branch-misses",        },
33   { CHW(BUS_CYCLES),            "bus-cycles",           },
34
35   { CSW(CPU_CLOCK),             "cpu-clock",            },
36   { CSW(TASK_CLOCK),            "task-clock",           },
37   { CSW(PAGE_FAULTS),           "page-faults",          },
38   { CSW(PAGE_FAULTS),           "faults",               },
39   { CSW(PAGE_FAULTS_MIN),       "minor-faults",         },
40   { CSW(PAGE_FAULTS_MAJ),       "major-faults",         },
41   { CSW(CONTEXT_SWITCHES),      "context-switches",     },
42   { CSW(CONTEXT_SWITCHES),      "cs",                   },
43   { CSW(CPU_MIGRATIONS),        "cpu-migrations",       },
44   { CSW(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-msecs",
67         "task-clock-msecs",
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"                                 },
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_COUNT_HW_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_COUNT_SW_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 -1;
164 }
165
166 static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
167 {
168         int 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_op == -1)
183                 cache_op = 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 }