aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-01-08 03:11:18 -0500
committerJaroslav Kysela <perex@perex.cz>2010-01-08 03:11:18 -0500
commita4ad68d57e4dc4138304df23d1817eb094149389 (patch)
treeca7d8c4ce5377c4251560de06e15dd7be7063351 /tools
parentcd9d95a55550555da8e587ead9cbba5f98a371a3 (diff)
parentc97259df3f2e163c72f4d0685c61fb2e026dc989 (diff)
Merge branch 'topic/hda' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6 into devel
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-probe.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt4
-rw-r--r--tools/perf/Documentation/perf-trace.txt27
-rw-r--r--tools/perf/Makefile16
-rw-r--r--tools/perf/bench/sched-messaging.c8
-rw-r--r--tools/perf/bench/sched-pipe.c11
-rw-r--r--tools/perf/builtin-annotate.c75
-rw-r--r--tools/perf/builtin-bench.c57
-rw-r--r--tools/perf/builtin-buildid-list.c57
-rw-r--r--tools/perf/builtin-diff.c248
-rw-r--r--tools/perf/builtin-kmem.c59
-rw-r--r--tools/perf/builtin-probe.c145
-rw-r--r--tools/perf/builtin-record.c166
-rw-r--r--tools/perf/builtin-report.c735
-rw-r--r--tools/perf/builtin-sched.c100
-rw-r--r--tools/perf/builtin-timechart.c70
-rw-r--r--tools/perf/builtin-top.c45
-rw-r--r--tools/perf/builtin-trace.c349
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/perf.h12
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report1
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report4
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report1
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report1
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report1
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl5
-rw-r--r--tools/perf/util/data_map.c163
-rw-r--r--tools/perf/util/data_map.h32
-rw-r--r--tools/perf/util/event.c147
-rw-r--r--tools/perf/util/event.h47
-rw-r--r--tools/perf/util/header.c30
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c518
-rw-r--r--tools/perf/util/hist.h55
-rw-r--r--tools/perf/util/map.c93
-rw-r--r--tools/perf/util/probe-event.c222
-rw-r--r--tools/perf/util/probe-event.h11
-rw-r--r--tools/perf/util/probe-finder.c4
-rw-r--r--tools/perf/util/probe-finder.h58
-rw-r--r--tools/perf/util/session.c150
-rw-r--r--tools/perf/util/session.h61
-rw-r--r--tools/perf/util/sort.c26
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/string.c25
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h41
-rw-r--r--tools/perf/util/symbol.c350
-rw-r--r--tools/perf/util/symbol.h45
-rw-r--r--tools/perf/util/thread.c100
-rw-r--r--tools/perf/util/thread.h50
-rw-r--r--tools/perf/util/trace-event-perl.c42
-rw-r--r--tools/perf/util/trace-event.h2
56 files changed, 2880 insertions, 1674 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
new file mode 100644
index 00000000000..8974e208cba
--- /dev/null
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -0,0 +1,55 @@
1perf-diff(1)
2==============
3
4NAME
5----
6perf-diff - Read two perf.data files and display the differential profile
7
8SYNOPSIS
9--------
10[verse]
11'perf diff' [oldfile] [newfile]
12
13DESCRIPTION
14-----------
15This command displays the performance difference amongst two perf.data files
16captured via perf record.
17
18If no parameters are passed it will assume perf.data.old and perf.data.
19
20OPTIONS
21-------
22-d::
23--dsos=::
24 Only consider symbols in these dsos. CSV that understands
25 file://filename entries.
26
27-C::
28--comms=::
29 Only consider symbols in these comms. CSV that understands
30 file://filename entries.
31
32-S::
33--symbols=::
34 Only consider these symbols. CSV that understands
35 file://filename entries.
36
37-s::
38--sort=::
39 Sort by key(s): pid, comm, dso, symbol.
40
41-t::
42--field-separator=::
43
44 Use a special separator character and don't pad with spaces, replacing
45 all occurances of this separator in symbol names (and other output)
46 with a '.' character, that thus it's the only non valid separator.
47
48-v::
49--verbose::
50 Be verbose, for instance, show the raw counts in addition to the
51 diff.
52
53SEE ALSO
54--------
55linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8fa6bf99fcb..250e391b4bc 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -49,8 +49,9 @@ PROBE SYNTAX
49------------ 49------------
50Probe points are defined by following syntax. 50Probe points are defined by following syntax.
51 51
52 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
53 53
54'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
54'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 55'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function.
55It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 56It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
56'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 57'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9dccb180b7a..abfabe9147a 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -39,6 +39,10 @@ OPTIONS
39 Only consider these symbols. CSV that understands 39 Only consider these symbols. CSV that understands
40 file://filename entries. 40 file://filename entries.
41 41
42-s::
43--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent.
45
42-w:: 46-w::
43--field-width=:: 47--field-width=::
44 Force each column width to the provided list, for large terminal 48 Force each column width to the provided list, for large terminal
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 07065efa60e..60e5900da48 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,18 +8,43 @@ perf-trace - Read perf.data (created by perf record) and display trace output
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-i <file> | --input=file] symbol_name 11'perf trace' {record <script> | report <script> [args] }
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command reads the input file and displays the trace recorded. 15This command reads the input file and displays the trace recorded.
16 16
17There are several variants of perf trace:
18
19 'perf trace' to see a detailed trace of the workload that was
20 recorded.
21
22 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language
25 extension.
26
27 'perf trace report <script>' to run and display the results of
28 <script>. <script> is the name displayed in the output of 'perf
29 trace --list' i.e. the actual script name minus any language
30 extension. The perf.data output from a previous run of 'perf trace
31 record <script>' is used and should be present for this command to
32 succeed.
33
17OPTIONS 34OPTIONS
18------- 35-------
19-D:: 36-D::
20--dump-raw-trace=:: 37--dump-raw-trace=::
21 Display verbose dump of the trace data. 38 Display verbose dump of the trace data.
22 39
40-L::
41--Latency=::
42 Show latency attributes (irqs/preemption disabled, etc).
43
44-l::
45--list=::
46 Display a list of available trace scripts.
47
23-s:: 48-s::
24--script=:: 49--script=::
25 Process trace data with the given script ([lang]:script[.ext]). 50 Process trace data with the given script ([lang]:script[.ext]).
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 23ec66098bd..4390d225686 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -237,8 +237,8 @@ lib = lib
237 237
238export prefix bindir sharedir sysconfdir 238export prefix bindir sharedir sysconfdir
239 239
240CC = gcc 240CC = $(CROSS_COMPILE)gcc
241AR = ar 241AR = $(CROSS_COMPILE)ar
242RM = rm -f 242RM = rm -f
243TAR = tar 243TAR = tar
244FIND = find 244FIND = find
@@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
356LIB_H += util/parse-events.h 356LIB_H += util/parse-events.h
357LIB_H += util/quote.h 357LIB_H += util/quote.h
358LIB_H += util/util.h 358LIB_H += util/util.h
359LIB_H += util/header.h
359LIB_H += util/help.h 360LIB_H += util/help.h
361LIB_H += util/session.h
360LIB_H += util/strbuf.h 362LIB_H += util/strbuf.h
361LIB_H += util/string.h 363LIB_H += util/string.h
362LIB_H += util/strlist.h 364LIB_H += util/strlist.h
@@ -368,7 +370,6 @@ LIB_H += util/values.h
368LIB_H += util/sort.h 370LIB_H += util/sort.h
369LIB_H += util/hist.h 371LIB_H += util/hist.h
370LIB_H += util/thread.h 372LIB_H += util/thread.h
371LIB_H += util/data_map.h
372LIB_H += util/probe-finder.h 373LIB_H += util/probe-finder.h
373LIB_H += util/probe-event.h 374LIB_H += util/probe-event.h
374 375
@@ -405,6 +406,7 @@ LIB_OBJS += util/callchain.o
405LIB_OBJS += util/values.o 406LIB_OBJS += util/values.o
406LIB_OBJS += util/debug.o 407LIB_OBJS += util/debug.o
407LIB_OBJS += util/map.o 408LIB_OBJS += util/map.o
409LIB_OBJS += util/session.o
408LIB_OBJS += util/thread.o 410LIB_OBJS += util/thread.o
409LIB_OBJS += util/trace-event-parse.o 411LIB_OBJS += util/trace-event-parse.o
410LIB_OBJS += util/trace-event-read.o 412LIB_OBJS += util/trace-event-read.o
@@ -425,6 +427,7 @@ BUILTIN_OBJS += bench/sched-messaging.o
425BUILTIN_OBJS += bench/sched-pipe.o 427BUILTIN_OBJS += bench/sched-pipe.o
426BUILTIN_OBJS += bench/mem-memcpy.o 428BUILTIN_OBJS += bench/mem-memcpy.o
427 429
430BUILTIN_OBJS += builtin-diff.o
428BUILTIN_OBJS += builtin-help.o 431BUILTIN_OBJS += builtin-help.o
429BUILTIN_OBJS += builtin-sched.o 432BUILTIN_OBJS += builtin-sched.o
430BUILTIN_OBJS += builtin-buildid-list.o 433BUILTIN_OBJS += builtin-buildid-list.o
@@ -484,16 +487,19 @@ else
484 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 487 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
485endif 488endif
486 489
487ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 490ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
488 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); 491 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
489 BASIC_CFLAGS += -DNO_LIBDWARF 492 BASIC_CFLAGS += -DNO_LIBDWARF
490else 493else
494 BASIC_CFLAGS += -I/usr/include/libdwarf
491 EXTLIBS += -lelf -ldwarf 495 EXTLIBS += -lelf -ldwarf
492 LIB_OBJS += util/probe-finder.o 496 LIB_OBJS += util/probe-finder.o
493endif 497endif
494 498
499ifndef NO_LIBPERL
495PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 500PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
496PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 501PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
502endif
497 503
498ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 504ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
499 BASIC_CFLAGS += -DNO_LIBPERL 505 BASIC_CFLAGS += -DNO_LIBPERL
@@ -991,8 +997,6 @@ install: all
991 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 997 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
992 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 998 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
993 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 999 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
994 $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
995 $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
996ifdef BUILT_INS 1000ifdef BUILT_INS
997 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1001 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
998 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1002 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 605a2a959aa..81cee78181f 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-messaging.c 3 * sched-messaging.c
4 * 4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms 5 * messaging: Benchmark for scheduler and IPC mechanisms
6 * 6 *
@@ -320,10 +320,12 @@ int bench_sched_messaging(int argc, const char **argv,
320 num_groups, num_groups * 2 * num_fds, 320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes"); 321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time", 322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec, diff.tv_usec/1000); 323 diff.tv_sec,
324 (unsigned long) (diff.tv_usec/1000));
324 break; 325 break;
325 case BENCH_FORMAT_SIMPLE: 326 case BENCH_FORMAT_SIMPLE:
326 printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000); 327 printf("%lu.%03lu\n", diff.tv_sec,
328 (unsigned long) (diff.tv_usec/1000));
327 break; 329 break;
328 default: 330 default:
329 /* reaching here is something disaster */ 331 /* reaching here is something disaster */
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 238185f9797..4f77c7c2764 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * 2 *
3 * builtin-bench-pipe.c 3 * sched-pipe.c
4 * 4 *
5 * pipe: Benchmark for pipe() 5 * pipe: Benchmark for pipe()
6 * 6 *
@@ -87,7 +87,8 @@ int bench_sched_pipe(int argc, const char **argv,
87 if (pid) { 87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0); 88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat)); 89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 return 0; 90 } else {
91 exit(0);
91 } 92 }
92 93
93 switch (bench_format) { 94 switch (bench_format) {
@@ -99,7 +100,8 @@ int bench_sched_pipe(int argc, const char **argv,
99 result_usec += diff.tv_usec; 100 result_usec += diff.tv_usec;
100 101
101 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 102 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
102 diff.tv_sec, diff.tv_usec/1000); 103 diff.tv_sec,
104 (unsigned long) (diff.tv_usec/1000));
103 105
104 printf(" %14lf usecs/op\n", 106 printf(" %14lf usecs/op\n",
105 (double)result_usec / (double)loops); 107 (double)result_usec / (double)loops);
@@ -110,7 +112,8 @@ int bench_sched_pipe(int argc, const char **argv,
110 112
111 case BENCH_FORMAT_SIMPLE: 113 case BENCH_FORMAT_SIMPLE:
112 printf("%lu.%03lu\n", 114 printf("%lu.%03lu\n",
113 diff.tv_sec, diff.tv_usec / 1000); 115 diff.tv_sec,
116 (unsigned long) (diff.tv_usec / 1000));
114 break; 117 break;
115 118
116 default: 119 default:
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0bf2e8f9af5..593ff25006d 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -25,7 +25,7 @@
25#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/data_map.h" 28#include "util/session.h"
29 29
30static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
31 31
@@ -51,11 +51,6 @@ struct sym_priv {
51 struct sym_ext *ext; 51 struct sym_ext *ext;
52}; 52};
53 53
54static struct symbol_conf symbol_conf = {
55 .priv_size = sizeof(struct sym_priv),
56 .try_vmlinux_path = true,
57};
58
59static const char *sym_hist_filter; 54static const char *sym_hist_filter;
60 55
61static int symbol_filter(struct map *map __used, struct symbol *sym) 56static int symbol_filter(struct map *map __used, struct symbol *sym)
@@ -121,30 +116,32 @@ static void hist_hit(struct hist_entry *he, u64 ip)
121 h->ip[offset]); 116 h->ip[offset]);
122} 117}
123 118
124static int hist_entry__add(struct addr_location *al, u64 count) 119static int perf_session__add_hist_entry(struct perf_session *self,
120 struct addr_location *al, u64 count)
125{ 121{
126 bool hit; 122 bool hit;
127 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit); 123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
124 count, &hit);
128 if (he == NULL) 125 if (he == NULL)
129 return -ENOMEM; 126 return -ENOMEM;
130 hist_hit(he, al->addr); 127 hist_hit(he, al->addr);
131 return 0; 128 return 0;
132} 129}
133 130
134static int process_sample_event(event_t *event) 131static int process_sample_event(event_t *event, struct perf_session *session)
135{ 132{
136 struct addr_location al; 133 struct addr_location al;
137 134
138 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 135 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
139 event->ip.pid, (void *)(long)event->ip.ip); 136 event->ip.pid, (void *)(long)event->ip.ip);
140 137
141 if (event__preprocess_sample(event, &al, symbol_filter) < 0) { 138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) {
142 fprintf(stderr, "problem processing %d event, skipping it.\n", 139 fprintf(stderr, "problem processing %d event, skipping it.\n",
143 event->header.type); 140 event->header.type);
144 return -1; 141 return -1;
145 } 142 }
146 143
147 if (hist_entry__add(&al, 1)) { 144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
148 fprintf(stderr, "problem incrementing symbol count, " 145 fprintf(stderr, "problem incrementing symbol count, "
149 "skipping event\n"); 146 "skipping event\n");
150 return -1; 147 return -1;
@@ -428,11 +425,11 @@ static void annotate_sym(struct hist_entry *he)
428 free_source_line(he, len); 425 free_source_line(he, len);
429} 426}
430 427
431static void find_annotations(void) 428static void perf_session__find_annotations(struct perf_session *self)
432{ 429{
433 struct rb_node *nd; 430 struct rb_node *nd;
434 431
435 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 432 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
436 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 433 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
437 struct sym_priv *priv; 434 struct sym_priv *priv;
438 435
@@ -453,7 +450,7 @@ static void find_annotations(void)
453 } 450 }
454} 451}
455 452
456static struct perf_file_handler file_handler = { 453static struct perf_event_ops event_ops = {
457 .process_sample_event = process_sample_event, 454 .process_sample_event = process_sample_event,
458 .process_mmap_event = event__process_mmap, 455 .process_mmap_event = event__process_mmap,
459 .process_comm_event = event__process_comm, 456 .process_comm_event = event__process_comm,
@@ -462,33 +459,33 @@ static struct perf_file_handler file_handler = {
462 459
463static int __cmd_annotate(void) 460static int __cmd_annotate(void)
464{ 461{
465 struct perf_header *header;
466 struct thread *idle;
467 int ret; 462 int ret;
463 struct perf_session *session;
468 464
469 idle = register_idle_thread(); 465 session = perf_session__new(input_name, O_RDONLY, force);
470 register_perf_file_handler(&file_handler); 466 if (session == NULL)
467 return -ENOMEM;
471 468
472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 469 ret = perf_session__process_events(session, &event_ops);
473 &event__cwdlen, &event__cwd);
474 if (ret) 470 if (ret)
475 return ret; 471 goto out_delete;
476 472
477 if (dump_trace) { 473 if (dump_trace) {
478 event__print_totals(); 474 event__print_totals();
479 return 0; 475 goto out_delete;
480 } 476 }
481 477
482 if (verbose > 3) 478 if (verbose > 3)
483 threads__fprintf(stdout); 479 perf_session__fprintf(session, stdout);
484 480
485 if (verbose > 2) 481 if (verbose > 2)
486 dsos__fprintf(stdout); 482 dsos__fprintf(stdout);
487 483
488 collapse__resort(); 484 perf_session__collapse_resort(session);
489 output__resort(event__total[0]); 485 perf_session__output_resort(session, session->event_total[0]);
490 486 perf_session__find_annotations(session);
491 find_annotations(); 487out_delete:
488 perf_session__delete(session);
492 489
493 return ret; 490 return ret;
494} 491}
@@ -519,29 +516,17 @@ static const struct option options[] = {
519 OPT_END() 516 OPT_END()
520}; 517};
521 518
522static void setup_sorting(void) 519int cmd_annotate(int argc, const char **argv, const char *prefix __used)
523{ 520{
524 char *tmp, *tok, *str = strdup(sort_order); 521 argc = parse_options(argc, argv, options, annotate_usage, 0);
525
526 for (tok = strtok_r(str, ", ", &tmp);
527 tok; tok = strtok_r(NULL, ", ", &tmp)) {
528 if (sort_dimension__add(tok) < 0) {
529 error("Unknown --sort key: `%s'", tok);
530 usage_with_options(annotate_usage, options);
531 }
532 }
533 522
534 free(str); 523 symbol_conf.priv_size = sizeof(struct sym_priv);
535} 524 symbol_conf.try_vmlinux_path = true;
536 525
537int cmd_annotate(int argc, const char **argv, const char *prefix __used) 526 if (symbol__init() < 0)
538{
539 if (symbol__init(&symbol_conf) < 0)
540 return -1; 527 return -1;
541 528
542 argc = parse_options(argc, argv, options, annotate_usage, 0); 529 setup_sorting(annotate_usage, options);
543
544 setup_sorting();
545 530
546 if (argc) { 531 if (argc) {
547 /* 532 /*
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index e043eb83092..46996774e55 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -31,6 +31,9 @@ struct bench_suite {
31 const char *summary; 31 const char *summary;
32 int (*fn)(int, const char **, const char *); 32 int (*fn)(int, const char **, const char *);
33}; 33};
34 \
35/* sentinel: easy for help */
36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
34 37
35static struct bench_suite sched_suites[] = { 38static struct bench_suite sched_suites[] = {
36 { "messaging", 39 { "messaging",
@@ -39,6 +42,7 @@ static struct bench_suite sched_suites[] = {
39 { "pipe", 42 { "pipe",
40 "Flood of communication over pipe() between two processes", 43 "Flood of communication over pipe() between two processes",
41 bench_sched_pipe }, 44 bench_sched_pipe },
45 suite_all,
42 { NULL, 46 { NULL,
43 NULL, 47 NULL,
44 NULL } 48 NULL }
@@ -48,6 +52,7 @@ static struct bench_suite mem_suites[] = {
48 { "memcpy", 52 { "memcpy",
49 "Simple memory copy in various ways", 53 "Simple memory copy in various ways",
50 bench_mem_memcpy }, 54 bench_mem_memcpy },
55 suite_all,
51 { NULL, 56 { NULL,
52 NULL, 57 NULL,
53 NULL } 58 NULL }
@@ -66,6 +71,9 @@ static struct bench_subsys subsystems[] = {
66 { "mem", 71 { "mem",
67 "memory access performance", 72 "memory access performance",
68 mem_suites }, 73 mem_suites },
74 { "all", /* sentinel: easy for help */
75 "test all subsystem (pseudo subsystem)",
76 NULL },
69 { NULL, 77 { NULL,
70 NULL, 78 NULL,
71 NULL } 79 NULL }
@@ -75,11 +83,11 @@ static void dump_suites(int subsys_index)
75{ 83{
76 int i; 84 int i;
77 85
78 printf("List of available suites for %s...\n\n", 86 printf("# List of available suites for %s...\n\n",
79 subsystems[subsys_index].name); 87 subsystems[subsys_index].name);
80 88
81 for (i = 0; subsystems[subsys_index].suites[i].name; i++) 89 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
82 printf("\t%s: %s\n", 90 printf("%14s: %s\n",
83 subsystems[subsys_index].suites[i].name, 91 subsystems[subsys_index].suites[i].name,
84 subsystems[subsys_index].suites[i].summary); 92 subsystems[subsys_index].suites[i].summary);
85 93
@@ -110,10 +118,10 @@ static void print_usage(void)
110 printf("\t%s\n", bench_usage[i]); 118 printf("\t%s\n", bench_usage[i]);
111 printf("\n"); 119 printf("\n");
112 120
113 printf("List of available subsystems...\n\n"); 121 printf("# List of available subsystems...\n\n");
114 122
115 for (i = 0; subsystems[i].name; i++) 123 for (i = 0; subsystems[i].name; i++)
116 printf("\t%s: %s\n", 124 printf("%14s: %s\n",
117 subsystems[i].name, subsystems[i].summary); 125 subsystems[i].name, subsystems[i].summary);
118 printf("\n"); 126 printf("\n");
119} 127}
@@ -131,6 +139,37 @@ static int bench_str2int(char *str)
131 return BENCH_FORMAT_UNKNOWN; 139 return BENCH_FORMAT_UNKNOWN;
132} 140}
133 141
142static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
143{
144 int i;
145 const char *argv[2];
146 struct bench_suite *suites = subsys->suites;
147
148 argv[1] = NULL;
149 /*
150 * TODO:
151 * preparing preset parameters for
152 * embedded, ordinary PC, HPC, etc...
153 * will be helpful
154 */
155 for (i = 0; suites[i].fn; i++) {
156 printf("# Running %s/%s benchmark...\n",
157 subsys->name,
158 suites[i].name);
159
160 argv[1] = suites[i].name;
161 suites[i].fn(1, argv, NULL);
162 printf("\n");
163 }
164}
165
166static void all_subsystem(void)
167{
168 int i;
169 for (i = 0; subsystems[i].suites; i++)
170 all_suite(&subsystems[i]);
171}
172
134int cmd_bench(int argc, const char **argv, const char *prefix __used) 173int cmd_bench(int argc, const char **argv, const char *prefix __used)
135{ 174{
136 int i, j, status = 0; 175 int i, j, status = 0;
@@ -155,6 +194,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
155 goto end; 194 goto end;
156 } 195 }
157 196
197 if (!strcmp(argv[0], "all")) {
198 all_subsystem();
199 goto end;
200 }
201
158 for (i = 0; subsystems[i].name; i++) { 202 for (i = 0; subsystems[i].name; i++) {
159 if (strcmp(subsystems[i].name, argv[0])) 203 if (strcmp(subsystems[i].name, argv[0]))
160 continue; 204 continue;
@@ -165,6 +209,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
165 goto end; 209 goto end;
166 } 210 }
167 211
212 if (!strcmp(argv[1], "all")) {
213 all_suite(&subsystems[i]);
214 goto end;
215 }
216
168 for (j = 0; subsystems[i].suites[j].name; j++) { 217 for (j = 0; subsystems[i].suites[j].name; j++) {
169 if (strcmp(subsystems[i].suites[j].name, argv[1])) 218 if (strcmp(subsystems[i].suites[j].name, argv[1]))
170 continue; 219 continue;
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index dcb6143a000..e693e6777af 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -9,10 +9,9 @@
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11#include "util/cache.h" 11#include "util/cache.h"
12#include "util/data_map.h"
13#include "util/debug.h" 12#include "util/debug.h"
14#include "util/header.h"
15#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/session.h"
16#include "util/symbol.h" 15#include "util/symbol.h"
17 16
18static char const *input_name = "perf.data"; 17static char const *input_name = "perf.data";
@@ -55,56 +54,18 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
55static int __cmd_buildid_list(void) 54static int __cmd_buildid_list(void)
56{ 55{
57 int err = -1; 56 int err = -1;
58 struct perf_header *header; 57 struct perf_session *session;
59 struct perf_file_header f_header;
60 struct stat input_stat;
61 int input = open(input_name, O_RDONLY);
62 58
63 if (input < 0) { 59 session = perf_session__new(input_name, O_RDONLY, force);
64 pr_err("failed to open file: %s", input_name); 60 if (session == NULL)
65 if (!strcmp(input_name, "perf.data")) 61 return -1;
66 pr_err(" (try 'perf record' first)");
67 pr_err("\n");
68 goto out;
69 }
70
71 err = fstat(input, &input_stat);
72 if (err < 0) {
73 perror("failed to stat file");
74 goto out_close;
75 }
76
77 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
78 pr_err("file %s not owned by current user or root\n",
79 input_name);
80 goto out_close;
81 }
82
83 if (!input_stat.st_size) {
84 pr_info("zero-sized file, nothing to do!\n");
85 goto out_close;
86 }
87
88 err = -1;
89 header = perf_header__new();
90 if (header == NULL)
91 goto out_close;
92
93 if (perf_file_header__read(&f_header, header, input) < 0) {
94 pr_warning("incompatible file format");
95 goto out_close;
96 }
97 62
98 err = perf_header__process_sections(header, input, 63 err = perf_header__process_sections(&session->header, session->fd,
99 perf_file_section__process_buildids); 64 perf_file_section__process_buildids);
65 if (err >= 0)
66 dsos__fprintf_buildid(stdout);
100 67
101 if (err < 0) 68 perf_session__delete(session);
102 goto out_close;
103
104 dsos__fprintf_buildid(stdout);
105out_close:
106 close(input);
107out:
108 return err; 69 return err;
109} 70}
110 71
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
new file mode 100644
index 00000000000..4d33b55d558
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,248 @@
1/*
2 * builtin-diff.c
3 *
4 * Builtin diff command: Analyze two perf.data input files, look up and read
5 * DSOs and symbol information, sort them and produce a diff.
6 */
7#include "builtin.h"
8
9#include "util/debug.h"
10#include "util/event.h"
11#include "util/hist.h"
12#include "util/session.h"
13#include "util/sort.h"
14#include "util/symbol.h"
15#include "util/util.h"
16
17#include <stdlib.h>
18
19static char const *input_old = "perf.data.old",
20 *input_new = "perf.data";
21static char diff__default_sort_order[] = "dso,symbol";
22static int force;
23static bool show_displacement;
24
25static int perf_session__add_hist_entry(struct perf_session *self,
26 struct addr_location *al, u64 count)
27{
28 bool hit;
29 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
30 count, &hit);
31 if (he == NULL)
32 return -ENOMEM;
33
34 if (hit)
35 he->count += count;
36
37 return 0;
38}
39
40static int diff__process_sample_event(event_t *event, struct perf_session *session)
41{
42 struct addr_location al;
43 struct sample_data data = { .period = 1, };
44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip);
47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n",
50 event->header.type);
51 return -1;
52 }
53
54 if (al.filtered)
55 return 0;
56
57 event__parse_sample(event, session->sample_type, &data);
58
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1;
62 }
63
64 session->events_stats.total += data.period;
65 return 0;
66}
67
68static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap,
71 .process_comm_event = event__process_comm,
72 .process_exit_event = event__process_task,
73 .process_fork_event = event__process_task,
74 .process_lost_event = event__process_lost,
75};
76
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
78 struct hist_entry *he)
79{
80 struct rb_node **p = &root->rb_node;
81 struct rb_node *parent = NULL;
82 struct hist_entry *iter;
83
84 while (*p != NULL) {
85 int cmp;
86 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node);
88
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left;
92 else if (cmp < 0)
93 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 }
102
103 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root);
105}
106
107static void perf_session__resort_by_name(struct perf_session *self)
108{
109 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT;
111 struct rb_node *next = rb_first(&self->hists);
112
113 while (next != NULL) {
114 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
115
116 next = rb_next(&n->rb_node);
117 rb_erase(&n->rb_node, &self->hists);
118 n->position = position++;
119 perf_session__insert_hist_entry_by_name(&tmp, n);
120 }
121
122 self->hists = tmp;
123}
124
125static struct hist_entry *
126perf_session__find_hist_entry_by_name(struct perf_session *self,
127 struct hist_entry *he)
128{
129 struct rb_node *n = self->hists.rb_node;
130
131 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name);
134
135 if (cmp > 0)
136 n = n->rb_left;
137 else if (cmp < 0)
138 n = n->rb_right;
139 else {
140 cmp = strcmp(he->sym->name, iter->sym->name);
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 }
149
150 return NULL;
151}
152
153static void perf_session__match_hists(struct perf_session *old_session,
154 struct perf_session *new_session)
155{
156 struct rb_node *nd;
157
158 perf_session__resort_by_name(old_session);
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos);
163 }
164}
165
166static int __cmd_diff(void)
167{
168 int ret, i;
169 struct perf_session *session[2];
170
171 session[0] = perf_session__new(input_old, O_RDONLY, force);
172 session[1] = perf_session__new(input_new, O_RDONLY, force);
173 if (session[0] == NULL || session[1] == NULL)
174 return -ENOMEM;
175
176 for (i = 0; i < 2; ++i) {
177 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret)
179 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 }
182
183 perf_session__match_hists(session[0], session[1]);
184 perf_session__fprintf_hists(session[1], session[0],
185 show_displacement, stdout);
186out_delete:
187 for (i = 0; i < 2; ++i)
188 perf_session__delete(session[i]);
189 return ret;
190}
191
192static const char *const diff_usage[] = {
193 "perf diff [<options>] [old_file] [new_file]",
194};
195
196static const struct option options[] = {
197 OPT_BOOLEAN('v', "verbose", &verbose,
198 "be more verbose (show symbol address, etc)"),
199 OPT_BOOLEAN('m', "displacement", &show_displacement,
200 "Show position displacement relative to baseline"),
201 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
202 "dump raw trace in ASCII"),
203 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
204 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
205 "load module symbols - WARNING: use only with -k and LIVE kernel"),
206 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
207 "Don't shorten the pathnames taking into account the cwd"),
208 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
209 "only consider symbols in these dsos"),
210 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
211 "only consider symbols in these comms"),
212 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
213 "only consider these symbols"),
214 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
215 "sort by key(s): pid, comm, dso, symbol, parent"),
216 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
217 "separator for columns, no spaces will be added between "
218 "columns '.' is reserved."),
219 OPT_END()
220};
221
222int cmd_diff(int argc, const char **argv, const char *prefix __used)
223{
224 sort_order = diff__default_sort_order;
225 argc = parse_options(argc, argv, options, diff_usage, 0);
226 if (argc) {
227 if (argc > 2)
228 usage_with_options(diff_usage, options);
229 if (argc == 2) {
230 input_old = argv[0];
231 input_new = argv[1];
232 } else
233 input_new = argv[0];
234 }
235
236 symbol_conf.exclude_other = false;
237 if (symbol__init() < 0)
238 return -1;
239
240 setup_sorting(diff_usage, options);
241 setup_pager();
242
243 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
244 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
245 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
246
247 return __cmd_diff();
248}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 5f209514f65..fc21ad79dd8 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -6,12 +6,12 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
12 13
13#include "util/debug.h" 14#include "util/debug.h"
14#include "util/data_map.h"
15 15
16#include <linux/rbtree.h> 16#include <linux/rbtree.h>
17 17
@@ -20,9 +20,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20 20
21static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
22 22
23static struct perf_header *header;
24static u64 sample_type;
25
26static int alloc_flag; 23static int alloc_flag;
27static int caller_flag; 24static int caller_flag;
28 25
@@ -312,7 +309,7 @@ process_raw_event(event_t *raw_event __used, void *data,
312 } 309 }
313} 310}
314 311
315static int process_sample_event(event_t *event) 312static int process_sample_event(event_t *event, struct perf_session *session)
316{ 313{
317 struct sample_data data; 314 struct sample_data data;
318 struct thread *thread; 315 struct thread *thread;
@@ -322,7 +319,7 @@ static int process_sample_event(event_t *event)
322 data.cpu = -1; 319 data.cpu = -1;
323 data.period = 1; 320 data.period = 1;
324 321
325 event__parse_sample(event, sample_type, &data); 322 event__parse_sample(event, session->sample_type, &data);
326 323
327 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
328 event->header.misc, 325 event->header.misc,
@@ -330,7 +327,7 @@ static int process_sample_event(event_t *event)
330 (void *)(long)data.ip, 327 (void *)(long)data.ip,
331 (long long)data.period); 328 (long long)data.period);
332 329
333 thread = threads__findnew(event->ip.pid); 330 thread = perf_session__findnew(session, event->ip.pid);
334 if (thread == NULL) { 331 if (thread == NULL) {
335 pr_debug("problem processing %d event, skipping it.\n", 332 pr_debug("problem processing %d event, skipping it.\n",
336 event->header.type); 333 event->header.type);
@@ -345,11 +342,9 @@ static int process_sample_event(event_t *event)
345 return 0; 342 return 0;
346} 343}
347 344
348static int sample_type_check(u64 type) 345static int sample_type_check(struct perf_session *session)
349{ 346{
350 sample_type = type; 347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
351
352 if (!(sample_type & PERF_SAMPLE_RAW)) {
353 fprintf(stderr, 348 fprintf(stderr,
354 "No trace sample to read. Did you call perf record " 349 "No trace sample to read. Did you call perf record "
355 "without -R?"); 350 "without -R?");
@@ -359,21 +354,12 @@ static int sample_type_check(u64 type)
359 return 0; 354 return 0;
360} 355}
361 356
362static struct perf_file_handler file_handler = { 357static struct perf_event_ops event_ops = {
363 .process_sample_event = process_sample_event, 358 .process_sample_event = process_sample_event,
364 .process_comm_event = event__process_comm, 359 .process_comm_event = event__process_comm,
365 .sample_type_check = sample_type_check, 360 .sample_type_check = sample_type_check,
366}; 361};
367 362
368static int read_events(void)
369{
370 register_idle_thread();
371 register_perf_file_handler(&file_handler);
372
373 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
374 &event__cwdlen, &event__cwd);
375}
376
377static double fragmentation(unsigned long n_req, unsigned long n_alloc) 363static double fragmentation(unsigned long n_req, unsigned long n_alloc)
378{ 364{
379 if (n_alloc == 0) 365 if (n_alloc == 0)
@@ -382,7 +368,8 @@ static double fragmentation(unsigned long n_req, unsigned long n_alloc)
382 return 100.0 - (100.0 * n_req / n_alloc); 368 return 100.0 - (100.0 * n_req / n_alloc);
383} 369}
384 370
385static void __print_result(struct rb_root *root, int n_lines, int is_caller) 371static void __print_result(struct rb_root *root, struct perf_session *session,
372 int n_lines, int is_caller)
386{ 373{
387 struct rb_node *next; 374 struct rb_node *next;
388 375
@@ -403,7 +390,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
403 if (is_caller) { 390 if (is_caller) {
404 addr = data->call_site; 391 addr = data->call_site;
405 if (!raw_ip) 392 if (!raw_ip)
406 sym = thread__find_function(kthread, addr, NULL); 393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL);
407 } else 394 } else
408 addr = data->ptr; 395 addr = data->ptr;
409 396
@@ -444,12 +431,12 @@ static void print_summary(void)
444 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); 431 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
445} 432}
446 433
447static void print_result(void) 434static void print_result(struct perf_session *session)
448{ 435{
449 if (caller_flag) 436 if (caller_flag)
450 __print_result(&root_caller_sorted, caller_lines, 1); 437 __print_result(&root_caller_sorted, session, caller_lines, 1);
451 if (alloc_flag) 438 if (alloc_flag)
452 __print_result(&root_alloc_sorted, alloc_lines, 0); 439 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
453 print_summary(); 440 print_summary();
454} 441}
455 442
@@ -517,12 +504,20 @@ static void sort_result(void)
517 504
518static int __cmd_kmem(void) 505static int __cmd_kmem(void)
519{ 506{
507 int err;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
509 if (session == NULL)
510 return -ENOMEM;
511
520 setup_pager(); 512 setup_pager();
521 read_events(); 513 err = perf_session__process_events(session, &event_ops);
514 if (err != 0)
515 goto out_delete;
522 sort_result(); 516 sort_result();
523 print_result(); 517 print_result(session);
524 518out_delete:
525 return 0; 519 perf_session__delete(session);
520 return err;
526} 521}
527 522
528static const char * const kmem_usage[] = { 523static const char * const kmem_usage[] = {
@@ -771,13 +766,13 @@ static int __cmd_record(int argc, const char **argv)
771 766
772int cmd_kmem(int argc, const char **argv, const char *prefix __used) 767int cmd_kmem(int argc, const char **argv, const char *prefix __used)
773{ 768{
774 symbol__init(0);
775
776 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 769 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
777 770
778 if (!argc) 771 if (!argc)
779 usage_with_options(kmem_usage, kmem_options); 772 usage_with_options(kmem_usage, kmem_options);
780 773
774 symbol__init();
775
781 if (!strncmp(argv[0], "rec", 3)) { 776 if (!strncmp(argv[0], "rec", 3)) {
782 return __cmd_record(argc, argv); 777 return __cmd_record(argc, argv);
783 } else if (!strcmp(argv[0], "stat")) { 778 } else if (!strcmp(argv[0], "stat")) {
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5a47c1e11f7..c1e6774fd3e 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -38,34 +38,30 @@
38#include "util/strlist.h" 38#include "util/strlist.h"
39#include "util/event.h" 39#include "util/event.h"
40#include "util/debug.h" 40#include "util/debug.h"
41#include "util/debugfs.h"
42#include "util/symbol.h"
43#include "util/thread.h"
44#include "util/session.h"
41#include "util/parse-options.h" 45#include "util/parse-options.h"
42#include "util/parse-events.h" /* For debugfs_path */ 46#include "util/parse-events.h" /* For debugfs_path */
43#include "util/probe-finder.h" 47#include "util/probe-finder.h"
44#include "util/probe-event.h" 48#include "util/probe-event.h"
45 49
46/* Default vmlinux search paths */
47#define NR_SEARCH_PATH 4
48const char *default_search_path[NR_SEARCH_PATH] = {
49"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
50"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
51"/boot/vmlinux-debug-%s", /* Ubuntu */
52"./vmlinux", /* CWD */
53};
54
55#define MAX_PATH_LEN 256 50#define MAX_PATH_LEN 256
56#define MAX_PROBES 128 51#define MAX_PROBES 128
57 52
58/* Session management structure */ 53/* Session management structure */
59static struct { 54static struct {
60 char *vmlinux; 55 bool need_dwarf;
61 char *release; 56 bool list_events;
62 int need_dwarf; 57 bool force_add;
63 int nr_probe; 58 int nr_probe;
64 struct probe_point probes[MAX_PROBES]; 59 struct probe_point probes[MAX_PROBES];
65 struct strlist *dellist; 60 struct strlist *dellist;
61 struct perf_session *psession;
62 struct map *kmap;
66} session; 63} session;
67 64
68static bool listing;
69 65
70/* Parse an event definition. Note that any error must die. */ 66/* Parse an event definition. Note that any error must die. */
71static void parse_probe_event(const char *str) 67static void parse_probe_event(const char *str)
@@ -77,7 +73,7 @@ static void parse_probe_event(const char *str)
77 die("Too many probes (> %d) are specified.", MAX_PROBES); 73 die("Too many probes (> %d) are specified.", MAX_PROBES);
78 74
79 /* Parse perf-probe event into probe_point */ 75 /* Parse perf-probe event into probe_point */
80 session.need_dwarf = parse_perf_probe_event(str, pp); 76 parse_perf_probe_event(str, pp, &session.need_dwarf);
81 77
82 pr_debug("%d arguments\n", pp->nr_args); 78 pr_debug("%d arguments\n", pp->nr_args);
83} 79}
@@ -120,34 +116,26 @@ static int opt_del_probe_event(const struct option *opt __used,
120 return 0; 116 return 0;
121} 117}
122 118
119/* Currently just checking function name from symbol map */
120static void evaluate_probe_point(struct probe_point *pp)
121{
122 struct symbol *sym;
123 sym = map__find_symbol_by_name(session.kmap, pp->function,
124 session.psession, NULL);
125 if (!sym)
126 die("Kernel symbol \'%s\' not found - probe not added.",
127 pp->function);
128}
129
123#ifndef NO_LIBDWARF 130#ifndef NO_LIBDWARF
124static int open_default_vmlinux(void) 131static int open_vmlinux(void)
125{ 132{
126 struct utsname uts; 133 if (map__load(session.kmap, session.psession, NULL) < 0) {
127 char fname[MAX_PATH_LEN]; 134 pr_debug("Failed to load kernel map.\n");
128 int fd, ret, i; 135 return -EINVAL;
129
130 ret = uname(&uts);
131 if (ret) {
132 pr_debug("uname() failed.\n");
133 return -errno;
134 }
135 session.release = uts.release;
136 for (i = 0; i < NR_SEARCH_PATH; i++) {
137 ret = snprintf(fname, MAX_PATH_LEN,
138 default_search_path[i], session.release);
139 if (ret >= MAX_PATH_LEN || ret < 0) {
140 pr_debug("Filename(%d,%s) is too long.\n", i,
141 uts.release);
142 errno = E2BIG;
143 return -E2BIG;
144 }
145 pr_debug("try to open %s\n", fname);
146 fd = open(fname, O_RDONLY);
147 if (fd >= 0)
148 break;
149 } 136 }
150 return fd; 137 pr_debug("Try to open %s\n", session.kmap->dso->long_name);
138 return open(session.kmap->dso->long_name, O_RDONLY);
151} 139}
152#endif 140#endif
153 141
@@ -163,21 +151,22 @@ static const struct option options[] = {
163 OPT_BOOLEAN('v', "verbose", &verbose, 151 OPT_BOOLEAN('v', "verbose", &verbose,
164 "be more verbose (show parsed arguments, etc)"), 152 "be more verbose (show parsed arguments, etc)"),
165#ifndef NO_LIBDWARF 153#ifndef NO_LIBDWARF
166 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 154 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
167 "vmlinux/module pathname"), 155 "file", "vmlinux pathname"),
168#endif 156#endif
169 OPT_BOOLEAN('l', "list", &listing, "list up current probe events"), 157 OPT_BOOLEAN('l', "list", &session.list_events,
158 "list up current probe events"),
170 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
171 opt_del_probe_event), 160 opt_del_probe_event),
172 OPT_CALLBACK('a', "add", NULL, 161 OPT_CALLBACK('a', "add", NULL,
173#ifdef NO_LIBDWARF 162#ifdef NO_LIBDWARF
174 "FUNC[+OFFS|%return] [ARG ...]", 163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]",
175#else 164#else
176 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
177#endif 166#endif
178 "probe point definition, where\n" 167 "probe point definition, where\n"
179 "\t\tGRP:\tGroup name (optional)\n" 168 "\t\tGROUP:\tGroup name (optional)\n"
180 "\t\tNAME:\tEvent name\n" 169 "\t\tEVENT:\tEvent name\n"
181 "\t\tFUNC:\tFunction name\n" 170 "\t\tFUNC:\tFunction name\n"
182 "\t\tOFFS:\tOffset from function entry (in byte)\n" 171 "\t\tOFFS:\tOffset from function entry (in byte)\n"
183 "\t\t%return:\tPut the probe at function return\n" 172 "\t\t%return:\tPut the probe at function return\n"
@@ -191,6 +180,8 @@ static const struct option options[] = {
191#endif 180#endif
192 "\t\t\tkprobe-tracer argument format.)\n", 181 "\t\t\tkprobe-tracer argument format.)\n",
193 opt_add_probe_event), 182 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
184 " with existing name"),
194 OPT_END() 185 OPT_END()
195}; 186};
196 187
@@ -204,13 +195,21 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
204 195
205 argc = parse_options(argc, argv, options, probe_usage, 196 argc = parse_options(argc, argv, options, probe_usage,
206 PARSE_OPT_STOP_AT_NON_OPTION); 197 PARSE_OPT_STOP_AT_NON_OPTION);
207 if (argc > 0) 198 if (argc > 0) {
199 if (strcmp(argv[0], "-") == 0) {
200 pr_warning(" Error: '-' is not supported.\n");
201 usage_with_options(probe_usage, options);
202 }
208 parse_probe_event_argv(argc, argv); 203 parse_probe_event_argv(argc, argv);
204 }
209 205
210 if ((session.nr_probe == 0 && !session.dellist && !listing)) 206 if ((!session.nr_probe && !session.dellist && !session.list_events))
211 usage_with_options(probe_usage, options); 207 usage_with_options(probe_usage, options);
212 208
213 if (listing) { 209 if (debugfs_valid_mountpoint(debugfs_path) < 0)
210 die("Failed to find debugfs path.");
211
212 if (session.list_events) {
214 if (session.nr_probe != 0 || session.dellist) { 213 if (session.nr_probe != 0 || session.dellist) {
215 pr_warning(" Error: Don't use --list with" 214 pr_warning(" Error: Don't use --list with"
216 " --add/--del.\n"); 215 " --add/--del.\n");
@@ -227,17 +226,28 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
227 return 0; 226 return 0;
228 } 227 }
229 228
229 /* Initialize symbol maps for vmlinux */
230 symbol_conf.sort_by_name = true;
231 if (symbol_conf.vmlinux_name == NULL)
232 symbol_conf.try_vmlinux_path = true;
233 if (symbol__init() < 0)
234 die("Failed to init symbol map.");
235 session.psession = perf_session__new(NULL, O_WRONLY, false);
236 if (session.psession == NULL)
237 die("Failed to init perf_session.");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
239 MAP__FUNCTION,
240 "[kernel.kallsyms]");
241 if (!session.kmap)
242 die("Could not find kernel map.\n");
243
230 if (session.need_dwarf) 244 if (session.need_dwarf)
231#ifdef NO_LIBDWARF 245#ifdef NO_LIBDWARF
232 die("Debuginfo-analysis is not supported"); 246 die("Debuginfo-analysis is not supported");
233#else /* !NO_LIBDWARF */ 247#else /* !NO_LIBDWARF */
234 pr_debug("Some probes require debuginfo.\n"); 248 pr_debug("Some probes require debuginfo.\n");
235 249
236 if (session.vmlinux) { 250 fd = open_vmlinux();
237 pr_debug("Try to open %s.", session.vmlinux);
238 fd = open(session.vmlinux, O_RDONLY);
239 } else
240 fd = open_default_vmlinux();
241 if (fd < 0) { 251 if (fd < 0) {
242 if (session.need_dwarf) 252 if (session.need_dwarf)
243 die("Could not open debuginfo file."); 253 die("Could not open debuginfo file.");
@@ -255,15 +265,22 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
255 265
256 lseek(fd, SEEK_SET, 0); 266 lseek(fd, SEEK_SET, 0);
257 ret = find_probepoint(fd, pp); 267 ret = find_probepoint(fd, pp);
258 if (ret < 0) { 268 if (ret > 0)
259 if (session.need_dwarf) 269 continue;
260 die("Could not analyze debuginfo."); 270 if (ret == 0) { /* No error but failed to find probe point. */
261 271 synthesize_perf_probe_point(pp);
262 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n"); 272 die("Probe point '%s' not found. - probe not added.",
263 break; 273 pp->probes[0]);
264 } 274 }
265 if (ret == 0) /* No error but failed to find probe point. */ 275 /* Error path */
266 die("No probe point found."); 276 if (session.need_dwarf) {
277 if (ret == -ENOENT)
278 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
279 die("Could not analyze debuginfo.");
280 }
281 pr_debug("An error occurred in debuginfo analysis."
282 " Try to use symbols.\n");
283 break;
267 } 284 }
268 close(fd); 285 close(fd);
269 286
@@ -276,6 +293,7 @@ end_dwarf:
276 if (pp->found) /* This probe is already found. */ 293 if (pp->found) /* This probe is already found. */
277 continue; 294 continue;
278 295
296 evaluate_probe_point(pp);
279 ret = synthesize_trace_kprobe_event(pp); 297 ret = synthesize_trace_kprobe_event(pp);
280 if (ret == -E2BIG) 298 if (ret == -E2BIG)
281 die("probe point definition becomes too long."); 299 die("probe point definition becomes too long.");
@@ -284,7 +302,8 @@ end_dwarf:
284 } 302 }
285 303
286 /* Settng up probe points */ 304 /* Settng up probe points */
287 add_trace_kprobe_events(session.probes, session.nr_probe); 305 add_trace_kprobe_events(session.probes, session.nr_probe,
306 session.force_add);
288 return 0; 307 return 0;
289} 308}
290 309
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0e519c667e3..63136d0534d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,6 +17,7 @@
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h" 18#include "util/event.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/session.h"
20#include "util/symbol.h" 21#include "util/symbol.h"
21 22
22#include <unistd.h> 23#include <unistd.h>
@@ -62,7 +63,7 @@ static int nr_cpu = 0;
62 63
63static int file_new = 1; 64static int file_new = 1;
64 65
65struct perf_header *header = NULL; 66static struct perf_session *session;
66 67
67struct mmap_data { 68struct mmap_data {
68 int counter; 69 int counter;
@@ -122,7 +123,8 @@ static void write_event(event_t *buf, size_t size)
122 write_output(buf, size); 123 write_output(buf, size);
123} 124}
124 125
125static int process_synthesized_event(event_t *event) 126static int process_synthesized_event(event_t *event,
127 struct perf_session *self __used)
126{ 128{
127 write_event(event, event->header.size); 129 write_event(event, event->header.size);
128 return 0; 130 return 0;
@@ -216,12 +218,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
216{ 218{
217 struct perf_header_attr *h_attr; 219 struct perf_header_attr *h_attr;
218 220
219 if (nr < header->attrs) { 221 if (nr < session->header.attrs) {
220 h_attr = header->attr[nr]; 222 h_attr = session->header.attr[nr];
221 } else { 223 } else {
222 h_attr = perf_header_attr__new(a); 224 h_attr = perf_header_attr__new(a);
223 if (h_attr != NULL) 225 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) { 226 if (perf_header__add_attr(&session->header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr); 227 perf_header_attr__delete(h_attr);
226 h_attr = NULL; 228 h_attr = NULL;
227 } 229 }
@@ -276,7 +278,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
276 278
277 attr->mmap = track; 279 attr->mmap = track;
278 attr->comm = track; 280 attr->comm = track;
279 attr->inherit = (cpu < 0) && inherit; 281 attr->inherit = inherit;
280 attr->disabled = 1; 282 attr->disabled = 1;
281 283
282try_again: 284try_again:
@@ -395,12 +397,12 @@ static void open_counters(int cpu, pid_t pid)
395 397
396static void atexit_header(void) 398static void atexit_header(void)
397{ 399{
398 header->data_size += bytes_written; 400 session->header.data_size += bytes_written;
399 401
400 perf_header__write(header, output, true); 402 perf_header__write(&session->header, output, true);
401} 403}
402 404
403static int __cmd_record(int argc, const char **argv) 405static int __cmd_record(int argc __used, const char **argv)
404{ 406{
405 int i, counter; 407 int i, counter;
406 struct stat st; 408 struct stat st;
@@ -408,6 +410,8 @@ static int __cmd_record(int argc, const char **argv)
408 int flags; 410 int flags;
409 int err; 411 int err;
410 unsigned long waking = 0; 412 unsigned long waking = 0;
413 int child_ready_pipe[2], go_pipe[2];
414 char buf;
411 415
412 page_size = sysconf(_SC_PAGE_SIZE); 416 page_size = sysconf(_SC_PAGE_SIZE);
413 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 417 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -418,11 +422,25 @@ static int __cmd_record(int argc, const char **argv)
418 signal(SIGCHLD, sig_handler); 422 signal(SIGCHLD, sig_handler);
419 signal(SIGINT, sig_handler); 423 signal(SIGINT, sig_handler);
420 424
425 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
426 perror("failed to create pipes");
427 exit(-1);
428 }
429
421 if (!stat(output_name, &st) && st.st_size) { 430 if (!stat(output_name, &st) && st.st_size) {
422 if (!force && !append_file) { 431 if (!force) {
423 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 432 if (!append_file) {
424 output_name); 433 pr_err("Error, output file %s exists, use -A "
425 exit(-1); 434 "to append or -f to overwrite.\n",
435 output_name);
436 exit(-1);
437 }
438 } else {
439 char oldname[PATH_MAX];
440 snprintf(oldname, sizeof(oldname), "%s.old",
441 output_name);
442 unlink(oldname);
443 rename(output_name, oldname);
426 } 444 }
427 } else { 445 } else {
428 append_file = 0; 446 append_file = 0;
@@ -440,24 +458,24 @@ static int __cmd_record(int argc, const char **argv)
440 exit(-1); 458 exit(-1);
441 } 459 }
442 460
443 header = perf_header__new(); 461 session = perf_session__new(output_name, O_WRONLY, force);
444 if (header == NULL) { 462 if (session == NULL) {
445 pr_err("Not enough memory for reading perf file header\n"); 463 pr_err("Not enough memory for reading perf file header\n");
446 return -1; 464 return -1;
447 } 465 }
448 466
449 if (!file_new) { 467 if (!file_new) {
450 err = perf_header__read(header, output); 468 err = perf_header__read(&session->header, output);
451 if (err < 0) 469 if (err < 0)
452 return err; 470 return err;
453 } 471 }
454 472
455 if (raw_samples) { 473 if (raw_samples) {
456 perf_header__set_feat(header, HEADER_TRACE_INFO); 474 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
457 } else { 475 } else {
458 for (i = 0; i < nr_counters; i++) { 476 for (i = 0; i < nr_counters; i++) {
459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 477 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
460 perf_header__set_feat(header, HEADER_TRACE_INFO); 478 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
461 break; 479 break;
462 } 480 }
463 } 481 }
@@ -465,56 +483,79 @@ static int __cmd_record(int argc, const char **argv)
465 483
466 atexit(atexit_header); 484 atexit(atexit_header);
467 485
468 if (!system_wide) { 486 if (target_pid == -1) {
469 pid = target_pid; 487 pid = fork();
470 if (pid == -1) 488 if (pid < 0) {
471 pid = getpid(); 489 perror("failed to fork");
472 490 exit(-1);
473 open_counters(profile_cpu, pid);
474 } else {
475 if (profile_cpu != -1) {
476 open_counters(profile_cpu, target_pid);
477 } else {
478 for (i = 0; i < nr_cpus; i++)
479 open_counters(i, target_pid);
480 } 491 }
481 }
482 492
483 if (file_new) { 493 if (!pid) {
484 err = perf_header__write(header, output, false); 494 close(child_ready_pipe[0]);
485 if (err < 0) 495 close(go_pipe[1]);
486 return err; 496 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
487 }
488 497
489 if (!system_wide) 498 /*
490 event__synthesize_thread(pid, process_synthesized_event); 499 * Do a dummy execvp to get the PLT entry resolved,
491 else 500 * so we avoid the resolver overhead on the real
492 event__synthesize_threads(process_synthesized_event); 501 * execvp call.
502 */
503 execvp("", (char **)argv);
493 504
494 if (target_pid == -1 && argc) { 505 /*
495 pid = fork(); 506 * Tell the parent we're ready to go
496 if (pid < 0) 507 */
497 die("failed to fork"); 508 close(child_ready_pipe[1]);
498 509
499 if (!pid) {
500 if (execvp(argv[0], (char **)argv)) {
501 perror(argv[0]);
502 exit(-1);
503 }
504 } else {
505 /* 510 /*
506 * Wait a bit for the execv'ed child to appear 511 * Wait until the parent tells us to go.
507 * and be updated in /proc
508 * FIXME: Do you know a less heuristical solution?
509 */ 512 */
510 usleep(1000); 513 if (read(go_pipe[0], &buf, 1) == -1)
511 event__synthesize_thread(pid, 514 perror("unable to read pipe");
512 process_synthesized_event); 515
516 execvp(argv[0], (char **)argv);
517
518 perror(argv[0]);
519 exit(-1);
513 } 520 }
514 521
515 child_pid = pid; 522 child_pid = pid;
523
524 if (!system_wide)
525 target_pid = pid;
526
527 close(child_ready_pipe[1]);
528 close(go_pipe[0]);
529 /*
530 * wait for child to settle
531 */
532 if (read(child_ready_pipe[0], &buf, 1) == -1) {
533 perror("unable to read pipe");
534 exit(-1);
535 }
536 close(child_ready_pipe[0]);
537 }
538
539
540 if ((!system_wide && !inherit) || profile_cpu != -1) {
541 open_counters(profile_cpu, target_pid);
542 } else {
543 for (i = 0; i < nr_cpus; i++)
544 open_counters(i, target_pid);
516 } 545 }
517 546
547 if (file_new) {
548 err = perf_header__write(&session->header, output, false);
549 if (err < 0)
550 return err;
551 }
552
553 if (!system_wide)
554 event__synthesize_thread(pid, process_synthesized_event,
555 session);
556 else
557 event__synthesize_threads(process_synthesized_event, session);
558
518 if (realtime_prio) { 559 if (realtime_prio) {
519 struct sched_param param; 560 struct sched_param param;
520 561
@@ -525,6 +566,11 @@ static int __cmd_record(int argc, const char **argv)
525 } 566 }
526 } 567 }
527 568
569 /*
570 * Let the child rip
571 */
572 close(go_pipe[1]);
573
528 for (;;) { 574 for (;;) {
529 int hits = samples; 575 int hits = samples;
530 576
@@ -619,13 +665,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
619{ 665{
620 int counter; 666 int counter;
621 667
622 symbol__init(0);
623
624 argc = parse_options(argc, argv, options, record_usage, 668 argc = parse_options(argc, argv, options, record_usage,
625 PARSE_OPT_STOP_AT_NON_OPTION); 669 PARSE_OPT_STOP_AT_NON_OPTION);
626 if (!argc && target_pid == -1 && !system_wide) 670 if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1))
627 usage_with_options(record_usage, options); 671 usage_with_options(record_usage, options);
628 672
673 symbol__init();
674
629 if (!nr_counters) { 675 if (!nr_counters) {
630 nr_counters = 1; 676 nr_counters = 1;
631 attrs[0].type = PERF_TYPE_HARDWARE; 677 attrs[0].type = PERF_TYPE_HARDWARE;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2b9eb3a553e..5c2ab5357ec 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -22,471 +22,46 @@
22#include "perf.h" 22#include "perf.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/header.h" 24#include "util/header.h"
25#include "util/session.h"
25 26
26#include "util/parse-options.h" 27#include "util/parse-options.h"
27#include "util/parse-events.h" 28#include "util/parse-events.h"
28 29
29#include "util/data_map.h"
30#include "util/thread.h" 30#include "util/thread.h"
31#include "util/sort.h" 31#include "util/sort.h"
32#include "util/hist.h" 32#include "util/hist.h"
33 33
34static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
35 35
36static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
38static struct strlist *dso_list, *comm_list, *sym_list;
39
40static int force; 36static int force;
41 37
42static int full_paths;
43static int show_nr_samples;
44
45static int show_threads; 38static int show_threads;
46static struct perf_read_values show_threads_values; 39static struct perf_read_values show_threads_values;
47 40
48static char default_pretty_printing_style[] = "normal"; 41static char default_pretty_printing_style[] = "normal";
49static char *pretty_printing_style = default_pretty_printing_style; 42static char *pretty_printing_style = default_pretty_printing_style;
50 43
51static int exclude_other = 1;
52
53static char callchain_default_opt[] = "fractal,0.5"; 44static char callchain_default_opt[] = "fractal,0.5";
54 45
55static struct perf_header *header; 46static int perf_session__add_hist_entry(struct perf_session *self,
56 47 struct addr_location *al,
57static u64 sample_type; 48 struct ip_callchain *chain, u64 count)
58
59struct symbol_conf symbol_conf;
60
61
62static size_t
63callchain__fprintf_left_margin(FILE *fp, int left_margin)
64{
65 int i;
66 int ret;
67
68 ret = fprintf(fp, " ");
69
70 for (i = 0; i < left_margin; i++)
71 ret += fprintf(fp, " ");
72
73 return ret;
74}
75
76static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
77 int left_margin)
78{
79 int i;
80 size_t ret = 0;
81
82 ret += callchain__fprintf_left_margin(fp, left_margin);
83
84 for (i = 0; i < depth; i++)
85 if (depth_mask & (1 << i))
86 ret += fprintf(fp, "| ");
87 else
88 ret += fprintf(fp, " ");
89
90 ret += fprintf(fp, "\n");
91
92 return ret;
93}
94static size_t
95ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
96 int depth_mask, int count, u64 total_samples,
97 int hits, int left_margin)
98{
99 int i;
100 size_t ret = 0;
101
102 ret += callchain__fprintf_left_margin(fp, left_margin);
103 for (i = 0; i < depth; i++) {
104 if (depth_mask & (1 << i))
105 ret += fprintf(fp, "|");
106 else
107 ret += fprintf(fp, " ");
108 if (!count && i == depth - 1) {
109 double percent;
110
111 percent = hits * 100.0 / total_samples;
112 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
113 } else
114 ret += fprintf(fp, "%s", " ");
115 }
116 if (chain->sym)
117 ret += fprintf(fp, "%s\n", chain->sym->name);
118 else
119 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
120
121 return ret;
122}
123
124static struct symbol *rem_sq_bracket;
125static struct callchain_list rem_hits;
126
127static void init_rem_hits(void)
128{
129 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
130 if (!rem_sq_bracket) {
131 fprintf(stderr, "Not enough memory to display remaining hits\n");
132 return;
133 }
134
135 strcpy(rem_sq_bracket->name, "[...]");
136 rem_hits.sym = rem_sq_bracket;
137}
138
139static size_t
140__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
141 u64 total_samples, int depth, int depth_mask,
142 int left_margin)
143{
144 struct rb_node *node, *next;
145 struct callchain_node *child;
146 struct callchain_list *chain;
147 int new_depth_mask = depth_mask;
148 u64 new_total;
149 u64 remaining;
150 size_t ret = 0;
151 int i;
152
153 if (callchain_param.mode == CHAIN_GRAPH_REL)
154 new_total = self->children_hit;
155 else
156 new_total = total_samples;
157
158 remaining = new_total;
159
160 node = rb_first(&self->rb_root);
161 while (node) {
162 u64 cumul;
163
164 child = rb_entry(node, struct callchain_node, rb_node);
165 cumul = cumul_hits(child);
166 remaining -= cumul;
167
168 /*
169 * The depth mask manages the output of pipes that show
170 * the depth. We don't want to keep the pipes of the current
171 * level for the last child of this depth.
172 * Except if we have remaining filtered hits. They will
173 * supersede the last child
174 */
175 next = rb_next(node);
176 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
177 new_depth_mask &= ~(1 << (depth - 1));
178
179 /*
180 * But we keep the older depth mask for the line seperator
181 * to keep the level link until we reach the last child
182 */
183 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
184 left_margin);
185 i = 0;
186 list_for_each_entry(chain, &child->val, list) {
187 if (chain->ip >= PERF_CONTEXT_MAX)
188 continue;
189 ret += ipchain__fprintf_graph(fp, chain, depth,
190 new_depth_mask, i++,
191 new_total,
192 cumul,
193 left_margin);
194 }
195 ret += __callchain__fprintf_graph(fp, child, new_total,
196 depth + 1,
197 new_depth_mask | (1 << depth),
198 left_margin);
199 node = next;
200 }
201
202 if (callchain_param.mode == CHAIN_GRAPH_REL &&
203 remaining && remaining != new_total) {
204
205 if (!rem_sq_bracket)
206 return ret;
207
208 new_depth_mask &= ~(1 << (depth - 1));
209
210 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
211 new_depth_mask, 0, new_total,
212 remaining, left_margin);
213 }
214
215 return ret;
216}
217
218
219static size_t
220callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
221 u64 total_samples, int left_margin)
222{
223 struct callchain_list *chain;
224 bool printed = false;
225 int i = 0;
226 int ret = 0;
227
228 list_for_each_entry(chain, &self->val, list) {
229 if (chain->ip >= PERF_CONTEXT_MAX)
230 continue;
231
232 if (!i++ && sort__first_dimension == SORT_SYM)
233 continue;
234
235 if (!printed) {
236 ret += callchain__fprintf_left_margin(fp, left_margin);
237 ret += fprintf(fp, "|\n");
238 ret += callchain__fprintf_left_margin(fp, left_margin);
239 ret += fprintf(fp, "---");
240
241 left_margin += 3;
242 printed = true;
243 } else
244 ret += callchain__fprintf_left_margin(fp, left_margin);
245
246 if (chain->sym)
247 ret += fprintf(fp, " %s\n", chain->sym->name);
248 else
249 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
250 }
251
252 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
253
254 return ret;
255}
256
257static size_t
258callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
259 u64 total_samples)
260{
261 struct callchain_list *chain;
262 size_t ret = 0;
263
264 if (!self)
265 return 0;
266
267 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
268
269
270 list_for_each_entry(chain, &self->val, list) {
271 if (chain->ip >= PERF_CONTEXT_MAX)
272 continue;
273 if (chain->sym)
274 ret += fprintf(fp, " %s\n", chain->sym->name);
275 else
276 ret += fprintf(fp, " %p\n",
277 (void *)(long)chain->ip);
278 }
279
280 return ret;
281}
282
283static size_t
284hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
285 u64 total_samples, int left_margin)
286{
287 struct rb_node *rb_node;
288 struct callchain_node *chain;
289 size_t ret = 0;
290
291 rb_node = rb_first(&self->sorted_chain);
292 while (rb_node) {
293 double percent;
294
295 chain = rb_entry(rb_node, struct callchain_node, rb_node);
296 percent = chain->hit * 100.0 / total_samples;
297 switch (callchain_param.mode) {
298 case CHAIN_FLAT:
299 ret += percent_color_fprintf(fp, " %6.2f%%\n",
300 percent);
301 ret += callchain__fprintf_flat(fp, chain, total_samples);
302 break;
303 case CHAIN_GRAPH_ABS: /* Falldown */
304 case CHAIN_GRAPH_REL:
305 ret += callchain__fprintf_graph(fp, chain, total_samples,
306 left_margin);
307 case CHAIN_NONE:
308 default:
309 break;
310 }
311 ret += fprintf(fp, "\n");
312 rb_node = rb_next(rb_node);
313 }
314
315 return ret;
316}
317
318static size_t
319hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
320{
321 struct sort_entry *se;
322 size_t ret;
323
324 if (exclude_other && !self->parent)
325 return 0;
326
327 if (total_samples)
328 ret = percent_color_fprintf(fp,
329 field_sep ? "%.2f" : " %6.2f%%",
330 (self->count * 100.0) / total_samples);
331 else
332 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
333
334 if (show_nr_samples) {
335 if (field_sep)
336 fprintf(fp, "%c%lld", *field_sep, self->count);
337 else
338 fprintf(fp, "%11lld", self->count);
339 }
340
341 list_for_each_entry(se, &hist_entry__sort_list, list) {
342 if (se->elide)
343 continue;
344
345 fprintf(fp, "%s", field_sep ?: " ");
346 ret += se->print(fp, self, se->width ? *se->width : 0);
347 }
348
349 ret += fprintf(fp, "\n");
350
351 if (callchain) {
352 int left_margin = 0;
353
354 if (sort__first_dimension == SORT_COMM) {
355 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
356 list);
357 left_margin = se->width ? *se->width : 0;
358 left_margin -= thread__comm_len(self->thread);
359 }
360
361 hist_entry_callchain__fprintf(fp, self, total_samples,
362 left_margin);
363 }
364
365 return ret;
366}
367
368/*
369 *
370 */
371
372static void dso__calc_col_width(struct dso *self)
373{
374 if (!col_width_list_str && !field_sep &&
375 (!dso_list || strlist__has_entry(dso_list, self->name))) {
376 unsigned int slen = strlen(self->name);
377 if (slen > dsos__col_width)
378 dsos__col_width = slen;
379 }
380
381 self->slen_calculated = 1;
382}
383
384static void thread__comm_adjust(struct thread *self)
385{
386 char *comm = self->comm;
387
388 if (!col_width_list_str && !field_sep &&
389 (!comm_list || strlist__has_entry(comm_list, comm))) {
390 unsigned int slen = strlen(comm);
391
392 if (slen > comms__col_width) {
393 comms__col_width = slen;
394 threads__col_width = slen + 6;
395 }
396 }
397}
398
399static int thread__set_comm_adjust(struct thread *self, const char *comm)
400{
401 int ret = thread__set_comm(self, comm);
402
403 if (ret)
404 return ret;
405
406 thread__comm_adjust(self);
407
408 return 0;
409}
410
411static int call__match(struct symbol *sym)
412{
413 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
414 return 1;
415
416 return 0;
417}
418
419static struct symbol **resolve_callchain(struct thread *thread,
420 struct ip_callchain *chain,
421 struct symbol **parent)
422{
423 u8 cpumode = PERF_RECORD_MISC_USER;
424 struct symbol **syms = NULL;
425 unsigned int i;
426
427 if (callchain) {
428 syms = calloc(chain->nr, sizeof(*syms));
429 if (!syms) {
430 fprintf(stderr, "Can't allocate memory for symbols\n");
431 exit(-1);
432 }
433 }
434
435 for (i = 0; i < chain->nr; i++) {
436 u64 ip = chain->ips[i];
437 struct addr_location al;
438
439 if (ip >= PERF_CONTEXT_MAX) {
440 switch (ip) {
441 case PERF_CONTEXT_HV:
442 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
443 case PERF_CONTEXT_KERNEL:
444 cpumode = PERF_RECORD_MISC_KERNEL; break;
445 case PERF_CONTEXT_USER:
446 cpumode = PERF_RECORD_MISC_USER; break;
447 default:
448 break;
449 }
450 continue;
451 }
452
453 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
454 ip, &al, NULL);
455 if (al.sym != NULL) {
456 if (sort__has_parent && !*parent &&
457 call__match(al.sym))
458 *parent = al.sym;
459 if (!callchain)
460 break;
461 syms[i] = al.sym;
462 }
463 }
464
465 return syms;
466}
467
468/*
469 * collect histogram counts
470 */
471
472static int hist_entry__add(struct addr_location *al,
473 struct ip_callchain *chain, u64 count)
474{ 49{
475 struct symbol **syms = NULL, *parent = NULL; 50 struct symbol **syms = NULL, *parent = NULL;
476 bool hit; 51 bool hit;
477 struct hist_entry *he; 52 struct hist_entry *he;
478 53
479 if ((sort__has_parent || callchain) && chain) 54 if ((sort__has_parent || symbol_conf.use_callchain) && chain)
480 syms = resolve_callchain(al->thread, chain, &parent); 55 syms = perf_session__resolve_callchain(self, al->thread,
481 56 chain, &parent);
482 he = __hist_entry__add(al, parent, count, &hit); 57 he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
483 if (he == NULL) 58 if (he == NULL)
484 return -ENOMEM; 59 return -ENOMEM;
485 60
486 if (hit) 61 if (hit)
487 he->count += count; 62 he->count += count;
488 63
489 if (callchain) { 64 if (symbol_conf.use_callchain) {
490 if (!hit) 65 if (!hit)
491 callchain_init(&he->callchain); 66 callchain_init(&he->callchain);
492 append_chain(&he->callchain, chain, syms); 67 append_chain(&he->callchain, chain, syms);
@@ -496,100 +71,6 @@ static int hist_entry__add(struct addr_location *al,
496 return 0; 71 return 0;
497} 72}
498 73
499static size_t output__fprintf(FILE *fp, u64 total_samples)
500{
501 struct hist_entry *pos;
502 struct sort_entry *se;
503 struct rb_node *nd;
504 size_t ret = 0;
505 unsigned int width;
506 char *col_width = col_width_list_str;
507 int raw_printing_style;
508
509 raw_printing_style = !strcmp(pretty_printing_style, "raw");
510
511 init_rem_hits();
512
513 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
514 fprintf(fp, "#\n");
515
516 fprintf(fp, "# Overhead");
517 if (show_nr_samples) {
518 if (field_sep)
519 fprintf(fp, "%cSamples", *field_sep);
520 else
521 fputs(" Samples ", fp);
522 }
523 list_for_each_entry(se, &hist_entry__sort_list, list) {
524 if (se->elide)
525 continue;
526 if (field_sep) {
527 fprintf(fp, "%c%s", *field_sep, se->header);
528 continue;
529 }
530 width = strlen(se->header);
531 if (se->width) {
532 if (col_width_list_str) {
533 if (col_width) {
534 *se->width = atoi(col_width);
535 col_width = strchr(col_width, ',');
536 if (col_width)
537 ++col_width;
538 }
539 }
540 width = *se->width = max(*se->width, width);
541 }
542 fprintf(fp, " %*s", width, se->header);
543 }
544 fprintf(fp, "\n");
545
546 if (field_sep)
547 goto print_entries;
548
549 fprintf(fp, "# ........");
550 if (show_nr_samples)
551 fprintf(fp, " ..........");
552 list_for_each_entry(se, &hist_entry__sort_list, list) {
553 unsigned int i;
554
555 if (se->elide)
556 continue;
557
558 fprintf(fp, " ");
559 if (se->width)
560 width = *se->width;
561 else
562 width = strlen(se->header);
563 for (i = 0; i < width; i++)
564 fprintf(fp, ".");
565 }
566 fprintf(fp, "\n");
567
568 fprintf(fp, "#\n");
569
570print_entries:
571 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
572 pos = rb_entry(nd, struct hist_entry, rb_node);
573 ret += hist_entry__fprintf(fp, pos, total_samples);
574 }
575
576 if (sort_order == default_sort_order &&
577 parent_pattern == default_parent_pattern) {
578 fprintf(fp, "#\n");
579 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
580 fprintf(fp, "#\n");
581 }
582 fprintf(fp, "\n");
583
584 free(rem_sq_bracket);
585
586 if (show_threads)
587 perf_read_values_display(fp, &show_threads_values,
588 raw_printing_style);
589
590 return ret;
591}
592
593static int validate_chain(struct ip_callchain *chain, event_t *event) 74static int validate_chain(struct ip_callchain *chain, event_t *event)
594{ 75{
595 unsigned int chain_size; 76 unsigned int chain_size;
@@ -603,17 +84,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
603 return 0; 84 return 0;
604} 85}
605 86
606static int process_sample_event(event_t *event) 87static int process_sample_event(event_t *event, struct perf_session *session)
607{ 88{
608 struct sample_data data; 89 struct sample_data data = { .period = 1, };
609 int cpumode;
610 struct addr_location al; 90 struct addr_location al;
611 struct thread *thread;
612
613 memset(&data, 0, sizeof(data));
614 data.period = 1;
615 91
616 event__parse_sample(event, sample_type, &data); 92 event__parse_sample(event, session->sample_type, &data);
617 93
618 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
619 event->header.misc, 95 event->header.misc,
@@ -621,7 +97,7 @@ static int process_sample_event(event_t *event)
621 (void *)(long)data.ip, 97 (void *)(long)data.ip,
622 (long long)data.period); 98 (long long)data.period);
623 99
624 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
625 unsigned int i; 101 unsigned int i;
626 102
627 dump_printf("... chain: nr:%Lu\n", data.callchain->nr); 103 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
@@ -639,69 +115,29 @@ static int process_sample_event(event_t *event)
639 } 115 }
640 } 116 }
641 117
642 thread = threads__findnew(data.pid); 118 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
643 if (thread == NULL) { 119 fprintf(stderr, "problem processing %d event, skipping it.\n",
644 pr_debug("problem processing %d event, skipping it.\n",
645 event->header.type); 120 event->header.type);
646 return -1; 121 return -1;
647 } 122 }
648 123
649 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 124 if (al.filtered)
650
651 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
652 return 0;
653
654 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
655
656 thread__find_addr_location(thread, cpumode,
657 MAP__FUNCTION, data.ip, &al, NULL);
658 /*
659 * We have to do this here as we may have a dso with no symbol hit that
660 * has a name longer than the ones with symbols sampled.
661 */
662 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
663 dso__calc_col_width(al.map->dso);
664
665 if (dso_list &&
666 (!al.map || !al.map->dso ||
667 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
668 (al.map->dso->short_name != al.map->dso->long_name &&
669 strlist__has_entry(dso_list, al.map->dso->long_name)))))
670 return 0; 125 return 0;
671 126
672 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name)) 127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
673 return 0;
674
675 if (hist_entry__add(&al, data.callchain, data.period)) {
676 pr_debug("problem incrementing symbol count, skipping event\n"); 128 pr_debug("problem incrementing symbol count, skipping event\n");
677 return -1; 129 return -1;
678 } 130 }
679 131
680 event__stats.total += data.period; 132 session->events_stats.total += data.period;
681
682 return 0; 133 return 0;
683} 134}
684 135
685static int process_comm_event(event_t *event) 136static int process_read_event(event_t *event, struct perf_session *session __used)
686{
687 struct thread *thread = threads__findnew(event->comm.pid);
688
689 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
690
691 if (thread == NULL ||
692 thread__set_comm_adjust(thread, event->comm.comm)) {
693 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
694 return -1;
695 }
696
697 return 0;
698}
699
700static int process_read_event(event_t *event)
701{ 137{
702 struct perf_event_attr *attr; 138 struct perf_event_attr *attr;
703 139
704 attr = perf_header__find_attr(event->read.id, header); 140 attr = perf_header__find_attr(event->read.id, &session->header);
705 141
706 if (show_threads) { 142 if (show_threads) {
707 const char *name = attr ? __event_name(attr->type, attr->config) 143 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -720,25 +156,23 @@ static int process_read_event(event_t *event)
720 return 0; 156 return 0;
721} 157}
722 158
723static int sample_type_check(u64 type) 159static int sample_type_check(struct perf_session *session)
724{ 160{
725 sample_type = type; 161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
726
727 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
728 if (sort__has_parent) { 162 if (sort__has_parent) {
729 fprintf(stderr, "selected --sort parent, but no" 163 fprintf(stderr, "selected --sort parent, but no"
730 " callchain data. Did you call" 164 " callchain data. Did you call"
731 " perf record without -g?\n"); 165 " perf record without -g?\n");
732 return -1; 166 return -1;
733 } 167 }
734 if (callchain) { 168 if (symbol_conf.use_callchain) {
735 fprintf(stderr, "selected -g but no callchain data." 169 fprintf(stderr, "selected -g but no callchain data."
736 " Did you call perf record without" 170 " Did you call perf record without"
737 " -g?\n"); 171 " -g?\n");
738 return -1; 172 return -1;
739 } 173 }
740 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) {
741 callchain = 1; 175 symbol_conf.use_callchain = true;
742 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
743 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
744 " params\n"); 178 " params\n");
@@ -749,10 +183,10 @@ static int sample_type_check(u64 type)
749 return 0; 183 return 0;
750} 184}
751 185
752static struct perf_file_handler file_handler = { 186static struct perf_event_ops event_ops = {
753 .process_sample_event = process_sample_event, 187 .process_sample_event = process_sample_event,
754 .process_mmap_event = event__process_mmap, 188 .process_mmap_event = event__process_mmap,
755 .process_comm_event = process_comm_event, 189 .process_comm_event = event__process_comm,
756 .process_exit_event = event__process_task, 190 .process_exit_event = event__process_task,
757 .process_fork_event = event__process_task, 191 .process_fork_event = event__process_task,
758 .process_lost_event = event__process_lost, 192 .process_lost_event = event__process_lost,
@@ -763,40 +197,47 @@ static struct perf_file_handler file_handler = {
763 197
764static int __cmd_report(void) 198static int __cmd_report(void)
765{ 199{
766 struct thread *idle;
767 int ret; 200 int ret;
201 struct perf_session *session;
768 202
769 idle = register_idle_thread(); 203 session = perf_session__new(input_name, O_RDONLY, force);
770 thread__comm_adjust(idle); 204 if (session == NULL)
205 return -ENOMEM;
771 206
772 if (show_threads) 207 if (show_threads)
773 perf_read_values_init(&show_threads_values); 208 perf_read_values_init(&show_threads_values);
774 209
775 register_perf_file_handler(&file_handler); 210 ret = perf_session__process_events(session, &event_ops);
776
777 ret = mmap_dispatch_perf_file(&header, input_name, force,
778 full_paths, &event__cwdlen, &event__cwd);
779 if (ret) 211 if (ret)
780 return ret; 212 goto out_delete;
781 213
782 if (dump_trace) { 214 if (dump_trace) {
783 event__print_totals(); 215 event__print_totals();
784 return 0; 216 goto out_delete;
785 } 217 }
786 218
787 if (verbose > 3) 219 if (verbose > 3)
788 threads__fprintf(stdout); 220 perf_session__fprintf(session, stdout);
789 221
790 if (verbose > 2) 222 if (verbose > 2)
791 dsos__fprintf(stdout); 223 dsos__fprintf(stdout);
792 224
793 collapse__resort(); 225 perf_session__collapse_resort(session);
794 output__resort(event__stats.total); 226 perf_session__output_resort(session, session->events_stats.total);
795 output__fprintf(stdout, event__stats.total); 227 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total);
228 perf_session__fprintf_hists(session, NULL, false, stdout);
229 if (sort_order == default_sort_order &&
230 parent_pattern == default_parent_pattern)
231 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
796 232
797 if (show_threads) 233 if (show_threads) {
234 bool raw_printing_style = !strcmp(pretty_printing_style, "raw");
235 perf_read_values_display(stdout, &show_threads_values,
236 raw_printing_style);
798 perf_read_values_destroy(&show_threads_values); 237 perf_read_values_destroy(&show_threads_values);
799 238 }
239out_delete:
240 perf_session__delete(session);
800 return ret; 241 return ret;
801} 242}
802 243
@@ -807,7 +248,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
807 char *tok; 248 char *tok;
808 char *endptr; 249 char *endptr;
809 250
810 callchain = 1; 251 symbol_conf.use_callchain = true;
811 252
812 if (!arg) 253 if (!arg)
813 return 0; 254 return 0;
@@ -828,7 +269,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
828 269
829 else if (!strncmp(tok, "none", strlen(arg))) { 270 else if (!strncmp(tok, "none", strlen(arg))) {
830 callchain_param.mode = CHAIN_NONE; 271 callchain_param.mode = CHAIN_NONE;
831 callchain = 0; 272 symbol_conf.use_callchain = true;
832 273
833 return 0; 274 return 0;
834 } 275 }
@@ -871,7 +312,7 @@ static const struct option options[] = {
871 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 312 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
872 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 313 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
873 "load module symbols - WARNING: use only with -k and LIVE kernel"), 314 "load module symbols - WARNING: use only with -k and LIVE kernel"),
874 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 315 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
875 "Show a column with the number of samples"), 316 "Show a column with the number of samples"),
876 OPT_BOOLEAN('T', "threads", &show_threads, 317 OPT_BOOLEAN('T', "threads", &show_threads,
877 "Show per-thread event counters"), 318 "Show per-thread event counters"),
@@ -879,78 +320,46 @@ static const struct option options[] = {
879 "pretty printing style key: normal raw"), 320 "pretty printing style key: normal raw"),
880 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 321 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
881 "sort by key(s): pid, comm, dso, symbol, parent"), 322 "sort by key(s): pid, comm, dso, symbol, parent"),
882 OPT_BOOLEAN('P', "full-paths", &full_paths, 323 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
883 "Don't shorten the pathnames taking into account the cwd"), 324 "Don't shorten the pathnames taking into account the cwd"),
884 OPT_STRING('p', "parent", &parent_pattern, "regex", 325 OPT_STRING('p', "parent", &parent_pattern, "regex",
885 "regex filter to identify parent, see: '--sort parent'"), 326 "regex filter to identify parent, see: '--sort parent'"),
886 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 327 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
887 "Only display entries with parent-match"), 328 "Only display entries with parent-match"),
888 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 329 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
889 "Display callchains using output_type and min percent threshold. " 330 "Display callchains using output_type and min percent threshold. "
890 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 331 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
891 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 332 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
892 "only consider symbols in these dsos"), 333 "only consider symbols in these dsos"),
893 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 334 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
894 "only consider symbols in these comms"), 335 "only consider symbols in these comms"),
895 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 336 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
896 "only consider these symbols"), 337 "only consider these symbols"),
897 OPT_STRING('w', "column-widths", &col_width_list_str, 338 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
898 "width[,width...]", 339 "width[,width...]",
899 "don't try to adjust column width, use these fixed values"), 340 "don't try to adjust column width, use these fixed values"),
900 OPT_STRING('t', "field-separator", &field_sep, "separator", 341 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
901 "separator for columns, no spaces will be added between " 342 "separator for columns, no spaces will be added between "
902 "columns '.' is reserved."), 343 "columns '.' is reserved."),
903 OPT_END() 344 OPT_END()
904}; 345};
905 346
906static void setup_sorting(void) 347int cmd_report(int argc, const char **argv, const char *prefix __used)
907{ 348{
908 char *tmp, *tok, *str = strdup(sort_order); 349 argc = parse_options(argc, argv, options, report_usage, 0);
909
910 for (tok = strtok_r(str, ", ", &tmp);
911 tok; tok = strtok_r(NULL, ", ", &tmp)) {
912 if (sort_dimension__add(tok) < 0) {
913 error("Unknown --sort key: `%s'", tok);
914 usage_with_options(report_usage, options);
915 }
916 }
917
918 free(str);
919}
920 350
921static void setup_list(struct strlist **list, const char *list_str, 351 setup_pager();
922 struct sort_entry *se, const char *list_name,
923 FILE *fp)
924{
925 if (list_str) {
926 *list = strlist__new(true, list_str);
927 if (!*list) {
928 fprintf(stderr, "problems parsing %s list\n",
929 list_name);
930 exit(129);
931 }
932 if (strlist__nr_entries(*list) == 1) {
933 fprintf(fp, "# %s: %s\n", list_name,
934 strlist__entry(*list, 0)->s);
935 se->elide = true;
936 }
937 }
938}
939 352
940int cmd_report(int argc, const char **argv, const char *prefix __used) 353 if (symbol__init() < 0)
941{
942 if (symbol__init(&symbol_conf) < 0)
943 return -1; 354 return -1;
944 355
945 argc = parse_options(argc, argv, options, report_usage, 0); 356 setup_sorting(report_usage, options);
946
947 setup_sorting();
948 357
949 if (parent_pattern != default_parent_pattern) { 358 if (parent_pattern != default_parent_pattern) {
950 sort_dimension__add("parent"); 359 sort_dimension__add("parent");
951 sort_parent.elide = 1; 360 sort_parent.elide = 1;
952 } else 361 } else
953 exclude_other = 0; 362 symbol_conf.exclude_other = false;
954 363
955 /* 364 /*
956 * Any (unrecognized) arguments left? 365 * Any (unrecognized) arguments left?
@@ -958,17 +367,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
958 if (argc) 367 if (argc)
959 usage_with_options(report_usage, options); 368 usage_with_options(report_usage, options);
960 369
961 setup_pager(); 370 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
962 371 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
963 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 372 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
964 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
965 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
966
967 if (field_sep && *field_sep == '.') {
968 fputs("'.' is the only non valid --field-separator argument\n",
969 stderr);
970 exit(129);
971 }
972 373
973 return __cmd_report(); 374 return __cmd_report();
974} 375}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 7cca7c15b40..80209df6cfe 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,12 +6,12 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
12 13
13#include "util/debug.h" 14#include "util/debug.h"
14#include "util/data_map.h"
15 15
16#include <sys/prctl.h> 16#include <sys/prctl.h>
17 17
@@ -21,9 +21,6 @@
21 21
22static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
23 23
24static struct perf_header *header;
25static u64 sample_type;
26
27static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
28static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
29 26
@@ -731,18 +728,21 @@ struct trace_migrate_task_event {
731 728
732struct trace_sched_handler { 729struct trace_sched_handler {
733 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
734 struct event *, 732 struct event *,
735 int cpu, 733 int cpu,
736 u64 timestamp, 734 u64 timestamp,
737 struct thread *thread); 735 struct thread *thread);
738 736
739 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
740 struct event *, 739 struct event *,
741 int cpu, 740 int cpu,
742 u64 timestamp, 741 u64 timestamp,
743 struct thread *thread); 742 struct thread *thread);
744 743
745 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
746 struct event *, 746 struct event *,
747 int cpu, 747 int cpu,
748 u64 timestamp, 748 u64 timestamp,
@@ -755,6 +755,7 @@ struct trace_sched_handler {
755 struct thread *thread); 755 struct thread *thread);
756 756
757 void (*migrate_task_event)(struct trace_migrate_task_event *, 757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
758 struct event *, 759 struct event *,
759 int cpu, 760 int cpu,
760 u64 timestamp, 761 u64 timestamp,
@@ -764,6 +765,7 @@ struct trace_sched_handler {
764 765
765static void 766static void
766replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
767 struct event *event, 769 struct event *event,
768 int cpu __used, 770 int cpu __used,
769 u64 timestamp __used, 771 u64 timestamp __used,
@@ -790,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
790 792
791static void 793static void
792replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
793 struct event *event, 796 struct event *event,
794 int cpu, 797 int cpu,
795 u64 timestamp, 798 u64 timestamp,
@@ -1023,6 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1023 1026
1024static void 1027static void
1025latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1026 struct event *event __used, 1030 struct event *event __used,
1027 int cpu, 1031 int cpu,
1028 u64 timestamp, 1032 u64 timestamp,
@@ -1046,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1046 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1047 1051
1048 1052
1049 sched_out = threads__findnew(switch_event->prev_pid); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1050 sched_in = threads__findnew(switch_event->next_pid); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1051 1055
1052 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1053 if (!out_events) { 1057 if (!out_events) {
@@ -1075,12 +1079,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1075 1079
1076static void 1080static void
1077latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1078 struct event *event __used, 1083 struct event *event __used,
1079 int cpu, 1084 int cpu,
1080 u64 timestamp, 1085 u64 timestamp,
1081 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1082{ 1087{
1083 struct thread *thread = threads__findnew(runtime_event->pid); 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1089 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1085 1090
1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1097 1102
1098static void 1103static void
1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1100 struct event *__event __used, 1106 struct event *__event __used,
1101 int cpu __used, 1107 int cpu __used,
1102 u64 timestamp, 1108 u64 timestamp,
@@ -1110,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1110 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1111 return; 1117 return;
1112 1118
1113 wakee = threads__findnew(wakeup_event->pid); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1114 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1115 if (!atoms) { 1121 if (!atoms) {
1116 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1144,6 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1144 1150
1145static void 1151static void
1146latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1152latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1153 struct perf_session *session,
1147 struct event *__event __used, 1154 struct event *__event __used,
1148 int cpu __used, 1155 int cpu __used,
1149 u64 timestamp, 1156 u64 timestamp,
@@ -1159,7 +1166,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1159 if (profile_cpu == -1) 1166 if (profile_cpu == -1)
1160 return; 1167 return;
1161 1168
1162 migrant = threads__findnew(migrate_task_event->pid); 1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1163 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1164 if (!atoms) { 1171 if (!atoms) {
1165 thread_atoms_insert(migrant); 1172 thread_atoms_insert(migrant);
@@ -1354,7 +1361,7 @@ static void sort_lat(void)
1354static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1355 1362
1356static void 1363static void
1357process_sched_wakeup_event(void *data, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1358 struct event *event, 1365 struct event *event,
1359 int cpu __used, 1366 int cpu __used,
1360 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1371,7 +1378,8 @@ process_sched_wakeup_event(void *data,
1371 FILL_FIELD(wakeup_event, cpu, event, data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1372 1379
1373 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1374 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1375} 1383}
1376 1384
1377/* 1385/*
@@ -1389,6 +1397,7 @@ static char next_shortname2 = '0';
1389 1397
1390static void 1398static void
1391map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1392 struct event *event __used, 1401 struct event *event __used,
1393 int this_cpu, 1402 int this_cpu,
1394 u64 timestamp, 1403 u64 timestamp,
@@ -1416,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1416 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1417 1426
1418 1427
1419 sched_out = threads__findnew(switch_event->prev_pid); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1420 sched_in = threads__findnew(switch_event->next_pid); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1421 1430
1422 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1423 1432
@@ -1467,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1467 1476
1468 1477
1469static void 1478static void
1470process_sched_switch_event(void *data, 1479process_sched_switch_event(void *data, struct perf_session *session,
1471 struct event *event, 1480 struct event *event,
1472 int this_cpu, 1481 int this_cpu,
1473 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1494,13 +1503,14 @@ process_sched_switch_event(void *data,
1494 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1495 } 1504 }
1496 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1497 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread); 1506 trace_handler->switch_event(&switch_event, session, event,
1507 this_cpu, timestamp, thread);
1498 1508
1499 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1500} 1510}
1501 1511
1502static void 1512static void
1503process_sched_runtime_event(void *data, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1504 struct event *event, 1514 struct event *event,
1505 int cpu __used, 1515 int cpu __used,
1506 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1514,7 +1524,7 @@ process_sched_runtime_event(void *data,
1514 FILL_FIELD(runtime_event, vruntime, event, data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1515 1525
1516 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1517 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1518} 1528}
1519 1529
1520static void 1530static void
@@ -1534,7 +1544,8 @@ process_sched_fork_event(void *data,
1534 FILL_FIELD(fork_event, child_pid, event, data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1535 1545
1536 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1537 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1538} 1549}
1539 1550
1540static void 1551static void
@@ -1548,7 +1559,7 @@ process_sched_exit_event(struct event *event,
1548} 1559}
1549 1560
1550static void 1561static void
1551process_sched_migrate_task_event(void *data, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1552 struct event *event, 1563 struct event *event,
1553 int cpu __used, 1564 int cpu __used,
1554 u64 timestamp __used, 1565 u64 timestamp __used,
@@ -1564,12 +1575,13 @@ process_sched_migrate_task_event(void *data,
1564 FILL_FIELD(migrate_task_event, cpu, event, data); 1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1565 1576
1566 if (trace_handler->migrate_task_event) 1577 if (trace_handler->migrate_task_event)
1567 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); 1578 trace_handler->migrate_task_event(&migrate_task_event, session,
1579 event, cpu, timestamp, thread);
1568} 1580}
1569 1581
1570static void 1582static void
1571process_raw_event(event_t *raw_event __used, void *data, 1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1572 int cpu, u64 timestamp, struct thread *thread) 1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1573{ 1585{
1574 struct event *event; 1586 struct event *event;
1575 int type; 1587 int type;
@@ -1579,27 +1591,27 @@ process_raw_event(event_t *raw_event __used, void *data,
1579 event = trace_find_event(type); 1591 event = trace_find_event(type);
1580 1592
1581 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1582 process_sched_switch_event(data, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1583 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1584 process_sched_runtime_event(data, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1585 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1586 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1587 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1588 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1589 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1590 process_sched_fork_event(data, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1591 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1592 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_migrate_task")) 1605 if (!strcmp(event->name, "sched_migrate_task"))
1594 process_sched_migrate_task_event(data, event, cpu, timestamp, thread); 1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1595} 1607}
1596 1608
1597static int process_sample_event(event_t *event) 1609static int process_sample_event(event_t *event, struct perf_session *session)
1598{ 1610{
1599 struct sample_data data; 1611 struct sample_data data;
1600 struct thread *thread; 1612 struct thread *thread;
1601 1613
1602 if (!(sample_type & PERF_SAMPLE_RAW)) 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1603 return 0; 1615 return 0;
1604 1616
1605 memset(&data, 0, sizeof(data)); 1617 memset(&data, 0, sizeof(data));
@@ -1607,7 +1619,7 @@ static int process_sample_event(event_t *event)
1607 data.cpu = -1; 1619 data.cpu = -1;
1608 data.period = -1; 1620 data.period = -1;
1609 1621
1610 event__parse_sample(event, sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1611 1623
1612 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1613 event->header.misc, 1625 event->header.misc,
@@ -1615,7 +1627,7 @@ static int process_sample_event(event_t *event)
1615 (void *)(long)data.ip, 1627 (void *)(long)data.ip,
1616 (long long)data.period); 1628 (long long)data.period);
1617 1629
1618 thread = threads__findnew(data.pid); 1630 thread = perf_session__findnew(session, data.pid);
1619 if (thread == NULL) { 1631 if (thread == NULL) {
1620 pr_debug("problem processing %d event, skipping it.\n", 1632 pr_debug("problem processing %d event, skipping it.\n",
1621 event->header.type); 1633 event->header.type);
@@ -1627,12 +1639,13 @@ static int process_sample_event(event_t *event)
1627 if (profile_cpu != -1 && profile_cpu != (int)data.cpu) 1639 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1628 return 0; 1640 return 0;
1629 1641
1630 process_raw_event(event, data.raw_data, data.cpu, data.time, thread); 1642 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1631 1643
1632 return 0; 1644 return 0;
1633} 1645}
1634 1646
1635static int process_lost_event(event_t *event __used) 1647static int process_lost_event(event_t *event __used,
1648 struct perf_session *session __used)
1636{ 1649{
1637 nr_lost_chunks++; 1650 nr_lost_chunks++;
1638 nr_lost_events += event->lost.lost; 1651 nr_lost_events += event->lost.lost;
@@ -1640,11 +1653,9 @@ static int process_lost_event(event_t *event __used)
1640 return 0; 1653 return 0;
1641} 1654}
1642 1655
1643static int sample_type_check(u64 type) 1656static int sample_type_check(struct perf_session *session __used)
1644{ 1657{
1645 sample_type = type; 1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1646
1647 if (!(sample_type & PERF_SAMPLE_RAW)) {
1648 fprintf(stderr, 1659 fprintf(stderr,
1649 "No trace sample to read. Did you call perf record " 1660 "No trace sample to read. Did you call perf record "
1650 "without -R?"); 1661 "without -R?");
@@ -1654,7 +1665,7 @@ static int sample_type_check(u64 type)
1654 return 0; 1665 return 0;
1655} 1666}
1656 1667
1657static struct perf_file_handler file_handler = { 1668static struct perf_event_ops event_ops = {
1658 .process_sample_event = process_sample_event, 1669 .process_sample_event = process_sample_event,
1659 .process_comm_event = event__process_comm, 1670 .process_comm_event = event__process_comm,
1660 .process_lost_event = process_lost_event, 1671 .process_lost_event = process_lost_event,
@@ -1663,11 +1674,14 @@ static struct perf_file_handler file_handler = {
1663 1674
1664static int read_events(void) 1675static int read_events(void)
1665{ 1676{
1666 register_idle_thread(); 1677 int err;
1667 register_perf_file_handler(&file_handler); 1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1679 if (session == NULL)
1680 return -ENOMEM;
1668 1681
1669 return mmap_dispatch_perf_file(&header, input_name, 0, 0, 1682 err = perf_session__process_events(session, &event_ops);
1670 &event__cwdlen, &event__cwd); 1683 perf_session__delete(session);
1684 return err;
1671} 1685}
1672 1686
1673static void print_bad_events(void) 1687static void print_bad_events(void)
@@ -1897,7 +1911,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1897 if (!strcmp(argv[0], "trace")) 1911 if (!strcmp(argv[0], "trace"))
1898 return cmd_trace(argc, argv, prefix); 1912 return cmd_trace(argc, argv, prefix);
1899 1913
1900 symbol__init(0); 1914 symbol__init();
1901 if (!strncmp(argv[0], "rec", 3)) { 1915 if (!strncmp(argv[0], "rec", 3)) {
1902 return __cmd_record(argc, argv); 1916 return __cmd_record(argc, argv);
1903 } else if (!strncmp(argv[0], "lat", 3)) { 1917 } else if (!strncmp(argv[0], "lat", 3)) {
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index f472df9561e..a589a43112d 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,15 +30,12 @@
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h" 32#include "util/event.h"
33#include "util/data_map.h" 33#include "util/session.h"
34#include "util/svghelper.h" 34#include "util/svghelper.h"
35 35
36static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
37static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
38 38
39
40static u64 sample_type;
41
42static unsigned int numcpus; 39static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */ 40static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */ 41static u64 max_freq; /* Highest CPU frequency seen */
@@ -281,21 +278,19 @@ static int cpus_cstate_state[MAX_CPUS];
281static u64 cpus_pstate_start_times[MAX_CPUS]; 278static u64 cpus_pstate_start_times[MAX_CPUS];
282static u64 cpus_pstate_state[MAX_CPUS]; 279static u64 cpus_pstate_state[MAX_CPUS];
283 280
284static int 281static int process_comm_event(event_t *event, struct perf_session *session __used)
285process_comm_event(event_t *event)
286{ 282{
287 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.pid, event->comm.comm);
288 return 0; 284 return 0;
289} 285}
290static int 286
291process_fork_event(event_t *event) 287static int process_fork_event(event_t *event, struct perf_session *session __used)
292{ 288{
293 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
294 return 0; 290 return 0;
295} 291}
296 292
297static int 293static int process_exit_event(event_t *event, struct perf_session *session __used)
298process_exit_event(event_t *event)
299{ 294{
300 pid_exit(event->fork.pid, event->fork.time); 295 pid_exit(event->fork.pid, event->fork.time);
301 return 0; 296 return 0;
@@ -480,17 +475,16 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
480} 475}
481 476
482 477
483static int 478static int process_sample_event(event_t *event, struct perf_session *session)
484process_sample_event(event_t *event)
485{ 479{
486 struct sample_data data; 480 struct sample_data data;
487 struct trace_entry *te; 481 struct trace_entry *te;
488 482
489 memset(&data, 0, sizeof(data)); 483 memset(&data, 0, sizeof(data));
490 484
491 event__parse_sample(event, sample_type, &data); 485 event__parse_sample(event, session->sample_type, &data);
492 486
493 if (sample_type & PERF_SAMPLE_TIME) { 487 if (session->sample_type & PERF_SAMPLE_TIME) {
494 if (!first_time || first_time > data.time) 488 if (!first_time || first_time > data.time)
495 first_time = data.time; 489 first_time = data.time;
496 if (last_time < data.time) 490 if (last_time < data.time)
@@ -498,7 +492,7 @@ process_sample_event(event_t *event)
498 } 492 }
499 493
500 te = (void *)data.raw_data; 494 te = (void *)data.raw_data;
501 if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
502 char *event_str; 496 char *event_str;
503 struct power_entry *pe; 497 struct power_entry *pe;
504 498
@@ -575,16 +569,16 @@ static void end_sample_processing(void)
575 } 569 }
576} 570}
577 571
578static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
579{ 573{
580 int cursor; 574 int cursor;
581 575
582 cursor = 0; 576 cursor = 0;
583 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
584 cursor++; 578 cursor++;
585 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
586 cursor++; 580 cursor++;
587 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
588 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
589 return 0; 583 return 0;
590} 584}
@@ -594,8 +588,7 @@ static u64 sample_time(event_t *event)
594 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
595 * The order will get flipped later. 589 * The order will get flipped later.
596 */ 590 */
597static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
598queue_sample_event(event_t *event)
599{ 592{
600 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
601 int size; 594 int size;
@@ -609,7 +602,7 @@ queue_sample_event(event_t *event)
609 memset(copy, 0, size); 602 memset(copy, 0, size);
610 603
611 copy->next = NULL; 604 copy->next = NULL;
612 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
613 606
614 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
615 608
@@ -1021,7 +1014,7 @@ static void write_svg_file(const char *filename)
1021 svg_close(); 1014 svg_close();
1022} 1015}
1023 1016
1024static void process_samples(void) 1017static void process_samples(struct perf_session *session)
1025{ 1018{
1026 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
1027 event_t *event; 1020 event_t *event;
@@ -1032,15 +1025,13 @@ static void process_samples(void)
1032 while (cursor) { 1025 while (cursor) {
1033 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1034 cursor = cursor->next; 1027 cursor = cursor->next;
1035 process_sample_event(event); 1028 process_sample_event(event, session);
1036 } 1029 }
1037} 1030}
1038 1031
1039static int sample_type_check(u64 type) 1032static int sample_type_check(struct perf_session *session)
1040{ 1033{
1041 sample_type = type; 1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1042
1043 if (!(sample_type & PERF_SAMPLE_RAW)) {
1044 fprintf(stderr, "No trace samples found in the file.\n" 1035 fprintf(stderr, "No trace samples found in the file.\n"
1045 "Have you used 'perf timechart record' to record it?\n"); 1036 "Have you used 'perf timechart record' to record it?\n");
1046 return -1; 1037 return -1;
@@ -1049,7 +1040,7 @@ static int sample_type_check(u64 type)
1049 return 0; 1040 return 0;
1050} 1041}
1051 1042
1052static struct perf_file_handler file_handler = { 1043static struct perf_event_ops event_ops = {
1053 .process_comm_event = process_comm_event, 1044 .process_comm_event = process_comm_event,
1054 .process_fork_event = process_fork_event, 1045 .process_fork_event = process_fork_event,
1055 .process_exit_event = process_exit_event, 1046 .process_exit_event = process_exit_event,
@@ -1059,17 +1050,17 @@ static struct perf_file_handler file_handler = {
1059 1050
1060static int __cmd_timechart(void) 1051static int __cmd_timechart(void)
1061{ 1052{
1062 struct perf_header *header; 1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1063 int ret; 1054 int ret;
1064 1055
1065 register_perf_file_handler(&file_handler); 1056 if (session == NULL)
1057 return -ENOMEM;
1066 1058
1067 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 1059 ret = perf_session__process_events(session, &event_ops);
1068 &event__cwdlen, &event__cwd);
1069 if (ret) 1060 if (ret)
1070 return EXIT_FAILURE; 1061 goto out_delete;
1071 1062
1072 process_samples(); 1063 process_samples(session);
1073 1064
1074 end_sample_processing(); 1065 end_sample_processing();
1075 1066
@@ -1079,8 +1070,9 @@ static int __cmd_timechart(void)
1079 1070
1080 pr_info("Written %2.1f seconds of trace to %s.\n", 1071 pr_info("Written %2.1f seconds of trace to %s.\n",
1081 (last_time - first_time) / 1000000000.0, output_name); 1072 (last_time - first_time) / 1000000000.0, output_name);
1082 1073out_delete:
1083 return EXIT_SUCCESS; 1074 perf_session__delete(session);
1075 return ret;
1084} 1076}
1085 1077
1086static const char * const timechart_usage[] = { 1078static const char * const timechart_usage[] = {
@@ -1145,11 +1137,11 @@ static const struct option options[] = {
1145 1137
1146int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1138int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1147{ 1139{
1148 symbol__init(0);
1149
1150 argc = parse_options(argc, argv, options, timechart_usage, 1140 argc = parse_options(argc, argv, options, timechart_usage,
1151 PARSE_OPT_STOP_AT_NON_OPTION); 1141 PARSE_OPT_STOP_AT_NON_OPTION);
1152 1142
1143 symbol__init();
1144
1153 if (argc && !strncmp(argv[0], "rec", 3)) 1145 if (argc && !strncmp(argv[0], "rec", 3))
1154 return __cmd_record(argc, argv); 1146 return __cmd_record(argc, argv);
1155 else if (argc) 1147 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e0a374d0e43..ddc584b6487 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,8 +20,9 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/symbol.h"
24#include "util/color.h" 23#include "util/color.h"
24#include "util/session.h"
25#include "util/symbol.h"
25#include "util/thread.h" 26#include "util/thread.h"
26#include "util/util.h" 27#include "util/util.h"
27#include <linux/rbtree.h> 28#include <linux/rbtree.h>
@@ -79,7 +80,6 @@ static int dump_symtab = 0;
79static bool hide_kernel_symbols = false; 80static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false; 81static bool hide_user_symbols = false;
81static struct winsize winsize; 82static struct winsize winsize;
82struct symbol_conf symbol_conf;
83 83
84/* 84/*
85 * Source 85 * Source
@@ -926,7 +926,8 @@ static int symbol_filter(struct map *map, struct symbol *sym)
926 return 0; 926 return 0;
927} 927}
928 928
929static void event__process_sample(const event_t *self, int counter) 929static void event__process_sample(const event_t *self,
930 struct perf_session *session, int counter)
930{ 931{
931 u64 ip = self->ip.ip; 932 u64 ip = self->ip.ip;
932 struct sym_entry *syme; 933 struct sym_entry *syme;
@@ -946,8 +947,8 @@ static void event__process_sample(const event_t *self, int counter)
946 return; 947 return;
947 } 948 }
948 949
949 if (event__preprocess_sample(self, &al, symbol_filter) < 0 || 950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
950 al.sym == NULL) 951 al.sym == NULL || al.filtered)
951 return; 952 return;
952 953
953 syme = symbol__priv(al.sym); 954 syme = symbol__priv(al.sym);
@@ -965,14 +966,14 @@ static void event__process_sample(const event_t *self, int counter)
965 } 966 }
966} 967}
967 968
968static int event__process(event_t *event) 969static int event__process(event_t *event, struct perf_session *session)
969{ 970{
970 switch (event->header.type) { 971 switch (event->header.type) {
971 case PERF_RECORD_COMM: 972 case PERF_RECORD_COMM:
972 event__process_comm(event); 973 event__process_comm(event, session);
973 break; 974 break;
974 case PERF_RECORD_MMAP: 975 case PERF_RECORD_MMAP:
975 event__process_mmap(event); 976 event__process_mmap(event, session);
976 break; 977 break;
977 default: 978 default:
978 break; 979 break;
@@ -999,7 +1000,8 @@ static unsigned int mmap_read_head(struct mmap_data *md)
999 return head; 1000 return head;
1000} 1001}
1001 1002
1002static void mmap_read_counter(struct mmap_data *md) 1003static void perf_session__mmap_read_counter(struct perf_session *self,
1004 struct mmap_data *md)
1003{ 1005{
1004 unsigned int head = mmap_read_head(md); 1006 unsigned int head = mmap_read_head(md);
1005 unsigned int old = md->prev; 1007 unsigned int old = md->prev;
@@ -1052,9 +1054,9 @@ static void mmap_read_counter(struct mmap_data *md)
1052 } 1054 }
1053 1055
1054 if (event->header.type == PERF_RECORD_SAMPLE) 1056 if (event->header.type == PERF_RECORD_SAMPLE)
1055 event__process_sample(event, md->counter); 1057 event__process_sample(event, self, md->counter);
1056 else 1058 else
1057 event__process(event); 1059 event__process(event, self);
1058 old += size; 1060 old += size;
1059 } 1061 }
1060 1062
@@ -1064,13 +1066,13 @@ static void mmap_read_counter(struct mmap_data *md)
1064static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1066static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
1065static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1067static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1066 1068
1067static void mmap_read(void) 1069static void perf_session__mmap_read(struct perf_session *self)
1068{ 1070{
1069 int i, counter; 1071 int i, counter;
1070 1072
1071 for (i = 0; i < nr_cpus; i++) { 1073 for (i = 0; i < nr_cpus; i++) {
1072 for (counter = 0; counter < nr_counters; counter++) 1074 for (counter = 0; counter < nr_counters; counter++)
1073 mmap_read_counter(&mmap_array[i][counter]); 1075 perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
1074 } 1076 }
1075} 1077}
1076 1078
@@ -1155,11 +1157,18 @@ static int __cmd_top(void)
1155 pthread_t thread; 1157 pthread_t thread;
1156 int i, counter; 1158 int i, counter;
1157 int ret; 1159 int ret;
1160 /*
1161 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1162 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1163 */
1164 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
1165 if (session == NULL)
1166 return -ENOMEM;
1158 1167
1159 if (target_pid != -1) 1168 if (target_pid != -1)
1160 event__synthesize_thread(target_pid, event__process); 1169 event__synthesize_thread(target_pid, event__process, session);
1161 else 1170 else
1162 event__synthesize_threads(event__process); 1171 event__synthesize_threads(event__process, session);
1163 1172
1164 for (i = 0; i < nr_cpus; i++) { 1173 for (i = 0; i < nr_cpus; i++) {
1165 group_fd = -1; 1174 group_fd = -1;
@@ -1170,7 +1179,7 @@ static int __cmd_top(void)
1170 /* Wait for a minimal set of events before starting the snapshot */ 1179 /* Wait for a minimal set of events before starting the snapshot */
1171 poll(event_array, nr_poll, 100); 1180 poll(event_array, nr_poll, 100);
1172 1181
1173 mmap_read(); 1182 perf_session__mmap_read(session);
1174 1183
1175 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1184 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1176 printf("Could not create display thread.\n"); 1185 printf("Could not create display thread.\n");
@@ -1190,7 +1199,7 @@ static int __cmd_top(void)
1190 while (1) { 1199 while (1) {
1191 int hits = samples; 1200 int hits = samples;
1192 1201
1193 mmap_read(); 1202 perf_session__mmap_read(session);
1194 1203
1195 if (hits == samples) 1204 if (hits == samples)
1196 ret = poll(event_array, nr_poll, 100); 1205 ret = poll(event_array, nr_poll, 100);
@@ -1273,7 +1282,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1273 (nr_counters + 1) * sizeof(unsigned long)); 1282 (nr_counters + 1) * sizeof(unsigned long));
1274 if (symbol_conf.vmlinux_name == NULL) 1283 if (symbol_conf.vmlinux_name == NULL)
1275 symbol_conf.try_vmlinux_path = true; 1284 symbol_conf.try_vmlinux_path = true;
1276 if (symbol__init(&symbol_conf) < 0) 1285 if (symbol__init() < 0)
1277 return -1; 1286 return -1;
1278 1287
1279 if (delay_secs < 1) 1288 if (delay_secs < 1)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c2fcc34486f..e2285e28720 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -7,11 +7,14 @@
7#include "util/header.h" 7#include "util/header.h"
8#include "util/exec_cmd.h" 8#include "util/exec_cmd.h"
9#include "util/trace-event.h" 9#include "util/trace-event.h"
10#include "util/session.h"
10 11
11static char const *script_name; 12static char const *script_name;
12static char const *generate_script_lang; 13static char const *generate_script_lang;
13 14
14static int default_start_script(const char *script __attribute((unused))) 15static int default_start_script(const char *script __unused,
16 int argc __unused,
17 const char **argv __unused)
15{ 18{
16 return 0; 19 return 0;
17} 20}
@@ -21,7 +24,7 @@ static int default_stop_script(void)
21 return 0; 24 return 0;
22} 25}
23 26
24static int default_generate_script(const char *outfile __attribute ((unused))) 27static int default_generate_script(const char *outfile __unused)
25{ 28{
26 return 0; 29 return 0;
27} 30}
@@ -56,15 +59,11 @@ static int cleanup_scripting(void)
56#include "util/debug.h" 59#include "util/debug.h"
57 60
58#include "util/trace-event.h" 61#include "util/trace-event.h"
59#include "util/data_map.h"
60#include "util/exec_cmd.h" 62#include "util/exec_cmd.h"
61 63
62static char const *input_name = "perf.data"; 64static char const *input_name = "perf.data";
63 65
64static struct perf_header *header; 66static int process_sample_event(event_t *event, struct perf_session *session)
65static u64 sample_type;
66
67static int process_sample_event(event_t *event)
68{ 67{
69 struct sample_data data; 68 struct sample_data data;
70 struct thread *thread; 69 struct thread *thread;
@@ -74,7 +73,7 @@ static int process_sample_event(event_t *event)
74 data.cpu = -1; 73 data.cpu = -1;
75 data.period = 1; 74 data.period = 1;
76 75
77 event__parse_sample(event, sample_type, &data); 76 event__parse_sample(event, session->sample_type, &data);
78 77
79 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
80 event->header.misc, 79 event->header.misc,
@@ -82,14 +81,14 @@ static int process_sample_event(event_t *event)
82 (void *)(long)data.ip, 81 (void *)(long)data.ip,
83 (long long)data.period); 82 (long long)data.period);
84 83
85 thread = threads__findnew(event->ip.pid); 84 thread = perf_session__findnew(session, event->ip.pid);
86 if (thread == NULL) { 85 if (thread == NULL) {
87 pr_debug("problem processing %d event, skipping it.\n", 86 pr_debug("problem processing %d event, skipping it.\n",
88 event->header.type); 87 event->header.type);
89 return -1; 88 return -1;
90 } 89 }
91 90
92 if (sample_type & PERF_SAMPLE_RAW) { 91 if (session->sample_type & PERF_SAMPLE_RAW) {
93 /* 92 /*
94 * FIXME: better resolve from pid from the struct trace_entry 93 * FIXME: better resolve from pid from the struct trace_entry
95 * field, although it should be the same than this perf 94 * field, although it should be the same than this perf
@@ -99,16 +98,14 @@ static int process_sample_event(event_t *event)
99 data.raw_size, 98 data.raw_size,
100 data.time, thread->comm); 99 data.time, thread->comm);
101 } 100 }
102 event__stats.total += data.period;
103 101
102 session->events_stats.total += data.period;
104 return 0; 103 return 0;
105} 104}
106 105
107static int sample_type_check(u64 type) 106static int sample_type_check(struct perf_session *session)
108{ 107{
109 sample_type = type; 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
110
111 if (!(sample_type & PERF_SAMPLE_RAW)) {
112 fprintf(stderr, 109 fprintf(stderr,
113 "No trace sample to read. Did you call perf record " 110 "No trace sample to read. Did you call perf record "
114 "without -R?"); 111 "without -R?");
@@ -118,19 +115,15 @@ static int sample_type_check(u64 type)
118 return 0; 115 return 0;
119} 116}
120 117
121static struct perf_file_handler file_handler = { 118static struct perf_event_ops event_ops = {
122 .process_sample_event = process_sample_event, 119 .process_sample_event = process_sample_event,
123 .process_comm_event = event__process_comm, 120 .process_comm_event = event__process_comm,
124 .sample_type_check = sample_type_check, 121 .sample_type_check = sample_type_check,
125}; 122};
126 123
127static int __cmd_trace(void) 124static int __cmd_trace(struct perf_session *session)
128{ 125{
129 register_idle_thread(); 126 return perf_session__process_events(session, &event_ops);
130 register_perf_file_handler(&file_handler);
131
132 return mmap_dispatch_perf_file(&header, input_name,
133 0, 0, &event__cwdlen, &event__cwd);
134} 127}
135 128
136struct script_spec { 129struct script_spec {
@@ -281,6 +274,244 @@ static int parse_scriptname(const struct option *opt __used,
281 return 0; 274 return 0;
282} 275}
283 276
277#define for_each_lang(scripts_dir, lang_dirent, lang_next) \
278 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
279 lang_next) \
280 if (lang_dirent.d_type == DT_DIR && \
281 (strcmp(lang_dirent.d_name, ".")) && \
282 (strcmp(lang_dirent.d_name, "..")))
283
284#define for_each_script(lang_dir, script_dirent, script_next) \
285 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
286 script_next) \
287 if (script_dirent.d_type != DT_DIR)
288
289
290#define RECORD_SUFFIX "-record"
291#define REPORT_SUFFIX "-report"
292
293struct script_desc {
294 struct list_head node;
295 char *name;
296 char *half_liner;
297 char *args;
298};
299
300LIST_HEAD(script_descs);
301
302static struct script_desc *script_desc__new(const char *name)
303{
304 struct script_desc *s = zalloc(sizeof(*s));
305
306 if (s != NULL)
307 s->name = strdup(name);
308
309 return s;
310}
311
312static void script_desc__delete(struct script_desc *s)
313{
314 free(s->name);
315 free(s);
316}
317
318static void script_desc__add(struct script_desc *s)
319{
320 list_add_tail(&s->node, &script_descs);
321}
322
323static struct script_desc *script_desc__find(const char *name)
324{
325 struct script_desc *s;
326
327 list_for_each_entry(s, &script_descs, node)
328 if (strcasecmp(s->name, name) == 0)
329 return s;
330 return NULL;
331}
332
333static struct script_desc *script_desc__findnew(const char *name)
334{
335 struct script_desc *s = script_desc__find(name);
336
337 if (s)
338 return s;
339
340 s = script_desc__new(name);
341 if (!s)
342 goto out_delete_desc;
343
344 script_desc__add(s);
345
346 return s;
347
348out_delete_desc:
349 script_desc__delete(s);
350
351 return NULL;
352}
353
354static char *ends_with(char *str, const char *suffix)
355{
356 size_t suffix_len = strlen(suffix);
357 char *p = str;
358
359 if (strlen(str) > suffix_len) {
360 p = str + strlen(str) - suffix_len;
361 if (!strncmp(p, suffix, suffix_len))
362 return p;
363 }
364
365 return NULL;
366}
367
368static char *ltrim(char *str)
369{
370 int len = strlen(str);
371
372 while (len && isspace(*str)) {
373 len--;
374 str++;
375 }
376
377 return str;
378}
379
380static int read_script_info(struct script_desc *desc, const char *filename)
381{
382 char line[BUFSIZ], *p;
383 FILE *fp;
384
385 fp = fopen(filename, "r");
386 if (!fp)
387 return -1;
388
389 while (fgets(line, sizeof(line), fp)) {
390 p = ltrim(line);
391 if (strlen(p) == 0)
392 continue;
393 if (*p != '#')
394 continue;
395 p++;
396 if (strlen(p) && *p == '!')
397 continue;
398
399 p = ltrim(p);
400 if (strlen(p) && p[strlen(p) - 1] == '\n')
401 p[strlen(p) - 1] = '\0';
402
403 if (!strncmp(p, "description:", strlen("description:"))) {
404 p += strlen("description:");
405 desc->half_liner = strdup(ltrim(p));
406 continue;
407 }
408
409 if (!strncmp(p, "args:", strlen("args:"))) {
410 p += strlen("args:");
411 desc->args = strdup(ltrim(p));
412 continue;
413 }
414 }
415
416 fclose(fp);
417
418 return 0;
419}
420
421static int list_available_scripts(const struct option *opt __used,
422 const char *s __used, int unset __used)
423{
424 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
425 char scripts_path[MAXPATHLEN];
426 DIR *scripts_dir, *lang_dir;
427 char script_path[MAXPATHLEN];
428 char lang_path[MAXPATHLEN];
429 struct script_desc *desc;
430 char first_half[BUFSIZ];
431 char *script_root;
432 char *str;
433
434 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
435
436 scripts_dir = opendir(scripts_path);
437 if (!scripts_dir)
438 return -1;
439
440 for_each_lang(scripts_dir, lang_dirent, lang_next) {
441 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
442 lang_dirent.d_name);
443 lang_dir = opendir(lang_path);
444 if (!lang_dir)
445 continue;
446
447 for_each_script(lang_dir, script_dirent, script_next) {
448 script_root = strdup(script_dirent.d_name);
449 str = ends_with(script_root, REPORT_SUFFIX);
450 if (str) {
451 *str = '\0';
452 desc = script_desc__findnew(script_root);
453 snprintf(script_path, MAXPATHLEN, "%s/%s",
454 lang_path, script_dirent.d_name);
455 read_script_info(desc, script_path);
456 }
457 free(script_root);
458 }
459 }
460
461 fprintf(stdout, "List of available trace scripts:\n");
462 list_for_each_entry(desc, &script_descs, node) {
463 sprintf(first_half, "%s %s", desc->name,
464 desc->args ? desc->args : "");
465 fprintf(stdout, " %-36s %s\n", first_half,
466 desc->half_liner ? desc->half_liner : "");
467 }
468
469 exit(0);
470}
471
472static char *get_script_path(const char *script_root, const char *suffix)
473{
474 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
475 char scripts_path[MAXPATHLEN];
476 char script_path[MAXPATHLEN];
477 DIR *scripts_dir, *lang_dir;
478 char lang_path[MAXPATHLEN];
479 char *str, *__script_root;
480 char *path = NULL;
481
482 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
483
484 scripts_dir = opendir(scripts_path);
485 if (!scripts_dir)
486 return NULL;
487
488 for_each_lang(scripts_dir, lang_dirent, lang_next) {
489 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
490 lang_dirent.d_name);
491 lang_dir = opendir(lang_path);
492 if (!lang_dir)
493 continue;
494
495 for_each_script(lang_dir, script_dirent, script_next) {
496 __script_root = strdup(script_dirent.d_name);
497 str = ends_with(__script_root, suffix);
498 if (str) {
499 *str = '\0';
500 if (strcmp(__script_root, script_root))
501 continue;
502 snprintf(script_path, MAXPATHLEN, "%s/%s",
503 lang_path, script_dirent.d_name);
504 path = strdup(script_path);
505 free(__script_root);
506 break;
507 }
508 free(__script_root);
509 }
510 }
511
512 return path;
513}
514
284static const char * const annotate_usage[] = { 515static const char * const annotate_usage[] = {
285 "perf trace [<options>] <command>", 516 "perf trace [<options>] <command>",
286 NULL 517 NULL
@@ -291,8 +522,10 @@ static const struct option options[] = {
291 "dump raw trace in ASCII"), 522 "dump raw trace in ASCII"),
292 OPT_BOOLEAN('v', "verbose", &verbose, 523 OPT_BOOLEAN('v', "verbose", &verbose,
293 "be more verbose (show symbol address, etc)"), 524 "be more verbose (show symbol address, etc)"),
294 OPT_BOOLEAN('l', "latency", &latency_format, 525 OPT_BOOLEAN('L', "Latency", &latency_format,
295 "show latency attributes (irqs/preemption disabled, etc)"), 526 "show latency attributes (irqs/preemption disabled, etc)"),
527 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
528 list_available_scripts),
296 OPT_CALLBACK('s', "script", NULL, "name", 529 OPT_CALLBACK('s', "script", NULL, "name",
297 "script file name (lang:script name, script name, or *)", 530 "script file name (lang:script name, script name, or *)",
298 parse_scriptname), 531 parse_scriptname),
@@ -304,24 +537,61 @@ static const struct option options[] = {
304 537
305int cmd_trace(int argc, const char **argv, const char *prefix __used) 538int cmd_trace(int argc, const char **argv, const char *prefix __used)
306{ 539{
307 int err; 540 struct perf_session *session;
541 const char *suffix = NULL;
542 const char **__argv;
543 char *script_path;
544 int i, err;
545
546 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
547 if (argc < 3) {
548 fprintf(stderr,
549 "Please specify a record script\n");
550 return -1;
551 }
552 suffix = RECORD_SUFFIX;
553 }
554
555 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
556 if (argc < 3) {
557 fprintf(stderr,
558 "Please specify a report script\n");
559 return -1;
560 }
561 suffix = REPORT_SUFFIX;
562 }
308 563
309 symbol__init(0); 564 if (suffix) {
565 script_path = get_script_path(argv[2], suffix);
566 if (!script_path) {
567 fprintf(stderr, "script not found\n");
568 return -1;
569 }
310 570
311 setup_scripting(); 571 __argv = malloc((argc + 1) * sizeof(const char *));
572 __argv[0] = "/bin/sh";
573 __argv[1] = script_path;
574 for (i = 3; i < argc; i++)
575 __argv[i - 1] = argv[i];
576 __argv[argc - 1] = NULL;
312 577
313 argc = parse_options(argc, argv, options, annotate_usage, 0); 578 execvp("/bin/sh", (char **)__argv);
314 if (argc) { 579 exit(-1);
315 /*
316 * Special case: if there's an argument left then assume tha
317 * it's a symbol filter:
318 */
319 if (argc > 1)
320 usage_with_options(annotate_usage, options);
321 } 580 }
322 581
582 setup_scripting();
583
584 argc = parse_options(argc, argv, options, annotate_usage,
585 PARSE_OPT_STOP_AT_NON_OPTION);
586
587 if (symbol__init() < 0)
588 return -1;
323 setup_pager(); 589 setup_pager();
324 590
591 session = perf_session__new(input_name, O_RDONLY, 0);
592 if (session == NULL)
593 return -ENOMEM;
594
325 if (generate_script_lang) { 595 if (generate_script_lang) {
326 struct stat perf_stat; 596 struct stat perf_stat;
327 597
@@ -348,23 +618,20 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
348 return -1; 618 return -1;
349 } 619 }
350 620
351 header = perf_header__new(); 621 perf_header__read(&session->header, input);
352 if (header == NULL)
353 return -1;
354
355 perf_header__read(header, input);
356 err = scripting_ops->generate_script("perf-trace"); 622 err = scripting_ops->generate_script("perf-trace");
357 goto out; 623 goto out;
358 } 624 }
359 625
360 if (script_name) { 626 if (script_name) {
361 err = scripting_ops->start_script(script_name); 627 err = scripting_ops->start_script(script_name, argc, argv);
362 if (err) 628 if (err)
363 goto out; 629 goto out;
364 } 630 }
365 631
366 err = __cmd_trace(); 632 err = __cmd_trace(session);
367 633
634 perf_session__delete(session);
368 cleanup_scripting(); 635 cleanup_scripting();
369out: 636out:
370 return err; 637 return err;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index a3d8bf65f26..18035b1f16c 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int check_pager_config(const char *cmd);
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix);
20extern int cmd_help(int argc, const char **argv, const char *prefix); 21extern int cmd_help(int argc, const char **argv, const char *prefix);
21extern int cmd_sched(int argc, const char **argv, const char *prefix); 22extern int cmd_sched(int argc, const char **argv, const char *prefix);
22extern int cmd_list(int argc, const char **argv, const char *prefix); 23extern int cmd_list(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 02b09ea17a3..71dc7c3fe7b 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -5,6 +5,7 @@
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-bench mainporcelain common 6perf-bench mainporcelain common
7perf-buildid-list mainporcelain common 7perf-buildid-list mainporcelain common
8perf-diff mainporcelain common
8perf-list mainporcelain common 9perf-list mainporcelain common
9perf-sched mainporcelain common 10perf-sched mainporcelain common
10perf-record mainporcelain common 11perf-record mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index cf64049bc9b..873e55fab37 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -286,6 +286,7 @@ static void handle_internal_command(int argc, const char **argv)
286 const char *cmd = argv[0]; 286 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 287 static struct cmd_struct commands[] = {
288 { "buildid-list", cmd_buildid_list, 0 }, 288 { "buildid-list", cmd_buildid_list, 0 },
289 { "diff", cmd_diff, 0 },
289 { "help", cmd_help, 0 }, 290 { "help", cmd_help, 0 },
290 { "list", cmd_list, 0 }, 291 { "list", cmd_list, 0 },
291 { "record", cmd_record, 0 }, 292 { "record", cmd_record, 0 },
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 454d5d55f32..75f941bfba9 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -59,6 +59,18 @@
59#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 59#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
60#endif 60#endif
61 61
62#ifdef __arm__
63#include "../../arch/arm/include/asm/unistd.h"
64/*
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.
67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory")
72#endif
73
62#include <time.h> 74#include <time.h>
63#include <unistd.h> 75#include <unistd.h>
64#include <sys/types.h> 76#include <sys/types.h>
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
index 89948b01502..7fc4a033dd4 100644
--- a/tools/perf/scripts/perl/bin/check-perf-trace-report
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: useless but exhaustive test script
2perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index f5dcf9cb5bd..eddb9ccce6a 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -1,5 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl 2# description: r/w activity for a program, by file
3# args: <comm>
4perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1
3 5
4 6
5 7
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index cea16f78a3a..7f44c25cc85 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index 85769dc456e..fce3adcb324 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency
2perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index aa68435be92..71cfbd182fb 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
2perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
index 61f91561d84..2a39097687b 100644
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -18,8 +18,9 @@ use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20 20
21# change this to the comm of the program you're interested in 21my $usage = "perf trace -s rw-by-file.pl <comm>\n";
22my $for_comm = "perf"; 22
23my $for_comm = shift or die $usage;
23 24
24my %reads; 25my %reads;
25my %writes; 26my %writes;
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 59b65d0bd7c..b557b836de3 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -1,20 +1,17 @@
1#include "data_map.h"
2#include "symbol.h" 1#include "symbol.h"
3#include "util.h" 2#include "util.h"
4#include "debug.h" 3#include "debug.h"
4#include "thread.h"
5#include "session.h"
5 6
6 7static int process_event_stub(event_t *event __used,
7static struct perf_file_handler *curr_handler; 8 struct perf_session *session __used)
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{ 9{
13 dump_printf(": unhandled!\n"); 10 dump_printf(": unhandled!\n");
14 return 0; 11 return 0;
15} 12}
16 13
17void register_perf_file_handler(struct perf_file_handler *handler) 14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
18{ 15{
19 if (!handler->process_sample_event) 16 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub; 17 handler->process_sample_event = process_event_stub;
@@ -34,8 +31,6 @@ void register_perf_file_handler(struct perf_file_handler *handler)
34 handler->process_throttle_event = process_event_stub; 31 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event) 32 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub; 33 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39} 34}
40 35
41static const char *event__name[] = { 36static const char *event__name[] = {
@@ -61,8 +56,9 @@ void event__print_totals(void)
61 event__name[i], event__total[i]); 56 event__name[i], event__total[i]);
62} 57}
63 58
64static int 59static int process_event(event_t *event, struct perf_session *session,
65process_event(event_t *event, unsigned long offset, unsigned long head) 60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
66{ 62{
67 trace_event(event); 63 trace_event(event);
68 64
@@ -77,25 +73,25 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
77 73
78 switch (event->header.type) { 74 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE: 75 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event); 76 return ops->process_sample_event(event, session);
81 case PERF_RECORD_MMAP: 77 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event); 78 return ops->process_mmap_event(event, session);
83 case PERF_RECORD_COMM: 79 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event); 80 return ops->process_comm_event(event, session);
85 case PERF_RECORD_FORK: 81 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event); 82 return ops->process_fork_event(event, session);
87 case PERF_RECORD_EXIT: 83 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event); 84 return ops->process_exit_event(event, session);
89 case PERF_RECORD_LOST: 85 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event); 86 return ops->process_lost_event(event, session);
91 case PERF_RECORD_READ: 87 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event); 88 return ops->process_read_event(event, session);
93 case PERF_RECORD_THROTTLE: 89 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event); 90 return ops->process_throttle_event(event, session);
95 case PERF_RECORD_UNTHROTTLE: 91 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event); 92 return ops->process_unthrottle_event(event, session);
97 default: 93 default:
98 curr_handler->total_unknown++; 94 ops->total_unknown++;
99 return -1; 95 return -1;
100 } 96 }
101} 97}
@@ -129,88 +125,58 @@ out:
129 return err; 125 return err;
130} 126}
131 127
132int mmap_dispatch_perf_file(struct perf_header **pheader, 128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
133 const char *input_name, 129{
134 int force, 130 struct thread *thread = perf_session__findnew(self, 0);
135 int full_paths, 131
136 int *cwdlen, 132 if (!thread || thread__set_comm(thread, "swapper")) {
137 char **cwd) 133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
138{ 142{
139 int err; 143 int err;
140 struct perf_header *header;
141 unsigned long head, shift; 144 unsigned long head, shift;
142 unsigned long offset = 0; 145 unsigned long offset = 0;
143 struct stat input_stat;
144 size_t page_size; 146 size_t page_size;
145 u64 sample_type;
146 event_t *event; 147 event_t *event;
147 uint32_t size; 148 uint32_t size;
148 int input;
149 char *buf; 149 char *buf;
150 150
151 if (curr_handler == NULL) { 151 if (perf_session__register_idle_thread(self) == NULL)
152 pr_debug("Forgot to register perf file handler\n"); 152 return -ENOMEM;
153 return -EINVAL;
154 }
155
156 page_size = getpagesize();
157
158 input = open(input_name, O_RDONLY);
159 if (input < 0) {
160 pr_err("Failed to open file: %s", input_name);
161 if (!strcmp(input_name, "perf.data"))
162 pr_err(" (try 'perf record' first)");
163 pr_err("\n");
164 return -errno;
165 }
166
167 if (fstat(input, &input_stat) < 0) {
168 pr_err("failed to stat file");
169 err = -errno;
170 goto out_close;
171 }
172
173 err = -EACCES;
174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175 pr_err("file: %s not owned by current user or root\n",
176 input_name);
177 goto out_close;
178 }
179
180 if (input_stat.st_size == 0) {
181 pr_info("zero-sized file, nothing to do!\n");
182 goto done;
183 }
184 153
185 err = -ENOMEM; 154 perf_event_ops__fill_defaults(ops);
186 header = perf_header__new();
187 if (header == NULL)
188 goto out_close;
189 155
190 err = perf_header__read(header, input); 156 page_size = getpagesize();
191 if (err < 0)
192 goto out_delete;
193 *pheader = header;
194 head = header->data_offset;
195 157
196 sample_type = perf_header__sample_type(header); 158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
197 160
198 err = -EINVAL; 161 err = -EINVAL;
199 if (curr_handler->sample_type_check && 162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
200 curr_handler->sample_type_check(sample_type) < 0) 163 goto out_err;
201 goto out_delete;
202 164
203 if (!full_paths) { 165 if (!ops->full_paths) {
204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 166 char bf[PATH_MAX];
205 pr_err("failed to get the current directory\n"); 167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
206 err = -errno; 169 err = -errno;
207 goto out_delete; 170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
208 } 178 }
209 *cwd = __cwd; 179 self->cwdlen = strlen(self->cwd);
210 *cwdlen = strlen(*cwd);
211 } else {
212 *cwd = NULL;
213 *cwdlen = 0;
214 } 180 }
215 181
216 shift = page_size * (head / page_size); 182 shift = page_size * (head / page_size);
@@ -218,12 +184,12 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
218 head -= shift; 184 head -= shift;
219 185
220remap: 186remap:
221 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
222 MAP_SHARED, input, offset); 188 MAP_SHARED, self->fd, offset);
223 if (buf == MAP_FAILED) { 189 if (buf == MAP_FAILED) {
224 pr_err("failed to mmap file\n"); 190 pr_err("failed to mmap file\n");
225 err = -errno; 191 err = -errno;
226 goto out_delete; 192 goto out_err;
227 } 193 }
228 194
229more: 195more:
@@ -233,12 +199,12 @@ more:
233 if (!size) 199 if (!size)
234 size = 8; 200 size = 8;
235 201
236 if (head + event->header.size >= page_size * mmap_window) { 202 if (head + event->header.size >= page_size * self->mmap_window) {
237 int munmap_ret; 203 int munmap_ret;
238 204
239 shift = page_size * (head / page_size); 205 shift = page_size * (head / page_size);
240 206
241 munmap_ret = munmap(buf, page_size * mmap_window); 207 munmap_ret = munmap(buf, page_size * self->mmap_window);
242 assert(munmap_ret == 0); 208 assert(munmap_ret == 0);
243 209
244 offset += shift; 210 offset += shift;
@@ -253,7 +219,7 @@ more:
253 (void *)(long)event->header.size, 219 (void *)(long)event->header.size,
254 event->header.type); 220 event->header.type);
255 221
256 if (!size || process_event(event, offset, head) < 0) { 222 if (!size || process_event(event, self, ops, offset, head) < 0) {
257 223
258 dump_printf("%p [%p]: skipping unknown header type: %d\n", 224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
259 (void *)(offset + head), 225 (void *)(offset + head),
@@ -273,19 +239,14 @@ more:
273 239
274 head += size; 240 head += size;
275 241
276 if (offset + head >= header->data_offset + header->data_size) 242 if (offset + head >= self->header.data_offset + self->header.data_size)
277 goto done; 243 goto done;
278 244
279 if (offset + head < (unsigned long)input_stat.st_size) 245 if (offset + head < self->size)
280 goto more; 246 goto more;
281 247
282done: 248done:
283 err = 0; 249 err = 0;
284out_close: 250out_err:
285 close(input);
286
287 return err; 251 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
291} 252}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
deleted file mode 100644
index 258a87bcc4f..00000000000
--- a/tools/perf/util/data_map.h
+++ /dev/null
@@ -1,32 +0,0 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6
7typedef int (*event_type_handler_t)(event_t *);
8
9struct perf_file_handler {
10 event_type_handler_t process_sample_event;
11 event_type_handler_t process_mmap_event;
12 event_type_handler_t process_comm_event;
13 event_type_handler_t process_fork_event;
14 event_type_handler_t process_exit_event;
15 event_type_handler_t process_lost_event;
16 event_type_handler_t process_read_event;
17 event_type_handler_t process_throttle_event;
18 event_type_handler_t process_unthrottle_event;
19 int (*sample_type_check)(u64 sample_type);
20 unsigned long total_unknown;
21};
22
23void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader,
25 const char *input_name,
26 int force,
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
31
32#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 4dcecafa85d..bb0fd6da2d5 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,11 +1,16 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h"
4#include "string.h" 6#include "string.h"
7#include "strlist.h"
5#include "thread.h" 8#include "thread.h"
6 9
7static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event)) 11 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
9{ 14{
10 event_t ev; 15 event_t ev;
11 char filename[PATH_MAX]; 16 char filename[PATH_MAX];
@@ -54,7 +59,7 @@ out_race:
54 if (!full) { 59 if (!full) {
55 ev.comm.tid = pid; 60 ev.comm.tid = pid;
56 61
57 process(&ev); 62 process(&ev, session);
58 goto out_fclose; 63 goto out_fclose;
59 } 64 }
60 65
@@ -72,7 +77,7 @@ out_race:
72 77
73 ev.comm.tid = pid; 78 ev.comm.tid = pid;
74 79
75 process(&ev); 80 process(&ev, session);
76 } 81 }
77 closedir(tasks); 82 closedir(tasks);
78 83
@@ -86,7 +91,9 @@ out_failure:
86} 91}
87 92
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event)) 94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
90{ 97{
91 char filename[PATH_MAX]; 98 char filename[PATH_MAX];
92 FILE *fp; 99 FILE *fp;
@@ -141,7 +148,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
141 ev.mmap.pid = tgid; 148 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid; 149 ev.mmap.tid = pid;
143 150
144 process(&ev); 151 process(&ev, session);
145 } 152 }
146 } 153 }
147 154
@@ -149,15 +156,20 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
149 return 0; 156 return 0;
150} 157}
151 158
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) 159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
153{ 163{
154 pid_t tgid = event__synthesize_comm(pid, 1, process); 164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
155 if (tgid == -1) 165 if (tgid == -1)
156 return -1; 166 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process); 167 return event__synthesize_mmap_events(pid, tgid, process, session);
158} 168}
159 169
160void event__synthesize_threads(int (*process)(event_t *event)) 170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
161{ 173{
162 DIR *proc; 174 DIR *proc;
163 struct dirent dirent, *next; 175 struct dirent dirent, *next;
@@ -171,24 +183,47 @@ void event__synthesize_threads(int (*process)(event_t *event))
171 if (*end) /* only interested in proper numerical dirents */ 183 if (*end) /* only interested in proper numerical dirents */
172 continue; 184 continue;
173 185
174 event__synthesize_thread(pid, process); 186 event__synthesize_thread(pid, process, session);
175 } 187 }
176 188
177 closedir(proc); 189 closedir(proc);
178} 190}
179 191
180char *event__cwd; 192static void thread__comm_adjust(struct thread *self)
181int event__cwdlen; 193{
194 char *comm = self->comm;
182 195
183struct events_stats event__stats; 196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
184 200
185int event__process_comm(event_t *self) 201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
186{ 209{
187 struct thread *thread = threads__findnew(self->comm.pid); 210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
214
215 thread__comm_adjust(self);
216
217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
221{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
188 223
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 225
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1; 228 return -1;
194 } 229 }
@@ -196,18 +231,18 @@ int event__process_comm(event_t *self)
196 return 0; 231 return 0;
197} 232}
198 233
199int event__process_lost(event_t *self) 234int event__process_lost(event_t *self, struct perf_session *session)
200{ 235{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost; 237 session->events_stats.lost += self->lost.lost;
203 return 0; 238 return 0;
204} 239}
205 240
206int event__process_mmap(event_t *self) 241int event__process_mmap(event_t *self, struct perf_session *session)
207{ 242{
208 struct thread *thread = threads__findnew(self->mmap.pid); 243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 event__cwd, event__cwdlen); 245 session->cwd, session->cwdlen);
211 246
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 self->mmap.pid, self->mmap.tid, 248 self->mmap.pid, self->mmap.tid,
@@ -224,10 +259,10 @@ int event__process_mmap(event_t *self)
224 return 0; 259 return 0;
225} 260}
226 261
227int event__process_task(event_t *self) 262int event__process_task(event_t *self, struct perf_session *session)
228{ 263{
229 struct thread *thread = threads__findnew(self->fork.pid); 264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid); 265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
231 266
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid); 268 self->fork.ppid, self->fork.ptid);
@@ -249,18 +284,20 @@ int event__process_task(event_t *self)
249 return 0; 284 return 0;
250} 285}
251 286
252void thread__find_addr_location(struct thread *self, u8 cpumode, 287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
253 enum map_type type, u64 addr, 289 enum map_type type, u64 addr,
254 struct addr_location *al, 290 struct addr_location *al,
255 symbol_filter_t filter) 291 symbol_filter_t filter)
256{ 292{
257 struct thread *thread = al->thread = self; 293 struct map_groups *mg = &self->mg;
258 294
295 al->thread = self;
259 al->addr = addr; 296 al->addr = addr;
260 297
261 if (cpumode & PERF_RECORD_MISC_KERNEL) { 298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
262 al->level = 'k'; 299 al->level = 'k';
263 thread = kthread; 300 mg = &session->kmaps;
264 } else if (cpumode & PERF_RECORD_MISC_USER) 301 } else if (cpumode & PERF_RECORD_MISC_USER)
265 al->level = '.'; 302 al->level = '.';
266 else { 303 else {
@@ -270,7 +307,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
270 return; 307 return;
271 } 308 }
272try_again: 309try_again:
273 al->map = thread__find_map(thread, type, al->addr); 310 al->map = map_groups__find(mg, type, al->addr);
274 if (al->map == NULL) { 311 if (al->map == NULL) {
275 /* 312 /*
276 * If this is outside of all known maps, and is a negative 313 * If this is outside of all known maps, and is a negative
@@ -281,33 +318,73 @@ try_again:
281 * "[vdso]" dso, but for now lets use the old trick of looking 318 * "[vdso]" dso, but for now lets use the old trick of looking
282 * in the whole kernel symbol list. 319 * in the whole kernel symbol list.
283 */ 320 */
284 if ((long long)al->addr < 0 && thread != kthread) { 321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
285 thread = kthread; 322 mg = &session->kmaps;
286 goto try_again; 323 goto try_again;
287 } 324 }
288 al->sym = NULL; 325 al->sym = NULL;
289 } else { 326 } else {
290 al->addr = al->map->map_ip(al->map, al->addr); 327 al->addr = al->map->map_ip(al->map, al->addr);
291 al->sym = map__find_symbol(al->map, al->addr, filter); 328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
292 } 329 }
293} 330}
294 331
295int event__preprocess_sample(const event_t *self, struct addr_location *al, 332static void dso__calc_col_width(struct dso *self)
296 symbol_filter_t filter) 333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
297{ 347{
298 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
299 struct thread *thread = threads__findnew(self->ip.pid); 349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
300 350
301 if (thread == NULL) 351 if (thread == NULL)
302 return -1; 352 return -1;
303 353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
304 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
305 359
306 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
307 self->ip.ip, al, filter); 361 self->ip.ip, al, filter);
308 dump_printf(" ...... dso: %s\n", 362 dump_printf(" ...... dso: %s\n",
309 al->map ? al->map->dso->long_name : 363 al->map ? al->map->dso->long_name :
310 al->level == 'H' ? "[hypervisor]" : "<not found>"); 364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
311 return 0; 388 return 0;
312} 389}
313 390
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c7a78eef8e5..690a96d0467 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -95,18 +95,19 @@ typedef union event_union {
95} event_t; 95} event_t;
96 96
97struct events_stats { 97struct events_stats {
98 unsigned long total; 98 u64 total;
99 unsigned long lost; 99 u64 lost;
100}; 100};
101 101
102void event__print_totals(void); 102void event__print_totals(void);
103 103
104enum map_type { 104enum map_type {
105 MAP__FUNCTION = 0, 105 MAP__FUNCTION = 0,
106 106 MAP__VARIABLE,
107 MAP__NR_TYPES,
108}; 107};
109 108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
110struct map { 111struct map {
111 union { 112 union {
112 struct rb_node rb_node; 113 struct rb_node rb_node;
@@ -148,27 +149,35 @@ void map__delete(struct map *self);
148struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
149int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
150size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
151struct symbol *map__find_symbol(struct map *self, u64 addr, 152
152 symbol_filter_t filter); 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
153void map__fixup_start(struct map *self); 162void map__fixup_start(struct map *self);
154void map__fixup_end(struct map *self); 163void map__fixup_end(struct map *self);
155 164
156int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 165int event__synthesize_thread(pid_t pid,
157void event__synthesize_threads(int (*process)(event_t *event)); 166 int (*process)(event_t *event,
158 167 struct perf_session *session),
159extern char *event__cwd; 168 struct perf_session *session);
160extern int event__cwdlen; 169void event__synthesize_threads(int (*process)(event_t *event,
161extern struct events_stats event__stats; 170 struct perf_session *session),
162extern unsigned long event__total[PERF_RECORD_MAX]; 171 struct perf_session *session);
163 172
164int event__process_comm(event_t *self); 173int event__process_comm(event_t *self, struct perf_session *session);
165int event__process_lost(event_t *self); 174int event__process_lost(event_t *self, struct perf_session *session);
166int event__process_mmap(event_t *self); 175int event__process_mmap(event_t *self, struct perf_session *session);
167int event__process_task(event_t *self); 176int event__process_task(event_t *self, struct perf_session *session);
168 177
169struct addr_location; 178struct addr_location;
170int event__preprocess_sample(const event_t *self, struct addr_location *al, 179int event__preprocess_sample(const event_t *self, struct perf_session *session,
171 symbol_filter_t filter); 180 struct addr_location *al, symbol_filter_t filter);
172int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
173 182
174#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 59a9c0b3033..8a0bca55106 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,8 +8,8 @@
8#include "header.h" 8#include "header.h"
9#include "../perf.h" 9#include "../perf.h"
10#include "trace-event.h" 10#include "trace-event.h"
11#include "session.h"
11#include "symbol.h" 12#include "symbol.h"
12#include "data_map.h"
13#include "debug.h" 13#include "debug.h"
14 14
15/* 15/*
@@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
58 return 0; 58 return 0;
59} 59}
60 60
61/* 61int perf_header__init(struct perf_header *self)
62 * Create new perf.data header:
63 */
64struct perf_header *perf_header__new(void)
65{ 62{
66 struct perf_header *self = zalloc(sizeof(*self)); 63 self->size = 1;
67 64 self->attr = malloc(sizeof(void *));
68 if (self != NULL) { 65 return self->attr == NULL ? -ENOMEM : 0;
69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
71
72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
77
78 return self;
79} 66}
80 67
81void perf_header__delete(struct perf_header *self) 68void perf_header__exit(struct perf_header *self)
82{ 69{
83 int i; 70 int i;
84
85 for (i = 0; i < self->attrs; ++i) 71 for (i = 0; i < self->attrs; ++i)
86 perf_header_attr__delete(self->attr[i]); 72 perf_header_attr__delete(self->attr[i]);
87
88 free(self->attr); 73 free(self->attr);
89 free(self);
90} 74}
91 75
92int perf_header__add_attr(struct perf_header *self, 76int perf_header__add_attr(struct perf_header *self,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d1dbe2b79c4..d118d05d3ab 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -55,8 +55,8 @@ struct perf_header {
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 56};
57 57
58struct perf_header *perf_header__new(void); 58int perf_header__init(struct perf_header *self);
59void perf_header__delete(struct perf_header *self); 59void perf_header__exit(struct perf_header *self);
60 60
61int perf_header__read(struct perf_header *self, int fd); 61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0ebf6ee16ca..e8daf5ca6fd 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,9 +1,7 @@
1#include "hist.h" 1#include "hist.h"
2 2#include "session.h"
3struct rb_root hist; 3#include "sort.h"
4struct rb_root collapse_hists; 4#include <math.h>
5struct rb_root output_hists;
6int callchain;
7 5
8struct callchain_param callchain_param = { 6struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 7 .mode = CHAIN_GRAPH_REL,
@@ -14,11 +12,12 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
15 */ 13 */
16 14
17struct hist_entry *__hist_entry__add(struct addr_location *al, 15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
18 struct symbol *sym_parent, 16 struct addr_location *al,
19 u64 count, bool *hit) 17 struct symbol *sym_parent,
18 u64 count, bool *hit)
20{ 19{
21 struct rb_node **p = &hist.rb_node; 20 struct rb_node **p = &self->hists.rb_node;
22 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
23 struct hist_entry *he; 22 struct hist_entry *he;
24 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -54,7 +53,7 @@ struct hist_entry *__hist_entry__add(struct addr_location *al,
54 return NULL; 53 return NULL;
55 *he = entry; 54 *he = entry;
56 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist); 56 rb_insert_color(&he->rb_node, &self->hists);
58 *hit = false; 57 *hit = false;
59 return he; 58 return he;
60} 59}
@@ -102,9 +101,9 @@ void hist_entry__free(struct hist_entry *he)
102 * collapse the histogram 101 * collapse the histogram
103 */ 102 */
104 103
105void collapse__insert_entry(struct hist_entry *he) 104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
106{ 105{
107 struct rb_node **p = &collapse_hists.rb_node; 106 struct rb_node **p = &root->rb_node;
108 struct rb_node *parent = NULL; 107 struct rb_node *parent = NULL;
109 struct hist_entry *iter; 108 struct hist_entry *iter;
110 int64_t cmp; 109 int64_t cmp;
@@ -128,38 +127,45 @@ void collapse__insert_entry(struct hist_entry *he)
128 } 127 }
129 128
130 rb_link_node(&he->rb_node, parent, p); 129 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists); 130 rb_insert_color(&he->rb_node, root);
132} 131}
133 132
134void collapse__resort(void) 133void perf_session__collapse_resort(struct perf_session *self)
135{ 134{
135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
137 struct hist_entry *n; 137 struct hist_entry *n;
138 138
139 if (!sort__need_collapse) 139 if (!sort__need_collapse)
140 return; 140 return;
141 141
142 next = rb_first(&hist); 142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
143 while (next) { 145 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
146 148
147 rb_erase(&n->rb_node, &hist); 149 rb_erase(&n->rb_node, &self->hists);
148 collapse__insert_entry(n); 150 collapse__insert_entry(&tmp, n);
149 } 151 }
152
153 self->hists = tmp;
150} 154}
151 155
152/* 156/*
153 * reverse the map, sort on count. 157 * reverse the map, sort on count.
154 */ 158 */
155 159
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) 160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
157{ 163{
158 struct rb_node **p = &output_hists.rb_node; 164 struct rb_node **p = &root->rb_node;
159 struct rb_node *parent = NULL; 165 struct rb_node *parent = NULL;
160 struct hist_entry *iter; 166 struct hist_entry *iter;
161 167
162 if (callchain) 168 if (symbol_conf.use_callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain, 169 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param); 170 min_callchain_hits, &callchain_param);
165 171
@@ -174,29 +180,483 @@ void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
174 } 180 }
175 181
176 rb_link_node(&he->rb_node, parent, p); 182 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists); 183 rb_insert_color(&he->rb_node, root);
178} 184}
179 185
180void output__resort(u64 total_samples) 186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
181{ 187{
188 struct rb_root tmp;
182 struct rb_node *next; 189 struct rb_node *next;
183 struct hist_entry *n; 190 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits; 191 u64 min_callchain_hits;
186 192
187 min_callchain_hits = 193 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
189 195
190 if (sort__need_collapse) 196 tmp = RB_ROOT;
191 tree = &collapse_hists; 197 next = rb_first(&self->hists);
192
193 next = rb_first(tree);
194 198
195 while (next) { 199 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
198 202
199 rb_erase(&n->rb_node, tree); 203 rb_erase(&n->rb_node, &self->hists);
200 output__insert_entry(n, min_callchain_hits); 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line seperator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session->events_stats.total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
201 } 657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
202} 662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3020db0c929..e5f99b24048 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -1,50 +1,27 @@
1#ifndef __PERF_HIST_H 1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3#include "../builtin.h"
4 3
5#include "util.h" 4#include <linux/types.h>
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h" 5#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23 6
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38 8
39struct hist_entry *__hist_entry__add(struct addr_location *al, 9struct perf_session;
40 struct symbol *parent, 10struct hist_entry;
41 u64 count, bool *hit); 11struct addr_location;
12struct symbol;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 20void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49 21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
50#endif /* __PERF_HIST_H */ 27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 69f94fe9db2..c4d55a0da2e 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,43 +104,70 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107struct symbol *map__find_symbol(struct map *self, u64 addr, 107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter) 108 symbol_filter_t filter)
109{ 109{
110 if (!dso__loaded(self->dso, self->type)) { 110 const char *name = self->dso->long_name;
111 int nr = dso__load(self->dso, self, filter); 111 int nr;
112 112
113 if (nr < 0) { 113 if (dso__loaded(self->dso, self->type))
114 if (self->dso->has_build_id) { 114 return 0;
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 115
116 116 nr = dso__load(self->dso, self, session, filter);
117 build_id__sprintf(self->dso->build_id, 117 if (nr < 0) {
118 sizeof(self->dso->build_id), 118 if (self->dso->has_build_id) {
119 sbuild_id); 119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
120 pr_warning("%s with build id %s not found", 120
121 self->dso->long_name, sbuild_id); 121 build_id__sprintf(self->dso->build_id,
122 } else 122 sizeof(self->dso->build_id),
123 pr_warning("Failed to open %s", 123 sbuild_id);
124 self->dso->long_name); 124 pr_warning("%s with build id %s not found",
125 pr_warning(", continuing without symbols\n"); 125 name, sbuild_id);
126 return NULL; 126 } else
127 } else if (nr == 0) { 127 pr_warning("Failed to open %s", name);
128 const char *name = self->dso->long_name; 128
129 const size_t len = strlen(name); 129 pr_warning(", continuing without symbols\n");
130 const size_t real_len = len - sizeof(DSO__DELETED); 130 return -1;
131 131 } else if (nr == 0) {
132 if (len > sizeof(DSO__DELETED) && 132 const size_t len = strlen(name);
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) { 133 const size_t real_len = len - sizeof(DSO__DELETED);
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n", 134
135 (int)real_len, name); 135 if (len > sizeof(DSO__DELETED) &&
136 } else { 136 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name); 137 pr_warning("%.*s was updated, restart the long "
138 } 138 "running apps that use it!\n",
139 return NULL; 139 (int)real_len, name);
140 } else {
141 pr_warning("no symbols found in %s, maybe install "
142 "a debug package?\n", name);
140 } 143 }
144
145 return -1;
141 } 146 }
142 147
143 return self->dso->find_symbol(self->dso, self->type, addr); 148 return 0;
149}
150
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
152 u64 addr, symbol_filter_t filter)
153{
154 if (map__load(self, session, filter) < 0)
155 return NULL;
156
157 return dso__find_symbol(self->dso, self->type, addr);
158}
159
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter)
163{
164 if (map__load(self, session, filter) < 0)
165 return NULL;
166
167 if (!dso__sorted_by_name(self->dso, self->type))
168 dso__sort_by_name(self->dso, self->type);
169
170 return dso__find_symbol_by_name(self->dso, self->type, name);
144} 171}
145 172
146struct map *map__clone(struct map *self) 173struct map *map__clone(struct map *self)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d14a4585bca..29465d44004 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -62,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 62 return ret;
63} 63}
64 64
65/* Check the name is good for event/group */
66static bool check_event_name(const char *name)
67{
68 if (!isalpha(*name) && *name != '_')
69 return false;
70 while (*++name != '\0') {
71 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
72 return false;
73 }
74 return true;
75}
76
65/* Parse probepoint definition. */ 77/* Parse probepoint definition. */
66static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
67{ 79{
@@ -69,10 +81,26 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
69 char c, nc = 0; 81 char c, nc = 0;
70 /* 82 /*
71 * <Syntax> 83 * <Syntax>
72 * perf probe SRC:LN 84 * perf probe [EVENT=]SRC:LN
73 * perf probe FUNC[+OFFS|%return][@SRC] 85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
74 */ 88 */
75 89
90 ptr = strchr(arg, '=');
91 if (ptr) { /* Event name */
92 *ptr = '\0';
93 tmp = ptr + 1;
94 ptr = strchr(arg, ':');
95 if (ptr) /* Group name is not supported yet. */
96 semantic_error("Group name is not supported yet.");
97 if (!check_event_name(arg))
98 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg);
100 pp->event = strdup(arg);
101 arg = tmp;
102 }
103
76 ptr = strpbrk(arg, ":+@%"); 104 ptr = strpbrk(arg, ":+@%");
77 if (ptr) { 105 if (ptr) {
78 nc = *ptr; 106 nc = *ptr;
@@ -150,10 +178,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
150} 178}
151 179
152/* Parse perf-probe event definition */ 180/* Parse perf-probe event definition */
153int parse_perf_probe_event(const char *str, struct probe_point *pp) 181void parse_perf_probe_event(const char *str, struct probe_point *pp,
182 bool *need_dwarf)
154{ 183{
155 char **argv; 184 char **argv;
156 int argc, i, need_dwarf = 0; 185 int argc, i;
186
187 *need_dwarf = false;
157 188
158 argv = argv_split(str, &argc); 189 argv = argv_split(str, &argc);
159 if (!argv) 190 if (!argv)
@@ -164,7 +195,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
164 /* Parse probe point */ 195 /* Parse probe point */
165 parse_perf_probe_probepoint(argv[0], pp); 196 parse_perf_probe_probepoint(argv[0], pp);
166 if (pp->file || pp->line) 197 if (pp->file || pp->line)
167 need_dwarf = 1; 198 *need_dwarf = true;
168 199
169 /* Copy arguments and ensure return probe has no C argument */ 200 /* Copy arguments and ensure return probe has no C argument */
170 pp->nr_args = argc - 1; 201 pp->nr_args = argc - 1;
@@ -177,17 +208,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
177 if (pp->retprobe) 208 if (pp->retprobe)
178 semantic_error("You can't specify local" 209 semantic_error("You can't specify local"
179 " variable for kretprobe"); 210 " variable for kretprobe");
180 need_dwarf = 1; 211 *need_dwarf = true;
181 } 212 }
182 } 213 }
183 214
184 argv_free(argv); 215 argv_free(argv);
185 return need_dwarf;
186} 216}
187 217
188/* Parse kprobe_events event into struct probe_point */ 218/* Parse kprobe_events event into struct probe_point */
189void parse_trace_kprobe_event(const char *str, char **group, char **event, 219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
190 struct probe_point *pp)
191{ 220{
192 char pr; 221 char pr;
193 char *p; 222 char *p;
@@ -203,18 +232,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
203 232
204 /* Scan event and group name. */ 233 /* Scan event and group name. */
205 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
206 &pr, (float *)(void *)group, (float *)(void *)event); 235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
207 if (ret != 3) 237 if (ret != 3)
208 semantic_error("Failed to parse event name: %s", argv[0]); 238 semantic_error("Failed to parse event name: %s", argv[0]);
209 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr); 239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
210
211 if (!pp)
212 goto end;
213 240
214 pp->retprobe = (pr == 'r'); 241 pp->retprobe = (pr == 'r');
215 242
216 /* Scan function name and offset */ 243 /* Scan function name and offset */
217 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); 244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
245 &pp->offset);
218 if (ret == 1) 246 if (ret == 1)
219 pp->offset = 0; 247 pp->offset = 0;
220 248
@@ -233,15 +261,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
233 die("Failed to copy argument."); 261 die("Failed to copy argument.");
234 } 262 }
235 263
236end:
237 argv_free(argv); 264 argv_free(argv);
238} 265}
239 266
240int synthesize_perf_probe_event(struct probe_point *pp) 267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
241{ 269{
242 char *buf; 270 char *buf;
243 char offs[64] = "", line[64] = ""; 271 char offs[64] = "", line[64] = "";
244 int i, len, ret; 272 int ret;
245 273
246 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
247 if (!buf) 275 if (!buf)
@@ -262,10 +290,24 @@ int synthesize_perf_probe_event(struct probe_point *pp)
262 offs, pp->retprobe ? "%return" : "", line); 290 offs, pp->retprobe ? "%return" : "", line);
263 else 291 else
264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
265 if (ret <= 0) 293 if (ret <= 0) {
266 goto error; 294error:
267 len = ret; 295 free(pp->probes[0]);
296 pp->probes[0] = NULL;
297 }
298 return ret;
299}
300
301int synthesize_perf_probe_event(struct probe_point *pp)
302{
303 char *buf;
304 int i, len, ret;
305
306 len = synthesize_perf_probe_point(pp);
307 if (len < 0)
308 return 0;
268 309
310 buf = pp->probes[0];
269 for (i = 0; i < pp->nr_args; i++) { 311 for (i = 0; i < pp->nr_args; i++) {
270 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
271 pp->args[i]); 313 pp->args[i]);
@@ -278,6 +320,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
278 return pp->found; 320 return pp->found;
279error: 321error:
280 free(pp->probes[0]); 322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
281 324
282 return ret; 325 return ret;
283} 326}
@@ -307,6 +350,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
307 return pp->found; 350 return pp->found;
308error: 351error:
309 free(pp->probes[0]); 352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
310 354
311 return ret; 355 return ret;
312} 356}
@@ -366,6 +410,10 @@ static void clear_probe_point(struct probe_point *pp)
366{ 410{
367 int i; 411 int i;
368 412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
369 if (pp->function) 417 if (pp->function)
370 free(pp->function); 418 free(pp->function);
371 if (pp->file) 419 if (pp->file)
@@ -380,13 +428,15 @@ static void clear_probe_point(struct probe_point *pp)
380} 428}
381 429
382/* Show an event */ 430/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event, 431static void show_perf_probe_event(const char *event, const char *place,
384 const char *place, struct probe_point *pp) 432 struct probe_point *pp)
385{ 433{
386 int i; 434 int i, ret;
387 char buf[128]; 435 char buf[128];
388 436
389 e_snprintf(buf, 128, "%s:%s", group, event); 437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
390 printf(" %-40s (on %s", buf, place); 440 printf(" %-40s (on %s", buf, place);
391 441
392 if (pp->nr_args > 0) { 442 if (pp->nr_args > 0) {
@@ -400,9 +450,7 @@ static void show_perf_probe_event(const char *group, const char *event,
400/* List up current perf-probe events */ 450/* List up current perf-probe events */
401void show_perf_probe_events(void) 451void show_perf_probe_events(void)
402{ 452{
403 unsigned int i; 453 int fd;
404 int fd, nr;
405 char *group, *event;
406 struct probe_point pp; 454 struct probe_point pp;
407 struct strlist *rawlist; 455 struct strlist *rawlist;
408 struct str_node *ent; 456 struct str_node *ent;
@@ -411,18 +459,12 @@ void show_perf_probe_events(void)
411 rawlist = get_trace_kprobe_event_rawlist(fd); 459 rawlist = get_trace_kprobe_event_rawlist(fd);
412 close(fd); 460 close(fd);
413 461
414 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 462 strlist__for_each(ent, rawlist) {
415 ent = strlist__entry(rawlist, i); 463 parse_trace_kprobe_event(ent->s, &pp);
416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */ 464 /* Synthesize only event probe point */
418 nr = pp.nr_args; 465 synthesize_perf_probe_point(&pp);
419 pp.nr_args = 0;
420 synthesize_perf_probe_event(&pp);
421 pp.nr_args = nr;
422 /* Show an event */ 466 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp); 467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
424 free(group);
425 free(event);
426 clear_probe_point(&pp); 468 clear_probe_point(&pp);
427 } 469 }
428 470
@@ -432,26 +474,25 @@ void show_perf_probe_events(void)
432/* Get current perf-probe event names */ 474/* Get current perf-probe event names */
433static struct strlist *get_perf_event_names(int fd, bool include_group) 475static struct strlist *get_perf_event_names(int fd, bool include_group)
434{ 476{
435 unsigned int i;
436 char *group, *event;
437 char buf[128]; 477 char buf[128];
438 struct strlist *sl, *rawlist; 478 struct strlist *sl, *rawlist;
439 struct str_node *ent; 479 struct str_node *ent;
480 struct probe_point pp;
440 481
482 memset(&pp, 0, sizeof(pp));
441 rawlist = get_trace_kprobe_event_rawlist(fd); 483 rawlist = get_trace_kprobe_event_rawlist(fd);
442 484
443 sl = strlist__new(true, NULL); 485 sl = strlist__new(true, NULL);
444 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 486 strlist__for_each(ent, rawlist) {
445 ent = strlist__entry(rawlist, i); 487 parse_trace_kprobe_event(ent->s, &pp);
446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
447 if (include_group) { 488 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
490 pp.event) < 0)
449 die("Failed to copy group:event name."); 491 die("Failed to copy group:event name.");
450 strlist__add(sl, buf); 492 strlist__add(sl, buf);
451 } else 493 } else
452 strlist__add(sl, event); 494 strlist__add(sl, pp.event);
453 free(group); 495 clear_probe_point(&pp);
454 free(event);
455 } 496 }
456 497
457 strlist__delete(rawlist); 498 strlist__delete(rawlist);
@@ -470,7 +511,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
470} 511}
471 512
472static void get_new_event_name(char *buf, size_t len, const char *base, 513static void get_new_event_name(char *buf, size_t len, const char *base,
473 struct strlist *namelist) 514 struct strlist *namelist, bool allow_suffix)
474{ 515{
475 int i, ret; 516 int i, ret;
476 517
@@ -481,6 +522,12 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
481 if (!strlist__has_entry(namelist, buf)) 522 if (!strlist__has_entry(namelist, buf))
482 return; 523 return;
483 524
525 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event.");
529 }
530
484 /* Try to add suffix */ 531 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) { 532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
486 ret = e_snprintf(buf, len, "%s_%d", base, i); 533 ret = e_snprintf(buf, len, "%s_%d", base, i);
@@ -493,13 +540,15 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
493 die("Too many events are on the same function."); 540 die("Too many events are on the same function.");
494} 541}
495 542
496void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) 543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
544 bool force_add)
497{ 545{
498 int i, j, fd; 546 int i, j, fd;
499 struct probe_point *pp; 547 struct probe_point *pp;
500 char buf[MAX_CMDLEN]; 548 char buf[MAX_CMDLEN];
501 char event[64]; 549 char event[64];
502 struct strlist *namelist; 550 struct strlist *namelist;
551 bool allow_suffix;
503 552
504 fd = open_kprobe_events(O_RDWR, O_APPEND); 553 fd = open_kprobe_events(O_RDWR, O_APPEND);
505 /* Get current event names */ 554 /* Get current event names */
@@ -507,21 +556,35 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
507 556
508 for (j = 0; j < nr_probes; j++) { 557 for (j = 0; j < nr_probes; j++) {
509 pp = probes + j; 558 pp = probes + j;
559 if (!pp->event)
560 pp->event = strdup(pp->function);
561 if (!pp->group)
562 pp->group = strdup(PERFPROBE_GROUP);
563 DIE_IF(!pp->event || !pp->group);
564 /* If force_add is true, suffix search is allowed */
565 allow_suffix = force_add;
510 for (i = 0; i < pp->found; i++) { 566 for (i = 0; i < pp->found; i++) {
511 /* Get an unused new event name */ 567 /* Get an unused new event name */
512 get_new_event_name(event, 64, pp->function, namelist); 568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
513 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
514 pp->retprobe ? 'r' : 'p', 571 pp->retprobe ? 'r' : 'p',
515 PERFPROBE_GROUP, event, 572 pp->group, event,
516 pp->probes[i]); 573 pp->probes[i]);
517 write_trace_kprobe_event(fd, buf); 574 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n"); 575 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */ 576 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf); 577 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event, 578 show_perf_probe_event(event, buf, pp);
522 buf, pp);
523 /* Add added event name to namelist */ 579 /* Add added event name to namelist */
524 strlist__add(namelist, event); 580 strlist__add(namelist, event);
581 /*
582 * Probes after the first probe which comes from same
583 * user input are always allowed to add suffix, because
584 * there might be several addresses corresponding to
585 * one code line.
586 */
587 allow_suffix = true;
525 } 588 }
526 } 589 }
527 /* Show how to use the event. */ 590 /* Show how to use the event. */
@@ -532,29 +595,55 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
532 close(fd); 595 close(fd);
533} 596}
534 597
598static void __del_trace_kprobe_event(int fd, struct str_node *ent)
599{
600 char *p;
601 char buf[128];
602
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':');
607 if (!p)
608 die("Internal error: %s should have ':' but not.", ent->s);
609 *p = '/';
610
611 write_trace_kprobe_event(fd, buf);
612 printf("Remove event: %s\n", ent->s);
613}
614
535static void del_trace_kprobe_event(int fd, const char *group, 615static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist) 616 const char *event, struct strlist *namelist)
537{ 617{
538 char buf[128]; 618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
539 621
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event."); 623 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549 624
550 write_trace_kprobe_event(fd, buf); 625 if (strpbrk(buf, "*?")) { /* Glob-exp */
551 printf("Remove event: %s:%s\n", group, event); 626 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) {
628 found++;
629 __del_trace_kprobe_event(fd, ent);
630 strlist__remove(namelist, ent);
631 }
632 } else {
633 ent = strlist__find(namelist, buf);
634 if (ent) {
635 found++;
636 __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent);
638 }
639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
552} 642}
553 643
554void del_trace_kprobe_events(struct strlist *dellist) 644void del_trace_kprobe_events(struct strlist *dellist)
555{ 645{
556 int fd; 646 int fd;
557 unsigned int i;
558 const char *group, *event; 647 const char *group, *event;
559 char *p, *str; 648 char *p, *str;
560 struct str_node *ent; 649 struct str_node *ent;
@@ -564,20 +653,21 @@ void del_trace_kprobe_events(struct strlist *dellist)
564 /* Get current event names */ 653 /* Get current event names */
565 namelist = get_perf_event_names(fd, true); 654 namelist = get_perf_event_names(fd, true);
566 655
567 for (i = 0; i < strlist__nr_entries(dellist); i++) { 656 strlist__for_each(ent, dellist) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s); 657 str = strdup(ent->s);
570 if (!str) 658 if (!str)
571 die("Failed to copy event."); 659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
572 p = strchr(str, ':'); 661 p = strchr(str, ':');
573 if (p) { 662 if (p) {
574 group = str; 663 group = str;
575 *p = '\0'; 664 *p = '\0';
576 event = p + 1; 665 event = p + 1;
577 } else { 666 } else {
578 group = PERFPROBE_GROUP; 667 group = "*";
579 event = str; 668 event = str;
580 } 669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
581 del_trace_kprobe_event(fd, group, event, namelist); 671 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str); 672 free(str);
583 } 673 }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f752159124a..7f1d499118c 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,15 +1,18 @@
1#ifndef _PROBE_EVENT_H 1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h>
4#include "probe-finder.h" 5#include "probe-finder.h"
5#include "strlist.h" 6#include "strlist.h"
6 7
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 8extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp); 11extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group, 12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
13extern void del_trace_kprobe_events(struct strlist *dellist); 16extern void del_trace_kprobe_events(struct strlist *dellist);
14extern void show_perf_probe_events(void); 17extern void show_perf_probe_events(void);
15 18
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4585f1d8679..4b852c0d16a 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -687,10 +687,8 @@ int find_probepoint(int fd, struct probe_point *pp)
687 struct probe_finder pf = {.pp = pp}; 687 struct probe_finder pf = {.pp = pp};
688 688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK) { 690 if (ret != DW_DLV_OK)
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT; 691 return -ENOENT;
693 }
694 692
695 pp->found = 0; 693 pp->found = 0;
696 while (++cu_number) { 694 while (++cu_number) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bdebca6697d..a4086aaddb7 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,9 +1,9 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#define MAX_PATH_LEN 256 4#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 5#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 6#define MAX_PROBES 128
7 7
8static inline int is_c_varname(const char *name) 8static inline int is_c_varname(const char *name)
9{ 9{
@@ -12,45 +12,53 @@ static inline int is_c_varname(const char *name)
12} 12}
13 13
14struct probe_point { 14struct probe_point {
15 char *event; /* Event name */
16 char *group; /* Event group */
17
15 /* Inputs */ 18 /* Inputs */
16 char *file; /* File name */ 19 char *file; /* File name */
17 int line; /* Line number */ 20 int line; /* Line number */
18 21
19 char *function; /* Function name */ 22 char *function; /* Function name */
20 int offset; /* Offset bytes */ 23 int offset; /* Offset bytes */
21 24
22 int nr_args; /* Number of arguments */ 25 int nr_args; /* Number of arguments */
23 char **args; /* Arguments */ 26 char **args; /* Arguments */
24 27
25 int retprobe; /* Return probe */ 28 int retprobe; /* Return probe */
26 29
27 /* Output */ 30 /* Output */
28 int found; /* Number of found probe points */ 31 int found; /* Number of found probe points */
29 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
30}; 33};
31 34
32#ifndef NO_LIBDWARF 35#ifndef NO_LIBDWARF
33extern int find_probepoint(int fd, struct probe_point *pp); 36extern int find_probepoint(int fd, struct probe_point *pp);
34 37
35#include <libdwarf/dwarf.h> 38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
36#include <libdwarf/libdwarf.h> 39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42
43#include <dwarf.h>
44#include <libdwarf.h>
37 45
38struct probe_finder { 46struct probe_finder {
39 struct probe_point *pp; /* Target probe point */ 47 struct probe_point *pp; /* Target probe point */
40 48
41 /* For function searching */ 49 /* For function searching */
42 Dwarf_Addr addr; /* Address */ 50 Dwarf_Addr addr; /* Address */
43 Dwarf_Unsigned fno; /* File number */ 51 Dwarf_Unsigned fno; /* File number */
44 Dwarf_Unsigned lno; /* Line number */ 52 Dwarf_Unsigned lno; /* Line number */
45 Dwarf_Off inl_offs; /* Inline offset */ 53 Dwarf_Off inl_offs; /* Inline offset */
46 Dwarf_Die cu_die; /* Current CU */ 54 Dwarf_Die cu_die; /* Current CU */
47 55
48 /* For variable searching */ 56 /* For variable searching */
49 Dwarf_Addr cu_base; /* Current CU base address */ 57 Dwarf_Addr cu_base; /* Current CU base address */
50 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
51 const char *var; /* Current variable name */ 59 const char *var; /* Current variable name */
52 char *buf; /* Current output buffer */ 60 char *buf; /* Current output buffer */
53 int len; /* Length of output buffer */ 61 int len; /* Length of output buffer */
54}; 62};
55#endif /* NO_LIBDWARF */ 63#endif /* NO_LIBDWARF */
56 64
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 00000000000..ce3a6c8abe7
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,150 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "sort.h"
8#include "util.h"
9
10static int perf_session__open(struct perf_session *self, bool force)
11{
12 struct stat input_stat;
13
14 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename);
17 if (!strcmp(self->filename, "perf.data"))
18 pr_err(" (try 'perf record' first)");
19 pr_err("\n");
20 return -errno;
21 }
22
23 if (fstat(self->fd, &input_stat) < 0)
24 goto out_close;
25
26 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
27 pr_err("file %s not owned by current user or root\n",
28 self->filename);
29 goto out_close;
30 }
31
32 if (!input_stat.st_size) {
33 pr_info("zero-sized file (%s), nothing to do!\n",
34 self->filename);
35 goto out_close;
36 }
37
38 if (perf_header__read(&self->header, self->fd) < 0) {
39 pr_err("incompatible file format");
40 goto out_close;
41 }
42
43 self->size = input_stat.st_size;
44 return 0;
45
46out_close:
47 close(self->fd);
48 self->fd = -1;
49 return -1;
50}
51
52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{
54 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len);
56
57 if (self == NULL)
58 goto out;
59
60 if (perf_header__init(&self->header) < 0)
61 goto out_free;
62
63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
73
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
75 goto out_delete;
76out:
77 return self;
78out_free:
79 free(self);
80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
84}
85
86void perf_session__delete(struct perf_session *self)
87{
88 perf_header__exit(&self->header);
89 close(self->fd);
90 free(self->cwd);
91 free(self);
92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 00000000000..32eaa1bada0
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
13
14struct perf_session {
15 struct perf_header header;
16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
25 int fd;
26 int cwdlen;
27 char *cwd;
28 char filename[0];
29};
30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self);
50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
61#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b490354d1b2..cb0f327de9e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -288,3 +288,29 @@ int sort_dimension__add(const char *tok)
288 288
289 return -ESRCH; 289 return -ESRCH;
290} 290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 333e664ff45..753f9ea99fb 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,9 +49,13 @@ struct hist_entry {
49 struct symbol *sym; 49 struct symbol *sym;
50 u64 ip; 50 u64 ip;
51 char level; 51 char level;
52 struct symbol *parent; 52 struct symbol *parent;
53 struct callchain_node callchain; 53 struct callchain_node callchain;
54 struct rb_root sorted_chain; 54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
55}; 59};
56 60
57enum sort_type { 61enum sort_type {
@@ -81,6 +85,8 @@ struct sort_entry {
81extern struct sort_entry sort_thread; 85extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list; 86extern struct list_head hist_entry__sort_list;
83 87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...); 90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
@@ -95,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *); 103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
98 106
99#endif /* __PERF_SORT_H */ 107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f24a8cc933d..5352d7dccc6 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -226,3 +226,28 @@ fail:
226 argv_free(argv); 226 argv_free(argv);
227 return NULL; 227 return NULL;
228} 228}
229
230/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bfecec265a1..02ede58c54b 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
@@ -8,6 +9,7 @@ char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 9s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
11 13
12#define _STR(x) #x 14#define _STR(x) #x
13#define STR(x) _STR(x) 15#define STR(x) _STR(x)
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2..6783a204355 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index cb4659306d7..3ba839007d2 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* __PERF_STRLIST_H */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e7508ad3450..ab92763edb0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,7 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
5#include "thread.h" 7#include "thread.h"
@@ -29,33 +31,50 @@ enum dso_origin {
29}; 31};
30 32
31static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *thread__find_map_by_name(struct thread *self, char *name);
33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct thread *thread, symbol_filter_t filter); 36 struct perf_session *session, symbol_filter_t filter);
37unsigned int symbol__priv_size;
38static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
39static char **vmlinux_path; 38static char **vmlinux_path;
40 39
41static struct symbol_conf symbol_conf__defaults = { 40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
42 .use_modules = true, 42 .use_modules = true,
43 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
44}; 44};
45 45
46static struct thread kthread_mem;
47struct thread *kthread = &kthread_mem;
48
49bool dso__loaded(const struct dso *self, enum map_type type) 46bool dso__loaded(const struct dso *self, enum map_type type)
50{ 47{
51 return self->loaded & (1 << type); 48 return self->loaded & (1 << type);
52} 49}
53 50
51bool dso__sorted_by_name(const struct dso *self, enum map_type type)
52{
53 return self->sorted_by_name & (1 << type);
54}
55
54static void dso__set_loaded(struct dso *self, enum map_type type) 56static void dso__set_loaded(struct dso *self, enum map_type type)
55{ 57{
56 self->loaded |= (1 << type); 58 self->loaded |= (1 << type);
57} 59}
58 60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{
63 self->sorted_by_name |= (1 << type);
64}
65
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{
68 switch (map_type) {
69 case MAP__FUNCTION:
70 return symbol_type == 'T' || symbol_type == 'W';
71 case MAP__VARIABLE:
72 return symbol_type == 'D' || symbol_type == 'd';
73 default:
74 return false;
75 }
76}
77
59static void symbols__fixup_end(struct rb_root *self) 78static void symbols__fixup_end(struct rb_root *self)
60{ 79{
61 struct rb_node *nd, *prevnd = rb_first(self); 80 struct rb_node *nd, *prevnd = rb_first(self);
@@ -79,7 +98,7 @@ static void symbols__fixup_end(struct rb_root *self)
79 curr->end = roundup(curr->start, 4096); 98 curr->end = roundup(curr->start, 4096);
80} 99}
81 100
82static void __thread__fixup_maps_end(struct thread *self, enum map_type type) 101static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
83{ 102{
84 struct map *prev, *curr; 103 struct map *prev, *curr;
85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 104 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
@@ -102,23 +121,23 @@ static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
102 curr->end = ~0UL; 121 curr->end = ~0UL;
103} 122}
104 123
105static void thread__fixup_maps_end(struct thread *self) 124static void map_groups__fixup_end(struct map_groups *self)
106{ 125{
107 int i; 126 int i;
108 for (i = 0; i < MAP__NR_TYPES; ++i) 127 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i); 128 __map_groups__fixup_end(self, i);
110} 129}
111 130
112static struct symbol *symbol__new(u64 start, u64 len, const char *name) 131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
113{ 132{
114 size_t namelen = strlen(name) + 1; 133 size_t namelen = strlen(name) + 1;
115 struct symbol *self = zalloc(symbol__priv_size + 134 struct symbol *self = zalloc(symbol_conf.priv_size +
116 sizeof(*self) + namelen); 135 sizeof(*self) + namelen);
117 if (self == NULL) 136 if (self == NULL)
118 return NULL; 137 return NULL;
119 138
120 if (symbol__priv_size) 139 if (symbol_conf.priv_size)
121 self = ((void *)self) + symbol__priv_size; 140 self = ((void *)self) + symbol_conf.priv_size;
122 141
123 self->start = start; 142 self->start = start;
124 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
@@ -132,7 +151,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
132 151
133static void symbol__delete(struct symbol *self) 152static void symbol__delete(struct symbol *self)
134{ 153{
135 free(((void *)self) - symbol__priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
136} 155}
137 156
138static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -164,11 +183,11 @@ struct dso *dso__new(const char *name)
164 dso__set_long_name(self, self->name); 183 dso__set_long_name(self, self->name);
165 self->short_name = self->name; 184 self->short_name = self->name;
166 for (i = 0; i < MAP__NR_TYPES; ++i) 185 for (i = 0; i < MAP__NR_TYPES; ++i)
167 self->symbols[i] = RB_ROOT; 186 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
168 self->find_symbol = dso__find_symbol;
169 self->slen_calculated = 0; 187 self->slen_calculated = 0;
170 self->origin = DSO__ORIG_NOT_FOUND; 188 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0; 189 self->loaded = 0;
190 self->sorted_by_name = 0;
172 self->has_build_id = 0; 191 self->has_build_id = 0;
173 } 192 }
174 193
@@ -246,11 +265,85 @@ static struct symbol *symbols__find(struct rb_root *self, u64 ip)
246 return NULL; 265 return NULL;
247} 266}
248 267
249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 268struct symbol_name_rb_node {
269 struct rb_node rb_node;
270 struct symbol sym;
271};
272
273static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
274{
275 struct rb_node **p = &self->rb_node;
276 struct rb_node *parent = NULL;
277 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
278
279 while (*p != NULL) {
280 parent = *p;
281 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
282 if (strcmp(sym->name, s->sym.name) < 0)
283 p = &(*p)->rb_left;
284 else
285 p = &(*p)->rb_right;
286 }
287 rb_link_node(&symn->rb_node, parent, p);
288 rb_insert_color(&symn->rb_node, self);
289}
290
291static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
292{
293 struct rb_node *nd;
294
295 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
296 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
297 symbols__insert_by_name(self, pos);
298 }
299}
300
301static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
302{
303 struct rb_node *n;
304
305 if (self == NULL)
306 return NULL;
307
308 n = self->rb_node;
309
310 while (n) {
311 struct symbol_name_rb_node *s;
312 int cmp;
313
314 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
315 cmp = strcmp(name, s->sym.name);
316
317 if (cmp < 0)
318 n = n->rb_left;
319 else if (cmp > 0)
320 n = n->rb_right;
321 else
322 return &s->sym;
323 }
324
325 return NULL;
326}
327
328struct symbol *dso__find_symbol(struct dso *self,
329 enum map_type type, u64 addr)
250{ 330{
251 return symbols__find(&self->symbols[type], addr); 331 return symbols__find(&self->symbols[type], addr);
252} 332}
253 333
334struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
335 const char *name)
336{
337 return symbols__find_by_name(&self->symbol_names[type], name);
338}
339
340void dso__sort_by_name(struct dso *self, enum map_type type)
341{
342 dso__set_sorted_by_name(self, type);
343 return symbols__sort_by_name(&self->symbol_names[type],
344 &self->symbols[type]);
345}
346
254int build_id__sprintf(u8 *self, int len, char *bf) 347int build_id__sprintf(u8 *self, int len, char *bf)
255{ 348{
256 char *bid = bf; 349 char *bid = bf;
@@ -327,10 +420,7 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
327 continue; 420 continue;
328 421
329 symbol_type = toupper(line[len]); 422 symbol_type = toupper(line[len]);
330 /* 423 if (!symbol_type__is_a(symbol_type, map->type))
331 * We're interested only in code ('T'ext)
332 */
333 if (symbol_type != 'T' && symbol_type != 'W')
334 continue; 424 continue;
335 425
336 symbol_name = line + len + 2; 426 symbol_name = line + len + 2;
@@ -364,8 +454,8 @@ out_failure:
364 * kernel range is broken in several maps, named [kernel].N, as we don't have 454 * kernel range is broken in several maps, named [kernel].N, as we don't have
365 * the original ELF section names vmlinux have. 455 * the original ELF section names vmlinux have.
366 */ 456 */
367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, 457static int dso__split_kallsyms(struct dso *self, struct map *map,
368 symbol_filter_t filter) 458 struct perf_session *session, symbol_filter_t filter)
369{ 459{
370 struct map *curr_map = map; 460 struct map *curr_map = map;
371 struct symbol *pos; 461 struct symbol *pos;
@@ -382,13 +472,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
382 472
383 module = strchr(pos->name, '\t'); 473 module = strchr(pos->name, '\t');
384 if (module) { 474 if (module) {
385 if (!thread->use_modules) 475 if (!symbol_conf.use_modules)
386 goto discard_symbol; 476 goto discard_symbol;
387 477
388 *module++ = '\0'; 478 *module++ = '\0';
389 479
390 if (strcmp(self->name, module)) { 480 if (strcmp(self->name, module)) {
391 curr_map = thread__find_map_by_name(thread, module); 481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
392 if (curr_map == NULL) { 482 if (curr_map == NULL) {
393 pr_debug("/proc/{kallsyms,modules} " 483 pr_debug("/proc/{kallsyms,modules} "
394 "inconsistency!\n"); 484 "inconsistency!\n");
@@ -419,7 +509,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread
419 } 509 }
420 510
421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422 __thread__insert_map(thread, curr_map); 512 map_groups__insert(&session->kmaps, curr_map);
423 ++kernel_range; 513 ++kernel_range;
424 } 514 }
425 515
@@ -440,7 +530,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
440 530
441 531
442static int dso__load_kallsyms(struct dso *self, struct map *map, 532static int dso__load_kallsyms(struct dso *self, struct map *map,
443 struct thread *thread, symbol_filter_t filter) 533 struct perf_session *session, symbol_filter_t filter)
444{ 534{
445 if (dso__load_all_kallsyms(self, map) < 0) 535 if (dso__load_all_kallsyms(self, map) < 0)
446 return -1; 536 return -1;
@@ -448,14 +538,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
448 symbols__fixup_end(&self->symbols[map->type]); 538 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL; 539 self->origin = DSO__ORIG_KERNEL;
450 540
451 return dso__split_kallsyms(self, map, thread, filter); 541 return dso__split_kallsyms(self, map, session, filter);
452}
453
454size_t kernel_maps__fprintf(FILE *fp)
455{
456 size_t printed = fprintf(fp, "Kernel maps:\n");
457 printed += thread__fprintf_maps(kthread, fp);
458 return printed + fprintf(fp, "END kernel maps\n");
459} 542}
460 543
461static int dso__load_perf_map(struct dso *self, struct map *map, 544static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -544,6 +627,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
544 sym->st_shndx != SHN_UNDEF; 627 sym->st_shndx != SHN_UNDEF;
545} 628}
546 629
630static inline bool elf_sym__is_object(const GElf_Sym *sym)
631{
632 return elf_sym__type(sym) == STT_OBJECT &&
633 sym->st_name != 0 &&
634 sym->st_shndx != SHN_UNDEF;
635}
636
547static inline int elf_sym__is_label(const GElf_Sym *sym) 637static inline int elf_sym__is_label(const GElf_Sym *sym)
548{ 638{
549 return elf_sym__type(sym) == STT_NOTYPE && 639 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -564,6 +654,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
564 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 654 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
565} 655}
566 656
657static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
658 const Elf_Data *secstrs)
659{
660 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
661}
662
567static inline const char *elf_sym__name(const GElf_Sym *sym, 663static inline const char *elf_sym__name(const GElf_Sym *sym,
568 const Elf_Data *symstrs) 664 const Elf_Data *symstrs)
569{ 665{
@@ -744,8 +840,32 @@ out:
744 return 0; 840 return 0;
745} 841}
746 842
843static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
844{
845 switch (type) {
846 case MAP__FUNCTION:
847 return elf_sym__is_function(self);
848 case MAP__VARIABLE:
849 return elf_sym__is_object(self);
850 default:
851 return false;
852 }
853}
854
855static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
856{
857 switch (type) {
858 case MAP__FUNCTION:
859 return elf_sec__is_text(self, secstrs);
860 case MAP__VARIABLE:
861 return elf_sec__is_data(self, secstrs);
862 default:
863 return false;
864 }
865}
866
747static int dso__load_sym(struct dso *self, struct map *map, 867static int dso__load_sym(struct dso *self, struct map *map,
748 struct thread *thread, const char *name, int fd, 868 struct perf_session *session, const char *name, int fd,
749 symbol_filter_t filter, int kernel, int kmodule) 869 symbol_filter_t filter, int kernel, int kmodule)
750{ 870{
751 struct map *curr_map = map; 871 struct map *curr_map = map;
@@ -818,7 +938,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
818 int is_label = elf_sym__is_label(&sym); 938 int is_label = elf_sym__is_label(&sym);
819 const char *section_name; 939 const char *section_name;
820 940
821 if (!is_label && !elf_sym__is_function(&sym)) 941 if (!is_label && !elf_sym__is_a(&sym, map->type))
822 continue; 942 continue;
823 943
824 sec = elf_getscn(elf, sym.st_shndx); 944 sec = elf_getscn(elf, sym.st_shndx);
@@ -827,7 +947,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
827 947
828 gelf_getshdr(sec, &shdr); 948 gelf_getshdr(sec, &shdr);
829 949
830 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
831 continue; 951 continue;
832 952
833 elf_name = elf_sym__name(&sym, symstrs); 953 elf_name = elf_sym__name(&sym, symstrs);
@@ -849,7 +969,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
849 snprintf(dso_name, sizeof(dso_name), 969 snprintf(dso_name, sizeof(dso_name),
850 "%s%s", self->short_name, section_name); 970 "%s%s", self->short_name, section_name);
851 971
852 curr_map = thread__find_map_by_name(thread, dso_name); 972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
853 if (curr_map == NULL) { 973 if (curr_map == NULL) {
854 u64 start = sym.st_value; 974 u64 start = sym.st_value;
855 975
@@ -868,7 +988,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
868 curr_map->map_ip = identity__map_ip; 988 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip; 989 curr_map->unmap_ip = identity__map_ip;
870 curr_dso->origin = DSO__ORIG_KERNEL; 990 curr_dso->origin = DSO__ORIG_KERNEL;
871 __thread__insert_map(kthread, curr_map); 991 map_groups__insert(&session->kmaps, curr_map);
872 dsos__add(&dsos__kernel, curr_dso); 992 dsos__add(&dsos__kernel, curr_dso);
873 } else 993 } else
874 curr_dso = curr_map->dso; 994 curr_dso = curr_map->dso;
@@ -1083,7 +1203,8 @@ char dso__symtab_origin(const struct dso *self)
1083 return origin[self->origin]; 1203 return origin[self->origin];
1084} 1204}
1085 1205
1086int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
1087{ 1208{
1088 int size = PATH_MAX; 1209 int size = PATH_MAX;
1089 char *name; 1210 char *name;
@@ -1094,7 +1215,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1094 dso__set_loaded(self, map->type); 1215 dso__set_loaded(self, map->type);
1095 1216
1096 if (self->kernel) 1217 if (self->kernel)
1097 return dso__load_kernel_sym(self, map, kthread, filter); 1218 return dso__load_kernel_sym(self, map, session, filter);
1098 1219
1099 name = malloc(size); 1220 name = malloc(size);
1100 if (!name) 1221 if (!name)
@@ -1180,11 +1301,12 @@ out:
1180 return ret; 1301 return ret;
1181} 1302}
1182 1303
1183static struct map *thread__find_map_by_name(struct thread *self, char *name) 1304struct map *map_groups__find_by_name(struct map_groups *self,
1305 enum map_type type, const char *name)
1184{ 1306{
1185 struct rb_node *nd; 1307 struct rb_node *nd;
1186 1308
1187 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1188 struct map *map = rb_entry(nd, struct map, rb_node); 1310 struct map *map = rb_entry(nd, struct map, rb_node);
1189 1311
1190 if (map->dso && strcmp(map->dso->name, name) == 0) 1312 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1194,7 +1316,7 @@ static struct map *thread__find_map_by_name(struct thread *self, char *name)
1194 return NULL; 1316 return NULL;
1195} 1317}
1196 1318
1197static int dsos__set_modules_path_dir(char *dirname) 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1198{ 1320{
1199 struct dirent *dent; 1321 struct dirent *dent;
1200 DIR *dir = opendir(dirname); 1322 DIR *dir = opendir(dirname);
@@ -1214,7 +1336,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1214 1336
1215 snprintf(path, sizeof(path), "%s/%s", 1337 snprintf(path, sizeof(path), "%s/%s",
1216 dirname, dent->d_name); 1338 dirname, dent->d_name);
1217 if (dsos__set_modules_path_dir(path) < 0) 1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1218 goto failure; 1340 goto failure;
1219 } else { 1341 } else {
1220 char *dot = strrchr(dent->d_name, '.'), 1342 char *dot = strrchr(dent->d_name, '.'),
@@ -1228,7 +1350,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1228 (int)(dot - dent->d_name), dent->d_name); 1350 (int)(dot - dent->d_name), dent->d_name);
1229 1351
1230 strxfrchar(dso_name, '-', '_'); 1352 strxfrchar(dso_name, '-', '_');
1231 map = thread__find_map_by_name(kthread, dso_name); 1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1232 if (map == NULL) 1354 if (map == NULL)
1233 continue; 1355 continue;
1234 1356
@@ -1248,7 +1370,7 @@ failure:
1248 return -1; 1370 return -1;
1249} 1371}
1250 1372
1251static int dsos__set_modules_path(void) 1373static int perf_session__set_modules_path(struct perf_session *self)
1252{ 1374{
1253 struct utsname uts; 1375 struct utsname uts;
1254 char modules_path[PATH_MAX]; 1376 char modules_path[PATH_MAX];
@@ -1259,7 +1381,7 @@ static int dsos__set_modules_path(void)
1259 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1260 uts.release); 1382 uts.release);
1261 1383
1262 return dsos__set_modules_path_dir(modules_path); 1384 return perf_session__set_modules_path_dir(self, modules_path);
1263} 1385}
1264 1386
1265/* 1387/*
@@ -1281,7 +1403,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1281 return self; 1403 return self;
1282} 1404}
1283 1405
1284static int thread__create_module_maps(struct thread *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
1285{ 1407{
1286 char *line = NULL; 1408 char *line = NULL;
1287 size_t n; 1409 size_t n;
@@ -1338,14 +1460,14 @@ static int thread__create_module_maps(struct thread *self)
1338 dso->has_build_id = true; 1460 dso->has_build_id = true;
1339 1461
1340 dso->origin = DSO__ORIG_KMODULE; 1462 dso->origin = DSO__ORIG_KMODULE;
1341 __thread__insert_map(self, map); 1463 map_groups__insert(&self->kmaps, map);
1342 dsos__add(&dsos__kernel, dso); 1464 dsos__add(&dsos__kernel, dso);
1343 } 1465 }
1344 1466
1345 free(line); 1467 free(line);
1346 fclose(file); 1468 fclose(file);
1347 1469
1348 return dsos__set_modules_path(); 1470 return perf_session__set_modules_path(self);
1349 1471
1350out_delete_line: 1472out_delete_line:
1351 free(line); 1473 free(line);
@@ -1353,7 +1475,8 @@ out_failure:
1353 return -1; 1475 return -1;
1354} 1476}
1355 1477
1356static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1357 const char *vmlinux, symbol_filter_t filter) 1480 const char *vmlinux, symbol_filter_t filter)
1358{ 1481{
1359 int err = -1, fd; 1482 int err = -1, fd;
@@ -1387,14 +1510,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t
1387 return -1; 1510 return -1;
1388 1511
1389 dso__set_loaded(self, map->type); 1512 dso__set_loaded(self, map->type);
1390 err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); 1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
1391 close(fd); 1514 close(fd);
1392 1515
1393 return err; 1516 return err;
1394} 1517}
1395 1518
1396static int dso__load_kernel_sym(struct dso *self, struct map *map, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
1397 struct thread *thread, symbol_filter_t filter) 1520 struct perf_session *session, symbol_filter_t filter)
1398{ 1521{
1399 int err; 1522 int err;
1400 bool is_kallsyms; 1523 bool is_kallsyms;
@@ -1404,7 +1527,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1404 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1405 vmlinux_path__nr_entries); 1528 vmlinux_path__nr_entries);
1406 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1407 err = dso__load_vmlinux(self, map, thread, 1530 err = dso__load_vmlinux(self, map, session,
1408 vmlinux_path[i], filter); 1531 vmlinux_path[i], filter);
1409 if (err > 0) { 1532 if (err > 0) {
1410 pr_debug("Using %s for symbols\n", 1533 pr_debug("Using %s for symbols\n",
@@ -1420,12 +1543,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1420 if (is_kallsyms) 1543 if (is_kallsyms)
1421 goto do_kallsyms; 1544 goto do_kallsyms;
1422 1545
1423 err = dso__load_vmlinux(self, map, thread, self->long_name, filter); 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1424 if (err <= 0) { 1547 if (err <= 0) {
1425 pr_info("The file %s cannot be used, " 1548 pr_info("The file %s cannot be used, "
1426 "trying to use /proc/kallsyms...", self->long_name); 1549 "trying to use /proc/kallsyms...", self->long_name);
1427do_kallsyms: 1550do_kallsyms:
1428 err = dso__load_kallsyms(self, map, thread, filter); 1551 err = dso__load_kallsyms(self, map, session, filter);
1429 if (err > 0 && !is_kallsyms) 1552 if (err > 0 && !is_kallsyms)
1430 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1431 } 1554 }
@@ -1508,42 +1631,59 @@ size_t dsos__fprintf_buildid(FILE *fp)
1508 __dsos__fprintf_buildid(&dsos__user, fp)); 1631 __dsos__fprintf_buildid(&dsos__user, fp));
1509} 1632}
1510 1633
1511static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1634static struct dso *dsos__create_kernel( const char *vmlinux)
1512{ 1635{
1513 struct map *kmap;
1514 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1515 1637
1516 if (kernel == NULL) 1638 if (kernel == NULL)
1517 return -1; 1639 return NULL;
1518
1519 kmap = map__new2(0, kernel, MAP__FUNCTION);
1520 if (kmap == NULL)
1521 goto out_delete_kernel_dso;
1522 1640
1523 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1524 kernel->short_name = "[kernel]"; 1641 kernel->short_name = "[kernel]";
1525 kernel->kernel = 1; 1642 kernel->kernel = 1;
1526 1643
1527 vdso = dso__new("[vdso]"); 1644 vdso = dso__new("[vdso]");
1528 if (vdso == NULL) 1645 if (vdso == NULL)
1529 goto out_delete_kernel_map; 1646 goto out_delete_kernel_dso;
1530 dso__set_loaded(vdso, MAP__FUNCTION); 1647 dso__set_loaded(vdso, MAP__FUNCTION);
1531 1648
1532 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1533 sizeof(kernel->build_id)) == 0) 1650 sizeof(kernel->build_id)) == 0)
1534 kernel->has_build_id = true; 1651 kernel->has_build_id = true;
1535 1652
1536 __thread__insert_map(self, kmap);
1537 dsos__add(&dsos__kernel, kernel); 1653 dsos__add(&dsos__kernel, kernel);
1538 dsos__add(&dsos__user, vdso); 1654 dsos__add(&dsos__user, vdso);
1539 1655
1540 return 0; 1656 return kernel;
1541 1657
1542out_delete_kernel_map:
1543 map__delete(kmap);
1544out_delete_kernel_dso: 1658out_delete_kernel_dso:
1545 dso__delete(kernel); 1659 dso__delete(kernel);
1546 return -1; 1660 return NULL;
1661}
1662
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1664{
1665 struct map *functions, *variables;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667
1668 if (kernel == NULL)
1669 return -1;
1670
1671 functions = map__new2(0, kernel, MAP__FUNCTION);
1672 if (functions == NULL)
1673 return -1;
1674
1675 variables = map__new2(0, kernel, MAP__VARIABLE);
1676 if (variables == NULL) {
1677 map__delete(functions);
1678 return -1;
1679 }
1680
1681 functions->map_ip = functions->unmap_ip =
1682 variables->map_ip = variables->unmap_ip = identity__map_ip;
1683 map_groups__insert(self, functions);
1684 map_groups__insert(self, variables);
1685
1686 return 0;
1547} 1687}
1548 1688
1549static void vmlinux_path__exit(void) 1689static void vmlinux_path__exit(void)
@@ -1601,29 +1741,69 @@ out_fail:
1601 return -1; 1741 return -1;
1602} 1742}
1603 1743
1604int symbol__init(struct symbol_conf *conf) 1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1605{ 1746{
1606 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1747 if (list_str == NULL)
1748 return 0;
1607 1749
1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1757
1758int symbol__init(void)
1759{
1608 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1609 symbol__priv_size = pconf->priv_size; 1761 if (symbol_conf.sort_by_name)
1610 thread__init(kthread, 0); 1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1763 sizeof(struct symbol));
1611 1764
1612 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1613 return -1; 1766 return -1;
1614 1767
1615 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { 1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1616 vmlinux_path__exit(); 1769 pr_err("'.' is the only non valid --field-separator argument\n");
1617 return -1; 1770 return -1;
1618 } 1771 }
1619 1772
1620 kthread->use_modules = pconf->use_modules; 1773 if (setup_list(&symbol_conf.dso_list,
1621 if (pconf->use_modules && thread__create_module_maps(kthread) < 0) 1774 symbol_conf.dso_list_str, "dso") < 0)
1622 pr_debug("Failed to load list of modules in use, " 1775 return -1;
1623 "continuing...\n"); 1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1624 /* 1804 /*
1625 * Now that we have all the maps created, just set the ->end of them: 1805 * Now that we have all the maps created, just set the ->end of them:
1626 */ 1806 */
1627 thread__fixup_maps_end(kthread); 1807 map_groups__fixup_end(&self->kmaps);
1628 return 0; 1808 return 0;
1629} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 17003efa0b3..8aded2356f7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,18 +49,32 @@ struct symbol {
49 char name[0]; 49 char name[0];
50}; 50};
51 51
52struct strlist;
53
52struct symbol_conf { 54struct symbol_conf {
53 unsigned short priv_size; 55 unsigned short priv_size;
54 bool try_vmlinux_path, 56 bool try_vmlinux_path,
55 use_modules; 57 use_modules,
56 const char *vmlinux_name; 58 sort_by_name,
59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
57}; 71};
58 72
59extern unsigned int symbol__priv_size; 73extern struct symbol_conf symbol_conf;
60 74
61static inline void *symbol__priv(struct symbol *self) 75static inline void *symbol__priv(struct symbol *self)
62{ 76{
63 return ((void *)self) - symbol__priv_size; 77 return ((void *)self) - symbol_conf.priv_size;
64} 78}
65 79
66struct addr_location { 80struct addr_location {
@@ -69,18 +83,19 @@ struct addr_location {
69 struct symbol *sym; 83 struct symbol *sym;
70 u64 addr; 84 u64 addr;
71 char level; 85 char level;
86 bool filtered;
72}; 87};
73 88
74struct dso { 89struct dso {
75 struct list_head node; 90 struct list_head node;
76 struct rb_root symbols[MAP__NR_TYPES]; 91 struct rb_root symbols[MAP__NR_TYPES];
77 struct symbol *(*find_symbol)(struct dso *self, 92 struct rb_root symbol_names[MAP__NR_TYPES];
78 enum map_type type, u64 addr);
79 u8 adjust_symbols:1; 93 u8 adjust_symbols:1;
80 u8 slen_calculated:1; 94 u8 slen_calculated:1;
81 u8 has_build_id:1; 95 u8 has_build_id:1;
82 u8 kernel:1; 96 u8 kernel:1;
83 unsigned char origin; 97 unsigned char origin;
98 u8 sorted_by_name;
84 u8 loaded; 99 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE]; 100 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len; 101 u16 long_name_len;
@@ -93,9 +108,15 @@ struct dso *dso__new(const char *name);
93void dso__delete(struct dso *self); 108void dso__delete(struct dso *self);
94 109
95bool dso__loaded(const struct dso *self, enum map_type type); 110bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112
113void dso__sort_by_name(struct dso *self, enum map_type type);
114
115struct perf_session;
96 116
97struct dso *dsos__findnew(const char *name); 117struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
99void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
100size_t dsos__fprintf_buildid(FILE *fp); 121size_t dsos__fprintf_buildid(FILE *fp);
101 122
@@ -103,18 +124,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
104char dso__symtab_origin(const struct dso *self); 125char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id); 126void dso__set_build_id(struct dso *self, void *build_id);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name);
106 130
107int filename__read_build_id(const char *filename, void *bf, size_t size); 131int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size); 132int sysfs__read_build_id(const char *filename, void *bf, size_t size);
109bool dsos__read_build_ids(void); 133bool dsos__read_build_ids(void);
110int build_id__sprintf(u8 *self, int len, char *bf); 134int build_id__sprintf(u8 *self, int len, char *bf);
111 135
112size_t kernel_maps__fprintf(FILE *fp); 136int symbol__init(void);
113 137int perf_session__create_kernel_maps(struct perf_session *self);
114int symbol__init(struct symbol_conf *conf);
115 138
116struct thread;
117struct thread *kthread;
118extern struct list_head dsos__user, dsos__kernel; 139extern struct list_head dsos__user, dsos__kernel;
119extern struct dso *vdso; 140extern struct dso *vdso;
120#endif /* __PERF_SYMBOL */ 141#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 603f5610861..4a08dcf50b6 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,18 +2,14 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
9static struct rb_root threads; 10void map_groups__init(struct map_groups *self)
10static struct thread *last_match;
11
12void thread__init(struct thread *self, pid_t pid)
13{ 11{
14 int i; 12 int i;
15 self->pid = pid;
16 self->comm = NULL;
17 for (i = 0; i < MAP__NR_TYPES; ++i) { 13 for (i = 0; i < MAP__NR_TYPES; ++i) {
18 self->maps[i] = RB_ROOT; 14 self->maps[i] = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps[i]); 15 INIT_LIST_HEAD(&self->removed_maps[i]);
@@ -25,7 +21,8 @@ static struct thread *thread__new(pid_t pid)
25 struct thread *self = zalloc(sizeof(*self)); 21 struct thread *self = zalloc(sizeof(*self));
26 22
27 if (self != NULL) { 23 if (self != NULL) {
28 thread__init(self, pid); 24 map_groups__init(&self->mg);
25 self->pid = pid;
29 self->comm = malloc(32); 26 self->comm = malloc(32);
30 if (self->comm) 27 if (self->comm)
31 snprintf(self->comm, 32, ":%d", self->pid); 28 snprintf(self->comm, 32, ":%d", self->pid);
@@ -55,10 +52,11 @@ int thread__comm_len(struct thread *self)
55 52
56static const char *map_type__name[MAP__NR_TYPES] = { 53static const char *map_type__name[MAP__NR_TYPES] = {
57 [MAP__FUNCTION] = "Functions", 54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
58}; 56};
59 57
60static size_t __thread__fprintf_maps(struct thread *self, 58static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp) 59 enum map_type type, FILE *fp)
62{ 60{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64 struct rb_node *nd; 62 struct rb_node *nd;
@@ -76,16 +74,16 @@ static size_t __thread__fprintf_maps(struct thread *self,
76 return printed; 74 return printed;
77} 75}
78 76
79size_t thread__fprintf_maps(struct thread *self, FILE *fp) 77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80{ 78{
81 size_t printed = 0, i; 79 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i) 80 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __thread__fprintf_maps(self, i, fp); 81 printed += __map_groups__fprintf_maps(self, i, fp);
84 return printed; 82 return printed;
85} 83}
86 84
87static size_t __thread__fprintf_removed_maps(struct thread *self, 85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
88 enum map_type type, FILE *fp) 86 enum map_type type, FILE *fp)
89{ 87{
90 struct map *pos; 88 struct map *pos;
91 size_t printed = 0; 89 size_t printed = 0;
@@ -101,25 +99,30 @@ static size_t __thread__fprintf_removed_maps(struct thread *self,
101 return printed; 99 return printed;
102} 100}
103 101
104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp) 102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
105{ 103{
106 size_t printed = 0, i; 104 size_t printed = 0, i;
107 for (i = 0; i < MAP__NR_TYPES; ++i) 105 for (i = 0; i < MAP__NR_TYPES; ++i)
108 printed += __thread__fprintf_removed_maps(self, i, fp); 106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
109 return printed; 107 return printed;
110} 108}
111 109
112static size_t thread__fprintf(struct thread *self, FILE *fp) 110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113{ 111{
114 size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 112 size_t printed = map_groups__fprintf_maps(self, fp);
115 printed += thread__fprintf_removed_maps(self, fp);
116 printed += fprintf(fp, "Removed maps:\n"); 113 printed += fprintf(fp, "Removed maps:\n");
117 return printed + thread__fprintf_removed_maps(self, fp); 114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp)
118{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp);
118} 121}
119 122
120struct thread *threads__findnew(pid_t pid) 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
121{ 124{
122 struct rb_node **p = &threads.rb_node; 125 struct rb_node **p = &self->threads.rb_node;
123 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
124 struct thread *th; 127 struct thread *th;
125 128
@@ -128,15 +131,15 @@ struct thread *threads__findnew(pid_t pid)
128 * so most of the time we dont have to look up 131 * so most of the time we dont have to look up
129 * the full rbtree: 132 * the full rbtree:
130 */ 133 */
131 if (last_match && last_match->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
132 return last_match; 135 return self->last_match;
133 136
134 while (*p != NULL) { 137 while (*p != NULL) {
135 parent = *p; 138 parent = *p;
136 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
137 140
138 if (th->pid == pid) { 141 if (th->pid == pid) {
139 last_match = th; 142 self->last_match = th;
140 return th; 143 return th;
141 } 144 }
142 145
@@ -149,26 +152,15 @@ struct thread *threads__findnew(pid_t pid)
149 th = thread__new(pid); 152 th = thread__new(pid);
150 if (th != NULL) { 153 if (th != NULL) {
151 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
152 rb_insert_color(&th->rb_node, &threads); 155 rb_insert_color(&th->rb_node, &self->threads);
153 last_match = th; 156 self->last_match = th;
154 } 157 }
155 158
156 return th; 159 return th;
157} 160}
158 161
159struct thread *register_idle_thread(void) 162static void map_groups__remove_overlappings(struct map_groups *self,
160{ 163 struct map *map)
161 struct thread *thread = threads__findnew(0);
162
163 if (!thread || thread__set_comm(thread, "swapper")) {
164 fprintf(stderr, "problem inserting idle task.\n");
165 exit(-1);
166 }
167
168 return thread;
169}
170
171static void thread__remove_overlappings(struct thread *self, struct map *map)
172{ 164{
173 struct rb_root *root = &self->maps[map->type]; 165 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root); 166 struct rb_node *next = rb_first(root);
@@ -238,12 +230,15 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
238 230
239void thread__insert_map(struct thread *self, struct map *map) 231void thread__insert_map(struct thread *self, struct map *map)
240{ 232{
241 thread__remove_overlappings(self, map); 233 map_groups__remove_overlappings(&self->mg, map);
242 maps__insert(&self->maps[map->type], map); 234 map_groups__insert(&self->mg, map);
243} 235}
244 236
245static int thread__clone_maps(struct thread *self, struct thread *parent, 237/*
246 enum map_type type) 238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
247{ 242{
248 struct rb_node *nd; 243 struct rb_node *nd;
249 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { 244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
@@ -251,7 +246,7 @@ static int thread__clone_maps(struct thread *self, struct thread *parent,
251 struct map *new = map__clone(map); 246 struct map *new = map__clone(map);
252 if (new == NULL) 247 if (new == NULL)
253 return -ENOMEM; 248 return -ENOMEM;
254 thread__insert_map(self, new); 249 map_groups__insert(self, new);
255 } 250 }
256 return 0; 251 return 0;
257} 252}
@@ -267,17 +262,17 @@ int thread__fork(struct thread *self, struct thread *parent)
267 return -ENOMEM; 262 return -ENOMEM;
268 263
269 for (i = 0; i < MAP__NR_TYPES; ++i) 264 for (i = 0; i < MAP__NR_TYPES; ++i)
270 if (thread__clone_maps(self, parent, i) < 0) 265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
271 return -ENOMEM; 266 return -ENOMEM;
272 return 0; 267 return 0;
273} 268}
274 269
275size_t threads__fprintf(FILE *fp) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
276{ 271{
277 size_t ret = 0; 272 size_t ret = 0;
278 struct rb_node *nd; 273 struct rb_node *nd;
279 274
280 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
281 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
282 277
283 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -286,14 +281,15 @@ size_t threads__fprintf(FILE *fp)
286 return ret; 281 return ret;
287} 282}
288 283
289struct symbol *thread__find_symbol(struct thread *self, 284struct symbol *map_groups__find_symbol(struct map_groups *self,
290 enum map_type type, u64 addr, 285 struct perf_session *session,
291 symbol_filter_t filter) 286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
292{ 288{
293 struct map *map = thread__find_map(self, type, addr); 289 struct map *map = map_groups__find(self, type, addr);
294 290
295 if (map != NULL) 291 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter); 292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
297 293
298 return NULL; 294 return NULL;
299} 295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 686d6e914d9..c206f72c888 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,52 +5,66 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct thread { 8struct map_groups {
9 struct rb_node rb_node;
10 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
13struct thread {
14 struct rb_node rb_node;
15 struct map_groups mg;
12 pid_t pid; 16 pid_t pid;
13 bool use_modules;
14 char shortname[3]; 17 char shortname[3];
15 char *comm; 18 char *comm;
16 int comm_len; 19 int comm_len;
17}; 20};
18 21
19void thread__init(struct thread *self, pid_t pid); 22void map_groups__init(struct map_groups *self);
20int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
21int thread__comm_len(struct thread *self); 24int thread__comm_len(struct thread *self);
22struct thread *threads__findnew(pid_t pid); 25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
23struct thread *register_idle_thread(void);
24void thread__insert_map(struct thread *self, struct map *map); 26void thread__insert_map(struct thread *self, struct map *map);
25int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
26size_t thread__fprintf_maps(struct thread *self, FILE *fp); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
27size_t threads__fprintf(FILE *fp); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
28 30
29void maps__insert(struct rb_root *maps, struct map *map); 31void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 addr); 32struct map *maps__find(struct rb_root *maps, u64 addr);
31 33
32static inline struct map *thread__find_map(struct thread *self, 34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
33 enum map_type type, u64 addr) 40 enum map_type type, u64 addr)
34{ 41{
35 return self ? maps__find(&self->maps[type], addr) : NULL; 42 return maps__find(&self->maps[type], addr);
36} 43}
37 44
38static inline void __thread__insert_map(struct thread *self, struct map *map) 45static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr)
39{ 47{
40 maps__insert(&self->maps[map->type], map); 48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
41} 49}
42 50
43void thread__find_addr_location(struct thread *self, u8 cpumode, 51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
44 enum map_type type, u64 addr, 53 enum map_type type, u64 addr,
45 struct addr_location *al, 54 struct addr_location *al,
46 symbol_filter_t filter); 55 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self, 56struct symbol *map_groups__find_symbol(struct map_groups *self,
48 enum map_type type, u64 addr, 57 struct perf_session *session,
49 symbol_filter_t filter); 58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
50 60
51static inline struct symbol * 61static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter) 62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
53{ 64{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
55} 66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
56#endif /* __PERF_THREAD_H */ 70#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index a5ffe60db5d..6d6d76b8a21 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -267,7 +267,7 @@ int common_lock_depth(struct scripting_context *context)
267} 267}
268 268
269static void perl_process_event(int cpu, void *data, 269static void perl_process_event(int cpu, void *data,
270 int size __attribute((unused)), 270 int size __unused,
271 unsigned long long nsecs, char *comm) 271 unsigned long long nsecs, char *comm)
272{ 272{
273 struct format_field *field; 273 struct format_field *field;
@@ -359,28 +359,46 @@ static void run_start_sub(void)
359/* 359/*
360 * Start trace script 360 * Start trace script
361 */ 361 */
362static int perl_start_script(const char *script) 362static int perl_start_script(const char *script, int argc, const char **argv)
363{ 363{
364 const char *command_line[2] = { "", NULL }; 364 const char **command_line;
365 int i, err = 0;
365 366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
366 command_line[1] = script; 369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
367 372
368 my_perl = perl_alloc(); 373 my_perl = perl_alloc();
369 perl_construct(my_perl); 374 perl_construct(my_perl);
370 375
371 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
372 (char **)NULL)) 377 (char **)NULL)) {
373 return -1; 378 err = -1;
379 goto error;
380 }
374 381
375 perl_run(my_perl); 382 if (perl_run(my_perl)) {
376 if (SvTRUE(ERRSV)) 383 err = -1;
377 return -1; 384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
378 391
379 run_start_sub(); 392 run_start_sub();
380 393
394 free(command_line);
381 fprintf(stderr, "perf trace started with Perl script %s\n\n", script); 395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
382
383 return 0; 396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
384} 402}
385 403
386/* 404/*
@@ -579,7 +597,9 @@ static void print_unsupported_msg(void)
579 "\n etc.\n"); 597 "\n etc.\n");
580} 598}
581 599
582static int perl_start_script_unsupported(const char *script __unused) 600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
583{ 603{
584 print_unsupported_msg(); 604 print_unsupported_msg();
585 605
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81698d5e650..6ad405620c9 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -270,7 +270,7 @@ enum trace_flag_type {
270 270
271struct scripting_ops { 271struct scripting_ops {
272 const char *name; 272 const char *name;
273 int (*start_script) (const char *); 273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void); 274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size, 275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm); 276 unsigned long long nsecs, char *comm);