aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-22 07:17:26 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-03-22 07:17:26 -0400
commitf9b44121b34174ae4f243a568393fc3225842e75 (patch)
tree943f68cd7458d08a9e8809ed0a10b71b23911f3e /tools
parent8727b909bb2348d29e62c599cd7a5d610da3760f (diff)
parent220bf991b0366cc50a94feede3d7341fa5710ee4 (diff)
Merge commit 'v2.6.34-rc2' into for-2.6.34
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/Makefile6
-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-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.c9
-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.c2
-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.c52
-rw-r--r--tools/perf/util/hist.h12
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/session.c1
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/thread.c41
-rw-r--r--tools/perf/util/thread.h3
26 files changed, 473 insertions, 80 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..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
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
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-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..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/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.c b/tools/perf/perf.c
index 57cb107c1f13..cd32c200cdb3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -445,7 +445,7 @@ int main(int argc, const char **argv)
445 445
446 /* 446 /*
447 * We use PATH to find perf commands, but we prepend some higher 447 * We use PATH to find perf commands, but we prepend some higher
448 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 448 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
449 * environment, and the $(perfexecdir) from the Makefile at build 449 * environment, and the $(perfexecdir) from the Makefile at build
450 * time. 450 * time.
451 */ 451 */
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 e8daf5ca6fd2..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)
@@ -321,7 +321,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 321 new_depth_mask &= ~(1 << (depth - 1));
322 322
323 /* 323 /*
324 * But we keep the older depth mask for the line seperator 324 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 325 * to keep the level link until we reach the last child
326 */ 326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
@@ -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..53181dbfe4a8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -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..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
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;