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