diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-05-27 12:42:36 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-05-27 12:42:36 -0400 |
commit | 6632c4b4e96c668e19173fa17f2c58c60490bac3 (patch) | |
tree | 7d9cae783cc4da0968f6c826ea4954c56217357b /tools/perf | |
parent | a82d24edfeaf1ed244cf8b969916840c6feb5165 (diff) | |
parent | dddc7ee32fa13efc66afa71ebd83bce545c8392a (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:
New features:
- Add option in 'perf sched' to merge like comms to lat output (Josef Bacik)
- Improve 'perf probe' error messages when not finding a
suitable vmlinux (Masami Hiramatsu)
Infrastructure changes:
- Use atomic.h for various pre-existing reference counts (Arnaldo Carvalho de Melo)
- Leg work for refcounting 'struct map' (Arnaldo Carvalho de Melo)
- Assign default value for some pointers (Martin Liška)
- Improve setting of gcc debug option (Martin Liška)
- Separate the tests and tools in installation (Nam T. Nguyen)
- Reduce number of arguments of hist_entry_iter__add() (Namhyung Kim)
- DSO data cache fixes (Namhyung Kim)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
33 files changed, 332 insertions, 204 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 03409cc02117..5816a3bb7e9f 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -464,7 +464,7 @@ check: $(OUTPUT)common-cmds.h | |||
464 | 464 | ||
465 | install-gtk: | 465 | install-gtk: |
466 | 466 | ||
467 | install-bin: all install-gtk | 467 | install-tools: all install-gtk |
468 | $(call QUIET_INSTALL, binaries) \ | 468 | $(call QUIET_INSTALL, binaries) \ |
469 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ | 469 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ |
470 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ | 470 | $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ |
@@ -502,12 +502,16 @@ endif | |||
502 | $(call QUIET_INSTALL, perf_completion-script) \ | 502 | $(call QUIET_INSTALL, perf_completion-script) \ |
503 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ | 503 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ |
504 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' | 504 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' |
505 | |||
506 | install-tests: all install-gtk | ||
505 | $(call QUIET_INSTALL, tests) \ | 507 | $(call QUIET_INSTALL, tests) \ |
506 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 508 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
507 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 509 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
508 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 510 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
509 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 511 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
510 | 512 | ||
513 | install-bin: install-tools install-tests | ||
514 | |||
511 | install: install-bin try-install-man install-traceevent-plugins | 515 | install: install-bin try-install-man install-traceevent-plugins |
512 | 516 | ||
513 | install-python_ext: | 517 | install-python_ext: |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 49776f190abf..b7bb42c44694 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -61,7 +61,7 @@ const char *const mips_triplets[] = { | |||
61 | static bool lookup_path(char *name) | 61 | static bool lookup_path(char *name) |
62 | { | 62 | { |
63 | bool found = false; | 63 | bool found = false; |
64 | char *path, *tmp; | 64 | char *path, *tmp = NULL; |
65 | char buf[PATH_MAX]; | 65 | char buf[PATH_MAX]; |
66 | char *env = getenv("PATH"); | 66 | char *env = getenv("PATH"); |
67 | 67 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 92fca2157e5e..56025d90622f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -139,8 +139,10 @@ static int process_sample_event(struct perf_tool *tool, | |||
139 | struct report *rep = container_of(tool, struct report, tool); | 139 | struct report *rep = container_of(tool, struct report, tool); |
140 | struct addr_location al; | 140 | struct addr_location al; |
141 | struct hist_entry_iter iter = { | 141 | struct hist_entry_iter iter = { |
142 | .hide_unresolved = rep->hide_unresolved, | 142 | .evsel = evsel, |
143 | .add_entry_cb = hist_iter__report_callback, | 143 | .sample = sample, |
144 | .hide_unresolved = rep->hide_unresolved, | ||
145 | .add_entry_cb = hist_iter__report_callback, | ||
144 | }; | 146 | }; |
145 | int ret = 0; | 147 | int ret = 0; |
146 | 148 | ||
@@ -168,8 +170,7 @@ static int process_sample_event(struct perf_tool *tool, | |||
168 | if (al.map != NULL) | 170 | if (al.map != NULL) |
169 | al.map->dso->hit = 1; | 171 | al.map->dso->hit = 1; |
170 | 172 | ||
171 | ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack, | 173 | ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep); |
172 | rep); | ||
173 | if (ret < 0) | 174 | if (ret < 0) |
174 | pr_debug("problem adding hist entry, skipping event\n"); | 175 | pr_debug("problem adding hist entry, skipping event\n"); |
175 | out_put: | 176 | out_put: |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 79273ecf92eb..33962612a5e9 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -95,6 +95,7 @@ struct work_atoms { | |||
95 | u64 total_lat; | 95 | u64 total_lat; |
96 | u64 nb_atoms; | 96 | u64 nb_atoms; |
97 | u64 total_runtime; | 97 | u64 total_runtime; |
98 | int num_merged; | ||
98 | }; | 99 | }; |
99 | 100 | ||
100 | typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); | 101 | typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *); |
@@ -168,9 +169,10 @@ struct perf_sched { | |||
168 | u64 all_runtime; | 169 | u64 all_runtime; |
169 | u64 all_count; | 170 | u64 all_count; |
170 | u64 cpu_last_switched[MAX_CPUS]; | 171 | u64 cpu_last_switched[MAX_CPUS]; |
171 | struct rb_root atom_root, sorted_atom_root; | 172 | struct rb_root atom_root, sorted_atom_root, merged_atom_root; |
172 | struct list_head sort_list, cmp_pid; | 173 | struct list_head sort_list, cmp_pid; |
173 | bool force; | 174 | bool force; |
175 | bool skip_merge; | ||
174 | }; | 176 | }; |
175 | 177 | ||
176 | static u64 get_nsecs(void) | 178 | static u64 get_nsecs(void) |
@@ -1182,7 +1184,10 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1182 | sched->all_runtime += work_list->total_runtime; | 1184 | sched->all_runtime += work_list->total_runtime; |
1183 | sched->all_count += work_list->nb_atoms; | 1185 | sched->all_count += work_list->nb_atoms; |
1184 | 1186 | ||
1185 | ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid); | 1187 | if (work_list->num_merged > 1) |
1188 | ret = printf(" %s:(%d) ", thread__comm_str(work_list->thread), work_list->num_merged); | ||
1189 | else | ||
1190 | ret = printf(" %s:%d ", thread__comm_str(work_list->thread), work_list->thread->tid); | ||
1186 | 1191 | ||
1187 | for (i = 0; i < 24 - ret; i++) | 1192 | for (i = 0; i < 24 - ret; i++) |
1188 | printf(" "); | 1193 | printf(" "); |
@@ -1302,17 +1307,22 @@ static int sort_dimension__add(const char *tok, struct list_head *list) | |||
1302 | static void perf_sched__sort_lat(struct perf_sched *sched) | 1307 | static void perf_sched__sort_lat(struct perf_sched *sched) |
1303 | { | 1308 | { |
1304 | struct rb_node *node; | 1309 | struct rb_node *node; |
1305 | 1310 | struct rb_root *root = &sched->atom_root; | |
1311 | again: | ||
1306 | for (;;) { | 1312 | for (;;) { |
1307 | struct work_atoms *data; | 1313 | struct work_atoms *data; |
1308 | node = rb_first(&sched->atom_root); | 1314 | node = rb_first(root); |
1309 | if (!node) | 1315 | if (!node) |
1310 | break; | 1316 | break; |
1311 | 1317 | ||
1312 | rb_erase(node, &sched->atom_root); | 1318 | rb_erase(node, root); |
1313 | data = rb_entry(node, struct work_atoms, node); | 1319 | data = rb_entry(node, struct work_atoms, node); |
1314 | __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list); | 1320 | __thread_latency_insert(&sched->sorted_atom_root, data, &sched->sort_list); |
1315 | } | 1321 | } |
1322 | if (root == &sched->atom_root) { | ||
1323 | root = &sched->merged_atom_root; | ||
1324 | goto again; | ||
1325 | } | ||
1316 | } | 1326 | } |
1317 | 1327 | ||
1318 | static int process_sched_wakeup_event(struct perf_tool *tool, | 1328 | static int process_sched_wakeup_event(struct perf_tool *tool, |
@@ -1572,6 +1582,59 @@ static void print_bad_events(struct perf_sched *sched) | |||
1572 | } | 1582 | } |
1573 | } | 1583 | } |
1574 | 1584 | ||
1585 | static void __merge_work_atoms(struct rb_root *root, struct work_atoms *data) | ||
1586 | { | ||
1587 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
1588 | struct work_atoms *this; | ||
1589 | const char *comm = thread__comm_str(data->thread), *this_comm; | ||
1590 | |||
1591 | while (*new) { | ||
1592 | int cmp; | ||
1593 | |||
1594 | this = container_of(*new, struct work_atoms, node); | ||
1595 | parent = *new; | ||
1596 | |||
1597 | this_comm = thread__comm_str(this->thread); | ||
1598 | cmp = strcmp(comm, this_comm); | ||
1599 | if (cmp > 0) { | ||
1600 | new = &((*new)->rb_left); | ||
1601 | } else if (cmp < 0) { | ||
1602 | new = &((*new)->rb_right); | ||
1603 | } else { | ||
1604 | this->num_merged++; | ||
1605 | this->total_runtime += data->total_runtime; | ||
1606 | this->nb_atoms += data->nb_atoms; | ||
1607 | this->total_lat += data->total_lat; | ||
1608 | list_splice(&data->work_list, &this->work_list); | ||
1609 | if (this->max_lat < data->max_lat) { | ||
1610 | this->max_lat = data->max_lat; | ||
1611 | this->max_lat_at = data->max_lat_at; | ||
1612 | } | ||
1613 | zfree(&data); | ||
1614 | return; | ||
1615 | } | ||
1616 | } | ||
1617 | |||
1618 | data->num_merged++; | ||
1619 | rb_link_node(&data->node, parent, new); | ||
1620 | rb_insert_color(&data->node, root); | ||
1621 | } | ||
1622 | |||
1623 | static void perf_sched__merge_lat(struct perf_sched *sched) | ||
1624 | { | ||
1625 | struct work_atoms *data; | ||
1626 | struct rb_node *node; | ||
1627 | |||
1628 | if (sched->skip_merge) | ||
1629 | return; | ||
1630 | |||
1631 | while ((node = rb_first(&sched->atom_root))) { | ||
1632 | rb_erase(node, &sched->atom_root); | ||
1633 | data = rb_entry(node, struct work_atoms, node); | ||
1634 | __merge_work_atoms(&sched->merged_atom_root, data); | ||
1635 | } | ||
1636 | } | ||
1637 | |||
1575 | static int perf_sched__lat(struct perf_sched *sched) | 1638 | static int perf_sched__lat(struct perf_sched *sched) |
1576 | { | 1639 | { |
1577 | struct rb_node *next; | 1640 | struct rb_node *next; |
@@ -1581,6 +1644,7 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1581 | if (perf_sched__read_events(sched)) | 1644 | if (perf_sched__read_events(sched)) |
1582 | return -1; | 1645 | return -1; |
1583 | 1646 | ||
1647 | perf_sched__merge_lat(sched); | ||
1584 | perf_sched__sort_lat(sched); | 1648 | perf_sched__sort_lat(sched); |
1585 | 1649 | ||
1586 | printf("\n -----------------------------------------------------------------------------------------------------------------\n"); | 1650 | printf("\n -----------------------------------------------------------------------------------------------------------------\n"); |
@@ -1732,6 +1796,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1732 | .profile_cpu = -1, | 1796 | .profile_cpu = -1, |
1733 | .next_shortname1 = 'A', | 1797 | .next_shortname1 = 'A', |
1734 | .next_shortname2 = '0', | 1798 | .next_shortname2 = '0', |
1799 | .skip_merge = 0, | ||
1735 | }; | 1800 | }; |
1736 | const struct option latency_options[] = { | 1801 | const struct option latency_options[] = { |
1737 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", | 1802 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", |
@@ -1742,6 +1807,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1742 | "CPU to profile on"), | 1807 | "CPU to profile on"), |
1743 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 1808 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
1744 | "dump raw trace in ASCII"), | 1809 | "dump raw trace in ASCII"), |
1810 | OPT_BOOLEAN('p', "pids", &sched.skip_merge, | ||
1811 | "latency stats per pid instead of per comm"), | ||
1745 | OPT_END() | 1812 | OPT_END() |
1746 | }; | 1813 | }; |
1747 | const struct option replay_options[] = { | 1814 | const struct option replay_options[] = { |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a19351728f0f..6b987424d015 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -775,7 +775,9 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
775 | if (al.sym == NULL || !al.sym->ignore) { | 775 | if (al.sym == NULL || !al.sym->ignore) { |
776 | struct hists *hists = evsel__hists(evsel); | 776 | struct hists *hists = evsel__hists(evsel); |
777 | struct hist_entry_iter iter = { | 777 | struct hist_entry_iter iter = { |
778 | .add_entry_cb = hist_iter__top_callback, | 778 | .evsel = evsel, |
779 | .sample = sample, | ||
780 | .add_entry_cb = hist_iter__top_callback, | ||
779 | }; | 781 | }; |
780 | 782 | ||
781 | if (symbol_conf.cumulate_callchain) | 783 | if (symbol_conf.cumulate_callchain) |
@@ -785,8 +787,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
785 | 787 | ||
786 | pthread_mutex_lock(&hists->lock); | 788 | pthread_mutex_lock(&hists->lock); |
787 | 789 | ||
788 | err = hist_entry_iter__add(&iter, &al, evsel, sample, | 790 | err = hist_entry_iter__add(&iter, &al, top->max_stack, top); |
789 | top->max_stack, top); | ||
790 | if (err < 0) | 791 | if (err < 0) |
791 | pr_err("Problem incrementing symbol period, skipping event\n"); | 792 | pr_err("Problem incrementing symbol period, skipping event\n"); |
792 | 793 | ||
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1b957a1272d0..317001c94660 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -32,7 +32,7 @@ ifeq ($(ARCH),x86) | |||
32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
33 | $(call detected,CONFIG_X86_64) | 33 | $(call detected,CONFIG_X86_64) |
34 | else | 34 | else |
35 | LIBUNWIND_LIBS = -lunwind -lunwind-x86 | 35 | LIBUNWIND_LIBS = -lunwind-x86 -llzma -lunwind |
36 | endif | 36 | endif |
37 | NO_PERF_REGS := 0 | 37 | NO_PERF_REGS := 0 |
38 | endif | 38 | endif |
@@ -130,6 +130,8 @@ endif | |||
130 | 130 | ||
131 | ifeq ($(DEBUG),0) | 131 | ifeq ($(DEBUG),0) |
132 | CFLAGS += -O6 | 132 | CFLAGS += -O6 |
133 | else | ||
134 | CFLAGS += $(call cc-option,-Og,-O0) | ||
133 | endif | 135 | endif |
134 | 136 | ||
135 | ifdef PARSER_DEBUG | 137 | ifdef PARSER_DEBUG |
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index c16ce833079c..0ebef09c0842 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
@@ -177,3 +177,22 @@ $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) | |||
177 | endef | 177 | endef |
178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2))) | 178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2))) |
179 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) | 179 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) |
180 | |||
181 | # try-run | ||
182 | # Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) | ||
183 | # Exit code chooses option. "$$TMP" is can be used as temporary file and | ||
184 | # is automatically cleaned up. | ||
185 | try-run = $(shell set -e; \ | ||
186 | TMP="$(TMPOUT).$$$$.tmp"; \ | ||
187 | TMPO="$(TMPOUT).$$$$.o"; \ | ||
188 | if ($(1)) >/dev/null 2>&1; \ | ||
189 | then echo "$(2)"; \ | ||
190 | else echo "$(3)"; \ | ||
191 | fi; \ | ||
192 | rm -f "$$TMP" "$$TMPO") | ||
193 | |||
194 | # cc-option | ||
195 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) | ||
196 | |||
197 | cc-option = $(call try-run,\ | ||
198 | $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) | ||
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 513e5febbe5a..3e41c61bd861 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -99,6 +99,17 @@ struct test_data_offset offsets[] = { | |||
99 | }, | 99 | }, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | /* move it from util/dso.c for compatibility */ | ||
103 | static int dso__data_fd(struct dso *dso, struct machine *machine) | ||
104 | { | ||
105 | int fd = dso__data_get_fd(dso, machine); | ||
106 | |||
107 | if (fd >= 0) | ||
108 | dso__data_put_fd(dso); | ||
109 | |||
110 | return fd; | ||
111 | } | ||
112 | |||
102 | int test__dso_data(void) | 113 | int test__dso_data(void) |
103 | { | 114 | { |
104 | struct machine machine; | 115 | struct machine machine; |
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 620f626e5b35..7d82c8be5e36 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
@@ -87,6 +87,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
87 | }, | 87 | }, |
88 | }; | 88 | }; |
89 | struct hist_entry_iter iter = { | 89 | struct hist_entry_iter iter = { |
90 | .evsel = evsel, | ||
91 | .sample = &sample, | ||
90 | .hide_unresolved = false, | 92 | .hide_unresolved = false, |
91 | }; | 93 | }; |
92 | 94 | ||
@@ -104,8 +106,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
104 | &sample) < 0) | 106 | &sample) < 0) |
105 | goto out; | 107 | goto out; |
106 | 108 | ||
107 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, | 109 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, |
108 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 110 | NULL) < 0) { |
109 | addr_location__put(&al); | 111 | addr_location__put(&al); |
110 | goto out; | 112 | goto out; |
111 | } | 113 | } |
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 82e1ee52e024..ce48775e6ada 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -63,6 +63,8 @@ static int add_hist_entries(struct perf_evlist *evlist, | |||
63 | }, | 63 | }, |
64 | }; | 64 | }; |
65 | struct hist_entry_iter iter = { | 65 | struct hist_entry_iter iter = { |
66 | .evsel = evsel, | ||
67 | .sample = &sample, | ||
66 | .ops = &hist_iter_normal, | 68 | .ops = &hist_iter_normal, |
67 | .hide_unresolved = false, | 69 | .hide_unresolved = false, |
68 | }; | 70 | }; |
@@ -81,7 +83,7 @@ static int add_hist_entries(struct perf_evlist *evlist, | |||
81 | &sample) < 0) | 83 | &sample) < 0) |
82 | goto out; | 84 | goto out; |
83 | 85 | ||
84 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, | 86 | if (hist_entry_iter__add(&iter, &al, |
85 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 87 | PERF_MAX_STACK_DEPTH, NULL) < 0) { |
86 | addr_location__put(&al); | 88 | addr_location__put(&al); |
87 | goto out; | 89 | goto out; |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index fd7ec4f9aeb4..adbebc852cc8 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -57,6 +57,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
57 | }, | 57 | }, |
58 | }; | 58 | }; |
59 | struct hist_entry_iter iter = { | 59 | struct hist_entry_iter iter = { |
60 | .evsel = evsel, | ||
61 | .sample = &sample, | ||
60 | .ops = &hist_iter_normal, | 62 | .ops = &hist_iter_normal, |
61 | .hide_unresolved = false, | 63 | .hide_unresolved = false, |
62 | }; | 64 | }; |
@@ -70,8 +72,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
70 | &sample) < 0) | 72 | &sample) < 0) |
71 | goto out; | 73 | goto out; |
72 | 74 | ||
73 | if (hist_entry_iter__add(&iter, &al, evsel, &sample, | 75 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, |
74 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 76 | NULL) < 0) { |
75 | addr_location__put(&al); | 77 | addr_location__put(&al); |
76 | goto out; | 78 | goto out; |
77 | } | 79 | } |
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 3d9088003a5b..94ac6924df65 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
@@ -23,9 +23,10 @@ int test__vmlinux_matches_kallsyms(void) | |||
23 | int err = -1; | 23 | int err = -1; |
24 | struct rb_node *nd; | 24 | struct rb_node *nd; |
25 | struct symbol *sym; | 25 | struct symbol *sym; |
26 | struct map *kallsyms_map, *vmlinux_map; | 26 | struct map *kallsyms_map, *vmlinux_map, *map; |
27 | struct machine kallsyms, vmlinux; | 27 | struct machine kallsyms, vmlinux; |
28 | enum map_type type = MAP__FUNCTION; | 28 | enum map_type type = MAP__FUNCTION; |
29 | struct rb_root *maps = &vmlinux.kmaps.maps[type]; | ||
29 | u64 mem_start, mem_end; | 30 | u64 mem_start, mem_end; |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -184,8 +185,8 @@ detour: | |||
184 | 185 | ||
185 | pr_info("Maps only in vmlinux:\n"); | 186 | pr_info("Maps only in vmlinux:\n"); |
186 | 187 | ||
187 | for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { | 188 | for (map = maps__first(maps); map; map = map__next(map)) { |
188 | struct map *pos = rb_entry(nd, struct map, rb_node), *pair; | 189 | struct map * |
189 | /* | 190 | /* |
190 | * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while | 191 | * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while |
191 | * the kernel will have the path for the vmlinux file being used, | 192 | * the kernel will have the path for the vmlinux file being used, |
@@ -193,22 +194,22 @@ detour: | |||
193 | * both cases. | 194 | * both cases. |
194 | */ | 195 | */ |
195 | pair = map_groups__find_by_name(&kallsyms.kmaps, type, | 196 | pair = map_groups__find_by_name(&kallsyms.kmaps, type, |
196 | (pos->dso->kernel ? | 197 | (map->dso->kernel ? |
197 | pos->dso->short_name : | 198 | map->dso->short_name : |
198 | pos->dso->name)); | 199 | map->dso->name)); |
199 | if (pair) | 200 | if (pair) |
200 | pair->priv = 1; | 201 | pair->priv = 1; |
201 | else | 202 | else |
202 | map__fprintf(pos, stderr); | 203 | map__fprintf(map, stderr); |
203 | } | 204 | } |
204 | 205 | ||
205 | pr_info("Maps in vmlinux with a different name in kallsyms:\n"); | 206 | pr_info("Maps in vmlinux with a different name in kallsyms:\n"); |
206 | 207 | ||
207 | for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) { | 208 | for (map = maps__first(maps); map; map = map__next(map)) { |
208 | struct map *pos = rb_entry(nd, struct map, rb_node), *pair; | 209 | struct map *pair; |
209 | 210 | ||
210 | mem_start = vmlinux_map->unmap_ip(vmlinux_map, pos->start); | 211 | mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start); |
211 | mem_end = vmlinux_map->unmap_ip(vmlinux_map, pos->end); | 212 | mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end); |
212 | 213 | ||
213 | pair = map_groups__find(&kallsyms.kmaps, type, mem_start); | 214 | pair = map_groups__find(&kallsyms.kmaps, type, mem_start); |
214 | if (pair == NULL || pair->priv) | 215 | if (pair == NULL || pair->priv) |
@@ -217,7 +218,7 @@ detour: | |||
217 | if (pair->start == mem_start) { | 218 | if (pair->start == mem_start) { |
218 | pair->priv = 1; | 219 | pair->priv = 1; |
219 | pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", | 220 | pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", |
220 | pos->start, pos->end, pos->pgoff, pos->dso->name); | 221 | map->start, map->end, map->pgoff, map->dso->name); |
221 | if (mem_end != pair->end) | 222 | if (mem_end != pair->end) |
222 | pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64, | 223 | pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64, |
223 | pair->start, pair->end, pair->pgoff); | 224 | pair->start, pair->end, pair->pgoff); |
@@ -228,12 +229,11 @@ detour: | |||
228 | 229 | ||
229 | pr_info("Maps only in kallsyms:\n"); | 230 | pr_info("Maps only in kallsyms:\n"); |
230 | 231 | ||
231 | for (nd = rb_first(&kallsyms.kmaps.maps[type]); | 232 | maps = &kallsyms.kmaps.maps[type]; |
232 | nd; nd = rb_next(nd)) { | ||
233 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
234 | 233 | ||
235 | if (!pos->priv) | 234 | for (map = maps__first(maps); map; map = map__next(map)) { |
236 | map__fprintf(pos, stderr); | 235 | if (!map->priv) |
236 | map__fprintf(map, stderr); | ||
237 | } | 237 | } |
238 | out: | 238 | out: |
239 | machine__exit(&kallsyms); | 239 | machine__exit(&kallsyms); |
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index b2bb59df65e1..21b7ff382c3f 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c | |||
@@ -2,24 +2,27 @@ | |||
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include <stdlib.h> | 3 | #include <stdlib.h> |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | #include <linux/atomic.h> | ||
5 | 6 | ||
6 | struct comm_str { | 7 | struct comm_str { |
7 | char *str; | 8 | char *str; |
8 | struct rb_node rb_node; | 9 | struct rb_node rb_node; |
9 | int ref; | 10 | atomic_t refcnt; |
10 | }; | 11 | }; |
11 | 12 | ||
12 | /* Should perhaps be moved to struct machine */ | 13 | /* Should perhaps be moved to struct machine */ |
13 | static struct rb_root comm_str_root; | 14 | static struct rb_root comm_str_root; |
14 | 15 | ||
15 | static void comm_str__get(struct comm_str *cs) | 16 | static struct comm_str *comm_str__get(struct comm_str *cs) |
16 | { | 17 | { |
17 | cs->ref++; | 18 | if (cs) |
19 | atomic_inc(&cs->refcnt); | ||
20 | return cs; | ||
18 | } | 21 | } |
19 | 22 | ||
20 | static void comm_str__put(struct comm_str *cs) | 23 | static void comm_str__put(struct comm_str *cs) |
21 | { | 24 | { |
22 | if (!--cs->ref) { | 25 | if (cs && atomic_dec_and_test(&cs->refcnt)) { |
23 | rb_erase(&cs->rb_node, &comm_str_root); | 26 | rb_erase(&cs->rb_node, &comm_str_root); |
24 | zfree(&cs->str); | 27 | zfree(&cs->str); |
25 | free(cs); | 28 | free(cs); |
@@ -40,6 +43,8 @@ static struct comm_str *comm_str__alloc(const char *str) | |||
40 | return NULL; | 43 | return NULL; |
41 | } | 44 | } |
42 | 45 | ||
46 | atomic_set(&cs->refcnt, 0); | ||
47 | |||
43 | return cs; | 48 | return cs; |
44 | } | 49 | } |
45 | 50 | ||
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 1b96c8d18435..7e11a700303f 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -440,15 +440,7 @@ void dso__data_close(struct dso *dso) | |||
440 | pthread_mutex_unlock(&dso__data_open_lock); | 440 | pthread_mutex_unlock(&dso__data_open_lock); |
441 | } | 441 | } |
442 | 442 | ||
443 | /** | 443 | static void try_to_open_dso(struct dso *dso, struct machine *machine) |
444 | * dso__data_fd - Get dso's data file descriptor | ||
445 | * @dso: dso object | ||
446 | * @machine: machine object | ||
447 | * | ||
448 | * External interface to find dso's file, open it and | ||
449 | * returns file descriptor. | ||
450 | */ | ||
451 | int dso__data_fd(struct dso *dso, struct machine *machine) | ||
452 | { | 444 | { |
453 | enum dso_binary_type binary_type_data[] = { | 445 | enum dso_binary_type binary_type_data[] = { |
454 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | 446 | DSO_BINARY_TYPE__BUILD_ID_CACHE, |
@@ -457,13 +449,8 @@ int dso__data_fd(struct dso *dso, struct machine *machine) | |||
457 | }; | 449 | }; |
458 | int i = 0; | 450 | int i = 0; |
459 | 451 | ||
460 | if (dso->data.status == DSO_DATA_STATUS_ERROR) | ||
461 | return -1; | ||
462 | |||
463 | pthread_mutex_lock(&dso__data_open_lock); | ||
464 | |||
465 | if (dso->data.fd >= 0) | 452 | if (dso->data.fd >= 0) |
466 | goto out; | 453 | return; |
467 | 454 | ||
468 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { | 455 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { |
469 | dso->data.fd = open_dso(dso, machine); | 456 | dso->data.fd = open_dso(dso, machine); |
@@ -483,11 +470,38 @@ out: | |||
483 | dso->data.status = DSO_DATA_STATUS_OK; | 470 | dso->data.status = DSO_DATA_STATUS_OK; |
484 | else | 471 | else |
485 | dso->data.status = DSO_DATA_STATUS_ERROR; | 472 | dso->data.status = DSO_DATA_STATUS_ERROR; |
473 | } | ||
474 | |||
475 | /** | ||
476 | * dso__data_get_fd - Get dso's data file descriptor | ||
477 | * @dso: dso object | ||
478 | * @machine: machine object | ||
479 | * | ||
480 | * External interface to find dso's file, open it and | ||
481 | * returns file descriptor. It should be paired with | ||
482 | * dso__data_put_fd() if it returns non-negative value. | ||
483 | */ | ||
484 | int dso__data_get_fd(struct dso *dso, struct machine *machine) | ||
485 | { | ||
486 | if (dso->data.status == DSO_DATA_STATUS_ERROR) | ||
487 | return -1; | ||
488 | |||
489 | if (pthread_mutex_lock(&dso__data_open_lock) < 0) | ||
490 | return -1; | ||
491 | |||
492 | try_to_open_dso(dso, machine); | ||
493 | |||
494 | if (dso->data.fd < 0) | ||
495 | pthread_mutex_unlock(&dso__data_open_lock); | ||
486 | 496 | ||
487 | pthread_mutex_unlock(&dso__data_open_lock); | ||
488 | return dso->data.fd; | 497 | return dso->data.fd; |
489 | } | 498 | } |
490 | 499 | ||
500 | void dso__data_put_fd(struct dso *dso __maybe_unused) | ||
501 | { | ||
502 | pthread_mutex_unlock(&dso__data_open_lock); | ||
503 | } | ||
504 | |||
491 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) | 505 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) |
492 | { | 506 | { |
493 | u32 flag = 1 << by; | 507 | u32 flag = 1 << by; |
@@ -609,13 +623,12 @@ dso_cache__read(struct dso *dso, struct machine *machine, | |||
609 | * dso->data.fd might be closed if other thread opened another | 623 | * dso->data.fd might be closed if other thread opened another |
610 | * file (dso) due to open file limit (RLIMIT_NOFILE). | 624 | * file (dso) due to open file limit (RLIMIT_NOFILE). |
611 | */ | 625 | */ |
626 | try_to_open_dso(dso, machine); | ||
627 | |||
612 | if (dso->data.fd < 0) { | 628 | if (dso->data.fd < 0) { |
613 | dso->data.fd = open_dso(dso, machine); | 629 | ret = -errno; |
614 | if (dso->data.fd < 0) { | 630 | dso->data.status = DSO_DATA_STATUS_ERROR; |
615 | ret = -errno; | 631 | break; |
616 | dso->data.status = DSO_DATA_STATUS_ERROR; | ||
617 | break; | ||
618 | } | ||
619 | } | 632 | } |
620 | 633 | ||
621 | cache_offset = offset & DSO__DATA_CACHE_MASK; | 634 | cache_offset = offset & DSO__DATA_CACHE_MASK; |
@@ -702,19 +715,21 @@ static int data_file_size(struct dso *dso, struct machine *machine) | |||
702 | if (dso->data.file_size) | 715 | if (dso->data.file_size) |
703 | return 0; | 716 | return 0; |
704 | 717 | ||
718 | if (dso->data.status == DSO_DATA_STATUS_ERROR) | ||
719 | return -1; | ||
720 | |||
705 | pthread_mutex_lock(&dso__data_open_lock); | 721 | pthread_mutex_lock(&dso__data_open_lock); |
706 | 722 | ||
707 | /* | 723 | /* |
708 | * dso->data.fd might be closed if other thread opened another | 724 | * dso->data.fd might be closed if other thread opened another |
709 | * file (dso) due to open file limit (RLIMIT_NOFILE). | 725 | * file (dso) due to open file limit (RLIMIT_NOFILE). |
710 | */ | 726 | */ |
727 | try_to_open_dso(dso, machine); | ||
728 | |||
711 | if (dso->data.fd < 0) { | 729 | if (dso->data.fd < 0) { |
712 | dso->data.fd = open_dso(dso, machine); | 730 | ret = -errno; |
713 | if (dso->data.fd < 0) { | 731 | dso->data.status = DSO_DATA_STATUS_ERROR; |
714 | ret = -errno; | 732 | goto out; |
715 | dso->data.status = DSO_DATA_STATUS_ERROR; | ||
716 | goto out; | ||
717 | } | ||
718 | } | 733 | } |
719 | 734 | ||
720 | if (fstat(dso->data.fd, &st) < 0) { | 735 | if (fstat(dso->data.fd, &st) < 0) { |
@@ -740,12 +755,6 @@ out: | |||
740 | */ | 755 | */ |
741 | off_t dso__data_size(struct dso *dso, struct machine *machine) | 756 | off_t dso__data_size(struct dso *dso, struct machine *machine) |
742 | { | 757 | { |
743 | int fd; | ||
744 | |||
745 | fd = dso__data_fd(dso, machine); | ||
746 | if (fd < 0) | ||
747 | return fd; | ||
748 | |||
749 | if (data_file_size(dso, machine)) | 758 | if (data_file_size(dso, machine)) |
750 | return -1; | 759 | return -1; |
751 | 760 | ||
@@ -1200,12 +1209,15 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
1200 | enum dso_type dso__type(struct dso *dso, struct machine *machine) | 1209 | enum dso_type dso__type(struct dso *dso, struct machine *machine) |
1201 | { | 1210 | { |
1202 | int fd; | 1211 | int fd; |
1212 | enum dso_type type = DSO__TYPE_UNKNOWN; | ||
1203 | 1213 | ||
1204 | fd = dso__data_fd(dso, machine); | 1214 | fd = dso__data_get_fd(dso, machine); |
1205 | if (fd < 0) | 1215 | if (fd >= 0) { |
1206 | return DSO__TYPE_UNKNOWN; | 1216 | type = dso__type_fd(fd); |
1217 | dso__data_put_fd(dso); | ||
1218 | } | ||
1207 | 1219 | ||
1208 | return dso__type_fd(fd); | 1220 | return type; |
1209 | } | 1221 | } |
1210 | 1222 | ||
1211 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) | 1223 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index b26ec3ab1336..bcec06ad73a2 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -240,7 +240,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
240 | 240 | ||
241 | /* | 241 | /* |
242 | * The dso__data_* external interface provides following functions: | 242 | * The dso__data_* external interface provides following functions: |
243 | * dso__data_fd | 243 | * dso__data_get_fd |
244 | * dso__data_put_fd | ||
244 | * dso__data_close | 245 | * dso__data_close |
245 | * dso__data_size | 246 | * dso__data_size |
246 | * dso__data_read_offset | 247 | * dso__data_read_offset |
@@ -257,8 +258,11 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
257 | * The current usage of the dso__data_* interface is as follows: | 258 | * The current usage of the dso__data_* interface is as follows: |
258 | * | 259 | * |
259 | * Get DSO's fd: | 260 | * Get DSO's fd: |
260 | * int fd = dso__data_fd(dso, machine); | 261 | * int fd = dso__data_get_fd(dso, machine); |
261 | * USE 'fd' SOMEHOW | 262 | * if (fd >= 0) { |
263 | * USE 'fd' SOMEHOW | ||
264 | * dso__data_put_fd(dso); | ||
265 | * } | ||
262 | * | 266 | * |
263 | * Read DSO's data: | 267 | * Read DSO's data: |
264 | * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); | 268 | * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); |
@@ -277,7 +281,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
277 | * | 281 | * |
278 | * TODO | 282 | * TODO |
279 | */ | 283 | */ |
280 | int dso__data_fd(struct dso *dso, struct machine *machine); | 284 | int dso__data_get_fd(struct dso *dso, struct machine *machine); |
285 | void dso__data_put_fd(struct dso *dso __maybe_unused); | ||
281 | void dso__data_close(struct dso *dso); | 286 | void dso__data_close(struct dso *dso); |
282 | 287 | ||
283 | off_t dso__data_size(struct dso *dso, struct machine *machine); | 288 | off_t dso__data_size(struct dso *dso, struct machine *machine); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index a513a51f7330..9d3bba175423 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -329,8 +329,9 @@ int perf_event__synthesize_modules(struct perf_tool *tool, | |||
329 | struct machine *machine) | 329 | struct machine *machine) |
330 | { | 330 | { |
331 | int rc = 0; | 331 | int rc = 0; |
332 | struct rb_node *nd; | 332 | struct map *pos; |
333 | struct map_groups *kmaps = &machine->kmaps; | 333 | struct map_groups *kmaps = &machine->kmaps; |
334 | struct rb_root *maps = &kmaps->maps[MAP__FUNCTION]; | ||
334 | union perf_event *event = zalloc((sizeof(event->mmap) + | 335 | union perf_event *event = zalloc((sizeof(event->mmap) + |
335 | machine->id_hdr_size)); | 336 | machine->id_hdr_size)); |
336 | if (event == NULL) { | 337 | if (event == NULL) { |
@@ -350,10 +351,8 @@ int perf_event__synthesize_modules(struct perf_tool *tool, | |||
350 | else | 351 | else |
351 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 352 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
352 | 353 | ||
353 | for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); | 354 | for (pos = maps__first(maps); pos; pos = map__next(pos)) { |
354 | nd; nd = rb_next(nd)) { | ||
355 | size_t size; | 355 | size_t size; |
356 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
357 | 356 | ||
358 | if (pos->dso->kernel) | 357 | if (pos->dso->kernel) |
359 | continue; | 358 | continue; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 338770679863..f53d017c7c22 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -362,10 +362,10 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
362 | return 0; | 362 | return 0; |
363 | } | 363 | } |
364 | 364 | ||
365 | static struct hist_entry *add_hist_entry(struct hists *hists, | 365 | static struct hist_entry *hists__findnew_entry(struct hists *hists, |
366 | struct hist_entry *entry, | 366 | struct hist_entry *entry, |
367 | struct addr_location *al, | 367 | struct addr_location *al, |
368 | bool sample_self) | 368 | bool sample_self) |
369 | { | 369 | { |
370 | struct rb_node **p; | 370 | struct rb_node **p; |
371 | struct rb_node *parent = NULL; | 371 | struct rb_node *parent = NULL; |
@@ -468,7 +468,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
468 | .transaction = transaction, | 468 | .transaction = transaction, |
469 | }; | 469 | }; |
470 | 470 | ||
471 | return add_hist_entry(hists, &entry, al, sample_self); | 471 | return hists__findnew_entry(hists, &entry, al, sample_self); |
472 | } | 472 | } |
473 | 473 | ||
474 | static int | 474 | static int |
@@ -548,9 +548,9 @@ iter_finish_mem_entry(struct hist_entry_iter *iter, | |||
548 | 548 | ||
549 | out: | 549 | out: |
550 | /* | 550 | /* |
551 | * We don't need to free iter->priv (mem_info) here since | 551 | * We don't need to free iter->priv (mem_info) here since the mem info |
552 | * the mem info was either already freed in add_hist_entry() or | 552 | * was either already freed in hists__findnew_entry() or passed to a |
553 | * passed to a new hist entry by hist_entry__new(). | 553 | * new hist entry by hist_entry__new(). |
554 | */ | 554 | */ |
555 | iter->priv = NULL; | 555 | iter->priv = NULL; |
556 | 556 | ||
@@ -851,19 +851,15 @@ const struct hist_iter_ops hist_iter_cumulative = { | |||
851 | }; | 851 | }; |
852 | 852 | ||
853 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 853 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
854 | struct perf_evsel *evsel, struct perf_sample *sample, | ||
855 | int max_stack_depth, void *arg) | 854 | int max_stack_depth, void *arg) |
856 | { | 855 | { |
857 | int err, err2; | 856 | int err, err2; |
858 | 857 | ||
859 | err = sample__resolve_callchain(sample, &iter->parent, evsel, al, | 858 | err = sample__resolve_callchain(iter->sample, &iter->parent, |
860 | max_stack_depth); | 859 | iter->evsel, al, max_stack_depth); |
861 | if (err) | 860 | if (err) |
862 | return err; | 861 | return err; |
863 | 862 | ||
864 | iter->evsel = evsel; | ||
865 | iter->sample = sample; | ||
866 | |||
867 | err = iter->ops->prepare_entry(iter, al); | 863 | err = iter->ops->prepare_entry(iter, al); |
868 | if (err) | 864 | if (err) |
869 | goto out; | 865 | goto out; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 9f31b89a527a..5ed8d9c22981 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -111,7 +111,6 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
111 | u64 weight, u64 transaction, | 111 | u64 weight, u64 transaction, |
112 | bool sample_self); | 112 | bool sample_self); |
113 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | 113 | int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, |
114 | struct perf_evsel *evsel, struct perf_sample *sample, | ||
115 | int max_stack_depth, void *arg); | 114 | int max_stack_depth, void *arg); |
116 | 115 | ||
117 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); | 116 | int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); |
diff --git a/tools/perf/util/include/linux/rbtree.h b/tools/perf/util/include/linux/rbtree.h index 2a030c5af3aa..f06d89f0b867 100644 --- a/tools/perf/util/include/linux/rbtree.h +++ b/tools/perf/util/include/linux/rbtree.h | |||
@@ -1,2 +1,16 @@ | |||
1 | #ifndef __TOOLS_LINUX_PERF_RBTREE_H | ||
2 | #define __TOOLS_LINUX_PERF_RBTREE_H | ||
1 | #include <stdbool.h> | 3 | #include <stdbool.h> |
2 | #include "../../../../include/linux/rbtree.h" | 4 | #include "../../../../include/linux/rbtree.h" |
5 | |||
6 | /* | ||
7 | * Handy for checking that we are not deleting an entry that is | ||
8 | * already in a list, found in block/{blk-throttle,cfq-iosched}.c, | ||
9 | * probably should be moved to lib/rbtree.c... | ||
10 | */ | ||
11 | static inline void rb_erase_init(struct rb_node *n, struct rb_root *root) | ||
12 | { | ||
13 | rb_erase(n, root); | ||
14 | RB_CLEAR_NODE(n); | ||
15 | } | ||
16 | #endif /* __TOOLS_LINUX_PERF_RBTREE_H */ | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index daa55910ff28..6bf845758ae3 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -333,7 +333,7 @@ static void machine__update_thread_pid(struct machine *machine, | |||
333 | if (!map_groups__empty(th->mg)) | 333 | if (!map_groups__empty(th->mg)) |
334 | pr_err("Discarding thread maps for %d:%d\n", | 334 | pr_err("Discarding thread maps for %d:%d\n", |
335 | th->pid_, th->tid); | 335 | th->pid_, th->tid); |
336 | map_groups__delete(th->mg); | 336 | map_groups__put(th->mg); |
337 | } | 337 | } |
338 | 338 | ||
339 | th->mg = map_groups__get(leader->mg); | 339 | th->mg = map_groups__get(leader->mg); |
@@ -400,7 +400,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine, | |||
400 | * leader and that would screwed the rb tree. | 400 | * leader and that would screwed the rb tree. |
401 | */ | 401 | */ |
402 | if (thread__init_map_groups(th, machine)) { | 402 | if (thread__init_map_groups(th, machine)) { |
403 | rb_erase(&th->rb_node, &machine->threads); | 403 | rb_erase_init(&th->rb_node, &machine->threads); |
404 | RB_CLEAR_NODE(&th->rb_node); | 404 | RB_CLEAR_NODE(&th->rb_node); |
405 | thread__delete(th); | 405 | thread__delete(th); |
406 | return NULL; | 406 | return NULL; |
@@ -1314,7 +1314,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th, | |||
1314 | BUG_ON(atomic_read(&th->refcnt) == 0); | 1314 | BUG_ON(atomic_read(&th->refcnt) == 0); |
1315 | if (lock) | 1315 | if (lock) |
1316 | pthread_rwlock_wrlock(&machine->threads_lock); | 1316 | pthread_rwlock_wrlock(&machine->threads_lock); |
1317 | rb_erase(&th->rb_node, &machine->threads); | 1317 | rb_erase_init(&th->rb_node, &machine->threads); |
1318 | RB_CLEAR_NODE(&th->rb_node); | 1318 | RB_CLEAR_NODE(&th->rb_node); |
1319 | /* | 1319 | /* |
1320 | * Move it first to the dead_threads list, then drop the reference, | 1320 | * Move it first to the dead_threads list, then drop the reference, |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 2d20c5ff8653..898ab92a98dd 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -498,28 +498,6 @@ void map_groups__put(struct map_groups *mg) | |||
498 | map_groups__delete(mg); | 498 | map_groups__delete(mg); |
499 | } | 499 | } |
500 | 500 | ||
501 | void map_groups__flush(struct map_groups *mg) | ||
502 | { | ||
503 | int type; | ||
504 | |||
505 | for (type = 0; type < MAP__NR_TYPES; type++) { | ||
506 | struct rb_root *root = &mg->maps[type]; | ||
507 | struct rb_node *next = rb_first(root); | ||
508 | |||
509 | while (next) { | ||
510 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
511 | next = rb_next(&pos->rb_node); | ||
512 | rb_erase(&pos->rb_node, root); | ||
513 | /* | ||
514 | * We may have references to this map, for | ||
515 | * instance in some hist_entry instances, so | ||
516 | * just move them to a separate list. | ||
517 | */ | ||
518 | list_add_tail(&pos->node, &mg->removed_maps[pos->type]); | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | struct symbol *map_groups__find_symbol(struct map_groups *mg, | 501 | struct symbol *map_groups__find_symbol(struct map_groups *mg, |
524 | enum map_type type, u64 addr, | 502 | enum map_type type, u64 addr, |
525 | struct map **mapp, | 503 | struct map **mapp, |
@@ -710,9 +688,10 @@ move_map: | |||
710 | int map_groups__clone(struct map_groups *mg, | 688 | int map_groups__clone(struct map_groups *mg, |
711 | struct map_groups *parent, enum map_type type) | 689 | struct map_groups *parent, enum map_type type) |
712 | { | 690 | { |
713 | struct rb_node *nd; | 691 | struct map *map; |
714 | for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { | 692 | struct rb_root *maps = &parent->maps[type]; |
715 | struct map *map = rb_entry(nd, struct map, rb_node); | 693 | |
694 | for (map = maps__first(maps); map; map = map__next(map)) { | ||
716 | struct map *new = map__clone(map); | 695 | struct map *new = map__clone(map); |
717 | if (new == NULL) | 696 | if (new == NULL) |
718 | return -ENOMEM; | 697 | return -ENOMEM; |
@@ -775,7 +754,7 @@ struct map *maps__first(struct rb_root *maps) | |||
775 | return NULL; | 754 | return NULL; |
776 | } | 755 | } |
777 | 756 | ||
778 | struct map *maps__next(struct map *map) | 757 | struct map *map__next(struct map *map) |
779 | { | 758 | { |
780 | struct rb_node *next = rb_next(&map->rb_node); | 759 | struct rb_node *next = rb_next(&map->rb_node); |
781 | 760 | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 7f39217d29bf..f2b27566d986 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -166,7 +166,7 @@ void maps__insert(struct rb_root *maps, struct map *map); | |||
166 | void maps__remove(struct rb_root *maps, struct map *map); | 166 | void maps__remove(struct rb_root *maps, struct map *map); |
167 | struct map *maps__find(struct rb_root *maps, u64 addr); | 167 | struct map *maps__find(struct rb_root *maps, u64 addr); |
168 | struct map *maps__first(struct rb_root *maps); | 168 | struct map *maps__first(struct rb_root *maps); |
169 | struct map *maps__next(struct map *map); | 169 | struct map *map__next(struct map *map); |
170 | void map_groups__init(struct map_groups *mg, struct machine *machine); | 170 | void map_groups__init(struct map_groups *mg, struct machine *machine); |
171 | void map_groups__exit(struct map_groups *mg); | 171 | void map_groups__exit(struct map_groups *mg); |
172 | int map_groups__clone(struct map_groups *mg, | 172 | int map_groups__clone(struct map_groups *mg, |
@@ -201,7 +201,7 @@ static inline struct map *map_groups__first(struct map_groups *mg, | |||
201 | 201 | ||
202 | static inline struct map *map_groups__next(struct map *map) | 202 | static inline struct map *map_groups__next(struct map *map) |
203 | { | 203 | { |
204 | return maps__next(map); | 204 | return map__next(map); |
205 | } | 205 | } |
206 | 206 | ||
207 | struct symbol *map_groups__find_symbol(struct map_groups *mg, | 207 | struct symbol *map_groups__find_symbol(struct map_groups *mg, |
@@ -233,6 +233,4 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, | |||
233 | struct map *map_groups__find_by_name(struct map_groups *mg, | 233 | struct map *map_groups__find_by_name(struct map_groups *mg, |
234 | enum map_type type, const char *name); | 234 | enum map_type type, const char *name); |
235 | 235 | ||
236 | void map_groups__flush(struct map_groups *mg); | ||
237 | |||
238 | #endif /* __PERF_MAP_H */ | 236 | #endif /* __PERF_MAP_H */ |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 80a50fdb6d8a..2a4d1ec02846 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -25,12 +25,6 @@ | |||
25 | extern int parse_events_debug; | 25 | extern int parse_events_debug; |
26 | #endif | 26 | #endif |
27 | int parse_events_parse(void *data, void *scanner); | 27 | int parse_events_parse(void *data, void *scanner); |
28 | int parse_events_term__num(struct parse_events_term **term, | ||
29 | int type_term, char *config, u64 num, | ||
30 | YYLTYPE *loc_term, YYLTYPE *loc_val); | ||
31 | int parse_events_term__str(struct parse_events_term **term, | ||
32 | int type_term, char *config, char *str, | ||
33 | YYLTYPE *loc_term, YYLTYPE *loc_val); | ||
34 | 28 | ||
35 | static struct perf_pmu_event_symbol *perf_pmu_events_list; | 29 | static struct perf_pmu_event_symbol *perf_pmu_events_list; |
36 | /* | 30 | /* |
@@ -1601,8 +1595,11 @@ static int new_term(struct parse_events_term **_term, int type_val, | |||
1601 | 1595 | ||
1602 | int parse_events_term__num(struct parse_events_term **term, | 1596 | int parse_events_term__num(struct parse_events_term **term, |
1603 | int type_term, char *config, u64 num, | 1597 | int type_term, char *config, u64 num, |
1604 | YYLTYPE *loc_term, YYLTYPE *loc_val) | 1598 | void *loc_term_, void *loc_val_) |
1605 | { | 1599 | { |
1600 | YYLTYPE *loc_term = loc_term_; | ||
1601 | YYLTYPE *loc_val = loc_val_; | ||
1602 | |||
1606 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, | 1603 | return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, |
1607 | config, NULL, num, | 1604 | config, NULL, num, |
1608 | loc_term ? loc_term->first_column : 0, | 1605 | loc_term ? loc_term->first_column : 0, |
@@ -1611,8 +1608,11 @@ int parse_events_term__num(struct parse_events_term **term, | |||
1611 | 1608 | ||
1612 | int parse_events_term__str(struct parse_events_term **term, | 1609 | int parse_events_term__str(struct parse_events_term **term, |
1613 | int type_term, char *config, char *str, | 1610 | int type_term, char *config, char *str, |
1614 | YYLTYPE *loc_term, YYLTYPE *loc_val) | 1611 | void *loc_term_, void *loc_val_) |
1615 | { | 1612 | { |
1613 | YYLTYPE *loc_term = loc_term_; | ||
1614 | YYLTYPE *loc_val = loc_val_; | ||
1615 | |||
1616 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, | 1616 | return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, |
1617 | config, str, 0, | 1617 | config, str, 0, |
1618 | loc_term ? loc_term->first_column : 0, | 1618 | loc_term ? loc_term->first_column : 0, |
@@ -1659,6 +1659,8 @@ void parse_events_evlist_error(struct parse_events_evlist *data, | |||
1659 | { | 1659 | { |
1660 | struct parse_events_error *err = data->error; | 1660 | struct parse_events_error *err = data->error; |
1661 | 1661 | ||
1662 | if (!err) | ||
1663 | return; | ||
1662 | err->idx = idx; | 1664 | err->idx = idx; |
1663 | err->str = strdup(str); | 1665 | err->str = strdup(str); |
1664 | WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); | 1666 | WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index e236f1b6ac6f..131f29b2f132 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -98,6 +98,12 @@ struct parse_events_terms { | |||
98 | }; | 98 | }; |
99 | 99 | ||
100 | int parse_events__is_hardcoded_term(struct parse_events_term *term); | 100 | int parse_events__is_hardcoded_term(struct parse_events_term *term); |
101 | int parse_events_term__num(struct parse_events_term **term, | ||
102 | int type_term, char *config, u64 num, | ||
103 | void *loc_term, void *loc_val); | ||
104 | int parse_events_term__str(struct parse_events_term **term, | ||
105 | int type_term, char *config, char *str, | ||
106 | void *loc_term, void *loc_val); | ||
101 | int parse_events_term__sym_hw(struct parse_events_term **term, | 107 | int parse_events_term__sym_hw(struct parse_events_term **term, |
102 | char *config, unsigned idx); | 108 | char *config, unsigned idx); |
103 | int parse_events_term__clone(struct parse_events_term **new, | 109 | int parse_events_term__clone(struct parse_events_term **new, |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 3d11e00243e3..591905a02b92 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -389,8 +389,10 @@ PE_NAME ':' PE_NAME | |||
389 | if (parse_events_add_tracepoint(list, &data->idx, $1, $3)) { | 389 | if (parse_events_add_tracepoint(list, &data->idx, $1, $3)) { |
390 | struct parse_events_error *error = data->error; | 390 | struct parse_events_error *error = data->error; |
391 | 391 | ||
392 | error->idx = @1.first_column; | 392 | if (error) { |
393 | error->str = strdup("unknown tracepoint"); | 393 | error->idx = @1.first_column; |
394 | error->str = strdup("unknown tracepoint"); | ||
395 | } | ||
394 | return -1; | 396 | return -1; |
395 | } | 397 | } |
396 | $$ = list; | 398 | $$ = list; |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 244c66f89891..5d3ab7c8ceaf 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -442,6 +442,10 @@ static struct perf_pmu *pmu_lookup(const char *name) | |||
442 | LIST_HEAD(aliases); | 442 | LIST_HEAD(aliases); |
443 | __u32 type; | 443 | __u32 type; |
444 | 444 | ||
445 | /* No support for intel_bts or intel_pt so disallow them */ | ||
446 | if (!strcmp(name, "intel_bts") || !strcmp(name, "intel_pt")) | ||
447 | return NULL; | ||
448 | |||
445 | /* | 449 | /* |
446 | * The pmu data we store & need consists of the pmu | 450 | * The pmu data we store & need consists of the pmu |
447 | * type value and format definitions. Load both right | 451 | * type value and format definitions. Load both right |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 1faa1e67398b..97da98481d89 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -162,8 +162,9 @@ static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) | |||
162 | 162 | ||
163 | static struct map *kernel_get_module_map(const char *module) | 163 | static struct map *kernel_get_module_map(const char *module) |
164 | { | 164 | { |
165 | struct rb_node *nd; | ||
166 | struct map_groups *grp = &host_machine->kmaps; | 165 | struct map_groups *grp = &host_machine->kmaps; |
166 | struct rb_root *maps = &grp->maps[MAP__FUNCTION]; | ||
167 | struct map *pos; | ||
167 | 168 | ||
168 | /* A file path -- this is an offline module */ | 169 | /* A file path -- this is an offline module */ |
169 | if (module && strchr(module, '/')) | 170 | if (module && strchr(module, '/')) |
@@ -172,8 +173,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
172 | if (!module) | 173 | if (!module) |
173 | module = "kernel"; | 174 | module = "kernel"; |
174 | 175 | ||
175 | for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { | 176 | for (pos = maps__first(maps); pos; pos = map__next(pos)) { |
176 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
177 | if (strncmp(pos->dso->short_name + 1, module, | 177 | if (strncmp(pos->dso->short_name + 1, module, |
178 | pos->dso->short_name_len - 2) == 0) { | 178 | pos->dso->short_name_len - 2) == 0) { |
179 | return pos; | 179 | return pos; |
@@ -195,17 +195,17 @@ static void put_target_map(struct map *map, bool user) | |||
195 | { | 195 | { |
196 | if (map && user) { | 196 | if (map && user) { |
197 | /* Only the user map needs to be released */ | 197 | /* Only the user map needs to be released */ |
198 | dso__delete(map->dso); | ||
199 | map__delete(map); | 198 | map__delete(map); |
200 | } | 199 | } |
201 | } | 200 | } |
202 | 201 | ||
203 | 202 | ||
204 | static struct dso *kernel_get_module_dso(const char *module) | 203 | static int kernel_get_module_dso(const char *module, struct dso **pdso) |
205 | { | 204 | { |
206 | struct dso *dso; | 205 | struct dso *dso; |
207 | struct map *map; | 206 | struct map *map; |
208 | const char *vmlinux_name; | 207 | const char *vmlinux_name; |
208 | int ret = 0; | ||
209 | 209 | ||
210 | if (module) { | 210 | if (module) { |
211 | list_for_each_entry(dso, &host_machine->kernel_dsos.head, | 211 | list_for_each_entry(dso, &host_machine->kernel_dsos.head, |
@@ -215,30 +215,21 @@ static struct dso *kernel_get_module_dso(const char *module) | |||
215 | goto found; | 215 | goto found; |
216 | } | 216 | } |
217 | pr_debug("Failed to find module %s.\n", module); | 217 | pr_debug("Failed to find module %s.\n", module); |
218 | return NULL; | 218 | return -ENOENT; |
219 | } | 219 | } |
220 | 220 | ||
221 | map = host_machine->vmlinux_maps[MAP__FUNCTION]; | 221 | map = host_machine->vmlinux_maps[MAP__FUNCTION]; |
222 | dso = map->dso; | 222 | dso = map->dso; |
223 | 223 | ||
224 | vmlinux_name = symbol_conf.vmlinux_name; | 224 | vmlinux_name = symbol_conf.vmlinux_name; |
225 | if (vmlinux_name) { | 225 | dso->load_errno = 0; |
226 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) | 226 | if (vmlinux_name) |
227 | return NULL; | 227 | ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL); |
228 | } else { | 228 | else |
229 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { | 229 | ret = dso__load_vmlinux_path(dso, map, NULL); |
230 | pr_debug("Failed to load kernel map.\n"); | ||
231 | return NULL; | ||
232 | } | ||
233 | } | ||
234 | found: | 230 | found: |
235 | return dso; | 231 | *pdso = dso; |
236 | } | 232 | return ret; |
237 | |||
238 | const char *kernel_get_module_path(const char *module) | ||
239 | { | ||
240 | struct dso *dso = kernel_get_module_dso(module); | ||
241 | return (dso) ? dso->long_name : NULL; | ||
242 | } | 233 | } |
243 | 234 | ||
244 | static int convert_exec_to_group(const char *exec, char **result) | 235 | static int convert_exec_to_group(const char *exec, char **result) |
@@ -390,16 +381,25 @@ static int get_alternative_line_range(struct debuginfo *dinfo, | |||
390 | static struct debuginfo *open_debuginfo(const char *module, bool silent) | 381 | static struct debuginfo *open_debuginfo(const char *module, bool silent) |
391 | { | 382 | { |
392 | const char *path = module; | 383 | const char *path = module; |
393 | struct debuginfo *ret; | 384 | char reason[STRERR_BUFSIZE]; |
385 | struct debuginfo *ret = NULL; | ||
386 | struct dso *dso = NULL; | ||
387 | int err; | ||
394 | 388 | ||
395 | if (!module || !strchr(module, '/')) { | 389 | if (!module || !strchr(module, '/')) { |
396 | path = kernel_get_module_path(module); | 390 | err = kernel_get_module_dso(module, &dso); |
397 | if (!path) { | 391 | if (err < 0) { |
392 | if (!dso || dso->load_errno == 0) { | ||
393 | if (!strerror_r(-err, reason, STRERR_BUFSIZE)) | ||
394 | strcpy(reason, "(unknown)"); | ||
395 | } else | ||
396 | dso__strerror_load(dso, reason, STRERR_BUFSIZE); | ||
398 | if (!silent) | 397 | if (!silent) |
399 | pr_err("Failed to find path of %s module.\n", | 398 | pr_err("Failed to find the path for %s: %s\n", |
400 | module ?: "kernel"); | 399 | module ?: "kernel", reason); |
401 | return NULL; | 400 | return NULL; |
402 | } | 401 | } |
402 | path = dso->long_name; | ||
403 | } | 403 | } |
404 | ret = debuginfo__new(path); | 404 | ret = debuginfo__new(path); |
405 | if (!ret && !silent) { | 405 | if (!ret && !silent) { |
@@ -1791,7 +1791,6 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | |||
1791 | 1791 | ||
1792 | out: | 1792 | out: |
1793 | if (map && !is_kprobe) { | 1793 | if (map && !is_kprobe) { |
1794 | dso__delete(map->dso); | ||
1795 | map__delete(map); | 1794 | map__delete(map); |
1796 | } | 1795 | } |
1797 | 1796 | ||
@@ -2812,13 +2811,14 @@ int del_perf_probe_events(struct strfilter *filter) | |||
2812 | goto error; | 2811 | goto error; |
2813 | 2812 | ||
2814 | ret2 = del_trace_probe_events(ufd, filter, unamelist); | 2813 | ret2 = del_trace_probe_events(ufd, filter, unamelist); |
2815 | if (ret2 < 0 && ret2 != -ENOENT) | 2814 | if (ret2 < 0 && ret2 != -ENOENT) { |
2816 | ret = ret2; | 2815 | ret = ret2; |
2817 | else if (ret == -ENOENT && ret2 == -ENOENT) { | 2816 | goto error; |
2817 | } | ||
2818 | if (ret == -ENOENT && ret2 == -ENOENT) | ||
2818 | pr_debug("\"%s\" does not hit any event.\n", str); | 2819 | pr_debug("\"%s\" does not hit any event.\n", str); |
2819 | /* Note that this is silently ignored */ | 2820 | /* Note that this is silently ignored */ |
2820 | ret = 0; | 2821 | ret = 0; |
2821 | } | ||
2822 | 2822 | ||
2823 | error: | 2823 | error: |
2824 | if (kfd >= 0) { | 2824 | if (kfd >= 0) { |
@@ -2884,7 +2884,6 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
2884 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | 2884 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); |
2885 | end: | 2885 | end: |
2886 | if (user) { | 2886 | if (user) { |
2887 | dso__delete(map->dso); | ||
2888 | map__delete(map); | 2887 | map__delete(map); |
2889 | } | 2888 | } |
2890 | exit_symbol_maps(); | 2889 | exit_symbol_maps(); |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 537eb329c2cf..31db6ee7db54 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -131,9 +131,6 @@ extern void line_range__clear(struct line_range *lr); | |||
131 | /* Initialize line range */ | 131 | /* Initialize line range */ |
132 | extern int line_range__init(struct line_range *lr); | 132 | extern int line_range__init(struct line_range *lr); |
133 | 133 | ||
134 | /* Internal use: Return kernel/module path */ | ||
135 | extern const char *kernel_get_module_path(const char *module); | ||
136 | |||
137 | extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); | 134 | extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); |
138 | extern int del_perf_probe_events(struct strfilter *filter); | 135 | extern int del_perf_probe_events(struct strfilter *filter); |
139 | extern int show_perf_probe_events(struct strfilter *filter); | 136 | extern int show_perf_probe_events(struct strfilter *filter); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index e722107f932a..39fe09d5a87e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1182,7 +1182,7 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset, | |||
1182 | return -1; | 1182 | return -1; |
1183 | 1183 | ||
1184 | if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 || | 1184 | if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 || |
1185 | readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz) | 1185 | readn(fd, buf, hdr_sz) != (ssize_t)hdr_sz) |
1186 | return -1; | 1186 | return -1; |
1187 | 1187 | ||
1188 | event = (union perf_event *)buf; | 1188 | event = (union perf_event *)buf; |
@@ -1190,12 +1190,12 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset, | |||
1190 | if (session->header.needs_swap) | 1190 | if (session->header.needs_swap) |
1191 | perf_event_header__bswap(&event->header); | 1191 | perf_event_header__bswap(&event->header); |
1192 | 1192 | ||
1193 | if (event->header.size < hdr_sz) | 1193 | if (event->header.size < hdr_sz || event->header.size > buf_sz) |
1194 | return -1; | 1194 | return -1; |
1195 | 1195 | ||
1196 | rest = event->header.size - hdr_sz; | 1196 | rest = event->header.size - hdr_sz; |
1197 | 1197 | ||
1198 | if (readn(fd, &buf, rest) != (ssize_t)rest) | 1198 | if (readn(fd, buf, rest) != (ssize_t)rest) |
1199 | return -1; | 1199 | return -1; |
1200 | 1200 | ||
1201 | if (session->header.needs_swap) | 1201 | if (session->header.needs_swap) |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 82a31fd0fcf5..b9e3eb581884 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -202,18 +202,16 @@ void symbols__fixup_end(struct rb_root *symbols) | |||
202 | 202 | ||
203 | void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) | 203 | void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) |
204 | { | 204 | { |
205 | struct map *prev, *curr; | 205 | struct rb_root *maps = &mg->maps[type]; |
206 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); | 206 | struct map *next, *curr; |
207 | 207 | ||
208 | if (prevnd == NULL) | 208 | curr = maps__first(maps); |
209 | if (curr == NULL) | ||
209 | return; | 210 | return; |
210 | 211 | ||
211 | curr = rb_entry(prevnd, struct map, rb_node); | 212 | for (next = map__next(curr); next; next = map__next(curr)) { |
212 | 213 | curr->end = next->start; | |
213 | for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { | 214 | curr = next; |
214 | prev = curr; | ||
215 | curr = rb_entry(nd, struct map, rb_node); | ||
216 | prev->end = curr->start; | ||
217 | } | 215 | } |
218 | 216 | ||
219 | /* | 217 | /* |
@@ -400,7 +398,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
400 | const char *name) | 398 | const char *name) |
401 | { | 399 | { |
402 | struct rb_node *n; | 400 | struct rb_node *n; |
403 | struct symbol_name_rb_node *s; | 401 | struct symbol_name_rb_node *s = NULL; |
404 | 402 | ||
405 | if (symbols == NULL) | 403 | if (symbols == NULL) |
406 | return NULL; | 404 | return NULL; |
@@ -1522,11 +1520,10 @@ out: | |||
1522 | struct map *map_groups__find_by_name(struct map_groups *mg, | 1520 | struct map *map_groups__find_by_name(struct map_groups *mg, |
1523 | enum map_type type, const char *name) | 1521 | enum map_type type, const char *name) |
1524 | { | 1522 | { |
1525 | struct rb_node *nd; | 1523 | struct rb_root *maps = &mg->maps[type]; |
1526 | 1524 | struct map *map; | |
1527 | for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { | ||
1528 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
1529 | 1525 | ||
1526 | for (map = maps__first(maps); map; map = map__next(map)) { | ||
1530 | if (map->dso && strcmp(map->dso->short_name, name) == 0) | 1527 | if (map->dso && strcmp(map->dso->short_name, name) == 0) |
1531 | return map; | 1528 | return map; |
1532 | } | 1529 | } |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 16c28a37a9e4..28c4b746baa1 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -54,7 +54,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) | |||
54 | 54 | ||
55 | list_add(&comm->list, &thread->comm_list); | 55 | list_add(&comm->list, &thread->comm_list); |
56 | atomic_set(&thread->refcnt, 0); | 56 | atomic_set(&thread->refcnt, 0); |
57 | INIT_LIST_HEAD(&thread->node); | ||
58 | RB_CLEAR_NODE(&thread->rb_node); | 57 | RB_CLEAR_NODE(&thread->rb_node); |
59 | } | 58 | } |
60 | 59 | ||
@@ -70,7 +69,6 @@ void thread__delete(struct thread *thread) | |||
70 | struct comm *comm, *tmp; | 69 | struct comm *comm, *tmp; |
71 | 70 | ||
72 | BUG_ON(!RB_EMPTY_NODE(&thread->rb_node)); | 71 | BUG_ON(!RB_EMPTY_NODE(&thread->rb_node)); |
73 | BUG_ON(!list_empty(&thread->node)); | ||
74 | 72 | ||
75 | thread_stack__free(thread); | 73 | thread_stack__free(thread); |
76 | 74 | ||
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 25d6c737be3e..d4957418657e 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -173,7 +173,7 @@ void parse_ftrace_printk(struct pevent *pevent, | |||
173 | char *line; | 173 | char *line; |
174 | char *next = NULL; | 174 | char *next = NULL; |
175 | char *addr_str; | 175 | char *addr_str; |
176 | char *fmt; | 176 | char *fmt = NULL; |
177 | 177 | ||
178 | line = strtok_r(file, "\n", &next); | 178 | line = strtok_r(file, "\n", &next); |
179 | while (line) { | 179 | while (line) { |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 7b09a443a280..f079b63f0b7f 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -269,13 +269,14 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | |||
269 | u64 offset = dso->data.eh_frame_hdr_offset; | 269 | u64 offset = dso->data.eh_frame_hdr_offset; |
270 | 270 | ||
271 | if (offset == 0) { | 271 | if (offset == 0) { |
272 | fd = dso__data_fd(dso, machine); | 272 | fd = dso__data_get_fd(dso, machine); |
273 | if (fd < 0) | 273 | if (fd < 0) |
274 | return -EINVAL; | 274 | return -EINVAL; |
275 | 275 | ||
276 | /* Check the .eh_frame section for unwinding info */ | 276 | /* Check the .eh_frame section for unwinding info */ |
277 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 277 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
278 | dso->data.eh_frame_hdr_offset = offset; | 278 | dso->data.eh_frame_hdr_offset = offset; |
279 | dso__data_put_fd(dso); | ||
279 | } | 280 | } |
280 | 281 | ||
281 | if (offset) | 282 | if (offset) |
@@ -294,13 +295,14 @@ static int read_unwind_spec_debug_frame(struct dso *dso, | |||
294 | u64 ofs = dso->data.debug_frame_offset; | 295 | u64 ofs = dso->data.debug_frame_offset; |
295 | 296 | ||
296 | if (ofs == 0) { | 297 | if (ofs == 0) { |
297 | fd = dso__data_fd(dso, machine); | 298 | fd = dso__data_get_fd(dso, machine); |
298 | if (fd < 0) | 299 | if (fd < 0) |
299 | return -EINVAL; | 300 | return -EINVAL; |
300 | 301 | ||
301 | /* Check the .debug_frame section for unwinding info */ | 302 | /* Check the .debug_frame section for unwinding info */ |
302 | ofs = elf_section_offset(fd, ".debug_frame"); | 303 | ofs = elf_section_offset(fd, ".debug_frame"); |
303 | dso->data.debug_frame_offset = ofs; | 304 | dso->data.debug_frame_offset = ofs; |
305 | dso__data_put_fd(dso); | ||
304 | } | 306 | } |
305 | 307 | ||
306 | *offset = ofs; | 308 | *offset = ofs; |
@@ -353,10 +355,13 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
353 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | 355 | #ifndef NO_LIBUNWIND_DEBUG_FRAME |
354 | /* Check the .debug_frame section for unwinding info */ | 356 | /* Check the .debug_frame section for unwinding info */ |
355 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 357 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
356 | int fd = dso__data_fd(map->dso, ui->machine); | 358 | int fd = dso__data_get_fd(map->dso, ui->machine); |
357 | int is_exec = elf_is_exec(fd, map->dso->name); | 359 | int is_exec = elf_is_exec(fd, map->dso->name); |
358 | unw_word_t base = is_exec ? 0 : map->start; | 360 | unw_word_t base = is_exec ? 0 : map->start; |
359 | 361 | ||
362 | if (fd >= 0) | ||
363 | dso__data_put_fd(dso); | ||
364 | |||
360 | memset(&di, 0, sizeof(di)); | 365 | memset(&di, 0, sizeof(di)); |
361 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, | 366 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, |
362 | map->start, map->end)) | 367 | map->start, map->end)) |