diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-18 19:52:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-18 19:52:46 -0400 |
commit | f82c37e7bb4c4d9b6a476c642d5c2d2efbd6f240 (patch) | |
tree | 09fc553c2fb6f527962048d139159dc139e04afc /tools/perf | |
parent | c6b9e73f2fee8bb86058f296de808b326473456b (diff) | |
parent | dcd5c1662db59a6b82942f47fb6ac9dd63f6d3dd (diff) |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (35 commits)
perf: Fix unexported generic perf_arch_fetch_caller_regs
perf record: Don't try to find buildids in a zero sized file
perf: export perf_trace_regs and perf_arch_fetch_caller_regs
perf, x86: Fix hw_perf_enable() event assignment
perf, ppc: Fix compile error due to new cpu notifiers
perf: Make the install relative to DESTDIR if specified
kprobes: Calculate the index correctly when freeing the out-of-line execution slot
perf tools: Fix sparse CPU numbering related bugs
perf_event: Fix oops triggered by cpu offline/online
perf: Drop the obsolete profile naming for trace events
perf: Take a hot regs snapshot for trace events
perf: Introduce new perf_fetch_caller_regs() for hot regs snapshot
perf/x86-64: Use frame pointer to walk on irq and process stacks
lockdep: Move lock events under lockdep recursion protection
perf report: Print the map table just after samples for which no map was found
perf report: Add multiple event support
perf session: Change perf_session post processing functions to take histogram tree
perf session: Add storage for seperating event types in report
perf session: Change add_hist_entry to take the tree root instead of session
perf record: Add ID and to recorded event data when recording multiple events
...
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/Makefile | 6 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 13 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 13 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 112 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 9 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 59 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 7 | ||||
-rw-r--r-- | tools/perf/util/event.h | 9 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 50 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 12 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 2 | ||||
-rw-r--r-- | tools/perf/util/session.c | 1 | ||||
-rw-r--r-- | tools/perf/util/session.h | 1 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 41 | ||||
-rw-r--r-- | tools/perf/util/thread.h | 3 |
18 files changed, 289 insertions, 69 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index bdd3b7ecad0a..bd498d496952 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile | |||
@@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT)) | |||
24 | DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) | 24 | DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) |
25 | DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) | 25 | DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) |
26 | 26 | ||
27 | # Make the path relative to DESTDIR, not prefix | ||
28 | ifndef DESTDIR | ||
27 | prefix?=$(HOME) | 29 | prefix?=$(HOME) |
30 | endif | ||
28 | bindir?=$(prefix)/bin | 31 | bindir?=$(prefix)/bin |
29 | htmldir?=$(prefix)/share/doc/perf-doc | 32 | htmldir?=$(prefix)/share/doc/perf-doc |
30 | pdfdir?=$(prefix)/share/doc/perf-doc | 33 | pdfdir?=$(prefix)/share/doc/perf-doc |
@@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man | |||
32 | man1dir=$(mandir)/man1 | 35 | man1dir=$(mandir)/man1 |
33 | man5dir=$(mandir)/man5 | 36 | man5dir=$(mandir)/man5 |
34 | man7dir=$(mandir)/man7 | 37 | man7dir=$(mandir)/man7 |
35 | # DESTDIR= | ||
36 | 38 | ||
37 | ASCIIDOC=asciidoc | 39 | ASCIIDOC=asciidoc |
38 | ASCIIDOC_EXTRA = --unsafe | 40 | ASCIIDOC_EXTRA = --unsafe |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2d537382c686..8a8f52db7e38 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -216,7 +216,10 @@ STRIP ?= strip | |||
216 | # runtime figures out where they are based on the path to the executable. | 216 | # runtime figures out where they are based on the path to the executable. |
217 | # This can help installing the suite in a relocatable way. | 217 | # This can help installing the suite in a relocatable way. |
218 | 218 | ||
219 | # Make the path relative to DESTDIR, not to prefix | ||
220 | ifndef DESTDIR | ||
219 | prefix = $(HOME) | 221 | prefix = $(HOME) |
222 | endif | ||
220 | bindir_relative = bin | 223 | bindir_relative = bin |
221 | bindir = $(prefix)/$(bindir_relative) | 224 | bindir = $(prefix)/$(bindir_relative) |
222 | mandir = share/man | 225 | mandir = share/man |
@@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc | |||
233 | ETC_PERFCONFIG = etc/perfconfig | 236 | ETC_PERFCONFIG = etc/perfconfig |
234 | endif | 237 | endif |
235 | lib = lib | 238 | lib = lib |
236 | # DESTDIR= | ||
237 | 239 | ||
238 | export prefix bindir sharedir sysconfdir | 240 | export prefix bindir sharedir sysconfdir |
239 | 241 | ||
@@ -387,6 +389,7 @@ LIB_H += util/thread.h | |||
387 | LIB_H += util/trace-event.h | 389 | LIB_H += util/trace-event.h |
388 | LIB_H += util/probe-finder.h | 390 | LIB_H += util/probe-finder.h |
389 | LIB_H += util/probe-event.h | 391 | LIB_H += util/probe-event.h |
392 | LIB_H += util/cpumap.h | ||
390 | 393 | ||
391 | LIB_OBJS += util/abspath.o | 394 | LIB_OBJS += util/abspath.o |
392 | LIB_OBJS += util/alias.o | 395 | LIB_OBJS += util/alias.o |
@@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o | |||
433 | LIB_OBJS += util/hist.o | 436 | LIB_OBJS += util/hist.o |
434 | LIB_OBJS += util/probe-event.o | 437 | LIB_OBJS += util/probe-event.o |
435 | LIB_OBJS += util/util.o | 438 | LIB_OBJS += util/util.o |
439 | LIB_OBJS += util/cpumap.o | ||
436 | 440 | ||
437 | BUILTIN_OBJS += builtin-annotate.o | 441 | BUILTIN_OBJS += builtin-annotate.o |
438 | 442 | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5ec5de995872..6ad7148451c5 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); | 119 | he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit); |
120 | if (he == NULL) | 120 | if (he == NULL) |
121 | return -ENOMEM; | 121 | return -ENOMEM; |
122 | 122 | ||
@@ -564,8 +564,8 @@ static int __cmd_annotate(void) | |||
564 | if (verbose > 2) | 564 | if (verbose > 2) |
565 | dsos__fprintf(stdout); | 565 | dsos__fprintf(stdout); |
566 | 566 | ||
567 | perf_session__collapse_resort(session); | 567 | perf_session__collapse_resort(&session->hists); |
568 | perf_session__output_resort(session, session->event_total[0]); | 568 | perf_session__output_resort(&session->hists, session->event_total[0]); |
569 | perf_session__find_annotations(session); | 569 | perf_session__find_annotations(session); |
570 | out_delete: | 570 | out_delete: |
571 | perf_session__delete(session); | 571 | perf_session__delete(session); |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 18b3f505f9db..1ea15d8aeed1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -26,7 +26,8 @@ static int perf_session__add_hist_entry(struct perf_session *self, | |||
26 | struct addr_location *al, u64 count) | 26 | struct addr_location *al, u64 count) |
27 | { | 27 | { |
28 | bool hit; | 28 | bool hit; |
29 | struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, | 29 | struct hist_entry *he = __perf_session__add_hist_entry(&self->hists, |
30 | al, NULL, | ||
30 | count, &hit); | 31 | count, &hit); |
31 | if (he == NULL) | 32 | if (he == NULL) |
32 | return -ENOMEM; | 33 | return -ENOMEM; |
@@ -114,7 +115,7 @@ static void perf_session__resort_hist_entries(struct perf_session *self) | |||
114 | 115 | ||
115 | static void perf_session__set_hist_entries_positions(struct perf_session *self) | 116 | static void perf_session__set_hist_entries_positions(struct perf_session *self) |
116 | { | 117 | { |
117 | perf_session__output_resort(self, self->events_stats.total); | 118 | perf_session__output_resort(&self->hists, self->events_stats.total); |
118 | perf_session__resort_hist_entries(self); | 119 | perf_session__resort_hist_entries(self); |
119 | } | 120 | } |
120 | 121 | ||
@@ -166,13 +167,15 @@ static int __cmd_diff(void) | |||
166 | goto out_delete; | 167 | goto out_delete; |
167 | } | 168 | } |
168 | 169 | ||
169 | perf_session__output_resort(session[1], session[1]->events_stats.total); | 170 | perf_session__output_resort(&session[1]->hists, |
171 | session[1]->events_stats.total); | ||
170 | if (show_displacement) | 172 | if (show_displacement) |
171 | perf_session__set_hist_entries_positions(session[0]); | 173 | perf_session__set_hist_entries_positions(session[0]); |
172 | 174 | ||
173 | perf_session__match_hists(session[0], session[1]); | 175 | perf_session__match_hists(session[0], session[1]); |
174 | perf_session__fprintf_hists(session[1], session[0], | 176 | perf_session__fprintf_hists(&session[1]->hists, session[0], |
175 | show_displacement, stdout); | 177 | show_displacement, stdout, |
178 | session[1]->events_stats.total); | ||
176 | out_delete: | 179 | out_delete: |
177 | for (i = 0; i < 2; ++i) | 180 | for (i = 0; i < 2; ++i) |
178 | perf_session__delete(session[i]); | 181 | perf_session__delete(session[i]); |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 771533ced6a8..3b8b6387c47c 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "util/debug.h" | 22 | #include "util/debug.h" |
23 | #include "util/session.h" | 23 | #include "util/session.h" |
24 | #include "util/symbol.h" | 24 | #include "util/symbol.h" |
25 | #include "util/cpumap.h" | ||
25 | 26 | ||
26 | #include <unistd.h> | 27 | #include <unistd.h> |
27 | #include <sched.h> | 28 | #include <sched.h> |
@@ -244,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid) | |||
244 | 245 | ||
245 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 246 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
246 | 247 | ||
248 | if (nr_counters > 1) | ||
249 | attr->sample_type |= PERF_SAMPLE_ID; | ||
250 | |||
247 | if (freq) { | 251 | if (freq) { |
248 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 252 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
249 | attr->freq = 1; | 253 | attr->freq = 1; |
@@ -391,6 +395,9 @@ static int process_buildids(void) | |||
391 | { | 395 | { |
392 | u64 size = lseek(output, 0, SEEK_CUR); | 396 | u64 size = lseek(output, 0, SEEK_CUR); |
393 | 397 | ||
398 | if (size == 0) | ||
399 | return 0; | ||
400 | |||
394 | session->fd = output; | 401 | session->fd = output; |
395 | return __perf_session__process_events(session, post_processing_offset, | 402 | return __perf_session__process_events(session, post_processing_offset, |
396 | size - post_processing_offset, | 403 | size - post_processing_offset, |
@@ -418,9 +425,6 @@ static int __cmd_record(int argc, const char **argv) | |||
418 | char buf; | 425 | char buf; |
419 | 426 | ||
420 | page_size = sysconf(_SC_PAGE_SIZE); | 427 | page_size = sysconf(_SC_PAGE_SIZE); |
421 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
422 | assert(nr_cpus <= MAX_NR_CPUS); | ||
423 | assert(nr_cpus >= 0); | ||
424 | 428 | ||
425 | atexit(sig_atexit); | 429 | atexit(sig_atexit); |
426 | signal(SIGCHLD, sig_handler); | 430 | signal(SIGCHLD, sig_handler); |
@@ -544,8 +548,9 @@ static int __cmd_record(int argc, const char **argv) | |||
544 | if ((!system_wide && !inherit) || profile_cpu != -1) { | 548 | if ((!system_wide && !inherit) || profile_cpu != -1) { |
545 | open_counters(profile_cpu, target_pid); | 549 | open_counters(profile_cpu, target_pid); |
546 | } else { | 550 | } else { |
551 | nr_cpus = read_cpu_map(); | ||
547 | for (i = 0; i < nr_cpus; i++) | 552 | for (i = 0; i < nr_cpus; i++) |
548 | open_counters(i, target_pid); | 553 | open_counters(cpumap[i], target_pid); |
549 | } | 554 | } |
550 | 555 | ||
551 | if (file_new) { | 556 | if (file_new) { |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cfc655d40bb7..f815de25d0fc 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -45,28 +45,71 @@ static char *pretty_printing_style = default_pretty_printing_style; | |||
45 | 45 | ||
46 | static char callchain_default_opt[] = "fractal,0.5"; | 46 | static char callchain_default_opt[] = "fractal,0.5"; |
47 | 47 | ||
48 | static struct event_stat_id *get_stats(struct perf_session *self, | ||
49 | u64 event_stream, u32 type, u64 config) | ||
50 | { | ||
51 | struct rb_node **p = &self->stats_by_id.rb_node; | ||
52 | struct rb_node *parent = NULL; | ||
53 | struct event_stat_id *iter, *new; | ||
54 | |||
55 | while (*p != NULL) { | ||
56 | parent = *p; | ||
57 | iter = rb_entry(parent, struct event_stat_id, rb_node); | ||
58 | if (iter->config == config) | ||
59 | return iter; | ||
60 | |||
61 | |||
62 | if (config > iter->config) | ||
63 | p = &(*p)->rb_right; | ||
64 | else | ||
65 | p = &(*p)->rb_left; | ||
66 | } | ||
67 | |||
68 | new = malloc(sizeof(struct event_stat_id)); | ||
69 | if (new == NULL) | ||
70 | return NULL; | ||
71 | memset(new, 0, sizeof(struct event_stat_id)); | ||
72 | new->event_stream = event_stream; | ||
73 | new->config = config; | ||
74 | new->type = type; | ||
75 | rb_link_node(&new->rb_node, parent, p); | ||
76 | rb_insert_color(&new->rb_node, &self->stats_by_id); | ||
77 | return new; | ||
78 | } | ||
79 | |||
48 | static int perf_session__add_hist_entry(struct perf_session *self, | 80 | static int perf_session__add_hist_entry(struct perf_session *self, |
49 | struct addr_location *al, | 81 | struct addr_location *al, |
50 | struct ip_callchain *chain, u64 count) | 82 | struct sample_data *data) |
51 | { | 83 | { |
52 | struct symbol **syms = NULL, *parent = NULL; | 84 | struct symbol **syms = NULL, *parent = NULL; |
53 | bool hit; | 85 | bool hit; |
54 | struct hist_entry *he; | 86 | struct hist_entry *he; |
87 | struct event_stat_id *stats; | ||
88 | struct perf_event_attr *attr; | ||
55 | 89 | ||
56 | if ((sort__has_parent || symbol_conf.use_callchain) && chain) | 90 | if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) |
57 | syms = perf_session__resolve_callchain(self, al->thread, | 91 | syms = perf_session__resolve_callchain(self, al->thread, |
58 | chain, &parent); | 92 | data->callchain, &parent); |
59 | he = __perf_session__add_hist_entry(self, al, parent, count, &hit); | 93 | |
94 | attr = perf_header__find_attr(data->id, &self->header); | ||
95 | if (attr) | ||
96 | stats = get_stats(self, data->id, attr->type, attr->config); | ||
97 | else | ||
98 | stats = get_stats(self, data->id, 0, 0); | ||
99 | if (stats == NULL) | ||
100 | return -ENOMEM; | ||
101 | he = __perf_session__add_hist_entry(&stats->hists, al, parent, | ||
102 | data->period, &hit); | ||
60 | if (he == NULL) | 103 | if (he == NULL) |
61 | return -ENOMEM; | 104 | return -ENOMEM; |
62 | 105 | ||
63 | if (hit) | 106 | if (hit) |
64 | he->count += count; | 107 | he->count += data->period; |
65 | 108 | ||
66 | if (symbol_conf.use_callchain) { | 109 | if (symbol_conf.use_callchain) { |
67 | if (!hit) | 110 | if (!hit) |
68 | callchain_init(&he->callchain); | 111 | callchain_init(&he->callchain); |
69 | append_chain(&he->callchain, chain, syms); | 112 | append_chain(&he->callchain, data->callchain, syms); |
70 | free(syms); | 113 | free(syms); |
71 | } | 114 | } |
72 | 115 | ||
@@ -86,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
86 | return 0; | 129 | return 0; |
87 | } | 130 | } |
88 | 131 | ||
132 | static int add_event_total(struct perf_session *session, | ||
133 | struct sample_data *data, | ||
134 | struct perf_event_attr *attr) | ||
135 | { | ||
136 | struct event_stat_id *stats; | ||
137 | |||
138 | if (attr) | ||
139 | stats = get_stats(session, data->id, attr->type, attr->config); | ||
140 | else | ||
141 | stats = get_stats(session, data->id, 0, 0); | ||
142 | |||
143 | if (!stats) | ||
144 | return -ENOMEM; | ||
145 | |||
146 | stats->stats.total += data->period; | ||
147 | session->events_stats.total += data->period; | ||
148 | return 0; | ||
149 | } | ||
150 | |||
89 | static int process_sample_event(event_t *event, struct perf_session *session) | 151 | static int process_sample_event(event_t *event, struct perf_session *session) |
90 | { | 152 | { |
91 | struct sample_data data = { .period = 1, }; | 153 | struct sample_data data = { .period = 1, }; |
92 | struct addr_location al; | 154 | struct addr_location al; |
155 | struct perf_event_attr *attr; | ||
93 | 156 | ||
94 | event__parse_sample(event, session->sample_type, &data); | 157 | event__parse_sample(event, session->sample_type, &data); |
95 | 158 | ||
@@ -123,12 +186,18 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
123 | if (al.filtered || (hide_unresolved && al.sym == NULL)) | 186 | if (al.filtered || (hide_unresolved && al.sym == NULL)) |
124 | return 0; | 187 | return 0; |
125 | 188 | ||
126 | if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { | 189 | if (perf_session__add_hist_entry(session, &al, &data)) { |
127 | pr_debug("problem incrementing symbol count, skipping event\n"); | 190 | pr_debug("problem incrementing symbol count, skipping event\n"); |
128 | return -1; | 191 | return -1; |
129 | } | 192 | } |
130 | 193 | ||
131 | session->events_stats.total += data.period; | 194 | attr = perf_header__find_attr(data.id, &session->header); |
195 | |||
196 | if (add_event_total(session, &data, attr)) { | ||
197 | pr_debug("problem adding event count\n"); | ||
198 | return -1; | ||
199 | } | ||
200 | |||
132 | return 0; | 201 | return 0; |
133 | } | 202 | } |
134 | 203 | ||
@@ -197,6 +266,7 @@ static int __cmd_report(void) | |||
197 | { | 266 | { |
198 | int ret = -EINVAL; | 267 | int ret = -EINVAL; |
199 | struct perf_session *session; | 268 | struct perf_session *session; |
269 | struct rb_node *next; | ||
200 | 270 | ||
201 | session = perf_session__new(input_name, O_RDONLY, force); | 271 | session = perf_session__new(input_name, O_RDONLY, force); |
202 | if (session == NULL) | 272 | if (session == NULL) |
@@ -224,10 +294,28 @@ static int __cmd_report(void) | |||
224 | if (verbose > 2) | 294 | if (verbose > 2) |
225 | dsos__fprintf(stdout); | 295 | dsos__fprintf(stdout); |
226 | 296 | ||
227 | perf_session__collapse_resort(session); | 297 | next = rb_first(&session->stats_by_id); |
228 | perf_session__output_resort(session, session->events_stats.total); | 298 | while (next) { |
229 | fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); | 299 | struct event_stat_id *stats; |
230 | perf_session__fprintf_hists(session, NULL, false, stdout); | 300 | |
301 | stats = rb_entry(next, struct event_stat_id, rb_node); | ||
302 | perf_session__collapse_resort(&stats->hists); | ||
303 | perf_session__output_resort(&stats->hists, stats->stats.total); | ||
304 | if (rb_first(&session->stats_by_id) == | ||
305 | rb_last(&session->stats_by_id)) | ||
306 | fprintf(stdout, "# Samples: %Ld\n#\n", | ||
307 | stats->stats.total); | ||
308 | else | ||
309 | fprintf(stdout, "# Samples: %Ld %s\n#\n", | ||
310 | stats->stats.total, | ||
311 | __event_name(stats->type, stats->config)); | ||
312 | |||
313 | perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, | ||
314 | stats->stats.total); | ||
315 | fprintf(stdout, "\n\n"); | ||
316 | next = rb_next(&stats->rb_node); | ||
317 | } | ||
318 | |||
231 | if (sort_order == default_sort_order && | 319 | if (sort_order == default_sort_order && |
232 | parent_pattern == default_parent_pattern) | 320 | parent_pattern == default_parent_pattern) |
233 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); | 321 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8c85d5aec41..95db31cff6fd 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include "util/event.h" | 45 | #include "util/event.h" |
46 | #include "util/debug.h" | 46 | #include "util/debug.h" |
47 | #include "util/header.h" | 47 | #include "util/header.h" |
48 | #include "util/cpumap.h" | ||
48 | 49 | ||
49 | #include <sys/prctl.h> | 50 | #include <sys/prctl.h> |
50 | #include <math.h> | 51 | #include <math.h> |
@@ -151,7 +152,7 @@ static void create_perf_stat_counter(int counter, int pid) | |||
151 | unsigned int cpu; | 152 | unsigned int cpu; |
152 | 153 | ||
153 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 154 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
154 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); | 155 | fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0); |
155 | if (fd[cpu][counter] < 0 && verbose) | 156 | if (fd[cpu][counter] < 0 && verbose) |
156 | fprintf(stderr, ERR_PERF_OPEN, counter, | 157 | fprintf(stderr, ERR_PERF_OPEN, counter, |
157 | fd[cpu][counter], strerror(errno)); | 158 | fd[cpu][counter], strerror(errno)); |
@@ -519,9 +520,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
519 | nr_counters = ARRAY_SIZE(default_attrs); | 520 | nr_counters = ARRAY_SIZE(default_attrs); |
520 | } | 521 | } |
521 | 522 | ||
522 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | 523 | if (system_wide) |
523 | assert(nr_cpus <= MAX_NR_CPUS); | 524 | nr_cpus = read_cpu_map(); |
524 | assert((int)nr_cpus >= 0); | 525 | else |
526 | nr_cpus = 1; | ||
525 | 527 | ||
526 | /* | 528 | /* |
527 | * We dont want to block the signals - that would cause | 529 | * We dont want to block the signals - that would cause |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31f2e597800c..0b719e3dde05 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/rbtree.h> | 28 | #include <linux/rbtree.h> |
29 | #include "util/parse-options.h" | 29 | #include "util/parse-options.h" |
30 | #include "util/parse-events.h" | 30 | #include "util/parse-events.h" |
31 | #include "util/cpumap.h" | ||
31 | 32 | ||
32 | #include "util/debug.h" | 33 | #include "util/debug.h" |
33 | 34 | ||
@@ -1123,7 +1124,7 @@ static void start_counter(int i, int counter) | |||
1123 | 1124 | ||
1124 | cpu = profile_cpu; | 1125 | cpu = profile_cpu; |
1125 | if (target_pid == -1 && profile_cpu == -1) | 1126 | if (target_pid == -1 && profile_cpu == -1) |
1126 | cpu = i; | 1127 | cpu = cpumap[i]; |
1127 | 1128 | ||
1128 | attr = attrs + counter; | 1129 | attr = attrs + counter; |
1129 | 1130 | ||
@@ -1347,12 +1348,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1347 | attrs[counter].sample_period = default_interval; | 1348 | attrs[counter].sample_period = default_interval; |
1348 | } | 1349 | } |
1349 | 1350 | ||
1350 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
1351 | assert(nr_cpus <= MAX_NR_CPUS); | ||
1352 | assert(nr_cpus >= 0); | ||
1353 | |||
1354 | if (target_pid != -1 || profile_cpu != -1) | 1351 | if (target_pid != -1 || profile_cpu != -1) |
1355 | nr_cpus = 1; | 1352 | nr_cpus = 1; |
1353 | else | ||
1354 | nr_cpus = read_cpu_map(); | ||
1356 | 1355 | ||
1357 | get_term_dimensions(&winsize); | 1356 | get_term_dimensions(&winsize); |
1358 | if (print_entries == 0) { | 1357 | if (print_entries == 0) { |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c new file mode 100644 index 000000000000..4e01490e51e5 --- /dev/null +++ b/tools/perf/util/cpumap.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include "util.h" | ||
2 | #include "../perf.h" | ||
3 | #include "cpumap.h" | ||
4 | #include <assert.h> | ||
5 | #include <stdio.h> | ||
6 | |||
7 | int cpumap[MAX_NR_CPUS]; | ||
8 | |||
9 | static int default_cpu_map(void) | ||
10 | { | ||
11 | int nr_cpus, i; | ||
12 | |||
13 | nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); | ||
14 | assert(nr_cpus <= MAX_NR_CPUS); | ||
15 | assert((int)nr_cpus >= 0); | ||
16 | |||
17 | for (i = 0; i < nr_cpus; ++i) | ||
18 | cpumap[i] = i; | ||
19 | |||
20 | return nr_cpus; | ||
21 | } | ||
22 | |||
23 | int read_cpu_map(void) | ||
24 | { | ||
25 | FILE *onlnf; | ||
26 | int nr_cpus = 0; | ||
27 | int n, cpu, prev; | ||
28 | char sep; | ||
29 | |||
30 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
31 | if (!onlnf) | ||
32 | return default_cpu_map(); | ||
33 | |||
34 | sep = 0; | ||
35 | prev = -1; | ||
36 | for (;;) { | ||
37 | n = fscanf(onlnf, "%u%c", &cpu, &sep); | ||
38 | if (n <= 0) | ||
39 | break; | ||
40 | if (prev >= 0) { | ||
41 | assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); | ||
42 | while (++prev < cpu) | ||
43 | cpumap[nr_cpus++] = prev; | ||
44 | } | ||
45 | assert (nr_cpus < MAX_NR_CPUS); | ||
46 | cpumap[nr_cpus++] = cpu; | ||
47 | if (n == 2 && sep == '-') | ||
48 | prev = cpu; | ||
49 | else | ||
50 | prev = -1; | ||
51 | if (n == 1 || sep == '\n') | ||
52 | break; | ||
53 | } | ||
54 | fclose(onlnf); | ||
55 | if (nr_cpus > 0) | ||
56 | return nr_cpus; | ||
57 | |||
58 | return default_cpu_map(); | ||
59 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h new file mode 100644 index 000000000000..86c78bb33098 --- /dev/null +++ b/tools/perf/util/cpumap.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef __PERF_CPUMAP_H | ||
2 | #define __PERF_CPUMAP_H | ||
3 | |||
4 | extern int read_cpu_map(void); | ||
5 | extern int cpumap[]; | ||
6 | |||
7 | #endif /* __PERF_CPUMAP_H */ | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 50a7132887f5..a33b94952e34 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -99,6 +99,15 @@ struct events_stats { | |||
99 | u64 lost; | 99 | u64 lost; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct event_stat_id { | ||
103 | struct rb_node rb_node; | ||
104 | struct rb_root hists; | ||
105 | struct events_stats stats; | ||
106 | u64 config; | ||
107 | u64 event_stream; | ||
108 | u32 type; | ||
109 | }; | ||
110 | |||
102 | void event__print_totals(void); | 111 | void event__print_totals(void); |
103 | 112 | ||
104 | struct perf_session; | 113 | struct perf_session; |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 44408c2621cf..2be33c7dbf03 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -12,12 +12,12 @@ struct callchain_param callchain_param = { | |||
12 | * histogram, sorted on item, collects counts | 12 | * histogram, sorted on item, collects counts |
13 | */ | 13 | */ |
14 | 14 | ||
15 | struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | 15 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, |
16 | struct addr_location *al, | 16 | struct addr_location *al, |
17 | struct symbol *sym_parent, | 17 | struct symbol *sym_parent, |
18 | u64 count, bool *hit) | 18 | u64 count, bool *hit) |
19 | { | 19 | { |
20 | struct rb_node **p = &self->hists.rb_node; | 20 | struct rb_node **p = &hists->rb_node; |
21 | struct rb_node *parent = NULL; | 21 | struct rb_node *parent = NULL; |
22 | struct hist_entry *he; | 22 | struct hist_entry *he; |
23 | struct hist_entry entry = { | 23 | struct hist_entry entry = { |
@@ -53,7 +53,7 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | |||
53 | return NULL; | 53 | return NULL; |
54 | *he = entry; | 54 | *he = entry; |
55 | rb_link_node(&he->rb_node, parent, p); | 55 | rb_link_node(&he->rb_node, parent, p); |
56 | rb_insert_color(&he->rb_node, &self->hists); | 56 | rb_insert_color(&he->rb_node, hists); |
57 | *hit = false; | 57 | *hit = false; |
58 | return he; | 58 | return he; |
59 | } | 59 | } |
@@ -130,7 +130,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he) | |||
130 | rb_insert_color(&he->rb_node, root); | 130 | rb_insert_color(&he->rb_node, root); |
131 | } | 131 | } |
132 | 132 | ||
133 | void perf_session__collapse_resort(struct perf_session *self) | 133 | void perf_session__collapse_resort(struct rb_root *hists) |
134 | { | 134 | { |
135 | struct rb_root tmp; | 135 | struct rb_root tmp; |
136 | struct rb_node *next; | 136 | struct rb_node *next; |
@@ -140,17 +140,17 @@ void perf_session__collapse_resort(struct perf_session *self) | |||
140 | return; | 140 | return; |
141 | 141 | ||
142 | tmp = RB_ROOT; | 142 | tmp = RB_ROOT; |
143 | next = rb_first(&self->hists); | 143 | next = rb_first(hists); |
144 | 144 | ||
145 | while (next) { | 145 | while (next) { |
146 | n = rb_entry(next, struct hist_entry, rb_node); | 146 | n = rb_entry(next, struct hist_entry, rb_node); |
147 | next = rb_next(&n->rb_node); | 147 | next = rb_next(&n->rb_node); |
148 | 148 | ||
149 | rb_erase(&n->rb_node, &self->hists); | 149 | rb_erase(&n->rb_node, hists); |
150 | collapse__insert_entry(&tmp, n); | 150 | collapse__insert_entry(&tmp, n); |
151 | } | 151 | } |
152 | 152 | ||
153 | self->hists = tmp; | 153 | *hists = tmp; |
154 | } | 154 | } |
155 | 155 | ||
156 | /* | 156 | /* |
@@ -183,7 +183,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root, | |||
183 | rb_insert_color(&he->rb_node, root); | 183 | rb_insert_color(&he->rb_node, root); |
184 | } | 184 | } |
185 | 185 | ||
186 | void perf_session__output_resort(struct perf_session *self, u64 total_samples) | 186 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples) |
187 | { | 187 | { |
188 | struct rb_root tmp; | 188 | struct rb_root tmp; |
189 | struct rb_node *next; | 189 | struct rb_node *next; |
@@ -194,18 +194,18 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples) | |||
194 | total_samples * (callchain_param.min_percent / 100); | 194 | total_samples * (callchain_param.min_percent / 100); |
195 | 195 | ||
196 | tmp = RB_ROOT; | 196 | tmp = RB_ROOT; |
197 | next = rb_first(&self->hists); | 197 | next = rb_first(hists); |
198 | 198 | ||
199 | while (next) { | 199 | while (next) { |
200 | n = rb_entry(next, struct hist_entry, rb_node); | 200 | n = rb_entry(next, struct hist_entry, rb_node); |
201 | next = rb_next(&n->rb_node); | 201 | next = rb_next(&n->rb_node); |
202 | 202 | ||
203 | rb_erase(&n->rb_node, &self->hists); | 203 | rb_erase(&n->rb_node, hists); |
204 | perf_session__insert_output_hist_entry(&tmp, n, | 204 | perf_session__insert_output_hist_entry(&tmp, n, |
205 | min_callchain_hits); | 205 | min_callchain_hits); |
206 | } | 206 | } |
207 | 207 | ||
208 | self->hists = tmp; | 208 | *hists = tmp; |
209 | } | 209 | } |
210 | 210 | ||
211 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 211 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
@@ -456,10 +456,10 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
456 | } | 456 | } |
457 | 457 | ||
458 | static size_t hist_entry__fprintf(struct hist_entry *self, | 458 | static size_t hist_entry__fprintf(struct hist_entry *self, |
459 | struct perf_session *session, | ||
460 | struct perf_session *pair_session, | 459 | struct perf_session *pair_session, |
461 | bool show_displacement, | 460 | bool show_displacement, |
462 | long displacement, FILE *fp) | 461 | long displacement, FILE *fp, |
462 | u64 session_total) | ||
463 | { | 463 | { |
464 | struct sort_entry *se; | 464 | struct sort_entry *se; |
465 | u64 count, total; | 465 | u64 count, total; |
@@ -474,7 +474,7 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
474 | total = pair_session->events_stats.total; | 474 | total = pair_session->events_stats.total; |
475 | } else { | 475 | } else { |
476 | count = self->count; | 476 | count = self->count; |
477 | total = session->events_stats.total; | 477 | total = session_total; |
478 | } | 478 | } |
479 | 479 | ||
480 | if (total) | 480 | if (total) |
@@ -496,8 +496,8 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
496 | 496 | ||
497 | if (total > 0) | 497 | if (total > 0) |
498 | old_percent = (count * 100.0) / total; | 498 | old_percent = (count * 100.0) / total; |
499 | if (session->events_stats.total > 0) | 499 | if (session_total > 0) |
500 | new_percent = (self->count * 100.0) / session->events_stats.total; | 500 | new_percent = (self->count * 100.0) / session_total; |
501 | 501 | ||
502 | diff = new_percent - old_percent; | 502 | diff = new_percent - old_percent; |
503 | 503 | ||
@@ -544,16 +544,17 @@ static size_t hist_entry__fprintf(struct hist_entry *self, | |||
544 | left_margin -= thread__comm_len(self->thread); | 544 | left_margin -= thread__comm_len(self->thread); |
545 | } | 545 | } |
546 | 546 | ||
547 | hist_entry_callchain__fprintf(fp, self, session->events_stats.total, | 547 | hist_entry_callchain__fprintf(fp, self, session_total, |
548 | left_margin); | 548 | left_margin); |
549 | } | 549 | } |
550 | 550 | ||
551 | return ret; | 551 | return ret; |
552 | } | 552 | } |
553 | 553 | ||
554 | size_t perf_session__fprintf_hists(struct perf_session *self, | 554 | size_t perf_session__fprintf_hists(struct rb_root *hists, |
555 | struct perf_session *pair, | 555 | struct perf_session *pair, |
556 | bool show_displacement, FILE *fp) | 556 | bool show_displacement, FILE *fp, |
557 | u64 session_total) | ||
557 | { | 558 | { |
558 | struct sort_entry *se; | 559 | struct sort_entry *se; |
559 | struct rb_node *nd; | 560 | struct rb_node *nd; |
@@ -641,7 +642,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self, | |||
641 | fprintf(fp, "\n#\n"); | 642 | fprintf(fp, "\n#\n"); |
642 | 643 | ||
643 | print_entries: | 644 | print_entries: |
644 | for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { | 645 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { |
645 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 646 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
646 | 647 | ||
647 | if (show_displacement) { | 648 | if (show_displacement) { |
@@ -652,8 +653,13 @@ print_entries: | |||
652 | displacement = 0; | 653 | displacement = 0; |
653 | ++position; | 654 | ++position; |
654 | } | 655 | } |
655 | ret += hist_entry__fprintf(h, self, pair, show_displacement, | 656 | ret += hist_entry__fprintf(h, pair, show_displacement, |
656 | displacement, fp); | 657 | displacement, fp, session_total); |
658 | if (h->map == NULL && verbose > 1) { | ||
659 | __map_groups__fprintf_maps(&h->thread->mg, | ||
660 | MAP__FUNCTION, fp); | ||
661 | fprintf(fp, "%.10s end\n", graph_dotted_line); | ||
662 | } | ||
657 | } | 663 | } |
658 | 664 | ||
659 | free(rem_sq_bracket); | 665 | free(rem_sq_bracket); |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e5f99b24048b..16f360cce5bf 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -10,8 +10,9 @@ struct perf_session; | |||
10 | struct hist_entry; | 10 | struct hist_entry; |
11 | struct addr_location; | 11 | struct addr_location; |
12 | struct symbol; | 12 | struct symbol; |
13 | struct rb_root; | ||
13 | 14 | ||
14 | struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, | 15 | struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, |
15 | struct addr_location *al, | 16 | struct addr_location *al, |
16 | struct symbol *parent, | 17 | struct symbol *parent, |
17 | u64 count, bool *hit); | 18 | u64 count, bool *hit); |
@@ -19,9 +20,10 @@ extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | |||
19 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
20 | void hist_entry__free(struct hist_entry *); | 21 | void hist_entry__free(struct hist_entry *); |
21 | 22 | ||
22 | void perf_session__output_resort(struct perf_session *self, u64 total_samples); | 23 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples); |
23 | void perf_session__collapse_resort(struct perf_session *self); | 24 | void perf_session__collapse_resort(struct rb_root *hists); |
24 | size_t perf_session__fprintf_hists(struct perf_session *self, | 25 | size_t perf_session__fprintf_hists(struct rb_root *hists, |
25 | struct perf_session *pair, | 26 | struct perf_session *pair, |
26 | bool show_displacement, FILE *fp); | 27 | bool show_displacement, FILE *fp, |
28 | u64 session_total); | ||
27 | #endif /* __PERF_HIST_H */ | 29 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e77dc886760e..1e6c65ebbd80 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -169,7 +169,7 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | |||
169 | { | 169 | { |
170 | Dwarf_Files *files; | 170 | Dwarf_Files *files; |
171 | size_t nfiles, i; | 171 | size_t nfiles, i; |
172 | const char *src; | 172 | const char *src = NULL; |
173 | int ret; | 173 | int ret; |
174 | 174 | ||
175 | if (!fname) | 175 | if (!fname) |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0de7258e70a5..eed1cb889008 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -70,6 +70,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc | |||
70 | 70 | ||
71 | memcpy(self->filename, filename, len); | 71 | memcpy(self->filename, filename, len); |
72 | self->threads = RB_ROOT; | 72 | self->threads = RB_ROOT; |
73 | self->stats_by_id = RB_ROOT; | ||
73 | self->last_match = NULL; | 74 | self->last_match = NULL; |
74 | self->mmap_window = 32; | 75 | self->mmap_window = 32; |
75 | self->cwd = NULL; | 76 | self->cwd = NULL; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 31950fcd8a4d..5c33417eebb3 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -20,6 +20,7 @@ struct perf_session { | |||
20 | struct thread *last_match; | 20 | struct thread *last_match; |
21 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 21 | struct map *vmlinux_maps[MAP__NR_TYPES]; |
22 | struct events_stats events_stats; | 22 | struct events_stats events_stats; |
23 | struct rb_root stats_by_id; | ||
23 | unsigned long event_total[PERF_RECORD_MAX]; | 24 | unsigned long event_total[PERF_RECORD_MAX]; |
24 | unsigned long unknown_events; | 25 | unsigned long unknown_events; |
25 | struct rb_root hists; | 26 | struct rb_root hists; |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 21b92162282b..fa968312ee7d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -79,8 +79,8 @@ int thread__comm_len(struct thread *self) | |||
79 | return self->comm_len; | 79 | return self->comm_len; |
80 | } | 80 | } |
81 | 81 | ||
82 | static size_t __map_groups__fprintf_maps(struct map_groups *self, | 82 | size_t __map_groups__fprintf_maps(struct map_groups *self, |
83 | enum map_type type, FILE *fp) | 83 | enum map_type type, FILE *fp) |
84 | { | 84 | { |
85 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | 85 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); |
86 | struct rb_node *nd; | 86 | struct rb_node *nd; |
@@ -89,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self, | |||
89 | struct map *pos = rb_entry(nd, struct map, rb_node); | 89 | struct map *pos = rb_entry(nd, struct map, rb_node); |
90 | printed += fprintf(fp, "Map:"); | 90 | printed += fprintf(fp, "Map:"); |
91 | printed += map__fprintf(pos, fp); | 91 | printed += map__fprintf(pos, fp); |
92 | if (verbose > 1) { | 92 | if (verbose > 2) { |
93 | printed += dso__fprintf(pos->dso, type, fp); | 93 | printed += dso__fprintf(pos->dso, type, fp); |
94 | printed += fprintf(fp, "--\n"); | 94 | printed += fprintf(fp, "--\n"); |
95 | } | 95 | } |
@@ -183,8 +183,8 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | |||
183 | return th; | 183 | return th; |
184 | } | 184 | } |
185 | 185 | ||
186 | static void map_groups__remove_overlappings(struct map_groups *self, | 186 | static int map_groups__fixup_overlappings(struct map_groups *self, |
187 | struct map *map) | 187 | struct map *map) |
188 | { | 188 | { |
189 | struct rb_root *root = &self->maps[map->type]; | 189 | struct rb_root *root = &self->maps[map->type]; |
190 | struct rb_node *next = rb_first(root); | 190 | struct rb_node *next = rb_first(root); |
@@ -209,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self, | |||
209 | * list. | 209 | * list. |
210 | */ | 210 | */ |
211 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | 211 | list_add_tail(&pos->node, &self->removed_maps[map->type]); |
212 | /* | ||
213 | * Now check if we need to create new maps for areas not | ||
214 | * overlapped by the new map: | ||
215 | */ | ||
216 | if (map->start > pos->start) { | ||
217 | struct map *before = map__clone(pos); | ||
218 | |||
219 | if (before == NULL) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | before->end = map->start - 1; | ||
223 | map_groups__insert(self, before); | ||
224 | if (verbose >= 2) | ||
225 | map__fprintf(before, stderr); | ||
226 | } | ||
227 | |||
228 | if (map->end < pos->end) { | ||
229 | struct map *after = map__clone(pos); | ||
230 | |||
231 | if (after == NULL) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | after->start = map->end + 1; | ||
235 | map_groups__insert(self, after); | ||
236 | if (verbose >= 2) | ||
237 | map__fprintf(after, stderr); | ||
238 | } | ||
212 | } | 239 | } |
240 | |||
241 | return 0; | ||
213 | } | 242 | } |
214 | 243 | ||
215 | void maps__insert(struct rb_root *maps, struct map *map) | 244 | void maps__insert(struct rb_root *maps, struct map *map) |
@@ -254,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
254 | 283 | ||
255 | void thread__insert_map(struct thread *self, struct map *map) | 284 | void thread__insert_map(struct thread *self, struct map *map) |
256 | { | 285 | { |
257 | map_groups__remove_overlappings(&self->mg, map); | 286 | map_groups__fixup_overlappings(&self->mg, map); |
258 | map_groups__insert(&self->mg, map); | 287 | map_groups__insert(&self->mg, map); |
259 | } | 288 | } |
260 | 289 | ||
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 0a28f39de545..dcf70303e58e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -10,6 +10,9 @@ struct map_groups { | |||
10 | struct list_head removed_maps[MAP__NR_TYPES]; | 10 | struct list_head removed_maps[MAP__NR_TYPES]; |
11 | }; | 11 | }; |
12 | 12 | ||
13 | size_t __map_groups__fprintf_maps(struct map_groups *self, | ||
14 | enum map_type type, FILE *fp); | ||
15 | |||
13 | struct thread { | 16 | struct thread { |
14 | struct rb_node rb_node; | 17 | struct rb_node rb_node; |
15 | struct map_groups mg; | 18 | struct map_groups mg; |