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, HW_CPU_CYCLES), "cpu-cycles", }, 26 { C(HARDWARE, HW_CPU_CYCLES), "cycles", }, 27 { C(HARDWARE, HW_INSTRUCTIONS), "instructions", }, 28 { C(HARDWARE, HW_CACHE_REFERENCES), "cache-references", }, 29 { C(HARDWARE, HW_CACHE_MISSES), "cache-misses", }, 30 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branch-instructions", }, 31 { C(HARDWARE, HW_BRANCH_INSTRUCTIONS),"branches", }, 32 { C(HARDWARE, HW_BRANCH_MISSES), "branch-misses", }, 33 { C(HARDWARE, HW_BUS_CYCLES), "bus-cycles", }, 34 35 { C(SOFTWARE, SW_CPU_CLOCK), "cpu-clock", }, 36 { C(SOFTWARE, SW_TASK_CLOCK), "task-clock", }, 37 { C(SOFTWARE, SW_PAGE_FAULTS), "page-faults", }, 38 { C(SOFTWARE, SW_PAGE_FAULTS), "faults", }, 39 { C(SOFTWARE, SW_PAGE_FAULTS_MIN), "minor-faults", }, 40 { C(SOFTWARE, SW_PAGE_FAULTS_MAJ), "major-faults", }, 41 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "context-switches", }, 42 { C(SOFTWARE, SW_CONTEXT_SWITCHES), "cs", }, 43 { C(SOFTWARE, SW_CPU_MIGRATIONS), "cpu-migrations", }, 44 { C(SOFTWARE, SW_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_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 } 317