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 free(line); 825 fclose(mapfp); 826 return -1; 827 } 828 line[strlen(line)-1] = '\0'; 829 830 cpuid = fixregex(strtok_r(p, ",", &save)); 831 version = strtok_r(NULL, ",", &save); 832 fname = strtok_r(NULL, ",", &save); 833 type = strtok_r(NULL, ",", &save); 834 835 tblname = file_name_to_table_name(fname); 836 fprintf(outfp, "{\n"); 837 fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid); 838 fprintf(outfp, "\t.version = \"%s\",\n", version); 839 fprintf(outfp, "\t.type = \"%s\",\n", type); 840 841 /* 842 * CHECK: We can't use the type (eg "core") field in the 843 * table name. For us to do that, we need to somehow tweak 844 * the other caller of file_name_to_table(), process_json() 845 * to determine the type. process_json() file has no way 846 * of knowing these are "core" events unless file name has 847 * core in it. If filename has core in it, we can safely 848 * ignore the type field here also. 849 */ 850 fprintf(outfp, "\t.table = %s\n", tblname); 851 fprintf(outfp, "},\n"); 852 } 853 854 out: 855 print_mapping_table_suffix(outfp); 856 free(line); 857 fclose(mapfp); 858 return 0; 859 } 860 861 /* 862 * If we fail to locate/process JSON and map files, create a NULL mapping 863 * table. This would at least allow perf to build even if we can't find/use 864 * the aliases. 865 */ 866 static void 867 create_empty_mapping(const char *output_file) 868 { 869 FILE *outfp; 870 871 pr_info("%s: Creating empty pmu_events_map[] table\n", prog); 872 873 /* Truncate file to clear any partial writes to it */ 874 outfp = fopen(output_file, "w"); 875 if (!outfp) { 876 perror("fopen()"); 877 _Exit(1); 878 } 879 880 fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n"); 881 print_mapping_table_prefix(outfp); 882 print_mapping_table_suffix(outfp); 883 fclose(outfp); 884 } 885 886 static int 887 get_maxfds(void) 888 { 889 struct rlimit rlim; 890 891 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 892 if (rlim.rlim_max == RLIM_INFINITY) 893 return 512; 894 return MIN(rlim.rlim_max / 2, 512); 895 } 896 897 return 512; 898 } 899 900 /* 901 * nftw() doesn't let us pass an argument to the processing function, 902 * so use a global variables. 903 */ 904 static FILE *eventsfp; 905 static char *mapfile; 906 907 static int 908 is_leaf_dir(const char *fpath) 909 { 910 DIR *d; 911 struct dirent *dir; 912 int res = 1; 913 914 d = opendir(fpath); 915 if (!d) 916 return 0; 917 918 while ((dir = readdir(d)) != NULL) { 919 if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) 920 continue; 921 922 if (dir->d_type == DT_DIR) { 923 res = 0; 924 break; 925 } else if (dir->d_type == DT_UNKNOWN) { 926 char path[PATH_MAX]; 927 struct stat st; 928 929 snprintf(path, sizeof(path), "%s/%s", fpath, 930 dir->d_name); 931 if (stat(path, &st)) 932 break; 933 934 if (S_ISDIR(st.st_mode)) { 935 res = 0; 936 break; 937 } 938 } 939 } 940 941 closedir(d); 942 943 return res; 944 } 945 946 static int 947 is_json_file(const char *name) 948 { 949 const char *suffix; 950 951 if (strlen(name) < 5) 952 return 0; 953 954 suffix = name + strlen(name) - 5; 955 956 if (strncmp(suffix, ".json", 5) == 0) 957 return 1; 958 return 0; 959 } 960 961 static int 962 preprocess_arch_std_files(const char *fpath, const struct stat *sb, 963 int typeflag, struct FTW *ftwbuf) 964 { 965 int level = ftwbuf->level; 966 int is_file = typeflag == FTW_F; 967 968 if (level == 1 && is_file && is_json_file(fpath)) 969 return json_events(fpath, save_arch_std_events, (void *)(uintptr_t)sb); 970 971 return 0; 972 } 973 974 static int 975 process_one_file(const char *fpath, const struct stat *sb, int typeflag, 976 struct FTW *ftwbuf) 977 { 978 char *tblname; 979 const char *bname; 980 int is_dir = typeflag == FTW_D; 981 int is_file = typeflag == FTW_F; 982 int level = ftwbuf->level; 983 int err = 0; 984 985 if (level == 2 && is_dir) { 986 /* 987 * For level 2 directory, bname will include parent name, 988 * like vendor/platform. So search back from platform dir 989 * to find this. 990 */ 991 bname = fpath + ftwbuf->base - 2; 992 for (;;) { 993 if (*bname == '/') 994 break; 995 bname--; 996 } 997 bname++; 998 } else 999 bname = fpath + ftwbuf->base; 1000 1001 pr_debug("%s %d %7jd %-20s %s\n", 1002 is_file ? "f" : is_dir ? "d" : "x", 1003 level, sb->st_size, bname, fpath); 1004 1005 /* base dir or too deep */ 1006 if (level == 0 || level > 3) 1007 return 0; 1008 1009 1010 /* model directory, reset topic */ 1011 if ((level == 1 && is_dir && is_leaf_dir(fpath)) || 1012 (level == 2 && is_dir)) { 1013 if (close_table) 1014 print_events_table_suffix(eventsfp); 1015 1016 /* 1017 * Drop file name suffix. Replace hyphens with underscores. 1018 * Fail if file name contains any alphanum characters besides 1019 * underscores. 1020 */ 1021 tblname = file_name_to_table_name(bname); 1022 if (!tblname) { 1023 pr_info("%s: Error determining table name for %s\n", prog, 1024 bname); 1025 return -1; 1026 } 1027 1028 print_events_table_prefix(eventsfp, tblname); 1029 return 0; 1030 } 1031 1032 /* 1033 * Save the mapfile name for now. We will process mapfile 1034 * after processing all JSON files (so we can write out the 1035 * mapping table after all PMU events tables). 1036 * 1037 */ 1038 if (level == 1 && is_file) { 1039 if (!strcmp(bname, "mapfile.csv")) { 1040 mapfile = strdup(fpath); 1041 return 0; 1042 } 1043 1044 pr_info("%s: Ignoring file %s\n", prog, fpath); 1045 return 0; 1046 } 1047 1048 /* 1049 * If the file name does not have a .json extension, 1050 * ignore it. It could be a readme.txt for instance. 1051 */ 1052 if (is_file) { 1053 if (!is_json_file(bname)) { 1054 pr_info("%s: Ignoring file without .json suffix %s\n", prog, 1055 fpath); 1056 return 0; 1057 } 1058 } 1059 1060 if (level > 1 && add_topic(bname)) 1061 return -ENOMEM; 1062 1063 /* 1064 * Assume all other files are JSON files. 1065 * 1066 * If mapfile refers to 'power7_core.json', we create a table 1067 * named 'power7_core'. Any inconsistencies between the mapfile 1068 * and directory tree could result in build failure due to table 1069 * names not being found. 1070 * 1071 * Atleast for now, be strict with processing JSON file names. 1072 * i.e. if JSON file name cannot be mapped to C-style table name, 1073 * fail. 1074 */ 1075 if (is_file) { 1076 struct perf_entry_data data = { 1077 .topic = get_topic(), 1078 .outfp = eventsfp, 1079 }; 1080 1081 err = json_events(fpath, print_events_table_entry, &data); 1082 1083 free(data.topic); 1084 } 1085 1086 return err; 1087 } 1088 1089 /* 1090 * Starting in directory 'start_dirname', find the "mapfile.csv" and 1091 * the set of JSON files for the architecture 'arch'. 1092 * 1093 * From each JSON file, create a C-style "PMU events table" from the 1094 * JSON file (see struct pmu_event). 1095 * 1096 * From the mapfile, create a mapping between the CPU revisions and 1097 * PMU event tables (see struct pmu_events_map). 1098 * 1099 * Write out the PMU events tables and the mapping table to pmu-event.c. 1100 */ 1101 int 1102 main(int argc, char *argv[]) 1103 { 1104 int rc; 1105 int maxfds; 1106 char ldirname[PATH_MAX]; 1107 1108 const char *arch; 1109 const char *output_file; 1110 const char *start_dirname; 1111 struct stat stbuf; 1112 1113 prog = basename(argv[0]); 1114 if (argc < 4) { 1115 pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog); 1116 return 1; 1117 } 1118 1119 arch = argv[1]; 1120 start_dirname = argv[2]; 1121 output_file = argv[3]; 1122 1123 if (argc > 4) 1124 verbose = atoi(argv[4]); 1125 1126 eventsfp = fopen(output_file, "w"); 1127 if (!eventsfp) { 1128 pr_err("%s Unable to create required file %s (%s)\n", 1129 prog, output_file, strerror(errno)); 1130 return 2; 1131 } 1132 1133 snprintf(ldirname, sizeof(ldirname), "%s/%s", start_dirname, arch); 1134 1135 /* If architecture does not have any event lists, bail out */ 1136 if (stat(ldirname, &stbuf) < 0) { 1137 pr_info("%s: Arch %s has no PMU event lists\n", prog, arch); 1138 goto empty_map; 1139 } 1140 1141 /* Include pmu-events.h first */ 1142 fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n"); 1143 1144 /* 1145 * The mapfile allows multiple CPUids to point to the same JSON file, 1146 * so, not sure if there is a need for symlinks within the pmu-events 1147 * directory. 1148 * 1149 * For now, treat symlinks of JSON files as regular files and create 1150 * separate tables for each symlink (presumably, each symlink refers 1151 * to specific version of the CPU). 1152 */ 1153 1154 maxfds = get_maxfds(); 1155 mapfile = NULL; 1156 rc = nftw_ordered(ldirname, preprocess_arch_std_files, maxfds, 0); 1157 if (rc && verbose) { 1158 pr_info("%s: Error preprocessing arch standard files %s: %s\n", 1159 prog, ldirname, strerror(errno)); 1160 goto empty_map; 1161 } else if (rc < 0) { 1162 /* Make build fail */ 1163 free_arch_std_events(); 1164 return 1; 1165 } else if (rc) { 1166 goto empty_map; 1167 } 1168 1169 rc = nftw_ordered(ldirname, process_one_file, maxfds, 0); 1170 if (rc && verbose) { 1171 pr_info("%s: Error walking file tree %s\n", prog, ldirname); 1172 goto empty_map; 1173 } else if (rc < 0) { 1174 /* Make build fail */ 1175 free_arch_std_events(); 1176 return 1; 1177 } else if (rc) { 1178 goto empty_map; 1179 } 1180 1181 if (close_table) 1182 print_events_table_suffix(eventsfp); 1183 1184 if (!mapfile) { 1185 pr_info("%s: No CPU->JSON mapping?\n", prog); 1186 goto empty_map; 1187 } 1188 1189 if (process_mapfile(eventsfp, mapfile)) { 1190 pr_info("%s: Error processing mapfile %s\n", prog, mapfile); 1191 /* Make build fail */ 1192 return 1; 1193 } 1194 1195 return 0; 1196 1197 empty_map: 1198 fclose(eventsfp); 1199 create_empty_mapping(output_file); 1200 free_arch_std_events(); 1201 return 0; 1202 } 1203 1204 static int 1205 fts_compare(const FTSENT * const *a, const FTSENT * const *b) 1206 { 1207 return (strcmp((*a)->fts_name, (*b)->fts_name)); 1208 } 1209 1210 static int 1211 nftw_ordered(const char *path, int (*fn)(const char *, const struct stat *, int, 1212 struct FTW *), int nfds, int ftwflags) 1213 { 1214 char * const paths[2] = { (char *)path, NULL }; 1215 struct FTW ftw; 1216 FTSENT *cur; 1217 FTS *ftsp; 1218 int error = 0, ftsflags, fnflag, postorder, sverrno; 1219 1220 /* XXX - nfds is currently unused */ 1221 if (nfds < 1) { 1222 errno = EINVAL; 1223 return (-1); 1224 } 1225 1226 ftsflags = FTS_COMFOLLOW; 1227 if (!(ftwflags & FTW_CHDIR)) 1228 ftsflags |= FTS_NOCHDIR; 1229 if (ftwflags & FTW_MOUNT) 1230 ftsflags |= FTS_XDEV; 1231 if (ftwflags & FTW_PHYS) 1232 ftsflags |= FTS_PHYSICAL; 1233 else 1234 ftsflags |= FTS_LOGICAL; 1235 postorder = (ftwflags & FTW_DEPTH) != 0; 1236 ftsp = fts_open(paths, ftsflags, fts_compare); 1237 if (ftsp == NULL) 1238 return (-1); 1239 while ((cur = fts_read(ftsp)) != NULL) { 1240 switch (cur->fts_info) { 1241 case FTS_D: 1242 if (postorder) 1243 continue; 1244 fnflag = FTW_D; 1245 break; 1246 case FTS_DC: 1247 continue; 1248 case FTS_DNR: 1249 fnflag = FTW_DNR; 1250 break; 1251 case FTS_DP: 1252 if (!postorder) 1253 continue; 1254 fnflag = FTW_DP; 1255 break; 1256 case FTS_F: 1257 case FTS_DEFAULT: 1258 fnflag = FTW_F; 1259 break; 1260 case FTS_NS: 1261 case FTS_NSOK: 1262 fnflag = FTW_NS; 1263 break; 1264 case FTS_SL: 1265 fnflag = FTW_SL; 1266 break; 1267 case FTS_SLNONE: 1268 fnflag = FTW_SLN; 1269 break; 1270 default: 1271 error = -1; 1272 goto done; 1273 } 1274 ftw.base = cur->fts_pathlen - cur->fts_namelen; 1275 ftw.level = cur->fts_level; 1276 error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); 1277 if (error != 0) 1278 break; 1279 } 1280 done: 1281 sverrno = errno; 1282 if (fts_close(ftsp) != 0 && error == 0) 1283 error = -1; 1284 else 1285 errno = sverrno; 1286 return (error); 1287 } 1288