aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/Makefile4
-rw-r--r--tools/perf/Documentation/perf-lock.txt29
-rw-r--r--tools/perf/Makefile16
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-diff.c13
-rw-r--r--tools/perf/builtin-lock.c148
-rw-r--r--tools/perf/builtin-probe.c1
-rw-r--r--tools/perf/builtin-record.c13
-rw-r--r--tools/perf/builtin-report.c112
-rw-r--r--tools/perf/builtin-stat.c10
-rw-r--r--tools/perf/builtin-top.c22
-rw-r--r--tools/perf/builtin-trace.c4
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf-archive.sh3
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/util/cpumap.c59
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/hist.c50
-rw-r--r--tools/perf/util/hist.h12
-rw-r--r--tools/perf/util/probe-event.c4
-rw-r--r--tools/perf/util/probe-finder.c20
-rw-r--r--tools/perf/util/probe-finder.h1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c17
-rw-r--r--tools/perf/util/session.c1
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/symbol.c18
-rw-r--r--tools/perf/util/symbol.h3
-rw-r--r--tools/perf/util/thread.c41
-rw-r--r--tools/perf/util/thread.h3
30 files changed, 520 insertions, 112 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))
24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) 24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) 25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
26 26
27# Make the path relative to DESTDIR, not prefix
28ifndef DESTDIR
27prefix?=$(HOME) 29prefix?=$(HOME)
30endif
28bindir?=$(prefix)/bin 31bindir?=$(prefix)/bin
29htmldir?=$(prefix)/share/doc/perf-doc 32htmldir?=$(prefix)/share/doc/perf-doc
30pdfdir?=$(prefix)/share/doc/perf-doc 33pdfdir?=$(prefix)/share/doc/perf-doc
@@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man
32man1dir=$(mandir)/man1 35man1dir=$(mandir)/man1
33man5dir=$(mandir)/man5 36man5dir=$(mandir)/man5
34man7dir=$(mandir)/man7 37man7dir=$(mandir)/man7
35# DESTDIR=
36 38
37ASCIIDOC=asciidoc 39ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = --unsafe 40ASCIIDOC_EXTRA = --unsafe
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
new file mode 100644
index 000000000000..b317102138c8
--- /dev/null
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -0,0 +1,29 @@
1perf-lock(1)
2============
3
4NAME
5----
6perf-lock - Analyze lock events
7
8SYNOPSIS
9--------
10[verse]
11'perf lock' {record|report|trace}
12
13DESCRIPTION
14-----------
15You can analyze various lock behaviours
16and statistics with this 'perf lock' command.
17
18 'perf lock record <command>' records lock events
19 between start and end <command>. And this command
20 produces the file "perf.data" which contains tracing
21 results of lock events.
22
23 'perf lock trace' shows raw lock events.
24
25 'perf lock report' reports statistical data.
26
27SEE ALSO
28--------
29linkperf:perf[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2d537382c686..bc0f670a8338 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -200,7 +200,7 @@ endif
200 200
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm 202EXTLIBS = -lpthread -lrt -lelf -lm
203ALL_CFLAGS = $(CFLAGS) 203ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
204ALL_LDFLAGS = $(LDFLAGS) 204ALL_LDFLAGS = $(LDFLAGS)
205STRIP ?= strip 205STRIP ?= strip
206 206
@@ -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
220ifndef DESTDIR
219prefix = $(HOME) 221prefix = $(HOME)
222endif
220bindir_relative = bin 223bindir_relative = bin
221bindir = $(prefix)/$(bindir_relative) 224bindir = $(prefix)/$(bindir_relative)
222mandir = share/man 225mandir = share/man
@@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc
233ETC_PERFCONFIG = etc/perfconfig 236ETC_PERFCONFIG = etc/perfconfig
234endif 237endif
235lib = lib 238lib = lib
236# DESTDIR=
237 239
238export prefix bindir sharedir sysconfdir 240export prefix bindir sharedir sysconfdir
239 241
@@ -387,6 +389,7 @@ LIB_H += util/thread.h
387LIB_H += util/trace-event.h 389LIB_H += util/trace-event.h
388LIB_H += util/probe-finder.h 390LIB_H += util/probe-finder.h
389LIB_H += util/probe-event.h 391LIB_H += util/probe-event.h
392LIB_H += util/cpumap.h
390 393
391LIB_OBJS += util/abspath.o 394LIB_OBJS += util/abspath.o
392LIB_OBJS += util/alias.o 395LIB_OBJS += util/alias.o
@@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o
433LIB_OBJS += util/hist.o 436LIB_OBJS += util/hist.o
434LIB_OBJS += util/probe-event.o 437LIB_OBJS += util/probe-event.o
435LIB_OBJS += util/util.o 438LIB_OBJS += util/util.o
439LIB_OBJS += util/cpumap.o
436 440
437BUILTIN_OBJS += builtin-annotate.o 441BUILTIN_OBJS += builtin-annotate.o
438 442
@@ -488,19 +492,19 @@ ifeq ($(uname_S),Darwin)
488 PTHREAD_LIBS = 492 PTHREAD_LIBS =
489endif 493endif
490 494
491ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 495ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
492ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 496ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
493 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 497 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
494endif 498endif
495 499
496 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 500 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
497 BASIC_CFLAGS += -DLIBELF_NO_MMAP 501 BASIC_CFLAGS += -DLIBELF_NO_MMAP
498 endif 502 endif
499else 503else
500 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 504 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
501endif 505endif
502 506
503ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 507ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
504 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev); 508 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
505 BASIC_CFLAGS += -DNO_DWARF_SUPPORT 509 BASIC_CFLAGS += -DNO_DWARF_SUPPORT
506else 510else
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);
570out_delete: 570out_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
115static void perf_session__set_hist_entries_positions(struct perf_session *self) 116static 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);
176out_delete: 179out_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-lock.c b/tools/perf/builtin-lock.c
index fb9ab2ad3f92..e12c844df1e2 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -460,6 +460,150 @@ process_raw_event(void *data, int cpu,
460 process_lock_release_event(data, event, cpu, timestamp, thread); 460 process_lock_release_event(data, event, cpu, timestamp, thread);
461} 461}
462 462
463struct raw_event_queue {
464 u64 timestamp;
465 int cpu;
466 void *data;
467 struct thread *thread;
468 struct list_head list;
469};
470
471static LIST_HEAD(raw_event_head);
472
473#define FLUSH_PERIOD (5 * NSEC_PER_SEC)
474
475static u64 flush_limit = ULLONG_MAX;
476static u64 last_flush = 0;
477struct raw_event_queue *last_inserted;
478
479static void flush_raw_event_queue(u64 limit)
480{
481 struct raw_event_queue *tmp, *iter;
482
483 list_for_each_entry_safe(iter, tmp, &raw_event_head, list) {
484 if (iter->timestamp > limit)
485 return;
486
487 if (iter == last_inserted)
488 last_inserted = NULL;
489
490 process_raw_event(iter->data, iter->cpu, iter->timestamp,
491 iter->thread);
492
493 last_flush = iter->timestamp;
494 list_del(&iter->list);
495 free(iter->data);
496 free(iter);
497 }
498}
499
500static void __queue_raw_event_end(struct raw_event_queue *new)
501{
502 struct raw_event_queue *iter;
503
504 list_for_each_entry_reverse(iter, &raw_event_head, list) {
505 if (iter->timestamp < new->timestamp) {
506 list_add(&new->list, &iter->list);
507 return;
508 }
509 }
510
511 list_add(&new->list, &raw_event_head);
512}
513
514static void __queue_raw_event_before(struct raw_event_queue *new,
515 struct raw_event_queue *iter)
516{
517 list_for_each_entry_continue_reverse(iter, &raw_event_head, list) {
518 if (iter->timestamp < new->timestamp) {
519 list_add(&new->list, &iter->list);
520 return;
521 }
522 }
523
524 list_add(&new->list, &raw_event_head);
525}
526
527static void __queue_raw_event_after(struct raw_event_queue *new,
528 struct raw_event_queue *iter)
529{
530 list_for_each_entry_continue(iter, &raw_event_head, list) {
531 if (iter->timestamp > new->timestamp) {
532 list_add_tail(&new->list, &iter->list);
533 return;
534 }
535 }
536 list_add_tail(&new->list, &raw_event_head);
537}
538
539/* The queue is ordered by time */
540static void __queue_raw_event(struct raw_event_queue *new)
541{
542 if (!last_inserted) {
543 __queue_raw_event_end(new);
544 return;
545 }
546
547 /*
548 * Most of the time the current event has a timestamp
549 * very close to the last event inserted, unless we just switched
550 * to another event buffer. Having a sorting based on a list and
551 * on the last inserted event that is close to the current one is
552 * probably more efficient than an rbtree based sorting.
553 */
554 if (last_inserted->timestamp >= new->timestamp)
555 __queue_raw_event_before(new, last_inserted);
556 else
557 __queue_raw_event_after(new, last_inserted);
558}
559
560static void queue_raw_event(void *data, int raw_size, int cpu,
561 u64 timestamp, struct thread *thread)
562{
563 struct raw_event_queue *new;
564
565 if (flush_limit == ULLONG_MAX)
566 flush_limit = timestamp + FLUSH_PERIOD;
567
568 if (timestamp < last_flush) {
569 printf("Warning: Timestamp below last timeslice flush\n");
570 return;
571 }
572
573 new = malloc(sizeof(*new));
574 if (!new)
575 die("Not enough memory\n");
576
577 new->timestamp = timestamp;
578 new->cpu = cpu;
579 new->thread = thread;
580
581 new->data = malloc(raw_size);
582 if (!new->data)
583 die("Not enough memory\n");
584
585 memcpy(new->data, data, raw_size);
586
587 __queue_raw_event(new);
588 last_inserted = new;
589
590 /*
591 * We want to have a slice of events covering 2 * FLUSH_PERIOD
592 * If FLUSH_PERIOD is big enough, it ensures every events that occured
593 * in the first half of the timeslice have all been buffered and there
594 * are none remaining (we need that because of the weakly ordered
595 * event recording we have). Then once we reach the 2 * FLUSH_PERIOD
596 * timeslice, we flush the first half to be gentle with the memory
597 * (the second half can still get new events in the middle, so wait
598 * another period to flush it)
599 */
600 if (new->timestamp > flush_limit &&
601 new->timestamp - flush_limit > FLUSH_PERIOD) {
602 flush_limit += FLUSH_PERIOD;
603 flush_raw_event_queue(flush_limit);
604 }
605}
606
463static int process_sample_event(event_t *event, struct perf_session *session) 607static int process_sample_event(event_t *event, struct perf_session *session)
464{ 608{
465 struct thread *thread; 609 struct thread *thread;
@@ -480,7 +624,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
480 if (profile_cpu != -1 && profile_cpu != (int) data.cpu) 624 if (profile_cpu != -1 && profile_cpu != (int) data.cpu)
481 return 0; 625 return 0;
482 626
483 process_raw_event(data.raw_data, data.cpu, data.time, thread); 627 queue_raw_event(data.raw_data, data.raw_size, data.cpu, data.time, thread);
484 628
485 return 0; 629 return 0;
486} 630}
@@ -576,6 +720,7 @@ static void __cmd_report(void)
576 setup_pager(); 720 setup_pager();
577 select_key(); 721 select_key();
578 read_events(); 722 read_events();
723 flush_raw_event_queue(ULLONG_MAX);
579 sort_result(); 724 sort_result();
580 print_result(); 725 print_result();
581} 726}
@@ -608,7 +753,6 @@ static const char *record_args[] = {
608 "record", 753 "record",
609 "-a", 754 "-a",
610 "-R", 755 "-R",
611 "-M",
612 "-f", 756 "-f",
613 "-m", "1024", 757 "-m", "1024",
614 "-c", "1", 758 "-c", "1",
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c30a33592340..152d6c9b1fa4 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -47,7 +47,6 @@
47#include "util/probe-event.h" 47#include "util/probe-event.h"
48 48
49#define MAX_PATH_LEN 256 49#define MAX_PATH_LEN 256
50#define MAX_PROBES 128
51 50
52/* Session management structure */ 51/* Session management structure */
53static struct { 52static struct {
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
46static char callchain_default_opt[] = "fractal,0.5"; 46static char callchain_default_opt[] = "fractal,0.5";
47 47
48static 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
48static int perf_session__add_hist_entry(struct perf_session *self, 80static 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
132static 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
89static int process_sample_event(event_t *event, struct perf_session *session) 151static 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..1f529321607e 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
@@ -454,7 +455,7 @@ static void print_sym_table(void)
454 struct sym_entry *syme, *n; 455 struct sym_entry *syme, *n;
455 struct rb_root tmp = RB_ROOT; 456 struct rb_root tmp = RB_ROOT;
456 struct rb_node *nd; 457 struct rb_node *nd;
457 int sym_width = 0, dso_width = 0, max_dso_width; 458 int sym_width = 0, dso_width = 0, dso_short_width = 0;
458 const int win_width = winsize.ws_col - 1; 459 const int win_width = winsize.ws_col - 1;
459 460
460 samples = userspace_samples = 0; 461 samples = userspace_samples = 0;
@@ -544,15 +545,20 @@ static void print_sym_table(void)
544 if (syme->map->dso->long_name_len > dso_width) 545 if (syme->map->dso->long_name_len > dso_width)
545 dso_width = syme->map->dso->long_name_len; 546 dso_width = syme->map->dso->long_name_len;
546 547
548 if (syme->map->dso->short_name_len > dso_short_width)
549 dso_short_width = syme->map->dso->short_name_len;
550
547 if (syme->name_len > sym_width) 551 if (syme->name_len > sym_width)
548 sym_width = syme->name_len; 552 sym_width = syme->name_len;
549 } 553 }
550 554
551 printed = 0; 555 printed = 0;
552 556
553 max_dso_width = winsize.ws_col - sym_width - 29; 557 if (sym_width + dso_width > winsize.ws_col - 29) {
554 if (dso_width > max_dso_width) 558 dso_width = dso_short_width;
555 dso_width = max_dso_width; 559 if (sym_width + dso_width > winsize.ws_col - 29)
560 sym_width = winsize.ws_col - dso_width - 29;
561 }
556 putchar('\n'); 562 putchar('\n');
557 if (nr_counters == 1) 563 if (nr_counters == 1)
558 printf(" samples pcnt"); 564 printf(" samples pcnt");
@@ -1123,7 +1129,7 @@ static void start_counter(int i, int counter)
1123 1129
1124 cpu = profile_cpu; 1130 cpu = profile_cpu;
1125 if (target_pid == -1 && profile_cpu == -1) 1131 if (target_pid == -1 && profile_cpu == -1)
1126 cpu = i; 1132 cpu = cpumap[i];
1127 1133
1128 attr = attrs + counter; 1134 attr = attrs + counter;
1129 1135
@@ -1347,12 +1353,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1347 attrs[counter].sample_period = default_interval; 1353 attrs[counter].sample_period = default_interval;
1348 } 1354 }
1349 1355
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) 1356 if (target_pid != -1 || profile_cpu != -1)
1355 nr_cpus = 1; 1357 nr_cpus = 1;
1358 else
1359 nr_cpus = read_cpu_map();
1356 1360
1357 get_term_dimensions(&winsize); 1361 get_term_dimensions(&winsize);
1358 if (print_entries == 0) { 1362 if (print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 5db687fc13de..407041d20de0 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -573,7 +573,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
573 573
574 if (symbol__init() < 0) 574 if (symbol__init() < 0)
575 return -1; 575 return -1;
576 setup_pager(); 576 if (!script_name)
577 setup_pager();
577 578
578 session = perf_session__new(input_name, O_RDONLY, 0); 579 session = perf_session__new(input_name, O_RDONLY, 0);
579 if (session == NULL) 580 if (session == NULL)
@@ -608,7 +609,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
608 return -1; 609 return -1;
609 } 610 }
610 611
611 perf_header__read(&session->header, input);
612 err = scripting_ops->generate_script("perf-trace"); 612 err = scripting_ops->generate_script("perf-trace");
613 goto out; 613 goto out;
614 } 614 }
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 9afcff2e3ae5..db6ee94d4a8e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -18,3 +18,4 @@ perf-top mainporcelain common
18perf-trace mainporcelain common 18perf-trace mainporcelain common
19perf-probe mainporcelain common 19perf-probe mainporcelain common
20perf-kmem mainporcelain common 20perf-kmem mainporcelain common
21perf-lock mainporcelain common
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 45fbe2f07b15..910468e6e01c 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -9,8 +9,9 @@ fi
9 9
10DEBUGDIR=~/.debug/ 10DEBUGDIR=~/.debug/
11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX) 11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
12NOBUILDID=0000000000000000000000000000000000000000
12 13
13perf buildid-list -i $PERF_DATA --with-hits > $BUILDIDS 14perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
14if [ ! -s $BUILDIDS ] ; then 15if [ ! -s $BUILDIDS ] ; then
15 echo "perf archive: no build-ids found" 16 echo "perf archive: no build-ids found"
16 rm -f $BUILDIDS 17 rm -f $BUILDIDS
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 75f941bfba9e..6fb379bc1d1f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -65,9 +65,7 @@
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See 65 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details. 66 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */ 67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \ 68#define rmb() ((void(*)(void))0xffff0fa0)()
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory") 69#define cpu_relax() asm volatile("":::"memory")
72#endif 70#endif
73 71
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
7int cpumap[MAX_NR_CPUS];
8
9static 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
23int 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
4extern int read_cpu_map(void);
5extern 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
102struct 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
102void event__print_totals(void); 111void event__print_totals(void);
103 112
104struct perf_session; 113struct 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
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 15struct 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
133void perf_session__collapse_resort(struct perf_session *self) 133void 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
186void perf_session__output_resort(struct perf_session *self, u64 total_samples) 186void 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
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 211static 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
458static size_t hist_entry__fprintf(struct hist_entry *self, 458static 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
554size_t perf_session__fprintf_hists(struct perf_session *self, 554size_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
643print_entries: 644print_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;
10struct hist_entry; 10struct hist_entry;
11struct addr_location; 11struct addr_location;
12struct symbol; 12struct symbol;
13struct rb_root;
13 14
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 15struct 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 *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
20void hist_entry__free(struct hist_entry *); 21void hist_entry__free(struct hist_entry *);
21 22
22void perf_session__output_resort(struct perf_session *self, u64 total_samples); 23void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self); 24void perf_session__collapse_resort(struct rb_root *hists);
24size_t perf_session__fprintf_hists(struct perf_session *self, 25size_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-event.c b/tools/perf/util/probe-event.c
index c971e81e9cbf..7c004b6ef24f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -242,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
242 242
243 /* Parse probe point */ 243 /* Parse probe point */
244 parse_perf_probe_probepoint(argv[0], pp); 244 parse_perf_probe_probepoint(argv[0], pp);
245 if (pp->file || pp->line) 245 if (pp->file || pp->line || pp->lazy_line)
246 *need_dwarf = true; 246 *need_dwarf = true;
247 247
248 /* Copy arguments and ensure return probe has no C argument */ 248 /* Copy arguments and ensure return probe has no C argument */
@@ -508,8 +508,8 @@ void show_perf_probe_events(void)
508 struct str_node *ent; 508 struct str_node *ent;
509 509
510 setup_pager(); 510 setup_pager();
511
512 memset(&pp, 0, sizeof(pp)); 511 memset(&pp, 0, sizeof(pp));
512
513 fd = open_kprobe_events(O_RDONLY, 0); 513 fd = open_kprobe_events(O_RDONLY, 0);
514 rawlist = get_trace_kprobe_event_rawlist(fd); 514 rawlist = get_trace_kprobe_event_rawlist(fd);
515 close(fd); 515 close(fd);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e77dc886760e..c171a243d05b 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)
@@ -333,8 +333,8 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
333 die("%u exceeds max register number.", regn); 333 die("%u exceeds max register number.", regn);
334 334
335 if (deref) 335 if (deref)
336 ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", 336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
337 pf->var, (uintmax_t)offs, regs); 337 pf->var, (intmax_t)offs, regs);
338 else 338 else
339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
340 DIE_IF(ret < 0); 340 DIE_IF(ret < 0);
@@ -352,8 +352,7 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
353 goto error; 353 goto error;
354 /* TODO: handle more than 1 exprs */ 354 /* TODO: handle more than 1 exprs */
355 ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), 355 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
356 &expr, &nexpr, 1);
357 if (ret <= 0 || nexpr == 0) 356 if (ret <= 0 || nexpr == 0)
358 goto error; 357 goto error;
359 358
@@ -437,8 +436,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
437 436
438 /* Get the frame base attribute/ops */ 437 /* Get the frame base attribute/ops */
439 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
440 ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), 439 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
441 &pf->fb_ops, &nops, 1);
442 if (ret <= 0 || nops == 0) 440 if (ret <= 0 || nops == 0)
443 pf->fb_ops = NULL; 441 pf->fb_ops = NULL;
444 442
@@ -455,6 +453,9 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
455 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 453 /* *pf->fb_ops will be cached in libdw. Don't free it. */
456 pf->fb_ops = NULL; 454 pf->fb_ops = NULL;
457 455
456 if (pp->found == MAX_PROBES)
457 die("Too many( > %d) probe point found.\n", MAX_PROBES);
458
458 pp->probes[pp->found] = strdup(tmp); 459 pp->probes[pp->found] = strdup(tmp);
459 pp->found++; 460 pp->found++;
460} 461}
@@ -641,7 +642,6 @@ static void find_probe_point_by_func(struct probe_finder *pf)
641int find_probe_point(int fd, struct probe_point *pp) 642int find_probe_point(int fd, struct probe_point *pp)
642{ 643{
643 struct probe_finder pf = {.pp = pp}; 644 struct probe_finder pf = {.pp = pp};
644 int ret;
645 Dwarf_Off off, noff; 645 Dwarf_Off off, noff;
646 size_t cuhl; 646 size_t cuhl;
647 Dwarf_Die *diep; 647 Dwarf_Die *diep;
@@ -668,10 +668,6 @@ int find_probe_point(int fd, struct probe_point *pp)
668 pf.fname = NULL; 668 pf.fname = NULL;
669 669
670 if (!pp->file || pf.fname) { 670 if (!pp->file || pf.fname) {
671 /* Save CU base address (for frame_base) */
672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
673 if (ret != 0)
674 pf.cu_base = 0;
675 if (pp->function) 671 if (pp->function)
676 find_probe_point_by_func(&pf); 672 find_probe_point_by_func(&pf);
677 else if (pp->lazy_line) 673 else if (pp->lazy_line)
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index d1a651793ba6..21f7354397b4 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -71,7 +71,6 @@ struct probe_finder {
71 71
72 /* For variable searching */ 72 /* For variable searching */
73 Dwarf_Op *fb_ops; /* Frame base attribute */ 73 Dwarf_Op *fb_ops; /* Frame base attribute */
74 Dwarf_Addr cu_base; /* Current CU base address */
75 const char *var; /* Current variable name */ 74 const char *var; /* Current variable name */
76 char *buf; /* Current output buffer */ 75 char *buf; /* Current output buffer */
77 int len; /* Length of output buffer */ 76 int len; /* Length of output buffer */
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 33a414bbba3e..6a72f14c5986 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data,
208 int size __unused, 208 int size __unused,
209 unsigned long long nsecs, char *comm) 209 unsigned long long nsecs, char *comm)
210{ 210{
211 PyObject *handler, *retval, *context, *t; 211 PyObject *handler, *retval, *context, *t, *obj;
212 static char handler_name[256]; 212 static char handler_name[256];
213 struct format_field *field; 213 struct format_field *field;
214 unsigned long long val; 214 unsigned long long val;
@@ -256,16 +256,23 @@ static void python_process_event(int cpu, void *data,
256 offset &= 0xffff; 256 offset &= 0xffff;
257 } else 257 } else
258 offset = field->offset; 258 offset = field->offset;
259 PyTuple_SetItem(t, n++, 259 obj = PyString_FromString((char *)data + offset);
260 PyString_FromString((char *)data + offset));
261 } else { /* FIELD_IS_NUMERIC */ 260 } else { /* FIELD_IS_NUMERIC */
262 val = read_size(data + field->offset, field->size); 261 val = read_size(data + field->offset, field->size);
263 if (field->flags & FIELD_IS_SIGNED) { 262 if (field->flags & FIELD_IS_SIGNED) {
264 PyTuple_SetItem(t, n++, PyInt_FromLong(val)); 263 if ((long long)val >= LONG_MIN &&
264 (long long)val <= LONG_MAX)
265 obj = PyInt_FromLong(val);
266 else
267 obj = PyLong_FromLongLong(val);
265 } else { 268 } else {
266 PyTuple_SetItem(t, n++, PyInt_FromLong(val)); 269 if (val <= LONG_MAX)
270 obj = PyInt_FromLong(val);
271 else
272 obj = PyLong_FromUnsignedLongLong(val);
267 } 273 }
268 } 274 }
275 PyTuple_SetItem(t, n++, obj);
269 } 276 }
270 277
271 if (_PyTuple_Resize(&t, n) == -1) 278 if (_PyTuple_Resize(&t, n) == -1)
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/symbol.c b/tools/perf/util/symbol.c
index 323c0aea0a91..c458c4a371d1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -163,9 +163,17 @@ void dso__set_long_name(struct dso *self, char *name)
163 self->long_name_len = strlen(name); 163 self->long_name_len = strlen(name);
164} 164}
165 165
166static void dso__set_short_name(struct dso *self, const char *name)
167{
168 if (name == NULL)
169 return;
170 self->short_name = name;
171 self->short_name_len = strlen(name);
172}
173
166static void dso__set_basename(struct dso *self) 174static void dso__set_basename(struct dso *self)
167{ 175{
168 self->short_name = basename(self->long_name); 176 dso__set_short_name(self, basename(self->long_name));
169} 177}
170 178
171struct dso *dso__new(const char *name) 179struct dso *dso__new(const char *name)
@@ -176,7 +184,7 @@ struct dso *dso__new(const char *name)
176 int i; 184 int i;
177 strcpy(self->name, name); 185 strcpy(self->name, name);
178 dso__set_long_name(self, self->name); 186 dso__set_long_name(self, self->name);
179 self->short_name = self->name; 187 dso__set_short_name(self, self->name);
180 for (i = 0; i < MAP__NR_TYPES; ++i) 188 for (i = 0; i < MAP__NR_TYPES; ++i)
181 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 189 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
182 self->slen_calculated = 0; 190 self->slen_calculated = 0;
@@ -897,7 +905,6 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
897 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 905 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
898 struct map *curr_map = map; 906 struct map *curr_map = map;
899 struct dso *curr_dso = self; 907 struct dso *curr_dso = self;
900 size_t dso_name_len = strlen(self->short_name);
901 Elf_Data *symstrs, *secstrs; 908 Elf_Data *symstrs, *secstrs;
902 uint32_t nr_syms; 909 uint32_t nr_syms;
903 int err = -1; 910 int err = -1;
@@ -987,7 +994,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
987 char dso_name[PATH_MAX]; 994 char dso_name[PATH_MAX];
988 995
989 if (strcmp(section_name, 996 if (strcmp(section_name,
990 curr_dso->short_name + dso_name_len) == 0) 997 (curr_dso->short_name +
998 self->short_name_len)) == 0)
991 goto new_symbol; 999 goto new_symbol;
992 1000
993 if (strcmp(section_name, ".text") == 0) { 1001 if (strcmp(section_name, ".text") == 0) {
@@ -1782,7 +1790,7 @@ struct dso *dso__new_kernel(const char *name)
1782 struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 1790 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1783 1791
1784 if (self != NULL) { 1792 if (self != NULL) {
1785 self->short_name = "[kernel]"; 1793 dso__set_short_name(self, "[kernel]");
1786 self->kernel = 1; 1794 self->kernel = 1;
1787 } 1795 }
1788 1796
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 280dadd32a08..f30a37428919 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -110,9 +110,10 @@ struct dso {
110 u8 sorted_by_name; 110 u8 sorted_by_name;
111 u8 loaded; 111 u8 loaded;
112 u8 build_id[BUILD_ID_SIZE]; 112 u8 build_id[BUILD_ID_SIZE];
113 u16 long_name_len;
114 const char *short_name; 113 const char *short_name;
115 char *long_name; 114 char *long_name;
115 u16 long_name_len;
116 u16 short_name_len;
116 char name[0]; 117 char name[0];
117}; 118};
118 119
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
82static size_t __map_groups__fprintf_maps(struct map_groups *self, 82size_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
186static void map_groups__remove_overlappings(struct map_groups *self, 186static 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
215void maps__insert(struct rb_root *maps, struct map *map) 244void 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
255void thread__insert_map(struct thread *self, struct map *map) 284void 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
13size_t __map_groups__fprintf_maps(struct map_groups *self,
14 enum map_type type, FILE *fp);
15
13struct thread { 16struct thread {
14 struct rb_node rb_node; 17 struct rb_node rb_node;
15 struct map_groups mg; 18 struct map_groups mg;