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