diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-11-28 04:49:10 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-11-28 04:49:10 -0500 |
commit | ac675d0d586a2d96df58228c495b4005bc7bca7b (patch) | |
tree | 557cc686d470ac513c647cafd07ae61bf9793e0c | |
parent | 3f3b1a46bfdbce97dd3f9594d8a95db82baa554b (diff) | |
parent | 0bb93490170477224f8bd4cc9ce8920517461643 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Fix 'perf list' segfault due to lack of support for PERF_CONF_SW_BPF_OUTPUT
in an array used just for printing available events, robustify the code
involved (Arnaldo Carvalho de Melo)
- 'perf test unwind' should create kernel maps, now that entry works and the
test passes (Jiri Olsa)
- Fix showing the running kernel build id in 'perf buildid-list' (Michael Petlan)
- Fix command line symbol filtering in 'perf report' (Namhyung Kim)
Infrastructure changes:
- Extract and collect map info from BPF object files in libbpf (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/lib/bpf/libbpf.c | 252 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 24 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 12 | ||||
-rw-r--r-- | tools/perf/tests/dwarf-unwind.c | 5 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 5 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.c | 65 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.h | 2 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 6 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 6 |
10 files changed, 268 insertions, 111 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e3f4c3379f14..a298614ad091 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -163,22 +163,25 @@ struct bpf_program { | |||
163 | bpf_program_clear_priv_t clear_priv; | 163 | bpf_program_clear_priv_t clear_priv; |
164 | }; | 164 | }; |
165 | 165 | ||
166 | struct bpf_map { | ||
167 | int fd; | ||
168 | char *name; | ||
169 | struct bpf_map_def def; | ||
170 | void *priv; | ||
171 | bpf_map_clear_priv_t clear_priv; | ||
172 | }; | ||
173 | |||
166 | static LIST_HEAD(bpf_objects_list); | 174 | static LIST_HEAD(bpf_objects_list); |
167 | 175 | ||
168 | struct bpf_object { | 176 | struct bpf_object { |
169 | char license[64]; | 177 | char license[64]; |
170 | u32 kern_version; | 178 | u32 kern_version; |
171 | void *maps_buf; | ||
172 | size_t maps_buf_sz; | ||
173 | 179 | ||
174 | struct bpf_program *programs; | 180 | struct bpf_program *programs; |
175 | size_t nr_programs; | 181 | size_t nr_programs; |
176 | int *map_fds; | 182 | struct bpf_map *maps; |
177 | /* | 183 | size_t nr_maps; |
178 | * This field is required because maps_buf will be freed and | 184 | |
179 | * maps_buf_sz will be set to 0 after loaded. | ||
180 | */ | ||
181 | size_t nr_map_fds; | ||
182 | bool loaded; | 185 | bool loaded; |
183 | 186 | ||
184 | /* | 187 | /* |
@@ -489,30 +492,81 @@ static int | |||
489 | bpf_object__init_maps(struct bpf_object *obj, void *data, | 492 | bpf_object__init_maps(struct bpf_object *obj, void *data, |
490 | size_t size) | 493 | size_t size) |
491 | { | 494 | { |
492 | if (size == 0) { | 495 | size_t nr_maps; |
496 | int i; | ||
497 | |||
498 | nr_maps = size / sizeof(struct bpf_map_def); | ||
499 | if (!data || !nr_maps) { | ||
493 | pr_debug("%s doesn't need map definition\n", | 500 | pr_debug("%s doesn't need map definition\n", |
494 | obj->path); | 501 | obj->path); |
495 | return 0; | 502 | return 0; |
496 | } | 503 | } |
497 | 504 | ||
498 | obj->maps_buf = malloc(size); | 505 | pr_debug("maps in %s: %zd bytes\n", obj->path, size); |
499 | if (!obj->maps_buf) { | 506 | |
500 | pr_warning("malloc maps failed: %s\n", obj->path); | 507 | obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); |
508 | if (!obj->maps) { | ||
509 | pr_warning("alloc maps for object failed\n"); | ||
501 | return -ENOMEM; | 510 | return -ENOMEM; |
502 | } | 511 | } |
512 | obj->nr_maps = nr_maps; | ||
503 | 513 | ||
504 | obj->maps_buf_sz = size; | 514 | for (i = 0; i < nr_maps; i++) { |
505 | memcpy(obj->maps_buf, data, size); | 515 | struct bpf_map_def *def = &obj->maps[i].def; |
506 | pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size); | 516 | |
517 | /* | ||
518 | * fill all fd with -1 so won't close incorrect | ||
519 | * fd (fd=0 is stdin) when failure (zclose won't close | ||
520 | * negative fd)). | ||
521 | */ | ||
522 | obj->maps[i].fd = -1; | ||
523 | |||
524 | /* Save map definition into obj->maps */ | ||
525 | *def = ((struct bpf_map_def *)data)[i]; | ||
526 | } | ||
507 | return 0; | 527 | return 0; |
508 | } | 528 | } |
509 | 529 | ||
530 | static void | ||
531 | bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) | ||
532 | { | ||
533 | int i; | ||
534 | Elf_Data *symbols = obj->efile.symbols; | ||
535 | |||
536 | if (!symbols || maps_shndx < 0) | ||
537 | return; | ||
538 | |||
539 | for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { | ||
540 | GElf_Sym sym; | ||
541 | size_t map_idx; | ||
542 | const char *map_name; | ||
543 | |||
544 | if (!gelf_getsym(symbols, i, &sym)) | ||
545 | continue; | ||
546 | if (sym.st_shndx != maps_shndx) | ||
547 | continue; | ||
548 | |||
549 | map_name = elf_strptr(obj->efile.elf, | ||
550 | obj->efile.ehdr.e_shstrndx, | ||
551 | sym.st_name); | ||
552 | map_idx = sym.st_value / sizeof(struct bpf_map_def); | ||
553 | if (map_idx >= obj->nr_maps) { | ||
554 | pr_warning("index of map \"%s\" is buggy: %zu > %zu\n", | ||
555 | map_name, map_idx, obj->nr_maps); | ||
556 | continue; | ||
557 | } | ||
558 | obj->maps[map_idx].name = strdup(map_name); | ||
559 | pr_debug("map %zu is \"%s\"\n", map_idx, | ||
560 | obj->maps[map_idx].name); | ||
561 | } | ||
562 | } | ||
563 | |||
510 | static int bpf_object__elf_collect(struct bpf_object *obj) | 564 | static int bpf_object__elf_collect(struct bpf_object *obj) |
511 | { | 565 | { |
512 | Elf *elf = obj->efile.elf; | 566 | Elf *elf = obj->efile.elf; |
513 | GElf_Ehdr *ep = &obj->efile.ehdr; | 567 | GElf_Ehdr *ep = &obj->efile.ehdr; |
514 | Elf_Scn *scn = NULL; | 568 | Elf_Scn *scn = NULL; |
515 | int idx = 0, err = 0; | 569 | int idx = 0, err = 0, maps_shndx = -1; |
516 | 570 | ||
517 | /* Elf is corrupted/truncated, avoid calling elf_strptr. */ | 571 | /* Elf is corrupted/truncated, avoid calling elf_strptr. */ |
518 | if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { | 572 | if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { |
@@ -562,10 +616,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
562 | err = bpf_object__init_kversion(obj, | 616 | err = bpf_object__init_kversion(obj, |
563 | data->d_buf, | 617 | data->d_buf, |
564 | data->d_size); | 618 | data->d_size); |
565 | else if (strcmp(name, "maps") == 0) | 619 | else if (strcmp(name, "maps") == 0) { |
566 | err = bpf_object__init_maps(obj, data->d_buf, | 620 | err = bpf_object__init_maps(obj, data->d_buf, |
567 | data->d_size); | 621 | data->d_size); |
568 | else if (sh.sh_type == SHT_SYMTAB) { | 622 | maps_shndx = idx; |
623 | } else if (sh.sh_type == SHT_SYMTAB) { | ||
569 | if (obj->efile.symbols) { | 624 | if (obj->efile.symbols) { |
570 | pr_warning("bpf: multiple SYMTAB in %s\n", | 625 | pr_warning("bpf: multiple SYMTAB in %s\n", |
571 | obj->path); | 626 | obj->path); |
@@ -606,6 +661,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
606 | if (err) | 661 | if (err) |
607 | goto out; | 662 | goto out; |
608 | } | 663 | } |
664 | |||
665 | if (maps_shndx >= 0) | ||
666 | bpf_object__init_maps_name(obj, maps_shndx); | ||
609 | out: | 667 | out: |
610 | return err; | 668 | return err; |
611 | } | 669 | } |
@@ -688,37 +746,15 @@ static int | |||
688 | bpf_object__create_maps(struct bpf_object *obj) | 746 | bpf_object__create_maps(struct bpf_object *obj) |
689 | { | 747 | { |
690 | unsigned int i; | 748 | unsigned int i; |
691 | size_t nr_maps; | ||
692 | int *pfd; | ||
693 | 749 | ||
694 | nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); | 750 | for (i = 0; i < obj->nr_maps; i++) { |
695 | if (!obj->maps_buf || !nr_maps) { | 751 | struct bpf_map_def *def = &obj->maps[i].def; |
696 | pr_debug("don't need create maps for %s\n", | 752 | int *pfd = &obj->maps[i].fd; |
697 | obj->path); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | obj->map_fds = malloc(sizeof(int) * nr_maps); | ||
702 | if (!obj->map_fds) { | ||
703 | pr_warning("realloc perf_bpf_map_fds failed\n"); | ||
704 | return -ENOMEM; | ||
705 | } | ||
706 | obj->nr_map_fds = nr_maps; | ||
707 | 753 | ||
708 | /* fill all fd with -1 */ | 754 | *pfd = bpf_create_map(def->type, |
709 | memset(obj->map_fds, -1, sizeof(int) * nr_maps); | 755 | def->key_size, |
710 | 756 | def->value_size, | |
711 | pfd = obj->map_fds; | 757 | def->max_entries); |
712 | for (i = 0; i < nr_maps; i++) { | ||
713 | struct bpf_map_def def; | ||
714 | |||
715 | def = *(struct bpf_map_def *)(obj->maps_buf + | ||
716 | i * sizeof(struct bpf_map_def)); | ||
717 | |||
718 | *pfd = bpf_create_map(def.type, | ||
719 | def.key_size, | ||
720 | def.value_size, | ||
721 | def.max_entries); | ||
722 | if (*pfd < 0) { | 758 | if (*pfd < 0) { |
723 | size_t j; | 759 | size_t j; |
724 | int err = *pfd; | 760 | int err = *pfd; |
@@ -726,22 +762,17 @@ bpf_object__create_maps(struct bpf_object *obj) | |||
726 | pr_warning("failed to create map: %s\n", | 762 | pr_warning("failed to create map: %s\n", |
727 | strerror(errno)); | 763 | strerror(errno)); |
728 | for (j = 0; j < i; j++) | 764 | for (j = 0; j < i; j++) |
729 | zclose(obj->map_fds[j]); | 765 | zclose(obj->maps[j].fd); |
730 | obj->nr_map_fds = 0; | ||
731 | zfree(&obj->map_fds); | ||
732 | return err; | 766 | return err; |
733 | } | 767 | } |
734 | pr_debug("create map: fd=%d\n", *pfd); | 768 | pr_debug("create map: fd=%d\n", *pfd); |
735 | pfd++; | ||
736 | } | 769 | } |
737 | 770 | ||
738 | zfree(&obj->maps_buf); | ||
739 | obj->maps_buf_sz = 0; | ||
740 | return 0; | 771 | return 0; |
741 | } | 772 | } |
742 | 773 | ||
743 | static int | 774 | static int |
744 | bpf_program__relocate(struct bpf_program *prog, int *map_fds) | 775 | bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) |
745 | { | 776 | { |
746 | int i; | 777 | int i; |
747 | 778 | ||
@@ -761,7 +792,7 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) | |||
761 | return -LIBBPF_ERRNO__RELOC; | 792 | return -LIBBPF_ERRNO__RELOC; |
762 | } | 793 | } |
763 | insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; | 794 | insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; |
764 | insns[insn_idx].imm = map_fds[map_idx]; | 795 | insns[insn_idx].imm = obj->maps[map_idx].fd; |
765 | } | 796 | } |
766 | 797 | ||
767 | zfree(&prog->reloc_desc); | 798 | zfree(&prog->reloc_desc); |
@@ -780,7 +811,7 @@ bpf_object__relocate(struct bpf_object *obj) | |||
780 | for (i = 0; i < obj->nr_programs; i++) { | 811 | for (i = 0; i < obj->nr_programs; i++) { |
781 | prog = &obj->programs[i]; | 812 | prog = &obj->programs[i]; |
782 | 813 | ||
783 | err = bpf_program__relocate(prog, obj->map_fds); | 814 | err = bpf_program__relocate(prog, obj); |
784 | if (err) { | 815 | if (err) { |
785 | pr_warning("failed to relocate '%s'\n", | 816 | pr_warning("failed to relocate '%s'\n", |
786 | prog->section_name); | 817 | prog->section_name); |
@@ -804,8 +835,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) | |||
804 | Elf_Data *data = obj->efile.reloc[i].data; | 835 | Elf_Data *data = obj->efile.reloc[i].data; |
805 | int idx = shdr->sh_info; | 836 | int idx = shdr->sh_info; |
806 | struct bpf_program *prog; | 837 | struct bpf_program *prog; |
807 | size_t nr_maps = obj->maps_buf_sz / | 838 | size_t nr_maps = obj->nr_maps; |
808 | sizeof(struct bpf_map_def); | ||
809 | 839 | ||
810 | if (shdr->sh_type != SHT_REL) { | 840 | if (shdr->sh_type != SHT_REL) { |
811 | pr_warning("internal error at %d\n", __LINE__); | 841 | pr_warning("internal error at %d\n", __LINE__); |
@@ -1050,10 +1080,8 @@ int bpf_object__unload(struct bpf_object *obj) | |||
1050 | if (!obj) | 1080 | if (!obj) |
1051 | return -EINVAL; | 1081 | return -EINVAL; |
1052 | 1082 | ||
1053 | for (i = 0; i < obj->nr_map_fds; i++) | 1083 | for (i = 0; i < obj->nr_maps; i++) |
1054 | zclose(obj->map_fds[i]); | 1084 | zclose(obj->maps[i].fd); |
1055 | zfree(&obj->map_fds); | ||
1056 | obj->nr_map_fds = 0; | ||
1057 | 1085 | ||
1058 | for (i = 0; i < obj->nr_programs; i++) | 1086 | for (i = 0; i < obj->nr_programs; i++) |
1059 | bpf_program__unload(&obj->programs[i]); | 1087 | bpf_program__unload(&obj->programs[i]); |
@@ -1096,7 +1124,16 @@ void bpf_object__close(struct bpf_object *obj) | |||
1096 | bpf_object__elf_finish(obj); | 1124 | bpf_object__elf_finish(obj); |
1097 | bpf_object__unload(obj); | 1125 | bpf_object__unload(obj); |
1098 | 1126 | ||
1099 | zfree(&obj->maps_buf); | 1127 | for (i = 0; i < obj->nr_maps; i++) { |
1128 | zfree(&obj->maps[i].name); | ||
1129 | if (obj->maps[i].clear_priv) | ||
1130 | obj->maps[i].clear_priv(&obj->maps[i], | ||
1131 | obj->maps[i].priv); | ||
1132 | obj->maps[i].priv = NULL; | ||
1133 | obj->maps[i].clear_priv = NULL; | ||
1134 | } | ||
1135 | zfree(&obj->maps); | ||
1136 | obj->nr_maps = 0; | ||
1100 | 1137 | ||
1101 | if (obj->programs && obj->nr_programs) { | 1138 | if (obj->programs && obj->nr_programs) { |
1102 | for (i = 0; i < obj->nr_programs; i++) | 1139 | for (i = 0; i < obj->nr_programs; i++) |
@@ -1251,3 +1288,92 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n) | |||
1251 | 1288 | ||
1252 | return fd; | 1289 | return fd; |
1253 | } | 1290 | } |
1291 | |||
1292 | int bpf_map__get_fd(struct bpf_map *map) | ||
1293 | { | ||
1294 | if (!map) | ||
1295 | return -EINVAL; | ||
1296 | |||
1297 | return map->fd; | ||
1298 | } | ||
1299 | |||
1300 | int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef) | ||
1301 | { | ||
1302 | if (!map || !pdef) | ||
1303 | return -EINVAL; | ||
1304 | |||
1305 | *pdef = map->def; | ||
1306 | return 0; | ||
1307 | } | ||
1308 | |||
1309 | const char *bpf_map__get_name(struct bpf_map *map) | ||
1310 | { | ||
1311 | if (!map) | ||
1312 | return NULL; | ||
1313 | return map->name; | ||
1314 | } | ||
1315 | |||
1316 | int bpf_map__set_private(struct bpf_map *map, void *priv, | ||
1317 | bpf_map_clear_priv_t clear_priv) | ||
1318 | { | ||
1319 | if (!map) | ||
1320 | return -EINVAL; | ||
1321 | |||
1322 | if (map->priv) { | ||
1323 | if (map->clear_priv) | ||
1324 | map->clear_priv(map, map->priv); | ||
1325 | } | ||
1326 | |||
1327 | map->priv = priv; | ||
1328 | map->clear_priv = clear_priv; | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | int bpf_map__get_private(struct bpf_map *map, void **ppriv) | ||
1333 | { | ||
1334 | if (!map) | ||
1335 | return -EINVAL; | ||
1336 | |||
1337 | if (ppriv) | ||
1338 | *ppriv = map->priv; | ||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | struct bpf_map * | ||
1343 | bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) | ||
1344 | { | ||
1345 | size_t idx; | ||
1346 | struct bpf_map *s, *e; | ||
1347 | |||
1348 | if (!obj || !obj->maps) | ||
1349 | return NULL; | ||
1350 | |||
1351 | s = obj->maps; | ||
1352 | e = obj->maps + obj->nr_maps; | ||
1353 | |||
1354 | if (prev == NULL) | ||
1355 | return s; | ||
1356 | |||
1357 | if ((prev < s) || (prev >= e)) { | ||
1358 | pr_warning("error in %s: map handler doesn't belong to object\n", | ||
1359 | __func__); | ||
1360 | return NULL; | ||
1361 | } | ||
1362 | |||
1363 | idx = (prev - obj->maps) + 1; | ||
1364 | if (idx >= obj->nr_maps) | ||
1365 | return NULL; | ||
1366 | return &obj->maps[idx]; | ||
1367 | } | ||
1368 | |||
1369 | struct bpf_map * | ||
1370 | bpf_object__get_map_by_name(struct bpf_object *obj, const char *name) | ||
1371 | { | ||
1372 | struct bpf_map *pos; | ||
1373 | |||
1374 | bpf_map__for_each(pos, obj) { | ||
1375 | if (strcmp(pos->name, name) == 0) | ||
1376 | return pos; | ||
1377 | } | ||
1378 | return NULL; | ||
1379 | } | ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 949df4b346cf..a51594c7b518 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h | |||
@@ -165,4 +165,28 @@ struct bpf_map_def { | |||
165 | unsigned int max_entries; | 165 | unsigned int max_entries; |
166 | }; | 166 | }; |
167 | 167 | ||
168 | /* | ||
169 | * There is another 'struct bpf_map' in include/linux/map.h. However, | ||
170 | * it is not a uapi header so no need to consider name clash. | ||
171 | */ | ||
172 | struct bpf_map; | ||
173 | struct bpf_map * | ||
174 | bpf_object__get_map_by_name(struct bpf_object *obj, const char *name); | ||
175 | |||
176 | struct bpf_map * | ||
177 | bpf_map__next(struct bpf_map *map, struct bpf_object *obj); | ||
178 | #define bpf_map__for_each(pos, obj) \ | ||
179 | for ((pos) = bpf_map__next(NULL, (obj)); \ | ||
180 | (pos) != NULL; \ | ||
181 | (pos) = bpf_map__next((pos), (obj))) | ||
182 | |||
183 | int bpf_map__get_fd(struct bpf_map *map); | ||
184 | int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef); | ||
185 | const char *bpf_map__get_name(struct bpf_map *map); | ||
186 | |||
187 | typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); | ||
188 | int bpf_map__set_private(struct bpf_map *map, void *priv, | ||
189 | bpf_map_clear_priv_t clear_priv); | ||
190 | int bpf_map__get_private(struct bpf_map *map, void **ppriv); | ||
191 | |||
168 | #endif | 192 | #endif |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8a9c6908f54e..af5db885ea9c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -513,20 +513,26 @@ static int __cmd_report(struct report *rep) | |||
513 | if (rep->cpu_list) { | 513 | if (rep->cpu_list) { |
514 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | 514 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, |
515 | rep->cpu_bitmap); | 515 | rep->cpu_bitmap); |
516 | if (ret) | 516 | if (ret) { |
517 | ui__error("failed to set cpu bitmap\n"); | ||
517 | return ret; | 518 | return ret; |
519 | } | ||
518 | } | 520 | } |
519 | 521 | ||
520 | if (rep->show_threads) | 522 | if (rep->show_threads) |
521 | perf_read_values_init(&rep->show_threads_values); | 523 | perf_read_values_init(&rep->show_threads_values); |
522 | 524 | ||
523 | ret = report__setup_sample_type(rep); | 525 | ret = report__setup_sample_type(rep); |
524 | if (ret) | 526 | if (ret) { |
527 | /* report__setup_sample_type() already showed error message */ | ||
525 | return ret; | 528 | return ret; |
529 | } | ||
526 | 530 | ||
527 | ret = perf_session__process_events(session); | 531 | ret = perf_session__process_events(session); |
528 | if (ret) | 532 | if (ret) { |
533 | ui__error("failed to process sample\n"); | ||
529 | return ret; | 534 | return ret; |
535 | } | ||
530 | 536 | ||
531 | report__warn_kptr_restrict(rep); | 537 | report__warn_kptr_restrict(rep); |
532 | 538 | ||
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index b2357e8115a2..3cce13b19cbb 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c | |||
@@ -173,6 +173,11 @@ int test__dwarf_unwind(int subtest __maybe_unused) | |||
173 | return -1; | 173 | return -1; |
174 | } | 174 | } |
175 | 175 | ||
176 | if (machine__create_kernel_maps(machine)) { | ||
177 | pr_err("Failed to create kernel maps\n"); | ||
178 | return -1; | ||
179 | } | ||
180 | |||
176 | callchain_param.record_mode = CALLCHAIN_DWARF; | 181 | callchain_param.record_mode = CALLCHAIN_DWARF; |
177 | 182 | ||
178 | if (init_live_machine(machine)) { | 183 | if (init_live_machine(machine)) { |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a211b7b6a81e..dcdcbafb078b 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -2055,10 +2055,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
2055 | SLang_reset_tty(); | 2055 | SLang_reset_tty(); |
2056 | SLang_init_tty(0, 0, 0); | 2056 | SLang_init_tty(0, 0, 0); |
2057 | 2057 | ||
2058 | if (min_pcnt) { | 2058 | if (min_pcnt) |
2059 | browser->min_pcnt = min_pcnt; | 2059 | browser->min_pcnt = min_pcnt; |
2060 | hist_browser__update_nr_entries(browser); | 2060 | hist_browser__update_nr_entries(browser); |
2061 | } | ||
2062 | 2061 | ||
2063 | browser->pstack = pstack__new(3); | 2062 | browser->pstack = pstack__new(3); |
2064 | if (browser->pstack == NULL) | 2063 | if (browser->pstack == NULL) |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 36544e5ece43..540a7efa657e 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -120,7 +120,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, | |||
120 | } | 120 | } |
121 | 121 | ||
122 | static int | 122 | static int |
123 | config__exec(const char *value, struct perf_probe_event *pev) | 123 | prog_config__exec(const char *value, struct perf_probe_event *pev) |
124 | { | 124 | { |
125 | pev->uprobes = true; | 125 | pev->uprobes = true; |
126 | pev->target = strdup(value); | 126 | pev->target = strdup(value); |
@@ -130,7 +130,7 @@ config__exec(const char *value, struct perf_probe_event *pev) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | static int | 132 | static int |
133 | config__module(const char *value, struct perf_probe_event *pev) | 133 | prog_config__module(const char *value, struct perf_probe_event *pev) |
134 | { | 134 | { |
135 | pev->uprobes = false; | 135 | pev->uprobes = false; |
136 | pev->target = strdup(value); | 136 | pev->target = strdup(value); |
@@ -140,8 +140,7 @@ config__module(const char *value, struct perf_probe_event *pev) | |||
140 | } | 140 | } |
141 | 141 | ||
142 | static int | 142 | static int |
143 | config__bool(const char *value, | 143 | prog_config__bool(const char *value, bool *pbool, bool invert) |
144 | bool *pbool, bool invert) | ||
145 | { | 144 | { |
146 | int err; | 145 | int err; |
147 | bool bool_value; | 146 | bool bool_value; |
@@ -158,17 +157,17 @@ config__bool(const char *value, | |||
158 | } | 157 | } |
159 | 158 | ||
160 | static int | 159 | static int |
161 | config__inlines(const char *value, | 160 | prog_config__inlines(const char *value, |
162 | struct perf_probe_event *pev __maybe_unused) | 161 | struct perf_probe_event *pev __maybe_unused) |
163 | { | 162 | { |
164 | return config__bool(value, &probe_conf.no_inlines, true); | 163 | return prog_config__bool(value, &probe_conf.no_inlines, true); |
165 | } | 164 | } |
166 | 165 | ||
167 | static int | 166 | static int |
168 | config__force(const char *value, | 167 | prog_config__force(const char *value, |
169 | struct perf_probe_event *pev __maybe_unused) | 168 | struct perf_probe_event *pev __maybe_unused) |
170 | { | 169 | { |
171 | return config__bool(value, &probe_conf.force_add, false); | 170 | return prog_config__bool(value, &probe_conf.force_add, false); |
172 | } | 171 | } |
173 | 172 | ||
174 | static struct { | 173 | static struct { |
@@ -176,58 +175,58 @@ static struct { | |||
176 | const char *usage; | 175 | const char *usage; |
177 | const char *desc; | 176 | const char *desc; |
178 | int (*func)(const char *, struct perf_probe_event *); | 177 | int (*func)(const char *, struct perf_probe_event *); |
179 | } bpf_config_terms[] = { | 178 | } bpf_prog_config_terms[] = { |
180 | { | 179 | { |
181 | .key = "exec", | 180 | .key = "exec", |
182 | .usage = "exec=<full path of file>", | 181 | .usage = "exec=<full path of file>", |
183 | .desc = "Set uprobe target", | 182 | .desc = "Set uprobe target", |
184 | .func = config__exec, | 183 | .func = prog_config__exec, |
185 | }, | 184 | }, |
186 | { | 185 | { |
187 | .key = "module", | 186 | .key = "module", |
188 | .usage = "module=<module name> ", | 187 | .usage = "module=<module name> ", |
189 | .desc = "Set kprobe module", | 188 | .desc = "Set kprobe module", |
190 | .func = config__module, | 189 | .func = prog_config__module, |
191 | }, | 190 | }, |
192 | { | 191 | { |
193 | .key = "inlines", | 192 | .key = "inlines", |
194 | .usage = "inlines=[yes|no] ", | 193 | .usage = "inlines=[yes|no] ", |
195 | .desc = "Probe at inline symbol", | 194 | .desc = "Probe at inline symbol", |
196 | .func = config__inlines, | 195 | .func = prog_config__inlines, |
197 | }, | 196 | }, |
198 | { | 197 | { |
199 | .key = "force", | 198 | .key = "force", |
200 | .usage = "force=[yes|no] ", | 199 | .usage = "force=[yes|no] ", |
201 | .desc = "Forcibly add events with existing name", | 200 | .desc = "Forcibly add events with existing name", |
202 | .func = config__force, | 201 | .func = prog_config__force, |
203 | }, | 202 | }, |
204 | }; | 203 | }; |
205 | 204 | ||
206 | static int | 205 | static int |
207 | do_config(const char *key, const char *value, | 206 | do_prog_config(const char *key, const char *value, |
208 | struct perf_probe_event *pev) | 207 | struct perf_probe_event *pev) |
209 | { | 208 | { |
210 | unsigned int i; | 209 | unsigned int i; |
211 | 210 | ||
212 | pr_debug("config bpf program: %s=%s\n", key, value); | 211 | pr_debug("config bpf program: %s=%s\n", key, value); |
213 | for (i = 0; i < ARRAY_SIZE(bpf_config_terms); i++) | 212 | for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++) |
214 | if (strcmp(key, bpf_config_terms[i].key) == 0) | 213 | if (strcmp(key, bpf_prog_config_terms[i].key) == 0) |
215 | return bpf_config_terms[i].func(value, pev); | 214 | return bpf_prog_config_terms[i].func(value, pev); |
216 | 215 | ||
217 | pr_debug("BPF: ERROR: invalid config option in object: %s=%s\n", | 216 | pr_debug("BPF: ERROR: invalid program config option: %s=%s\n", |
218 | key, value); | 217 | key, value); |
219 | 218 | ||
220 | pr_debug("\nHint: Currently valid options are:\n"); | 219 | pr_debug("\nHint: Valid options are:\n"); |
221 | for (i = 0; i < ARRAY_SIZE(bpf_config_terms); i++) | 220 | for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++) |
222 | pr_debug("\t%s:\t%s\n", bpf_config_terms[i].usage, | 221 | pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage, |
223 | bpf_config_terms[i].desc); | 222 | bpf_prog_config_terms[i].desc); |
224 | pr_debug("\n"); | 223 | pr_debug("\n"); |
225 | 224 | ||
226 | return -BPF_LOADER_ERRNO__CONFIG_TERM; | 225 | return -BPF_LOADER_ERRNO__PROGCONF_TERM; |
227 | } | 226 | } |
228 | 227 | ||
229 | static const char * | 228 | static const char * |
230 | parse_config_kvpair(const char *config_str, struct perf_probe_event *pev) | 229 | parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev) |
231 | { | 230 | { |
232 | char *text = strdup(config_str); | 231 | char *text = strdup(config_str); |
233 | char *sep, *line; | 232 | char *sep, *line; |
@@ -253,7 +252,7 @@ parse_config_kvpair(const char *config_str, struct perf_probe_event *pev) | |||
253 | } | 252 | } |
254 | *equ = '\0'; | 253 | *equ = '\0'; |
255 | 254 | ||
256 | err = do_config(line, equ + 1, pev); | 255 | err = do_prog_config(line, equ + 1, pev); |
257 | if (err) | 256 | if (err) |
258 | break; | 257 | break; |
259 | nextline: | 258 | nextline: |
@@ -268,10 +267,10 @@ nextline: | |||
268 | } | 267 | } |
269 | 268 | ||
270 | static int | 269 | static int |
271 | parse_config(const char *config_str, struct perf_probe_event *pev) | 270 | parse_prog_config(const char *config_str, struct perf_probe_event *pev) |
272 | { | 271 | { |
273 | int err; | 272 | int err; |
274 | const char *main_str = parse_config_kvpair(config_str, pev); | 273 | const char *main_str = parse_prog_config_kvpair(config_str, pev); |
275 | 274 | ||
276 | if (IS_ERR(main_str)) | 275 | if (IS_ERR(main_str)) |
277 | return PTR_ERR(main_str); | 276 | return PTR_ERR(main_str); |
@@ -312,7 +311,7 @@ config_bpf_program(struct bpf_program *prog) | |||
312 | pev = &priv->pev; | 311 | pev = &priv->pev; |
313 | 312 | ||
314 | pr_debug("bpf: config program '%s'\n", config_str); | 313 | pr_debug("bpf: config program '%s'\n", config_str); |
315 | err = parse_config(config_str, pev); | 314 | err = parse_prog_config(config_str, pev); |
316 | if (err) | 315 | if (err) |
317 | goto errout; | 316 | goto errout; |
318 | 317 | ||
@@ -750,7 +749,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = { | |||
750 | [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", | 749 | [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", |
751 | [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", | 750 | [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", |
752 | [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", | 751 | [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", |
753 | [ERRCODE_OFFSET(CONFIG_TERM)] = "Invalid config term in config string", | 752 | [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string", |
754 | [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", | 753 | [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", |
755 | [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", | 754 | [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", |
756 | [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", | 755 | [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", |
@@ -834,7 +833,7 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | |||
834 | int err, char *buf, size_t size) | 833 | int err, char *buf, size_t size) |
835 | { | 834 | { |
836 | bpf__strerror_head(err, buf, size); | 835 | bpf__strerror_head(err, buf, size); |
837 | case BPF_LOADER_ERRNO__CONFIG_TERM: { | 836 | case BPF_LOADER_ERRNO__PROGCONF_TERM: { |
838 | scnprintf(buf, size, "%s (add -v to see detail)", emsg); | 837 | scnprintf(buf, size, "%s (add -v to see detail)", emsg); |
839 | break; | 838 | break; |
840 | } | 839 | } |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index a58740b0f31e..6fdc0457e2b6 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
@@ -20,7 +20,7 @@ enum bpf_loader_errno { | |||
20 | BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ | 20 | BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */ |
21 | BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ | 21 | BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */ |
22 | BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ | 22 | BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */ |
23 | BPF_LOADER_ERRNO__CONFIG_TERM, /* Invalid config term in config term */ | 23 | BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */ |
24 | BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ | 24 | BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ |
25 | BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ | 25 | BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ |
26 | BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ | 26 | BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 217b5a60e2ab..6a7e273a514a 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -91,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) | |||
91 | bid += 2; | 91 | bid += 2; |
92 | } | 92 | } |
93 | 93 | ||
94 | return raw - build_id; | 94 | return (bid - bf) + 1; |
95 | } | 95 | } |
96 | 96 | ||
97 | int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) | 97 | int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4fd37d6708cb..6e8e0ee9ec37 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -924,9 +924,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) | |||
924 | int64_t cmp = 0; | 924 | int64_t cmp = 0; |
925 | 925 | ||
926 | perf_hpp__for_each_sort_list(fmt) { | 926 | perf_hpp__for_each_sort_list(fmt) { |
927 | if (perf_hpp__should_skip(fmt)) | ||
928 | continue; | ||
929 | |||
930 | cmp = fmt->cmp(fmt, left, right); | 927 | cmp = fmt->cmp(fmt, left, right); |
931 | if (cmp) | 928 | if (cmp) |
932 | break; | 929 | break; |
@@ -942,9 +939,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
942 | int64_t cmp = 0; | 939 | int64_t cmp = 0; |
943 | 940 | ||
944 | perf_hpp__for_each_sort_list(fmt) { | 941 | perf_hpp__for_each_sort_list(fmt) { |
945 | if (perf_hpp__should_skip(fmt)) | ||
946 | continue; | ||
947 | |||
948 | cmp = fmt->collapse(fmt, left, right); | 942 | cmp = fmt->collapse(fmt, left, right); |
949 | if (cmp) | 943 | if (cmp) |
950 | break; | 944 | break; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index e48d9da75707..6fc8cd753e1a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { | |||
124 | .symbol = "dummy", | 124 | .symbol = "dummy", |
125 | .alias = "", | 125 | .alias = "", |
126 | }, | 126 | }, |
127 | [PERF_COUNT_SW_BPF_OUTPUT] = { | ||
128 | .symbol = "bpf-output", | ||
129 | .alias = "", | ||
130 | }, | ||
127 | }; | 131 | }; |
128 | 132 | ||
129 | #define __PERF_EVENT_FIELD(config, name) \ | 133 | #define __PERF_EVENT_FIELD(config, name) \ |
@@ -1879,7 +1883,7 @@ restart: | |||
1879 | 1883 | ||
1880 | for (i = 0; i < max; i++, syms++) { | 1884 | for (i = 0; i < max; i++, syms++) { |
1881 | 1885 | ||
1882 | if (event_glob != NULL && | 1886 | if (event_glob != NULL && syms->symbol != NULL && |
1883 | !(strglobmatch(syms->symbol, event_glob) || | 1887 | !(strglobmatch(syms->symbol, event_glob) || |
1884 | (syms->alias && strglobmatch(syms->alias, event_glob)))) | 1888 | (syms->alias && strglobmatch(syms->alias, event_glob)))) |
1885 | continue; | 1889 | continue; |