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