cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

jevents.c (32385B)


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