diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-12-14 03:31:39 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-12-14 03:31:39 -0500 |
commit | 0d76ded582c178d3cca55c9112eceb5b0f12f558 (patch) | |
tree | 0d75c2caf05d42b95385019ec4032587989dde25 | |
parent | 057032e457f702e2f4af18cfa99c3afab6841d24 (diff) | |
parent | 93b0ba3c60da89043ce2b9f601cd2b3da408903b (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 top' annotation in --stdio (Namhyung Kim)
- Support hw breakpoint events (mem:0xAddress) in the default output mode in
'perf script' (Wang Nan)
Infrastructure changes:
- Do not hold the hists lock while emitting one specific warning (Namhyung Kim)
- Fetch map names from correct strtab, worked so far because llvm/clang
uses just one string table (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 | 24 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 14 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 52 | ||||
-rw-r--r-- | tools/perf/util/data-convert-bt.c | 2 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 1 |
5 files changed, 57 insertions, 36 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index a298614ad091..8334a5a9d5d7 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c | |||
@@ -195,6 +195,7 @@ struct bpf_object { | |||
195 | Elf *elf; | 195 | Elf *elf; |
196 | GElf_Ehdr ehdr; | 196 | GElf_Ehdr ehdr; |
197 | Elf_Data *symbols; | 197 | Elf_Data *symbols; |
198 | size_t strtabidx; | ||
198 | struct { | 199 | struct { |
199 | GElf_Shdr shdr; | 200 | GElf_Shdr shdr; |
200 | Elf_Data *data; | 201 | Elf_Data *data; |
@@ -527,14 +528,14 @@ bpf_object__init_maps(struct bpf_object *obj, void *data, | |||
527 | return 0; | 528 | return 0; |
528 | } | 529 | } |
529 | 530 | ||
530 | static void | 531 | static int |
531 | bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) | 532 | bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) |
532 | { | 533 | { |
533 | int i; | 534 | int i; |
534 | Elf_Data *symbols = obj->efile.symbols; | 535 | Elf_Data *symbols = obj->efile.symbols; |
535 | 536 | ||
536 | if (!symbols || maps_shndx < 0) | 537 | if (!symbols || maps_shndx < 0) |
537 | return; | 538 | return -EINVAL; |
538 | 539 | ||
539 | for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { | 540 | for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { |
540 | GElf_Sym sym; | 541 | GElf_Sym sym; |
@@ -547,7 +548,7 @@ bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) | |||
547 | continue; | 548 | continue; |
548 | 549 | ||
549 | map_name = elf_strptr(obj->efile.elf, | 550 | map_name = elf_strptr(obj->efile.elf, |
550 | obj->efile.ehdr.e_shstrndx, | 551 | obj->efile.strtabidx, |
551 | sym.st_name); | 552 | sym.st_name); |
552 | map_idx = sym.st_value / sizeof(struct bpf_map_def); | 553 | map_idx = sym.st_value / sizeof(struct bpf_map_def); |
553 | if (map_idx >= obj->nr_maps) { | 554 | if (map_idx >= obj->nr_maps) { |
@@ -556,9 +557,14 @@ bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) | |||
556 | continue; | 557 | continue; |
557 | } | 558 | } |
558 | obj->maps[map_idx].name = strdup(map_name); | 559 | obj->maps[map_idx].name = strdup(map_name); |
560 | if (!obj->maps[map_idx].name) { | ||
561 | pr_warning("failed to alloc map name\n"); | ||
562 | return -ENOMEM; | ||
563 | } | ||
559 | pr_debug("map %zu is \"%s\"\n", map_idx, | 564 | pr_debug("map %zu is \"%s\"\n", map_idx, |
560 | obj->maps[map_idx].name); | 565 | obj->maps[map_idx].name); |
561 | } | 566 | } |
567 | return 0; | ||
562 | } | 568 | } |
563 | 569 | ||
564 | static int bpf_object__elf_collect(struct bpf_object *obj) | 570 | static int bpf_object__elf_collect(struct bpf_object *obj) |
@@ -625,8 +631,10 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
625 | pr_warning("bpf: multiple SYMTAB in %s\n", | 631 | pr_warning("bpf: multiple SYMTAB in %s\n", |
626 | obj->path); | 632 | obj->path); |
627 | err = -LIBBPF_ERRNO__FORMAT; | 633 | err = -LIBBPF_ERRNO__FORMAT; |
628 | } else | 634 | } else { |
629 | obj->efile.symbols = data; | 635 | obj->efile.symbols = data; |
636 | obj->efile.strtabidx = sh.sh_link; | ||
637 | } | ||
630 | } else if ((sh.sh_type == SHT_PROGBITS) && | 638 | } else if ((sh.sh_type == SHT_PROGBITS) && |
631 | (sh.sh_flags & SHF_EXECINSTR) && | 639 | (sh.sh_flags & SHF_EXECINSTR) && |
632 | (data->d_size > 0)) { | 640 | (data->d_size > 0)) { |
@@ -662,8 +670,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj) | |||
662 | goto out; | 670 | goto out; |
663 | } | 671 | } |
664 | 672 | ||
673 | if (!obj->efile.strtabidx || obj->efile.strtabidx >= idx) { | ||
674 | pr_warning("Corrupted ELF file: index of strtab invalid\n"); | ||
675 | return LIBBPF_ERRNO__FORMAT; | ||
676 | } | ||
665 | if (maps_shndx >= 0) | 677 | if (maps_shndx >= 0) |
666 | bpf_object__init_maps_name(obj, maps_shndx); | 678 | err = bpf_object__init_maps_name(obj, maps_shndx); |
667 | out: | 679 | out: |
668 | return err; | 680 | return err; |
669 | } | 681 | } |
@@ -1372,7 +1384,7 @@ bpf_object__get_map_by_name(struct bpf_object *obj, const char *name) | |||
1372 | struct bpf_map *pos; | 1384 | struct bpf_map *pos; |
1373 | 1385 | ||
1374 | bpf_map__for_each(pos, obj) { | 1386 | bpf_map__for_each(pos, obj) { |
1375 | if (strcmp(pos->name, name) == 0) | 1387 | if (pos->name && !strcmp(pos->name, name)) |
1376 | return pos; | 1388 | return pos; |
1377 | } | 1389 | } |
1378 | return NULL; | 1390 | return NULL; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3c3f8d0e3064..d259e9aa3a71 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -130,6 +130,18 @@ static struct { | |||
130 | 130 | ||
131 | .invalid_fields = PERF_OUTPUT_TRACE, | 131 | .invalid_fields = PERF_OUTPUT_TRACE, |
132 | }, | 132 | }, |
133 | |||
134 | [PERF_TYPE_BREAKPOINT] = { | ||
135 | .user_set = false, | ||
136 | |||
137 | .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | | ||
138 | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | | ||
139 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | ||
140 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | ||
141 | PERF_OUTPUT_PERIOD, | ||
142 | |||
143 | .invalid_fields = PERF_OUTPUT_TRACE, | ||
144 | }, | ||
133 | }; | 145 | }; |
134 | 146 | ||
135 | static bool output_set_by_user(void) | 147 | static bool output_set_by_user(void) |
@@ -1129,6 +1141,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused, | |||
1129 | type = PERF_TYPE_TRACEPOINT; | 1141 | type = PERF_TYPE_TRACEPOINT; |
1130 | else if (!strcmp(str, "raw")) | 1142 | else if (!strcmp(str, "raw")) |
1131 | type = PERF_TYPE_RAW; | 1143 | type = PERF_TYPE_RAW; |
1144 | else if (!strcmp(str, "break")) | ||
1145 | type = PERF_TYPE_BREAKPOINT; | ||
1132 | else { | 1146 | else { |
1133 | fprintf(stderr, "Invalid event type in field string.\n"); | 1147 | fprintf(stderr, "Invalid event type in field string.\n"); |
1134 | rc = -EINVAL; | 1148 | rc = -EINVAL; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 785aa2dd8f0b..92fe963e43c4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -175,42 +175,40 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
175 | int counter, u64 ip) | 175 | int counter, u64 ip) |
176 | { | 176 | { |
177 | struct annotation *notes; | 177 | struct annotation *notes; |
178 | struct symbol *sym; | 178 | struct symbol *sym = he->ms.sym; |
179 | int err = 0; | 179 | int err = 0; |
180 | 180 | ||
181 | if (he == NULL || he->ms.sym == NULL || | 181 | if (sym == NULL || (use_browser == 0 && |
182 | ((top->sym_filter_entry == NULL || | 182 | (top->sym_filter_entry == NULL || |
183 | top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | 183 | top->sym_filter_entry->ms.sym != sym))) |
184 | return; | 184 | return; |
185 | 185 | ||
186 | sym = he->ms.sym; | ||
187 | notes = symbol__annotation(sym); | 186 | notes = symbol__annotation(sym); |
188 | 187 | ||
189 | if (pthread_mutex_trylock(¬es->lock)) | 188 | if (pthread_mutex_trylock(¬es->lock)) |
190 | return; | 189 | return; |
191 | 190 | ||
192 | ip = he->ms.map->map_ip(he->ms.map, ip); | 191 | err = hist_entry__inc_addr_samples(he, counter, ip); |
193 | |||
194 | if (ui__has_annotation()) | ||
195 | err = hist_entry__inc_addr_samples(he, counter, ip); | ||
196 | 192 | ||
197 | pthread_mutex_unlock(¬es->lock); | 193 | pthread_mutex_unlock(¬es->lock); |
198 | 194 | ||
199 | /* | 195 | if (unlikely(err)) { |
200 | * This function is now called with he->hists->lock held. | 196 | /* |
201 | * Release it before going to sleep. | 197 | * This function is now called with he->hists->lock held. |
202 | */ | 198 | * Release it before going to sleep. |
203 | pthread_mutex_unlock(&he->hists->lock); | 199 | */ |
200 | pthread_mutex_unlock(&he->hists->lock); | ||
201 | |||
202 | if (err == -ERANGE && !he->ms.map->erange_warned) | ||
203 | ui__warn_map_erange(he->ms.map, sym, ip); | ||
204 | else if (err == -ENOMEM) { | ||
205 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
206 | sym->name); | ||
207 | sleep(1); | ||
208 | } | ||
204 | 209 | ||
205 | if (err == -ERANGE && !he->ms.map->erange_warned) | 210 | pthread_mutex_lock(&he->hists->lock); |
206 | ui__warn_map_erange(he->ms.map, sym, ip); | ||
207 | else if (err == -ENOMEM) { | ||
208 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
209 | sym->name); | ||
210 | sleep(1); | ||
211 | } | 211 | } |
212 | |||
213 | pthread_mutex_lock(&he->hists->lock); | ||
214 | } | 212 | } |
215 | 213 | ||
216 | static void perf_top__show_details(struct perf_top *top) | 214 | static void perf_top__show_details(struct perf_top *top) |
@@ -687,14 +685,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, | |||
687 | struct hist_entry *he = iter->he; | 685 | struct hist_entry *he = iter->he; |
688 | struct perf_evsel *evsel = iter->evsel; | 686 | struct perf_evsel *evsel = iter->evsel; |
689 | 687 | ||
690 | if (sort__has_sym && single) { | 688 | if (sort__has_sym && single) |
691 | u64 ip = al->addr; | 689 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); |
692 | |||
693 | if (al->map) | ||
694 | ip = al->map->unmap_ip(al->map, ip); | ||
695 | |||
696 | perf_top__record_precise_ip(top, he, evsel->idx, ip); | ||
697 | } | ||
698 | 690 | ||
699 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 691 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, |
700 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); | 692 | !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 5bfc1198ab46..34cd1e4039d3 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -63,6 +63,7 @@ struct ctf_writer { | |||
63 | struct bt_ctf_field_type *s32; | 63 | struct bt_ctf_field_type *s32; |
64 | struct bt_ctf_field_type *u32; | 64 | struct bt_ctf_field_type *u32; |
65 | struct bt_ctf_field_type *string; | 65 | struct bt_ctf_field_type *string; |
66 | struct bt_ctf_field_type *u32_hex; | ||
66 | struct bt_ctf_field_type *u64_hex; | 67 | struct bt_ctf_field_type *u64_hex; |
67 | }; | 68 | }; |
68 | struct bt_ctf_field_type *array[6]; | 69 | struct bt_ctf_field_type *array[6]; |
@@ -982,6 +983,7 @@ do { \ | |||
982 | CREATE_INT_TYPE(cw->data.u64, 64, false, false); | 983 | CREATE_INT_TYPE(cw->data.u64, 64, false, false); |
983 | CREATE_INT_TYPE(cw->data.s32, 32, true, false); | 984 | CREATE_INT_TYPE(cw->data.s32, 32, true, false); |
984 | CREATE_INT_TYPE(cw->data.u32, 32, false, false); | 985 | CREATE_INT_TYPE(cw->data.u32, 32, false, false); |
986 | CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true); | ||
985 | CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); | 987 | CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); |
986 | 988 | ||
987 | cw->data.string = bt_ctf_field_type_string_create(); | 989 | cw->data.string = bt_ctf_field_type_string_create(); |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index f5882b8c8db9..1407d5107480 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -25,6 +25,7 @@ static void dsos__init(struct dsos *dsos) | |||
25 | 25 | ||
26 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 26 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
27 | { | 27 | { |
28 | memset(machine, 0, sizeof(*machine)); | ||
28 | map_groups__init(&machine->kmaps, machine); | 29 | map_groups__init(&machine->kmaps, machine); |
29 | RB_CLEAR_NODE(&machine->rb_node); | 30 | RB_CLEAR_NODE(&machine->rb_node); |
30 | dsos__init(&machine->dsos); | 31 | dsos__init(&machine->dsos); |