1 /* Parse event JSON files */ 2 3 /* 4 * Copyright (c) 2014, Intel Corporation 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 28 * OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/resource.h> /* getrlimit */ 33 #include <sys/stat.h> 34 #include <sys/time.h> /* getrlimit */ 35 #include <ctype.h> 36 #include <dirent.h> 37 #include <errno.h> 38 #include <libgen.h> 39 #include <limits.h> 40 #include <stdarg.h> 41 #include <stddef.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <ftw.h> 47 #include "list.h" 48 #include "jsmn.h" 49 #include "json.h" 50 #include "pmu-events.h" 51 52 static int 53 nftw_ordered(const char *path, int (*fn)(const char *, const struct stat *, int, 54 struct FTW *), int nfds, int ftwflags); 55 #define nftw nftw_ordered 56 57 _Noreturn void _Exit(int); 58 char *get_cpu_str(void); 59 60 int verbose; 61 static char *prog; 62 63 struct json_event { 64 char *name; 65 char *compat; 66 char *event; 67 char *desc; 68 char *long_desc; 69 char *pmu; 70 char *unit; 71 char *perpkg; 72 char *aggr_mode; 73 char *metric_expr; 74 char *metric_name; 75 char *metric_group; 76 char *deprecated; 77 char *metric_constraint; 78 }; 79 80 static enum aggr_mode_class convert(const char *aggr_mode) 81 { 82 if (!strcmp(aggr_mode, "PerCore")) 83 return PerCore; 84 else if (!strcmp(aggr_mode, "PerChip")) 85 return PerChip; 86 87 pr_err("%s: Wrong AggregationMode value '%s'\n", prog, aggr_mode); 88 return -1; 89 } 90 91 static LIST_HEAD(sys_event_tables); 92 93 struct sys_event_table { 94 struct list_head list; 95 char *soc_id; 96 }; 97 98 static void free_sys_event_tables(void) 99 { 100 struct sys_event_table *et, *next; 101 102 list_for_each_entry_safe(et, next, &sys_event_tables, list) { 103 free(et->soc_id); 104 free(et); 105 } 106 } 107 108 int eprintf(int level, int var, const char *fmt, ...) 109 { 110 111 int ret; 112 va_list args; 113 114 if (var < level) 115 return 0; 116 117 va_start(args, fmt); 118 119 ret = vfprintf(stderr, fmt, args); 120 121 va_end(args); 122 123 return ret; 124 } 125 126 static void addfield(char *map, char **dst, const char *sep, 127 const char *a, jsmntok_t *bt) 128 { 129 unsigned int len = strlen(a) + 1 + strlen(sep); 130 int olen = *dst ? strlen(*dst) : 0; 131 int blen = bt ? json_len(bt) : 0; 132 char *out; 133 134 out = realloc(*dst, len + olen + blen); 135 if (!out) { 136 /* Don't add field in this case */ 137 return; 138 } 139 *dst = out; 140 141 if (!olen) 142 *(*dst) = 0; 143 else 144 strcat(*dst, sep); 145 strcat(*dst, a); 146 if (bt) 147 strncat(*dst, map + bt->start, blen); 148 } 149 150 static void fixname(char *s) 151 { 152 for (; *s; s++) 153 *s = tolower(*s); 154 } 155 156 static void fixdesc(char *s) 157 { 158 char *e = s + strlen(s); 159 160 /* Remove trailing dots that look ugly in perf list */ 161 --e; 162 while (e >= s && isspace(*e)) 163 --e; 164 if (e >= s && *e == '.') 165 *e = 0; 166 } 167 168 /* Add escapes for '\' so they are proper C strings. */ 169 static char *fixregex(char *s) 170 { 171 int len = 0; 172 int esc_count = 0; 173 char *fixed = NULL; 174 char *p, *q; 175 176 /* Count the number of '\' in string */ 177 for (p = s; *p; p++) { 178 ++len; 179 if (*p == '\\') 180 ++esc_count; 181 } 182 183 if (esc_count == 0) 184 return s; 185 186 /* allocate space for a new string */ 187 fixed = (char *) malloc(len + esc_count + 1); 188 if (!fixed) 189 return NULL; 190 191 /* copy over the characters */ 192 q = fixed; 193 for (p = s; *p; p++) { 194 if (*p == '\\') { 195 *q = '\\'; 196 ++q; 197 } 198 *q = *p; 199 ++q; 200 } 201 *q = '\0'; 202 return fixed; 203 } 204 205 static struct msrmap { 206 const char *num; 207 const char *pname; 208 } msrmap[] = { 209 { "0x3F6", "ldlat=" }, 210 { "0x1A6", "offcore_rsp=" }, 211 { "0x1A7", "offcore_rsp=" }, 212 { "0x3F7", "frontend=" }, 213 { NULL, NULL } 214 }; 215 216 static void cut_comma(char *map, jsmntok_t *newval) 217 { 218 int i; 219 220 /* Cut off everything after comma */ 221 for (i = newval->start; i < newval->end; i++) { 222 if (map[i] == ',') 223 newval->end = i; 224 } 225 } 226 227 static struct msrmap *lookup_msr(char *map, jsmntok_t *val) 228 { 229 jsmntok_t newval = *val; 230 static bool warned; 231 int i; 232 233 cut_comma(map, &newval); 234 for (i = 0; msrmap[i].num; i++) 235 if (json_streq(map, &newval, msrmap[i].num)) 236 return &msrmap[i]; 237 if (!warned) { 238 warned = true; 239 pr_err("%s: Unknown MSR in event file %.*s\n", prog, 240 json_len(val), map + val->start); 241 } 242 return NULL; 243 } 244 245 static struct map { 246 const char *json; 247 const char *perf; 248 } unit_to_pmu[] = { 249 { "CBO", "uncore_cbox" }, 250 { "QPI LL", "uncore_qpi" }, 251 { "SBO", "uncore_sbox" }, 252 { "iMPH-U", "uncore_arb" }, 253 { "CPU-M-CF", "cpum_cf" }, 254 { "CPU-M-SF", "cpum_sf" }, 255 { "UPI LL", "uncore_upi" }, 256 { "hisi_sicl,cpa", "hisi_sicl,cpa"}, 257 { "hisi_sccl,ddrc", "hisi_sccl,ddrc" }, 258 { "hisi_sccl,hha", "hisi_sccl,hha" }, 259 { "hisi_sccl,l3c", "hisi_sccl,l3c" }, 260 /* it's not realistic to keep adding these, we need something more scalable ... */ 261 { "imx8_ddr", "imx8_ddr" }, 262 { "L3PMC", "amd_l3" }, 263 { "DFPMC", "amd_df" }, 264 { "cpu_core", "cpu_core" }, 265 { "cpu_atom", "cpu_atom" }, 266 {} 267 }; 268 269 static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val) 270 { 271 int i; 272 273 for (i = 0; table[i].json; i++) { 274 if (json_streq(map, val, table[i].json)) 275 return table[i].perf; 276 } 277 return NULL; 278 } 279 280 #define EXPECT(e, t, m) do { if (!(e)) { \ 281 jsmntok_t *loc = (t); \ 282 if (!(t)->start && (t) > tokens) \ 283 loc = (t) - 1; \ 284 pr_err("%s:%d: " m ", got %s\n", fn, \ 285 json_line(map, loc), \ 286 json_name(t)); \ 287 err = -EIO; \ 288 goto out_free; \ 289 } } while (0) 290 291 static char *topic; 292 293 static char *get_topic(void) 294 { 295 char *tp; 296 int i; 297 298 /* tp is free'd in process_one_file() */ 299 i = asprintf(&tp, "%s", topic); 300 if (i < 0) { 301 pr_info("%s: asprintf() error %s\n", prog); 302 return NULL; 303 } 304 305 for (i = 0; i < (int) strlen(tp); i++) { 306 char c = tp[i]; 307 308 if (c == '-') 309 tp[i] = ' '; 310 else if (c == '.') { 311 tp[i] = '\0'; 312 break; 313 } 314 } 315 316 return tp; 317 } 318 319 static int add_topic(char *bname) 320 { 321 free(topic); 322 topic = strdup(bname); 323 if (!topic) { 324 pr_info("%s: strdup() error %s for file %s\n", prog, 325 strerror(errno), bname); 326 return -ENOMEM; 327 } 328 return 0; 329 } 330 331 struct perf_entry_data { 332 FILE *outfp; 333 char *topic; 334 }; 335 336 static int close_table; 337 338 static void print_events_table_prefix(FILE *fp, const char *tblname) 339 { 340 fprintf(fp, "static const struct pmu_event %s[] = {\n", tblname); 341 close_table = 1; 342 } 343 344 static int print_events_table_entry(void *data, struct json_event *je) 345 { 346 struct perf_entry_data *pd = data; 347 FILE *outfp = pd->outfp; 348 char *topic_local = pd->topic; 349 350 /* 351 * TODO: Remove formatting chars after debugging to reduce 352 * string lengths. 353 */ 354 fprintf(outfp, "{\n"); 355 356 if (je->name) 357 fprintf(outfp, "\t.name = \"%s\",\n", je->name); 358 if (je->event) 359 fprintf(outfp, "\t.event = \"%s\",\n", je->event); 360 fprintf(outfp, "\t.desc = \"%s\",\n", je->desc); 361 if (je->compat) 362 fprintf(outfp, "\t.compat = \"%s\",\n", je->compat); 363 fprintf(outfp, "\t.topic = \"%s\",\n", topic_local); 364 if (je->long_desc && je->long_desc[0]) 365 fprintf(outfp, "\t.long_desc = \"%s\",\n", je->long_desc); 366 if (je->pmu) 367 fprintf(outfp, "\t.pmu = \"%s\",\n", je->pmu); 368 if (je->unit) 369 fprintf(outfp, "\t.unit = \"%s\",\n", je->unit); 370 if (je->perpkg) 371 fprintf(outfp, "\t.perpkg = \"%s\",\n", je->perpkg); 372 if (je->aggr_mode) 373 fprintf(outfp, "\t.aggr_mode = \"%d\",\n", convert(je->aggr_mode)); 374 if (je->metric_expr) 375 fprintf(outfp, "\t.metric_expr = \"%s\",\n", je->metric_expr); 376 if (je->metric_name) 377 fprintf(outfp, "\t.metric_name = \"%s\",\n", je->metric_name); 378 if (je->metric_group) 379 fprintf(outfp, "\t.metric_group = \"%s\",\n", je->metric_group); 380 if (je->deprecated) 381 fprintf(outfp, "\t.deprecated = \"%s\",\n", je->deprecated); 382 if (je->metric_constraint) 383 fprintf(outfp, "\t.metric_constraint = \"%s\",\n", je->metric_constraint); 384 fprintf(outfp, "},\n"); 385 386 return 0; 387 } 388 389 struct event_struct { 390 struct list_head list; 391 char *name; 392 char *event; 393 char *compat; 394 char *desc; 395 char *long_desc; 396 char *pmu; 397 char *unit; 398 char *perpkg; 399 char *aggr_mode; 400 char *metric_expr; 401 char *metric_name; 402 char *metric_group; 403 char *deprecated; 404 char *metric_constraint; 405 }; 406 407 #define ADD_EVENT_FIELD(field) do { if (je->field) { \ 408 es->field = strdup(je->field); \ 409 if (!es->field) \ 410 goto out_free; \ 411 } } while (0) 412 413 #define FREE_EVENT_FIELD(field) free(es->field) 414 415 #define TRY_FIXUP_FIELD(field) do { if (es->field && !je->field) {\ 416 je->field = strdup(es->field); \ 417 if (!je->field) \ 418 return -ENOMEM; \ 419 } } while (0) 420 421 #define FOR_ALL_EVENT_STRUCT_FIELDS(op) do { \ 422 op(name); \ 423 op(event); \ 424 op(desc); \ 425 op(long_desc); \ 426 op(pmu); \ 427 op(unit); \ 428 op(perpkg); \ 429 op(aggr_mode); \ 430 op(metric_expr); \ 431 op(metric_name); \ 432 op(metric_group); \ 433 op(deprecated); \ 434 } while (0) 435 436 static LIST_HEAD(arch_std_events); 437 438 static void free_arch_std_events(void) 439 { 440 struct event_struct *es, *next; 441 442 list_for_each_entry_safe(es, next, &arch_std_events, list) { 443 FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD); 444 list_del_init(&es->list); 445 free(es); 446 } 447 } 448 449 static int save_arch_std_events(void *data __unused, struct json_event *je) 450 { 451 struct event_struct *es; 452 453 es = malloc(sizeof(*es)); 454 if (!es) 455 return -ENOMEM; 456 memset(es, 0, sizeof(*es)); 457 FOR_ALL_EVENT_STRUCT_FIELDS(ADD_EVENT_FIELD); 458 list_add_tail(&es->list, &arch_std_events); 459 return 0; 460 out_free: 461 FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD); 462 free(es); 463 return -ENOMEM; 464 } 465 466 static void print_events_table_suffix(FILE *outfp) 467 { 468 fprintf(outfp, "{\n"); 469 470 fprintf(outfp, "\t.name = 0,\n"); 471 fprintf(outfp, "\t.event = 0,\n"); 472 fprintf(outfp, "\t.desc = 0,\n"); 473 474 fprintf(outfp, "},\n"); 475 fprintf(outfp, "};\n"); 476 close_table = 0; 477 } 478 479 static struct fixed { 480 const char *name; 481 const char *event; 482 } fixed[] = { 483 { "inst_retired.any", "event=0xc0,period=2000003" }, 484 { "inst_retired.any_p", "event=0xc0,period=2000003" }, 485 { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03,period=2000003" }, 486 { "cpu_clk_unhalted.thread", "event=0x3c,period=2000003" }, 487 { "cpu_clk_unhalted.core", "event=0x3c,period=2000003" }, 488 { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1,period=2000003" }, 489 { NULL, NULL}, 490 }; 491 492 /* 493 * Handle different fixed counter encodings between JSON and perf. 494 */ 495 static char *real_event(const char *name, char *event) 496 { 497 int i; 498 499 if (!name) 500 return NULL; 501 502 for (i = 0; fixed[i].name; i++) 503 if (!strcasecmp(name, fixed[i].name)) 504 return (char *)fixed[i].event; 505 return event; 506 } 507 508 static int 509 try_fixup(const char *fn, char *arch_std, struct json_event *je, char **event) 510 { 511 /* try to find matching event from arch standard values */ 512 struct event_struct *es; 513 514 list_for_each_entry(es, &arch_std_events, list) { 515 if (!strcmp(arch_std, es->name)) { 516 FOR_ALL_EVENT_STRUCT_FIELDS(TRY_FIXUP_FIELD); 517 *event = je->event; 518 return 0; 519 } 520 } 521 522 pr_err("%s: could not find matching %s for %s\n", 523 prog, arch_std, fn); 524 return -1; 525 } 526 527 /* Call func with each event in the json file */ 528 static int json_events(const char *fn, 529 int (*func)(void *data, struct json_event *je), 530 void *data) 531 { 532 int err; 533 size_t size; 534 jsmntok_t *tokens, *tok; 535 int i, j, len; 536 char *map; 537 char buf[128]; 538 539 if (!fn) 540 return -ENOENT; 541 542 tokens = parse_json(fn, &map, &size, &len); 543 if (!tokens) 544 return -EIO; 545 EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array"); 546 tok = tokens + 1; 547 for (i = 0; i < tokens->size; i++) { 548 char *event = NULL; 549 char *extra_desc = NULL; 550 char *filter = NULL; 551 struct json_event je = {}; 552 char *arch_std = NULL; 553 unsigned long long eventcode = 0; 554 unsigned long long configcode = 0; 555 struct msrmap *msr = NULL; 556 jsmntok_t *msrval = NULL; 557 jsmntok_t *precise = NULL; 558 jsmntok_t *obj = tok++; 559 bool configcode_present = false; 560 char *umask = NULL; 561 char *cmask = NULL; 562 char *inv = NULL; 563 char *any = NULL; 564 char *edge = NULL; 565 char *period = NULL; 566 char *fc_mask = NULL; 567 char *ch_mask = NULL; 568 569 EXPECT(obj->type == JSMN_OBJECT, obj, "expected object"); 570 for (j = 0; j < obj->size; j += 2) { 571 jsmntok_t *field, *val; 572 int nz; 573 char *s; 574 575 field = tok + j; 576 EXPECT(field->type == JSMN_STRING, tok + j, 577 "Expected field name"); 578 val = tok + j + 1; 579 EXPECT(val->type == JSMN_STRING, tok + j + 1, 580 "Expected string value"); 581 582 nz = !json_streq(map, val, "0"); 583 /* match_field */ 584 if (json_streq(map, field, "UMask") && nz) { 585 addfield(map, &umask, "", "umask=", val); 586 } else if (json_streq(map, field, "CounterMask") && nz) { 587 addfield(map, &cmask, "", "cmask=", val); 588 } else if (json_streq(map, field, "Invert") && nz) { 589 addfield(map, &inv, "", "inv=", val); 590 } else if (json_streq(map, field, "AnyThread") && nz) { 591 addfield(map, &any, "", "any=", val); 592 } else if (json_streq(map, field, "EdgeDetect") && nz) { 593 addfield(map, &edge, "", "edge=", val); 594 } else if (json_streq(map, field, "SampleAfterValue") && nz) { 595 addfield(map, &period, "", "period=", val); 596 } else if (json_streq(map, field, "FCMask") && nz) { 597 addfield(map, &fc_mask, "", "fc_mask=", val); 598 } else if (json_streq(map, field, "PortMask") && nz) { 599 addfield(map, &ch_mask, "", "ch_mask=", val); 600 } else if (json_streq(map, field, "EventCode")) { 601 char *code = NULL; 602 addfield(map, &code, "", "", val); 603 eventcode |= strtoul(code, NULL, 0); 604 free(code); 605 } else if (json_streq(map, field, "ConfigCode")) { 606 char *code = NULL; 607 addfield(map, &code, "", "", val); 608 configcode |= strtoul(code, NULL, 0); 609 free(code); 610 configcode_present = true; 611 } else if (json_streq(map, field, "ExtSel")) { 612 char *code = NULL; 613 addfield(map, &code, "", "", val); 614 eventcode |= strtoul(code, NULL, 0) << 8; 615 free(code); 616 } else if (json_streq(map, field, "EventName")) { 617 addfield(map, &je.name, "", "", val); 618 } else if (json_streq(map, field, "Compat")) { 619 addfield(map, &je.compat, "", "", val); 620 } else if (json_streq(map, field, "BriefDescription")) { 621 addfield(map, &je.desc, "", "", val); 622 fixdesc(je.desc); 623 } else if (json_streq(map, field, 624 "PublicDescription")) { 625 addfield(map, &je.long_desc, "", "", val); 626 fixdesc(je.long_desc); 627 } else if (json_streq(map, field, "PEBS") && nz) { 628 precise = val; 629 } else if (json_streq(map, field, "MSRIndex") && nz) { 630 msr = lookup_msr(map, val); 631 } else if (json_streq(map, field, "MSRValue")) { 632 msrval = val; 633 } else if (json_streq(map, field, "Errata") && 634 !json_streq(map, val, "null")) { 635 addfield(map, &extra_desc, ". ", 636 " Spec update: ", val); 637 } else if (json_streq(map, field, "Data_LA") && nz) { 638 addfield(map, &extra_desc, ". ", 639 " Supports address when precise", 640 NULL); 641 } else if (json_streq(map, field, "Unit")) { 642 const char *ppmu; 643 644 ppmu = field_to_perf(unit_to_pmu, map, val); 645 if (ppmu) { 646 je.pmu = strdup(ppmu); 647 } else { 648 if (!je.pmu) 649 je.pmu = strdup("uncore_"); 650 addfield(map, &je.pmu, "", "", val); 651 for (s = je.pmu; *s; s++) 652 *s = tolower(*s); 653 } 654 } else if (json_streq(map, field, "Filter")) { 655 addfield(map, &filter, "", "", val); 656 } else if (json_streq(map, field, "ScaleUnit")) { 657 addfield(map, &je.unit, "", "", val); 658 } else if (json_streq(map, field, "PerPkg")) { 659 addfield(map, &je.perpkg, "", "", val); 660 } else if (json_streq(map, field, "AggregationMode")) { 661 addfield(map, &je.aggr_mode, "", "", val); 662 } else if (json_streq(map, field, "Deprecated")) { 663 addfield(map, &je.deprecated, "", "", val); 664 } else if (json_streq(map, field, "MetricName")) { 665 addfield(map, &je.metric_name, "", "", val); 666 } else if (json_streq(map, field, "MetricGroup")) { 667 addfield(map, &je.metric_group, "", "", val); 668 } else if (json_streq(map, field, "MetricConstraint")) { 669 addfield(map, &je.metric_constraint, "", "", val); 670 } else if (json_streq(map, field, "MetricExpr")) { 671 addfield(map, &je.metric_expr, "", "", val); 672 } else if (json_streq(map, field, "ArchStdEvent")) { 673 addfield(map, &arch_std, "", "", val); 674 for (s = arch_std; *s; s++) 675 *s = tolower(*s); 676 } 677 /* ignore unknown fields */ 678 } 679 if (precise && je.desc && !strstr(je.desc, "(Precise Event)")) { 680 if (json_streq(map, precise, "2")) 681 addfield(map, &extra_desc, " ", 682 "(Must be precise)", NULL); 683 else 684 addfield(map, &extra_desc, " ", 685 "(Precise event)", NULL); 686 } 687 if (configcode_present) 688 snprintf(buf, sizeof buf, "config=%#llx", configcode); 689 else 690 snprintf(buf, sizeof buf, "event=%#llx", eventcode); 691 addfield(map, &event, ",", buf, NULL); 692 if (any) 693 addfield(map, &event, ",", any, NULL); 694 if (ch_mask) 695 addfield(map, &event, ",", ch_mask, NULL); 696 if (cmask) 697 addfield(map, &event, ",", cmask, NULL); 698 if (edge) 699 addfield(map, &event, ",", edge, NULL); 700 if (fc_mask) 701 addfield(map, &event, ",", fc_mask, NULL); 702 if (inv) 703 addfield(map, &event, ",", inv, NULL); 704 if (period) 705 addfield(map, &event, ",", period, NULL); 706 if (umask) 707 addfield(map, &event, ",", umask, NULL); 708 709 if (je.desc && extra_desc) 710 addfield(map, &je.desc, " ", extra_desc, NULL); 711 if (je.long_desc && extra_desc) 712 addfield(map, &je.long_desc, " ", extra_desc, NULL); 713 if (je.pmu) { 714 addfield(map, &je.desc, ". ", "Unit: ", NULL); 715 addfield(map, &je.desc, "", je.pmu, NULL); 716 addfield(map, &je.desc, "", " ", NULL); 717 } 718 if (filter) 719 addfield(map, &event, ",", filter, NULL); 720 if (msr != NULL) 721 addfield(map, &event, ",", msr->pname, msrval); 722 if (je.name) 723 fixname(je.name); 724 725 if (arch_std) { 726 /* 727 * An arch standard event is referenced, so try to 728 * fixup any unassigned values. 729 */ 730 err = try_fixup(fn, arch_std, &je, &event); 731 if (err) 732 goto free_strings; 733 } 734 je.event = real_event(je.name, event); 735 err = func(data, &je); 736 free_strings: 737 free(umask); 738 free(cmask); 739 free(inv); 740 free(any); 741 free(edge); 742 free(period); 743 free(fc_mask); 744 free(ch_mask); 745 free(event); 746 free(je.desc); 747 free(je.name); 748 free(je.compat); 749 free(je.long_desc); 750 free(extra_desc); 751 free(je.pmu); 752 free(filter); 753 free(je.perpkg); 754 free(je.aggr_mode); 755 free(je.deprecated); 756 free(je.unit); 757 free(je.metric_expr); 758 free(je.metric_name); 759 free(je.metric_group); 760 free(je.metric_constraint); 761 free(arch_std); 762 763 if (err) 764 break; 765 tok += j; 766 } 767 EXPECT(tok - tokens == len, tok, "unexpected objects at end"); 768 err = 0; 769 out_free: 770 free_json(map, size, tokens); 771 return err; 772 } 773 774 static char *file_name_to_table_name(char *fname) 775 { 776 unsigned int i; 777 int n; 778 int c; 779 char *tblname; 780 781 /* 782 * Ensure tablename starts with alphabetic character. 783 * Derive rest of table name from basename of the JSON file, 784 * replacing hyphens and stripping out .json suffix. 785 */ 786 n = asprintf(&tblname, "pme_%s", fname); 787 if (n < 0) { 788 pr_info("%s: asprintf() error %s for file %s\n", prog, 789 strerror(errno), fname); 790 return NULL; 791 } 792 793 for (i = 0; i < strlen(tblname); i++) { 794 c = tblname[i]; 795 796 if (c == '-' || c == '/') 797 tblname[i] = '_'; 798 else if (c == '.') { 799 tblname[i] = '\0'; 800 break; 801 } else if (!isalnum(c) && c != '_') { 802 pr_err("%s: Invalid character '%c' in file name '%s'\n", 803 prog, c, fname); 804 free(tblname); 805 tblname = NULL; 806 break; 807 } 808 } 809 810 return tblname; 811 } 812 813 static bool is_sys_dir(char *fname) 814 { 815 size_t len = strlen(fname), len2 = strlen("/sys"); 816 817 if (len2 > len) 818 return false; 819 return !strcmp(fname+len-len2, "/sys"); 820 } 821 822 static void print_mapping_table_prefix(FILE *outfp) 823 { 824 fprintf(outfp, "const struct pmu_events_map pmu_events_map[] = {\n"); 825 } 826 827 static void print_mapping_table_suffix(FILE *outfp) 828 { 829 /* 830 * Print the terminating, NULL entry. 831 */ 832 fprintf(outfp, "{\n"); 833 fprintf(outfp, "\t.cpuid = 0,\n"); 834 fprintf(outfp, "\t.version = 0,\n"); 835 fprintf(outfp, "\t.type = 0,\n"); 836 fprintf(outfp, "\t.table = 0,\n"); 837 fprintf(outfp, "},\n"); 838 839 /* and finally, the closing curly bracket for the struct */ 840 fprintf(outfp, "};\n"); 841 } 842 843 static void print_mapping_test_table(FILE *outfp) 844 { 845 /* 846 * Print the terminating, NULL entry. 847 */ 848 fprintf(outfp, "{\n"); 849 fprintf(outfp, "\t.cpuid = \"testcpu\",\n"); 850 fprintf(outfp, "\t.version = \"v1\",\n"); 851 fprintf(outfp, "\t.type = \"core\",\n"); 852 fprintf(outfp, "\t.table = pme_test_soc_cpu,\n"); 853 fprintf(outfp, "},\n"); 854 } 855 856 static void print_system_event_mapping_table_prefix(FILE *outfp) 857 { 858 fprintf(outfp, "\nconst struct pmu_sys_events pmu_sys_event_tables[] = {"); 859 } 860 861 static void print_system_event_mapping_table_suffix(FILE *outfp) 862 { 863 fprintf(outfp, "\n\t{\n\t\t.table = 0\n\t},"); 864 fprintf(outfp, "\n};\n"); 865 } 866 867 static int process_system_event_tables(FILE *outfp) 868 { 869 struct sys_event_table *sys_event_table; 870 871 print_system_event_mapping_table_prefix(outfp); 872 873 list_for_each_entry(sys_event_table, &sys_event_tables, list) { 874 fprintf(outfp, "\n\t{\n\t\t.table = %s,\n\t\t.name = \"%s\",\n\t},", 875 sys_event_table->soc_id, 876 sys_event_table->soc_id); 877 } 878 879 print_system_event_mapping_table_suffix(outfp); 880 881 return 0; 882 } 883 884 static int process_mapfile(FILE *outfp, char *fpath) 885 { 886 int n = 16384; 887 FILE *mapfp; 888 char *save = NULL; 889 char *line, *p; 890 int line_num; 891 char *tblname; 892 int ret = 0; 893 894 pr_info("%s: Processing mapfile %s\n", prog, fpath); 895 896 line = malloc(n); 897 if (!line) 898 return -1; 899 900 mapfp = fopen(fpath, "r"); 901 if (!mapfp) { 902 pr_info("%s: Error %s opening %s\n", prog, strerror(errno), 903 fpath); 904 free(line); 905 return -1; 906 } 907 908 print_mapping_table_prefix(outfp); 909 910 /* Skip first line (header) */ 911 p = fgets(line, n, mapfp); 912 if (!p) 913 goto out; 914 915 line_num = 1; 916 while (1) { 917 char *cpuid, *version, *type, *fname; 918 919 line_num++; 920 p = fgets(line, n, mapfp); 921 if (!p) 922 break; 923 924 if (line[0] == '#' || line[0] == '\n') 925 continue; 926 927 if (line[strlen(line)-1] != '\n') { 928 /* TODO Deal with lines longer than 16K */ 929 pr_info("%s: Mapfile %s: line %d too long, aborting\n", 930 prog, fpath, line_num); 931 ret = -1; 932 goto out; 933 } 934 line[strlen(line)-1] = '\0'; 935 936 cpuid = fixregex(strtok_r(p, ",", &save)); 937 version = strtok_r(NULL, ",", &save); 938 fname = strtok_r(NULL, ",", &save); 939 type = strtok_r(NULL, ",", &save); 940 941 tblname = file_name_to_table_name(fname); 942 fprintf(outfp, "{\n"); 943 fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid); 944 fprintf(outfp, "\t.version = \"%s\",\n", version); 945 fprintf(outfp, "\t.type = \"%s\",\n", type); 946 947 /* 948 * CHECK: We can't use the type (eg "core") field in the 949 * table name. For us to do that, we need to somehow tweak 950 * the other caller of file_name_to_table(), process_json() 951 * to determine the type. process_json() file has no way 952 * of knowing these are "core" events unless file name has 953 * core in it. If filename has core in it, we can safely 954 * ignore the type field here also. 955 */ 956 fprintf(outfp, "\t.table = %s\n", tblname); 957 fprintf(outfp, "},\n"); 958 } 959 960 out: 961 print_mapping_test_table(outfp); 962 print_mapping_table_suffix(outfp); 963 fclose(mapfp); 964 free(line); 965 return ret; 966 } 967 968 /* 969 * If we fail to locate/process JSON and map files, create a NULL mapping 970 * table. This would at least allow perf to build even if we can't find/use 971 * the aliases. 972 */ 973 static void create_empty_mapping(const char *output_file) 974 { 975 FILE *outfp; 976 977 pr_info("%s: Creating empty pmu_events_map[] table\n", prog); 978 979 /* Truncate file to clear any partial writes to it */ 980 outfp = fopen(output_file, "w"); 981 if (!outfp) { 982 perror("fopen()"); 983 _Exit(1); 984 } 985 986 fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n"); 987 print_mapping_table_prefix(outfp); 988 print_mapping_table_suffix(outfp); 989 print_system_event_mapping_table_prefix(outfp); 990 print_system_event_mapping_table_suffix(outfp); 991 fclose(outfp); 992 } 993 994 static int get_maxfds(void) 995 { 996 struct rlimit rlim; 997 998 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 999 if (rlim.rlim_max == RLIM_INFINITY) 1000 return 512; 1001 return MIN(rlim.rlim_max / 2, 512); 1002 } 1003 1004 return 512; 1005 } 1006 1007 /* 1008 * nftw() doesn't let us pass an argument to the processing function, 1009 * so use a global variables. 1010 */ 1011 static FILE *eventsfp; 1012 static char *mapfile; 1013 1014 static int is_leaf_dir(const char *fpath) 1015 { 1016 DIR *d; 1017 struct dirent *dir; 1018 int res = 1; 1019 1020 d = opendir(fpath); 1021 if (!d) 1022 return 0; 1023 1024 while ((dir = readdir(d)) != NULL) { 1025 if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) 1026 continue; 1027 1028 if (dir->d_type == DT_DIR) { 1029 res = 0; 1030 break; 1031 } else if (dir->d_type == DT_UNKNOWN) { 1032 char path[PATH_MAX]; 1033 struct stat st; 1034 1035 snprintf(path, sizeof(path), "%s/%s", fpath, dir->d_name); 1036 if (stat(path, &st)) 1037 break; 1038 1039 if (S_ISDIR(st.st_mode)) { 1040 res = 0; 1041 break; 1042 } 1043 } 1044 } 1045 1046 closedir(d); 1047 1048 return res; 1049 } 1050 1051 static int is_json_file(const char *name) 1052 { 1053 const char *suffix; 1054 1055 if (strlen(name) < 5) 1056 return 0; 1057 1058 suffix = name + strlen(name) - 5; 1059 1060 if (strncmp(suffix, ".json", 5) == 0) 1061 return 1; 1062 return 0; 1063 } 1064 1065 static int preprocess_arch_std_files(const char *fpath, const struct stat *sb, 1066 int typeflag, struct FTW *ftwbuf) 1067 { 1068 int level = ftwbuf->level; 1069 int is_file = typeflag == FTW_F; 1070 1071 if (level == 1 && is_file && is_json_file(fpath)) 1072 return json_events(fpath, save_arch_std_events, (void *)(uintptr_t)sb); 1073 1074 return 0; 1075 } 1076 1077 static int process_one_file(const char *fpath, const struct stat *sb, 1078 int typeflag, struct FTW *ftwbuf) 1079 { 1080 char *tblname, *bname; 1081 int is_dir = typeflag == FTW_D; 1082 int is_file = typeflag == FTW_F; 1083 int level = ftwbuf->level; 1084 int err = 0; 1085 1086 if (level >= 2 && is_dir) { 1087 int count = 0; 1088 /* 1089 * For level 2 directory, bname will include parent name, 1090 * like vendor/platform. So search back from platform dir 1091 * to find this. 1092 * Something similar for level 3 directory, but we're a PMU 1093 * category folder, like vendor/platform/cpu. 1094 */ 1095 bname = (char *) fpath + ftwbuf->base - 2; 1096 for (;;) { 1097 if (*bname == '/') 1098 count++; 1099 if (count == level - 1) 1100 break; 1101 bname--; 1102 } 1103 bname++; 1104 } else 1105 bname = (char *) fpath + ftwbuf->base; 1106 1107 pr_debug("%s %d %7jd %-20s %s\n", 1108 is_file ? "f" : is_dir ? "d" : "x", 1109 level, sb->st_size, bname, fpath); 1110 1111 /* base dir or too deep */ 1112 if (level == 0 || level > 4) 1113 return 0; 1114 1115 1116 /* model directory, reset topic */ 1117 if ((level == 1 && is_dir && is_leaf_dir(fpath)) || 1118 (level >= 2 && is_dir && is_leaf_dir(fpath))) { 1119 if (close_table) 1120 print_events_table_suffix(eventsfp); 1121 1122 /* 1123 * Drop file name suffix. Replace hyphens with underscores. 1124 * Fail if file name contains any alphanum characters besides 1125 * underscores. 1126 */ 1127 tblname = file_name_to_table_name(bname); 1128 if (!tblname) { 1129 pr_info("%s: Error determining table name for %s\n", prog, 1130 bname); 1131 return -1; 1132 } 1133 1134 if (is_sys_dir(bname)) { 1135 struct sys_event_table *sys_event_table; 1136 1137 sys_event_table = malloc(sizeof(*sys_event_table)); 1138 if (!sys_event_table) 1139 return -1; 1140 1141 sys_event_table->soc_id = strdup(tblname); 1142 if (!sys_event_table->soc_id) { 1143 free(sys_event_table); 1144 return -1; 1145 } 1146 list_add_tail(&sys_event_table->list, 1147 &sys_event_tables); 1148 } 1149 1150 print_events_table_prefix(eventsfp, tblname); 1151 return 0; 1152 } 1153 1154 /* 1155 * Save the mapfile name for now. We will process mapfile 1156 * after processing all JSON files (so we can write out the 1157 * mapping table after all PMU events tables). 1158 * 1159 */ 1160 if (level == 1 && is_file) { 1161 if (!strcmp(bname, "mapfile.csv")) { 1162 mapfile = strdup(fpath); 1163 return 0; 1164 } 1165 if (is_json_file(bname)) 1166 pr_debug("%s: ArchStd json is preprocessed %s\n", prog, fpath); 1167 else 1168 pr_info("%s: Ignoring file %s\n", prog, fpath); 1169 return 0; 1170 } 1171 1172 /* 1173 * If the file name does not have a .json extension, 1174 * ignore it. It could be a readme.txt for instance. 1175 */ 1176 if (is_file) { 1177 if (!is_json_file(bname)) { 1178 pr_info("%s: Ignoring file without .json suffix %s\n", prog, 1179 fpath); 1180 return 0; 1181 } 1182 } 1183 1184 if (level > 1 && add_topic(bname)) 1185 return -ENOMEM; 1186 1187 /* 1188 * Assume all other files are JSON files. 1189 * 1190 * If mapfile refers to 'power7_core.json', we create a table 1191 * named 'power7_core'. Any inconsistencies between the mapfile 1192 * and directory tree could result in build failure due to table 1193 * names not being found. 1194 * 1195 * At least for now, be strict with processing JSON file names. 1196 * i.e. if JSON file name cannot be mapped to C-style table name, 1197 * fail. 1198 */ 1199 if (is_file) { 1200 struct perf_entry_data data = { 1201 .topic = get_topic(), 1202 .outfp = eventsfp, 1203 }; 1204 1205 err = json_events(fpath, print_events_table_entry, &data); 1206 1207 free(data.topic); 1208 } 1209 1210 return err; 1211 } 1212 1213 #ifndef PATH_MAX 1214 #define PATH_MAX 4096 1215 #endif 1216 1217 /* 1218 * Starting in directory 'start_dirname', find the "mapfile.csv" and 1219 * the set of JSON files for the architecture 'arch'. 1220 * 1221 * From each JSON file, create a C-style "PMU events table" from the 1222 * JSON file (see struct pmu_event). 1223 * 1224 * From the mapfile, create a mapping between the CPU revisions and 1225 * PMU event tables (see struct pmu_events_map). 1226 * 1227 * Write out the PMU events tables and the mapping table to pmu-event.c. 1228 */ 1229 int main(int argc, char *argv[]) 1230 { 1231 int rc, ret = 0, empty_map = 0; 1232 int maxfds; 1233 char ldirname[PATH_MAX]; 1234 const char *arch; 1235 const char *output_file; 1236 const char *start_dirname; 1237 const char *err_string_ext = ""; 1238 struct stat stbuf; 1239 1240 prog = basename(argv[0]); 1241 if (argc < 4) { 1242 pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog); 1243 return 1; 1244 } 1245 1246 arch = argv[1]; 1247 start_dirname = argv[2]; 1248 output_file = argv[3]; 1249 1250 if (argc > 4) 1251 verbose = atoi(argv[4]); 1252 1253 eventsfp = fopen(output_file, "w"); 1254 if (!eventsfp) { 1255 pr_err("%s Unable to create required file %s (%s)\n", 1256 prog, output_file, strerror(errno)); 1257 return 2; 1258 } 1259 1260 snprintf(ldirname, sizeof(ldirname), "%s/%s", start_dirname, arch); 1261 1262 /* If architecture does not have any event lists, bail out */ 1263 if (stat(ldirname, &stbuf) < 0) { 1264 pr_info("%s: Arch %s has no PMU event lists\n", prog, arch); 1265 empty_map = 1; 1266 goto err_close_eventsfp; 1267 } 1268 1269 /* Include pmu-events.h first */ 1270 fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n"); 1271 1272 /* 1273 * The mapfile allows multiple CPUids to point to the same JSON file, 1274 * so, not sure if there is a need for symlinks within the pmu-events 1275 * directory. 1276 * 1277 * For now, treat symlinks of JSON files as regular files and create 1278 * separate tables for each symlink (presumably, each symlink refers 1279 * to specific version of the CPU). 1280 */ 1281 1282 maxfds = get_maxfds(); 1283 rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0); 1284 if (rc) 1285 goto err_processing_std_arch_event_dir; 1286 1287 rc = nftw(ldirname, process_one_file, maxfds, 0); 1288 if (rc) 1289 goto err_processing_dir; 1290 1291 sprintf(ldirname, "%s/test", start_dirname); 1292 1293 rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0); 1294 if (rc) 1295 goto err_processing_std_arch_event_dir; 1296 1297 rc = nftw(ldirname, process_one_file, maxfds, 0); 1298 if (rc) 1299 goto err_processing_dir; 1300 1301 if (close_table) 1302 print_events_table_suffix(eventsfp); 1303 1304 if (!mapfile) { 1305 pr_info("%s: No CPU->JSON mapping?\n", prog); 1306 empty_map = 1; 1307 goto err_close_eventsfp; 1308 } 1309 1310 rc = process_mapfile(eventsfp, mapfile); 1311 if (rc) { 1312 pr_info("%s: Error processing mapfile %s\n", prog, mapfile); 1313 /* Make build fail */ 1314 ret = 1; 1315 goto err_close_eventsfp; 1316 } 1317 1318 rc = process_system_event_tables(eventsfp); 1319 fclose(eventsfp); 1320 if (rc) { 1321 ret = 1; 1322 goto err_out; 1323 } 1324 1325 free_arch_std_events(); 1326 free_sys_event_tables(); 1327 free(mapfile); 1328 return 0; 1329 1330 err_processing_std_arch_event_dir: 1331 err_string_ext = " for std arch event"; 1332 err_processing_dir: 1333 if (verbose) { 1334 pr_info("%s: Error walking file tree %s%s\n", prog, ldirname, 1335 err_string_ext); 1336 empty_map = 1; 1337 } else if (rc < 0) { 1338 ret = 1; 1339 } else { 1340 empty_map = 1; 1341 } 1342 err_close_eventsfp: 1343 fclose(eventsfp); 1344 if (empty_map) 1345 create_empty_mapping(output_file); 1346 err_out: 1347 free_arch_std_events(); 1348 free_sys_event_tables(); 1349 free(mapfile); 1350 return ret; 1351 } 1352 1353 #include <fts.h> 1354 1355 static int 1356 fts_compare(const FTSENT * const *a, const FTSENT * const *b) 1357 { 1358 return (strcmp((*a)->fts_name, (*b)->fts_name)); 1359 } 1360 1361 static int 1362 nftw_ordered(const char *path, int (*fn)(const char *, const struct stat *, int, 1363 struct FTW *), int nfds, int ftwflags) 1364 { 1365 char * const paths[2] = { (char *)path, NULL }; 1366 struct FTW ftw; 1367 FTSENT *cur; 1368 FTS *ftsp; 1369 int error = 0, ftsflags, fnflag, postorder, sverrno; 1370 1371 /* XXX - nfds is currently unused */ 1372 if (nfds < 1) { 1373 errno = EINVAL; 1374 return (-1); 1375 } 1376 1377 ftsflags = FTS_COMFOLLOW; 1378 if (!(ftwflags & FTW_CHDIR)) 1379 ftsflags |= FTS_NOCHDIR; 1380 if (ftwflags & FTW_MOUNT) 1381 ftsflags |= FTS_XDEV; 1382 if (ftwflags & FTW_PHYS) 1383 ftsflags |= FTS_PHYSICAL; 1384 else 1385 ftsflags |= FTS_LOGICAL; 1386 postorder = (ftwflags & FTW_DEPTH) != 0; 1387 ftsp = fts_open(paths, ftsflags, fts_compare); 1388 if (ftsp == NULL) 1389 return (-1); 1390 while ((cur = fts_read(ftsp)) != NULL) { 1391 switch (cur->fts_info) { 1392 case FTS_D: 1393 if (postorder) 1394 continue; 1395 fnflag = FTW_D; 1396 break; 1397 case FTS_DC: 1398 continue; 1399 case FTS_DNR: 1400 fnflag = FTW_DNR; 1401 break; 1402 case FTS_DP: 1403 if (!postorder) 1404 continue; 1405 fnflag = FTW_DP; 1406 break; 1407 case FTS_F: 1408 case FTS_DEFAULT: 1409 fnflag = FTW_F; 1410 break; 1411 case FTS_NS: 1412 case FTS_NSOK: 1413 fnflag = FTW_NS; 1414 break; 1415 case FTS_SL: 1416 fnflag = FTW_SL; 1417 break; 1418 case FTS_SLNONE: 1419 fnflag = FTW_SLN; 1420 break; 1421 default: 1422 error = -1; 1423 goto done; 1424 } 1425 ftw.base = cur->fts_pathlen - cur->fts_namelen; 1426 ftw.level = cur->fts_level; 1427 error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); 1428 if (error != 0) 1429 break; 1430 } 1431 done: 1432 sverrno = errno; 1433 if (fts_close(ftsp) != 0 && error == 0) 1434 error = -1; 1435 else 1436 errno = sverrno; 1437 return (error); 1438 } 1439