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