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