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        { "cpu_core", "cpu_core" },
 289        { "cpu_atom", "cpu_atom" },
 290        {}
 291};
 292
 293static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val)
 294{
 295        int i;
 296
 297        for (i = 0; table[i].json; i++) {
 298                if (json_streq(map, val, table[i].json))
 299                        return table[i].perf;
 300        }
 301        return NULL;
 302}
 303
 304#define EXPECT(e, t, m) do { if (!(e)) {                        \
 305        jsmntok_t *loc = (t);                                   \
 306        if (!(t)->start && (t) > tokens)                        \
 307                loc = (t) - 1;                                  \
 308        pr_err("%s:%d: " m ", got %s\n", fn,                    \
 309               json_line(map, loc),                             \
 310               json_name(t));                                   \
 311        err = -EIO;                                             \
 312        goto out_free;                                          \
 313} } while (0)
 314
 315static char *topic;
 316
 317static char *get_topic(void)
 318{
 319        char *tp;
 320        int i;
 321
 322        /* tp is free'd in process_one_file() */
 323        i = asprintf(&tp, "%s", topic);
 324        if (i < 0) {
 325                pr_info("%s: asprintf() error %s\n", prog);
 326                return NULL;
 327        }
 328
 329        for (i = 0; i < (int) strlen(tp); i++) {
 330                char c = tp[i];
 331
 332                if (c == '-')
 333                        tp[i] = ' ';
 334                else if (c == '.') {
 335                        tp[i] = '\0';
 336                        break;
 337                }
 338        }
 339
 340        return tp;
 341}
 342
 343static int add_topic(char *bname)
 344{
 345        free(topic);
 346        topic = strdup(bname);
 347        if (!topic) {
 348                pr_info("%s: strdup() error %s for file %s\n", prog,
 349                                strerror(errno), bname);
 350                return -ENOMEM;
 351        }
 352        return 0;
 353}
 354
 355struct perf_entry_data {
 356        FILE *outfp;
 357        char *topic;
 358};
 359
 360static int close_table;
 361
 362static void print_events_table_prefix(FILE *fp, const char *tblname)
 363{
 364        fprintf(fp, "struct pmu_event %s[] = {\n", tblname);
 365        close_table = 1;
 366}
 367
 368static int print_events_table_entry(void *data, struct json_event *je)
 369{
 370        struct perf_entry_data *pd = data;
 371        FILE *outfp = pd->outfp;
 372        char *topic = pd->topic;
 373
 374        /*
 375         * TODO: Remove formatting chars after debugging to reduce
 376         *       string lengths.
 377         */
 378        fprintf(outfp, "{\n");
 379
 380        if (je->name)
 381                fprintf(outfp, "\t.name = \"%s\",\n", je->name);
 382        if (je->event)
 383                fprintf(outfp, "\t.event = \"%s\",\n", je->event);
 384        fprintf(outfp, "\t.desc = \"%s\",\n", je->desc);
 385        if (je->compat)
 386                fprintf(outfp, "\t.compat = \"%s\",\n", je->compat);
 387        fprintf(outfp, "\t.topic = \"%s\",\n", topic);
 388        if (je->long_desc && je->long_desc[0])
 389                fprintf(outfp, "\t.long_desc = \"%s\",\n", je->long_desc);
 390        if (je->pmu)
 391                fprintf(outfp, "\t.pmu = \"%s\",\n", je->pmu);
 392        if (je->unit)
 393                fprintf(outfp, "\t.unit = \"%s\",\n", je->unit);
 394        if (je->perpkg)
 395                fprintf(outfp, "\t.perpkg = \"%s\",\n", je->perpkg);
 396        if (je->aggr_mode)
 397                fprintf(outfp, "\t.aggr_mode = \"%d\",\n", convert(je->aggr_mode));
 398        if (je->metric_expr)
 399                fprintf(outfp, "\t.metric_expr = \"%s\",\n", je->metric_expr);
 400        if (je->metric_name)
 401                fprintf(outfp, "\t.metric_name = \"%s\",\n", je->metric_name);
 402        if (je->metric_group)
 403                fprintf(outfp, "\t.metric_group = \"%s\",\n", je->metric_group);
 404        if (je->deprecated)
 405                fprintf(outfp, "\t.deprecated = \"%s\",\n", je->deprecated);
 406        if (je->metric_constraint)
 407                fprintf(outfp, "\t.metric_constraint = \"%s\",\n", je->metric_constraint);
 408        fprintf(outfp, "},\n");
 409
 410        return 0;
 411}
 412
 413struct event_struct {
 414        struct list_head list;
 415        char *name;
 416        char *event;
 417        char *compat;
 418        char *desc;
 419        char *long_desc;
 420        char *pmu;
 421        char *unit;
 422        char *perpkg;
 423        char *aggr_mode;
 424        char *metric_expr;
 425        char *metric_name;
 426        char *metric_group;
 427        char *deprecated;
 428        char *metric_constraint;
 429};
 430
 431#define ADD_EVENT_FIELD(field) do { if (je->field) {            \
 432        es->field = strdup(je->field);                          \
 433        if (!es->field)                                         \
 434                goto out_free;                                  \
 435} } while (0)
 436
 437#define FREE_EVENT_FIELD(field) free(es->field)
 438
 439#define TRY_FIXUP_FIELD(field) do { if (es->field && !je->field) {\
 440        je->field = strdup(es->field);                          \
 441        if (!je->field)                                         \
 442                return -ENOMEM;                                 \
 443} } while (0)
 444
 445#define FOR_ALL_EVENT_STRUCT_FIELDS(op) do {                    \
 446        op(name);                                               \
 447        op(event);                                              \
 448        op(desc);                                               \
 449        op(long_desc);                                          \
 450        op(pmu);                                                \
 451        op(unit);                                               \
 452        op(perpkg);                                             \
 453        op(aggr_mode);                                          \
 454        op(metric_expr);                                        \
 455        op(metric_name);                                        \
 456        op(metric_group);                                       \
 457        op(deprecated);                                         \
 458} while (0)
 459
 460static LIST_HEAD(arch_std_events);
 461
 462static void free_arch_std_events(void)
 463{
 464        struct event_struct *es, *next;
 465
 466        list_for_each_entry_safe(es, next, &arch_std_events, list) {
 467                FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
 468                list_del_init(&es->list);
 469                free(es);
 470        }
 471}
 472
 473static int save_arch_std_events(void *data, struct json_event *je)
 474{
 475        struct event_struct *es;
 476
 477        es = malloc(sizeof(*es));
 478        if (!es)
 479                return -ENOMEM;
 480        memset(es, 0, sizeof(*es));
 481        FOR_ALL_EVENT_STRUCT_FIELDS(ADD_EVENT_FIELD);
 482        list_add_tail(&es->list, &arch_std_events);
 483        return 0;
 484out_free:
 485        FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
 486        free(es);
 487        return -ENOMEM;
 488}
 489
 490static void print_events_table_suffix(FILE *outfp)
 491{
 492        fprintf(outfp, "{\n");
 493
 494        fprintf(outfp, "\t.name = 0,\n");
 495        fprintf(outfp, "\t.event = 0,\n");
 496        fprintf(outfp, "\t.desc = 0,\n");
 497
 498        fprintf(outfp, "},\n");
 499        fprintf(outfp, "};\n");
 500        close_table = 0;
 501}
 502
 503static struct fixed {
 504        const char *name;
 505        const char *event;
 506} fixed[] = {
 507        { "inst_retired.any", "event=0xc0,period=2000003" },
 508        { "inst_retired.any_p", "event=0xc0,period=2000003" },
 509        { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03,period=2000003" },
 510        { "cpu_clk_unhalted.thread", "event=0x3c,period=2000003" },
 511        { "cpu_clk_unhalted.core", "event=0x3c,period=2000003" },
 512        { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1,period=2000003" },
 513        { NULL, NULL},
 514};
 515
 516/*
 517 * Handle different fixed counter encodings between JSON and perf.
 518 */
 519static 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
 532static int
 533try_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 */
 552static 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                struct msrmap *msr = NULL;
 579                jsmntok_t *msrval = NULL;
 580                jsmntok_t *precise = NULL;
 581                jsmntok_t *obj = tok++;
 582
 583                EXPECT(obj->type == JSMN_OBJECT, obj, "expected object");
 584                for (j = 0; j < obj->size; j += 2) {
 585                        jsmntok_t *field, *val;
 586                        int nz;
 587                        char *s;
 588
 589                        field = tok + j;
 590                        EXPECT(field->type == JSMN_STRING, tok + j,
 591                               "Expected field name");
 592                        val = tok + j + 1;
 593                        EXPECT(val->type == JSMN_STRING, tok + j + 1,
 594                               "Expected string value");
 595
 596                        nz = !json_streq(map, val, "0");
 597                        if (match_field(map, field, nz, &event, val)) {
 598                                /* ok */
 599                        } else if (json_streq(map, field, "EventCode")) {
 600                                char *code = NULL;
 601                                addfield(map, &code, "", "", val);
 602                                eventcode |= strtoul(code, NULL, 0);
 603                                free(code);
 604                        } else if (json_streq(map, field, "ExtSel")) {
 605                                char *code = NULL;
 606                                addfield(map, &code, "", "", val);
 607                                eventcode |= strtoul(code, NULL, 0) << 21;
 608                                free(code);
 609                        } else if (json_streq(map, field, "EventName")) {
 610                                addfield(map, &je.name, "", "", val);
 611                        } else if (json_streq(map, field, "Compat")) {
 612                                addfield(map, &je.compat, "", "", val);
 613                        } else if (json_streq(map, field, "BriefDescription")) {
 614                                addfield(map, &je.desc, "", "", val);
 615                                fixdesc(je.desc);
 616                        } else if (json_streq(map, field,
 617                                             "PublicDescription")) {
 618                                addfield(map, &je.long_desc, "", "", val);
 619                                fixdesc(je.long_desc);
 620                        } else if (json_streq(map, field, "PEBS") && nz) {
 621                                precise = val;
 622                        } else if (json_streq(map, field, "MSRIndex") && nz) {
 623                                msr = lookup_msr(map, val);
 624                        } else if (json_streq(map, field, "MSRValue")) {
 625                                msrval = val;
 626                        } else if (json_streq(map, field, "Errata") &&
 627                                   !json_streq(map, val, "null")) {
 628                                addfield(map, &extra_desc, ". ",
 629                                        " Spec update: ", val);
 630                        } else if (json_streq(map, field, "Data_LA") && nz) {
 631                                addfield(map, &extra_desc, ". ",
 632                                        " Supports address when precise",
 633                                        NULL);
 634                        } else if (json_streq(map, field, "Unit")) {
 635                                const char *ppmu;
 636
 637                                ppmu = field_to_perf(unit_to_pmu, map, val);
 638                                if (ppmu) {
 639                                        je.pmu = strdup(ppmu);
 640                                } else {
 641                                        if (!je.pmu)
 642                                                je.pmu = strdup("uncore_");
 643                                        addfield(map, &je.pmu, "", "", val);
 644                                        for (s = je.pmu; *s; s++)
 645                                                *s = tolower(*s);
 646                                }
 647                                addfield(map, &je.desc, ". ", "Unit: ", NULL);
 648                                addfield(map, &je.desc, "", je.pmu, NULL);
 649                                addfield(map, &je.desc, "", " ", NULL);
 650                        } else if (json_streq(map, field, "Filter")) {
 651                                addfield(map, &filter, "", "", val);
 652                        } else if (json_streq(map, field, "ScaleUnit")) {
 653                                addfield(map, &je.unit, "", "", val);
 654                        } else if (json_streq(map, field, "PerPkg")) {
 655                                addfield(map, &je.perpkg, "", "", val);
 656                        } else if (json_streq(map, field, "AggregationMode")) {
 657                                addfield(map, &je.aggr_mode, "", "", val);
 658                        } else if (json_streq(map, field, "Deprecated")) {
 659                                addfield(map, &je.deprecated, "", "", val);
 660                        } else if (json_streq(map, field, "MetricName")) {
 661                                addfield(map, &je.metric_name, "", "", val);
 662                        } else if (json_streq(map, field, "MetricGroup")) {
 663                                addfield(map, &je.metric_group, "", "", val);
 664                        } else if (json_streq(map, field, "MetricConstraint")) {
 665                                addfield(map, &je.metric_constraint, "", "", val);
 666                        } else if (json_streq(map, field, "MetricExpr")) {
 667                                addfield(map, &je.metric_expr, "", "", val);
 668                                for (s = je.metric_expr; *s; s++)
 669                                        *s = tolower(*s);
 670                        } else if (json_streq(map, field, "ArchStdEvent")) {
 671                                addfield(map, &arch_std, "", "", val);
 672                                for (s = arch_std; *s; s++)
 673                                        *s = tolower(*s);
 674                        }
 675                        /* ignore unknown fields */
 676                }
 677                if (precise && je.desc && !strstr(je.desc, "(Precise Event)")) {
 678                        if (json_streq(map, precise, "2"))
 679                                addfield(map, &extra_desc, " ",
 680                                                "(Must be precise)", NULL);
 681                        else
 682                                addfield(map, &extra_desc, " ",
 683                                                "(Precise event)", NULL);
 684                }
 685                snprintf(buf, sizeof buf, "event=%#llx", eventcode);
 686                addfield(map, &event, ",", buf, NULL);
 687                if (je.desc && extra_desc)
 688                        addfield(map, &je.desc, " ", extra_desc, NULL);
 689                if (je.long_desc && extra_desc)
 690                        addfield(map, &je.long_desc, " ", extra_desc, NULL);
 691                if (filter)
 692                        addfield(map, &event, ",", filter, NULL);
 693                if (msr != NULL)
 694                        addfield(map, &event, ",", msr->pname, msrval);
 695                if (je.name)
 696                        fixname(je.name);
 697
 698                if (arch_std) {
 699                        /*
 700                         * An arch standard event is referenced, so try to
 701                         * fixup any unassigned values.
 702                         */
 703                        err = try_fixup(fn, arch_std, &je, &event);
 704                        if (err)
 705                                goto free_strings;
 706                }
 707                je.event = real_event(je.name, event);
 708                err = func(data, &je);
 709free_strings:
 710                free(event);
 711                free(je.desc);
 712                free(je.name);
 713                free(je.compat);
 714                free(je.long_desc);
 715                free(extra_desc);
 716                free(je.pmu);
 717                free(filter);
 718                free(je.perpkg);
 719                free(je.aggr_mode);
 720                free(je.deprecated);
 721                free(je.unit);
 722                free(je.metric_expr);
 723                free(je.metric_name);
 724                free(je.metric_group);
 725                free(je.metric_constraint);
 726                free(arch_std);
 727
 728                if (err)
 729                        break;
 730                tok += j;
 731        }
 732        EXPECT(tok - tokens == len, tok, "unexpected objects at end");
 733        err = 0;
 734out_free:
 735        free_json(map, size, tokens);
 736        return err;
 737}
 738
 739static char *file_name_to_table_name(char *fname)
 740{
 741        unsigned int i;
 742        int n;
 743        int c;
 744        char *tblname;
 745
 746        /*
 747         * Ensure tablename starts with alphabetic character.
 748         * Derive rest of table name from basename of the JSON file,
 749         * replacing hyphens and stripping out .json suffix.
 750         */
 751        n = asprintf(&tblname, "pme_%s", fname);
 752        if (n < 0) {
 753                pr_info("%s: asprintf() error %s for file %s\n", prog,
 754                                strerror(errno), fname);
 755                return NULL;
 756        }
 757
 758        for (i = 0; i < strlen(tblname); i++) {
 759                c = tblname[i];
 760
 761                if (c == '-' || c == '/')
 762                        tblname[i] = '_';
 763                else if (c == '.') {
 764                        tblname[i] = '\0';
 765                        break;
 766                } else if (!isalnum(c) && c != '_') {
 767                        pr_err("%s: Invalid character '%c' in file name %s\n",
 768                                        prog, c, basename(fname));
 769                        free(tblname);
 770                        tblname = NULL;
 771                        break;
 772                }
 773        }
 774
 775        return tblname;
 776}
 777
 778static bool is_sys_dir(char *fname)
 779{
 780        size_t len = strlen(fname), len2 = strlen("/sys");
 781
 782        if (len2 > len)
 783                return false;
 784        return !strcmp(fname+len-len2, "/sys");
 785}
 786
 787static void print_mapping_table_prefix(FILE *outfp)
 788{
 789        fprintf(outfp, "struct pmu_events_map pmu_events_map[] = {\n");
 790}
 791
 792static void print_mapping_table_suffix(FILE *outfp)
 793{
 794        /*
 795         * Print the terminating, NULL entry.
 796         */
 797        fprintf(outfp, "{\n");
 798        fprintf(outfp, "\t.cpuid = 0,\n");
 799        fprintf(outfp, "\t.version = 0,\n");
 800        fprintf(outfp, "\t.type = 0,\n");
 801        fprintf(outfp, "\t.table = 0,\n");
 802        fprintf(outfp, "},\n");
 803
 804        /* and finally, the closing curly bracket for the struct */
 805        fprintf(outfp, "};\n");
 806}
 807
 808static void print_mapping_test_table(FILE *outfp)
 809{
 810        /*
 811         * Print the terminating, NULL entry.
 812         */
 813        fprintf(outfp, "{\n");
 814        fprintf(outfp, "\t.cpuid = \"testcpu\",\n");
 815        fprintf(outfp, "\t.version = \"v1\",\n");
 816        fprintf(outfp, "\t.type = \"core\",\n");
 817        fprintf(outfp, "\t.table = pme_test_cpu,\n");
 818        fprintf(outfp, "},\n");
 819}
 820
 821static void print_system_event_mapping_table_prefix(FILE *outfp)
 822{
 823        fprintf(outfp, "\nstruct pmu_sys_events pmu_sys_event_tables[] = {");
 824}
 825
 826static void print_system_event_mapping_table_suffix(FILE *outfp)
 827{
 828        fprintf(outfp, "\n\t{\n\t\t.table = 0\n\t},");
 829        fprintf(outfp, "\n};\n");
 830}
 831
 832static int process_system_event_tables(FILE *outfp)
 833{
 834        struct sys_event_table *sys_event_table;
 835
 836        print_system_event_mapping_table_prefix(outfp);
 837
 838        list_for_each_entry(sys_event_table, &sys_event_tables, list) {
 839                fprintf(outfp, "\n\t{\n\t\t.table = %s,\n\t},",
 840                        sys_event_table->soc_id);
 841        }
 842
 843        print_system_event_mapping_table_suffix(outfp);
 844
 845        return 0;
 846}
 847
 848static int process_mapfile(FILE *outfp, char *fpath)
 849{
 850        int n = 16384;
 851        FILE *mapfp;
 852        char *save = NULL;
 853        char *line, *p;
 854        int line_num;
 855        char *tblname;
 856        int ret = 0;
 857
 858        pr_info("%s: Processing mapfile %s\n", prog, fpath);
 859
 860        line = malloc(n);
 861        if (!line)
 862                return -1;
 863
 864        mapfp = fopen(fpath, "r");
 865        if (!mapfp) {
 866                pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
 867                                fpath);
 868                free(line);
 869                return -1;
 870        }
 871
 872        print_mapping_table_prefix(outfp);
 873
 874        /* Skip first line (header) */
 875        p = fgets(line, n, mapfp);
 876        if (!p)
 877                goto out;
 878
 879        line_num = 1;
 880        while (1) {
 881                char *cpuid, *version, *type, *fname;
 882
 883                line_num++;
 884                p = fgets(line, n, mapfp);
 885                if (!p)
 886                        break;
 887
 888                if (line[0] == '#' || line[0] == '\n')
 889                        continue;
 890
 891                if (line[strlen(line)-1] != '\n') {
 892                        /* TODO Deal with lines longer than 16K */
 893                        pr_info("%s: Mapfile %s: line %d too long, aborting\n",
 894                                        prog, fpath, line_num);
 895                        ret = -1;
 896                        goto out;
 897                }
 898                line[strlen(line)-1] = '\0';
 899
 900                cpuid = fixregex(strtok_r(p, ",", &save));
 901                version = strtok_r(NULL, ",", &save);
 902                fname = strtok_r(NULL, ",", &save);
 903                type = strtok_r(NULL, ",", &save);
 904
 905                tblname = file_name_to_table_name(fname);
 906                fprintf(outfp, "{\n");
 907                fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid);
 908                fprintf(outfp, "\t.version = \"%s\",\n", version);
 909                fprintf(outfp, "\t.type = \"%s\",\n", type);
 910
 911                /*
 912                 * CHECK: We can't use the type (eg "core") field in the
 913                 * table name. For us to do that, we need to somehow tweak
 914                 * the other caller of file_name_to_table(), process_json()
 915                 * to determine the type. process_json() file has no way
 916                 * of knowing these are "core" events unless file name has
 917                 * core in it. If filename has core in it, we can safely
 918                 * ignore the type field here also.
 919                 */
 920                fprintf(outfp, "\t.table = %s\n", tblname);
 921                fprintf(outfp, "},\n");
 922        }
 923
 924out:
 925        print_mapping_test_table(outfp);
 926        print_mapping_table_suffix(outfp);
 927        fclose(mapfp);
 928        free(line);
 929        return ret;
 930}
 931
 932/*
 933 * If we fail to locate/process JSON and map files, create a NULL mapping
 934 * table. This would at least allow perf to build even if we can't find/use
 935 * the aliases.
 936 */
 937static void create_empty_mapping(const char *output_file)
 938{
 939        FILE *outfp;
 940
 941        pr_info("%s: Creating empty pmu_events_map[] table\n", prog);
 942
 943        /* Truncate file to clear any partial writes to it */
 944        outfp = fopen(output_file, "w");
 945        if (!outfp) {
 946                perror("fopen()");
 947                _Exit(1);
 948        }
 949
 950        fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n");
 951        print_mapping_table_prefix(outfp);
 952        print_mapping_table_suffix(outfp);
 953        print_system_event_mapping_table_prefix(outfp);
 954        print_system_event_mapping_table_suffix(outfp);
 955        fclose(outfp);
 956}
 957
 958static int get_maxfds(void)
 959{
 960        struct rlimit rlim;
 961
 962        if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
 963                return min(rlim.rlim_max / 2, (rlim_t)512);
 964
 965        return 512;
 966}
 967
 968/*
 969 * nftw() doesn't let us pass an argument to the processing function,
 970 * so use a global variables.
 971 */
 972static FILE *eventsfp;
 973static char *mapfile;
 974
 975static int is_leaf_dir(const char *fpath)
 976{
 977        DIR *d;
 978        struct dirent *dir;
 979        int res = 1;
 980
 981        d = opendir(fpath);
 982        if (!d)
 983                return 0;
 984
 985        while ((dir = readdir(d)) != NULL) {
 986                if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
 987                        continue;
 988
 989                if (dir->d_type == DT_DIR) {
 990                        res = 0;
 991                        break;
 992                } else if (dir->d_type == DT_UNKNOWN) {
 993                        char path[PATH_MAX];
 994                        struct stat st;
 995
 996                        sprintf(path, "%s/%s", fpath, dir->d_name);
 997                        if (stat(path, &st))
 998                                break;
 999
1000                        if (S_ISDIR(st.st_mode)) {
1001                                res = 0;
1002                                break;
1003                        }
1004                }
1005        }
1006
1007        closedir(d);
1008
1009        return res;
1010}
1011
1012static int is_json_file(const char *name)
1013{
1014        const char *suffix;
1015
1016        if (strlen(name) < 5)
1017                return 0;
1018
1019        suffix = name + strlen(name) - 5;
1020
1021        if (strncmp(suffix, ".json", 5) == 0)
1022                return 1;
1023        return 0;
1024}
1025
1026static int preprocess_arch_std_files(const char *fpath, const struct stat *sb,
1027                                int typeflag, struct FTW *ftwbuf)
1028{
1029        int level = ftwbuf->level;
1030        int is_file = typeflag == FTW_F;
1031
1032        if (level == 1 && is_file && is_json_file(fpath))
1033                return json_events(fpath, save_arch_std_events, (void *)sb);
1034
1035        return 0;
1036}
1037
1038static int process_one_file(const char *fpath, const struct stat *sb,
1039                            int typeflag, struct FTW *ftwbuf)
1040{
1041        char *tblname, *bname;
1042        int is_dir  = typeflag == FTW_D;
1043        int is_file = typeflag == FTW_F;
1044        int level   = ftwbuf->level;
1045        int err = 0;
1046
1047        if (level >= 2 && is_dir) {
1048                int count = 0;
1049                /*
1050                 * For level 2 directory, bname will include parent name,
1051                 * like vendor/platform. So search back from platform dir
1052                 * to find this.
1053                 * Something similar for level 3 directory, but we're a PMU
1054                 * category folder, like vendor/platform/cpu.
1055                 */
1056                bname = (char *) fpath + ftwbuf->base - 2;
1057                for (;;) {
1058                        if (*bname == '/')
1059                                count++;
1060                        if (count == level - 1)
1061                                break;
1062                        bname--;
1063                }
1064                bname++;
1065        } else
1066                bname = (char *) fpath + ftwbuf->base;
1067
1068        pr_debug("%s %d %7jd %-20s %s\n",
1069                 is_file ? "f" : is_dir ? "d" : "x",
1070                 level, sb->st_size, bname, fpath);
1071
1072        /* base dir or too deep */
1073        if (level == 0 || level > 4)
1074                return 0;
1075
1076
1077        /* model directory, reset topic */
1078        if ((level == 1 && is_dir && is_leaf_dir(fpath)) ||
1079            (level >= 2 && is_dir && is_leaf_dir(fpath))) {
1080                if (close_table)
1081                        print_events_table_suffix(eventsfp);
1082
1083                /*
1084                 * Drop file name suffix. Replace hyphens with underscores.
1085                 * Fail if file name contains any alphanum characters besides
1086                 * underscores.
1087                 */
1088                tblname = file_name_to_table_name(bname);
1089                if (!tblname) {
1090                        pr_info("%s: Error determining table name for %s\n", prog,
1091                                bname);
1092                        return -1;
1093                }
1094
1095                if (is_sys_dir(bname)) {
1096                        struct sys_event_table *sys_event_table;
1097
1098                        sys_event_table = malloc(sizeof(*sys_event_table));
1099                        if (!sys_event_table)
1100                                return -1;
1101
1102                        sys_event_table->soc_id = strdup(tblname);
1103                        if (!sys_event_table->soc_id) {
1104                                free(sys_event_table);
1105                                return -1;
1106                        }
1107                        list_add_tail(&sys_event_table->list,
1108                                      &sys_event_tables);
1109                }
1110
1111                print_events_table_prefix(eventsfp, tblname);
1112                return 0;
1113        }
1114
1115        /*
1116         * Save the mapfile name for now. We will process mapfile
1117         * after processing all JSON files (so we can write out the
1118         * mapping table after all PMU events tables).
1119         *
1120         */
1121        if (level == 1 && is_file) {
1122                if (!strcmp(bname, "mapfile.csv")) {
1123                        mapfile = strdup(fpath);
1124                        return 0;
1125                }
1126                if (is_json_file(bname))
1127                        pr_debug("%s: ArchStd json is preprocessed %s\n", prog, fpath);
1128                else
1129                        pr_info("%s: Ignoring file %s\n", prog, fpath);
1130                return 0;
1131        }
1132
1133        /*
1134         * If the file name does not have a .json extension,
1135         * ignore it. It could be a readme.txt for instance.
1136         */
1137        if (is_file) {
1138                if (!is_json_file(bname)) {
1139                        pr_info("%s: Ignoring file without .json suffix %s\n", prog,
1140                                fpath);
1141                        return 0;
1142                }
1143        }
1144
1145        if (level > 1 && add_topic(bname))
1146                return -ENOMEM;
1147
1148        /*
1149         * Assume all other files are JSON files.
1150         *
1151         * If mapfile refers to 'power7_core.json', we create a table
1152         * named 'power7_core'. Any inconsistencies between the mapfile
1153         * and directory tree could result in build failure due to table
1154         * names not being found.
1155         *
1156         * At least for now, be strict with processing JSON file names.
1157         * i.e. if JSON file name cannot be mapped to C-style table name,
1158         * fail.
1159         */
1160        if (is_file) {
1161                struct perf_entry_data data = {
1162                        .topic = get_topic(),
1163                        .outfp = eventsfp,
1164                };
1165
1166                err = json_events(fpath, print_events_table_entry, &data);
1167
1168                free(data.topic);
1169        }
1170
1171        return err;
1172}
1173
1174#ifndef PATH_MAX
1175#define PATH_MAX        4096
1176#endif
1177
1178/*
1179 * Starting in directory 'start_dirname', find the "mapfile.csv" and
1180 * the set of JSON files for the architecture 'arch'.
1181 *
1182 * From each JSON file, create a C-style "PMU events table" from the
1183 * JSON file (see struct pmu_event).
1184 *
1185 * From the mapfile, create a mapping between the CPU revisions and
1186 * PMU event tables (see struct pmu_events_map).
1187 *
1188 * Write out the PMU events tables and the mapping table to pmu-event.c.
1189 */
1190int main(int argc, char *argv[])
1191{
1192        int rc, ret = 0, empty_map = 0;
1193        int maxfds;
1194        char ldirname[PATH_MAX];
1195        const char *arch;
1196        const char *output_file;
1197        const char *start_dirname;
1198        char *err_string_ext = "";
1199        struct stat stbuf;
1200
1201        prog = basename(argv[0]);
1202        if (argc < 4) {
1203                pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog);
1204                return 1;
1205        }
1206
1207        arch = argv[1];
1208        start_dirname = argv[2];
1209        output_file = argv[3];
1210
1211        if (argc > 4)
1212                verbose = atoi(argv[4]);
1213
1214        eventsfp = fopen(output_file, "w");
1215        if (!eventsfp) {
1216                pr_err("%s Unable to create required file %s (%s)\n",
1217                                prog, output_file, strerror(errno));
1218                return 2;
1219        }
1220
1221        sprintf(ldirname, "%s/%s", start_dirname, arch);
1222
1223        /* If architecture does not have any event lists, bail out */
1224        if (stat(ldirname, &stbuf) < 0) {
1225                pr_info("%s: Arch %s has no PMU event lists\n", prog, arch);
1226                empty_map = 1;
1227                goto err_close_eventsfp;
1228        }
1229
1230        /* Include pmu-events.h first */
1231        fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n");
1232
1233        /*
1234         * The mapfile allows multiple CPUids to point to the same JSON file,
1235         * so, not sure if there is a need for symlinks within the pmu-events
1236         * directory.
1237         *
1238         * For now, treat symlinks of JSON files as regular files and create
1239         * separate tables for each symlink (presumably, each symlink refers
1240         * to specific version of the CPU).
1241         */
1242
1243        maxfds = get_maxfds();
1244        rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
1245        if (rc)
1246                goto err_processing_std_arch_event_dir;
1247
1248        rc = nftw(ldirname, process_one_file, maxfds, 0);
1249        if (rc)
1250                goto err_processing_dir;
1251
1252        sprintf(ldirname, "%s/test", start_dirname);
1253
1254        rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
1255        if (rc)
1256                goto err_processing_std_arch_event_dir;
1257
1258        rc = nftw(ldirname, process_one_file, maxfds, 0);
1259        if (rc)
1260                goto err_processing_dir;
1261
1262        if (close_table)
1263                print_events_table_suffix(eventsfp);
1264
1265        if (!mapfile) {
1266                pr_info("%s: No CPU->JSON mapping?\n", prog);
1267                empty_map = 1;
1268                goto err_close_eventsfp;
1269        }
1270
1271        rc = process_mapfile(eventsfp, mapfile);
1272        if (rc) {
1273                pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
1274                /* Make build fail */
1275                ret = 1;
1276                goto err_close_eventsfp;
1277        }
1278
1279        rc = process_system_event_tables(eventsfp);
1280        fclose(eventsfp);
1281        if (rc) {
1282                ret = 1;
1283                goto err_out;
1284        }
1285
1286        free_arch_std_events();
1287        free(mapfile);
1288        return 0;
1289
1290err_processing_std_arch_event_dir:
1291        err_string_ext = " for std arch event";
1292err_processing_dir:
1293        if (verbose) {
1294                pr_info("%s: Error walking file tree %s%s\n", prog, ldirname,
1295                        err_string_ext);
1296                empty_map = 1;
1297        } else if (rc < 0) {
1298                ret = 1;
1299        } else {
1300                empty_map = 1;
1301        }
1302err_close_eventsfp:
1303        fclose(eventsfp);
1304        if (empty_map)
1305                create_empty_mapping(output_file);
1306err_out:
1307        free_arch_std_events();
1308        free(mapfile);
1309        return ret;
1310}
1311