Linux Audio

Check our new training course

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