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