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