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