static int match_field(char *map, jsmntok_t *field, int nz, char **event, jsmntok_t *val) { struct field *f; jsmntok_t newval = *val; for (f = fields; f->field; f++) if (json_streq(map, field, f->field) && nz) { if (json_streq(map, val, "0x00") || json_streq(map, val, "0x0")) return 1; cut_comma(map, &newval); addfield(map, event, ",", f->kernel, &newval); return 1; } return 0; }
static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val) { int i; for (i = 0; table[i].json; i++) { if (json_streq(map, val, table[i].json)) return table[i].perf; } return NULL; }
static struct msrmap *lookup_msr(char *map, jsmntok_t *val) { jsmntok_t newval = *val; static bool warned = false; int i; cut_comma(map, &newval); for (i = 0; msrmap[i].num; i++) if (json_streq(map, &newval, msrmap[i].num)) return &msrmap[i]; if (!warned) { warned = true; fprintf(stderr, "Unknown MSR in event file %.*s\n", json_len(val), map + val->start); } return NULL; }
static struct msrmap *lookup_msr(char *map, jsmntok_t *val) { jsmntok_t newval = *val; static bool warned = false; int i; cut_comma(map, &newval); for (i = 0; msrmap[i].num; i++) if (json_streq(map, &newval, msrmap[i].num)) return &msrmap[i]; if (!warned && strncmp(map + val->start, "0x3F7", 5)) { /* no warning for Skylake PEBS Frontend MSR */ warned = true; fprintf(stderr, "Unknown MSR in event file %.*s\n", json_len(val), map + val->start); } return NULL; }
/** * json_events - Read JSON event file from disk and call event callback. * @fn: File name to read or NULL for default. * @func: Callback to call for each event * @data: Abstract pointer to pass to func. * * The callback gets the data pointer, the event name, the event * in perf format and a description passed. * * Call func with each event in the json file * Return: -1 on failure, otherwise 0. */ int json_events(const char *fn, int (*func)(void *data, char *name, char *event, char *desc, char *pmu), void *data) { int err = -EIO; size_t size; jsmntok_t *tokens, *tok; int i, j, len; char *map; char buf[128]; const char *orig_fn = fn; if (!fn) fn = json_default_name("-core"); tokens = parse_json(fn, &map, &size, &len); if (!tokens) return -EIO; EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array"); tok = tokens + 1; for (i = 0; i < tokens->size; i++) { char *event = NULL, *desc = NULL, *name = NULL; char *pmu = NULL; char *filter = NULL; unsigned long long eventcode = 0; struct msrmap *msr = NULL; jsmntok_t *msrval = NULL; jsmntok_t *precise = NULL; jsmntok_t *obj = tok++; EXPECT(obj->type == JSMN_OBJECT, obj, "expected object"); for (j = 0; j < obj->size; j += 2) { jsmntok_t *field, *val; int nz; field = tok + j; EXPECT(field->type == JSMN_STRING, tok + j, "Expected field name"); val = tok + j + 1; EXPECT(val->type == JSMN_STRING, tok + j + 1, "Expected string value"); nz = !json_streq(map, val, "0"); if (match_field(map, field, nz, &event, val)) { /* ok */ } else if (json_streq(map, field, "EventCode")) { char *code = NULL; addfield(map, &code, "", "", val); eventcode |= strtoul(code, NULL, 0); free(code); } else if (json_streq(map, field, "ExtSel")) { char *code = NULL; addfield(map, &code, "", "", val); eventcode |= strtoul(code, NULL, 0) << 21; free(code); } else if (json_streq(map, field, "EventName")) { addfield(map, &name, "", "", val); } else if (json_streq(map, field, "BriefDescription")) { addfield(map, &desc, "", "", val); fixdesc(desc); } else if (json_streq(map, field, "PEBS") && nz && desc && !strstr(desc, "(Precise Event)")) { precise = val; } else if (json_streq(map, field, "MSRIndex") && nz) { msr = lookup_msr(map, val); } else if (json_streq(map, field, "MSRValue")) { msrval = val; } else if (json_streq(map, field, "Errata") && !json_streq(map, val, "null")) { addfield(map, &desc, ". ", " Spec update: ", val); } else if (json_streq(map, field, "Data_LA") && nz) { addfield(map, &desc, ". ", " Supports address when precise", NULL); } else if (json_streq(map, field, "Unit")) { const char *ppmu; char *s; ppmu = field_to_perf(unit_to_pmu, map, val); if (ppmu) { pmu = strdup(ppmu); } else { addfield(map, &pmu, "", "", val); for (s = pmu; *s; s++) *s = tolower(*s); } addfield(map, &desc, ". ", "Unit: ", NULL); addfield(map, &desc, "", pmu, NULL); } else if (json_streq(map, field, "Filter")) { addfield(map, &filter, "", "", val); } /* ignore unknown fields */ } if (precise) { if (json_streq(map, precise, "2")) addfield(map, &desc, " ", "(Must be precise)", NULL); else addfield(map, &desc, " ", "(Precise event)", NULL); } snprintf(buf, sizeof buf, "event=%#llx", eventcode); addfield(map, &event, ",", buf, NULL); if (filter) addfield(map, &event, ",", filter, NULL); if (msr != NULL) addfield(map, &event, ",", msr->pname, msrval); if (!pmu) pmu = strdup("cpu"); err = -EIO; if (name && event) { fixname(name); err = func(data, name, event, desc, pmu); } free(event); free(desc); free(name); free(pmu); free(filter); if (err) break; tok += j; } EXPECT(tok - tokens == len, tok, "unexpected objects at end"); err = 0; out_free: free_json(map, size, tokens); if (!orig_fn && !err) { fn = json_default_name("-uncore"); err = json_events(fn, func, data); /* Ignore open error */ if (err == -EIO) return 0; } if (!orig_fn) free((char *)fn); return err; }
/** * json_events - Read JSON event file from disk and call event callback. * @fn: File name to read or NULL for default. * @func: Callback to call for each event * @data: Abstract pointer to pass to func. * * The callback gets the data pointer, the event name, the event * in perf format and a description passed. * * Call func with each event in the json file * Return: -1 on failure, otherwise 0. */ int json_events(const char *fn, int (*func)(void *data, char *name, char *event, char *desc), void *data) { int err = -EIO; size_t size; jsmntok_t *tokens, *tok; int i, j, len; char *map; if (!fn) fn = json_default_name(); tokens = parse_json(fn, &map, &size, &len); if (!tokens) return -EIO; EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array"); tok = tokens + 1; for (i = 0; i < tokens->size; i++) { char *event = NULL, *desc = NULL, *name = NULL; struct msrmap *msr = NULL; jsmntok_t *msrval = NULL; jsmntok_t *precise = NULL; jsmntok_t *obj = tok++; EXPECT(obj->type == JSMN_OBJECT, obj, "expected object"); for (j = 0; j < obj->size; j += 2) { jsmntok_t *field, *val; int nz; field = tok + j; EXPECT(field->type == JSMN_STRING, tok + j, "Expected field name"); val = tok + j + 1; EXPECT(val->type == JSMN_STRING, tok + j + 1, "Expected string value"); nz = !json_streq(map, val, "0"); if (match_field(map, field, nz, &event, val)) { /* ok */ } else if (json_streq(map, field, "EventName")) { addfield(map, &name, "", "", val); } else if (json_streq(map, field, "BriefDescription")) { addfield(map, &desc, "", "", val); fixdesc(desc); } else if (json_streq(map, field, "PEBS") && nz && desc && !strstr(desc, "(Precise Event)")) { precise = val; } else if (json_streq(map, field, "MSRIndex") && nz) { msr = lookup_msr(map, val); } else if (json_streq(map, field, "MSRValue")) { msrval = val; } else if (json_streq(map, field, "Errata") && !json_streq(map, val, "null")) { addfield(map, &desc, ". ", " Spec update: ", val); } else if (json_streq(map, field, "Data_LA") && nz) { addfield(map, &desc, ". ", " Supports address when precise", NULL); } /* ignore unknown fields */ } if (precise) { if (json_streq(map, precise, "2")) addfield(map, &desc, " ", "(Must be precise)", NULL); else addfield(map, &desc, " ", "(Precise event)", NULL); } if (msr != NULL) addfield(map, &event, ",", msr->pname, msrval); err = -EIO; if (name && event) { fixname(name); err = func(data, name, event, desc); } free(event); free(desc); free(name); if (err) break; tok += j; } EXPECT(tok - tokens == len, tok, "unexpected objects at end"); err = 0; out_free: free_json(map, size, tokens); return err; }