diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-06-18 03:36:33 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-06-18 03:40:46 -0400 |
commit | 79928928c5a27d58ae48285d2a3f7aa835db7547 (patch) | |
tree | 49989d6b2eea50b9c6610d051ed7c1df700755d3 | |
parent | 61d67d568445413137995e1bea2746783e3a81e9 (diff) | |
parent | 5d484f99aed547e235f2229653c95392a1bc3692 (diff) |
Merge tag 'perf-core-for-mingo-2' 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:
- List perf probes to stdout. (Masami Hiramatsu)
- Return error when none of the requested probes were
installed. (Masami Hiramatsu)
- Cut off the gcc optimization postfixes from
function name in 'perf probe'. (Masami Hiramatsu)
- Allow disabling/enabling events dynamicly in 'perf top':
a 'perf top' session can instantly become a 'perf report'
one, i.e. going from dynamic analysis to a static one,
returning to a dynamic one is possible, to toogle the
modes, just press CTRL+z. (Arnaldo Carvalho de Melo)
- Greatly speed up 'perf probe --list' by caching debuginfo.
(Masami Hiramatsu)
- Fix 'perf trace' race condition at the end of started
workloads. (Sukadev Bhattiprolu)
- Fix a problem when opening old perf.data with different
byte order. (Wang Nan)
Infrastructure changes:
- Replace map->referenced & maps->removed_maps with
map->refcnt. (Arnaldo Carvalho de Melo)
- Introduce the xyarray__reset() function. (Jiri Olsa)
- Add thread_map__(alloc|realloc)() helpers. (Jiri Olsa)
- Move perf_evsel__(alloc|free|reset)_counts into stat object. (Jiri Olsa)
- Introduce perf_counts__(new|delete|reset)() functions. (Jiri Olsa)
- Ignore .config-detected in .gitignore. (Wang Nan)
- Move libtraceevent dynamic list to separated LDFLAGS
variable. (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/.gitignore | 1 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 10 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 19 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 52 | ||||
-rw-r--r-- | tools/perf/tests/openat-syscall-all-cpus.c | 1 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 2 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 18 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 19 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 3 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 37 | ||||
-rw-r--r-- | tools/perf/util/map.c | 58 | ||||
-rw-r--r-- | tools/perf/util/map.h | 10 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 240 | ||||
-rw-r--r-- | tools/perf/util/python-ext-sources | 1 | ||||
-rw-r--r-- | tools/perf/util/session.c | 50 | ||||
-rw-r--r-- | tools/perf/util/stat.c | 36 | ||||
-rw-r--r-- | tools/perf/util/stat.h | 6 | ||||
-rw-r--r-- | tools/perf/util/thread_map.c | 24 | ||||
-rw-r--r-- | tools/perf/util/unwind-libunwind.c | 2 | ||||
-rw-r--r-- | tools/perf/util/xyarray.c | 8 | ||||
-rw-r--r-- | tools/perf/util/xyarray.h | 2 |
22 files changed, 378 insertions, 223 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 812f904193e8..09db62ba5786 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore | |||
@@ -28,3 +28,4 @@ config.mak.autogen | |||
28 | *-flex.* | 28 | *-flex.* |
29 | *.pyc | 29 | *.pyc |
30 | *.pyo | 30 | *.pyo |
31 | .config-detected | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index b1dfcd8e93e3..1af0cfeb7a57 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -174,7 +174,7 @@ LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | |||
174 | export LIBTRACEEVENT | 174 | export LIBTRACEEVENT |
175 | 175 | ||
176 | LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list | 176 | LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list |
177 | LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) | 177 | LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) |
178 | 178 | ||
179 | LIBAPI = $(LIB_PATH)libapi.a | 179 | LIBAPI = $(LIB_PATH)libapi.a |
180 | export LIBAPI | 180 | export LIBAPI |
@@ -190,8 +190,9 @@ python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT | |||
190 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 190 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
191 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) | 191 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) |
192 | 192 | ||
193 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 193 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) |
194 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 194 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ |
195 | $(PYTHON_WORD) util/setup.py \ | ||
195 | --quiet build_ext; \ | 196 | --quiet build_ext; \ |
196 | mkdir -p $(OUTPUT)python && \ | 197 | mkdir -p $(OUTPUT)python && \ |
197 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ | 198 | cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ |
@@ -282,7 +283,8 @@ $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE | |||
282 | $(Q)$(MAKE) $(build)=perf | 283 | $(Q)$(MAKE) $(build)=perf |
283 | 284 | ||
284 | $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) | 285 | $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) |
285 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ | 286 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ |
287 | $(PERF_IN) $(LIBS) -o $@ | ||
286 | 288 | ||
287 | $(GTK_IN): FORCE | 289 | $(GTK_IN): FORCE |
288 | $(Q)$(MAKE) $(build)=gtk | 290 | $(Q)$(MAKE) $(build)=gtk |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index b24ecee95fec..fcf99bdeb19e 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -178,24 +178,19 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | |||
178 | 178 | ||
179 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) | 179 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) |
180 | { | 180 | { |
181 | void *addr; | 181 | struct perf_counts *counts; |
182 | size_t sz; | ||
183 | 182 | ||
184 | sz = sizeof(*evsel->counts) + | 183 | counts = perf_counts__new(perf_evsel__nr_cpus(evsel)); |
185 | (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values)); | 184 | if (counts) |
185 | evsel->prev_raw_counts = counts; | ||
186 | 186 | ||
187 | addr = zalloc(sz); | 187 | return counts ? 0 : -ENOMEM; |
188 | if (!addr) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | evsel->prev_raw_counts = addr; | ||
192 | |||
193 | return 0; | ||
194 | } | 188 | } |
195 | 189 | ||
196 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) | 190 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) |
197 | { | 191 | { |
198 | zfree(&evsel->prev_raw_counts); | 192 | perf_counts__delete(evsel->prev_raw_counts); |
193 | evsel->prev_raw_counts = NULL; | ||
199 | } | 194 | } |
200 | 195 | ||
201 | static void perf_evlist__free_stats(struct perf_evlist *evlist) | 196 | static void perf_evlist__free_stats(struct perf_evlist *evlist) |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6b987424d015..72d8a7ae5986 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -235,10 +235,13 @@ static void perf_top__show_details(struct perf_top *top) | |||
235 | 235 | ||
236 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, | 236 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, |
237 | 0, top->sym_pcnt_filter, top->print_entries, 4); | 237 | 0, top->sym_pcnt_filter, top->print_entries, 4); |
238 | if (top->zero) | 238 | |
239 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); | 239 | if (top->evlist->enabled) { |
240 | else | 240 | if (top->zero) |
241 | symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); | 241 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); |
242 | else | ||
243 | symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); | ||
244 | } | ||
242 | if (more != 0) | 245 | if (more != 0) |
243 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | 246 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); |
244 | out_unlock: | 247 | out_unlock: |
@@ -276,11 +279,13 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
276 | return; | 279 | return; |
277 | } | 280 | } |
278 | 281 | ||
279 | if (top->zero) { | 282 | if (top->evlist->enabled) { |
280 | hists__delete_entries(hists); | 283 | if (top->zero) { |
281 | } else { | 284 | hists__delete_entries(hists); |
282 | hists__decay_entries(hists, top->hide_user_symbols, | 285 | } else { |
283 | top->hide_kernel_symbols); | 286 | hists__decay_entries(hists, top->hide_user_symbols, |
287 | top->hide_kernel_symbols); | ||
288 | } | ||
284 | } | 289 | } |
285 | 290 | ||
286 | hists__collapse_resort(hists, NULL); | 291 | hists__collapse_resort(hists, NULL); |
@@ -545,11 +550,13 @@ static void perf_top__sort_new_samples(void *arg) | |||
545 | 550 | ||
546 | hists = evsel__hists(t->sym_evsel); | 551 | hists = evsel__hists(t->sym_evsel); |
547 | 552 | ||
548 | if (t->zero) { | 553 | if (t->evlist->enabled) { |
549 | hists__delete_entries(hists); | 554 | if (t->zero) { |
550 | } else { | 555 | hists__delete_entries(hists); |
551 | hists__decay_entries(hists, t->hide_user_symbols, | 556 | } else { |
552 | t->hide_kernel_symbols); | 557 | hists__decay_entries(hists, t->hide_user_symbols, |
558 | t->hide_kernel_symbols); | ||
559 | } | ||
553 | } | 560 | } |
554 | 561 | ||
555 | hists__collapse_resort(hists, NULL); | 562 | hists__collapse_resort(hists, NULL); |
@@ -579,8 +586,21 @@ static void *display_thread_tui(void *arg) | |||
579 | hists->uid_filter_str = top->record_opts.target.uid_str; | 586 | hists->uid_filter_str = top->record_opts.target.uid_str; |
580 | } | 587 | } |
581 | 588 | ||
582 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, | 589 | while (true) { |
583 | &top->session->header.env); | 590 | int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
591 | top->min_percent, | ||
592 | &top->session->header.env); | ||
593 | |||
594 | if (key != CTRL('z')) | ||
595 | break; | ||
596 | |||
597 | perf_evlist__toggle_enable(top->evlist); | ||
598 | /* | ||
599 | * No need to refresh, resort/decay histogram entries | ||
600 | * if we are not collecting samples: | ||
601 | */ | ||
602 | hbt.refresh = top->evlist->enabled ? top->delay_secs : 0; | ||
603 | } | ||
584 | 604 | ||
585 | done = 1; | 605 | done = 1; |
586 | return NULL; | 606 | return NULL; |
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index e34dfdf96b5a..9a7a116e09b8 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "thread_map.h" | 3 | #include "thread_map.h" |
4 | #include "cpumap.h" | 4 | #include "cpumap.h" |
5 | #include "debug.h" | 5 | #include "debug.h" |
6 | #include "stat.h" | ||
6 | 7 | ||
7 | int test__openat_syscall_event_on_all_cpus(void) | 8 | int test__openat_syscall_event_on_all_cpus(void) |
8 | { | 9 | { |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e64893f2fd7f..8f7c4d49d327 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1736,6 +1736,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1736 | "t Zoom into current Thread\n" | 1736 | "t Zoom into current Thread\n" |
1737 | "V Verbose (DSO names in callchains, etc)\n" | 1737 | "V Verbose (DSO names in callchains, etc)\n" |
1738 | "z Toggle zeroing of samples\n" | 1738 | "z Toggle zeroing of samples\n" |
1739 | "CTRL+z Enable/Disable events\n" | ||
1739 | "/ Filter symbol by name"; | 1740 | "/ Filter symbol by name"; |
1740 | 1741 | ||
1741 | if (browser == NULL) | 1742 | if (browser == NULL) |
@@ -1900,6 +1901,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1900 | /* Fall thru */ | 1901 | /* Fall thru */ |
1901 | case 'q': | 1902 | case 'q': |
1902 | case CTRL('c'): | 1903 | case CTRL('c'): |
1904 | case CTRL('z'): | ||
1903 | goto out_free_stack; | 1905 | goto out_free_stack; |
1904 | default: | 1906 | default: |
1905 | continue; | 1907 | continue; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index dc1dc2c181ef..8366511b45f8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -297,6 +297,8 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
297 | PERF_EVENT_IOC_DISABLE, 0); | 297 | PERF_EVENT_IOC_DISABLE, 0); |
298 | } | 298 | } |
299 | } | 299 | } |
300 | |||
301 | evlist->enabled = false; | ||
300 | } | 302 | } |
301 | 303 | ||
302 | void perf_evlist__enable(struct perf_evlist *evlist) | 304 | void perf_evlist__enable(struct perf_evlist *evlist) |
@@ -316,6 +318,13 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
316 | PERF_EVENT_IOC_ENABLE, 0); | 318 | PERF_EVENT_IOC_ENABLE, 0); |
317 | } | 319 | } |
318 | } | 320 | } |
321 | |||
322 | evlist->enabled = true; | ||
323 | } | ||
324 | |||
325 | void perf_evlist__toggle_enable(struct perf_evlist *evlist) | ||
326 | { | ||
327 | (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); | ||
319 | } | 328 | } |
320 | 329 | ||
321 | int perf_evlist__disable_event(struct perf_evlist *evlist, | 330 | int perf_evlist__disable_event(struct perf_evlist *evlist, |
@@ -634,11 +643,18 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, | |||
634 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 643 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) |
635 | { | 644 | { |
636 | struct perf_mmap *md = &evlist->mmap[idx]; | 645 | struct perf_mmap *md = &evlist->mmap[idx]; |
637 | u64 head = perf_mmap__read_head(md); | 646 | u64 head; |
638 | u64 old = md->prev; | 647 | u64 old = md->prev; |
639 | unsigned char *data = md->base + page_size; | 648 | unsigned char *data = md->base + page_size; |
640 | union perf_event *event = NULL; | 649 | union perf_event *event = NULL; |
641 | 650 | ||
651 | /* | ||
652 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
653 | */ | ||
654 | if (!atomic_read(&md->refcnt)) | ||
655 | return NULL; | ||
656 | |||
657 | head = perf_mmap__read_head(md); | ||
642 | if (evlist->overwrite) { | 658 | if (evlist->overwrite) { |
643 | /* | 659 | /* |
644 | * If we're further behind than half the buffer, there's a chance | 660 | * If we're further behind than half the buffer, there's a chance |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 955bf31b7dd3..a8489b9d2812 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -41,6 +41,7 @@ struct perf_evlist { | |||
41 | int nr_groups; | 41 | int nr_groups; |
42 | int nr_mmaps; | 42 | int nr_mmaps; |
43 | bool overwrite; | 43 | bool overwrite; |
44 | bool enabled; | ||
44 | size_t mmap_len; | 45 | size_t mmap_len; |
45 | int id_pos; | 46 | int id_pos; |
46 | int is_pos; | 47 | int is_pos; |
@@ -139,6 +140,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist); | |||
139 | 140 | ||
140 | void perf_evlist__disable(struct perf_evlist *evlist); | 141 | void perf_evlist__disable(struct perf_evlist *evlist); |
141 | void perf_evlist__enable(struct perf_evlist *evlist); | 142 | void perf_evlist__enable(struct perf_evlist *evlist); |
143 | void perf_evlist__toggle_enable(struct perf_evlist *evlist); | ||
142 | 144 | ||
143 | int perf_evlist__disable_event(struct perf_evlist *evlist, | 145 | int perf_evlist__disable_event(struct perf_evlist *evlist, |
144 | struct perf_evsel *evsel); | 146 | struct perf_evsel *evsel); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d4f9994ae47f..33449decf7bd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "perf_regs.h" | 26 | #include "perf_regs.h" |
27 | #include "debug.h" | 27 | #include "debug.h" |
28 | #include "trace-event.h" | 28 | #include "trace-event.h" |
29 | #include "stat.h" | ||
29 | 30 | ||
30 | static struct { | 31 | static struct { |
31 | bool sample_id_all; | 32 | bool sample_id_all; |
@@ -851,19 +852,6 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
851 | return 0; | 852 | return 0; |
852 | } | 853 | } |
853 | 854 | ||
854 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) | ||
855 | { | ||
856 | memset(evsel->counts, 0, (sizeof(*evsel->counts) + | ||
857 | (ncpus * sizeof(struct perf_counts_values)))); | ||
858 | } | ||
859 | |||
860 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | ||
861 | { | ||
862 | evsel->counts = zalloc((sizeof(*evsel->counts) + | ||
863 | (ncpus * sizeof(struct perf_counts_values)))); | ||
864 | return evsel->counts != NULL ? 0 : -ENOMEM; | ||
865 | } | ||
866 | |||
867 | static void perf_evsel__free_fd(struct perf_evsel *evsel) | 855 | static void perf_evsel__free_fd(struct perf_evsel *evsel) |
868 | { | 856 | { |
869 | xyarray__delete(evsel->fd); | 857 | xyarray__delete(evsel->fd); |
@@ -891,11 +879,6 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
891 | } | 879 | } |
892 | } | 880 | } |
893 | 881 | ||
894 | void perf_evsel__free_counts(struct perf_evsel *evsel) | ||
895 | { | ||
896 | zfree(&evsel->counts); | ||
897 | } | ||
898 | |||
899 | void perf_evsel__exit(struct perf_evsel *evsel) | 882 | void perf_evsel__exit(struct perf_evsel *evsel) |
900 | { | 883 | { |
901 | assert(list_empty(&evsel->node)); | 884 | assert(list_empty(&evsel->node)); |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 21ec08247d47..bb0579e8a10a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -170,9 +170,6 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel); | |||
170 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | 170 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); |
171 | 171 | ||
172 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 172 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
173 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | ||
174 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | ||
175 | void perf_evsel__free_counts(struct perf_evsel *evsel); | ||
176 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 173 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
177 | 174 | ||
178 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | 175 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f53d017c7c22..6f28d53d4e46 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -313,8 +313,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
313 | memset(&he->stat, 0, sizeof(he->stat)); | 313 | memset(&he->stat, 0, sizeof(he->stat)); |
314 | } | 314 | } |
315 | 315 | ||
316 | if (he->ms.map) | 316 | map__get(he->ms.map); |
317 | he->ms.map->referenced = true; | ||
318 | 317 | ||
319 | if (he->branch_info) { | 318 | if (he->branch_info) { |
320 | /* | 319 | /* |
@@ -324,6 +323,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
324 | */ | 323 | */ |
325 | he->branch_info = malloc(sizeof(*he->branch_info)); | 324 | he->branch_info = malloc(sizeof(*he->branch_info)); |
326 | if (he->branch_info == NULL) { | 325 | if (he->branch_info == NULL) { |
326 | map__zput(he->ms.map); | ||
327 | free(he->stat_acc); | 327 | free(he->stat_acc); |
328 | free(he); | 328 | free(he); |
329 | return NULL; | 329 | return NULL; |
@@ -332,17 +332,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, | |||
332 | memcpy(he->branch_info, template->branch_info, | 332 | memcpy(he->branch_info, template->branch_info, |
333 | sizeof(*he->branch_info)); | 333 | sizeof(*he->branch_info)); |
334 | 334 | ||
335 | if (he->branch_info->from.map) | 335 | map__get(he->branch_info->from.map); |
336 | he->branch_info->from.map->referenced = true; | 336 | map__get(he->branch_info->to.map); |
337 | if (he->branch_info->to.map) | ||
338 | he->branch_info->to.map->referenced = true; | ||
339 | } | 337 | } |
340 | 338 | ||
341 | if (he->mem_info) { | 339 | if (he->mem_info) { |
342 | if (he->mem_info->iaddr.map) | 340 | map__get(he->mem_info->iaddr.map); |
343 | he->mem_info->iaddr.map->referenced = true; | 341 | map__get(he->mem_info->daddr.map); |
344 | if (he->mem_info->daddr.map) | ||
345 | he->mem_info->daddr.map->referenced = true; | ||
346 | } | 342 | } |
347 | 343 | ||
348 | if (symbol_conf.use_callchain) | 344 | if (symbol_conf.use_callchain) |
@@ -407,9 +403,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists, | |||
407 | * the history counter to increment. | 403 | * the history counter to increment. |
408 | */ | 404 | */ |
409 | if (he->ms.map != entry->ms.map) { | 405 | if (he->ms.map != entry->ms.map) { |
410 | he->ms.map = entry->ms.map; | 406 | map__put(he->ms.map); |
411 | if (he->ms.map) | 407 | he->ms.map = map__get(entry->ms.map); |
412 | he->ms.map->referenced = true; | ||
413 | } | 408 | } |
414 | goto out; | 409 | goto out; |
415 | } | 410 | } |
@@ -933,8 +928,20 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
933 | void hist_entry__delete(struct hist_entry *he) | 928 | void hist_entry__delete(struct hist_entry *he) |
934 | { | 929 | { |
935 | thread__zput(he->thread); | 930 | thread__zput(he->thread); |
936 | zfree(&he->branch_info); | 931 | map__zput(he->ms.map); |
937 | zfree(&he->mem_info); | 932 | |
933 | if (he->branch_info) { | ||
934 | map__zput(he->branch_info->from.map); | ||
935 | map__zput(he->branch_info->to.map); | ||
936 | zfree(&he->branch_info); | ||
937 | } | ||
938 | |||
939 | if (he->mem_info) { | ||
940 | map__zput(he->mem_info->iaddr.map); | ||
941 | map__zput(he->mem_info->daddr.map); | ||
942 | zfree(&he->mem_info); | ||
943 | } | ||
944 | |||
938 | zfree(&he->stat_acc); | 945 | zfree(&he->stat_acc); |
939 | free_srcline(he->srcline); | 946 | free_srcline(he->srcline); |
940 | free_callchain(he->callchain); | 947 | free_callchain(he->callchain); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 1241ab989cf5..b5a5e9c02437 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -137,7 +137,6 @@ void map__init(struct map *map, enum map_type type, | |||
137 | map->unmap_ip = map__unmap_ip; | 137 | map->unmap_ip = map__unmap_ip; |
138 | RB_CLEAR_NODE(&map->rb_node); | 138 | RB_CLEAR_NODE(&map->rb_node); |
139 | map->groups = NULL; | 139 | map->groups = NULL; |
140 | map->referenced = false; | ||
141 | map->erange_warned = false; | 140 | map->erange_warned = false; |
142 | atomic_set(&map->refcnt, 1); | 141 | atomic_set(&map->refcnt, 1); |
143 | } | 142 | } |
@@ -439,7 +438,6 @@ static void maps__init(struct maps *maps) | |||
439 | { | 438 | { |
440 | maps->entries = RB_ROOT; | 439 | maps->entries = RB_ROOT; |
441 | pthread_rwlock_init(&maps->lock, NULL); | 440 | pthread_rwlock_init(&maps->lock, NULL); |
442 | INIT_LIST_HEAD(&maps->removed_maps); | ||
443 | } | 441 | } |
444 | 442 | ||
445 | void map_groups__init(struct map_groups *mg, struct machine *machine) | 443 | void map_groups__init(struct map_groups *mg, struct machine *machine) |
@@ -466,21 +464,10 @@ static void __maps__purge(struct maps *maps) | |||
466 | } | 464 | } |
467 | } | 465 | } |
468 | 466 | ||
469 | static void __maps__purge_removed_maps(struct maps *maps) | ||
470 | { | ||
471 | struct map *pos, *n; | ||
472 | |||
473 | list_for_each_entry_safe(pos, n, &maps->removed_maps, node) { | ||
474 | list_del_init(&pos->node); | ||
475 | map__put(pos); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | static void maps__exit(struct maps *maps) | 467 | static void maps__exit(struct maps *maps) |
480 | { | 468 | { |
481 | pthread_rwlock_wrlock(&maps->lock); | 469 | pthread_rwlock_wrlock(&maps->lock); |
482 | __maps__purge(maps); | 470 | __maps__purge(maps); |
483 | __maps__purge_removed_maps(maps); | ||
484 | pthread_rwlock_unlock(&maps->lock); | 471 | pthread_rwlock_unlock(&maps->lock); |
485 | } | 472 | } |
486 | 473 | ||
@@ -499,8 +486,6 @@ bool map_groups__empty(struct map_groups *mg) | |||
499 | for (i = 0; i < MAP__NR_TYPES; ++i) { | 486 | for (i = 0; i < MAP__NR_TYPES; ++i) { |
500 | if (maps__first(&mg->maps[i])) | 487 | if (maps__first(&mg->maps[i])) |
501 | return false; | 488 | return false; |
502 | if (!list_empty(&mg->maps[i].removed_maps)) | ||
503 | return false; | ||
504 | } | 489 | } |
505 | 490 | ||
506 | return true; | 491 | return true; |
@@ -621,7 +606,7 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, | |||
621 | return printed += maps__fprintf(&mg->maps[type], fp); | 606 | return printed += maps__fprintf(&mg->maps[type], fp); |
622 | } | 607 | } |
623 | 608 | ||
624 | static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) | 609 | size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) |
625 | { | 610 | { |
626 | size_t printed = 0, i; | 611 | size_t printed = 0, i; |
627 | for (i = 0; i < MAP__NR_TYPES; ++i) | 612 | for (i = 0; i < MAP__NR_TYPES; ++i) |
@@ -629,39 +614,6 @@ static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) | |||
629 | return printed; | 614 | return printed; |
630 | } | 615 | } |
631 | 616 | ||
632 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, | ||
633 | enum map_type type, FILE *fp) | ||
634 | { | ||
635 | struct map *pos; | ||
636 | size_t printed = 0; | ||
637 | |||
638 | list_for_each_entry(pos, &mg->maps[type].removed_maps, node) { | ||
639 | printed += fprintf(fp, "Map:"); | ||
640 | printed += map__fprintf(pos, fp); | ||
641 | if (verbose > 1) { | ||
642 | printed += dso__fprintf(pos->dso, type, fp); | ||
643 | printed += fprintf(fp, "--\n"); | ||
644 | } | ||
645 | } | ||
646 | return printed; | ||
647 | } | ||
648 | |||
649 | static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, | ||
650 | FILE *fp) | ||
651 | { | ||
652 | size_t printed = 0, i; | ||
653 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
654 | printed += __map_groups__fprintf_removed_maps(mg, i, fp); | ||
655 | return printed; | ||
656 | } | ||
657 | |||
658 | size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) | ||
659 | { | ||
660 | size_t printed = map_groups__fprintf_maps(mg, fp); | ||
661 | printed += fprintf(fp, "Removed maps:\n"); | ||
662 | return printed + map_groups__fprintf_removed_maps(mg, fp); | ||
663 | } | ||
664 | |||
665 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) | 617 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) |
666 | { | 618 | { |
667 | struct rb_root *root; | 619 | struct rb_root *root; |
@@ -719,13 +671,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp | |||
719 | map__fprintf(after, fp); | 671 | map__fprintf(after, fp); |
720 | } | 672 | } |
721 | put_map: | 673 | put_map: |
722 | /* | 674 | map__put(pos); |
723 | * If we have references, just move them to a separate list. | ||
724 | */ | ||
725 | if (pos->referenced) | ||
726 | list_add_tail(&pos->node, &maps->removed_maps); | ||
727 | else | ||
728 | map__put(pos); | ||
729 | 675 | ||
730 | if (err) | 676 | if (err) |
731 | goto out; | 677 | goto out; |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b8df09d94aca..d73e687b224e 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -34,7 +34,6 @@ struct map { | |||
34 | u64 start; | 34 | u64 start; |
35 | u64 end; | 35 | u64 end; |
36 | u8 /* enum map_type */ type; | 36 | u8 /* enum map_type */ type; |
37 | bool referenced; | ||
38 | bool erange_warned; | 37 | bool erange_warned; |
39 | u32 priv; | 38 | u32 priv; |
40 | u32 prot; | 39 | u32 prot; |
@@ -63,7 +62,6 @@ struct kmap { | |||
63 | struct maps { | 62 | struct maps { |
64 | struct rb_root entries; | 63 | struct rb_root entries; |
65 | pthread_rwlock_t lock; | 64 | pthread_rwlock_t lock; |
66 | struct list_head removed_maps; | ||
67 | }; | 65 | }; |
68 | 66 | ||
69 | struct map_groups { | 67 | struct map_groups { |
@@ -161,6 +159,14 @@ static inline struct map *map__get(struct map *map) | |||
161 | 159 | ||
162 | void map__put(struct map *map); | 160 | void map__put(struct map *map); |
163 | 161 | ||
162 | static inline void __map__zput(struct map **map) | ||
163 | { | ||
164 | map__put(*map); | ||
165 | *map = NULL; | ||
166 | } | ||
167 | |||
168 | #define map__zput(map) __map__zput(&map) | ||
169 | |||
164 | int map__overlap(struct map *l, struct map *r); | 170 | int map__overlap(struct map *l, struct map *r); |
165 | size_t map__fprintf(struct map *map, FILE *fp); | 171 | size_t map__fprintf(struct map *map, FILE *fp); |
166 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 172 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d4cf50b91839..076527b639bd 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -246,6 +246,20 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | |||
246 | clear_probe_trace_event(tevs + i); | 246 | clear_probe_trace_event(tevs + i); |
247 | } | 247 | } |
248 | 248 | ||
249 | static bool kprobe_blacklist__listed(unsigned long address); | ||
250 | static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | ||
251 | { | ||
252 | /* Get the address of _etext for checking non-probable text symbol */ | ||
253 | if (kernel_get_symbol_address_by_name("_etext", false) < address) | ||
254 | pr_warning("%s is out of .text, skip it.\n", symbol); | ||
255 | else if (kprobe_blacklist__listed(address)) | ||
256 | pr_warning("%s is blacklisted function, skip it.\n", symbol); | ||
257 | else | ||
258 | return false; | ||
259 | |||
260 | return true; | ||
261 | } | ||
262 | |||
249 | #ifdef HAVE_DWARF_SUPPORT | 263 | #ifdef HAVE_DWARF_SUPPORT |
250 | 264 | ||
251 | static int kernel_get_module_dso(const char *module, struct dso **pdso) | 265 | static int kernel_get_module_dso(const char *module, struct dso **pdso) |
@@ -415,6 +429,41 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent) | |||
415 | return ret; | 429 | return ret; |
416 | } | 430 | } |
417 | 431 | ||
432 | /* For caching the last debuginfo */ | ||
433 | static struct debuginfo *debuginfo_cache; | ||
434 | static char *debuginfo_cache_path; | ||
435 | |||
436 | static struct debuginfo *debuginfo_cache__open(const char *module, bool silent) | ||
437 | { | ||
438 | if ((debuginfo_cache_path && !strcmp(debuginfo_cache_path, module)) || | ||
439 | (!debuginfo_cache_path && !module && debuginfo_cache)) | ||
440 | goto out; | ||
441 | |||
442 | /* Copy module path */ | ||
443 | free(debuginfo_cache_path); | ||
444 | if (module) { | ||
445 | debuginfo_cache_path = strdup(module); | ||
446 | if (!debuginfo_cache_path) { | ||
447 | debuginfo__delete(debuginfo_cache); | ||
448 | debuginfo_cache = NULL; | ||
449 | goto out; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | debuginfo_cache = open_debuginfo(module, silent); | ||
454 | if (!debuginfo_cache) | ||
455 | zfree(&debuginfo_cache_path); | ||
456 | out: | ||
457 | return debuginfo_cache; | ||
458 | } | ||
459 | |||
460 | static void debuginfo_cache__exit(void) | ||
461 | { | ||
462 | debuginfo__delete(debuginfo_cache); | ||
463 | debuginfo_cache = NULL; | ||
464 | zfree(&debuginfo_cache_path); | ||
465 | } | ||
466 | |||
418 | 467 | ||
419 | static int get_text_start_address(const char *exec, unsigned long *address) | 468 | static int get_text_start_address(const char *exec, unsigned long *address) |
420 | { | 469 | { |
@@ -476,12 +525,11 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, | |||
476 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, | 525 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, |
477 | tp->module ? : "kernel"); | 526 | tp->module ? : "kernel"); |
478 | 527 | ||
479 | dinfo = open_debuginfo(tp->module, verbose == 0); | 528 | dinfo = debuginfo_cache__open(tp->module, verbose == 0); |
480 | if (dinfo) { | 529 | if (dinfo) |
481 | ret = debuginfo__find_probe_point(dinfo, | 530 | ret = debuginfo__find_probe_point(dinfo, |
482 | (unsigned long)addr, pp); | 531 | (unsigned long)addr, pp); |
483 | debuginfo__delete(dinfo); | 532 | else |
484 | } else | ||
485 | ret = -ENOENT; | 533 | ret = -ENOENT; |
486 | 534 | ||
487 | if (ret > 0) { | 535 | if (ret > 0) { |
@@ -559,7 +607,6 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, | |||
559 | bool uprobe) | 607 | bool uprobe) |
560 | { | 608 | { |
561 | struct ref_reloc_sym *reloc_sym; | 609 | struct ref_reloc_sym *reloc_sym; |
562 | u64 etext_addr; | ||
563 | char *tmp; | 610 | char *tmp; |
564 | int i, skipped = 0; | 611 | int i, skipped = 0; |
565 | 612 | ||
@@ -575,31 +622,28 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, | |||
575 | pr_warning("Relocated base symbol is not found!\n"); | 622 | pr_warning("Relocated base symbol is not found!\n"); |
576 | return -EINVAL; | 623 | return -EINVAL; |
577 | } | 624 | } |
578 | /* Get the address of _etext for checking non-probable text symbol */ | ||
579 | etext_addr = kernel_get_symbol_address_by_name("_etext", false); | ||
580 | 625 | ||
581 | for (i = 0; i < ntevs; i++) { | 626 | for (i = 0; i < ntevs; i++) { |
582 | if (tevs[i].point.address && !tevs[i].point.retprobe) { | 627 | if (!tevs[i].point.address || tevs[i].point.retprobe) |
583 | /* If we found a wrong one, mark it by NULL symbol */ | 628 | continue; |
584 | if (etext_addr < tevs[i].point.address) { | 629 | /* If we found a wrong one, mark it by NULL symbol */ |
585 | pr_warning("%s+%lu is out of .text, skip it.\n", | 630 | if (kprobe_warn_out_range(tevs[i].point.symbol, |
586 | tevs[i].point.symbol, tevs[i].point.offset); | 631 | tevs[i].point.address)) { |
587 | tmp = NULL; | 632 | tmp = NULL; |
588 | skipped++; | 633 | skipped++; |
589 | } else { | 634 | } else { |
590 | tmp = strdup(reloc_sym->name); | 635 | tmp = strdup(reloc_sym->name); |
591 | if (!tmp) | 636 | if (!tmp) |
592 | return -ENOMEM; | 637 | return -ENOMEM; |
593 | } | ||
594 | /* If we have no realname, use symbol for it */ | ||
595 | if (!tevs[i].point.realname) | ||
596 | tevs[i].point.realname = tevs[i].point.symbol; | ||
597 | else | ||
598 | free(tevs[i].point.symbol); | ||
599 | tevs[i].point.symbol = tmp; | ||
600 | tevs[i].point.offset = tevs[i].point.address - | ||
601 | reloc_sym->unrelocated_addr; | ||
602 | } | 638 | } |
639 | /* If we have no realname, use symbol for it */ | ||
640 | if (!tevs[i].point.realname) | ||
641 | tevs[i].point.realname = tevs[i].point.symbol; | ||
642 | else | ||
643 | free(tevs[i].point.symbol); | ||
644 | tevs[i].point.symbol = tmp; | ||
645 | tevs[i].point.offset = tevs[i].point.address - | ||
646 | reloc_sym->unrelocated_addr; | ||
603 | } | 647 | } |
604 | return skipped; | 648 | return skipped; |
605 | } | 649 | } |
@@ -920,6 +964,10 @@ out: | |||
920 | 964 | ||
921 | #else /* !HAVE_DWARF_SUPPORT */ | 965 | #else /* !HAVE_DWARF_SUPPORT */ |
922 | 966 | ||
967 | static void debuginfo_cache__exit(void) | ||
968 | { | ||
969 | } | ||
970 | |||
923 | static int | 971 | static int |
924 | find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, | 972 | find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, |
925 | struct perf_probe_point *pp __maybe_unused, | 973 | struct perf_probe_point *pp __maybe_unused, |
@@ -2126,9 +2174,31 @@ kprobe_blacklist__find_by_address(struct list_head *blacklist, | |||
2126 | return NULL; | 2174 | return NULL; |
2127 | } | 2175 | } |
2128 | 2176 | ||
2129 | /* Show an event */ | 2177 | static LIST_HEAD(kprobe_blacklist); |
2130 | static int show_perf_probe_event(struct perf_probe_event *pev, | 2178 | |
2131 | const char *module) | 2179 | static void kprobe_blacklist__init(void) |
2180 | { | ||
2181 | if (!list_empty(&kprobe_blacklist)) | ||
2182 | return; | ||
2183 | |||
2184 | if (kprobe_blacklist__load(&kprobe_blacklist) < 0) | ||
2185 | pr_debug("No kprobe blacklist support, ignored\n"); | ||
2186 | } | ||
2187 | |||
2188 | static void kprobe_blacklist__release(void) | ||
2189 | { | ||
2190 | kprobe_blacklist__delete(&kprobe_blacklist); | ||
2191 | } | ||
2192 | |||
2193 | static bool kprobe_blacklist__listed(unsigned long address) | ||
2194 | { | ||
2195 | return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address); | ||
2196 | } | ||
2197 | |||
2198 | static int perf_probe_event__sprintf(const char *group, const char *event, | ||
2199 | struct perf_probe_event *pev, | ||
2200 | const char *module, | ||
2201 | struct strbuf *result) | ||
2132 | { | 2202 | { |
2133 | int i, ret; | 2203 | int i, ret; |
2134 | char buf[128]; | 2204 | char buf[128]; |
@@ -2139,29 +2209,50 @@ static int show_perf_probe_event(struct perf_probe_event *pev, | |||
2139 | if (!place) | 2209 | if (!place) |
2140 | return -EINVAL; | 2210 | return -EINVAL; |
2141 | 2211 | ||
2142 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | 2212 | ret = e_snprintf(buf, 128, "%s:%s", group, event); |
2143 | if (ret < 0) | 2213 | if (ret < 0) |
2144 | return ret; | 2214 | goto out; |
2145 | 2215 | ||
2146 | pr_info(" %-20s (on %s", buf, place); | 2216 | strbuf_addf(result, " %-20s (on %s", buf, place); |
2147 | if (module) | 2217 | if (module) |
2148 | pr_info(" in %s", module); | 2218 | strbuf_addf(result, " in %s", module); |
2149 | 2219 | ||
2150 | if (pev->nargs > 0) { | 2220 | if (pev->nargs > 0) { |
2151 | pr_info(" with"); | 2221 | strbuf_addstr(result, " with"); |
2152 | for (i = 0; i < pev->nargs; i++) { | 2222 | for (i = 0; i < pev->nargs; i++) { |
2153 | ret = synthesize_perf_probe_arg(&pev->args[i], | 2223 | ret = synthesize_perf_probe_arg(&pev->args[i], |
2154 | buf, 128); | 2224 | buf, 128); |
2155 | if (ret < 0) | 2225 | if (ret < 0) |
2156 | break; | 2226 | goto out; |
2157 | pr_info(" %s", buf); | 2227 | strbuf_addf(result, " %s", buf); |
2158 | } | 2228 | } |
2159 | } | 2229 | } |
2160 | pr_info(")\n"); | 2230 | strbuf_addch(result, ')'); |
2231 | out: | ||
2161 | free(place); | 2232 | free(place); |
2162 | return ret; | 2233 | return ret; |
2163 | } | 2234 | } |
2164 | 2235 | ||
2236 | /* Show an event */ | ||
2237 | static int show_perf_probe_event(const char *group, const char *event, | ||
2238 | struct perf_probe_event *pev, | ||
2239 | const char *module, bool use_stdout) | ||
2240 | { | ||
2241 | struct strbuf buf = STRBUF_INIT; | ||
2242 | int ret; | ||
2243 | |||
2244 | ret = perf_probe_event__sprintf(group, event, pev, module, &buf); | ||
2245 | if (ret >= 0) { | ||
2246 | if (use_stdout) | ||
2247 | printf("%s\n", buf.buf); | ||
2248 | else | ||
2249 | pr_info("%s\n", buf.buf); | ||
2250 | } | ||
2251 | strbuf_release(&buf); | ||
2252 | |||
2253 | return ret; | ||
2254 | } | ||
2255 | |||
2165 | static bool filter_probe_trace_event(struct probe_trace_event *tev, | 2256 | static bool filter_probe_trace_event(struct probe_trace_event *tev, |
2166 | struct strfilter *filter) | 2257 | struct strfilter *filter) |
2167 | { | 2258 | { |
@@ -2200,9 +2291,11 @@ static int __show_perf_probe_events(int fd, bool is_kprobe, | |||
2200 | goto next; | 2291 | goto next; |
2201 | ret = convert_to_perf_probe_event(&tev, &pev, | 2292 | ret = convert_to_perf_probe_event(&tev, &pev, |
2202 | is_kprobe); | 2293 | is_kprobe); |
2203 | if (ret >= 0) | 2294 | if (ret < 0) |
2204 | ret = show_perf_probe_event(&pev, | 2295 | goto next; |
2205 | tev.point.module); | 2296 | ret = show_perf_probe_event(pev.group, pev.event, |
2297 | &pev, tev.point.module, | ||
2298 | true); | ||
2206 | } | 2299 | } |
2207 | next: | 2300 | next: |
2208 | clear_perf_probe_event(&pev); | 2301 | clear_perf_probe_event(&pev); |
@@ -2211,6 +2304,8 @@ next: | |||
2211 | break; | 2304 | break; |
2212 | } | 2305 | } |
2213 | strlist__delete(rawlist); | 2306 | strlist__delete(rawlist); |
2307 | /* Cleanup cached debuginfo if needed */ | ||
2308 | debuginfo_cache__exit(); | ||
2214 | 2309 | ||
2215 | return ret; | 2310 | return ret; |
2216 | } | 2311 | } |
@@ -2316,6 +2411,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2316 | struct strlist *namelist, bool allow_suffix) | 2411 | struct strlist *namelist, bool allow_suffix) |
2317 | { | 2412 | { |
2318 | int i, ret; | 2413 | int i, ret; |
2414 | char *p; | ||
2319 | 2415 | ||
2320 | if (*base == '.') | 2416 | if (*base == '.') |
2321 | base++; | 2417 | base++; |
@@ -2326,6 +2422,10 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2326 | pr_debug("snprintf() failed: %d\n", ret); | 2422 | pr_debug("snprintf() failed: %d\n", ret); |
2327 | return ret; | 2423 | return ret; |
2328 | } | 2424 | } |
2425 | /* Cut off the postfixes (e.g. .const, .isra)*/ | ||
2426 | p = strchr(buf, '.'); | ||
2427 | if (p && p != buf) | ||
2428 | *p = '\0'; | ||
2329 | if (!strlist__has_entry(namelist, buf)) | 2429 | if (!strlist__has_entry(namelist, buf)) |
2330 | return 0; | 2430 | return 0; |
2331 | 2431 | ||
@@ -2381,10 +2481,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2381 | int i, fd, ret; | 2481 | int i, fd, ret; |
2382 | struct probe_trace_event *tev = NULL; | 2482 | struct probe_trace_event *tev = NULL; |
2383 | char buf[64]; | 2483 | char buf[64]; |
2384 | const char *event, *group; | 2484 | const char *event = NULL, *group = NULL; |
2385 | struct strlist *namelist; | 2485 | struct strlist *namelist; |
2386 | LIST_HEAD(blacklist); | ||
2387 | struct kprobe_blacklist_node *node; | ||
2388 | bool safename; | 2486 | bool safename; |
2389 | 2487 | ||
2390 | if (pev->uprobes) | 2488 | if (pev->uprobes) |
@@ -2404,28 +2502,15 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2404 | ret = -ENOMEM; | 2502 | ret = -ENOMEM; |
2405 | goto close_out; | 2503 | goto close_out; |
2406 | } | 2504 | } |
2407 | /* Get kprobe blacklist if exists */ | ||
2408 | if (!pev->uprobes) { | ||
2409 | ret = kprobe_blacklist__load(&blacklist); | ||
2410 | if (ret < 0) | ||
2411 | pr_debug("No kprobe blacklist support, ignored\n"); | ||
2412 | } | ||
2413 | 2505 | ||
2414 | safename = (pev->point.function && !strisglob(pev->point.function)); | 2506 | safename = (pev->point.function && !strisglob(pev->point.function)); |
2415 | ret = 0; | 2507 | ret = 0; |
2416 | pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); | 2508 | pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); |
2417 | for (i = 0; i < ntevs; i++) { | 2509 | for (i = 0; i < ntevs; i++) { |
2418 | tev = &tevs[i]; | 2510 | tev = &tevs[i]; |
2419 | /* Skip if the symbol is out of .text (marked previously) */ | 2511 | /* Skip if the symbol is out of .text or blacklisted */ |
2420 | if (!tev->point.symbol) | 2512 | if (!tev->point.symbol) |
2421 | continue; | 2513 | continue; |
2422 | /* Ensure that the address is NOT blacklisted */ | ||
2423 | node = kprobe_blacklist__find_by_address(&blacklist, | ||
2424 | tev->point.address); | ||
2425 | if (node) { | ||
2426 | pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); | ||
2427 | continue; | ||
2428 | } | ||
2429 | 2514 | ||
2430 | if (pev->event) | 2515 | if (pev->event) |
2431 | event = pev->event; | 2516 | event = pev->event; |
@@ -2458,15 +2543,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2458 | /* Add added event name to namelist */ | 2543 | /* Add added event name to namelist */ |
2459 | strlist__add(namelist, event); | 2544 | strlist__add(namelist, event); |
2460 | 2545 | ||
2461 | /* Trick here - save current event/group */ | 2546 | /* We use tev's name for showing new events */ |
2462 | event = pev->event; | 2547 | show_perf_probe_event(tev->group, tev->event, pev, |
2463 | group = pev->group; | 2548 | tev->point.module, false); |
2464 | pev->event = tev->event; | 2549 | /* Save the last valid name */ |
2465 | pev->group = tev->group; | 2550 | event = tev->event; |
2466 | show_perf_probe_event(pev, tev->point.module); | 2551 | group = tev->group; |
2467 | /* Trick here - restore current event/group */ | ||
2468 | pev->event = (char *)event; | ||
2469 | pev->group = (char *)group; | ||
2470 | 2552 | ||
2471 | /* | 2553 | /* |
2472 | * Probes after the first probe which comes from same | 2554 | * Probes after the first probe which comes from same |
@@ -2480,14 +2562,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2480 | warn_uprobe_event_compat(tev); | 2562 | warn_uprobe_event_compat(tev); |
2481 | 2563 | ||
2482 | /* Note that it is possible to skip all events because of blacklist */ | 2564 | /* Note that it is possible to skip all events because of blacklist */ |
2483 | if (ret >= 0 && tev->event) { | 2565 | if (ret >= 0 && event) { |
2484 | /* Show how to use the event. */ | 2566 | /* Show how to use the event. */ |
2485 | pr_info("\nYou can now use it in all perf tools, such as:\n\n"); | 2567 | pr_info("\nYou can now use it in all perf tools, such as:\n\n"); |
2486 | pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, | 2568 | pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); |
2487 | tev->event); | ||
2488 | } | 2569 | } |
2489 | 2570 | ||
2490 | kprobe_blacklist__delete(&blacklist); | ||
2491 | strlist__delete(namelist); | 2571 | strlist__delete(namelist); |
2492 | close_out: | 2572 | close_out: |
2493 | close(fd); | 2573 | close(fd); |
@@ -2537,7 +2617,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2537 | struct perf_probe_point *pp = &pev->point; | 2617 | struct perf_probe_point *pp = &pev->point; |
2538 | struct probe_trace_point *tp; | 2618 | struct probe_trace_point *tp; |
2539 | int num_matched_functions; | 2619 | int num_matched_functions; |
2540 | int ret, i, j; | 2620 | int ret, i, j, skipped = 0; |
2541 | 2621 | ||
2542 | map = get_target_map(pev->target, pev->uprobes); | 2622 | map = get_target_map(pev->target, pev->uprobes); |
2543 | if (!map) { | 2623 | if (!map) { |
@@ -2605,7 +2685,12 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2605 | } | 2685 | } |
2606 | /* Add one probe point */ | 2686 | /* Add one probe point */ |
2607 | tp->address = map->unmap_ip(map, sym->start) + pp->offset; | 2687 | tp->address = map->unmap_ip(map, sym->start) + pp->offset; |
2608 | if (reloc_sym) { | 2688 | /* If we found a wrong one, mark it by NULL symbol */ |
2689 | if (!pev->uprobes && | ||
2690 | kprobe_warn_out_range(sym->name, tp->address)) { | ||
2691 | tp->symbol = NULL; /* Skip it */ | ||
2692 | skipped++; | ||
2693 | } else if (reloc_sym) { | ||
2609 | tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); | 2694 | tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); |
2610 | tp->offset = tp->address - reloc_sym->addr; | 2695 | tp->offset = tp->address - reloc_sym->addr; |
2611 | } else { | 2696 | } else { |
@@ -2641,6 +2726,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2641 | } | 2726 | } |
2642 | arch__fix_tev_from_maps(pev, tev, map); | 2727 | arch__fix_tev_from_maps(pev, tev, map); |
2643 | } | 2728 | } |
2729 | if (ret == skipped) { | ||
2730 | ret = -ENOENT; | ||
2731 | goto err_out; | ||
2732 | } | ||
2644 | 2733 | ||
2645 | out: | 2734 | out: |
2646 | put_target_map(map, pev->uprobes); | 2735 | put_target_map(map, pev->uprobes); |
@@ -2711,6 +2800,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) | |||
2711 | /* Loop 1: convert all events */ | 2800 | /* Loop 1: convert all events */ |
2712 | for (i = 0; i < npevs; i++) { | 2801 | for (i = 0; i < npevs; i++) { |
2713 | pkgs[i].pev = &pevs[i]; | 2802 | pkgs[i].pev = &pevs[i]; |
2803 | /* Init kprobe blacklist if needed */ | ||
2804 | if (!pkgs[i].pev->uprobes) | ||
2805 | kprobe_blacklist__init(); | ||
2714 | /* Convert with or without debuginfo */ | 2806 | /* Convert with or without debuginfo */ |
2715 | ret = convert_to_probe_trace_events(pkgs[i].pev, | 2807 | ret = convert_to_probe_trace_events(pkgs[i].pev, |
2716 | &pkgs[i].tevs); | 2808 | &pkgs[i].tevs); |
@@ -2718,6 +2810,8 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) | |||
2718 | goto end; | 2810 | goto end; |
2719 | pkgs[i].ntevs = ret; | 2811 | pkgs[i].ntevs = ret; |
2720 | } | 2812 | } |
2813 | /* This just release blacklist only if allocated */ | ||
2814 | kprobe_blacklist__release(); | ||
2721 | 2815 | ||
2722 | /* Loop 2: add all events */ | 2816 | /* Loop 2: add all events */ |
2723 | for (i = 0; i < npevs; i++) { | 2817 | for (i = 0; i < npevs; i++) { |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 4d28624a1eca..5925fec90562 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -16,6 +16,7 @@ util/util.c | |||
16 | util/xyarray.c | 16 | util/xyarray.c |
17 | util/cgroup.c | 17 | util/cgroup.c |
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/stat.c | ||
19 | util/strlist.c | 20 | util/strlist.c |
20 | util/trace-event.c | 21 | util/trace-event.c |
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f31e024ddf7d..e1cd17c2afab 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -517,20 +517,42 @@ void perf_event__attr_swap(struct perf_event_attr *attr) | |||
517 | { | 517 | { |
518 | attr->type = bswap_32(attr->type); | 518 | attr->type = bswap_32(attr->type); |
519 | attr->size = bswap_32(attr->size); | 519 | attr->size = bswap_32(attr->size); |
520 | attr->config = bswap_64(attr->config); | 520 | |
521 | attr->sample_period = bswap_64(attr->sample_period); | 521 | #define bswap_safe(f, n) \ |
522 | attr->sample_type = bswap_64(attr->sample_type); | 522 | (attr->size > (offsetof(struct perf_event_attr, f) + \ |
523 | attr->read_format = bswap_64(attr->read_format); | 523 | sizeof(attr->f) * (n))) |
524 | attr->wakeup_events = bswap_32(attr->wakeup_events); | 524 | #define bswap_field(f, sz) \ |
525 | attr->bp_type = bswap_32(attr->bp_type); | 525 | do { \ |
526 | attr->bp_addr = bswap_64(attr->bp_addr); | 526 | if (bswap_safe(f, 0)) \ |
527 | attr->bp_len = bswap_64(attr->bp_len); | 527 | attr->f = bswap_##sz(attr->f); \ |
528 | attr->branch_sample_type = bswap_64(attr->branch_sample_type); | 528 | } while(0) |
529 | attr->sample_regs_user = bswap_64(attr->sample_regs_user); | 529 | #define bswap_field_32(f) bswap_field(f, 32) |
530 | attr->sample_stack_user = bswap_32(attr->sample_stack_user); | 530 | #define bswap_field_64(f) bswap_field(f, 64) |
531 | attr->aux_watermark = bswap_32(attr->aux_watermark); | 531 | |
532 | 532 | bswap_field_64(config); | |
533 | swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); | 533 | bswap_field_64(sample_period); |
534 | bswap_field_64(sample_type); | ||
535 | bswap_field_64(read_format); | ||
536 | bswap_field_32(wakeup_events); | ||
537 | bswap_field_32(bp_type); | ||
538 | bswap_field_64(bp_addr); | ||
539 | bswap_field_64(bp_len); | ||
540 | bswap_field_64(branch_sample_type); | ||
541 | bswap_field_64(sample_regs_user); | ||
542 | bswap_field_32(sample_stack_user); | ||
543 | bswap_field_32(aux_watermark); | ||
544 | |||
545 | /* | ||
546 | * After read_format are bitfields. Check read_format because | ||
547 | * we are unable to use offsetof on bitfield. | ||
548 | */ | ||
549 | if (bswap_safe(read_format, 1)) | ||
550 | swap_bitfield((u8 *) (&attr->read_format + 1), | ||
551 | sizeof(u64)); | ||
552 | #undef bswap_field_64 | ||
553 | #undef bswap_field_32 | ||
554 | #undef bswap_field | ||
555 | #undef bswap_safe | ||
534 | } | 556 | } |
535 | 557 | ||
536 | static void perf_event__hdr_attr_swap(union perf_event *event, | 558 | static void perf_event__hdr_attr_swap(union perf_event *event, |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 60b92822f655..4014b709f956 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
@@ -94,3 +94,39 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | } | 96 | } |
97 | |||
98 | struct perf_counts *perf_counts__new(int ncpus) | ||
99 | { | ||
100 | int size = sizeof(struct perf_counts) + | ||
101 | ncpus * sizeof(struct perf_counts_values); | ||
102 | |||
103 | return zalloc(size); | ||
104 | } | ||
105 | |||
106 | void perf_counts__delete(struct perf_counts *counts) | ||
107 | { | ||
108 | free(counts); | ||
109 | } | ||
110 | |||
111 | static void perf_counts__reset(struct perf_counts *counts, int ncpus) | ||
112 | { | ||
113 | memset(counts, 0, (sizeof(*counts) + | ||
114 | (ncpus * sizeof(struct perf_counts_values)))); | ||
115 | } | ||
116 | |||
117 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) | ||
118 | { | ||
119 | perf_counts__reset(evsel->counts, ncpus); | ||
120 | } | ||
121 | |||
122 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | ||
123 | { | ||
124 | evsel->counts = perf_counts__new(ncpus); | ||
125 | return evsel->counts != NULL ? 0 : -ENOMEM; | ||
126 | } | ||
127 | |||
128 | void perf_evsel__free_counts(struct perf_evsel *evsel) | ||
129 | { | ||
130 | perf_counts__delete(evsel->counts); | ||
131 | evsel->counts = NULL; | ||
132 | } | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 615c779eb42a..093dc3cb28dd 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
@@ -62,4 +62,10 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, | |||
62 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, | 62 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, |
63 | double avg, int cpu, enum aggr_mode aggr); | 63 | double avg, int cpu, enum aggr_mode aggr); |
64 | 64 | ||
65 | struct perf_counts *perf_counts__new(int ncpus); | ||
66 | void perf_counts__delete(struct perf_counts *counts); | ||
67 | |||
68 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | ||
69 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | ||
70 | void perf_evsel__free_counts(struct perf_evsel *evsel); | ||
65 | #endif | 71 | #endif |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index f93b9734735b..f4822bd03709 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -20,6 +20,15 @@ static int filter(const struct dirent *dir) | |||
20 | return 1; | 20 | return 1; |
21 | } | 21 | } |
22 | 22 | ||
23 | static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) | ||
24 | { | ||
25 | size_t size = sizeof(*map) + sizeof(pid_t) * nr; | ||
26 | |||
27 | return realloc(map, size); | ||
28 | } | ||
29 | |||
30 | #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) | ||
31 | |||
23 | struct thread_map *thread_map__new_by_pid(pid_t pid) | 32 | struct thread_map *thread_map__new_by_pid(pid_t pid) |
24 | { | 33 | { |
25 | struct thread_map *threads; | 34 | struct thread_map *threads; |
@@ -33,7 +42,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) | |||
33 | if (items <= 0) | 42 | if (items <= 0) |
34 | return NULL; | 43 | return NULL; |
35 | 44 | ||
36 | threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); | 45 | threads = thread_map__alloc(items); |
37 | if (threads != NULL) { | 46 | if (threads != NULL) { |
38 | for (i = 0; i < items; i++) | 47 | for (i = 0; i < items; i++) |
39 | threads->map[i] = atoi(namelist[i]->d_name); | 48 | threads->map[i] = atoi(namelist[i]->d_name); |
@@ -49,7 +58,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) | |||
49 | 58 | ||
50 | struct thread_map *thread_map__new_by_tid(pid_t tid) | 59 | struct thread_map *thread_map__new_by_tid(pid_t tid) |
51 | { | 60 | { |
52 | struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); | 61 | struct thread_map *threads = thread_map__alloc(1); |
53 | 62 | ||
54 | if (threads != NULL) { | 63 | if (threads != NULL) { |
55 | threads->map[0] = tid; | 64 | threads->map[0] = tid; |
@@ -65,8 +74,8 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
65 | int max_threads = 32, items, i; | 74 | int max_threads = 32, items, i; |
66 | char path[256]; | 75 | char path[256]; |
67 | struct dirent dirent, *next, **namelist = NULL; | 76 | struct dirent dirent, *next, **namelist = NULL; |
68 | struct thread_map *threads = malloc(sizeof(*threads) + | 77 | struct thread_map *threads = thread_map__alloc(max_threads); |
69 | max_threads * sizeof(pid_t)); | 78 | |
70 | if (threads == NULL) | 79 | if (threads == NULL) |
71 | goto out; | 80 | goto out; |
72 | 81 | ||
@@ -185,8 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | |||
185 | goto out_free_threads; | 194 | goto out_free_threads; |
186 | 195 | ||
187 | total_tasks += items; | 196 | total_tasks += items; |
188 | nt = realloc(threads, (sizeof(*threads) + | 197 | nt = thread_map__realloc(threads, total_tasks); |
189 | sizeof(pid_t) * total_tasks)); | ||
190 | if (nt == NULL) | 198 | if (nt == NULL) |
191 | goto out_free_namelist; | 199 | goto out_free_namelist; |
192 | 200 | ||
@@ -216,7 +224,7 @@ out_free_threads: | |||
216 | 224 | ||
217 | struct thread_map *thread_map__new_dummy(void) | 225 | struct thread_map *thread_map__new_dummy(void) |
218 | { | 226 | { |
219 | struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); | 227 | struct thread_map *threads = thread_map__alloc(1); |
220 | 228 | ||
221 | if (threads != NULL) { | 229 | if (threads != NULL) { |
222 | threads->map[0] = -1; | 230 | threads->map[0] = -1; |
@@ -253,7 +261,7 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | |||
253 | continue; | 261 | continue; |
254 | 262 | ||
255 | ntasks++; | 263 | ntasks++; |
256 | nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); | 264 | nt = thread_map__realloc(threads, ntasks); |
257 | 265 | ||
258 | if (nt == NULL) | 266 | if (nt == NULL) |
259 | goto out_free_threads; | 267 | goto out_free_threads; |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index f079b63f0b7f..4c00507ee3fd 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -360,7 +360,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
360 | unw_word_t base = is_exec ? 0 : map->start; | 360 | unw_word_t base = is_exec ? 0 : map->start; |
361 | 361 | ||
362 | if (fd >= 0) | 362 | if (fd >= 0) |
363 | dso__data_put_fd(dso); | 363 | dso__data_put_fd(map->dso); |
364 | 364 | ||
365 | memset(&di, 0, sizeof(di)); | 365 | memset(&di, 0, sizeof(di)); |
366 | 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, |
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c index 22afbf6c536a..c10ba41ef3f6 100644 --- a/tools/perf/util/xyarray.c +++ b/tools/perf/util/xyarray.c | |||
@@ -9,11 +9,19 @@ struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) | |||
9 | if (xy != NULL) { | 9 | if (xy != NULL) { |
10 | xy->entry_size = entry_size; | 10 | xy->entry_size = entry_size; |
11 | xy->row_size = row_size; | 11 | xy->row_size = row_size; |
12 | xy->entries = xlen * ylen; | ||
12 | } | 13 | } |
13 | 14 | ||
14 | return xy; | 15 | return xy; |
15 | } | 16 | } |
16 | 17 | ||
18 | void xyarray__reset(struct xyarray *xy) | ||
19 | { | ||
20 | size_t n = xy->entries * xy->entry_size; | ||
21 | |||
22 | memset(xy->contents, 0, n); | ||
23 | } | ||
24 | |||
17 | void xyarray__delete(struct xyarray *xy) | 25 | void xyarray__delete(struct xyarray *xy) |
18 | { | 26 | { |
19 | free(xy); | 27 | free(xy); |
diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h index c488a07275dd..7f30af371b7e 100644 --- a/tools/perf/util/xyarray.h +++ b/tools/perf/util/xyarray.h | |||
@@ -6,11 +6,13 @@ | |||
6 | struct xyarray { | 6 | struct xyarray { |
7 | size_t row_size; | 7 | size_t row_size; |
8 | size_t entry_size; | 8 | size_t entry_size; |
9 | size_t entries; | ||
9 | char contents[]; | 10 | char contents[]; |
10 | }; | 11 | }; |
11 | 12 | ||
12 | struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); | 13 | struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); |
13 | void xyarray__delete(struct xyarray *xy); | 14 | void xyarray__delete(struct xyarray *xy); |
15 | void xyarray__reset(struct xyarray *xy); | ||
14 | 16 | ||
15 | static inline void *xyarray__entry(struct xyarray *xy, int x, int y) | 17 | static inline void *xyarray__entry(struct xyarray *xy, int x, int y) |
16 | { | 18 | { |