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