This source file includes following definitions.
- eprintf
- get_cpu_str
- addfield
- fixname
- fixdesc
- fixregex
- cut_comma
- match_field
- lookup_msr
- field_to_perf
- get_topic
- add_topic
- print_events_table_prefix
- print_events_table_entry
- free_arch_std_events
- save_arch_std_events
- print_events_table_suffix
- real_event
- try_fixup
- json_events
- file_name_to_table_name
- print_mapping_table_prefix
- print_mapping_table_suffix
- process_mapfile
- create_empty_mapping
- get_maxfds
- is_leaf_dir
- is_json_file
- preprocess_arch_std_files
- process_one_file
- main
1 #define _XOPEN_SOURCE 500
2 #define _GNU_SOURCE
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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>
45 #include <sys/resource.h>
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
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
114 --e;
115 while (e >= s && isspace(*e))
116 --e;
117 if (*e == '.')
118 *e = 0;
119 }
120
121
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
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
140 fixed = (char *) malloc(len + 1);
141 if (!fixed)
142 return NULL;
143
144
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
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 { "CPU-M-CF", "cpum_cf" },
237 { "CPU-M-SF", "cpum_sf" },
238 { "UPI LL", "uncore_upi" },
239 { "hisi_sccl,ddrc", "hisi_sccl,ddrc" },
240 { "hisi_sccl,hha", "hisi_sccl,hha" },
241 { "hisi_sccl,l3c", "hisi_sccl,l3c" },
242 { "L3PMC", "amd_l3" },
243 {}
244 };
245
246 static const char *field_to_perf(struct map *table, char *map, jsmntok_t *val)
247 {
248 int i;
249
250 for (i = 0; table[i].json; i++) {
251 if (json_streq(map, val, table[i].json))
252 return table[i].perf;
253 }
254 return NULL;
255 }
256
257 #define EXPECT(e, t, m) do { if (!(e)) { \
258 jsmntok_t *loc = (t); \
259 if (!(t)->start && (t) > tokens) \
260 loc = (t) - 1; \
261 pr_err("%s:%d: " m ", got %s\n", fn, \
262 json_line(map, loc), \
263 json_name(t)); \
264 err = -EIO; \
265 goto out_free; \
266 } } while (0)
267
268 static char *topic;
269
270 static char *get_topic(void)
271 {
272 char *tp;
273 int i;
274
275
276 i = asprintf(&tp, "%s", topic);
277 if (i < 0) {
278 pr_info("%s: asprintf() error %s\n", prog);
279 return NULL;
280 }
281
282 for (i = 0; i < (int) strlen(tp); i++) {
283 char c = tp[i];
284
285 if (c == '-')
286 tp[i] = ' ';
287 else if (c == '.') {
288 tp[i] = '\0';
289 break;
290 }
291 }
292
293 return tp;
294 }
295
296 static int add_topic(char *bname)
297 {
298 free(topic);
299 topic = strdup(bname);
300 if (!topic) {
301 pr_info("%s: strdup() error %s for file %s\n", prog,
302 strerror(errno), bname);
303 return -ENOMEM;
304 }
305 return 0;
306 }
307
308 struct perf_entry_data {
309 FILE *outfp;
310 char *topic;
311 };
312
313 static int close_table;
314
315 static void print_events_table_prefix(FILE *fp, const char *tblname)
316 {
317 fprintf(fp, "struct pmu_event %s[] = {\n", tblname);
318 close_table = 1;
319 }
320
321 static int print_events_table_entry(void *data, char *name, char *event,
322 char *desc, char *long_desc,
323 char *pmu, char *unit, char *perpkg,
324 char *metric_expr,
325 char *metric_name, char *metric_group)
326 {
327 struct perf_entry_data *pd = data;
328 FILE *outfp = pd->outfp;
329 char *topic = pd->topic;
330
331
332
333
334
335 fprintf(outfp, "{\n");
336
337 if (name)
338 fprintf(outfp, "\t.name = \"%s\",\n", name);
339 if (event)
340 fprintf(outfp, "\t.event = \"%s\",\n", event);
341 fprintf(outfp, "\t.desc = \"%s\",\n", desc);
342 fprintf(outfp, "\t.topic = \"%s\",\n", topic);
343 if (long_desc && long_desc[0])
344 fprintf(outfp, "\t.long_desc = \"%s\",\n", long_desc);
345 if (pmu)
346 fprintf(outfp, "\t.pmu = \"%s\",\n", pmu);
347 if (unit)
348 fprintf(outfp, "\t.unit = \"%s\",\n", unit);
349 if (perpkg)
350 fprintf(outfp, "\t.perpkg = \"%s\",\n", perpkg);
351 if (metric_expr)
352 fprintf(outfp, "\t.metric_expr = \"%s\",\n", metric_expr);
353 if (metric_name)
354 fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
355 if (metric_group)
356 fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
357 fprintf(outfp, "},\n");
358
359 return 0;
360 }
361
362 struct event_struct {
363 struct list_head list;
364 char *name;
365 char *event;
366 char *desc;
367 char *long_desc;
368 char *pmu;
369 char *unit;
370 char *perpkg;
371 char *metric_expr;
372 char *metric_name;
373 char *metric_group;
374 };
375
376 #define ADD_EVENT_FIELD(field) do { if (field) { \
377 es->field = strdup(field); \
378 if (!es->field) \
379 goto out_free; \
380 } } while (0)
381
382 #define FREE_EVENT_FIELD(field) free(es->field)
383
384 #define TRY_FIXUP_FIELD(field) do { if (es->field && !*field) {\
385 *field = strdup(es->field); \
386 if (!*field) \
387 return -ENOMEM; \
388 } } while (0)
389
390 #define FOR_ALL_EVENT_STRUCT_FIELDS(op) do { \
391 op(name); \
392 op(event); \
393 op(desc); \
394 op(long_desc); \
395 op(pmu); \
396 op(unit); \
397 op(perpkg); \
398 op(metric_expr); \
399 op(metric_name); \
400 op(metric_group); \
401 } while (0)
402
403 static LIST_HEAD(arch_std_events);
404
405 static void free_arch_std_events(void)
406 {
407 struct event_struct *es, *next;
408
409 list_for_each_entry_safe(es, next, &arch_std_events, list) {
410 FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
411 list_del_init(&es->list);
412 free(es);
413 }
414 }
415
416 static int save_arch_std_events(void *data, char *name, char *event,
417 char *desc, char *long_desc, char *pmu,
418 char *unit, char *perpkg, char *metric_expr,
419 char *metric_name, char *metric_group)
420 {
421 struct event_struct *es;
422
423 es = malloc(sizeof(*es));
424 if (!es)
425 return -ENOMEM;
426 memset(es, 0, sizeof(*es));
427 FOR_ALL_EVENT_STRUCT_FIELDS(ADD_EVENT_FIELD);
428 list_add_tail(&es->list, &arch_std_events);
429 return 0;
430 out_free:
431 FOR_ALL_EVENT_STRUCT_FIELDS(FREE_EVENT_FIELD);
432 free(es);
433 return -ENOMEM;
434 }
435
436 static void print_events_table_suffix(FILE *outfp)
437 {
438 fprintf(outfp, "{\n");
439
440 fprintf(outfp, "\t.name = 0,\n");
441 fprintf(outfp, "\t.event = 0,\n");
442 fprintf(outfp, "\t.desc = 0,\n");
443
444 fprintf(outfp, "},\n");
445 fprintf(outfp, "};\n");
446 close_table = 0;
447 }
448
449 static struct fixed {
450 const char *name;
451 const char *event;
452 } fixed[] = {
453 { "inst_retired.any", "event=0xc0,period=2000003" },
454 { "inst_retired.any_p", "event=0xc0,period=2000003" },
455 { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03,period=2000003" },
456 { "cpu_clk_unhalted.thread", "event=0x3c,period=2000003" },
457 { "cpu_clk_unhalted.core", "event=0x3c,period=2000003" },
458 { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1,period=2000003" },
459 { NULL, NULL},
460 };
461
462
463
464
465 static char *real_event(const char *name, char *event)
466 {
467 int i;
468
469 if (!name)
470 return NULL;
471
472 for (i = 0; fixed[i].name; i++)
473 if (!strcasecmp(name, fixed[i].name))
474 return (char *)fixed[i].event;
475 return event;
476 }
477
478 static int
479 try_fixup(const char *fn, char *arch_std, char **event, char **desc,
480 char **name, char **long_desc, char **pmu, char **filter,
481 char **perpkg, char **unit, char **metric_expr, char **metric_name,
482 char **metric_group, unsigned long long eventcode)
483 {
484
485 struct event_struct *es;
486
487 list_for_each_entry(es, &arch_std_events, list) {
488 if (!strcmp(arch_std, es->name)) {
489 if (!eventcode && es->event) {
490
491 free(*event);
492 *event = NULL;
493 }
494 FOR_ALL_EVENT_STRUCT_FIELDS(TRY_FIXUP_FIELD);
495 return 0;
496 }
497 }
498
499 pr_err("%s: could not find matching %s for %s\n",
500 prog, arch_std, fn);
501 return -1;
502 }
503
504
505 int json_events(const char *fn,
506 int (*func)(void *data, char *name, char *event, char *desc,
507 char *long_desc,
508 char *pmu, char *unit, char *perpkg,
509 char *metric_expr,
510 char *metric_name, char *metric_group),
511 void *data)
512 {
513 int err;
514 size_t size;
515 jsmntok_t *tokens, *tok;
516 int i, j, len;
517 char *map;
518 char buf[128];
519
520 if (!fn)
521 return -ENOENT;
522
523 tokens = parse_json(fn, &map, &size, &len);
524 if (!tokens)
525 return -EIO;
526 EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array");
527 tok = tokens + 1;
528 for (i = 0; i < tokens->size; i++) {
529 char *event = NULL, *desc = NULL, *name = NULL;
530 char *long_desc = NULL;
531 char *extra_desc = NULL;
532 char *pmu = NULL;
533 char *filter = NULL;
534 char *perpkg = NULL;
535 char *unit = NULL;
536 char *metric_expr = NULL;
537 char *metric_name = NULL;
538 char *metric_group = NULL;
539 char *arch_std = NULL;
540 unsigned long long eventcode = 0;
541 struct msrmap *msr = NULL;
542 jsmntok_t *msrval = NULL;
543 jsmntok_t *precise = NULL;
544 jsmntok_t *obj = tok++;
545
546 EXPECT(obj->type == JSMN_OBJECT, obj, "expected object");
547 for (j = 0; j < obj->size; j += 2) {
548 jsmntok_t *field, *val;
549 int nz;
550 char *s;
551
552 field = tok + j;
553 EXPECT(field->type == JSMN_STRING, tok + j,
554 "Expected field name");
555 val = tok + j + 1;
556 EXPECT(val->type == JSMN_STRING, tok + j + 1,
557 "Expected string value");
558
559 nz = !json_streq(map, val, "0");
560 if (match_field(map, field, nz, &event, val)) {
561
562 } else if (json_streq(map, field, "EventCode")) {
563 char *code = NULL;
564 addfield(map, &code, "", "", val);
565 eventcode |= strtoul(code, NULL, 0);
566 free(code);
567 } else if (json_streq(map, field, "ExtSel")) {
568 char *code = NULL;
569 addfield(map, &code, "", "", val);
570 eventcode |= strtoul(code, NULL, 0) << 21;
571 free(code);
572 } else if (json_streq(map, field, "EventName")) {
573 addfield(map, &name, "", "", val);
574 } else if (json_streq(map, field, "BriefDescription")) {
575 addfield(map, &desc, "", "", val);
576 fixdesc(desc);
577 } else if (json_streq(map, field,
578 "PublicDescription")) {
579 addfield(map, &long_desc, "", "", val);
580 fixdesc(long_desc);
581 } else if (json_streq(map, field, "PEBS") && nz) {
582 precise = val;
583 } else if (json_streq(map, field, "MSRIndex") && nz) {
584 msr = lookup_msr(map, val);
585 } else if (json_streq(map, field, "MSRValue")) {
586 msrval = val;
587 } else if (json_streq(map, field, "Errata") &&
588 !json_streq(map, val, "null")) {
589 addfield(map, &extra_desc, ". ",
590 " Spec update: ", val);
591 } else if (json_streq(map, field, "Data_LA") && nz) {
592 addfield(map, &extra_desc, ". ",
593 " Supports address when precise",
594 NULL);
595 } else if (json_streq(map, field, "Unit")) {
596 const char *ppmu;
597
598 ppmu = field_to_perf(unit_to_pmu, map, val);
599 if (ppmu) {
600 pmu = strdup(ppmu);
601 } else {
602 if (!pmu)
603 pmu = strdup("uncore_");
604 addfield(map, &pmu, "", "", val);
605 for (s = pmu; *s; s++)
606 *s = tolower(*s);
607 }
608 addfield(map, &desc, ". ", "Unit: ", NULL);
609 addfield(map, &desc, "", pmu, NULL);
610 addfield(map, &desc, "", " ", NULL);
611 } else if (json_streq(map, field, "Filter")) {
612 addfield(map, &filter, "", "", val);
613 } else if (json_streq(map, field, "ScaleUnit")) {
614 addfield(map, &unit, "", "", val);
615 } else if (json_streq(map, field, "PerPkg")) {
616 addfield(map, &perpkg, "", "", val);
617 } else if (json_streq(map, field, "MetricName")) {
618 addfield(map, &metric_name, "", "", val);
619 } else if (json_streq(map, field, "MetricGroup")) {
620 addfield(map, &metric_group, "", "", val);
621 } else if (json_streq(map, field, "MetricExpr")) {
622 addfield(map, &metric_expr, "", "", val);
623 for (s = metric_expr; *s; s++)
624 *s = tolower(*s);
625 } else if (json_streq(map, field, "ArchStdEvent")) {
626 addfield(map, &arch_std, "", "", val);
627 for (s = arch_std; *s; s++)
628 *s = tolower(*s);
629 }
630
631 }
632 if (precise && desc && !strstr(desc, "(Precise Event)")) {
633 if (json_streq(map, precise, "2"))
634 addfield(map, &extra_desc, " ",
635 "(Must be precise)", NULL);
636 else
637 addfield(map, &extra_desc, " ",
638 "(Precise event)", NULL);
639 }
640 snprintf(buf, sizeof buf, "event=%#llx", eventcode);
641 addfield(map, &event, ",", buf, NULL);
642 if (desc && extra_desc)
643 addfield(map, &desc, " ", extra_desc, NULL);
644 if (long_desc && extra_desc)
645 addfield(map, &long_desc, " ", extra_desc, NULL);
646 if (filter)
647 addfield(map, &event, ",", filter, NULL);
648 if (msr != NULL)
649 addfield(map, &event, ",", msr->pname, msrval);
650 if (name)
651 fixname(name);
652
653 if (arch_std) {
654
655
656
657
658 err = try_fixup(fn, arch_std, &event, &desc, &name,
659 &long_desc, &pmu, &filter, &perpkg,
660 &unit, &metric_expr, &metric_name,
661 &metric_group, eventcode);
662 if (err)
663 goto free_strings;
664 }
665 err = func(data, name, real_event(name, event), desc, long_desc,
666 pmu, unit, perpkg, metric_expr, metric_name, metric_group);
667 free_strings:
668 free(event);
669 free(desc);
670 free(name);
671 free(long_desc);
672 free(extra_desc);
673 free(pmu);
674 free(filter);
675 free(perpkg);
676 free(unit);
677 free(metric_expr);
678 free(metric_name);
679 free(metric_group);
680 free(arch_std);
681
682 if (err)
683 break;
684 tok += j;
685 }
686 EXPECT(tok - tokens == len, tok, "unexpected objects at end");
687 err = 0;
688 out_free:
689 free_json(map, size, tokens);
690 return err;
691 }
692
693 static char *file_name_to_table_name(char *fname)
694 {
695 unsigned int i;
696 int n;
697 int c;
698 char *tblname;
699
700
701
702
703
704
705 n = asprintf(&tblname, "pme_%s", fname);
706 if (n < 0) {
707 pr_info("%s: asprintf() error %s for file %s\n", prog,
708 strerror(errno), fname);
709 return NULL;
710 }
711
712 for (i = 0; i < strlen(tblname); i++) {
713 c = tblname[i];
714
715 if (c == '-' || c == '/')
716 tblname[i] = '_';
717 else if (c == '.') {
718 tblname[i] = '\0';
719 break;
720 } else if (!isalnum(c) && c != '_') {
721 pr_err("%s: Invalid character '%c' in file name %s\n",
722 prog, c, basename(fname));
723 free(tblname);
724 tblname = NULL;
725 break;
726 }
727 }
728
729 return tblname;
730 }
731
732 static void print_mapping_table_prefix(FILE *outfp)
733 {
734 fprintf(outfp, "struct pmu_events_map pmu_events_map[] = {\n");
735 }
736
737 static void print_mapping_table_suffix(FILE *outfp)
738 {
739
740
741
742 fprintf(outfp, "{\n");
743 fprintf(outfp, "\t.cpuid = 0,\n");
744 fprintf(outfp, "\t.version = 0,\n");
745 fprintf(outfp, "\t.type = 0,\n");
746 fprintf(outfp, "\t.table = 0,\n");
747 fprintf(outfp, "},\n");
748
749
750 fprintf(outfp, "};\n");
751 }
752
753 static int process_mapfile(FILE *outfp, char *fpath)
754 {
755 int n = 16384;
756 FILE *mapfp;
757 char *save = NULL;
758 char *line, *p;
759 int line_num;
760 char *tblname;
761 int ret = 0;
762
763 pr_info("%s: Processing mapfile %s\n", prog, fpath);
764
765 line = malloc(n);
766 if (!line)
767 return -1;
768
769 mapfp = fopen(fpath, "r");
770 if (!mapfp) {
771 pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
772 fpath);
773 free(line);
774 return -1;
775 }
776
777 print_mapping_table_prefix(outfp);
778
779
780 p = fgets(line, n, mapfp);
781 if (!p)
782 goto out;
783
784 line_num = 1;
785 while (1) {
786 char *cpuid, *version, *type, *fname;
787
788 line_num++;
789 p = fgets(line, n, mapfp);
790 if (!p)
791 break;
792
793 if (line[0] == '#' || line[0] == '\n')
794 continue;
795
796 if (line[strlen(line)-1] != '\n') {
797
798 pr_info("%s: Mapfile %s: line %d too long, aborting\n",
799 prog, fpath, line_num);
800 ret = -1;
801 goto out;
802 }
803 line[strlen(line)-1] = '\0';
804
805 cpuid = fixregex(strtok_r(p, ",", &save));
806 version = strtok_r(NULL, ",", &save);
807 fname = strtok_r(NULL, ",", &save);
808 type = strtok_r(NULL, ",", &save);
809
810 tblname = file_name_to_table_name(fname);
811 fprintf(outfp, "{\n");
812 fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid);
813 fprintf(outfp, "\t.version = \"%s\",\n", version);
814 fprintf(outfp, "\t.type = \"%s\",\n", type);
815
816
817
818
819
820
821
822
823
824
825 fprintf(outfp, "\t.table = %s\n", tblname);
826 fprintf(outfp, "},\n");
827 }
828
829 out:
830 print_mapping_table_suffix(outfp);
831 fclose(mapfp);
832 free(line);
833 return ret;
834 }
835
836
837
838
839
840
841 static void create_empty_mapping(const char *output_file)
842 {
843 FILE *outfp;
844
845 pr_info("%s: Creating empty pmu_events_map[] table\n", prog);
846
847
848 outfp = fopen(output_file, "w");
849 if (!outfp) {
850 perror("fopen()");
851 _Exit(1);
852 }
853
854 fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n");
855 print_mapping_table_prefix(outfp);
856 print_mapping_table_suffix(outfp);
857 fclose(outfp);
858 }
859
860 static int get_maxfds(void)
861 {
862 struct rlimit rlim;
863
864 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
865 return min((int)rlim.rlim_max / 2, 512);
866
867 return 512;
868 }
869
870
871
872
873
874 static FILE *eventsfp;
875 static char *mapfile;
876
877 static int is_leaf_dir(const char *fpath)
878 {
879 DIR *d;
880 struct dirent *dir;
881 int res = 1;
882
883 d = opendir(fpath);
884 if (!d)
885 return 0;
886
887 while ((dir = readdir(d)) != NULL) {
888 if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
889 continue;
890
891 if (dir->d_type == DT_DIR) {
892 res = 0;
893 break;
894 } else if (dir->d_type == DT_UNKNOWN) {
895 char path[PATH_MAX];
896 struct stat st;
897
898 sprintf(path, "%s/%s", fpath, dir->d_name);
899 if (stat(path, &st))
900 break;
901
902 if (S_ISDIR(st.st_mode)) {
903 res = 0;
904 break;
905 }
906 }
907 }
908
909 closedir(d);
910
911 return res;
912 }
913
914 static int is_json_file(const char *name)
915 {
916 const char *suffix;
917
918 if (strlen(name) < 5)
919 return 0;
920
921 suffix = name + strlen(name) - 5;
922
923 if (strncmp(suffix, ".json", 5) == 0)
924 return 1;
925 return 0;
926 }
927
928 static int preprocess_arch_std_files(const char *fpath, const struct stat *sb,
929 int typeflag, struct FTW *ftwbuf)
930 {
931 int level = ftwbuf->level;
932 int is_file = typeflag == FTW_F;
933
934 if (level == 1 && is_file && is_json_file(fpath))
935 return json_events(fpath, save_arch_std_events, (void *)sb);
936
937 return 0;
938 }
939
940 static int process_one_file(const char *fpath, const struct stat *sb,
941 int typeflag, struct FTW *ftwbuf)
942 {
943 char *tblname, *bname;
944 int is_dir = typeflag == FTW_D;
945 int is_file = typeflag == FTW_F;
946 int level = ftwbuf->level;
947 int err = 0;
948
949 if (level == 2 && is_dir) {
950
951
952
953
954
955 bname = (char *) fpath + ftwbuf->base - 2;
956 for (;;) {
957 if (*bname == '/')
958 break;
959 bname--;
960 }
961 bname++;
962 } else
963 bname = (char *) fpath + ftwbuf->base;
964
965 pr_debug("%s %d %7jd %-20s %s\n",
966 is_file ? "f" : is_dir ? "d" : "x",
967 level, sb->st_size, bname, fpath);
968
969
970 if (level == 0 || level > 3)
971 return 0;
972
973
974
975 if ((level == 1 && is_dir && is_leaf_dir(fpath)) ||
976 (level == 2 && is_dir)) {
977 if (close_table)
978 print_events_table_suffix(eventsfp);
979
980
981
982
983
984
985 tblname = file_name_to_table_name(bname);
986 if (!tblname) {
987 pr_info("%s: Error determining table name for %s\n", prog,
988 bname);
989 return -1;
990 }
991
992 print_events_table_prefix(eventsfp, tblname);
993 return 0;
994 }
995
996
997
998
999
1000
1001
1002 if (level == 1 && is_file) {
1003 if (!strcmp(bname, "mapfile.csv")) {
1004 mapfile = strdup(fpath);
1005 return 0;
1006 }
1007
1008 pr_info("%s: Ignoring file %s\n", prog, fpath);
1009 return 0;
1010 }
1011
1012
1013
1014
1015
1016 if (is_file) {
1017 if (!is_json_file(bname)) {
1018 pr_info("%s: Ignoring file without .json suffix %s\n", prog,
1019 fpath);
1020 return 0;
1021 }
1022 }
1023
1024 if (level > 1 && add_topic(bname))
1025 return -ENOMEM;
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039 if (is_file) {
1040 struct perf_entry_data data = {
1041 .topic = get_topic(),
1042 .outfp = eventsfp,
1043 };
1044
1045 err = json_events(fpath, print_events_table_entry, &data);
1046
1047 free(data.topic);
1048 }
1049
1050 return err;
1051 }
1052
1053 #ifndef PATH_MAX
1054 #define PATH_MAX 4096
1055 #endif
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 int main(int argc, char *argv[])
1070 {
1071 int rc;
1072 int maxfds;
1073 char ldirname[PATH_MAX];
1074
1075 const char *arch;
1076 const char *output_file;
1077 const char *start_dirname;
1078 struct stat stbuf;
1079
1080 prog = basename(argv[0]);
1081 if (argc < 4) {
1082 pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog);
1083 return 1;
1084 }
1085
1086 arch = argv[1];
1087 start_dirname = argv[2];
1088 output_file = argv[3];
1089
1090 if (argc > 4)
1091 verbose = atoi(argv[4]);
1092
1093 eventsfp = fopen(output_file, "w");
1094 if (!eventsfp) {
1095 pr_err("%s Unable to create required file %s (%s)\n",
1096 prog, output_file, strerror(errno));
1097 return 2;
1098 }
1099
1100 sprintf(ldirname, "%s/%s", start_dirname, arch);
1101
1102
1103 if (stat(ldirname, &stbuf) < 0) {
1104 pr_info("%s: Arch %s has no PMU event lists\n", prog, arch);
1105 goto empty_map;
1106 }
1107
1108
1109 fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n");
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121 maxfds = get_maxfds();
1122 mapfile = NULL;
1123 rc = nftw(ldirname, preprocess_arch_std_files, maxfds, 0);
1124 if (rc && verbose) {
1125 pr_info("%s: Error preprocessing arch standard files %s\n",
1126 prog, ldirname);
1127 goto empty_map;
1128 } else if (rc < 0) {
1129
1130 fclose(eventsfp);
1131 free_arch_std_events();
1132 return 1;
1133 } else if (rc) {
1134 goto empty_map;
1135 }
1136
1137 rc = nftw(ldirname, process_one_file, maxfds, 0);
1138 if (rc && verbose) {
1139 pr_info("%s: Error walking file tree %s\n", prog, ldirname);
1140 goto empty_map;
1141 } else if (rc < 0) {
1142
1143 fclose(eventsfp);
1144 free_arch_std_events();
1145 return 1;
1146 } else if (rc) {
1147 goto empty_map;
1148 }
1149
1150 if (close_table)
1151 print_events_table_suffix(eventsfp);
1152
1153 if (!mapfile) {
1154 pr_info("%s: No CPU->JSON mapping?\n", prog);
1155 goto empty_map;
1156 }
1157
1158 if (process_mapfile(eventsfp, mapfile)) {
1159 pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
1160
1161 fclose(eventsfp);
1162 free_arch_std_events();
1163 return 1;
1164 }
1165
1166 return 0;
1167
1168 empty_map:
1169 fclose(eventsfp);
1170 create_empty_mapping(output_file);
1171 free_arch_std_events();
1172 return 0;
1173 }