perf_counter tools: Introduce alias member in event_symbol
[pandora-kernel.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         char    *alias;
20 };
21
22 #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
23 #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
24
25 static struct event_symbol event_symbols[] = {
26   { CHW(CPU_CYCLES),            "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",  "branches"      },
31   { CHW(BRANCH_MISSES),         "branch-misses",        ""              },
32   { CHW(BUS_CYCLES),            "bus-cycles",           ""              },
33
34   { CSW(CPU_CLOCK),             "cpu-clock",            ""              },
35   { CSW(TASK_CLOCK),            "task-clock",           ""              },
36   { CSW(PAGE_FAULTS),           "page-faults",          ""              },
37   { CSW(PAGE_FAULTS),           "faults",               ""              },
38   { CSW(PAGE_FAULTS_MIN),       "minor-faults",         ""              },
39   { CSW(PAGE_FAULTS_MAJ),       "major-faults",         ""              },
40   { CSW(CONTEXT_SWITCHES),      "context-switches",     "cs"            },
41   { CSW(CPU_MIGRATIONS),        "cpu-migrations",       "migrations"    },
42 };
43
44 #define __PERF_COUNTER_FIELD(config, name) \
45         ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT)
46
47 #define PERF_COUNTER_RAW(config)        __PERF_COUNTER_FIELD(config, RAW)
48 #define PERF_COUNTER_CONFIG(config)     __PERF_COUNTER_FIELD(config, CONFIG)
49 #define PERF_COUNTER_TYPE(config)       __PERF_COUNTER_FIELD(config, TYPE)
50 #define PERF_COUNTER_ID(config)         __PERF_COUNTER_FIELD(config, EVENT)
51
52 static char *hw_event_names[] = {
53         "cycles",
54         "instructions",
55         "cache-references",
56         "cache-misses",
57         "branches",
58         "branch-misses",
59         "bus-cycles",
60 };
61
62 static char *sw_event_names[] = {
63         "cpu-clock-msecs",
64         "task-clock-msecs",
65         "page-faults",
66         "context-switches",
67         "CPU-migrations",
68         "minor-faults",
69         "major-faults",
70 };
71
72 #define MAX_ALIASES 8
73
74 static char *hw_cache [][MAX_ALIASES] = {
75         { "L1-data"             , "l1-d", "l1d"                                 },
76         { "L1-instruction"      , "l1-i", "l1i"                                 },
77         { "L2"                  , "l2"                                          },
78         { "Data-TLB"            , "dtlb", "d-tlb"                               },
79         { "Instruction-TLB"     , "itlb", "i-tlb"                               },
80         { "Branch"              , "bpu" , "btb", "bpc"                          },
81 };
82
83 static char *hw_cache_op [][MAX_ALIASES] = {
84         { "Load"                , "read"                                        },
85         { "Store"               , "write"                                       },
86         { "Prefetch"            , "speculative-read", "speculative-load"        },
87 };
88
89 static char *hw_cache_result [][MAX_ALIASES] = {
90         { "Reference"           , "ops", "access"                               },
91         { "Miss"                                                                },
92 };
93
94 char *event_name(int counter)
95 {
96         u64 config = attrs[counter].config;
97         int type = attrs[counter].type;
98         static char buf[32];
99
100         if (attrs[counter].type == PERF_TYPE_RAW) {
101                 sprintf(buf, "raw 0x%llx", config);
102                 return buf;
103         }
104
105         switch (type) {
106         case PERF_TYPE_HARDWARE:
107                 if (config < PERF_COUNT_HW_MAX)
108                         return hw_event_names[config];
109                 return "unknown-hardware";
110
111         case PERF_TYPE_HW_CACHE: {
112                 u8 cache_type, cache_op, cache_result;
113                 static char name[100];
114
115                 cache_type   = (config >>  0) & 0xff;
116                 if (cache_type > PERF_COUNT_HW_CACHE_MAX)
117                         return "unknown-ext-hardware-cache-type";
118
119                 cache_op     = (config >>  8) & 0xff;
120                 if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
121                         return "unknown-ext-hardware-cache-op";
122
123                 cache_result = (config >> 16) & 0xff;
124                 if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
125                         return "unknown-ext-hardware-cache-result";
126
127                 sprintf(name, "%s-Cache-%s-%ses",
128                         hw_cache[cache_type][0],
129                         hw_cache_op[cache_op][0],
130                         hw_cache_result[cache_result][0]);
131
132                 return name;
133         }
134
135         case PERF_TYPE_SOFTWARE:
136                 if (config < PERF_COUNT_SW_MAX)
137                         return sw_event_names[config];
138                 return "unknown-software";
139
140         default:
141                 break;
142         }
143
144         return "unknown";
145 }
146
147 static int parse_aliases(const char *str, char *names[][MAX_ALIASES], int size)
148 {
149         int i, j;
150
151         for (i = 0; i < size; i++) {
152                 for (j = 0; j < MAX_ALIASES; j++) {
153                         if (!names[i][j])
154                                 break;
155                         if (strcasestr(str, names[i][j]))
156                                 return i;
157                 }
158         }
159
160         return -1;
161 }
162
163 static int parse_generic_hw_symbols(const char *str, struct perf_counter_attr *attr)
164 {
165         int cache_type = -1, cache_op = 0, cache_result = 0;
166
167         cache_type = parse_aliases(str, hw_cache, PERF_COUNT_HW_CACHE_MAX);
168         /*
169          * No fallback - if we cannot get a clear cache type
170          * then bail out:
171          */
172         if (cache_type == -1)
173                 return -EINVAL;
174
175         cache_op = parse_aliases(str, hw_cache_op, PERF_COUNT_HW_CACHE_OP_MAX);
176         /*
177          * Fall back to reads:
178          */
179         if (cache_op == -1)
180                 cache_op = PERF_COUNT_HW_CACHE_OP_READ;
181
182         cache_result = parse_aliases(str, hw_cache_result,
183                                         PERF_COUNT_HW_CACHE_RESULT_MAX);
184         /*
185          * Fall back to accesses:
186          */
187         if (cache_result == -1)
188                 cache_result = PERF_COUNT_HW_CACHE_RESULT_ACCESS;
189
190         attr->config = cache_type | (cache_op << 8) | (cache_result << 16);
191         attr->type = PERF_TYPE_HW_CACHE;
192
193         return 0;
194 }
195
196 static int check_events(const char *str, unsigned int i)
197 {
198         if (!strncmp(str, event_symbols[i].symbol,
199                      strlen(event_symbols[i].symbol)))
200                 return 1;
201
202         if (strlen(event_symbols[i].alias))
203                 if (!strncmp(str, event_symbols[i].alias,
204                       strlen(event_symbols[i].alias)))
205                         return 1;
206         return 0;
207 }
208
209 /*
210  * Each event can have multiple symbolic names.
211  * Symbolic names are (almost) exactly matched.
212  */
213 static int parse_event_symbols(const char *str, struct perf_counter_attr *attr)
214 {
215         u64 config, id;
216         int type;
217         unsigned int i;
218         const char *sep, *pstr;
219
220         if (str[0] == 'r' && hex2u64(str + 1, &config) > 0) {
221                 attr->type = PERF_TYPE_RAW;
222                 attr->config = config;
223
224                 return 0;
225         }
226
227         pstr = str;
228         sep = strchr(pstr, ':');
229         if (sep) {
230                 type = atoi(pstr);
231                 pstr = sep + 1;
232                 id = atoi(pstr);
233                 sep = strchr(pstr, ':');
234                 if (sep) {
235                         pstr = sep + 1;
236                         if (strchr(pstr, 'k'))
237                                 attr->exclude_user = 1;
238                         if (strchr(pstr, 'u'))
239                                 attr->exclude_kernel = 1;
240                 }
241                 attr->type = type;
242                 attr->config = id;
243
244                 return 0;
245         }
246
247         for (i = 0; i < ARRAY_SIZE(event_symbols); i++) {
248                 if (check_events(str, i)) {
249                         attr->type = event_symbols[i].type;
250                         attr->config = event_symbols[i].config;
251
252                         return 0;
253                 }
254         }
255
256         return parse_generic_hw_symbols(str, attr);
257 }
258
259 int parse_events(const struct option *opt, const char *str, int unset)
260 {
261         struct perf_counter_attr attr;
262         int ret;
263
264         memset(&attr, 0, sizeof(attr));
265 again:
266         if (nr_counters == MAX_COUNTERS)
267                 return -1;
268
269         ret = parse_event_symbols(str, &attr);
270         if (ret < 0)
271                 return ret;
272
273         attrs[nr_counters] = attr;
274         nr_counters++;
275
276         str = strstr(str, ",");
277         if (str) {
278                 str++;
279                 goto again;
280         }
281
282         return 0;
283 }
284
285 static const char * const event_type_descriptors[] = {
286         "",
287         "Hardware event",
288         "Software event",
289         "Tracepoint event",
290         "Hardware cache event",
291 };
292
293 /*
294  * Print the help text for the event symbols:
295  */
296 void print_events(void)
297 {
298         struct event_symbol *syms = event_symbols;
299         unsigned int i, type, prev_type = -1;
300         char name[40];
301
302         fprintf(stderr, "\n");
303         fprintf(stderr, "List of pre-defined events (to be used in -e):\n");
304
305         for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
306                 type = syms->type + 1;
307                 if (type > ARRAY_SIZE(event_type_descriptors))
308                         type = 0;
309
310                 if (type != prev_type)
311                         fprintf(stderr, "\n");
312
313                 if (strlen(syms->alias))
314                         sprintf(name, "%s OR %s", syms->symbol, syms->alias);
315                 else
316                         strcpy(name, syms->symbol);
317                 fprintf(stderr, "  %-40s [%s]\n", name,
318                         event_type_descriptors[type]);
319
320                 prev_type = type;
321         }
322
323         fprintf(stderr, "\n");
324         fprintf(stderr, "  %-40s [raw hardware event descriptor]\n",
325                 "rNNN");
326         fprintf(stderr, "\n");
327
328         exit(129);
329 }