1959826caSMatt Macy /* Parse event JSON files */ 2959826caSMatt Macy 3959826caSMatt Macy /* 4959826caSMatt Macy * Copyright (c) 2014, Intel Corporation 5959826caSMatt Macy * All rights reserved. 6959826caSMatt Macy * 7959826caSMatt Macy * Redistribution and use in source and binary forms, with or without 8959826caSMatt Macy * modification, are permitted provided that the following conditions are met: 9959826caSMatt Macy * 10959826caSMatt Macy * 1. Redistributions of source code must retain the above copyright notice, 11959826caSMatt Macy * this list of conditions and the following disclaimer. 12959826caSMatt Macy * 13959826caSMatt Macy * 2. Redistributions in binary form must reproduce the above copyright 14959826caSMatt Macy * notice, this list of conditions and the following disclaimer in the 15959826caSMatt Macy * documentation and/or other materials provided with the distribution. 16959826caSMatt Macy * 17959826caSMatt Macy * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18959826caSMatt Macy * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19959826caSMatt Macy * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20959826caSMatt Macy * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21959826caSMatt Macy * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22959826caSMatt Macy * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23959826caSMatt Macy * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24959826caSMatt Macy * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25959826caSMatt Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26959826caSMatt Macy * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27959826caSMatt Macy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 28959826caSMatt Macy * OF THE POSSIBILITY OF SUCH DAMAGE. 29959826caSMatt Macy */ 30959826caSMatt Macy 31b3d01a2aSEnji Cooper #include <sys/param.h> 32b3d01a2aSEnji Cooper #include <sys/resource.h> /* getrlimit */ 33b3d01a2aSEnji Cooper #include <sys/stat.h> 34b3d01a2aSEnji Cooper #include <sys/time.h> /* getrlimit */ 35b3d01a2aSEnji Cooper #include <ctype.h> 36b3d01a2aSEnji Cooper #include <dirent.h> 37b3d01a2aSEnji Cooper #include <errno.h> 38b3d01a2aSEnji Cooper #include <libgen.h> 39b3d01a2aSEnji Cooper #include <limits.h> 40b3d01a2aSEnji Cooper #include <stdarg.h> 412fa224b1SAlex Richardson #include <stddef.h> 42959826caSMatt Macy #include <stdio.h> 43959826caSMatt Macy #include <stdlib.h> 44959826caSMatt Macy #include <string.h> 45959826caSMatt Macy #include <unistd.h> 4651f32966SAlexander Motin #include <ftw.h> 47959826caSMatt Macy #include "list.h" 48959826caSMatt Macy #include "jsmn.h" 49959826caSMatt Macy #include "json.h" 5062ff619dSAlexander Motin #include "pmu-events.h" 51959826caSMatt Macy 52334fd3daSMatt Macy static int 53334fd3daSMatt Macy nftw_ordered(const char *path, int (*fn)(const char *, const struct stat *, int, 54334fd3daSMatt Macy struct FTW *), int nfds, int ftwflags); 5562ff619dSAlexander Motin #define nftw nftw_ordered 56334fd3daSMatt Macy 5751f32966SAlexander Motin _Noreturn void _Exit(int); 5862ff619dSAlexander Motin char *get_cpu_str(void); 5951f32966SAlexander Motin 60959826caSMatt Macy int verbose; 61959826caSMatt Macy static char *prog; 62959826caSMatt Macy 6362ff619dSAlexander Motin struct json_event { 6462ff619dSAlexander Motin char *name; 6562ff619dSAlexander Motin char *compat; 6662ff619dSAlexander Motin char *event; 6762ff619dSAlexander Motin char *desc; 6862ff619dSAlexander Motin char *long_desc; 6962ff619dSAlexander Motin char *pmu; 7062ff619dSAlexander Motin char *unit; 7162ff619dSAlexander Motin char *perpkg; 7262ff619dSAlexander Motin char *aggr_mode; 7362ff619dSAlexander Motin char *metric_expr; 7462ff619dSAlexander Motin char *metric_name; 7562ff619dSAlexander Motin char *metric_group; 7662ff619dSAlexander Motin char *deprecated; 7762ff619dSAlexander Motin char *metric_constraint; 7862ff619dSAlexander Motin }; 7962ff619dSAlexander Motin 8062ff619dSAlexander Motin static enum aggr_mode_class convert(const char *aggr_mode) 8162ff619dSAlexander Motin { 8262ff619dSAlexander Motin if (!strcmp(aggr_mode, "PerCore")) 8362ff619dSAlexander Motin return PerCore; 8462ff619dSAlexander Motin else if (!strcmp(aggr_mode, "PerChip")) 8562ff619dSAlexander Motin return PerChip; 8662ff619dSAlexander Motin 8762ff619dSAlexander Motin pr_err("%s: Wrong AggregationMode value '%s'\n", prog, aggr_mode); 8862ff619dSAlexander Motin return -1; 8962ff619dSAlexander Motin } 9062ff619dSAlexander Motin 9162ff619dSAlexander Motin static LIST_HEAD(sys_event_tables); 9262ff619dSAlexander Motin 9362ff619dSAlexander Motin struct sys_event_table { 9462ff619dSAlexander Motin struct list_head list; 9562ff619dSAlexander Motin char *soc_id; 9662ff619dSAlexander Motin }; 9762ff619dSAlexander Motin 9862ff619dSAlexander Motin static void free_sys_event_tables(void) 9962ff619dSAlexander Motin { 10062ff619dSAlexander Motin struct sys_event_table *et, *next; 10162ff619dSAlexander Motin 10262ff619dSAlexander Motin list_for_each_entry_safe(et, next, &sys_event_tables, list) { 10362ff619dSAlexander Motin free(et->soc_id); 10462ff619dSAlexander Motin free(et); 10562ff619dSAlexander Motin } 10662ff619dSAlexander Motin } 10762ff619dSAlexander Motin 10851f32966SAlexander Motin int eprintf(int level, int var, const char *fmt, ...) 109959826caSMatt Macy { 110959826caSMatt Macy 111959826caSMatt Macy int ret; 112959826caSMatt Macy va_list args; 113959826caSMatt Macy 114959826caSMatt Macy if (var < level) 115959826caSMatt Macy return 0; 116959826caSMatt Macy 117959826caSMatt Macy va_start(args, fmt); 118959826caSMatt Macy 119959826caSMatt Macy ret = vfprintf(stderr, fmt, args); 120959826caSMatt Macy 121959826caSMatt Macy va_end(args); 122959826caSMatt Macy 123959826caSMatt Macy return ret; 124959826caSMatt Macy } 125959826caSMatt Macy 12651f32966SAlexander Motin static void addfield(char *map, char **dst, const char *sep, 12751f32966SAlexander Motin const char *a, jsmntok_t *bt) 128959826caSMatt Macy { 129959826caSMatt Macy unsigned int len = strlen(a) + 1 + strlen(sep); 130959826caSMatt Macy int olen = *dst ? strlen(*dst) : 0; 131959826caSMatt Macy int blen = bt ? json_len(bt) : 0; 132959826caSMatt Macy char *out; 133959826caSMatt Macy 134959826caSMatt Macy out = realloc(*dst, len + olen + blen); 135959826caSMatt Macy if (!out) { 136959826caSMatt Macy /* Don't add field in this case */ 137959826caSMatt Macy return; 138959826caSMatt Macy } 139959826caSMatt Macy *dst = out; 140959826caSMatt Macy 141959826caSMatt Macy if (!olen) 142959826caSMatt Macy *(*dst) = 0; 143959826caSMatt Macy else 144959826caSMatt Macy strcat(*dst, sep); 145959826caSMatt Macy strcat(*dst, a); 146959826caSMatt Macy if (bt) 147959826caSMatt Macy strncat(*dst, map + bt->start, blen); 148959826caSMatt Macy } 149959826caSMatt Macy 15051f32966SAlexander Motin static void fixname(char *s) 151959826caSMatt Macy { 152959826caSMatt Macy for (; *s; s++) 153959826caSMatt Macy *s = tolower(*s); 154959826caSMatt Macy } 155959826caSMatt Macy 15651f32966SAlexander Motin static void fixdesc(char *s) 157959826caSMatt Macy { 158959826caSMatt Macy char *e = s + strlen(s); 159959826caSMatt Macy 160959826caSMatt Macy /* Remove trailing dots that look ugly in perf list */ 161959826caSMatt Macy --e; 162959826caSMatt Macy while (e >= s && isspace(*e)) 163959826caSMatt Macy --e; 1646a2a926dSEd Maste if (e >= s && *e == '.') 165959826caSMatt Macy *e = 0; 166959826caSMatt Macy } 167959826caSMatt Macy 168959826caSMatt Macy /* Add escapes for '\' so they are proper C strings. */ 16951f32966SAlexander Motin static char *fixregex(char *s) 170959826caSMatt Macy { 171959826caSMatt Macy int len = 0; 172959826caSMatt Macy int esc_count = 0; 173959826caSMatt Macy char *fixed = NULL; 174959826caSMatt Macy char *p, *q; 175959826caSMatt Macy 176959826caSMatt Macy /* Count the number of '\' in string */ 177959826caSMatt Macy for (p = s; *p; p++) { 178959826caSMatt Macy ++len; 179959826caSMatt Macy if (*p == '\\') 180959826caSMatt Macy ++esc_count; 181959826caSMatt Macy } 182959826caSMatt Macy 183959826caSMatt Macy if (esc_count == 0) 184959826caSMatt Macy return s; 185959826caSMatt Macy 186959826caSMatt Macy /* allocate space for a new string */ 18762ff619dSAlexander Motin fixed = (char *) malloc(len + esc_count + 1); 188959826caSMatt Macy if (!fixed) 189959826caSMatt Macy return NULL; 190959826caSMatt Macy 191959826caSMatt Macy /* copy over the characters */ 192959826caSMatt Macy q = fixed; 193959826caSMatt Macy for (p = s; *p; p++) { 194959826caSMatt Macy if (*p == '\\') { 195959826caSMatt Macy *q = '\\'; 196959826caSMatt Macy ++q; 197959826caSMatt Macy } 198959826caSMatt Macy *q = *p; 199959826caSMatt Macy ++q; 200959826caSMatt Macy } 201959826caSMatt Macy *q = '\0'; 202959826caSMatt Macy return fixed; 203959826caSMatt Macy } 204959826caSMatt Macy 205959826caSMatt Macy static struct msrmap { 206959826caSMatt Macy const char *num; 207959826caSMatt Macy const char *pname; 208959826caSMatt Macy } msrmap[] = { 209959826caSMatt Macy { "0x3F6", "ldlat=" }, 210959826caSMatt Macy { "0x1A6", "offcore_rsp=" }, 211959826caSMatt Macy { "0x1A7", "offcore_rsp=" }, 212959826caSMatt Macy { "0x3F7", "frontend=" }, 213959826caSMatt Macy { NULL, NULL } 214959826caSMatt Macy }; 215959826caSMatt Macy 21651f32966SAlexander Motin static void cut_comma(char *map, jsmntok_t *newval) 217959826caSMatt Macy { 218959826caSMatt Macy int i; 219959826caSMatt Macy 220959826caSMatt Macy /* Cut off everything after comma */ 221959826caSMatt Macy for (i = newval->start; i < newval->end; i++) { 222959826caSMatt Macy if (map[i] == ',') 223959826caSMatt Macy newval->end = i; 224959826caSMatt Macy } 225959826caSMatt Macy } 226959826caSMatt Macy 22751f32966SAlexander Motin static struct msrmap *lookup_msr(char *map, jsmntok_t *val) 228959826caSMatt Macy { 229959826caSMatt Macy jsmntok_t newval = *val; 230959826caSMatt Macy static bool warned; 231959826caSMatt Macy int i; 232959826caSMatt Macy 233959826caSMatt Macy cut_comma(map, &newval); 234959826caSMatt Macy for (i = 0; msrmap[i].num; i++) 235959826caSMatt Macy if (json_streq(map, &newval, msrmap[i].num)) 236959826caSMatt Macy return &msrmap[i]; 237959826caSMatt Macy if (!warned) { 238959826caSMatt Macy warned = true; 239959826caSMatt Macy pr_err("%s: Unknown MSR in event file %.*s\n", prog, 240959826caSMatt Macy json_len(val), map + val->start); 241959826caSMatt Macy } 242959826caSMatt Macy return NULL; 243959826caSMatt Macy } 244959826caSMatt Macy 245959826caSMatt Macy static struct map { 246959826caSMatt Macy const char *json; 247959826caSMatt Macy const char *perf; 248959826caSMatt Macy } unit_to_pmu[] = { 249959826caSMatt Macy { "CBO", "uncore_cbox" }, 250959826caSMatt Macy { "QPI LL", "uncore_qpi" }, 251959826caSMatt Macy { "SBO", "uncore_sbox" }, 252959826caSMatt Macy { "iMPH-U", "uncore_arb" }, 25362ff619dSAlexander Motin { "CPU-M-CF", "cpum_cf" }, 25462ff619dSAlexander Motin { "CPU-M-SF", "cpum_sf" }, 25518054d02SAlexander Motin { "UPI LL", "uncore_upi" }, 25662ff619dSAlexander Motin { "hisi_sicl,cpa", "hisi_sicl,cpa"}, 25762ff619dSAlexander Motin { "hisi_sccl,ddrc", "hisi_sccl,ddrc" }, 25862ff619dSAlexander Motin { "hisi_sccl,hha", "hisi_sccl,hha" }, 25962ff619dSAlexander Motin { "hisi_sccl,l3c", "hisi_sccl,l3c" }, 26062ff619dSAlexander Motin /* it's not realistic to keep adding these, we need something more scalable ... */ 26162ff619dSAlexander Motin { "imx8_ddr", "imx8_ddr" }, 26218054d02SAlexander Motin { "L3PMC", "amd_l3" }, 26318054d02SAlexander Motin { "DFPMC", "amd_df" }, 26418054d02SAlexander Motin { "cpu_core", "cpu_core" }, 26518054d02SAlexander Motin { "cpu_atom", "cpu_atom" }, 266959826caSMatt Macy {} 267959826caSMatt Macy }; 268959826caSMatt Macy 26951f32966SAlexander Motin static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val) 270959826caSMatt Macy { 271959826caSMatt Macy int i; 272959826caSMatt Macy 273959826caSMatt Macy for (i = 0; table[i].json; i++) { 274959826caSMatt Macy if (json_streq(map, val, table[i].json)) 275959826caSMatt Macy return table[i].perf; 276959826caSMatt Macy } 277959826caSMatt Macy return NULL; 278959826caSMatt Macy } 279959826caSMatt Macy 280959826caSMatt Macy #define EXPECT(e, t, m) do { if (!(e)) { \ 281959826caSMatt Macy jsmntok_t *loc = (t); \ 282959826caSMatt Macy if (!(t)->start && (t) > tokens) \ 283959826caSMatt Macy loc = (t) - 1; \ 284959826caSMatt Macy pr_err("%s:%d: " m ", got %s\n", fn, \ 285959826caSMatt Macy json_line(map, loc), \ 286959826caSMatt Macy json_name(t)); \ 287959826caSMatt Macy err = -EIO; \ 288959826caSMatt Macy goto out_free; \ 289959826caSMatt Macy } } while (0) 290959826caSMatt Macy 291959826caSMatt Macy static char *topic; 292959826caSMatt Macy 29351f32966SAlexander Motin static char *get_topic(void) 294959826caSMatt Macy { 295959826caSMatt Macy char *tp; 296959826caSMatt Macy int i; 297959826caSMatt Macy 298959826caSMatt Macy /* tp is free'd in process_one_file() */ 299959826caSMatt Macy i = asprintf(&tp, "%s", topic); 300959826caSMatt Macy if (i < 0) { 301959826caSMatt Macy pr_info("%s: asprintf() error %s\n", prog); 302959826caSMatt Macy return NULL; 303959826caSMatt Macy } 304959826caSMatt Macy 305959826caSMatt Macy for (i = 0; i < (int) strlen(tp); i++) { 306959826caSMatt Macy char c = tp[i]; 307959826caSMatt Macy 308959826caSMatt Macy if (c == '-') 309959826caSMatt Macy tp[i] = ' '; 310959826caSMatt Macy else if (c == '.') { 311959826caSMatt Macy tp[i] = '\0'; 312959826caSMatt Macy break; 313959826caSMatt Macy } 314959826caSMatt Macy } 315959826caSMatt Macy 316959826caSMatt Macy return tp; 317959826caSMatt Macy } 318959826caSMatt Macy 31962ff619dSAlexander Motin static int add_topic(char *bname) 320959826caSMatt Macy { 321959826caSMatt Macy free(topic); 322959826caSMatt Macy topic = strdup(bname); 323959826caSMatt Macy if (!topic) { 324959826caSMatt Macy pr_info("%s: strdup() error %s for file %s\n", prog, 325959826caSMatt Macy strerror(errno), bname); 326959826caSMatt Macy return -ENOMEM; 327959826caSMatt Macy } 328959826caSMatt Macy return 0; 329959826caSMatt Macy } 330959826caSMatt Macy 331959826caSMatt Macy struct perf_entry_data { 332959826caSMatt Macy FILE *outfp; 333959826caSMatt Macy char *topic; 334959826caSMatt Macy }; 335959826caSMatt Macy 336959826caSMatt Macy static int close_table; 337959826caSMatt Macy 33851f32966SAlexander Motin static void print_events_table_prefix(FILE *fp, const char *tblname) 339959826caSMatt Macy { 34062ff619dSAlexander Motin fprintf(fp, "static const struct pmu_event %s[] = {\n", tblname); 341959826caSMatt Macy close_table = 1; 342959826caSMatt Macy } 343959826caSMatt Macy 34462ff619dSAlexander Motin static int print_events_table_entry(void *data, struct json_event *je) 345959826caSMatt Macy { 346959826caSMatt Macy struct perf_entry_data *pd = data; 347959826caSMatt Macy FILE *outfp = pd->outfp; 34862ff619dSAlexander Motin char *topic_local = pd->topic; 349959826caSMatt Macy 350959826caSMatt Macy /* 351959826caSMatt Macy * TODO: Remove formatting chars after debugging to reduce 352959826caSMatt Macy * string lengths. 353959826caSMatt Macy */ 354959826caSMatt Macy fprintf(outfp, "{\n"); 355959826caSMatt Macy 35662ff619dSAlexander Motin if (je->name) 35762ff619dSAlexander Motin fprintf(outfp, "\t.name = \"%s\",\n", je->name); 35862ff619dSAlexander Motin if (je->event) 35962ff619dSAlexander Motin fprintf(outfp, "\t.event = \"%s\",\n", je->event); 36062ff619dSAlexander Motin fprintf(outfp, "\t.desc = \"%s\",\n", je->desc); 36162ff619dSAlexander Motin if (je->compat) 36262ff619dSAlexander Motin fprintf(outfp, "\t.compat = \"%s\",\n", je->compat); 36362ff619dSAlexander Motin fprintf(outfp, "\t.topic = \"%s\",\n", topic_local); 36462ff619dSAlexander Motin if (je->long_desc && je->long_desc[0]) 36562ff619dSAlexander Motin fprintf(outfp, "\t.long_desc = \"%s\",\n", je->long_desc); 36662ff619dSAlexander Motin if (je->pmu) 36762ff619dSAlexander Motin fprintf(outfp, "\t.pmu = \"%s\",\n", je->pmu); 36862ff619dSAlexander Motin if (je->unit) 36962ff619dSAlexander Motin fprintf(outfp, "\t.unit = \"%s\",\n", je->unit); 37062ff619dSAlexander Motin if (je->perpkg) 37162ff619dSAlexander Motin fprintf(outfp, "\t.perpkg = \"%s\",\n", je->perpkg); 37262ff619dSAlexander Motin if (je->aggr_mode) 37362ff619dSAlexander Motin fprintf(outfp, "\t.aggr_mode = \"%d\",\n", convert(je->aggr_mode)); 37462ff619dSAlexander Motin if (je->metric_expr) 37562ff619dSAlexander Motin fprintf(outfp, "\t.metric_expr = \"%s\",\n", je->metric_expr); 37662ff619dSAlexander Motin if (je->metric_name) 37762ff619dSAlexander Motin fprintf(outfp, "\t.metric_name = \"%s\",\n", je->metric_name); 37862ff619dSAlexander Motin if (je->metric_group) 37962ff619dSAlexander Motin fprintf(outfp, "\t.metric_group = \"%s\",\n", je->metric_group); 38062ff619dSAlexander Motin if (je->deprecated) 38162ff619dSAlexander Motin fprintf(outfp, "\t.deprecated = \"%s\",\n", je->deprecated); 38262ff619dSAlexander Motin if (je->metric_constraint) 38362ff619dSAlexander Motin fprintf(outfp, "\t.metric_constraint = \"%s\",\n", je->metric_constraint); 384959826caSMatt Macy fprintf(outfp, "},\n"); 385959826caSMatt Macy 386959826caSMatt Macy return 0; 387959826caSMatt Macy } 388959826caSMatt Macy 389959826caSMatt Macy struct event_struct { 390959826caSMatt Macy struct list_head list; 391959826caSMatt Macy char *name; 392959826caSMatt Macy char *event; 39362ff619dSAlexander Motin char *compat; 394959826caSMatt Macy char *desc; 395959826caSMatt Macy char *long_desc; 396959826caSMatt Macy char *pmu; 397959826caSMatt Macy char *unit; 398959826caSMatt Macy char *perpkg; 39962ff619dSAlexander Motin char *aggr_mode; 400959826caSMatt Macy char *metric_expr; 401959826caSMatt Macy char *metric_name; 402959826caSMatt Macy char *metric_group; 40362ff619dSAlexander Motin char *deprecated; 40462ff619dSAlexander Motin char *metric_constraint; 405959826caSMatt Macy }; 406959826caSMatt Macy 40762ff619dSAlexander Motin #define ADD_EVENT_FIELD(field) do { if (je->field) { \ 40862ff619dSAlexander Motin es->field = strdup(je->field); \ 409959826caSMatt Macy if (!es->field) \ 410959826caSMatt Macy goto out_free; \ 411959826caSMatt Macy } } while (0) 412959826caSMatt Macy 413959826caSMatt Macy #define FREE_EVENT_FIELD(field) free(es->field) 414959826caSMatt Macy 41562ff619dSAlexander Motin #define TRY_FIXUP_FIELD(field) do { if (es->field && !je->field) {\ 41662ff619dSAlexander Motin je->field = strdup(es->field); \ 41762ff619dSAlexander Motin if (!je->field) \ 418959826caSMatt Macy return -ENOMEM; \ 419959826caSMatt Macy } } while (0) 420959826caSMatt Macy 421959826caSMatt Macy #define FOR_ALL_EVENT_STRUCT_FIELDS(op) do { \ 422959826caSMatt Macy op(name); \ 423959826caSMatt Macy op(event); \ 424959826caSMatt Macy op(desc); \ 425959826caSMatt Macy op(long_desc); \ 426959826caSMatt Macy op(pmu); \ 427959826caSMatt Macy op(unit); \ 428959826caSMatt Macy op(perpkg); \ 42962ff619dSAlexander Motin op(aggr_mode); \ 430959826caSMatt Macy op(metric_expr); \ 431959826caSMatt Macy op(metric_name); \ 432959826caSMatt Macy op(metric_group); \ 43362ff619dSAlexander Motin op(deprecated); \ 434959826caSMatt Macy } while (0) 435959826caSMatt Macy 436959826caSMatt Macy static LIST_HEAD(arch_std_events); 437959826caSMatt Macy 43851f32966SAlexander Motin static void free_arch_std_events(void) 439959826caSMatt Macy { 440959826caSMatt Macy struct event_struct *es, *next; 441959826caSMatt Macy 442959826caSMatt Macy list_for_each_entry_safe(es, next, &arch_std_events, list) { 443959826caSMatt Macy FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD); 44462ff619dSAlexander Motin list_del_init(&es->list); 445959826caSMatt Macy free(es); 446959826caSMatt Macy } 447959826caSMatt Macy } 448959826caSMatt Macy 44962ff619dSAlexander Motin static int save_arch_std_events(void *data __unused, struct json_event *je) 450959826caSMatt Macy { 451959826caSMatt Macy struct event_struct *es; 452959826caSMatt Macy 453959826caSMatt Macy es = malloc(sizeof(*es)); 454959826caSMatt Macy if (!es) 455959826caSMatt Macy return -ENOMEM; 456959826caSMatt Macy memset(es, 0, sizeof(*es)); 457959826caSMatt Macy FOR_ALL_EVENT_STRUCT_FIELDS(ADD_EVENT_FIELD); 458959826caSMatt Macy list_add_tail(&es->list, &arch_std_events); 459959826caSMatt Macy return 0; 460959826caSMatt Macy out_free: 461959826caSMatt Macy FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD); 462959826caSMatt Macy free(es); 463959826caSMatt Macy return -ENOMEM; 464959826caSMatt Macy } 465959826caSMatt Macy 46651f32966SAlexander Motin static void print_events_table_suffix(FILE *outfp) 467959826caSMatt Macy { 468959826caSMatt Macy fprintf(outfp, "{\n"); 469959826caSMatt Macy 470959826caSMatt Macy fprintf(outfp, "\t.name = 0,\n"); 471959826caSMatt Macy fprintf(outfp, "\t.event = 0,\n"); 472959826caSMatt Macy fprintf(outfp, "\t.desc = 0,\n"); 473959826caSMatt Macy 474959826caSMatt Macy fprintf(outfp, "},\n"); 475959826caSMatt Macy fprintf(outfp, "};\n"); 476959826caSMatt Macy close_table = 0; 477959826caSMatt Macy } 478959826caSMatt Macy 479959826caSMatt Macy static struct fixed { 480959826caSMatt Macy const char *name; 481959826caSMatt Macy const char *event; 482959826caSMatt Macy } fixed[] = { 48373b7b181SAlexander Motin #if 0 48462ff619dSAlexander Motin { "inst_retired.any", "event=0xc0,period=2000003" }, 48562ff619dSAlexander Motin { "inst_retired.any_p", "event=0xc0,period=2000003" }, 48662ff619dSAlexander Motin { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03,period=2000003" }, 48762ff619dSAlexander Motin { "cpu_clk_unhalted.thread", "event=0x3c,period=2000003" }, 48862ff619dSAlexander Motin { "cpu_clk_unhalted.core", "event=0x3c,period=2000003" }, 48962ff619dSAlexander Motin { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1,period=2000003" }, 49073b7b181SAlexander Motin #endif 491959826caSMatt Macy { NULL, NULL}, 492959826caSMatt Macy }; 493959826caSMatt Macy 494959826caSMatt Macy /* 495959826caSMatt Macy * Handle different fixed counter encodings between JSON and perf. 496959826caSMatt Macy */ 49762ff619dSAlexander Motin static char *real_event(const char *name, char *event) 498959826caSMatt Macy { 499959826caSMatt Macy int i; 500959826caSMatt Macy 501959826caSMatt Macy if (!name) 502959826caSMatt Macy return NULL; 503959826caSMatt Macy 504959826caSMatt Macy for (i = 0; fixed[i].name; i++) 505959826caSMatt Macy if (!strcasecmp(name, fixed[i].name)) 50662ff619dSAlexander Motin return (char *)fixed[i].event; 507959826caSMatt Macy return event; 508959826caSMatt Macy } 509959826caSMatt Macy 510959826caSMatt Macy static int 51162ff619dSAlexander Motin try_fixup(const char *fn, char *arch_std, struct json_event *je, char **event) 512959826caSMatt Macy { 513959826caSMatt Macy /* try to find matching event from arch standard values */ 514959826caSMatt Macy struct event_struct *es; 515959826caSMatt Macy 516959826caSMatt Macy list_for_each_entry(es, &arch_std_events, list) { 517959826caSMatt Macy if (!strcmp(arch_std, es->name)) { 518959826caSMatt Macy FOR_ALL_EVENT_STRUCT_FIELDS(TRY_FIXUP_FIELD); 51962ff619dSAlexander Motin *event = je->event; 520959826caSMatt Macy return 0; 521959826caSMatt Macy } 522959826caSMatt Macy } 523959826caSMatt Macy 524959826caSMatt Macy pr_err("%s: could not find matching %s for %s\n", 525959826caSMatt Macy prog, arch_std, fn); 526959826caSMatt Macy return -1; 527959826caSMatt Macy } 528959826caSMatt Macy 529959826caSMatt Macy /* Call func with each event in the json file */ 53062ff619dSAlexander Motin static int json_events(const char *fn, 53162ff619dSAlexander Motin int (*func)(void *data, struct json_event *je), 532959826caSMatt Macy void *data) 533959826caSMatt Macy { 534959826caSMatt Macy int err; 535959826caSMatt Macy size_t size; 536959826caSMatt Macy jsmntok_t *tokens, *tok; 537959826caSMatt Macy int i, j, len; 538959826caSMatt Macy char *map; 539959826caSMatt Macy char buf[128]; 540959826caSMatt Macy 541959826caSMatt Macy if (!fn) 542959826caSMatt Macy return -ENOENT; 543959826caSMatt Macy 544959826caSMatt Macy tokens = parse_json(fn, &map, &size, &len); 545959826caSMatt Macy if (!tokens) 546959826caSMatt Macy return -EIO; 547959826caSMatt Macy EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array"); 548959826caSMatt Macy tok = tokens + 1; 549959826caSMatt Macy for (i = 0; i < tokens->size; i++) { 55062ff619dSAlexander Motin char *event = NULL; 551959826caSMatt Macy char *extra_desc = NULL; 552959826caSMatt Macy char *filter = NULL; 55362ff619dSAlexander Motin struct json_event je = {}; 554959826caSMatt Macy char *arch_std = NULL; 555959826caSMatt Macy unsigned long long eventcode = 0; 55662ff619dSAlexander Motin unsigned long long configcode = 0; 557959826caSMatt Macy struct msrmap *msr = NULL; 558959826caSMatt Macy jsmntok_t *msrval = NULL; 559959826caSMatt Macy jsmntok_t *precise = NULL; 560959826caSMatt Macy jsmntok_t *obj = tok++; 56162ff619dSAlexander Motin bool configcode_present = false; 56262ff619dSAlexander Motin char *umask = NULL; 56362ff619dSAlexander Motin char *cmask = NULL; 56462ff619dSAlexander Motin char *inv = NULL; 56562ff619dSAlexander Motin char *any = NULL; 56662ff619dSAlexander Motin char *edge = NULL; 56762ff619dSAlexander Motin char *period = NULL; 56862ff619dSAlexander Motin char *fc_mask = NULL; 56962ff619dSAlexander Motin char *ch_mask = NULL; 570959826caSMatt Macy 571959826caSMatt Macy EXPECT(obj->type == JSMN_OBJECT, obj, "expected object"); 572959826caSMatt Macy for (j = 0; j < obj->size; j += 2) { 573959826caSMatt Macy jsmntok_t *field, *val; 574959826caSMatt Macy int nz; 575959826caSMatt Macy char *s; 576959826caSMatt Macy 577959826caSMatt Macy field = tok + j; 578959826caSMatt Macy EXPECT(field->type == JSMN_STRING, tok + j, 579959826caSMatt Macy "Expected field name"); 580959826caSMatt Macy val = tok + j + 1; 581959826caSMatt Macy EXPECT(val->type == JSMN_STRING, tok + j + 1, 582959826caSMatt Macy "Expected string value"); 583959826caSMatt Macy 584959826caSMatt Macy nz = !json_streq(map, val, "0"); 58562ff619dSAlexander Motin /* match_field */ 58662ff619dSAlexander Motin if (json_streq(map, field, "UMask") && nz) { 58762ff619dSAlexander Motin addfield(map, &umask, "", "umask=", val); 58862ff619dSAlexander Motin } else if (json_streq(map, field, "CounterMask") && nz) { 58962ff619dSAlexander Motin addfield(map, &cmask, "", "cmask=", val); 59062ff619dSAlexander Motin } else if (json_streq(map, field, "Invert") && nz) { 59162ff619dSAlexander Motin addfield(map, &inv, "", "inv=", val); 59262ff619dSAlexander Motin } else if (json_streq(map, field, "AnyThread") && nz) { 59362ff619dSAlexander Motin addfield(map, &any, "", "any=", val); 59462ff619dSAlexander Motin } else if (json_streq(map, field, "EdgeDetect") && nz) { 59562ff619dSAlexander Motin addfield(map, &edge, "", "edge=", val); 59662ff619dSAlexander Motin } else if (json_streq(map, field, "SampleAfterValue") && nz) { 59762ff619dSAlexander Motin addfield(map, &period, "", "period=", val); 59862ff619dSAlexander Motin } else if (json_streq(map, field, "FCMask") && nz) { 59962ff619dSAlexander Motin addfield(map, &fc_mask, "", "fc_mask=", val); 60062ff619dSAlexander Motin } else if (json_streq(map, field, "PortMask") && nz) { 60162ff619dSAlexander Motin addfield(map, &ch_mask, "", "ch_mask=", val); 602959826caSMatt Macy } else if (json_streq(map, field, "EventCode")) { 603959826caSMatt Macy char *code = NULL; 604959826caSMatt Macy addfield(map, &code, "", "", val); 605959826caSMatt Macy eventcode |= strtoul(code, NULL, 0); 606959826caSMatt Macy free(code); 60762ff619dSAlexander Motin } else if (json_streq(map, field, "ConfigCode")) { 60862ff619dSAlexander Motin char *code = NULL; 60962ff619dSAlexander Motin addfield(map, &code, "", "", val); 61062ff619dSAlexander Motin configcode |= strtoul(code, NULL, 0); 61162ff619dSAlexander Motin free(code); 61262ff619dSAlexander Motin configcode_present = true; 613959826caSMatt Macy } else if (json_streq(map, field, "ExtSel")) { 614959826caSMatt Macy char *code = NULL; 615959826caSMatt Macy addfield(map, &code, "", "", val); 61662ff619dSAlexander Motin eventcode |= strtoul(code, NULL, 0) << 8; 617959826caSMatt Macy free(code); 618959826caSMatt Macy } else if (json_streq(map, field, "EventName")) { 61962ff619dSAlexander Motin addfield(map, &je.name, "", "", val); 62062ff619dSAlexander Motin } else if (json_streq(map, field, "Compat")) { 62162ff619dSAlexander Motin addfield(map, &je.compat, "", "", val); 622959826caSMatt Macy } else if (json_streq(map, field, "BriefDescription")) { 62362ff619dSAlexander Motin addfield(map, &je.desc, "", "", val); 62462ff619dSAlexander Motin fixdesc(je.desc); 625959826caSMatt Macy } else if (json_streq(map, field, 626959826caSMatt Macy "PublicDescription")) { 62762ff619dSAlexander Motin addfield(map, &je.long_desc, "", "", val); 62862ff619dSAlexander Motin fixdesc(je.long_desc); 629959826caSMatt Macy } else if (json_streq(map, field, "PEBS") && nz) { 630959826caSMatt Macy precise = val; 631959826caSMatt Macy } else if (json_streq(map, field, "MSRIndex") && nz) { 632959826caSMatt Macy msr = lookup_msr(map, val); 633959826caSMatt Macy } else if (json_streq(map, field, "MSRValue")) { 634959826caSMatt Macy msrval = val; 635959826caSMatt Macy } else if (json_streq(map, field, "Errata") && 636959826caSMatt Macy !json_streq(map, val, "null")) { 637959826caSMatt Macy addfield(map, &extra_desc, ". ", 638959826caSMatt Macy " Spec update: ", val); 639959826caSMatt Macy } else if (json_streq(map, field, "Data_LA") && nz) { 640959826caSMatt Macy addfield(map, &extra_desc, ". ", 641959826caSMatt Macy " Supports address when precise", 642959826caSMatt Macy NULL); 643959826caSMatt Macy } else if (json_streq(map, field, "Unit")) { 644959826caSMatt Macy const char *ppmu; 645959826caSMatt Macy 646959826caSMatt Macy ppmu = field_to_perf(unit_to_pmu, map, val); 647959826caSMatt Macy if (ppmu) { 64862ff619dSAlexander Motin je.pmu = strdup(ppmu); 649959826caSMatt Macy } else { 65062ff619dSAlexander Motin if (!je.pmu) 65162ff619dSAlexander Motin je.pmu = strdup("uncore_"); 65262ff619dSAlexander Motin addfield(map, &je.pmu, "", "", val); 65362ff619dSAlexander Motin for (s = je.pmu; *s; s++) 654959826caSMatt Macy *s = tolower(*s); 655959826caSMatt Macy } 656959826caSMatt Macy } else if (json_streq(map, field, "Filter")) { 657959826caSMatt Macy addfield(map, &filter, "", "", val); 658959826caSMatt Macy } else if (json_streq(map, field, "ScaleUnit")) { 65962ff619dSAlexander Motin addfield(map, &je.unit, "", "", val); 660959826caSMatt Macy } else if (json_streq(map, field, "PerPkg")) { 66162ff619dSAlexander Motin addfield(map, &je.perpkg, "", "", val); 66262ff619dSAlexander Motin } else if (json_streq(map, field, "AggregationMode")) { 66362ff619dSAlexander Motin addfield(map, &je.aggr_mode, "", "", val); 66462ff619dSAlexander Motin } else if (json_streq(map, field, "Deprecated")) { 66562ff619dSAlexander Motin addfield(map, &je.deprecated, "", "", val); 666959826caSMatt Macy } else if (json_streq(map, field, "MetricName")) { 66762ff619dSAlexander Motin addfield(map, &je.metric_name, "", "", val); 668959826caSMatt Macy } else if (json_streq(map, field, "MetricGroup")) { 66962ff619dSAlexander Motin addfield(map, &je.metric_group, "", "", val); 67062ff619dSAlexander Motin } else if (json_streq(map, field, "MetricConstraint")) { 67162ff619dSAlexander Motin addfield(map, &je.metric_constraint, "", "", val); 672959826caSMatt Macy } else if (json_streq(map, field, "MetricExpr")) { 67362ff619dSAlexander Motin addfield(map, &je.metric_expr, "", "", val); 674959826caSMatt Macy } else if (json_streq(map, field, "ArchStdEvent")) { 675959826caSMatt Macy addfield(map, &arch_std, "", "", val); 676959826caSMatt Macy for (s = arch_std; *s; s++) 677959826caSMatt Macy *s = tolower(*s); 678959826caSMatt Macy } 679959826caSMatt Macy /* ignore unknown fields */ 680959826caSMatt Macy } 68162ff619dSAlexander Motin if (precise && je.desc && !strstr(je.desc, "(Precise Event)")) { 682959826caSMatt Macy if (json_streq(map, precise, "2")) 683959826caSMatt Macy addfield(map, &extra_desc, " ", 684959826caSMatt Macy "(Must be precise)", NULL); 685959826caSMatt Macy else 686959826caSMatt Macy addfield(map, &extra_desc, " ", 687959826caSMatt Macy "(Precise event)", NULL); 688959826caSMatt Macy } 68962ff619dSAlexander Motin if (configcode_present) 69062ff619dSAlexander Motin snprintf(buf, sizeof buf, "config=%#llx", configcode); 69162ff619dSAlexander Motin else 69262ff619dSAlexander Motin snprintf(buf, sizeof buf, "event=%#llx", eventcode); 693959826caSMatt Macy addfield(map, &event, ",", buf, NULL); 69462ff619dSAlexander Motin if (any) 69562ff619dSAlexander Motin addfield(map, &event, ",", any, NULL); 69662ff619dSAlexander Motin if (ch_mask) 69762ff619dSAlexander Motin addfield(map, &event, ",", ch_mask, NULL); 69862ff619dSAlexander Motin if (cmask) 69962ff619dSAlexander Motin addfield(map, &event, ",", cmask, NULL); 70062ff619dSAlexander Motin if (edge) 70162ff619dSAlexander Motin addfield(map, &event, ",", edge, NULL); 70262ff619dSAlexander Motin if (fc_mask) 70362ff619dSAlexander Motin addfield(map, &event, ",", fc_mask, NULL); 70462ff619dSAlexander Motin if (inv) 70562ff619dSAlexander Motin addfield(map, &event, ",", inv, NULL); 70662ff619dSAlexander Motin if (period) 70762ff619dSAlexander Motin addfield(map, &event, ",", period, NULL); 70862ff619dSAlexander Motin if (umask) 70962ff619dSAlexander Motin addfield(map, &event, ",", umask, NULL); 71062ff619dSAlexander Motin 71162ff619dSAlexander Motin if (je.desc && extra_desc) 71262ff619dSAlexander Motin addfield(map, &je.desc, " ", extra_desc, NULL); 71362ff619dSAlexander Motin if (je.long_desc && extra_desc) 71462ff619dSAlexander Motin addfield(map, &je.long_desc, " ", extra_desc, NULL); 71562ff619dSAlexander Motin if (je.pmu) { 71662ff619dSAlexander Motin addfield(map, &je.desc, ". ", "Unit: ", NULL); 71762ff619dSAlexander Motin addfield(map, &je.desc, "", je.pmu, NULL); 71862ff619dSAlexander Motin addfield(map, &je.desc, "", " ", NULL); 71962ff619dSAlexander Motin } 720959826caSMatt Macy if (filter) 721959826caSMatt Macy addfield(map, &event, ",", filter, NULL); 722959826caSMatt Macy if (msr != NULL) 723959826caSMatt Macy addfield(map, &event, ",", msr->pname, msrval); 72462ff619dSAlexander Motin if (je.name) 72562ff619dSAlexander Motin fixname(je.name); 726959826caSMatt Macy 727959826caSMatt Macy if (arch_std) { 728959826caSMatt Macy /* 729959826caSMatt Macy * An arch standard event is referenced, so try to 730959826caSMatt Macy * fixup any unassigned values. 731959826caSMatt Macy */ 73262ff619dSAlexander Motin err = try_fixup(fn, arch_std, &je, &event); 733959826caSMatt Macy if (err) 734959826caSMatt Macy goto free_strings; 735959826caSMatt Macy } 73662ff619dSAlexander Motin je.event = real_event(je.name, event); 73762ff619dSAlexander Motin err = func(data, &je); 738959826caSMatt Macy free_strings: 73962ff619dSAlexander Motin free(umask); 74062ff619dSAlexander Motin free(cmask); 74162ff619dSAlexander Motin free(inv); 74262ff619dSAlexander Motin free(any); 74362ff619dSAlexander Motin free(edge); 74462ff619dSAlexander Motin free(period); 74562ff619dSAlexander Motin free(fc_mask); 74662ff619dSAlexander Motin free(ch_mask); 747959826caSMatt Macy free(event); 74862ff619dSAlexander Motin free(je.desc); 74962ff619dSAlexander Motin free(je.name); 75062ff619dSAlexander Motin free(je.compat); 75162ff619dSAlexander Motin free(je.long_desc); 752959826caSMatt Macy free(extra_desc); 75362ff619dSAlexander Motin free(je.pmu); 754959826caSMatt Macy free(filter); 75562ff619dSAlexander Motin free(je.perpkg); 75662ff619dSAlexander Motin free(je.aggr_mode); 75762ff619dSAlexander Motin free(je.deprecated); 75862ff619dSAlexander Motin free(je.unit); 75962ff619dSAlexander Motin free(je.metric_expr); 76062ff619dSAlexander Motin free(je.metric_name); 76162ff619dSAlexander Motin free(je.metric_group); 76262ff619dSAlexander Motin free(je.metric_constraint); 763959826caSMatt Macy free(arch_std); 764959826caSMatt Macy 765959826caSMatt Macy if (err) 766959826caSMatt Macy break; 767959826caSMatt Macy tok += j; 768959826caSMatt Macy } 769959826caSMatt Macy EXPECT(tok - tokens == len, tok, "unexpected objects at end"); 770959826caSMatt Macy err = 0; 771959826caSMatt Macy out_free: 772959826caSMatt Macy free_json(map, size, tokens); 773959826caSMatt Macy return err; 774959826caSMatt Macy } 775959826caSMatt Macy 77662ff619dSAlexander Motin static char *file_name_to_table_name(char *fname) 777959826caSMatt Macy { 778959826caSMatt Macy unsigned int i; 779959826caSMatt Macy int n; 780959826caSMatt Macy int c; 781959826caSMatt Macy char *tblname; 782959826caSMatt Macy 783959826caSMatt Macy /* 784959826caSMatt Macy * Ensure tablename starts with alphabetic character. 785959826caSMatt Macy * Derive rest of table name from basename of the JSON file, 786959826caSMatt Macy * replacing hyphens and stripping out .json suffix. 787959826caSMatt Macy */ 788959826caSMatt Macy n = asprintf(&tblname, "pme_%s", fname); 789959826caSMatt Macy if (n < 0) { 790959826caSMatt Macy pr_info("%s: asprintf() error %s for file %s\n", prog, 791959826caSMatt Macy strerror(errno), fname); 792959826caSMatt Macy return NULL; 793959826caSMatt Macy } 794959826caSMatt Macy 795959826caSMatt Macy for (i = 0; i < strlen(tblname); i++) { 796959826caSMatt Macy c = tblname[i]; 797959826caSMatt Macy 798959826caSMatt Macy if (c == '-' || c == '/') 799959826caSMatt Macy tblname[i] = '_'; 800959826caSMatt Macy else if (c == '.') { 801959826caSMatt Macy tblname[i] = '\0'; 802959826caSMatt Macy break; 803959826caSMatt Macy } else if (!isalnum(c) && c != '_') { 80462ff619dSAlexander Motin pr_err("%s: Invalid character '%c' in file name '%s'\n", 80562ff619dSAlexander Motin prog, c, fname); 806959826caSMatt Macy free(tblname); 807959826caSMatt Macy tblname = NULL; 808959826caSMatt Macy break; 809959826caSMatt Macy } 810959826caSMatt Macy } 811959826caSMatt Macy 812959826caSMatt Macy return tblname; 813959826caSMatt Macy } 814959826caSMatt Macy 81562ff619dSAlexander Motin static bool is_sys_dir(char *fname) 81662ff619dSAlexander Motin { 81762ff619dSAlexander Motin size_t len = strlen(fname), len2 = strlen("/sys"); 81862ff619dSAlexander Motin 81962ff619dSAlexander Motin if (len2 > len) 82062ff619dSAlexander Motin return false; 82162ff619dSAlexander Motin return !strcmp(fname+len-len2, "/sys"); 82262ff619dSAlexander Motin } 82362ff619dSAlexander Motin 82451f32966SAlexander Motin static void print_mapping_table_prefix(FILE *outfp) 825959826caSMatt Macy { 82662ff619dSAlexander Motin fprintf(outfp, "const struct pmu_events_map pmu_events_map[] = {\n"); 827959826caSMatt Macy } 828959826caSMatt Macy 82951f32966SAlexander Motin static void print_mapping_table_suffix(FILE *outfp) 830959826caSMatt Macy { 831959826caSMatt Macy /* 832959826caSMatt Macy * Print the terminating, NULL entry. 833959826caSMatt Macy */ 834959826caSMatt Macy fprintf(outfp, "{\n"); 835959826caSMatt Macy fprintf(outfp, "\t.cpuid = 0,\n"); 836959826caSMatt Macy fprintf(outfp, "\t.version = 0,\n"); 837959826caSMatt Macy fprintf(outfp, "\t.type = 0,\n"); 838959826caSMatt Macy fprintf(outfp, "\t.table = 0,\n"); 839959826caSMatt Macy fprintf(outfp, "},\n"); 840959826caSMatt Macy 841959826caSMatt Macy /* and finally, the closing curly bracket for the struct */ 842959826caSMatt Macy fprintf(outfp, "};\n"); 843959826caSMatt Macy } 844959826caSMatt Macy 84562ff619dSAlexander Motin static void print_mapping_test_table(FILE *outfp) 84662ff619dSAlexander Motin { 84762ff619dSAlexander Motin /* 84862ff619dSAlexander Motin * Print the terminating, NULL entry. 84962ff619dSAlexander Motin */ 85062ff619dSAlexander Motin fprintf(outfp, "{\n"); 85162ff619dSAlexander Motin fprintf(outfp, "\t.cpuid = \"testcpu\",\n"); 85262ff619dSAlexander Motin fprintf(outfp, "\t.version = \"v1\",\n"); 85362ff619dSAlexander Motin fprintf(outfp, "\t.type = \"core\",\n"); 85462ff619dSAlexander Motin fprintf(outfp, "\t.table = pme_test_soc_cpu,\n"); 85562ff619dSAlexander Motin fprintf(outfp, "},\n"); 85662ff619dSAlexander Motin } 85762ff619dSAlexander Motin 85862ff619dSAlexander Motin static void print_system_event_mapping_table_prefix(FILE *outfp) 85962ff619dSAlexander Motin { 86062ff619dSAlexander Motin fprintf(outfp, "\nconst struct pmu_sys_events pmu_sys_event_tables[] = {"); 86162ff619dSAlexander Motin } 86262ff619dSAlexander Motin 86362ff619dSAlexander Motin static void print_system_event_mapping_table_suffix(FILE *outfp) 86462ff619dSAlexander Motin { 86562ff619dSAlexander Motin fprintf(outfp, "\n\t{\n\t\t.table = 0\n\t},"); 86662ff619dSAlexander Motin fprintf(outfp, "\n};\n"); 86762ff619dSAlexander Motin } 86862ff619dSAlexander Motin 86962ff619dSAlexander Motin static int process_system_event_tables(FILE *outfp) 87062ff619dSAlexander Motin { 87162ff619dSAlexander Motin struct sys_event_table *sys_event_table; 87262ff619dSAlexander Motin 87362ff619dSAlexander Motin print_system_event_mapping_table_prefix(outfp); 87462ff619dSAlexander Motin 87562ff619dSAlexander Motin list_for_each_entry(sys_event_table, &sys_event_tables, list) { 87662ff619dSAlexander Motin fprintf(outfp, "\n\t{\n\t\t.table = %s,\n\t\t.name = \"%s\",\n\t},", 87762ff619dSAlexander Motin sys_event_table->soc_id, 87862ff619dSAlexander Motin sys_event_table->soc_id); 87962ff619dSAlexander Motin } 88062ff619dSAlexander Motin 88162ff619dSAlexander Motin print_system_event_mapping_table_suffix(outfp); 88262ff619dSAlexander Motin 88362ff619dSAlexander Motin return 0; 88462ff619dSAlexander Motin } 88562ff619dSAlexander Motin 88651f32966SAlexander Motin static int process_mapfile(FILE *outfp, char *fpath) 887959826caSMatt Macy { 888959826caSMatt Macy int n = 16384; 889959826caSMatt Macy FILE *mapfp; 890959826caSMatt Macy char *save = NULL; 891959826caSMatt Macy char *line, *p; 892959826caSMatt Macy int line_num; 893959826caSMatt Macy char *tblname; 89462ff619dSAlexander Motin int ret = 0; 895959826caSMatt Macy 896959826caSMatt Macy pr_info("%s: Processing mapfile %s\n", prog, fpath); 897959826caSMatt Macy 898959826caSMatt Macy line = malloc(n); 899959826caSMatt Macy if (!line) 900959826caSMatt Macy return -1; 901959826caSMatt Macy 902959826caSMatt Macy mapfp = fopen(fpath, "r"); 903959826caSMatt Macy if (!mapfp) { 904959826caSMatt Macy pr_info("%s: Error %s opening %s\n", prog, strerror(errno), 905959826caSMatt Macy fpath); 9064644463cSEric van Gyzen free(line); 907959826caSMatt Macy return -1; 908959826caSMatt Macy } 909959826caSMatt Macy 910959826caSMatt Macy print_mapping_table_prefix(outfp); 911959826caSMatt Macy 912959826caSMatt Macy /* Skip first line (header) */ 913959826caSMatt Macy p = fgets(line, n, mapfp); 914959826caSMatt Macy if (!p) 915959826caSMatt Macy goto out; 916959826caSMatt Macy 917959826caSMatt Macy line_num = 1; 918959826caSMatt Macy while (1) { 919959826caSMatt Macy char *cpuid, *version, *type, *fname; 920959826caSMatt Macy 921959826caSMatt Macy line_num++; 922959826caSMatt Macy p = fgets(line, n, mapfp); 923959826caSMatt Macy if (!p) 924959826caSMatt Macy break; 925959826caSMatt Macy 926959826caSMatt Macy if (line[0] == '#' || line[0] == '\n') 927959826caSMatt Macy continue; 928959826caSMatt Macy 929959826caSMatt Macy if (line[strlen(line)-1] != '\n') { 930959826caSMatt Macy /* TODO Deal with lines longer than 16K */ 931959826caSMatt Macy pr_info("%s: Mapfile %s: line %d too long, aborting\n", 932959826caSMatt Macy prog, fpath, line_num); 93362ff619dSAlexander Motin ret = -1; 93462ff619dSAlexander Motin goto out; 935959826caSMatt Macy } 936959826caSMatt Macy line[strlen(line)-1] = '\0'; 937959826caSMatt Macy 938959826caSMatt Macy cpuid = fixregex(strtok_r(p, ",", &save)); 939959826caSMatt Macy version = strtok_r(NULL, ",", &save); 940959826caSMatt Macy fname = strtok_r(NULL, ",", &save); 941959826caSMatt Macy type = strtok_r(NULL, ",", &save); 942959826caSMatt Macy 943959826caSMatt Macy tblname = file_name_to_table_name(fname); 944959826caSMatt Macy fprintf(outfp, "{\n"); 945959826caSMatt Macy fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid); 946959826caSMatt Macy fprintf(outfp, "\t.version = \"%s\",\n", version); 947959826caSMatt Macy fprintf(outfp, "\t.type = \"%s\",\n", type); 948959826caSMatt Macy 949959826caSMatt Macy /* 950959826caSMatt Macy * CHECK: We can't use the type (eg "core") field in the 951959826caSMatt Macy * table name. For us to do that, we need to somehow tweak 952959826caSMatt Macy * the other caller of file_name_to_table(), process_json() 953959826caSMatt Macy * to determine the type. process_json() file has no way 954959826caSMatt Macy * of knowing these are "core" events unless file name has 955959826caSMatt Macy * core in it. If filename has core in it, we can safely 956959826caSMatt Macy * ignore the type field here also. 957959826caSMatt Macy */ 958959826caSMatt Macy fprintf(outfp, "\t.table = %s\n", tblname); 959959826caSMatt Macy fprintf(outfp, "},\n"); 960959826caSMatt Macy } 961959826caSMatt Macy 962959826caSMatt Macy out: 96362ff619dSAlexander Motin print_mapping_test_table(outfp); 964959826caSMatt Macy print_mapping_table_suffix(outfp); 9654644463cSEric van Gyzen fclose(mapfp); 96662ff619dSAlexander Motin free(line); 96762ff619dSAlexander Motin return ret; 968959826caSMatt Macy } 969959826caSMatt Macy 970959826caSMatt Macy /* 971959826caSMatt Macy * If we fail to locate/process JSON and map files, create a NULL mapping 972959826caSMatt Macy * table. This would at least allow perf to build even if we can't find/use 973959826caSMatt Macy * the aliases. 974959826caSMatt Macy */ 97551f32966SAlexander Motin static void create_empty_mapping(const char *output_file) 976959826caSMatt Macy { 977959826caSMatt Macy FILE *outfp; 978959826caSMatt Macy 979959826caSMatt Macy pr_info("%s: Creating empty pmu_events_map[] table\n", prog); 980959826caSMatt Macy 981959826caSMatt Macy /* Truncate file to clear any partial writes to it */ 982959826caSMatt Macy outfp = fopen(output_file, "w"); 983959826caSMatt Macy if (!outfp) { 984959826caSMatt Macy perror("fopen()"); 985959826caSMatt Macy _Exit(1); 986959826caSMatt Macy } 987959826caSMatt Macy 988959826caSMatt Macy fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n"); 989959826caSMatt Macy print_mapping_table_prefix(outfp); 990959826caSMatt Macy print_mapping_table_suffix(outfp); 99162ff619dSAlexander Motin print_system_event_mapping_table_prefix(outfp); 99262ff619dSAlexander Motin print_system_event_mapping_table_suffix(outfp); 993959826caSMatt Macy fclose(outfp); 994959826caSMatt Macy } 995959826caSMatt Macy 99651f32966SAlexander Motin static int get_maxfds(void) 997959826caSMatt Macy { 998959826caSMatt Macy struct rlimit rlim; 999959826caSMatt Macy 10002fa224b1SAlex Richardson if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 10012fa224b1SAlex Richardson if (rlim.rlim_max == RLIM_INFINITY) 10022fa224b1SAlex Richardson return 512; 1003b3d01a2aSEnji Cooper return MIN(rlim.rlim_max / 2, 512); 10042fa224b1SAlex Richardson } 1005959826caSMatt Macy 1006959826caSMatt Macy return 512; 1007959826caSMatt Macy } 1008959826caSMatt Macy 1009959826caSMatt Macy /* 1010959826caSMatt Macy * nftw() doesn't let us pass an argument to the processing function, 1011959826caSMatt Macy * so use a global variables. 1012959826caSMatt Macy */ 1013959826caSMatt Macy static FILE *eventsfp; 1014959826caSMatt Macy static char *mapfile; 1015959826caSMatt Macy 101651f32966SAlexander Motin static int is_leaf_dir(const char *fpath) 1017959826caSMatt Macy { 1018959826caSMatt Macy DIR *d; 1019959826caSMatt Macy struct dirent *dir; 1020959826caSMatt Macy int res = 1; 1021959826caSMatt Macy 1022959826caSMatt Macy d = opendir(fpath); 1023959826caSMatt Macy if (!d) 1024959826caSMatt Macy return 0; 1025959826caSMatt Macy 1026959826caSMatt Macy while ((dir = readdir(d)) != NULL) { 1027959826caSMatt Macy if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) 1028959826caSMatt Macy continue; 1029959826caSMatt Macy 1030959826caSMatt Macy if (dir->d_type == DT_DIR) { 1031959826caSMatt Macy res = 0; 1032959826caSMatt Macy break; 1033959826caSMatt Macy } else if (dir->d_type == DT_UNKNOWN) { 1034959826caSMatt Macy char path[PATH_MAX]; 1035959826caSMatt Macy struct stat st; 1036959826caSMatt Macy 103762ff619dSAlexander Motin snprintf(path, sizeof(path), "%s/%s", fpath, dir->d_name); 1038959826caSMatt Macy if (stat(path, &st)) 1039959826caSMatt Macy break; 1040959826caSMatt Macy 1041959826caSMatt Macy if (S_ISDIR(st.st_mode)) { 1042959826caSMatt Macy res = 0; 1043959826caSMatt Macy break; 1044959826caSMatt Macy } 1045959826caSMatt Macy } 1046959826caSMatt Macy } 1047959826caSMatt Macy 1048959826caSMatt Macy closedir(d); 1049959826caSMatt Macy 1050959826caSMatt Macy return res; 1051959826caSMatt Macy } 1052959826caSMatt Macy 105351f32966SAlexander Motin static int is_json_file(const char *name) 1054959826caSMatt Macy { 1055959826caSMatt Macy const char *suffix; 1056959826caSMatt Macy 1057959826caSMatt Macy if (strlen(name) < 5) 1058959826caSMatt Macy return 0; 1059959826caSMatt Macy 1060959826caSMatt Macy suffix = name + strlen(name) - 5; 1061959826caSMatt Macy 1062959826caSMatt Macy if (strncmp(suffix, ".json", 5) == 0) 1063959826caSMatt Macy return 1; 1064959826caSMatt Macy return 0; 1065959826caSMatt Macy } 1066959826caSMatt Macy 106751f32966SAlexander Motin static int preprocess_arch_std_files(const char *fpath, const struct stat *sb, 1068959826caSMatt Macy int typeflag, struct FTW *ftwbuf) 1069959826caSMatt Macy { 1070959826caSMatt Macy int level = ftwbuf->level; 1071959826caSMatt Macy int is_file = typeflag == FTW_F; 1072959826caSMatt Macy 1073959826caSMatt Macy if (level == 1 && is_file && is_json_file(fpath)) 1074959826caSMatt Macy return json_events(fpath, save_arch_std_events, (void *)(uintptr_t)sb); 1075959826caSMatt Macy 1076959826caSMatt Macy return 0; 1077959826caSMatt Macy } 1078959826caSMatt Macy 107951f32966SAlexander Motin static int process_one_file(const char *fpath, const struct stat *sb, 108051f32966SAlexander Motin int typeflag, struct FTW *ftwbuf) 1081959826caSMatt Macy { 108262ff619dSAlexander Motin char *tblname, *bname; 1083959826caSMatt Macy int is_dir = typeflag == FTW_D; 1084959826caSMatt Macy int is_file = typeflag == FTW_F; 1085959826caSMatt Macy int level = ftwbuf->level; 1086959826caSMatt Macy int err = 0; 1087959826caSMatt Macy 108862ff619dSAlexander Motin if (level >= 2 && is_dir) { 108962ff619dSAlexander Motin int count = 0; 1090959826caSMatt Macy /* 1091959826caSMatt Macy * For level 2 directory, bname will include parent name, 1092959826caSMatt Macy * like vendor/platform. So search back from platform dir 1093959826caSMatt Macy * to find this. 109462ff619dSAlexander Motin * Something similar for level 3 directory, but we're a PMU 109562ff619dSAlexander Motin * category folder, like vendor/platform/cpu. 1096959826caSMatt Macy */ 109762ff619dSAlexander Motin bname = (char *) fpath + ftwbuf->base - 2; 1098959826caSMatt Macy for (;;) { 1099959826caSMatt Macy if (*bname == '/') 110062ff619dSAlexander Motin count++; 110162ff619dSAlexander Motin if (count == level - 1) 1102959826caSMatt Macy break; 1103959826caSMatt Macy bname--; 1104959826caSMatt Macy } 1105959826caSMatt Macy bname++; 1106959826caSMatt Macy } else 110762ff619dSAlexander Motin bname = (char *) fpath + ftwbuf->base; 1108959826caSMatt Macy 1109959826caSMatt Macy pr_debug("%s %d %7jd %-20s %s\n", 1110959826caSMatt Macy is_file ? "f" : is_dir ? "d" : "x", 1111959826caSMatt Macy level, sb->st_size, bname, fpath); 1112959826caSMatt Macy 1113959826caSMatt Macy /* base dir or too deep */ 111462ff619dSAlexander Motin if (level == 0 || level > 4) 1115959826caSMatt Macy return 0; 1116959826caSMatt Macy 1117959826caSMatt Macy 1118959826caSMatt Macy /* model directory, reset topic */ 1119959826caSMatt Macy if ((level == 1 && is_dir && is_leaf_dir(fpath)) || 112062ff619dSAlexander Motin (level >= 2 && is_dir && is_leaf_dir(fpath))) { 1121959826caSMatt Macy if (close_table) 1122959826caSMatt Macy print_events_table_suffix(eventsfp); 1123959826caSMatt Macy 1124959826caSMatt Macy /* 1125959826caSMatt Macy * Drop file name suffix. Replace hyphens with underscores. 1126959826caSMatt Macy * Fail if file name contains any alphanum characters besides 1127959826caSMatt Macy * underscores. 1128959826caSMatt Macy */ 1129959826caSMatt Macy tblname = file_name_to_table_name(bname); 1130959826caSMatt Macy if (!tblname) { 1131959826caSMatt Macy pr_info("%s: Error determining table name for %s\n", prog, 1132959826caSMatt Macy bname); 1133959826caSMatt Macy return -1; 1134959826caSMatt Macy } 1135959826caSMatt Macy 113662ff619dSAlexander Motin if (is_sys_dir(bname)) { 113762ff619dSAlexander Motin struct sys_event_table *sys_event_table; 113862ff619dSAlexander Motin 113962ff619dSAlexander Motin sys_event_table = malloc(sizeof(*sys_event_table)); 114062ff619dSAlexander Motin if (!sys_event_table) 114162ff619dSAlexander Motin return -1; 114262ff619dSAlexander Motin 114362ff619dSAlexander Motin sys_event_table->soc_id = strdup(tblname); 114462ff619dSAlexander Motin if (!sys_event_table->soc_id) { 114562ff619dSAlexander Motin free(sys_event_table); 114662ff619dSAlexander Motin return -1; 114762ff619dSAlexander Motin } 114862ff619dSAlexander Motin list_add_tail(&sys_event_table->list, 114962ff619dSAlexander Motin &sys_event_tables); 115062ff619dSAlexander Motin } 115162ff619dSAlexander Motin 1152959826caSMatt Macy print_events_table_prefix(eventsfp, tblname); 1153959826caSMatt Macy return 0; 1154959826caSMatt Macy } 1155959826caSMatt Macy 1156959826caSMatt Macy /* 1157959826caSMatt Macy * Save the mapfile name for now. We will process mapfile 1158959826caSMatt Macy * after processing all JSON files (so we can write out the 1159959826caSMatt Macy * mapping table after all PMU events tables). 1160959826caSMatt Macy * 1161959826caSMatt Macy */ 1162959826caSMatt Macy if (level == 1 && is_file) { 1163959826caSMatt Macy if (!strcmp(bname, "mapfile.csv")) { 1164959826caSMatt Macy mapfile = strdup(fpath); 1165959826caSMatt Macy return 0; 1166959826caSMatt Macy } 116762ff619dSAlexander Motin if (is_json_file(bname)) 116862ff619dSAlexander Motin pr_debug("%s: ArchStd json is preprocessed %s\n", prog, fpath); 116962ff619dSAlexander Motin else 1170959826caSMatt Macy pr_info("%s: Ignoring file %s\n", prog, fpath); 1171959826caSMatt Macy return 0; 1172959826caSMatt Macy } 1173959826caSMatt Macy 1174959826caSMatt Macy /* 1175959826caSMatt Macy * If the file name does not have a .json extension, 1176959826caSMatt Macy * ignore it. It could be a readme.txt for instance. 1177959826caSMatt Macy */ 1178959826caSMatt Macy if (is_file) { 1179959826caSMatt Macy if (!is_json_file(bname)) { 1180959826caSMatt Macy pr_info("%s: Ignoring file without .json suffix %s\n", prog, 1181959826caSMatt Macy fpath); 1182959826caSMatt Macy return 0; 1183959826caSMatt Macy } 1184959826caSMatt Macy } 1185959826caSMatt Macy 1186959826caSMatt Macy if (level > 1 && add_topic(bname)) 1187959826caSMatt Macy return -ENOMEM; 1188959826caSMatt Macy 1189959826caSMatt Macy /* 1190959826caSMatt Macy * Assume all other files are JSON files. 1191959826caSMatt Macy * 1192959826caSMatt Macy * If mapfile refers to 'power7_core.json', we create a table 1193959826caSMatt Macy * named 'power7_core'. Any inconsistencies between the mapfile 1194959826caSMatt Macy * and directory tree could result in build failure due to table 1195959826caSMatt Macy * names not being found. 1196959826caSMatt Macy * 1197959826caSMatt Macy * At least for now, be strict with processing JSON file names. 1198959826caSMatt Macy * i.e. if JSON file name cannot be mapped to C-style table name, 1199959826caSMatt Macy * fail. 1200959826caSMatt Macy */ 1201959826caSMatt Macy if (is_file) { 1202959826caSMatt Macy struct perf_entry_data data = { 1203959826caSMatt Macy .topic = get_topic(), 1204959826caSMatt Macy .outfp = eventsfp, 1205959826caSMatt Macy }; 1206959826caSMatt Macy 1207959826caSMatt Macy err = json_events(fpath, print_events_table_entry, &data); 1208959826caSMatt Macy 1209959826caSMatt Macy free(data.topic); 1210959826caSMatt Macy } 1211959826caSMatt Macy 1212959826caSMatt Macy return err; 1213959826caSMatt Macy } 1214959826caSMatt Macy 121562ff619dSAlexander Motin #ifndef PATH_MAX 121662ff619dSAlexander Motin #define PATH_MAX 4096 121762ff619dSAlexander Motin #endif 121862ff619dSAlexander Motin 1219959826caSMatt Macy /* 1220959826caSMatt Macy * Starting in directory 'start_dirname', find the "mapfile.csv" and 1221959826caSMatt Macy * the set of JSON files for the architecture 'arch'. 1222959826caSMatt Macy * 1223959826caSMatt Macy * From each JSON file, create a C-style "PMU events table" from the 1224959826caSMatt Macy * JSON file (see struct pmu_event). 1225959826caSMatt Macy * 1226959826caSMatt Macy * From the mapfile, create a mapping between the CPU revisions and 1227959826caSMatt Macy * PMU event tables (see struct pmu_events_map). 1228959826caSMatt Macy * 1229959826caSMatt Macy * Write out the PMU events tables and the mapping table to pmu-event.c. 1230959826caSMatt Macy */ 123151f32966SAlexander Motin int main(int argc, char *argv[]) 1232959826caSMatt Macy { 123362ff619dSAlexander Motin int rc, ret = 0, empty_map = 0; 1234959826caSMatt Macy int maxfds; 1235959826caSMatt Macy char ldirname[PATH_MAX]; 1236959826caSMatt Macy const char *arch; 1237959826caSMatt Macy const char *output_file; 1238959826caSMatt Macy const char *start_dirname; 123962ff619dSAlexander Motin const char *err_string_ext = ""; 1240959826caSMatt Macy struct stat stbuf; 1241959826caSMatt Macy 1242959826caSMatt Macy prog = basename(argv[0]); 1243959826caSMatt Macy if (argc < 4) { 1244959826caSMatt Macy pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog); 1245959826caSMatt Macy return 1; 1246959826caSMatt Macy } 1247959826caSMatt Macy 1248959826caSMatt Macy arch = argv[1]; 1249959826caSMatt Macy start_dirname = argv[2]; 1250959826caSMatt Macy output_file = argv[3]; 1251959826caSMatt Macy 1252959826caSMatt Macy if (argc > 4) 1253959826caSMatt Macy verbose = atoi(argv[4]); 1254959826caSMatt Macy 1255959826caSMatt Macy eventsfp = fopen(output_file, "w"); 1256959826caSMatt Macy if (!eventsfp) { 1257959826caSMatt Macy pr_err("%s Unable to create required file %s (%s)\n", 1258959826caSMatt Macy prog, output_file, strerror(errno)); 1259959826caSMatt Macy return 2; 1260959826caSMatt Macy } 1261959826caSMatt Macy 1262f824ea0cSConrad Meyer snprintf(ldirname, sizeof(ldirname), "%s/%s", start_dirname, arch); 1263959826caSMatt Macy 1264959826caSMatt Macy /* If architecture does not have any event lists, bail out */ 1265959826caSMatt Macy if (stat(ldirname, &stbuf) < 0) { 1266959826caSMatt Macy pr_info("%s: Arch %s has no PMU event lists\n", prog, arch); 126762ff619dSAlexander Motin empty_map = 1; 126862ff619dSAlexander Motin goto err_close_eventsfp; 1269959826caSMatt Macy } 1270959826caSMatt Macy 1271959826caSMatt Macy /* Include pmu-events.h first */ 1272959826caSMatt Macy fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n"); 1273959826caSMatt Macy 1274959826caSMatt Macy /* 1275959826caSMatt Macy * The mapfile allows multiple CPUids to point to the same JSON file, 1276959826caSMatt Macy * so, not sure if there is a need for symlinks within the pmu-events 1277959826caSMatt Macy * directory. 1278959826caSMatt Macy * 1279959826caSMatt Macy * For now, treat symlinks of JSON files as regular files and create 1280959826caSMatt Macy * separate tables for each symlink (presumably, each symlink refers 1281959826caSMatt Macy * to specific version of the CPU). 1282959826caSMatt Macy */ 1283959826caSMatt Macy 1284959826caSMatt Macy maxfds = get_maxfds(); 128562ff619dSAlexander Motin rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0); 128662ff619dSAlexander Motin if (rc) 128762ff619dSAlexander Motin goto err_processing_std_arch_event_dir; 1288959826caSMatt Macy 128962ff619dSAlexander Motin rc = nftw(ldirname, process_one_file, maxfds, 0); 129062ff619dSAlexander Motin if (rc) 129162ff619dSAlexander Motin goto err_processing_dir; 129262ff619dSAlexander Motin 129362ff619dSAlexander Motin sprintf(ldirname, "%s/test", start_dirname); 129462ff619dSAlexander Motin 129562ff619dSAlexander Motin rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0); 129662ff619dSAlexander Motin if (rc) 129762ff619dSAlexander Motin goto err_processing_std_arch_event_dir; 129862ff619dSAlexander Motin 129962ff619dSAlexander Motin rc = nftw(ldirname, process_one_file, maxfds, 0); 130062ff619dSAlexander Motin if (rc) 130162ff619dSAlexander Motin goto err_processing_dir; 1302959826caSMatt Macy 1303959826caSMatt Macy if (close_table) 1304959826caSMatt Macy print_events_table_suffix(eventsfp); 1305959826caSMatt Macy 1306959826caSMatt Macy if (!mapfile) { 1307959826caSMatt Macy pr_info("%s: No CPU->JSON mapping?\n", prog); 130862ff619dSAlexander Motin empty_map = 1; 130962ff619dSAlexander Motin goto err_close_eventsfp; 1310959826caSMatt Macy } 1311959826caSMatt Macy 131262ff619dSAlexander Motin rc = process_mapfile(eventsfp, mapfile); 131362ff619dSAlexander Motin if (rc) { 1314959826caSMatt Macy pr_info("%s: Error processing mapfile %s\n", prog, mapfile); 1315959826caSMatt Macy /* Make build fail */ 131662ff619dSAlexander Motin ret = 1; 131762ff619dSAlexander Motin goto err_close_eventsfp; 1318959826caSMatt Macy } 1319959826caSMatt Macy 132062ff619dSAlexander Motin rc = process_system_event_tables(eventsfp); 132162ff619dSAlexander Motin fclose(eventsfp); 132262ff619dSAlexander Motin if (rc) { 132362ff619dSAlexander Motin ret = 1; 132462ff619dSAlexander Motin goto err_out; 132562ff619dSAlexander Motin } 132662ff619dSAlexander Motin 132762ff619dSAlexander Motin free_arch_std_events(); 132862ff619dSAlexander Motin free_sys_event_tables(); 132962ff619dSAlexander Motin free(mapfile); 1330959826caSMatt Macy return 0; 1331959826caSMatt Macy 133262ff619dSAlexander Motin err_processing_std_arch_event_dir: 133362ff619dSAlexander Motin err_string_ext = " for std arch event"; 133462ff619dSAlexander Motin err_processing_dir: 133562ff619dSAlexander Motin if (verbose) { 133662ff619dSAlexander Motin pr_info("%s: Error walking file tree %s%s\n", prog, ldirname, 133762ff619dSAlexander Motin err_string_ext); 133862ff619dSAlexander Motin empty_map = 1; 133962ff619dSAlexander Motin } else if (rc < 0) { 134062ff619dSAlexander Motin ret = 1; 134162ff619dSAlexander Motin } else { 134262ff619dSAlexander Motin empty_map = 1; 134362ff619dSAlexander Motin } 134462ff619dSAlexander Motin err_close_eventsfp: 1345959826caSMatt Macy fclose(eventsfp); 134662ff619dSAlexander Motin if (empty_map) 1347959826caSMatt Macy create_empty_mapping(output_file); 134862ff619dSAlexander Motin err_out: 1349959826caSMatt Macy free_arch_std_events(); 135062ff619dSAlexander Motin free_sys_event_tables(); 135162ff619dSAlexander Motin free(mapfile); 135262ff619dSAlexander Motin return ret; 1353959826caSMatt Macy } 1354334fd3daSMatt Macy 135551f32966SAlexander Motin #include <fts.h> 135651f32966SAlexander Motin 1357334fd3daSMatt Macy static int 1358*364c014dSWarner Losh #if defined(__linux__) || defined(__APPLE__) 135960e845ceSAlex Richardson fts_compare(const FTSENT **a, const FTSENT **b) 136060e845ceSAlex Richardson #else 1361334fd3daSMatt Macy fts_compare(const FTSENT * const *a, const FTSENT * const *b) 136260e845ceSAlex Richardson #endif 1363334fd3daSMatt Macy { 1364334fd3daSMatt Macy return (strcmp((*a)->fts_name, (*b)->fts_name)); 1365334fd3daSMatt Macy } 1366334fd3daSMatt Macy 1367334fd3daSMatt Macy static int 1368334fd3daSMatt Macy nftw_ordered(const char *path, int (*fn)(const char *, const struct stat *, int, 1369334fd3daSMatt Macy struct FTW *), int nfds, int ftwflags) 1370334fd3daSMatt Macy { 1371334fd3daSMatt Macy char * const paths[2] = { (char *)path, NULL }; 1372334fd3daSMatt Macy struct FTW ftw; 1373334fd3daSMatt Macy FTSENT *cur; 1374334fd3daSMatt Macy FTS *ftsp; 1375334fd3daSMatt Macy int error = 0, ftsflags, fnflag, postorder, sverrno; 1376334fd3daSMatt Macy 1377334fd3daSMatt Macy /* XXX - nfds is currently unused */ 1378334fd3daSMatt Macy if (nfds < 1) { 1379334fd3daSMatt Macy errno = EINVAL; 1380334fd3daSMatt Macy return (-1); 1381334fd3daSMatt Macy } 1382334fd3daSMatt Macy 1383334fd3daSMatt Macy ftsflags = FTS_COMFOLLOW; 1384334fd3daSMatt Macy if (!(ftwflags & FTW_CHDIR)) 1385334fd3daSMatt Macy ftsflags |= FTS_NOCHDIR; 1386334fd3daSMatt Macy if (ftwflags & FTW_MOUNT) 1387334fd3daSMatt Macy ftsflags |= FTS_XDEV; 1388334fd3daSMatt Macy if (ftwflags & FTW_PHYS) 1389334fd3daSMatt Macy ftsflags |= FTS_PHYSICAL; 1390334fd3daSMatt Macy else 1391334fd3daSMatt Macy ftsflags |= FTS_LOGICAL; 1392334fd3daSMatt Macy postorder = (ftwflags & FTW_DEPTH) != 0; 1393334fd3daSMatt Macy ftsp = fts_open(paths, ftsflags, fts_compare); 1394334fd3daSMatt Macy if (ftsp == NULL) 1395334fd3daSMatt Macy return (-1); 1396334fd3daSMatt Macy while ((cur = fts_read(ftsp)) != NULL) { 1397334fd3daSMatt Macy switch (cur->fts_info) { 1398334fd3daSMatt Macy case FTS_D: 1399334fd3daSMatt Macy if (postorder) 1400334fd3daSMatt Macy continue; 1401334fd3daSMatt Macy fnflag = FTW_D; 1402334fd3daSMatt Macy break; 1403334fd3daSMatt Macy case FTS_DC: 1404334fd3daSMatt Macy continue; 1405334fd3daSMatt Macy case FTS_DNR: 1406334fd3daSMatt Macy fnflag = FTW_DNR; 1407334fd3daSMatt Macy break; 1408334fd3daSMatt Macy case FTS_DP: 1409334fd3daSMatt Macy if (!postorder) 1410334fd3daSMatt Macy continue; 1411334fd3daSMatt Macy fnflag = FTW_DP; 1412334fd3daSMatt Macy break; 1413334fd3daSMatt Macy case FTS_F: 1414334fd3daSMatt Macy case FTS_DEFAULT: 1415334fd3daSMatt Macy fnflag = FTW_F; 1416334fd3daSMatt Macy break; 1417334fd3daSMatt Macy case FTS_NS: 1418334fd3daSMatt Macy case FTS_NSOK: 1419334fd3daSMatt Macy fnflag = FTW_NS; 1420334fd3daSMatt Macy break; 1421334fd3daSMatt Macy case FTS_SL: 1422334fd3daSMatt Macy fnflag = FTW_SL; 1423334fd3daSMatt Macy break; 1424334fd3daSMatt Macy case FTS_SLNONE: 1425334fd3daSMatt Macy fnflag = FTW_SLN; 1426334fd3daSMatt Macy break; 1427334fd3daSMatt Macy default: 1428334fd3daSMatt Macy error = -1; 1429334fd3daSMatt Macy goto done; 1430334fd3daSMatt Macy } 1431334fd3daSMatt Macy ftw.base = cur->fts_pathlen - cur->fts_namelen; 1432334fd3daSMatt Macy ftw.level = cur->fts_level; 1433334fd3daSMatt Macy error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); 1434334fd3daSMatt Macy if (error != 0) 1435334fd3daSMatt Macy break; 1436334fd3daSMatt Macy } 1437334fd3daSMatt Macy done: 1438334fd3daSMatt Macy sverrno = errno; 1439334fd3daSMatt Macy if (fts_close(ftsp) != 0 && error == 0) 1440334fd3daSMatt Macy error = -1; 1441334fd3daSMatt Macy else 1442334fd3daSMatt Macy errno = sverrno; 1443334fd3daSMatt Macy return (error); 1444334fd3daSMatt Macy } 1445