aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-01-23 01:45:46 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-23 01:45:46 -0500
commit6be325719b3e54624397e413efd4b33a997e55a3 (patch)
tree57f321a56794cab2222e179b16731e0d76a4a68a /tools/perf
parent26d92f9276a56d55511a427fb70bd70886af647a (diff)
parent92dcffb916d309aa01778bf8963a6932e4014d07 (diff)
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-kmem.txt13
-rw-r--r--tools/perf/Documentation/perf-probe.txt24
-rw-r--r--tools/perf/Documentation/perf-report.txt4
-rw-r--r--tools/perf/Documentation/perf-trace.txt27
-rw-r--r--tools/perf/Makefile66
-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.c61
-rw-r--r--tools/perf/builtin-diff.c249
-rw-r--r--tools/perf/builtin-kmem.c187
-rw-r--r--tools/perf/builtin-probe.c209
-rw-r--r--tools/perf/builtin-record.c166
-rw-r--r--tools/perf/builtin-report.c757
-rw-r--r--tools/perf/builtin-sched.c284
-rw-r--r--tools/perf/builtin-timechart.c120
-rw-r--r--tools/perf/builtin-top.c45
-rw-r--r--tools/perf/builtin-trace.c393
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/design.txt8
-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.c167
-rw-r--r--tools/perf/util/data_map.h32
-rw-r--r--tools/perf/util/event.c214
-rw-r--r--tools/perf/util/event.h64
-rw-r--r--tools/perf/util/header.c39
-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/parse-events.c17
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/probe-event.c299
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/probe-finder.c6
-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.c355
-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-parse.c4
-rw-r--r--tools/perf/util/trace-event-perl.c107
-rw-r--r--tools/perf/util/trace-event-perl.h4
-rw-r--r--tools/perf/util/trace-event-read.c3
-rw-r--r--tools/perf/util/trace-event.h2
63 files changed, 3438 insertions, 1983 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
new file mode 100644
index 000000000000..8974e208cba6
--- /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-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index 44b0ce35c28a..eac4d852e7cd 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -8,16 +8,16 @@ perf-kmem - Tool to trace/measure kernel memory(slab) properties
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf kmem' {record} [<options>] 11'perf kmem' {record|stat} [<options>]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15There's two variants of perf kmem: 15There are two variants of perf kmem:
16 16
17 'perf kmem record <command>' to record the kmem events 17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload. 18 of an arbitrary workload.
19 19
20 'perf kmem' to report kernel memory statistics. 20 'perf kmem stat' to report kernel memory statistics.
21 21
22OPTIONS 22OPTIONS
23------- 23-------
@@ -25,8 +25,11 @@ OPTIONS
25--input=<file>:: 25--input=<file>::
26 Select the input file (default: perf.data) 26 Select the input file (default: perf.data)
27 27
28--stat=<caller|alloc>:: 28--caller::
29 Select per callsite or per allocation statistics 29 Show per-callsite statistics
30
31--alloc::
32 Show per-allocation statistics
30 33
31-s <key[,key2...]>:: 34-s <key[,key2...]>::
32--sort=<key[,key2...]>:: 35--sort=<key[,key2...]>::
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 9270594e6dfd..250e391b4bc8 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -8,10 +8,13 @@ perf-probe - Define new dynamic tracepoints
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...] 11'perf probe' [options] --add='PROBE' [...]
12or 12or
13'perf probe' [options] 'PROBE' ['PROBE' ...] 13'perf probe' [options] PROBE
14 14or
15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or
17'perf probe' --list
15 18
16DESCRIPTION 19DESCRIPTION
17----------- 20-----------
@@ -31,15 +34,24 @@ OPTIONS
31 Be more verbose (show parsed arguments, etc). 34 Be more verbose (show parsed arguments, etc).
32 35
33-a:: 36-a::
34--add:: 37--add=::
35 Define a probe point (see PROBE SYNTAX for detail) 38 Define a probe event (see PROBE SYNTAX for detail).
39
40-d::
41--del=::
42 Delete a probe event.
43
44-l::
45--list::
46 List up current probe events.
36 47
37PROBE SYNTAX 48PROBE SYNTAX
38------------ 49------------
39Probe points are defined by following syntax. 50Probe points are defined by following syntax.
40 51
41 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
42 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'.
43'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.
44It 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.
45'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 9dccb180b7af..abfabe9147a4 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 07065efa60e0..60e5900da483 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 23ec66098bdc..2e7fa3a06806 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
@@ -250,7 +250,19 @@ PTHREAD_LIBS = -lpthread
250# explicitly what architecture to check for. Fix this up for yours.. 250# explicitly what architecture to check for. Fix this up for yours..
251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
252 252
253ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null "$(QUIET_STDERR)" && echo y"), y) 253ifeq ($(V), 2)
254 QUIET_STDERR = ">/dev/null"
255else
256 QUIET_STDERR = ">/dev/null 2>&1"
257endif
258
259BITBUCKET = "/dev/null"
260
261ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
262 BITBUCKET = .perf.dev.null
263endif
264
265ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
254 CFLAGS := $(CFLAGS) -fstack-protector-all 266 CFLAGS := $(CFLAGS) -fstack-protector-all
255endif 267endif
256 268
@@ -343,23 +355,31 @@ LIB_H += util/include/linux/string.h
343LIB_H += util/include/linux/types.h 355LIB_H += util/include/linux/types.h
344LIB_H += util/include/asm/asm-offsets.h 356LIB_H += util/include/asm/asm-offsets.h
345LIB_H += util/include/asm/bitops.h 357LIB_H += util/include/asm/bitops.h
358LIB_H += util/include/asm/bug.h
346LIB_H += util/include/asm/byteorder.h 359LIB_H += util/include/asm/byteorder.h
347LIB_H += util/include/asm/swab.h 360LIB_H += util/include/asm/swab.h
348LIB_H += util/include/asm/system.h 361LIB_H += util/include/asm/system.h
349LIB_H += util/include/asm/uaccess.h 362LIB_H += util/include/asm/uaccess.h
350LIB_H += perf.h 363LIB_H += perf.h
364LIB_H += util/cache.h
365LIB_H += util/callchain.h
366LIB_H += util/debug.h
351LIB_H += util/debugfs.h 367LIB_H += util/debugfs.h
352LIB_H += util/event.h 368LIB_H += util/event.h
369LIB_H += util/exec_cmd.h
353LIB_H += util/types.h 370LIB_H += util/types.h
354LIB_H += util/levenshtein.h 371LIB_H += util/levenshtein.h
355LIB_H += util/parse-options.h 372LIB_H += util/parse-options.h
356LIB_H += util/parse-events.h 373LIB_H += util/parse-events.h
357LIB_H += util/quote.h 374LIB_H += util/quote.h
358LIB_H += util/util.h 375LIB_H += util/util.h
376LIB_H += util/header.h
359LIB_H += util/help.h 377LIB_H += util/help.h
378LIB_H += util/session.h
360LIB_H += util/strbuf.h 379LIB_H += util/strbuf.h
361LIB_H += util/string.h 380LIB_H += util/string.h
362LIB_H += util/strlist.h 381LIB_H += util/strlist.h
382LIB_H += util/svghelper.h
363LIB_H += util/run-command.h 383LIB_H += util/run-command.h
364LIB_H += util/sigchain.h 384LIB_H += util/sigchain.h
365LIB_H += util/symbol.h 385LIB_H += util/symbol.h
@@ -368,7 +388,8 @@ LIB_H += util/values.h
368LIB_H += util/sort.h 388LIB_H += util/sort.h
369LIB_H += util/hist.h 389LIB_H += util/hist.h
370LIB_H += util/thread.h 390LIB_H += util/thread.h
371LIB_H += util/data_map.h 391LIB_H += util/trace-event.h
392LIB_H += util/trace-event-perl.h
372LIB_H += util/probe-finder.h 393LIB_H += util/probe-finder.h
373LIB_H += util/probe-event.h 394LIB_H += util/probe-event.h
374 395
@@ -405,6 +426,7 @@ LIB_OBJS += util/callchain.o
405LIB_OBJS += util/values.o 426LIB_OBJS += util/values.o
406LIB_OBJS += util/debug.o 427LIB_OBJS += util/debug.o
407LIB_OBJS += util/map.o 428LIB_OBJS += util/map.o
429LIB_OBJS += util/session.o
408LIB_OBJS += util/thread.o 430LIB_OBJS += util/thread.o
409LIB_OBJS += util/trace-event-parse.o 431LIB_OBJS += util/trace-event-parse.o
410LIB_OBJS += util/trace-event-read.o 432LIB_OBJS += util/trace-event-read.o
@@ -425,6 +447,7 @@ BUILTIN_OBJS += bench/sched-messaging.o
425BUILTIN_OBJS += bench/sched-pipe.o 447BUILTIN_OBJS += bench/sched-pipe.o
426BUILTIN_OBJS += bench/mem-memcpy.o 448BUILTIN_OBJS += bench/mem-memcpy.o
427 449
450BUILTIN_OBJS += builtin-diff.o
428BUILTIN_OBJS += builtin-help.o 451BUILTIN_OBJS += builtin-help.o
429BUILTIN_OBJS += builtin-sched.o 452BUILTIN_OBJS += builtin-sched.o
430BUILTIN_OBJS += builtin-buildid-list.o 453BUILTIN_OBJS += builtin-buildid-list.o
@@ -440,11 +463,6 @@ BUILTIN_OBJS += builtin-kmem.o
440 463
441PERFLIBS = $(LIB_FILE) 464PERFLIBS = $(LIB_FILE)
442 465
443ifeq ($(V), 2)
444 QUIET_STDERR = ">/dev/null"
445else
446 QUIET_STDERR = ">/dev/null 2>&1"
447endif
448# 466#
449# Platform specific tweaks 467# Platform specific tweaks
450# 468#
@@ -472,30 +490,33 @@ ifeq ($(uname_S),Darwin)
472 PTHREAD_LIBS = 490 PTHREAD_LIBS =
473endif 491endif
474 492
475ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 493ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
476ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 494ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
477 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 495 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
478endif 496endif
479 497
480 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 498 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
481 BASIC_CFLAGS += -DLIBELF_NO_MMAP 499 BASIC_CFLAGS += -DLIBELF_NO_MMAP
482 endif 500 endif
483else 501else
484 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 502 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
485endif 503endif
486 504
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) 505ifneq ($(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 $(BITBUCKET) $(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); 506 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 507 BASIC_CFLAGS += -DNO_LIBDWARF
490else 508else
509 BASIC_CFLAGS += -I/usr/include/libdwarf
491 EXTLIBS += -lelf -ldwarf 510 EXTLIBS += -lelf -ldwarf
492 LIB_OBJS += util/probe-finder.o 511 LIB_OBJS += util/probe-finder.o
493endif 512endif
494 513
514ifndef NO_LIBPERL
495PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 515PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
496PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 516PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
517endif
497 518
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) 519ifneq ($(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 $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
499 BASIC_CFLAGS += -DNO_LIBPERL 520 BASIC_CFLAGS += -DNO_LIBPERL
500else 521else
501 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 522 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
@@ -505,20 +526,20 @@ endif
505ifdef NO_DEMANGLE 526ifdef NO_DEMANGLE
506 BASIC_CFLAGS += -DNO_DEMANGLE 527 BASIC_CFLAGS += -DNO_DEMANGLE
507else 528else
508 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") 529 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
509 530
510 ifeq ($(has_bfd),y) 531 ifeq ($(has_bfd),y)
511 EXTLIBS += -lbfd 532 EXTLIBS += -lbfd
512 else 533 else
513 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") 534 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
514 ifeq ($(has_bfd_iberty),y) 535 ifeq ($(has_bfd_iberty),y)
515 EXTLIBS += -lbfd -liberty 536 EXTLIBS += -lbfd -liberty
516 else 537 else
517 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") 538 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
518 ifeq ($(has_bfd_iberty_z),y) 539 ifeq ($(has_bfd_iberty_z),y)
519 EXTLIBS += -lbfd -liberty -lz 540 EXTLIBS += -lbfd -liberty -lz
520 else 541 else
521 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") 542 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
522 ifeq ($(has_cplus_demangle),y) 543 ifeq ($(has_cplus_demangle),y)
523 EXTLIBS += -liberty 544 EXTLIBS += -liberty
524 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 545 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -766,7 +787,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
766 787
767SHELL = $(SHELL_PATH) 788SHELL = $(SHELL_PATH)
768 789
769all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 790all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
770ifneq (,$X) 791ifneq (,$X)
771 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 792 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
772endif 793endif
@@ -991,8 +1012,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' 1012 $(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' 1013 $(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' 1014 $(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 1015ifdef BUILT_INS
997 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1016 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
998 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1017 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1095,6 +1114,11 @@ clean:
1095.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1114.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1096.PHONY: .FORCE-PERF-BUILD-OPTIONS 1115.PHONY: .FORCE-PERF-BUILD-OPTIONS
1097 1116
1117.perf.dev.null:
1118 touch .perf.dev.null
1119
1120.INTERMEDIATE: .perf.dev.null
1121
1098### Make sure built-ins do not have dups and listed in perf.c 1122### Make sure built-ins do not have dups and listed in perf.c
1099# 1123#
1100check-builtins:: 1124check-builtins::
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 605a2a959aa8..81cee78181fa 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 238185f97977..4f77c7c27640 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 0bf2e8f9af57..593ff25006de 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 e043eb83092a..46996774e559 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 7dee9d19ab7a..1e99ac806913 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -9,17 +9,16 @@
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";
19static int force; 18static int force;
20 19
21static const char *const buildid_list_usage[] = { 20static const char * const buildid_list_usage[] = {
22 "perf report [<options>]", 21 "perf buildid-list [<options>]",
23 NULL 22 NULL
24}; 23};
25 24
@@ -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 000000000000..bd71b8ceafb7
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,249 @@
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 NULL,
195};
196
197static const struct option options[] = {
198 OPT_BOOLEAN('v', "verbose", &verbose,
199 "be more verbose (show symbol address, etc)"),
200 OPT_BOOLEAN('m', "displacement", &show_displacement,
201 "Show position displacement relative to baseline"),
202 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
203 "dump raw trace in ASCII"),
204 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
205 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
206 "load module symbols - WARNING: use only with -k and LIVE kernel"),
207 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
208 "Don't shorten the pathnames taking into account the cwd"),
209 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
210 "only consider symbols in these dsos"),
211 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
212 "only consider symbols in these comms"),
213 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
214 "only consider these symbols"),
215 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
216 "sort by key(s): pid, comm, dso, symbol, parent"),
217 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
218 "separator for columns, no spaces will be added between "
219 "columns '.' is reserved."),
220 OPT_END()
221};
222
223int cmd_diff(int argc, const char **argv, const char *prefix __used)
224{
225 sort_order = diff__default_sort_order;
226 argc = parse_options(argc, argv, options, diff_usage, 0);
227 if (argc) {
228 if (argc > 2)
229 usage_with_options(diff_usage, options);
230 if (argc == 2) {
231 input_old = argv[0];
232 input_new = argv[1];
233 } else
234 input_new = argv[0];
235 }
236
237 symbol_conf.exclude_other = false;
238 if (symbol__init() < 0)
239 return -1;
240
241 setup_sorting(diff_usage, options);
242 setup_pager();
243
244 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
245 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
246 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
247
248 return __cmd_diff();
249}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 047fef74bd52..93c67bf53d2c 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
@@ -57,11 +54,6 @@ static struct rb_root root_caller_sorted;
57static unsigned long total_requested, total_allocated; 54static unsigned long total_requested, total_allocated;
58static unsigned long nr_allocs, nr_cross_allocs; 55static unsigned long nr_allocs, nr_cross_allocs;
59 56
60struct raw_event_sample {
61 u32 size;
62 char data[0];
63};
64
65#define PATH_SYS_NODE "/sys/devices/system/node" 57#define PATH_SYS_NODE "/sys/devices/system/node"
66 58
67static void init_cpunode_map(void) 59static void init_cpunode_map(void)
@@ -145,7 +137,7 @@ static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
145 if (data && data->ptr == ptr) { 137 if (data && data->ptr == ptr) {
146 data->hit++; 138 data->hit++;
147 data->bytes_req += bytes_req; 139 data->bytes_req += bytes_req;
148 data->bytes_alloc += bytes_req; 140 data->bytes_alloc += bytes_alloc;
149 } else { 141 } else {
150 data = malloc(sizeof(*data)); 142 data = malloc(sizeof(*data));
151 if (!data) 143 if (!data)
@@ -185,7 +177,7 @@ static void insert_caller_stat(unsigned long call_site,
185 if (data && data->call_site == call_site) { 177 if (data && data->call_site == call_site) {
186 data->hit++; 178 data->hit++;
187 data->bytes_req += bytes_req; 179 data->bytes_req += bytes_req;
188 data->bytes_alloc += bytes_req; 180 data->bytes_alloc += bytes_alloc;
189 } else { 181 } else {
190 data = malloc(sizeof(*data)); 182 data = malloc(sizeof(*data));
191 if (!data) 183 if (!data)
@@ -201,7 +193,7 @@ static void insert_caller_stat(unsigned long call_site,
201 } 193 }
202} 194}
203 195
204static void process_alloc_event(struct raw_event_sample *raw, 196static void process_alloc_event(void *data,
205 struct event *event, 197 struct event *event,
206 int cpu, 198 int cpu,
207 u64 timestamp __used, 199 u64 timestamp __used,
@@ -214,10 +206,10 @@ static void process_alloc_event(struct raw_event_sample *raw,
214 int bytes_alloc; 206 int bytes_alloc;
215 int node1, node2; 207 int node1, node2;
216 208
217 ptr = raw_field_value(event, "ptr", raw->data); 209 ptr = raw_field_value(event, "ptr", data);
218 call_site = raw_field_value(event, "call_site", raw->data); 210 call_site = raw_field_value(event, "call_site", data);
219 bytes_req = raw_field_value(event, "bytes_req", raw->data); 211 bytes_req = raw_field_value(event, "bytes_req", data);
220 bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); 212 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
221 213
222 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu); 214 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
223 insert_caller_stat(call_site, bytes_req, bytes_alloc); 215 insert_caller_stat(call_site, bytes_req, bytes_alloc);
@@ -227,7 +219,7 @@ static void process_alloc_event(struct raw_event_sample *raw,
227 219
228 if (node) { 220 if (node) {
229 node1 = cpunode_map[cpu]; 221 node1 = cpunode_map[cpu];
230 node2 = raw_field_value(event, "node", raw->data); 222 node2 = raw_field_value(event, "node", data);
231 if (node1 != node2) 223 if (node1 != node2)
232 nr_cross_allocs++; 224 nr_cross_allocs++;
233 } 225 }
@@ -262,7 +254,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
262 return NULL; 254 return NULL;
263} 255}
264 256
265static void process_free_event(struct raw_event_sample *raw, 257static void process_free_event(void *data,
266 struct event *event, 258 struct event *event,
267 int cpu, 259 int cpu,
268 u64 timestamp __used, 260 u64 timestamp __used,
@@ -271,7 +263,7 @@ static void process_free_event(struct raw_event_sample *raw,
271 unsigned long ptr; 263 unsigned long ptr;
272 struct alloc_stat *s_alloc, *s_caller; 264 struct alloc_stat *s_alloc, *s_caller;
273 265
274 ptr = raw_field_value(event, "ptr", raw->data); 266 ptr = raw_field_value(event, "ptr", data);
275 267
276 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp); 268 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
277 if (!s_alloc) 269 if (!s_alloc)
@@ -289,66 +281,53 @@ static void process_free_event(struct raw_event_sample *raw,
289} 281}
290 282
291static void 283static void
292process_raw_event(event_t *raw_event __used, void *more_data, 284process_raw_event(event_t *raw_event __used, void *data,
293 int cpu, u64 timestamp, struct thread *thread) 285 int cpu, u64 timestamp, struct thread *thread)
294{ 286{
295 struct raw_event_sample *raw = more_data;
296 struct event *event; 287 struct event *event;
297 int type; 288 int type;
298 289
299 type = trace_parse_common_type(raw->data); 290 type = trace_parse_common_type(data);
300 event = trace_find_event(type); 291 event = trace_find_event(type);
301 292
302 if (!strcmp(event->name, "kmalloc") || 293 if (!strcmp(event->name, "kmalloc") ||
303 !strcmp(event->name, "kmem_cache_alloc")) { 294 !strcmp(event->name, "kmem_cache_alloc")) {
304 process_alloc_event(raw, event, cpu, timestamp, thread, 0); 295 process_alloc_event(data, event, cpu, timestamp, thread, 0);
305 return; 296 return;
306 } 297 }
307 298
308 if (!strcmp(event->name, "kmalloc_node") || 299 if (!strcmp(event->name, "kmalloc_node") ||
309 !strcmp(event->name, "kmem_cache_alloc_node")) { 300 !strcmp(event->name, "kmem_cache_alloc_node")) {
310 process_alloc_event(raw, event, cpu, timestamp, thread, 1); 301 process_alloc_event(data, event, cpu, timestamp, thread, 1);
311 return; 302 return;
312 } 303 }
313 304
314 if (!strcmp(event->name, "kfree") || 305 if (!strcmp(event->name, "kfree") ||
315 !strcmp(event->name, "kmem_cache_free")) { 306 !strcmp(event->name, "kmem_cache_free")) {
316 process_free_event(raw, event, cpu, timestamp, thread); 307 process_free_event(data, event, cpu, timestamp, thread);
317 return; 308 return;
318 } 309 }
319} 310}
320 311
321static int process_sample_event(event_t *event) 312static int process_sample_event(event_t *event, struct perf_session *session)
322{ 313{
323 u64 ip = event->ip.ip; 314 struct sample_data data;
324 u64 timestamp = -1; 315 struct thread *thread;
325 u32 cpu = -1;
326 u64 period = 1;
327 void *more_data = event->ip.__more_data;
328 struct thread *thread = threads__findnew(event->ip.pid);
329
330 if (sample_type & PERF_SAMPLE_TIME) {
331 timestamp = *(u64 *)more_data;
332 more_data += sizeof(u64);
333 }
334 316
335 if (sample_type & PERF_SAMPLE_CPU) { 317 memset(&data, 0, sizeof(data));
336 cpu = *(u32 *)more_data; 318 data.time = -1;
337 more_data += sizeof(u32); 319 data.cpu = -1;
338 more_data += sizeof(u32); /* reserved */ 320 data.period = 1;
339 }
340 321
341 if (sample_type & PERF_SAMPLE_PERIOD) { 322 event__parse_sample(event, session->sample_type, &data);
342 period = *(u64 *)more_data;
343 more_data += sizeof(u64);
344 }
345 323
346 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
347 event->header.misc, 325 event->header.misc,
348 event->ip.pid, event->ip.tid, 326 data.pid, data.tid,
349 (void *)(long)ip, 327 (void *)(long)data.ip,
350 (long long)period); 328 (long long)data.period);
351 329
330 thread = perf_session__findnew(session, event->ip.pid);
352 if (thread == NULL) { 331 if (thread == NULL) {
353 pr_debug("problem processing %d event, skipping it.\n", 332 pr_debug("problem processing %d event, skipping it.\n",
354 event->header.type); 333 event->header.type);
@@ -357,16 +336,15 @@ static int process_sample_event(event_t *event)
357 336
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 337 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
359 338
360 process_raw_event(event, more_data, cpu, timestamp, thread); 339 process_raw_event(event, data.raw_data, data.cpu,
340 data.time, thread);
361 341
362 return 0; 342 return 0;
363} 343}
364 344
365static int sample_type_check(u64 type) 345static int sample_type_check(struct perf_session *session)
366{ 346{
367 sample_type = type; 347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
368
369 if (!(sample_type & PERF_SAMPLE_RAW)) {
370 fprintf(stderr, 348 fprintf(stderr,
371 "No trace sample to read. Did you call perf record " 349 "No trace sample to read. Did you call perf record "
372 "without -R?"); 350 "without -R?");
@@ -376,21 +354,12 @@ static int sample_type_check(u64 type)
376 return 0; 354 return 0;
377} 355}
378 356
379static struct perf_file_handler file_handler = { 357static struct perf_event_ops event_ops = {
380 .process_sample_event = process_sample_event, 358 .process_sample_event = process_sample_event,
381 .process_comm_event = event__process_comm, 359 .process_comm_event = event__process_comm,
382 .sample_type_check = sample_type_check, 360 .sample_type_check = sample_type_check,
383}; 361};
384 362
385static int read_events(void)
386{
387 register_idle_thread();
388 register_perf_file_handler(&file_handler);
389
390 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
391 &event__cwdlen, &event__cwd);
392}
393
394static double fragmentation(unsigned long n_req, unsigned long n_alloc) 363static double fragmentation(unsigned long n_req, unsigned long n_alloc)
395{ 364{
396 if (n_alloc == 0) 365 if (n_alloc == 0)
@@ -399,13 +368,14 @@ static double fragmentation(unsigned long n_req, unsigned long n_alloc)
399 return 100.0 - (100.0 * n_req / n_alloc); 368 return 100.0 - (100.0 * n_req / n_alloc);
400} 369}
401 370
402static 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)
403{ 373{
404 struct rb_node *next; 374 struct rb_node *next;
405 375
406 printf("%.102s\n", graph_dotted_line); 376 printf("%.102s\n", graph_dotted_line);
407 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 377 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
408 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 378 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
409 printf("%.102s\n", graph_dotted_line); 379 printf("%.102s\n", graph_dotted_line);
410 380
411 next = rb_first(root); 381 next = rb_first(root);
@@ -420,7 +390,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
420 if (is_caller) { 390 if (is_caller) {
421 addr = data->call_site; 391 addr = data->call_site;
422 if (!raw_ip) 392 if (!raw_ip)
423 sym = thread__find_function(kthread, addr, NULL); 393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL);
424 } else 394 } else
425 addr = data->ptr; 395 addr = data->ptr;
426 396
@@ -431,7 +401,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
431 snprintf(buf, sizeof(buf), "%#Lx", addr); 401 snprintf(buf, sizeof(buf), "%#Lx", addr);
432 printf(" %-34s |", buf); 402 printf(" %-34s |", buf);
433 403
434 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n", 404 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
435 (unsigned long long)data->bytes_alloc, 405 (unsigned long long)data->bytes_alloc,
436 (unsigned long)data->bytes_alloc / data->hit, 406 (unsigned long)data->bytes_alloc / data->hit,
437 (unsigned long long)data->bytes_req, 407 (unsigned long long)data->bytes_req,
@@ -461,12 +431,12 @@ static void print_summary(void)
461 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);
462} 432}
463 433
464static void print_result(void) 434static void print_result(struct perf_session *session)
465{ 435{
466 if (caller_flag) 436 if (caller_flag)
467 __print_result(&root_caller_sorted, caller_lines, 1); 437 __print_result(&root_caller_sorted, session, caller_lines, 1);
468 if (alloc_flag) 438 if (alloc_flag)
469 __print_result(&root_alloc_sorted, alloc_lines, 0); 439 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
470 print_summary(); 440 print_summary();
471} 441}
472 442
@@ -534,16 +504,24 @@ static void sort_result(void)
534 504
535static int __cmd_kmem(void) 505static int __cmd_kmem(void)
536{ 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
537 setup_pager(); 512 setup_pager();
538 read_events(); 513 err = perf_session__process_events(session, &event_ops);
514 if (err != 0)
515 goto out_delete;
539 sort_result(); 516 sort_result();
540 print_result(); 517 print_result(session);
541 518out_delete:
542 return 0; 519 perf_session__delete(session);
520 return err;
543} 521}
544 522
545static const char * const kmem_usage[] = { 523static const char * const kmem_usage[] = {
546 "perf kmem [<options>] {record}", 524 "perf kmem [<options>] {record|stat}",
547 NULL 525 NULL
548}; 526};
549 527
@@ -703,18 +681,17 @@ static int parse_sort_opt(const struct option *opt __used,
703 return 0; 681 return 0;
704} 682}
705 683
706static int parse_stat_opt(const struct option *opt __used, 684static int parse_caller_opt(const struct option *opt __used,
707 const char *arg, int unset __used) 685 const char *arg __used, int unset __used)
708{ 686{
709 if (!arg) 687 caller_flag = (alloc_flag + 1);
710 return -1; 688 return 0;
689}
711 690
712 if (strcmp(arg, "alloc") == 0) 691static int parse_alloc_opt(const struct option *opt __used,
713 alloc_flag = (caller_flag + 1); 692 const char *arg __used, int unset __used)
714 else if (strcmp(arg, "caller") == 0) 693{
715 caller_flag = (alloc_flag + 1); 694 alloc_flag = (caller_flag + 1);
716 else
717 return -1;
718 return 0; 695 return 0;
719} 696}
720 697
@@ -739,14 +716,17 @@ static int parse_line_opt(const struct option *opt __used,
739static const struct option kmem_options[] = { 716static const struct option kmem_options[] = {
740 OPT_STRING('i', "input", &input_name, "file", 717 OPT_STRING('i', "input", &input_name, "file",
741 "input file name"), 718 "input file name"),
742 OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", 719 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
743 "stat selector, Pass 'alloc' or 'caller'.", 720 "show per-callsite statistics",
744 parse_stat_opt), 721 parse_caller_opt),
722 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
723 "show per-allocation statistics",
724 parse_alloc_opt),
745 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 725 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
746 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag", 726 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
747 parse_sort_opt), 727 parse_sort_opt),
748 OPT_CALLBACK('l', "line", NULL, "num", 728 OPT_CALLBACK('l', "line", NULL, "num",
749 "show n lins", 729 "show n lines",
750 parse_line_opt), 730 parse_line_opt),
751 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 731 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
752 OPT_END() 732 OPT_END()
@@ -786,22 +766,27 @@ static int __cmd_record(int argc, const char **argv)
786 766
787int cmd_kmem(int argc, const char **argv, const char *prefix __used) 767int cmd_kmem(int argc, const char **argv, const char *prefix __used)
788{ 768{
789 symbol__init(0);
790
791 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 769 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
792 770
793 if (argc && !strncmp(argv[0], "rec", 3)) 771 if (!argc)
794 return __cmd_record(argc, argv);
795 else if (argc)
796 usage_with_options(kmem_usage, kmem_options); 772 usage_with_options(kmem_usage, kmem_options);
797 773
798 if (list_empty(&caller_sort)) 774 symbol__init();
799 setup_sorting(&caller_sort, default_sort_order); 775
800 if (list_empty(&alloc_sort)) 776 if (!strncmp(argv[0], "rec", 3)) {
801 setup_sorting(&alloc_sort, default_sort_order); 777 return __cmd_record(argc, argv);
778 } else if (!strcmp(argv[0], "stat")) {
779 setup_cpunode_map();
802 780
803 setup_cpunode_map(); 781 if (list_empty(&caller_sort))
782 setup_sorting(&caller_sort, default_sort_order);
783 if (list_empty(&alloc_sort))
784 setup_sorting(&alloc_sort, default_sort_order);
804 785
805 return __cmd_kmem(); 786 return __cmd_kmem();
787 } else
788 usage_with_options(kmem_usage, kmem_options);
789
790 return 0;
806} 791}
807 792
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a58e11b7ea80..c1e6774fd3ed 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -35,34 +35,33 @@
35#include "perf.h" 35#include "perf.h"
36#include "builtin.h" 36#include "builtin.h"
37#include "util/util.h" 37#include "util/util.h"
38#include "util/strlist.h"
38#include "util/event.h" 39#include "util/event.h"
39#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"
40#include "util/parse-options.h" 45#include "util/parse-options.h"
41#include "util/parse-events.h" /* For debugfs_path */ 46#include "util/parse-events.h" /* For debugfs_path */
42#include "util/probe-finder.h" 47#include "util/probe-finder.h"
43#include "util/probe-event.h" 48#include "util/probe-event.h"
44 49
45/* Default vmlinux search paths */
46#define NR_SEARCH_PATH 3
47const char *default_search_path[NR_SEARCH_PATH] = {
48"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
49"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
50"/boot/vmlinux-debug-%s", /* Ubuntu */
51};
52
53#define MAX_PATH_LEN 256 50#define MAX_PATH_LEN 256
54#define MAX_PROBES 128 51#define MAX_PROBES 128
55 52
56/* Session management structure */ 53/* Session management structure */
57static struct { 54static struct {
58 char *vmlinux; 55 bool need_dwarf;
59 char *release; 56 bool list_events;
60 int need_dwarf; 57 bool force_add;
61 int nr_probe; 58 int nr_probe;
62 struct probe_point probes[MAX_PROBES]; 59 struct probe_point probes[MAX_PROBES];
60 struct strlist *dellist;
61 struct perf_session *psession;
62 struct map *kmap;
63} session; 63} session;
64 64
65static bool listing;
66 65
67/* Parse an event definition. Note that any error must die. */ 66/* Parse an event definition. Note that any error must die. */
68static void parse_probe_event(const char *str) 67static void parse_probe_event(const char *str)
@@ -74,11 +73,30 @@ static void parse_probe_event(const char *str)
74 die("Too many probes (> %d) are specified.", MAX_PROBES); 73 die("Too many probes (> %d) are specified.", MAX_PROBES);
75 74
76 /* Parse perf-probe event into probe_point */ 75 /* Parse perf-probe event into probe_point */
77 session.need_dwarf = parse_perf_probe_event(str, pp); 76 parse_perf_probe_event(str, pp, &session.need_dwarf);
78 77
79 pr_debug("%d arguments\n", pp->nr_args); 78 pr_debug("%d arguments\n", pp->nr_args);
80} 79}
81 80
81static void parse_probe_event_argv(int argc, const char **argv)
82{
83 int i, len;
84 char *buf;
85
86 /* Bind up rest arguments */
87 len = 0;
88 for (i = 0; i < argc; i++)
89 len += strlen(argv[i]) + 1;
90 buf = zalloc(len + 1);
91 if (!buf)
92 die("Failed to allocate memory for binding arguments.");
93 len = 0;
94 for (i = 0; i < argc; i++)
95 len += sprintf(&buf[len], "%s ", argv[i]);
96 parse_probe_event(buf);
97 free(buf);
98}
99
82static int opt_add_probe_event(const struct option *opt __used, 100static int opt_add_probe_event(const struct option *opt __used,
83 const char *str, int unset __used) 101 const char *str, int unset __used)
84{ 102{
@@ -87,40 +105,44 @@ static int opt_add_probe_event(const struct option *opt __used,
87 return 0; 105 return 0;
88} 106}
89 107
90#ifndef NO_LIBDWARF 108static int opt_del_probe_event(const struct option *opt __used,
91static int open_default_vmlinux(void) 109 const char *str, int unset __used)
92{ 110{
93 struct utsname uts; 111 if (str) {
94 char fname[MAX_PATH_LEN]; 112 if (!session.dellist)
95 int fd, ret, i; 113 session.dellist = strlist__new(true, NULL);
96 114 strlist__add(session.dellist, str);
97 ret = uname(&uts);
98 if (ret) {
99 pr_debug("uname() failed.\n");
100 return -errno;
101 } 115 }
102 session.release = uts.release; 116 return 0;
103 for (i = 0; i < NR_SEARCH_PATH; i++) { 117}
104 ret = snprintf(fname, MAX_PATH_LEN, 118
105 default_search_path[i], session.release); 119/* Currently just checking function name from symbol map */
106 if (ret >= MAX_PATH_LEN || ret < 0) { 120static void evaluate_probe_point(struct probe_point *pp)
107 pr_debug("Filename(%d,%s) is too long.\n", i, 121{
108 uts.release); 122 struct symbol *sym;
109 errno = E2BIG; 123 sym = map__find_symbol_by_name(session.kmap, pp->function,
110 return -E2BIG; 124 session.psession, NULL);
111 } 125 if (!sym)
112 pr_debug("try to open %s\n", fname); 126 die("Kernel symbol \'%s\' not found - probe not added.",
113 fd = open(fname, O_RDONLY); 127 pp->function);
114 if (fd >= 0) 128}
115 break; 129
130#ifndef NO_LIBDWARF
131static int open_vmlinux(void)
132{
133 if (map__load(session.kmap, session.psession, NULL) < 0) {
134 pr_debug("Failed to load kernel map.\n");
135 return -EINVAL;
116 } 136 }
117 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);
118} 139}
119#endif 140#endif
120 141
121static const char * const probe_usage[] = { 142static const char * const probe_usage[] = {
122 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 143 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
123 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
124 "perf probe --list", 146 "perf probe --list",
125 NULL 147 NULL
126}; 148};
@@ -129,19 +151,22 @@ static const struct option options[] = {
129 OPT_BOOLEAN('v', "verbose", &verbose, 151 OPT_BOOLEAN('v', "verbose", &verbose,
130 "be more verbose (show parsed arguments, etc)"), 152 "be more verbose (show parsed arguments, etc)"),
131#ifndef NO_LIBDWARF 153#ifndef NO_LIBDWARF
132 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 154 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
133 "vmlinux/module pathname"), 155 "file", "vmlinux pathname"),
134#endif 156#endif
135 OPT_BOOLEAN('l', "list", &listing, "list up current probes"), 157 OPT_BOOLEAN('l', "list", &session.list_events,
158 "list up current probe events"),
159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
160 opt_del_probe_event),
136 OPT_CALLBACK('a', "add", NULL, 161 OPT_CALLBACK('a', "add", NULL,
137#ifdef NO_LIBDWARF 162#ifdef NO_LIBDWARF
138 "FUNC[+OFFS|%return] [ARG ...]", 163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]",
139#else 164#else
140 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
141#endif 166#endif
142 "probe point definition, where\n" 167 "probe point definition, where\n"
143 "\t\tGRP:\tGroup name (optional)\n" 168 "\t\tGROUP:\tGroup name (optional)\n"
144 "\t\tNAME:\tEvent name\n" 169 "\t\tEVENT:\tEvent name\n"
145 "\t\tFUNC:\tFunction name\n" 170 "\t\tFUNC:\tFunction name\n"
146 "\t\tOFFS:\tOffset from function entry (in byte)\n" 171 "\t\tOFFS:\tOffset from function entry (in byte)\n"
147 "\t\t%return:\tPut the probe at function return\n" 172 "\t\t%return:\tPut the probe at function return\n"
@@ -155,12 +180,14 @@ static const struct option options[] = {
155#endif 180#endif
156 "\t\t\tkprobe-tracer argument format.)\n", 181 "\t\t\tkprobe-tracer argument format.)\n",
157 opt_add_probe_event), 182 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
184 " with existing name"),
158 OPT_END() 185 OPT_END()
159}; 186};
160 187
161int cmd_probe(int argc, const char **argv, const char *prefix __used) 188int cmd_probe(int argc, const char **argv, const char *prefix __used)
162{ 189{
163 int i, j, ret; 190 int i, ret;
164#ifndef NO_LIBDWARF 191#ifndef NO_LIBDWARF
165 int fd; 192 int fd;
166#endif 193#endif
@@ -168,54 +195,92 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
168 195
169 argc = parse_options(argc, argv, options, probe_usage, 196 argc = parse_options(argc, argv, options, probe_usage,
170 PARSE_OPT_STOP_AT_NON_OPTION); 197 PARSE_OPT_STOP_AT_NON_OPTION);
171 for (i = 0; i < argc; i++) 198 if (argc > 0) {
172 parse_probe_event(argv[i]); 199 if (strcmp(argv[0], "-") == 0) {
200 pr_warning(" Error: '-' is not supported.\n");
201 usage_with_options(probe_usage, options);
202 }
203 parse_probe_event_argv(argc, argv);
204 }
173 205
174 if ((session.nr_probe == 0 && !listing) || 206 if ((!session.nr_probe && !session.dellist && !session.list_events))
175 (session.nr_probe != 0 && listing))
176 usage_with_options(probe_usage, options); 207 usage_with_options(probe_usage, options);
177 208
178 if (listing) { 209 if (debugfs_valid_mountpoint(debugfs_path) < 0)
210 die("Failed to find debugfs path.");
211
212 if (session.list_events) {
213 if (session.nr_probe != 0 || session.dellist) {
214 pr_warning(" Error: Don't use --list with"
215 " --add/--del.\n");
216 usage_with_options(probe_usage, options);
217 }
179 show_perf_probe_events(); 218 show_perf_probe_events();
180 return 0; 219 return 0;
181 } 220 }
182 221
222 if (session.dellist) {
223 del_trace_kprobe_events(session.dellist);
224 strlist__delete(session.dellist);
225 if (session.nr_probe == 0)
226 return 0;
227 }
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
183 if (session.need_dwarf) 244 if (session.need_dwarf)
184#ifdef NO_LIBDWARF 245#ifdef NO_LIBDWARF
185 die("Debuginfo-analysis is not supported"); 246 die("Debuginfo-analysis is not supported");
186#else /* !NO_LIBDWARF */ 247#else /* !NO_LIBDWARF */
187 pr_debug("Some probes require debuginfo.\n"); 248 pr_debug("Some probes require debuginfo.\n");
188 249
189 if (session.vmlinux) 250 fd = open_vmlinux();
190 fd = open(session.vmlinux, O_RDONLY);
191 else
192 fd = open_default_vmlinux();
193 if (fd < 0) { 251 if (fd < 0) {
194 if (session.need_dwarf) 252 if (session.need_dwarf)
195 die("Could not open vmlinux/module file."); 253 die("Could not open debuginfo file.");
196 254
197 pr_warning("Could not open vmlinux/module file." 255 pr_debug("Could not open vmlinux/module file."
198 " Try to use symbols.\n"); 256 " Try to use symbols.\n");
199 goto end_dwarf; 257 goto end_dwarf;
200 } 258 }
201 259
202 /* Searching probe points */ 260 /* Searching probe points */
203 for (j = 0; j < session.nr_probe; j++) { 261 for (i = 0; i < session.nr_probe; i++) {
204 pp = &session.probes[j]; 262 pp = &session.probes[i];
205 if (pp->found) 263 if (pp->found)
206 continue; 264 continue;
207 265
208 lseek(fd, SEEK_SET, 0); 266 lseek(fd, SEEK_SET, 0);
209 ret = find_probepoint(fd, pp); 267 ret = find_probepoint(fd, pp);
210 if (ret < 0) { 268 if (ret > 0)
211 if (session.need_dwarf) 269 continue;
212 die("Could not analyze debuginfo."); 270 if (ret == 0) { /* No error but failed to find probe point. */
213 271 synthesize_perf_probe_point(pp);
214 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n"); 272 die("Probe point '%s' not found. - probe not added.",
215 break; 273 pp->probes[0]);
274 }
275 /* Error path */
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.");
216 } 280 }
217 if (ret == 0) /* No error but failed to find probe point. */ 281 pr_debug("An error occurred in debuginfo analysis."
218 die("No probe point found."); 282 " Try to use symbols.\n");
283 break;
219 } 284 }
220 close(fd); 285 close(fd);
221 286
@@ -223,11 +288,12 @@ end_dwarf:
223#endif /* !NO_LIBDWARF */ 288#endif /* !NO_LIBDWARF */
224 289
225 /* Synthesize probes without dwarf */ 290 /* Synthesize probes without dwarf */
226 for (j = 0; j < session.nr_probe; j++) { 291 for (i = 0; i < session.nr_probe; i++) {
227 pp = &session.probes[j]; 292 pp = &session.probes[i];
228 if (pp->found) /* This probe is already found. */ 293 if (pp->found) /* This probe is already found. */
229 continue; 294 continue;
230 295
296 evaluate_probe_point(pp);
231 ret = synthesize_trace_kprobe_event(pp); 297 ret = synthesize_trace_kprobe_event(pp);
232 if (ret == -E2BIG) 298 if (ret == -E2BIG)
233 die("probe point definition becomes too long."); 299 die("probe point definition becomes too long.");
@@ -236,7 +302,8 @@ end_dwarf:
236 } 302 }
237 303
238 /* Settng up probe points */ 304 /* Settng up probe points */
239 add_trace_kprobe_events(session.probes, session.nr_probe); 305 add_trace_kprobe_events(session.probes, session.nr_probe,
306 session.force_add);
240 return 0; 307 return 0;
241} 308}
242 309
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0e519c667e3a..265425322734 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,9 +397,9 @@ 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, const char **argv)
@@ -408,6 +410,9 @@ 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 const bool forks = target_pid == -1 && argc > 0;
415 char buf;
411 416
412 page_size = sysconf(_SC_PAGE_SIZE); 417 page_size = sysconf(_SC_PAGE_SIZE);
413 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 418 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -418,11 +423,25 @@ static int __cmd_record(int argc, const char **argv)
418 signal(SIGCHLD, sig_handler); 423 signal(SIGCHLD, sig_handler);
419 signal(SIGINT, sig_handler); 424 signal(SIGINT, sig_handler);
420 425
426 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
427 perror("failed to create pipes");
428 exit(-1);
429 }
430
421 if (!stat(output_name, &st) && st.st_size) { 431 if (!stat(output_name, &st) && st.st_size) {
422 if (!force && !append_file) { 432 if (!force) {
423 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 433 if (!append_file) {
424 output_name); 434 pr_err("Error, output file %s exists, use -A "
425 exit(-1); 435 "to append or -f to overwrite.\n",
436 output_name);
437 exit(-1);
438 }
439 } else {
440 char oldname[PATH_MAX];
441 snprintf(oldname, sizeof(oldname), "%s.old",
442 output_name);
443 unlink(oldname);
444 rename(output_name, oldname);
426 } 445 }
427 } else { 446 } else {
428 append_file = 0; 447 append_file = 0;
@@ -440,24 +459,24 @@ static int __cmd_record(int argc, const char **argv)
440 exit(-1); 459 exit(-1);
441 } 460 }
442 461
443 header = perf_header__new(); 462 session = perf_session__new(output_name, O_WRONLY, force);
444 if (header == NULL) { 463 if (session == NULL) {
445 pr_err("Not enough memory for reading perf file header\n"); 464 pr_err("Not enough memory for reading perf file header\n");
446 return -1; 465 return -1;
447 } 466 }
448 467
449 if (!file_new) { 468 if (!file_new) {
450 err = perf_header__read(header, output); 469 err = perf_header__read(&session->header, output);
451 if (err < 0) 470 if (err < 0)
452 return err; 471 return err;
453 } 472 }
454 473
455 if (raw_samples) { 474 if (raw_samples) {
456 perf_header__set_feat(header, HEADER_TRACE_INFO); 475 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
457 } else { 476 } else {
458 for (i = 0; i < nr_counters; i++) { 477 for (i = 0; i < nr_counters; i++) {
459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 478 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
460 perf_header__set_feat(header, HEADER_TRACE_INFO); 479 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
461 break; 480 break;
462 } 481 }
463 } 482 }
@@ -465,56 +484,79 @@ static int __cmd_record(int argc, const char **argv)
465 484
466 atexit(atexit_header); 485 atexit(atexit_header);
467 486
468 if (!system_wide) { 487 if (forks) {
469 pid = target_pid; 488 pid = fork();
470 if (pid == -1) 489 if (pid < 0) {
471 pid = getpid(); 490 perror("failed to fork");
472 491 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 } 492 }
481 }
482 493
483 if (file_new) { 494 if (!pid) {
484 err = perf_header__write(header, output, false); 495 close(child_ready_pipe[0]);
485 if (err < 0) 496 close(go_pipe[1]);
486 return err; 497 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
487 }
488 498
489 if (!system_wide) 499 /*
490 event__synthesize_thread(pid, process_synthesized_event); 500 * Do a dummy execvp to get the PLT entry resolved,
491 else 501 * so we avoid the resolver overhead on the real
492 event__synthesize_threads(process_synthesized_event); 502 * execvp call.
503 */
504 execvp("", (char **)argv);
493 505
494 if (target_pid == -1 && argc) { 506 /*
495 pid = fork(); 507 * Tell the parent we're ready to go
496 if (pid < 0) 508 */
497 die("failed to fork"); 509 close(child_ready_pipe[1]);
498 510
499 if (!pid) {
500 if (execvp(argv[0], (char **)argv)) {
501 perror(argv[0]);
502 exit(-1);
503 }
504 } else {
505 /* 511 /*
506 * Wait a bit for the execv'ed child to appear 512 * Wait until the parent tells us to go.
507 * and be updated in /proc
508 * FIXME: Do you know a less heuristical solution?
509 */ 513 */
510 usleep(1000); 514 if (read(go_pipe[0], &buf, 1) == -1)
511 event__synthesize_thread(pid, 515 perror("unable to read pipe");
512 process_synthesized_event); 516
517 execvp(argv[0], (char **)argv);
518
519 perror(argv[0]);
520 exit(-1);
513 } 521 }
514 522
515 child_pid = pid; 523 child_pid = pid;
524
525 if (!system_wide)
526 target_pid = pid;
527
528 close(child_ready_pipe[1]);
529 close(go_pipe[0]);
530 /*
531 * wait for child to settle
532 */
533 if (read(child_ready_pipe[0], &buf, 1) == -1) {
534 perror("unable to read pipe");
535 exit(-1);
536 }
537 close(child_ready_pipe[0]);
538 }
539
540
541 if ((!system_wide && !inherit) || profile_cpu != -1) {
542 open_counters(profile_cpu, target_pid);
543 } else {
544 for (i = 0; i < nr_cpus; i++)
545 open_counters(i, target_pid);
516 } 546 }
517 547
548 if (file_new) {
549 err = perf_header__write(&session->header, output, false);
550 if (err < 0)
551 return err;
552 }
553
554 if (!system_wide && profile_cpu == -1)
555 event__synthesize_thread(pid, process_synthesized_event,
556 session);
557 else
558 event__synthesize_threads(process_synthesized_event, session);
559
518 if (realtime_prio) { 560 if (realtime_prio) {
519 struct sched_param param; 561 struct sched_param param;
520 562
@@ -525,6 +567,12 @@ static int __cmd_record(int argc, const char **argv)
525 } 567 }
526 } 568 }
527 569
570 /*
571 * Let the child rip
572 */
573 if (forks)
574 close(go_pipe[1]);
575
528 for (;;) { 576 for (;;) {
529 int hits = samples; 577 int hits = samples;
530 578
@@ -619,13 +667,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
619{ 667{
620 int counter; 668 int counter;
621 669
622 symbol__init(0);
623
624 argc = parse_options(argc, argv, options, record_usage, 670 argc = parse_options(argc, argv, options, record_usage,
625 PARSE_OPT_STOP_AT_NON_OPTION); 671 PARSE_OPT_STOP_AT_NON_OPTION);
626 if (!argc && target_pid == -1 && !system_wide) 672 if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1)
627 usage_with_options(record_usage, options); 673 usage_with_options(record_usage, options);
628 674
675 symbol__init();
676
629 if (!nr_counters) { 677 if (!nr_counters) {
630 nr_counters = 1; 678 nr_counters = 1;
631 attrs[0].type = PERF_TYPE_HARDWARE; 679 attrs[0].type = PERF_TYPE_HARDWARE;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 383c4ab4f9af..db10c0e8ecae 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,108 +84,60 @@ 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 u64 ip = event->ip.ip; 89 struct sample_data data = { .period = 1, };
609 u64 period = 1;
610 void *more_data = event->ip.__more_data;
611 struct ip_callchain *chain = NULL;
612 int cpumode;
613 struct addr_location al; 90 struct addr_location al;
614 struct thread *thread = threads__findnew(event->ip.pid);
615 91
616 if (sample_type & PERF_SAMPLE_PERIOD) { 92 event__parse_sample(event, session->sample_type, &data);
617 period = *(u64 *)more_data;
618 more_data += sizeof(u64);
619 }
620 93
621 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
622 event->header.misc, 95 event->header.misc,
623 event->ip.pid, event->ip.tid, 96 data.pid, data.tid,
624 (void *)(long)ip, 97 (void *)(long)data.ip,
625 (long long)period); 98 (long long)data.period);
626 99
627 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
628 unsigned int i; 101 unsigned int i;
629 102
630 chain = (void *)more_data; 103 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
631 104
632 dump_printf("... chain: nr:%Lu\n", chain->nr); 105 if (validate_chain(data.callchain, event) < 0) {
633
634 if (validate_chain(chain, event) < 0) {
635 pr_debug("call-chain problem with event, " 106 pr_debug("call-chain problem with event, "
636 "skipping it.\n"); 107 "skipping it.\n");
637 return 0; 108 return 0;
638 } 109 }
639 110
640 if (dump_trace) { 111 if (dump_trace) {
641 for (i = 0; i < chain->nr; i++) 112 for (i = 0; i < data.callchain->nr; i++)
642 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 113 dump_printf("..... %2d: %016Lx\n",
114 i, data.callchain->ips[i]);
643 } 115 }
644 } 116 }
645 117
646 if (thread == NULL) { 118 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
647 pr_debug("problem processing %d event, skipping it.\n", 119 fprintf(stderr, "problem processing %d event, skipping it.\n",
648 event->header.type); 120 event->header.type);
649 return -1; 121 return -1;
650 } 122 }
651 123
652 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 124 if (al.filtered)
653
654 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
655 return 0;
656
657 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
658
659 thread__find_addr_location(thread, cpumode,
660 MAP__FUNCTION, ip, &al, NULL);
661 /*
662 * We have to do this here as we may have a dso with no symbol hit that
663 * has a name longer than the ones with symbols sampled.
664 */
665 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
666 dso__calc_col_width(al.map->dso);
667
668 if (dso_list &&
669 (!al.map || !al.map->dso ||
670 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
671 (al.map->dso->short_name != al.map->dso->long_name &&
672 strlist__has_entry(dso_list, al.map->dso->long_name)))))
673 return 0; 125 return 0;
674 126
675 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)) {
676 return 0;
677
678 if (hist_entry__add(&al, chain, period)) {
679 pr_debug("problem incrementing symbol count, skipping event\n"); 128 pr_debug("problem incrementing symbol count, skipping event\n");
680 return -1; 129 return -1;
681 } 130 }
682 131
683 event__stats.total += period; 132 session->events_stats.total += data.period;
684
685 return 0; 133 return 0;
686} 134}
687 135
688static int process_comm_event(event_t *event) 136static int process_read_event(event_t *event, struct perf_session *session __used)
689{
690 struct thread *thread = threads__findnew(event->comm.pid);
691
692 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
693
694 if (thread == NULL ||
695 thread__set_comm_adjust(thread, event->comm.comm)) {
696 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
697 return -1;
698 }
699
700 return 0;
701}
702
703static int process_read_event(event_t *event)
704{ 137{
705 struct perf_event_attr *attr; 138 struct perf_event_attr *attr;
706 139
707 attr = perf_header__find_attr(event->read.id, header); 140 attr = perf_header__find_attr(event->read.id, &session->header);
708 141
709 if (show_threads) { 142 if (show_threads) {
710 const char *name = attr ? __event_name(attr->type, attr->config) 143 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -723,25 +156,23 @@ static int process_read_event(event_t *event)
723 return 0; 156 return 0;
724} 157}
725 158
726static int sample_type_check(u64 type) 159static int sample_type_check(struct perf_session *session)
727{ 160{
728 sample_type = type; 161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
729
730 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
731 if (sort__has_parent) { 162 if (sort__has_parent) {
732 fprintf(stderr, "selected --sort parent, but no" 163 fprintf(stderr, "selected --sort parent, but no"
733 " callchain data. Did you call" 164 " callchain data. Did you call"
734 " perf record without -g?\n"); 165 " perf record without -g?\n");
735 return -1; 166 return -1;
736 } 167 }
737 if (callchain) { 168 if (symbol_conf.use_callchain) {
738 fprintf(stderr, "selected -g but no callchain data." 169 fprintf(stderr, "selected -g but no callchain data."
739 " Did you call perf record without" 170 " Did you call perf record without"
740 " -g?\n"); 171 " -g?\n");
741 return -1; 172 return -1;
742 } 173 }
743 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) {
744 callchain = 1; 175 symbol_conf.use_callchain = true;
745 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
746 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
747 " params\n"); 178 " params\n");
@@ -752,10 +183,10 @@ static int sample_type_check(u64 type)
752 return 0; 183 return 0;
753} 184}
754 185
755static struct perf_file_handler file_handler = { 186static struct perf_event_ops event_ops = {
756 .process_sample_event = process_sample_event, 187 .process_sample_event = process_sample_event,
757 .process_mmap_event = event__process_mmap, 188 .process_mmap_event = event__process_mmap,
758 .process_comm_event = process_comm_event, 189 .process_comm_event = event__process_comm,
759 .process_exit_event = event__process_task, 190 .process_exit_event = event__process_task,
760 .process_fork_event = event__process_task, 191 .process_fork_event = event__process_task,
761 .process_lost_event = event__process_lost, 192 .process_lost_event = event__process_lost,
@@ -766,40 +197,47 @@ static struct perf_file_handler file_handler = {
766 197
767static int __cmd_report(void) 198static int __cmd_report(void)
768{ 199{
769 struct thread *idle;
770 int ret; 200 int ret;
201 struct perf_session *session;
771 202
772 idle = register_idle_thread(); 203 session = perf_session__new(input_name, O_RDONLY, force);
773 thread__comm_adjust(idle); 204 if (session == NULL)
205 return -ENOMEM;
774 206
775 if (show_threads) 207 if (show_threads)
776 perf_read_values_init(&show_threads_values); 208 perf_read_values_init(&show_threads_values);
777 209
778 register_perf_file_handler(&file_handler); 210 ret = perf_session__process_events(session, &event_ops);
779
780 ret = mmap_dispatch_perf_file(&header, input_name, force,
781 full_paths, &event__cwdlen, &event__cwd);
782 if (ret) 211 if (ret)
783 return ret; 212 goto out_delete;
784 213
785 if (dump_trace) { 214 if (dump_trace) {
786 event__print_totals(); 215 event__print_totals();
787 return 0; 216 goto out_delete;
788 } 217 }
789 218
790 if (verbose > 3) 219 if (verbose > 3)
791 threads__fprintf(stdout); 220 perf_session__fprintf(session, stdout);
792 221
793 if (verbose > 2) 222 if (verbose > 2)
794 dsos__fprintf(stdout); 223 dsos__fprintf(stdout);
795 224
796 collapse__resort(); 225 perf_session__collapse_resort(session);
797 output__resort(event__stats.total); 226 perf_session__output_resort(session, session->events_stats.total);
798 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");
799 232
800 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);
801 perf_read_values_destroy(&show_threads_values); 237 perf_read_values_destroy(&show_threads_values);
802 238 }
239out_delete:
240 perf_session__delete(session);
803 return ret; 241 return ret;
804} 242}
805 243
@@ -810,7 +248,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
810 char *tok; 248 char *tok;
811 char *endptr; 249 char *endptr;
812 250
813 callchain = 1; 251 symbol_conf.use_callchain = true;
814 252
815 if (!arg) 253 if (!arg)
816 return 0; 254 return 0;
@@ -831,7 +269,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
831 269
832 else if (!strncmp(tok, "none", strlen(arg))) { 270 else if (!strncmp(tok, "none", strlen(arg))) {
833 callchain_param.mode = CHAIN_NONE; 271 callchain_param.mode = CHAIN_NONE;
834 callchain = 0; 272 symbol_conf.use_callchain = true;
835 273
836 return 0; 274 return 0;
837 } 275 }
@@ -856,8 +294,7 @@ setup:
856 return 0; 294 return 0;
857} 295}
858 296
859//static const char * const report_usage[] = { 297static const char * const report_usage[] = {
860const char * const report_usage[] = {
861 "perf report [<options>] <command>", 298 "perf report [<options>] <command>",
862 NULL 299 NULL
863}; 300};
@@ -874,7 +311,7 @@ static const struct option options[] = {
874 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 311 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
875 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 312 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
876 "load module symbols - WARNING: use only with -k and LIVE kernel"), 313 "load module symbols - WARNING: use only with -k and LIVE kernel"),
877 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 314 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
878 "Show a column with the number of samples"), 315 "Show a column with the number of samples"),
879 OPT_BOOLEAN('T', "threads", &show_threads, 316 OPT_BOOLEAN('T', "threads", &show_threads,
880 "Show per-thread event counters"), 317 "Show per-thread event counters"),
@@ -882,78 +319,46 @@ static const struct option options[] = {
882 "pretty printing style key: normal raw"), 319 "pretty printing style key: normal raw"),
883 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 320 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
884 "sort by key(s): pid, comm, dso, symbol, parent"), 321 "sort by key(s): pid, comm, dso, symbol, parent"),
885 OPT_BOOLEAN('P', "full-paths", &full_paths, 322 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
886 "Don't shorten the pathnames taking into account the cwd"), 323 "Don't shorten the pathnames taking into account the cwd"),
887 OPT_STRING('p', "parent", &parent_pattern, "regex", 324 OPT_STRING('p', "parent", &parent_pattern, "regex",
888 "regex filter to identify parent, see: '--sort parent'"), 325 "regex filter to identify parent, see: '--sort parent'"),
889 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 326 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
890 "Only display entries with parent-match"), 327 "Only display entries with parent-match"),
891 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 328 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
892 "Display callchains using output_type and min percent threshold. " 329 "Display callchains using output_type and min percent threshold. "
893 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 330 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
894 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 331 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
895 "only consider symbols in these dsos"), 332 "only consider symbols in these dsos"),
896 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 333 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
897 "only consider symbols in these comms"), 334 "only consider symbols in these comms"),
898 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 335 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
899 "only consider these symbols"), 336 "only consider these symbols"),
900 OPT_STRING('w', "column-widths", &col_width_list_str, 337 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
901 "width[,width...]", 338 "width[,width...]",
902 "don't try to adjust column width, use these fixed values"), 339 "don't try to adjust column width, use these fixed values"),
903 OPT_STRING('t', "field-separator", &field_sep, "separator", 340 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
904 "separator for columns, no spaces will be added between " 341 "separator for columns, no spaces will be added between "
905 "columns '.' is reserved."), 342 "columns '.' is reserved."),
906 OPT_END() 343 OPT_END()
907}; 344};
908 345
909static void setup_sorting(void) 346int cmd_report(int argc, const char **argv, const char *prefix __used)
910{ 347{
911 char *tmp, *tok, *str = strdup(sort_order); 348 argc = parse_options(argc, argv, options, report_usage, 0);
912
913 for (tok = strtok_r(str, ", ", &tmp);
914 tok; tok = strtok_r(NULL, ", ", &tmp)) {
915 if (sort_dimension__add(tok) < 0) {
916 error("Unknown --sort key: `%s'", tok);
917 usage_with_options(report_usage, options);
918 }
919 }
920
921 free(str);
922}
923 349
924static void setup_list(struct strlist **list, const char *list_str, 350 setup_pager();
925 struct sort_entry *se, const char *list_name,
926 FILE *fp)
927{
928 if (list_str) {
929 *list = strlist__new(true, list_str);
930 if (!*list) {
931 fprintf(stderr, "problems parsing %s list\n",
932 list_name);
933 exit(129);
934 }
935 if (strlist__nr_entries(*list) == 1) {
936 fprintf(fp, "# %s: %s\n", list_name,
937 strlist__entry(*list, 0)->s);
938 se->elide = true;
939 }
940 }
941}
942 351
943int cmd_report(int argc, const char **argv, const char *prefix __used) 352 if (symbol__init() < 0)
944{
945 if (symbol__init(&symbol_conf) < 0)
946 return -1; 353 return -1;
947 354
948 argc = parse_options(argc, argv, options, report_usage, 0); 355 setup_sorting(report_usage, options);
949
950 setup_sorting();
951 356
952 if (parent_pattern != default_parent_pattern) { 357 if (parent_pattern != default_parent_pattern) {
953 sort_dimension__add("parent"); 358 sort_dimension__add("parent");
954 sort_parent.elide = 1; 359 sort_parent.elide = 1;
955 } else 360 } else
956 exclude_other = 0; 361 symbol_conf.exclude_other = false;
957 362
958 /* 363 /*
959 * Any (unrecognized) arguments left? 364 * Any (unrecognized) arguments left?
@@ -961,17 +366,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
961 if (argc) 366 if (argc)
962 usage_with_options(report_usage, options); 367 usage_with_options(report_usage, options);
963 368
964 setup_pager(); 369 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
965 370 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
966 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 371 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
967 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
968 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
969
970 if (field_sep && *field_sep == '.') {
971 fputs("'.' is the only non valid --field-separator argument\n",
972 stderr);
973 exit(129);
974 }
975 372
976 return __cmd_report(); 373 return __cmd_report();
977} 374}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 26b782f26ee1..80209df6cfe8 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,14 +6,13 @@
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/types.h>
17#include <sys/prctl.h> 16#include <sys/prctl.h>
18 17
19#include <semaphore.h> 18#include <semaphore.h>
@@ -22,9 +21,6 @@
22 21
23static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
24 23
25static struct perf_header *header;
26static u64 sample_type;
27
28static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
29static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
30 26
@@ -141,6 +137,7 @@ struct work_atoms {
141 struct thread *thread; 137 struct thread *thread;
142 struct rb_node node; 138 struct rb_node node;
143 u64 max_lat; 139 u64 max_lat;
140 u64 max_lat_at;
144 u64 total_lat; 141 u64 total_lat;
145 u64 nb_atoms; 142 u64 nb_atoms;
146 u64 total_runtime; 143 u64 total_runtime;
@@ -414,34 +411,33 @@ static u64 get_cpu_usage_nsec_parent(void)
414 return sum; 411 return sum;
415} 412}
416 413
417static u64 get_cpu_usage_nsec_self(void) 414static int self_open_counters(void)
418{ 415{
419 char filename [] = "/proc/1234567890/sched"; 416 struct perf_event_attr attr;
420 unsigned long msecs, nsecs; 417 int fd;
421 char *line = NULL;
422 u64 total = 0;
423 size_t len = 0;
424 ssize_t chars;
425 FILE *file;
426 int ret;
427 418
428 sprintf(filename, "/proc/%d/sched", getpid()); 419 memset(&attr, 0, sizeof(attr));
429 file = fopen(filename, "r");
430 BUG_ON(!file);
431 420
432 while ((chars = getline(&line, &len, file)) != -1) { 421 attr.type = PERF_TYPE_SOFTWARE;
433 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", 422 attr.config = PERF_COUNT_SW_TASK_CLOCK;
434 &msecs, &nsecs); 423
435 if (ret == 2) { 424 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
436 total = msecs*1e6 + nsecs; 425
437 break; 426 if (fd < 0)
438 } 427 die("Error: sys_perf_event_open() syscall returned"
439 } 428 "with %d (%s)\n", fd, strerror(errno));
440 if (line) 429 return fd;
441 free(line); 430}
442 fclose(file); 431
432static u64 get_cpu_usage_nsec_self(int fd)
433{
434 u64 runtime;
435 int ret;
443 436
444 return total; 437 ret = read(fd, &runtime, sizeof(runtime));
438 BUG_ON(ret != sizeof(runtime));
439
440 return runtime;
445} 441}
446 442
447static void *thread_func(void *ctx) 443static void *thread_func(void *ctx)
@@ -450,9 +446,11 @@ static void *thread_func(void *ctx)
450 u64 cpu_usage_0, cpu_usage_1; 446 u64 cpu_usage_0, cpu_usage_1;
451 unsigned long i, ret; 447 unsigned long i, ret;
452 char comm2[22]; 448 char comm2[22];
449 int fd;
453 450
454 sprintf(comm2, ":%s", this_task->comm); 451 sprintf(comm2, ":%s", this_task->comm);
455 prctl(PR_SET_NAME, comm2); 452 prctl(PR_SET_NAME, comm2);
453 fd = self_open_counters();
456 454
457again: 455again:
458 ret = sem_post(&this_task->ready_for_work); 456 ret = sem_post(&this_task->ready_for_work);
@@ -462,16 +460,15 @@ again:
462 ret = pthread_mutex_unlock(&start_work_mutex); 460 ret = pthread_mutex_unlock(&start_work_mutex);
463 BUG_ON(ret); 461 BUG_ON(ret);
464 462
465 cpu_usage_0 = get_cpu_usage_nsec_self(); 463 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
466 464
467 for (i = 0; i < this_task->nr_events; i++) { 465 for (i = 0; i < this_task->nr_events; i++) {
468 this_task->curr_event = i; 466 this_task->curr_event = i;
469 process_sched_event(this_task, this_task->atoms[i]); 467 process_sched_event(this_task, this_task->atoms[i]);
470 } 468 }
471 469
472 cpu_usage_1 = get_cpu_usage_nsec_self(); 470 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
473 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 471 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
474
475 ret = sem_post(&this_task->work_done_sem); 472 ret = sem_post(&this_task->work_done_sem);
476 BUG_ON(ret); 473 BUG_ON(ret);
477 474
@@ -628,11 +625,6 @@ static void test_calibrations(void)
628 printf("the sleep test took %Ld nsecs\n", T1-T0); 625 printf("the sleep test took %Ld nsecs\n", T1-T0);
629} 626}
630 627
631struct raw_event_sample {
632 u32 size;
633 char data[0];
634};
635
636#define FILL_FIELD(ptr, field, event, data) \ 628#define FILL_FIELD(ptr, field, event, data) \
637 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) 629 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
638 630
@@ -736,18 +728,21 @@ struct trace_migrate_task_event {
736 728
737struct trace_sched_handler { 729struct trace_sched_handler {
738 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
739 struct event *, 732 struct event *,
740 int cpu, 733 int cpu,
741 u64 timestamp, 734 u64 timestamp,
742 struct thread *thread); 735 struct thread *thread);
743 736
744 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
745 struct event *, 739 struct event *,
746 int cpu, 740 int cpu,
747 u64 timestamp, 741 u64 timestamp,
748 struct thread *thread); 742 struct thread *thread);
749 743
750 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
751 struct event *, 746 struct event *,
752 int cpu, 747 int cpu,
753 u64 timestamp, 748 u64 timestamp,
@@ -760,6 +755,7 @@ struct trace_sched_handler {
760 struct thread *thread); 755 struct thread *thread);
761 756
762 void (*migrate_task_event)(struct trace_migrate_task_event *, 757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
763 struct event *, 759 struct event *,
764 int cpu, 760 int cpu,
765 u64 timestamp, 761 u64 timestamp,
@@ -769,6 +765,7 @@ struct trace_sched_handler {
769 765
770static void 766static void
771replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
772 struct event *event, 769 struct event *event,
773 int cpu __used, 770 int cpu __used,
774 u64 timestamp __used, 771 u64 timestamp __used,
@@ -795,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
795 792
796static void 793static void
797replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
798 struct event *event, 796 struct event *event,
799 int cpu, 797 int cpu,
800 u64 timestamp, 798 u64 timestamp,
@@ -1019,13 +1017,16 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1019 1017
1020 delta = atom->sched_in_time - atom->wake_up_time; 1018 delta = atom->sched_in_time - atom->wake_up_time;
1021 atoms->total_lat += delta; 1019 atoms->total_lat += delta;
1022 if (delta > atoms->max_lat) 1020 if (delta > atoms->max_lat) {
1023 atoms->max_lat = delta; 1021 atoms->max_lat = delta;
1022 atoms->max_lat_at = timestamp;
1023 }
1024 atoms->nb_atoms++; 1024 atoms->nb_atoms++;
1025} 1025}
1026 1026
1027static void 1027static void
1028latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1029 struct event *event __used, 1030 struct event *event __used,
1030 int cpu, 1031 int cpu,
1031 u64 timestamp, 1032 u64 timestamp,
@@ -1049,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1049 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1050 1051
1051 1052
1052 sched_out = threads__findnew(switch_event->prev_pid); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1053 sched_in = threads__findnew(switch_event->next_pid); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1054 1055
1055 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1056 if (!out_events) { 1057 if (!out_events) {
@@ -1078,12 +1079,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1078 1079
1079static void 1080static void
1080latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1081 struct event *event __used, 1083 struct event *event __used,
1082 int cpu, 1084 int cpu,
1083 u64 timestamp, 1085 u64 timestamp,
1084 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1085{ 1087{
1086 struct thread *thread = threads__findnew(runtime_event->pid); 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1087 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);
1088 1090
1089 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1100,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1100 1102
1101static void 1103static void
1102latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1103 struct event *__event __used, 1106 struct event *__event __used,
1104 int cpu __used, 1107 int cpu __used,
1105 u64 timestamp, 1108 u64 timestamp,
@@ -1113,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1113 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1114 return; 1117 return;
1115 1118
1116 wakee = threads__findnew(wakeup_event->pid); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1117 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1118 if (!atoms) { 1121 if (!atoms) {
1119 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1147,6 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1147 1150
1148static void 1151static void
1149latency_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,
1150 struct event *__event __used, 1154 struct event *__event __used,
1151 int cpu __used, 1155 int cpu __used,
1152 u64 timestamp, 1156 u64 timestamp,
@@ -1162,7 +1166,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1162 if (profile_cpu == -1) 1166 if (profile_cpu == -1)
1163 return; 1167 return;
1164 1168
1165 migrant = threads__findnew(migrate_task_event->pid); 1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1166 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1167 if (!atoms) { 1171 if (!atoms) {
1168 thread_atoms_insert(migrant); 1172 thread_atoms_insert(migrant);
@@ -1216,10 +1220,11 @@ static void output_lat_thread(struct work_atoms *work_list)
1216 1220
1217 avg = work_list->total_lat / work_list->nb_atoms; 1221 avg = work_list->total_lat / work_list->nb_atoms;
1218 1222
1219 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", 1223 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1220 (double)work_list->total_runtime / 1e6, 1224 (double)work_list->total_runtime / 1e6,
1221 work_list->nb_atoms, (double)avg / 1e6, 1225 work_list->nb_atoms, (double)avg / 1e6,
1222 (double)work_list->max_lat / 1e6); 1226 (double)work_list->max_lat / 1e6,
1227 (double)work_list->max_lat_at / 1e9);
1223} 1228}
1224 1229
1225static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1230static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1356,7 +1361,7 @@ static void sort_lat(void)
1356static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1357 1362
1358static void 1363static void
1359process_sched_wakeup_event(struct raw_event_sample *raw, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1360 struct event *event, 1365 struct event *event,
1361 int cpu __used, 1366 int cpu __used,
1362 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1364,16 +1369,17 @@ process_sched_wakeup_event(struct raw_event_sample *raw,
1364{ 1369{
1365 struct trace_wakeup_event wakeup_event; 1370 struct trace_wakeup_event wakeup_event;
1366 1371
1367 FILL_COMMON_FIELDS(wakeup_event, event, raw->data); 1372 FILL_COMMON_FIELDS(wakeup_event, event, data);
1368 1373
1369 FILL_ARRAY(wakeup_event, comm, event, raw->data); 1374 FILL_ARRAY(wakeup_event, comm, event, data);
1370 FILL_FIELD(wakeup_event, pid, event, raw->data); 1375 FILL_FIELD(wakeup_event, pid, event, data);
1371 FILL_FIELD(wakeup_event, prio, event, raw->data); 1376 FILL_FIELD(wakeup_event, prio, event, data);
1372 FILL_FIELD(wakeup_event, success, event, raw->data); 1377 FILL_FIELD(wakeup_event, success, event, data);
1373 FILL_FIELD(wakeup_event, cpu, event, raw->data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1374 1379
1375 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1376 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1377} 1383}
1378 1384
1379/* 1385/*
@@ -1391,6 +1397,7 @@ static char next_shortname2 = '0';
1391 1397
1392static void 1398static void
1393map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1394 struct event *event __used, 1401 struct event *event __used,
1395 int this_cpu, 1402 int this_cpu,
1396 u64 timestamp, 1403 u64 timestamp,
@@ -1418,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1418 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1419 1426
1420 1427
1421 sched_out = threads__findnew(switch_event->prev_pid); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1422 sched_in = threads__findnew(switch_event->next_pid); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1423 1430
1424 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1425 1432
@@ -1469,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1469 1476
1470 1477
1471static void 1478static void
1472process_sched_switch_event(struct raw_event_sample *raw, 1479process_sched_switch_event(void *data, struct perf_session *session,
1473 struct event *event, 1480 struct event *event,
1474 int this_cpu, 1481 int this_cpu,
1475 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1477,15 +1484,15 @@ process_sched_switch_event(struct raw_event_sample *raw,
1477{ 1484{
1478 struct trace_switch_event switch_event; 1485 struct trace_switch_event switch_event;
1479 1486
1480 FILL_COMMON_FIELDS(switch_event, event, raw->data); 1487 FILL_COMMON_FIELDS(switch_event, event, data);
1481 1488
1482 FILL_ARRAY(switch_event, prev_comm, event, raw->data); 1489 FILL_ARRAY(switch_event, prev_comm, event, data);
1483 FILL_FIELD(switch_event, prev_pid, event, raw->data); 1490 FILL_FIELD(switch_event, prev_pid, event, data);
1484 FILL_FIELD(switch_event, prev_prio, event, raw->data); 1491 FILL_FIELD(switch_event, prev_prio, event, data);
1485 FILL_FIELD(switch_event, prev_state, event, raw->data); 1492 FILL_FIELD(switch_event, prev_state, event, data);
1486 FILL_ARRAY(switch_event, next_comm, event, raw->data); 1493 FILL_ARRAY(switch_event, next_comm, event, data);
1487 FILL_FIELD(switch_event, next_pid, event, raw->data); 1494 FILL_FIELD(switch_event, next_pid, event, data);
1488 FILL_FIELD(switch_event, next_prio, event, raw->data); 1495 FILL_FIELD(switch_event, next_prio, event, data);
1489 1496
1490 if (curr_pid[this_cpu] != (u32)-1) { 1497 if (curr_pid[this_cpu] != (u32)-1) {
1491 /* 1498 /*
@@ -1496,13 +1503,14 @@ process_sched_switch_event(struct raw_event_sample *raw,
1496 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1497 } 1504 }
1498 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1499 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);
1500 1508
1501 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1502} 1510}
1503 1511
1504static void 1512static void
1505process_sched_runtime_event(struct raw_event_sample *raw, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1506 struct event *event, 1514 struct event *event,
1507 int cpu __used, 1515 int cpu __used,
1508 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1510,17 +1518,17 @@ process_sched_runtime_event(struct raw_event_sample *raw,
1510{ 1518{
1511 struct trace_runtime_event runtime_event; 1519 struct trace_runtime_event runtime_event;
1512 1520
1513 FILL_ARRAY(runtime_event, comm, event, raw->data); 1521 FILL_ARRAY(runtime_event, comm, event, data);
1514 FILL_FIELD(runtime_event, pid, event, raw->data); 1522 FILL_FIELD(runtime_event, pid, event, data);
1515 FILL_FIELD(runtime_event, runtime, event, raw->data); 1523 FILL_FIELD(runtime_event, runtime, event, data);
1516 FILL_FIELD(runtime_event, vruntime, event, raw->data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1517 1525
1518 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1519 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1520} 1528}
1521 1529
1522static void 1530static void
1523process_sched_fork_event(struct raw_event_sample *raw, 1531process_sched_fork_event(void *data,
1524 struct event *event, 1532 struct event *event,
1525 int cpu __used, 1533 int cpu __used,
1526 u64 timestamp __used, 1534 u64 timestamp __used,
@@ -1528,15 +1536,16 @@ process_sched_fork_event(struct raw_event_sample *raw,
1528{ 1536{
1529 struct trace_fork_event fork_event; 1537 struct trace_fork_event fork_event;
1530 1538
1531 FILL_COMMON_FIELDS(fork_event, event, raw->data); 1539 FILL_COMMON_FIELDS(fork_event, event, data);
1532 1540
1533 FILL_ARRAY(fork_event, parent_comm, event, raw->data); 1541 FILL_ARRAY(fork_event, parent_comm, event, data);
1534 FILL_FIELD(fork_event, parent_pid, event, raw->data); 1542 FILL_FIELD(fork_event, parent_pid, event, data);
1535 FILL_ARRAY(fork_event, child_comm, event, raw->data); 1543 FILL_ARRAY(fork_event, child_comm, event, data);
1536 FILL_FIELD(fork_event, child_pid, event, raw->data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1537 1545
1538 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1539 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1540} 1549}
1541 1550
1542static void 1551static void
@@ -1550,7 +1559,7 @@ process_sched_exit_event(struct event *event,
1550} 1559}
1551 1560
1552static void 1561static void
1553process_sched_migrate_task_event(struct raw_event_sample *raw, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1554 struct event *event, 1563 struct event *event,
1555 int cpu __used, 1564 int cpu __used,
1556 u64 timestamp __used, 1565 u64 timestamp __used,
@@ -1558,80 +1567,67 @@ process_sched_migrate_task_event(struct raw_event_sample *raw,
1558{ 1567{
1559 struct trace_migrate_task_event migrate_task_event; 1568 struct trace_migrate_task_event migrate_task_event;
1560 1569
1561 FILL_COMMON_FIELDS(migrate_task_event, event, raw->data); 1570 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1562 1571
1563 FILL_ARRAY(migrate_task_event, comm, event, raw->data); 1572 FILL_ARRAY(migrate_task_event, comm, event, data);
1564 FILL_FIELD(migrate_task_event, pid, event, raw->data); 1573 FILL_FIELD(migrate_task_event, pid, event, data);
1565 FILL_FIELD(migrate_task_event, prio, event, raw->data); 1574 FILL_FIELD(migrate_task_event, prio, event, data);
1566 FILL_FIELD(migrate_task_event, cpu, event, raw->data); 1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1567 1576
1568 if (trace_handler->migrate_task_event) 1577 if (trace_handler->migrate_task_event)
1569 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);
1570} 1580}
1571 1581
1572static void 1582static void
1573process_raw_event(event_t *raw_event __used, void *more_data, 1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1574 int cpu, u64 timestamp, struct thread *thread) 1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1575{ 1585{
1576 struct raw_event_sample *raw = more_data;
1577 struct event *event; 1586 struct event *event;
1578 int type; 1587 int type;
1579 1588
1580 type = trace_parse_common_type(raw->data); 1589
1590 type = trace_parse_common_type(data);
1581 event = trace_find_event(type); 1591 event = trace_find_event(type);
1582 1592
1583 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1584 process_sched_switch_event(raw, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1585 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1586 process_sched_runtime_event(raw, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1587 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1588 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1589 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1590 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1591 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1592 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1594 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1595 if (!strcmp(event->name, "sched_migrate_task")) 1605 if (!strcmp(event->name, "sched_migrate_task"))
1596 process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); 1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1597} 1607}
1598 1608
1599static int process_sample_event(event_t *event) 1609static int process_sample_event(event_t *event, struct perf_session *session)
1600{ 1610{
1611 struct sample_data data;
1601 struct thread *thread; 1612 struct thread *thread;
1602 u64 ip = event->ip.ip;
1603 u64 timestamp = -1;
1604 u32 cpu = -1;
1605 u64 period = 1;
1606 void *more_data = event->ip.__more_data;
1607 1613
1608 if (!(sample_type & PERF_SAMPLE_RAW)) 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1609 return 0; 1615 return 0;
1610 1616
1611 thread = threads__findnew(event->ip.pid); 1617 memset(&data, 0, sizeof(data));
1618 data.time = -1;
1619 data.cpu = -1;
1620 data.period = -1;
1612 1621
1613 if (sample_type & PERF_SAMPLE_TIME) { 1622 event__parse_sample(event, session->sample_type, &data);
1614 timestamp = *(u64 *)more_data;
1615 more_data += sizeof(u64);
1616 }
1617
1618 if (sample_type & PERF_SAMPLE_CPU) {
1619 cpu = *(u32 *)more_data;
1620 more_data += sizeof(u32);
1621 more_data += sizeof(u32); /* reserved */
1622 }
1623
1624 if (sample_type & PERF_SAMPLE_PERIOD) {
1625 period = *(u64 *)more_data;
1626 more_data += sizeof(u64);
1627 }
1628 1623
1629 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1630 event->header.misc, 1625 event->header.misc,
1631 event->ip.pid, event->ip.tid, 1626 data.pid, data.tid,
1632 (void *)(long)ip, 1627 (void *)(long)data.ip,
1633 (long long)period); 1628 (long long)data.period);
1634 1629
1630 thread = perf_session__findnew(session, data.pid);
1635 if (thread == NULL) { 1631 if (thread == NULL) {
1636 pr_debug("problem processing %d event, skipping it.\n", 1632 pr_debug("problem processing %d event, skipping it.\n",
1637 event->header.type); 1633 event->header.type);
@@ -1640,15 +1636,16 @@ static int process_sample_event(event_t *event)
1640 1636
1641 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1637 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1642 1638
1643 if (profile_cpu != -1 && profile_cpu != (int) cpu) 1639 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1644 return 0; 1640 return 0;
1645 1641
1646 process_raw_event(event, more_data, cpu, timestamp, thread); 1642 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1647 1643
1648 return 0; 1644 return 0;
1649} 1645}
1650 1646
1651static int process_lost_event(event_t *event __used) 1647static int process_lost_event(event_t *event __used,
1648 struct perf_session *session __used)
1652{ 1649{
1653 nr_lost_chunks++; 1650 nr_lost_chunks++;
1654 nr_lost_events += event->lost.lost; 1651 nr_lost_events += event->lost.lost;
@@ -1656,11 +1653,9 @@ static int process_lost_event(event_t *event __used)
1656 return 0; 1653 return 0;
1657} 1654}
1658 1655
1659static int sample_type_check(u64 type) 1656static int sample_type_check(struct perf_session *session __used)
1660{ 1657{
1661 sample_type = type; 1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1662
1663 if (!(sample_type & PERF_SAMPLE_RAW)) {
1664 fprintf(stderr, 1659 fprintf(stderr,
1665 "No trace sample to read. Did you call perf record " 1660 "No trace sample to read. Did you call perf record "
1666 "without -R?"); 1661 "without -R?");
@@ -1670,7 +1665,7 @@ static int sample_type_check(u64 type)
1670 return 0; 1665 return 0;
1671} 1666}
1672 1667
1673static struct perf_file_handler file_handler = { 1668static struct perf_event_ops event_ops = {
1674 .process_sample_event = process_sample_event, 1669 .process_sample_event = process_sample_event,
1675 .process_comm_event = event__process_comm, 1670 .process_comm_event = event__process_comm,
1676 .process_lost_event = process_lost_event, 1671 .process_lost_event = process_lost_event,
@@ -1679,11 +1674,14 @@ static struct perf_file_handler file_handler = {
1679 1674
1680static int read_events(void) 1675static int read_events(void)
1681{ 1676{
1682 register_idle_thread(); 1677 int err;
1683 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;
1684 1681
1685 return mmap_dispatch_perf_file(&header, input_name, 0, 0, 1682 err = perf_session__process_events(session, &event_ops);
1686 &event__cwdlen, &event__cwd); 1683 perf_session__delete(session);
1684 return err;
1687} 1685}
1688 1686
1689static void print_bad_events(void) 1687static void print_bad_events(void)
@@ -1724,9 +1722,9 @@ static void __cmd_lat(void)
1724 read_events(); 1722 read_events();
1725 sort_lat(); 1723 sort_lat();
1726 1724
1727 printf("\n -----------------------------------------------------------------------------------------\n"); 1725 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1728 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1726 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1729 printf(" -----------------------------------------------------------------------------------------\n"); 1727 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1730 1728
1731 next = rb_first(&sorted_atom_root); 1729 next = rb_first(&sorted_atom_root);
1732 1730
@@ -1902,13 +1900,18 @@ static int __cmd_record(int argc, const char **argv)
1902 1900
1903int cmd_sched(int argc, const char **argv, const char *prefix __used) 1901int cmd_sched(int argc, const char **argv, const char *prefix __used)
1904{ 1902{
1905 symbol__init(0);
1906
1907 argc = parse_options(argc, argv, sched_options, sched_usage, 1903 argc = parse_options(argc, argv, sched_options, sched_usage,
1908 PARSE_OPT_STOP_AT_NON_OPTION); 1904 PARSE_OPT_STOP_AT_NON_OPTION);
1909 if (!argc) 1905 if (!argc)
1910 usage_with_options(sched_usage, sched_options); 1906 usage_with_options(sched_usage, sched_options);
1911 1907
1908 /*
1909 * Aliased to 'perf trace' for now:
1910 */
1911 if (!strcmp(argv[0], "trace"))
1912 return cmd_trace(argc, argv, prefix);
1913
1914 symbol__init();
1912 if (!strncmp(argv[0], "rec", 3)) { 1915 if (!strncmp(argv[0], "rec", 3)) {
1913 return __cmd_record(argc, argv); 1916 return __cmd_record(argc, argv);
1914 } else if (!strncmp(argv[0], "lat", 3)) { 1917 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1932,11 +1935,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1932 usage_with_options(replay_usage, replay_options); 1935 usage_with_options(replay_usage, replay_options);
1933 } 1936 }
1934 __cmd_replay(); 1937 __cmd_replay();
1935 } else if (!strcmp(argv[0], "trace")) {
1936 /*
1937 * Aliased to 'perf trace' for now:
1938 */
1939 return cmd_trace(argc, argv, prefix);
1940 } else { 1938 } else {
1941 usage_with_options(sched_usage, sched_options); 1939 usage_with_options(sched_usage, sched_options);
1942 } 1940 }
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index cb58b6605fcc..3f8bbcfb1e9b 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,33 +278,30 @@ 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.tid, 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;
302} 297}
303 298
304struct trace_entry { 299struct trace_entry {
305 u32 size;
306 unsigned short type; 300 unsigned short type;
307 unsigned char flags; 301 unsigned char flags;
308 unsigned char preempt_count; 302 unsigned char preempt_count;
309 int pid; 303 int pid;
310 int tgid; 304 int lock_depth;
311}; 305};
312 306
313struct power_entry { 307struct power_entry {
@@ -481,46 +475,24 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
481} 475}
482 476
483 477
484static int 478static int process_sample_event(event_t *event, struct perf_session *session)
485process_sample_event(event_t *event)
486{ 479{
487 int cursor = 0; 480 struct sample_data data;
488 u64 addr = 0;
489 u64 stamp = 0;
490 u32 cpu = 0;
491 u32 pid = 0;
492 struct trace_entry *te; 481 struct trace_entry *te;
493 482
494 if (sample_type & PERF_SAMPLE_IP) 483 memset(&data, 0, sizeof(data));
495 cursor++;
496
497 if (sample_type & PERF_SAMPLE_TID) {
498 pid = event->sample.array[cursor]>>32;
499 cursor++;
500 }
501 if (sample_type & PERF_SAMPLE_TIME) {
502 stamp = event->sample.array[cursor++];
503 484
504 if (!first_time || first_time > stamp) 485 event__parse_sample(event, session->sample_type, &data);
505 first_time = stamp;
506 if (last_time < stamp)
507 last_time = stamp;
508 486
487 if (session->sample_type & PERF_SAMPLE_TIME) {
488 if (!first_time || first_time > data.time)
489 first_time = data.time;
490 if (last_time < data.time)
491 last_time = data.time;
509 } 492 }
510 if (sample_type & PERF_SAMPLE_ADDR)
511 addr = event->sample.array[cursor++];
512 if (sample_type & PERF_SAMPLE_ID)
513 cursor++;
514 if (sample_type & PERF_SAMPLE_STREAM_ID)
515 cursor++;
516 if (sample_type & PERF_SAMPLE_CPU)
517 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
518 if (sample_type & PERF_SAMPLE_PERIOD)
519 cursor++;
520
521 te = (void *)&event->sample.array[cursor];
522 493
523 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { 494 te = (void *)data.raw_data;
495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
524 char *event_str; 496 char *event_str;
525 struct power_entry *pe; 497 struct power_entry *pe;
526 498
@@ -532,19 +504,19 @@ process_sample_event(event_t *event)
532 return 0; 504 return 0;
533 505
534 if (strcmp(event_str, "power:power_start") == 0) 506 if (strcmp(event_str, "power:power_start") == 0)
535 c_state_start(cpu, stamp, pe->value); 507 c_state_start(data.cpu, data.time, pe->value);
536 508
537 if (strcmp(event_str, "power:power_end") == 0) 509 if (strcmp(event_str, "power:power_end") == 0)
538 c_state_end(cpu, stamp); 510 c_state_end(data.cpu, data.time);
539 511
540 if (strcmp(event_str, "power:power_frequency") == 0) 512 if (strcmp(event_str, "power:power_frequency") == 0)
541 p_state_change(cpu, stamp, pe->value); 513 p_state_change(data.cpu, data.time, pe->value);
542 514
543 if (strcmp(event_str, "sched:sched_wakeup") == 0) 515 if (strcmp(event_str, "sched:sched_wakeup") == 0)
544 sched_wakeup(cpu, stamp, pid, te); 516 sched_wakeup(data.cpu, data.time, data.pid, te);
545 517
546 if (strcmp(event_str, "sched:sched_switch") == 0) 518 if (strcmp(event_str, "sched:sched_switch") == 0)
547 sched_switch(cpu, stamp, te); 519 sched_switch(data.cpu, data.time, te);
548 } 520 }
549 return 0; 521 return 0;
550} 522}
@@ -597,16 +569,16 @@ static void end_sample_processing(void)
597 } 569 }
598} 570}
599 571
600static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
601{ 573{
602 int cursor; 574 int cursor;
603 575
604 cursor = 0; 576 cursor = 0;
605 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
606 cursor++; 578 cursor++;
607 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
608 cursor++; 580 cursor++;
609 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
610 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
611 return 0; 583 return 0;
612} 584}
@@ -616,8 +588,7 @@ static u64 sample_time(event_t *event)
616 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
617 * The order will get flipped later. 589 * The order will get flipped later.
618 */ 590 */
619static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
620queue_sample_event(event_t *event)
621{ 592{
622 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
623 int size; 594 int size;
@@ -631,7 +602,7 @@ queue_sample_event(event_t *event)
631 memset(copy, 0, size); 602 memset(copy, 0, size);
632 603
633 copy->next = NULL; 604 copy->next = NULL;
634 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
635 606
636 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
637 608
@@ -1043,7 +1014,7 @@ static void write_svg_file(const char *filename)
1043 svg_close(); 1014 svg_close();
1044} 1015}
1045 1016
1046static void process_samples(void) 1017static void process_samples(struct perf_session *session)
1047{ 1018{
1048 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
1049 event_t *event; 1020 event_t *event;
@@ -1054,15 +1025,13 @@ static void process_samples(void)
1054 while (cursor) { 1025 while (cursor) {
1055 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1056 cursor = cursor->next; 1027 cursor = cursor->next;
1057 process_sample_event(event); 1028 process_sample_event(event, session);
1058 } 1029 }
1059} 1030}
1060 1031
1061static int sample_type_check(u64 type) 1032static int sample_type_check(struct perf_session *session)
1062{ 1033{
1063 sample_type = type; 1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1064
1065 if (!(sample_type & PERF_SAMPLE_RAW)) {
1066 fprintf(stderr, "No trace samples found in the file.\n" 1035 fprintf(stderr, "No trace samples found in the file.\n"
1067 "Have you used 'perf timechart record' to record it?\n"); 1036 "Have you used 'perf timechart record' to record it?\n");
1068 return -1; 1037 return -1;
@@ -1071,7 +1040,7 @@ static int sample_type_check(u64 type)
1071 return 0; 1040 return 0;
1072} 1041}
1073 1042
1074static struct perf_file_handler file_handler = { 1043static struct perf_event_ops event_ops = {
1075 .process_comm_event = process_comm_event, 1044 .process_comm_event = process_comm_event,
1076 .process_fork_event = process_fork_event, 1045 .process_fork_event = process_fork_event,
1077 .process_exit_event = process_exit_event, 1046 .process_exit_event = process_exit_event,
@@ -1081,17 +1050,17 @@ static struct perf_file_handler file_handler = {
1081 1050
1082static int __cmd_timechart(void) 1051static int __cmd_timechart(void)
1083{ 1052{
1084 struct perf_header *header; 1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1085 int ret; 1054 int ret;
1086 1055
1087 register_perf_file_handler(&file_handler); 1056 if (session == NULL)
1057 return -ENOMEM;
1088 1058
1089 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0, 1059 ret = perf_session__process_events(session, &event_ops);
1090 &event__cwdlen, &event__cwd);
1091 if (ret) 1060 if (ret)
1092 return EXIT_FAILURE; 1061 goto out_delete;
1093 1062
1094 process_samples(); 1063 process_samples(session);
1095 1064
1096 end_sample_processing(); 1065 end_sample_processing();
1097 1066
@@ -1101,8 +1070,9 @@ static int __cmd_timechart(void)
1101 1070
1102 pr_info("Written %2.1f seconds of trace to %s.\n", 1071 pr_info("Written %2.1f seconds of trace to %s.\n",
1103 (last_time - first_time) / 1000000000.0, output_name); 1072 (last_time - first_time) / 1000000000.0, output_name);
1104 1073out_delete:
1105 return EXIT_SUCCESS; 1074 perf_session__delete(session);
1075 return ret;
1106} 1076}
1107 1077
1108static const char * const timechart_usage[] = { 1078static const char * const timechart_usage[] = {
@@ -1167,11 +1137,11 @@ static const struct option options[] = {
1167 1137
1168int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1138int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1169{ 1139{
1170 symbol__init(0);
1171
1172 argc = parse_options(argc, argv, options, timechart_usage, 1140 argc = parse_options(argc, argv, options, timechart_usage,
1173 PARSE_OPT_STOP_AT_NON_OPTION); 1141 PARSE_OPT_STOP_AT_NON_OPTION);
1174 1142
1143 symbol__init();
1144
1175 if (argc && !strncmp(argv[0], "rec", 3)) 1145 if (argc && !strncmp(argv[0], "rec", 3))
1176 return __cmd_record(argc, argv); 1146 return __cmd_record(argc, argv);
1177 else if (argc) 1147 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e0a374d0e43a..ddc584b64871 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 abb914aa7be6..574a215e800b 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,77 +59,53 @@ 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 u64 ip = event->ip.ip; 68 struct sample_data data;
70 u64 timestamp = -1; 69 struct thread *thread;
71 u32 cpu = -1;
72 u64 period = 1;
73 void *more_data = event->ip.__more_data;
74 struct thread *thread = threads__findnew(event->ip.pid);
75
76 if (sample_type & PERF_SAMPLE_TIME) {
77 timestamp = *(u64 *)more_data;
78 more_data += sizeof(u64);
79 }
80 70
81 if (sample_type & PERF_SAMPLE_CPU) { 71 memset(&data, 0, sizeof(data));
82 cpu = *(u32 *)more_data; 72 data.time = -1;
83 more_data += sizeof(u32); 73 data.cpu = -1;
84 more_data += sizeof(u32); /* reserved */ 74 data.period = 1;
85 }
86 75
87 if (sample_type & PERF_SAMPLE_PERIOD) { 76 event__parse_sample(event, session->sample_type, &data);
88 period = *(u64 *)more_data;
89 more_data += sizeof(u64);
90 }
91 77
92 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
93 event->header.misc, 79 event->header.misc,
94 event->ip.pid, event->ip.tid, 80 data.pid, data.tid,
95 (void *)(long)ip, 81 (void *)(long)data.ip,
96 (long long)period); 82 (long long)data.period);
97 83
84 thread = perf_session__findnew(session, event->ip.pid);
98 if (thread == NULL) { 85 if (thread == NULL) {
99 pr_debug("problem processing %d event, skipping it.\n", 86 pr_debug("problem processing %d event, skipping it.\n",
100 event->header.type); 87 event->header.type);
101 return -1; 88 return -1;
102 } 89 }
103 90
104 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 91 if (session->sample_type & PERF_SAMPLE_RAW) {
105
106 if (sample_type & PERF_SAMPLE_RAW) {
107 struct {
108 u32 size;
109 char data[0];
110 } *raw = more_data;
111
112 /* 92 /*
113 * FIXME: better resolve from pid from the struct trace_entry 93 * FIXME: better resolve from pid from the struct trace_entry
114 * field, although it should be the same than this perf 94 * field, although it should be the same than this perf
115 * event pid 95 * event pid
116 */ 96 */
117 scripting_ops->process_event(cpu, raw->data, raw->size, 97 scripting_ops->process_event(data.cpu, data.raw_data,
118 timestamp, thread->comm); 98 data.raw_size,
99 data.time, thread->comm);
119 } 100 }
120 event__stats.total += period;
121 101
102 session->events_stats.total += data.period;
122 return 0; 103 return 0;
123} 104}
124 105
125static int sample_type_check(u64 type) 106static int sample_type_check(struct perf_session *session)
126{ 107{
127 sample_type = type; 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
128
129 if (!(sample_type & PERF_SAMPLE_RAW)) {
130 fprintf(stderr, 109 fprintf(stderr,
131 "No trace sample to read. Did you call perf record " 110 "No trace sample to read. Did you call perf record "
132 "without -R?"); 111 "without -R?");
@@ -136,19 +115,15 @@ static int sample_type_check(u64 type)
136 return 0; 115 return 0;
137} 116}
138 117
139static struct perf_file_handler file_handler = { 118static struct perf_event_ops event_ops = {
140 .process_sample_event = process_sample_event, 119 .process_sample_event = process_sample_event,
141 .process_comm_event = event__process_comm, 120 .process_comm_event = event__process_comm,
142 .sample_type_check = sample_type_check, 121 .sample_type_check = sample_type_check,
143}; 122};
144 123
145static int __cmd_trace(void) 124static int __cmd_trace(struct perf_session *session)
146{ 125{
147 register_idle_thread(); 126 return perf_session__process_events(session, &event_ops);
148 register_perf_file_handler(&file_handler);
149
150 return mmap_dispatch_perf_file(&header, input_name,
151 0, 0, &event__cwdlen, &event__cwd);
152} 127}
153 128
154struct script_spec { 129struct script_spec {
@@ -299,7 +274,245 @@ static int parse_scriptname(const struct option *opt __used,
299 return 0; 274 return 0;
300} 275}
301 276
302static const char * const annotate_usage[] = { 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
515static const char * const trace_usage[] = {
303 "perf trace [<options>] <command>", 516 "perf trace [<options>] <command>",
304 NULL 517 NULL
305}; 518};
@@ -309,8 +522,10 @@ static const struct option options[] = {
309 "dump raw trace in ASCII"), 522 "dump raw trace in ASCII"),
310 OPT_BOOLEAN('v', "verbose", &verbose, 523 OPT_BOOLEAN('v', "verbose", &verbose,
311 "be more verbose (show symbol address, etc)"), 524 "be more verbose (show symbol address, etc)"),
312 OPT_BOOLEAN('l', "latency", &latency_format, 525 OPT_BOOLEAN('L', "Latency", &latency_format,
313 "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),
314 OPT_CALLBACK('s', "script", NULL, "name", 529 OPT_CALLBACK('s', "script", NULL, "name",
315 "script file name (lang:script name, script name, or *)", 530 "script file name (lang:script name, script name, or *)",
316 parse_scriptname), 531 parse_scriptname),
@@ -322,24 +537,61 @@ static const struct option options[] = {
322 537
323int cmd_trace(int argc, const char **argv, const char *prefix __used) 538int cmd_trace(int argc, const char **argv, const char *prefix __used)
324{ 539{
325 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 }
326 563
327 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 }
328 570
329 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;
330 577
331 argc = parse_options(argc, argv, options, annotate_usage, 0); 578 execvp("/bin/sh", (char **)__argv);
332 if (argc) { 579 exit(-1);
333 /*
334 * Special case: if there's an argument left then assume tha
335 * it's a symbol filter:
336 */
337 if (argc > 1)
338 usage_with_options(annotate_usage, options);
339 } 580 }
340 581
582 setup_scripting();
583
584 argc = parse_options(argc, argv, options, trace_usage,
585 PARSE_OPT_STOP_AT_NON_OPTION);
586
587 if (symbol__init() < 0)
588 return -1;
341 setup_pager(); 589 setup_pager();
342 590
591 session = perf_session__new(input_name, O_RDONLY, 0);
592 if (session == NULL)
593 return -ENOMEM;
594
343 if (generate_script_lang) { 595 if (generate_script_lang) {
344 struct stat perf_stat; 596 struct stat perf_stat;
345 597
@@ -366,23 +618,20 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
366 return -1; 618 return -1;
367 } 619 }
368 620
369 header = perf_header__new(); 621 perf_header__read(&session->header, input);
370 if (header == NULL)
371 return -1;
372
373 perf_header__read(header, input);
374 err = scripting_ops->generate_script("perf-trace"); 622 err = scripting_ops->generate_script("perf-trace");
375 goto out; 623 goto out;
376 } 624 }
377 625
378 if (script_name) { 626 if (script_name) {
379 err = scripting_ops->start_script(script_name); 627 err = scripting_ops->start_script(script_name, argc, argv);
380 if (err) 628 if (err)
381 goto out; 629 goto out;
382 } 630 }
383 631
384 err = __cmd_trace(); 632 err = __cmd_trace(session);
385 633
634 perf_session__delete(session);
386 cleanup_scripting(); 635 cleanup_scripting();
387out: 636out:
388 return err; 637 return err;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index a3d8bf65f26c..18035b1f16c7 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 02b09ea17a3e..71dc7c3fe7b2 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/design.txt b/tools/perf/design.txt
index f000c30877ac..8d0de5130db3 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -21,7 +21,7 @@ There's one file descriptor per virtual counter used.
21The special file descriptor is opened via the perf_event_open() 21The special file descriptor is opened via the perf_event_open()
22system call: 22system call:
23 23
24 int sys_perf_event_open(struct perf_event_hw_event *hw_event_uptr, 24 int sys_perf_event_open(struct perf_event_attr *hw_event_uptr,
25 pid_t pid, int cpu, int group_fd, 25 pid_t pid, int cpu, int group_fd,
26 unsigned long flags); 26 unsigned long flags);
27 27
@@ -32,9 +32,9 @@ can be used to set the blocking mode, etc.
32Multiple counters can be kept open at a time, and the counters 32Multiple counters can be kept open at a time, and the counters
33can be poll()ed. 33can be poll()ed.
34 34
35When creating a new counter fd, 'perf_event_hw_event' is: 35When creating a new counter fd, 'perf_event_attr' is:
36 36
37struct perf_event_hw_event { 37struct perf_event_attr {
38 /* 38 /*
39 * The MSB of the config word signifies if the rest contains cpu 39 * The MSB of the config word signifies if the rest contains cpu
40 * specific (raw) counter configuration data, if unset, the next 40 * specific (raw) counter configuration data, if unset, the next
@@ -399,7 +399,7 @@ Notification of new events is possible through poll()/select()/epoll() and
399fcntl() managing signals. 399fcntl() managing signals.
400 400
401Normally a notification is generated for every page filled, however one can 401Normally a notification is generated for every page filled, however one can
402additionally set perf_event_hw_event.wakeup_events to generate one every 402additionally set perf_event_attr.wakeup_events to generate one every
403so many counter overflow events. 403so many counter overflow events.
404 404
405Future work will include a splice() interface to the ring-buffer. 405Future work will include a splice() interface to the ring-buffer.
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index cf64049bc9bd..873e55fab375 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 454d5d55f32d..75f941bfba9e 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 89948b015020..7fc4a033dd49 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 f5dcf9cb5bd2..eddb9ccce6a5 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 cea16f78a3a2..7f44c25cc857 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 85769dc456eb..fce3adcb3249 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 aa68435be926..71cfbd182fb9 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 61f91561d848..2a39097687b9 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 ca0bedf637c2..b557b836de3d 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,34 +73,34 @@ 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}
102 98
103int perf_header__read_build_ids(int input, off_t offset, off_t size) 99int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{ 100{
105 struct build_id_event bev; 101 struct build_id_event bev;
106 char filename[PATH_MAX]; 102 char filename[PATH_MAX];
107 off_t limit = offset + size; 103 u64 limit = offset + size;
108 int err = -1; 104 int err = -1;
109 105
110 while (offset < limit) { 106 while (offset < limit) {
@@ -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 3180ff7e3633..000000000000
--- 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, off_t offset, off_t file_size);
31
32#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 414b89d1bde9..bb0fd6da2d56 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;
195
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);
200
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)
209{
210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
182 214
183struct events_stats event__stats; 215 thread__comm_adjust(self);
184 216
185int event__process_comm(event_t *self) 217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
186{ 221{
187 struct thread *thread = threads__findnew(self->comm.pid); 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,32 +318,139 @@ 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;
388 return 0;
389}
390
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
392{
393 u64 *array = event->sample.array;
394
395 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip;
397 array++;
398 }
399
400 if (type & PERF_SAMPLE_TID) {
401 u32 *p = (u32 *)array;
402 data->pid = p[0];
403 data->tid = p[1];
404 array++;
405 }
406
407 if (type & PERF_SAMPLE_TIME) {
408 data->time = *array;
409 array++;
410 }
411
412 if (type & PERF_SAMPLE_ADDR) {
413 data->addr = *array;
414 array++;
415 }
416
417 if (type & PERF_SAMPLE_ID) {
418 data->id = *array;
419 array++;
420 }
421
422 if (type & PERF_SAMPLE_STREAM_ID) {
423 data->stream_id = *array;
424 array++;
425 }
426
427 if (type & PERF_SAMPLE_CPU) {
428 u32 *p = (u32 *)array;
429 data->cpu = *p;
430 array++;
431 }
432
433 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array;
435 array++;
436 }
437
438 if (type & PERF_SAMPLE_READ) {
439 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
440 return -1;
441 }
442
443 if (type & PERF_SAMPLE_CALLCHAIN) {
444 data->callchain = (struct ip_callchain *)array;
445 array += 1 + data->callchain->nr;
446 }
447
448 if (type & PERF_SAMPLE_RAW) {
449 u32 *p = (u32 *)array;
450 data->raw_size = *p;
451 p++;
452 data->raw_data = p;
453 }
454
311 return 0; 455 return 0;
312} 456}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a4cc8105cf67..690a96d0467c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -56,11 +56,25 @@ struct read_event {
56 u64 id; 56 u64 id;
57}; 57};
58 58
59struct sample_event{ 59struct sample_event {
60 struct perf_event_header header; 60 struct perf_event_header header;
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64struct sample_data {
65 u64 ip;
66 u32 pid, tid;
67 u64 time;
68 u64 addr;
69 u64 id;
70 u64 stream_id;
71 u32 cpu;
72 u64 period;
73 struct ip_callchain *callchain;
74 u32 raw_size;
75 void *raw_data;
76};
77
64#define BUILD_ID_SIZE 20 78#define BUILD_ID_SIZE 20
65 79
66struct build_id_event { 80struct build_id_event {
@@ -81,18 +95,19 @@ typedef union event_union {
81} event_t; 95} event_t;
82 96
83struct events_stats { 97struct events_stats {
84 unsigned long total; 98 u64 total;
85 unsigned long lost; 99 u64 lost;
86}; 100};
87 101
88void event__print_totals(void); 102void event__print_totals(void);
89 103
90enum map_type { 104enum map_type {
91 MAP__FUNCTION = 0, 105 MAP__FUNCTION = 0,
92 106 MAP__VARIABLE,
93 MAP__NR_TYPES,
94}; 107};
95 108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
96struct map { 111struct map {
97 union { 112 union {
98 struct rb_node rb_node; 113 struct rb_node rb_node;
@@ -134,26 +149,35 @@ void map__delete(struct map *self);
134struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
135int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
136size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
137struct symbol *map__find_symbol(struct map *self, u64 addr, 152
138 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);
139void map__fixup_start(struct map *self); 162void map__fixup_start(struct map *self);
140void map__fixup_end(struct map *self); 163void map__fixup_end(struct map *self);
141 164
142int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 165int event__synthesize_thread(pid_t pid,
143void event__synthesize_threads(int (*process)(event_t *event)); 166 int (*process)(event_t *event,
144 167 struct perf_session *session),
145extern char *event__cwd; 168 struct perf_session *session);
146extern int event__cwdlen; 169void event__synthesize_threads(int (*process)(event_t *event,
147extern struct events_stats event__stats; 170 struct perf_session *session),
148extern unsigned long event__total[PERF_RECORD_MAX]; 171 struct perf_session *session);
149 172
150int event__process_comm(event_t *self); 173int event__process_comm(event_t *self, struct perf_session *session);
151int event__process_lost(event_t *self); 174int event__process_lost(event_t *self, struct perf_session *session);
152int event__process_mmap(event_t *self); 175int event__process_mmap(event_t *self, struct perf_session *session);
153int event__process_task(event_t *self); 176int event__process_task(event_t *self, struct perf_session *session);
154 177
155struct addr_location; 178struct addr_location;
156int event__preprocess_sample(const event_t *self, struct addr_location *al, 179int event__preprocess_sample(const event_t *self, struct perf_session *session,
157 symbol_filter_t filter); 180 struct addr_location *al, symbol_filter_t filter);
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
158 182
159#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4805e6dfd23c..8a0bca55106f 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,
@@ -187,7 +171,9 @@ static int do_write(int fd, const void *buf, size_t size)
187 171
188static int __dsos__write_buildid_table(struct list_head *head, int fd) 172static int __dsos__write_buildid_table(struct list_head *head, int fd)
189{ 173{
174#define NAME_ALIGN 64
190 struct dso *pos; 175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN];
191 177
192 list_for_each_entry(pos, head, node) { 178 list_for_each_entry(pos, head, node) {
193 int err; 179 int err;
@@ -197,14 +183,17 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
197 if (!pos->has_build_id) 183 if (!pos->has_build_id)
198 continue; 184 continue;
199 len = pos->long_name_len + 1; 185 len = pos->long_name_len + 1;
200 len = ALIGN(len, 64); 186 len = ALIGN(len, NAME_ALIGN);
201 memset(&b, 0, sizeof(b)); 187 memset(&b, 0, sizeof(b));
202 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
203 b.header.size = sizeof(b) + len; 189 b.header.size = sizeof(b) + len;
204 err = do_write(fd, &b, sizeof(b)); 190 err = do_write(fd, &b, sizeof(b));
205 if (err < 0) 191 if (err < 0)
206 return err; 192 return err;
207 err = do_write(fd, pos->long_name, len); 193 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
194 if (err < 0)
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
208 if (err < 0) 197 if (err < 0)
209 return err; 198 return err;
210 } 199 }
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d1dbe2b79c42..d118d05d3abe 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 0ebf6ee16caa..e8daf5ca6fd2 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 3020db0c9292..e5f99b24048b 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 69f94fe9db20..c4d55a0da2ea 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/parse-events.c b/tools/perf/util/parse-events.c
index 9e5dbd66d34d..e5bc0fb016b2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -197,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
197 if (id == config) { 197 if (id == config) {
198 closedir(evt_dir); 198 closedir(evt_dir);
199 closedir(sys_dir); 199 closedir(sys_dir);
200 path = zalloc(sizeof(path)); 200 path = zalloc(sizeof(*path));
201 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
202 if (!path->system) { 202 if (!path->system) {
203 free(path); 203 free(path);
@@ -467,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
467 while ((evt_ent = readdir(evt_dir))) { 467 while ((evt_ent = readdir(evt_dir))) {
468 char event_opt[MAX_EVOPT_LEN + 1]; 468 char event_opt[MAX_EVOPT_LEN + 1];
469 int len; 469 int len;
470 unsigned int rem = MAX_EVOPT_LEN;
471 470
472 if (!strcmp(evt_ent->d_name, ".") 471 if (!strcmp(evt_ent->d_name, ".")
473 || !strcmp(evt_ent->d_name, "..") 472 || !strcmp(evt_ent->d_name, "..")
@@ -475,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
475 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
476 continue; 475 continue;
477 476
478 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
479 evt_ent->d_name); 478 evt_ent->d_name, flags ? ":" : "",
479 flags ?: "");
480 if (len < 0) 480 if (len < 0)
481 return EVT_FAILED; 481 return EVT_FAILED;
482 482
483 rem -= len;
484 if (flags) {
485 if (rem < strlen(flags) + 1)
486 return EVT_FAILED;
487
488 strcat(event_opt, ":");
489 strcat(event_opt, flags);
490 }
491
492 if (parse_events(NULL, event_opt, 0)) 483 if (parse_events(NULL, event_opt, 0))
493 return EVT_FAILED; 484 return EVT_FAILED;
494 } 485 }
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 6d8af48c925e..efebd5b476b3 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr,
430 pos = fprintf(stderr, " "); 430 pos = fprintf(stderr, " ");
431 if (opts->short_name) 431 if (opts->short_name)
432 pos += fprintf(stderr, "-%c", opts->short_name); 432 pos += fprintf(stderr, "-%c", opts->short_name);
433 else
434 pos += fprintf(stderr, " ");
435
433 if (opts->long_name && opts->short_name) 436 if (opts->long_name && opts->short_name)
434 pos += fprintf(stderr, ", "); 437 pos += fprintf(stderr, ", ");
435 if (opts->long_name) 438 if (opts->long_name)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index cd7fbda5e2a5..29465d440043 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -48,6 +48,9 @@
48 48
49/* If there is no space to write, returns -E2BIG. */ 49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...) 50static int e_snprintf(char *str, size_t size, const char *format, ...)
51 __attribute__((format(printf, 3, 4)));
52
53static int e_snprintf(char *str, size_t size, const char *format, ...)
51{ 54{
52 int ret; 55 int ret;
53 va_list ap; 56 va_list ap;
@@ -59,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
59 return ret; 62 return ret;
60} 63}
61 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
62/* Parse probepoint definition. */ 77/* Parse probepoint definition. */
63static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
64{ 79{
@@ -66,10 +81,26 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
66 char c, nc = 0; 81 char c, nc = 0;
67 /* 82 /*
68 * <Syntax> 83 * <Syntax>
69 * perf probe SRC:LN 84 * perf probe [EVENT=]SRC:LN
70 * perf probe FUNC[+OFFS|%return][@SRC] 85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
71 */ 88 */
72 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
73 ptr = strpbrk(arg, ":+@%"); 104 ptr = strpbrk(arg, ":+@%");
74 if (ptr) { 105 if (ptr) {
75 nc = *ptr; 106 nc = *ptr;
@@ -147,10 +178,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
147} 178}
148 179
149/* Parse perf-probe event definition */ 180/* Parse perf-probe event definition */
150int 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)
151{ 183{
152 char **argv; 184 char **argv;
153 int argc, i, need_dwarf = 0; 185 int argc, i;
186
187 *need_dwarf = false;
154 188
155 argv = argv_split(str, &argc); 189 argv = argv_split(str, &argc);
156 if (!argv) 190 if (!argv)
@@ -161,7 +195,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
161 /* Parse probe point */ 195 /* Parse probe point */
162 parse_perf_probe_probepoint(argv[0], pp); 196 parse_perf_probe_probepoint(argv[0], pp);
163 if (pp->file || pp->line) 197 if (pp->file || pp->line)
164 need_dwarf = 1; 198 *need_dwarf = true;
165 199
166 /* Copy arguments and ensure return probe has no C argument */ 200 /* Copy arguments and ensure return probe has no C argument */
167 pp->nr_args = argc - 1; 201 pp->nr_args = argc - 1;
@@ -174,17 +208,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
174 if (pp->retprobe) 208 if (pp->retprobe)
175 semantic_error("You can't specify local" 209 semantic_error("You can't specify local"
176 " variable for kretprobe"); 210 " variable for kretprobe");
177 need_dwarf = 1; 211 *need_dwarf = true;
178 } 212 }
179 } 213 }
180 214
181 argv_free(argv); 215 argv_free(argv);
182 return need_dwarf;
183} 216}
184 217
185/* Parse kprobe_events event into struct probe_point */ 218/* Parse kprobe_events event into struct probe_point */
186void parse_trace_kprobe_event(const char *str, char **group, char **event, 219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
187 struct probe_point *pp)
188{ 220{
189 char pr; 221 char pr;
190 char *p; 222 char *p;
@@ -200,18 +232,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
200 232
201 /* Scan event and group name. */ 233 /* Scan event and group name. */
202 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
203 &pr, (float *)(void *)group, (float *)(void *)event); 235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
204 if (ret != 3) 237 if (ret != 3)
205 semantic_error("Failed to parse event name: %s", argv[0]); 238 semantic_error("Failed to parse event name: %s", argv[0]);
206 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);
207
208 if (!pp)
209 goto end;
210 240
211 pp->retprobe = (pr == 'r'); 241 pp->retprobe = (pr == 'r');
212 242
213 /* Scan function name and offset */ 243 /* Scan function name and offset */
214 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);
215 if (ret == 1) 246 if (ret == 1)
216 pp->offset = 0; 247 pp->offset = 0;
217 248
@@ -230,15 +261,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
230 die("Failed to copy argument."); 261 die("Failed to copy argument.");
231 } 262 }
232 263
233end:
234 argv_free(argv); 264 argv_free(argv);
235} 265}
236 266
237int synthesize_perf_probe_event(struct probe_point *pp) 267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
238{ 269{
239 char *buf; 270 char *buf;
240 char offs[64] = "", line[64] = ""; 271 char offs[64] = "", line[64] = "";
241 int i, len, ret; 272 int ret;
242 273
243 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
244 if (!buf) 275 if (!buf)
@@ -258,11 +289,25 @@ int synthesize_perf_probe_event(struct probe_point *pp)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line); 290 offs, pp->retprobe ? "%return" : "", line);
260 else 291 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line); 292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
262 if (ret <= 0) 293 if (ret <= 0) {
263 goto error; 294error:
264 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;
265 309
310 buf = pp->probes[0];
266 for (i = 0; i < pp->nr_args; i++) { 311 for (i = 0; i < pp->nr_args; i++) {
267 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
268 pp->args[i]); 313 pp->args[i]);
@@ -275,6 +320,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
275 return pp->found; 320 return pp->found;
276error: 321error:
277 free(pp->probes[0]); 322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
278 324
279 return ret; 325 return ret;
280} 326}
@@ -304,6 +350,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
304 return pp->found; 350 return pp->found;
305error: 351error:
306 free(pp->probes[0]); 352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
307 354
308 return ret; 355 return ret;
309} 356}
@@ -363,6 +410,10 @@ static void clear_probe_point(struct probe_point *pp)
363{ 410{
364 int i; 411 int i;
365 412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
366 if (pp->function) 417 if (pp->function)
367 free(pp->function); 418 free(pp->function);
368 if (pp->file) 419 if (pp->file)
@@ -373,15 +424,33 @@ static void clear_probe_point(struct probe_point *pp)
373 free(pp->args); 424 free(pp->args);
374 for (i = 0; i < pp->found; i++) 425 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]); 426 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp)); 427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place,
432 struct probe_point *pp)
433{
434 int i, ret;
435 char buf[128];
436
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
440 printf(" %-40s (on %s", buf, place);
441
442 if (pp->nr_args > 0) {
443 printf(" with");
444 for (i = 0; i < pp->nr_args; i++)
445 printf(" %s", pp->args[i]);
446 }
447 printf(")\n");
377} 448}
378 449
379/* List up current perf-probe events */ 450/* List up current perf-probe events */
380void show_perf_probe_events(void) 451void show_perf_probe_events(void)
381{ 452{
382 unsigned int i;
383 int fd; 453 int fd;
384 char *group, *event;
385 struct probe_point pp; 454 struct probe_point pp;
386 struct strlist *rawlist; 455 struct strlist *rawlist;
387 struct str_node *ent; 456 struct str_node *ent;
@@ -390,13 +459,12 @@ void show_perf_probe_events(void)
390 rawlist = get_trace_kprobe_event_rawlist(fd); 459 rawlist = get_trace_kprobe_event_rawlist(fd);
391 close(fd); 460 close(fd);
392 461
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 462 strlist__for_each(ent, rawlist) {
394 ent = strlist__entry(rawlist, i); 463 parse_trace_kprobe_event(ent->s, &pp);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp); 464 /* Synthesize only event probe point */
396 synthesize_perf_probe_event(&pp); 465 synthesize_perf_probe_point(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]); 466 /* Show an event */
398 free(group); 467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
399 free(event);
400 clear_probe_point(&pp); 468 clear_probe_point(&pp);
401 } 469 }
402 470
@@ -404,21 +472,27 @@ void show_perf_probe_events(void)
404} 472}
405 473
406/* Get current perf-probe event names */ 474/* Get current perf-probe event names */
407static struct strlist *get_perf_event_names(int fd) 475static struct strlist *get_perf_event_names(int fd, bool include_group)
408{ 476{
409 unsigned int i; 477 char buf[128];
410 char *group, *event;
411 struct strlist *sl, *rawlist; 478 struct strlist *sl, *rawlist;
412 struct str_node *ent; 479 struct str_node *ent;
480 struct probe_point pp;
413 481
482 memset(&pp, 0, sizeof(pp));
414 rawlist = get_trace_kprobe_event_rawlist(fd); 483 rawlist = get_trace_kprobe_event_rawlist(fd);
415 484
416 sl = strlist__new(false, NULL); 485 sl = strlist__new(true, NULL);
417 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 486 strlist__for_each(ent, rawlist) {
418 ent = strlist__entry(rawlist, i); 487 parse_trace_kprobe_event(ent->s, &pp);
419 parse_trace_kprobe_event(ent->s, &group, &event, NULL); 488 if (include_group) {
420 strlist__add(sl, event); 489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
421 free(group); 490 pp.event) < 0)
491 die("Failed to copy group:event name.");
492 strlist__add(sl, buf);
493 } else
494 strlist__add(sl, pp.event);
495 clear_probe_point(&pp);
422 } 496 }
423 497
424 strlist__delete(rawlist); 498 strlist__delete(rawlist);
@@ -426,24 +500,36 @@ static struct strlist *get_perf_event_names(int fd)
426 return sl; 500 return sl;
427} 501}
428 502
429static int write_trace_kprobe_event(int fd, const char *buf) 503static void write_trace_kprobe_event(int fd, const char *buf)
430{ 504{
431 int ret; 505 int ret;
432 506
507 pr_debug("Writing event: %s\n", buf);
433 ret = write(fd, buf, strlen(buf)); 508 ret = write(fd, buf, strlen(buf));
434 if (ret <= 0) 509 if (ret <= 0)
435 die("Failed to create event."); 510 die("Failed to write event: %s", strerror(errno));
436 else
437 printf("Added new event: %s\n", buf);
438
439 return ret;
440} 511}
441 512
442static 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,
443 struct strlist *namelist) 514 struct strlist *namelist, bool allow_suffix)
444{ 515{
445 int i, ret; 516 int i, ret;
446 for (i = 0; i < MAX_EVENT_INDEX; i++) { 517
518 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0)
521 die("snprintf() failed: %s", strerror(-ret));
522 if (!strlist__has_entry(namelist, buf))
523 return;
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
531 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
447 ret = e_snprintf(buf, len, "%s_%d", base, i); 533 ret = e_snprintf(buf, len, "%s_%d", base, i);
448 if (ret < 0) 534 if (ret < 0)
449 die("snprintf() failed: %s", strerror(-ret)); 535 die("snprintf() failed: %s", strerror(-ret));
@@ -454,31 +540,138 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
454 die("Too many events are on the same function."); 540 die("Too many events are on the same function.");
455} 541}
456 542
457void 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)
458{ 545{
459 int i, j, fd; 546 int i, j, fd;
460 struct probe_point *pp; 547 struct probe_point *pp;
461 char buf[MAX_CMDLEN]; 548 char buf[MAX_CMDLEN];
462 char event[64]; 549 char event[64];
463 struct strlist *namelist; 550 struct strlist *namelist;
551 bool allow_suffix;
464 552
465 fd = open_kprobe_events(O_RDWR, O_APPEND); 553 fd = open_kprobe_events(O_RDWR, O_APPEND);
466 /* Get current event names */ 554 /* Get current event names */
467 namelist = get_perf_event_names(fd); 555 namelist = get_perf_event_names(fd, false);
468 556
469 for (j = 0; j < nr_probes; j++) { 557 for (j = 0; j < nr_probes; j++) {
470 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;
471 for (i = 0; i < pp->found; i++) { 566 for (i = 0; i < pp->found; i++) {
472 /* Get an unused new event name */ 567 /* Get an unused new event name */
473 get_new_event_name(event, 64, pp->function, namelist); 568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
474 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
475 pp->retprobe ? 'r' : 'p', 571 pp->retprobe ? 'r' : 'p',
476 PERFPROBE_GROUP, event, 572 pp->group, event,
477 pp->probes[i]); 573 pp->probes[i]);
478 write_trace_kprobe_event(fd, buf); 574 write_trace_kprobe_event(fd, buf);
575 printf("Added new event:\n");
576 /* Get the first parameter (probe-point) */
577 sscanf(pp->probes[i], "%s", buf);
578 show_perf_probe_event(event, buf, pp);
479 /* Add added event name to namelist */ 579 /* Add added event name to namelist */
480 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;
588 }
589 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593
594 strlist__delete(namelist);
595 close(fd);
596}
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
615static void del_trace_kprobe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist)
617{
618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
621
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
623 die("Failed to copy event.");
624
625 if (strpbrk(buf, "*?")) { /* Glob-exp */
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);
481 } 638 }
482 } 639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
642}
643
644void del_trace_kprobe_events(struct strlist *dellist)
645{
646 int fd;
647 const char *group, *event;
648 char *p, *str;
649 struct str_node *ent;
650 struct strlist *namelist;
651
652 fd = open_kprobe_events(O_RDWR, O_APPEND);
653 /* Get current event names */
654 namelist = get_perf_event_names(fd, true);
655
656 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s);
658 if (!str)
659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':');
662 if (p) {
663 group = str;
664 *p = '\0';
665 event = p + 1;
666 } else {
667 group = "*";
668 event = str;
669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist);
672 free(str);
673 }
674 strlist__delete(namelist);
483 close(fd); 675 close(fd);
484} 676}
677
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 0c6fe56fe38a..7f1d499118c0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,15 +1,19 @@
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);
16extern void del_trace_kprobe_events(struct strlist *dellist);
13extern void show_perf_probe_events(void); 17extern void show_perf_probe_events(void);
14 18
15/* Maximum index number of event-name postfix */ 19/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 293cdfc1b8ca..4b852c0d16a5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -106,7 +106,7 @@ static int strtailcmp(const char *s1, const char *s2)
106{ 106{
107 int i1 = strlen(s1); 107 int i1 = strlen(s1);
108 int i2 = strlen(s2); 108 int i2 = strlen(s2);
109 while (--i1 > 0 && --i2 > 0) { 109 while (--i1 >= 0 && --i2 >= 0) {
110 if (s1[i1] != s2[i2]) 110 if (s1[i1] != s2[i2])
111 return s1[i1] - s2[i2]; 111 return s1[i1] - s2[i2];
112 } 112 }
@@ -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 bdebca6697d2..a4086aaddb73 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 000000000000..ce3a6c8abe76
--- /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 000000000000..32eaa1bada06
--- /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 b490354d1b23..cb0f327de9e8 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 333e664ff45f..753f9ea99fb0 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 f24a8cc933d5..5352d7dccc61 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 bfecec265a1a..02ede58c54b4 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 7ad38171dc2b..6783a2043555 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 cb4659306d7b..3ba839007d2c 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 fffcb937cdcb..ab92763edb03 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;
@@ -938,8 +1058,9 @@ static bool __dsos__read_build_ids(struct list_head *head)
938 1058
939bool dsos__read_build_ids(void) 1059bool dsos__read_build_ids(void)
940{ 1060{
941 return __dsos__read_build_ids(&dsos__kernel) || 1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
942 __dsos__read_build_ids(&dsos__user); 1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
943} 1064}
944 1065
945/* 1066/*
@@ -1082,7 +1203,8 @@ char dso__symtab_origin(const struct dso *self)
1082 return origin[self->origin]; 1203 return origin[self->origin];
1083} 1204}
1084 1205
1085int 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)
1086{ 1208{
1087 int size = PATH_MAX; 1209 int size = PATH_MAX;
1088 char *name; 1210 char *name;
@@ -1093,7 +1215,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1093 dso__set_loaded(self, map->type); 1215 dso__set_loaded(self, map->type);
1094 1216
1095 if (self->kernel) 1217 if (self->kernel)
1096 return dso__load_kernel_sym(self, map, kthread, filter); 1218 return dso__load_kernel_sym(self, map, session, filter);
1097 1219
1098 name = malloc(size); 1220 name = malloc(size);
1099 if (!name) 1221 if (!name)
@@ -1179,11 +1301,12 @@ out:
1179 return ret; 1301 return ret;
1180} 1302}
1181 1303
1182static 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)
1183{ 1306{
1184 struct rb_node *nd; 1307 struct rb_node *nd;
1185 1308
1186 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)) {
1187 struct map *map = rb_entry(nd, struct map, rb_node); 1310 struct map *map = rb_entry(nd, struct map, rb_node);
1188 1311
1189 if (map->dso && strcmp(map->dso->name, name) == 0) 1312 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1193,7 +1316,7 @@ static struct map *thread__find_map_by_name(struct thread *self, char *name)
1193 return NULL; 1316 return NULL;
1194} 1317}
1195 1318
1196static int dsos__set_modules_path_dir(char *dirname) 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1197{ 1320{
1198 struct dirent *dent; 1321 struct dirent *dent;
1199 DIR *dir = opendir(dirname); 1322 DIR *dir = opendir(dirname);
@@ -1213,7 +1336,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1213 1336
1214 snprintf(path, sizeof(path), "%s/%s", 1337 snprintf(path, sizeof(path), "%s/%s",
1215 dirname, dent->d_name); 1338 dirname, dent->d_name);
1216 if (dsos__set_modules_path_dir(path) < 0) 1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1217 goto failure; 1340 goto failure;
1218 } else { 1341 } else {
1219 char *dot = strrchr(dent->d_name, '.'), 1342 char *dot = strrchr(dent->d_name, '.'),
@@ -1227,7 +1350,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1227 (int)(dot - dent->d_name), dent->d_name); 1350 (int)(dot - dent->d_name), dent->d_name);
1228 1351
1229 strxfrchar(dso_name, '-', '_'); 1352 strxfrchar(dso_name, '-', '_');
1230 map = thread__find_map_by_name(kthread, dso_name); 1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1231 if (map == NULL) 1354 if (map == NULL)
1232 continue; 1355 continue;
1233 1356
@@ -1247,7 +1370,7 @@ failure:
1247 return -1; 1370 return -1;
1248} 1371}
1249 1372
1250static int dsos__set_modules_path(void) 1373static int perf_session__set_modules_path(struct perf_session *self)
1251{ 1374{
1252 struct utsname uts; 1375 struct utsname uts;
1253 char modules_path[PATH_MAX]; 1376 char modules_path[PATH_MAX];
@@ -1258,7 +1381,7 @@ static int dsos__set_modules_path(void)
1258 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1259 uts.release); 1382 uts.release);
1260 1383
1261 return dsos__set_modules_path_dir(modules_path); 1384 return perf_session__set_modules_path_dir(self, modules_path);
1262} 1385}
1263 1386
1264/* 1387/*
@@ -1280,7 +1403,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1280 return self; 1403 return self;
1281} 1404}
1282 1405
1283static int thread__create_module_maps(struct thread *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
1284{ 1407{
1285 char *line = NULL; 1408 char *line = NULL;
1286 size_t n; 1409 size_t n;
@@ -1337,14 +1460,14 @@ static int thread__create_module_maps(struct thread *self)
1337 dso->has_build_id = true; 1460 dso->has_build_id = true;
1338 1461
1339 dso->origin = DSO__ORIG_KMODULE; 1462 dso->origin = DSO__ORIG_KMODULE;
1340 __thread__insert_map(self, map); 1463 map_groups__insert(&self->kmaps, map);
1341 dsos__add(&dsos__kernel, dso); 1464 dsos__add(&dsos__kernel, dso);
1342 } 1465 }
1343 1466
1344 free(line); 1467 free(line);
1345 fclose(file); 1468 fclose(file);
1346 1469
1347 return dsos__set_modules_path(); 1470 return perf_session__set_modules_path(self);
1348 1471
1349out_delete_line: 1472out_delete_line:
1350 free(line); 1473 free(line);
@@ -1352,7 +1475,8 @@ out_failure:
1352 return -1; 1475 return -1;
1353} 1476}
1354 1477
1355static 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,
1356 const char *vmlinux, symbol_filter_t filter) 1480 const char *vmlinux, symbol_filter_t filter)
1357{ 1481{
1358 int err = -1, fd; 1482 int err = -1, fd;
@@ -1386,14 +1510,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *t
1386 return -1; 1510 return -1;
1387 1511
1388 dso__set_loaded(self, map->type); 1512 dso__set_loaded(self, map->type);
1389 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);
1390 close(fd); 1514 close(fd);
1391 1515
1392 return err; 1516 return err;
1393} 1517}
1394 1518
1395static int dso__load_kernel_sym(struct dso *self, struct map *map, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
1396 struct thread *thread, symbol_filter_t filter) 1520 struct perf_session *session, symbol_filter_t filter)
1397{ 1521{
1398 int err; 1522 int err;
1399 bool is_kallsyms; 1523 bool is_kallsyms;
@@ -1403,7 +1527,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1403 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1404 vmlinux_path__nr_entries); 1528 vmlinux_path__nr_entries);
1405 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1406 err = dso__load_vmlinux(self, map, thread, 1530 err = dso__load_vmlinux(self, map, session,
1407 vmlinux_path[i], filter); 1531 vmlinux_path[i], filter);
1408 if (err > 0) { 1532 if (err > 0) {
1409 pr_debug("Using %s for symbols\n", 1533 pr_debug("Using %s for symbols\n",
@@ -1419,12 +1543,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1419 if (is_kallsyms) 1543 if (is_kallsyms)
1420 goto do_kallsyms; 1544 goto do_kallsyms;
1421 1545
1422 err = dso__load_vmlinux(self, map, thread, self->long_name, filter); 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1423 if (err <= 0) { 1547 if (err <= 0) {
1424 pr_info("The file %s cannot be used, " 1548 pr_info("The file %s cannot be used, "
1425 "trying to use /proc/kallsyms...", self->long_name); 1549 "trying to use /proc/kallsyms...", self->long_name);
1426do_kallsyms: 1550do_kallsyms:
1427 err = dso__load_kallsyms(self, map, thread, filter); 1551 err = dso__load_kallsyms(self, map, session, filter);
1428 if (err > 0 && !is_kallsyms) 1552 if (err > 0 && !is_kallsyms)
1429 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1430 } 1554 }
@@ -1507,42 +1631,59 @@ size_t dsos__fprintf_buildid(FILE *fp)
1507 __dsos__fprintf_buildid(&dsos__user, fp)); 1631 __dsos__fprintf_buildid(&dsos__user, fp));
1508} 1632}
1509 1633
1510static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1634static struct dso *dsos__create_kernel( const char *vmlinux)
1511{ 1635{
1512 struct map *kmap;
1513 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1514 1637
1515 if (kernel == NULL) 1638 if (kernel == NULL)
1516 return -1; 1639 return NULL;
1517
1518 kmap = map__new2(0, kernel, MAP__FUNCTION);
1519 if (kmap == NULL)
1520 goto out_delete_kernel_dso;
1521 1640
1522 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1523 kernel->short_name = "[kernel]"; 1641 kernel->short_name = "[kernel]";
1524 kernel->kernel = 1; 1642 kernel->kernel = 1;
1525 1643
1526 vdso = dso__new("[vdso]"); 1644 vdso = dso__new("[vdso]");
1527 if (vdso == NULL) 1645 if (vdso == NULL)
1528 goto out_delete_kernel_map; 1646 goto out_delete_kernel_dso;
1529 dso__set_loaded(vdso, MAP__FUNCTION); 1647 dso__set_loaded(vdso, MAP__FUNCTION);
1530 1648
1531 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1532 sizeof(kernel->build_id)) == 0) 1650 sizeof(kernel->build_id)) == 0)
1533 kernel->has_build_id = true; 1651 kernel->has_build_id = true;
1534 1652
1535 __thread__insert_map(self, kmap);
1536 dsos__add(&dsos__kernel, kernel); 1653 dsos__add(&dsos__kernel, kernel);
1537 dsos__add(&dsos__user, vdso); 1654 dsos__add(&dsos__user, vdso);
1538 1655
1539 return 0; 1656 return kernel;
1540 1657
1541out_delete_kernel_map:
1542 map__delete(kmap);
1543out_delete_kernel_dso: 1658out_delete_kernel_dso:
1544 dso__delete(kernel); 1659 dso__delete(kernel);
1545 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;
1546} 1687}
1547 1688
1548static void vmlinux_path__exit(void) 1689static void vmlinux_path__exit(void)
@@ -1600,29 +1741,69 @@ out_fail:
1600 return -1; 1741 return -1;
1601} 1742}
1602 1743
1603int symbol__init(struct symbol_conf *conf) 1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1604{ 1746{
1605 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1747 if (list_str == NULL)
1748 return 0;
1606 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{
1607 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1608 symbol__priv_size = pconf->priv_size; 1761 if (symbol_conf.sort_by_name)
1609 thread__init(kthread, 0); 1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1763 sizeof(struct symbol));
1610 1764
1611 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1612 return -1; 1766 return -1;
1613 1767
1614 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { 1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1615 vmlinux_path__exit(); 1769 pr_err("'.' is the only non valid --field-separator argument\n");
1616 return -1; 1770 return -1;
1617 } 1771 }
1618 1772
1619 kthread->use_modules = pconf->use_modules; 1773 if (setup_list(&symbol_conf.dso_list,
1620 if (pconf->use_modules && thread__create_module_maps(kthread) < 0) 1774 symbol_conf.dso_list_str, "dso") < 0)
1621 pr_debug("Failed to load list of modules in use, " 1775 return -1;
1622 "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);
1623 /* 1804 /*
1624 * 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:
1625 */ 1806 */
1626 thread__fixup_maps_end(kthread); 1807 map_groups__fixup_end(&self->kmaps);
1627 return 0; 1808 return 0;
1628} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 17003efa0b39..8aded2356f79 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 603f5610861b..4a08dcf50b68 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 686d6e914d9e..c206f72c8881 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-parse.c b/tools/perf/util/trace-event-parse.c
index 0302405aa2ca..c5c32be040bf 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -177,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
177 func_count++; 177 func_count++;
178 } 178 }
179 179
180 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181 181
182 i = 0; 182 i = 0;
183 while (list) { 183 while (list) {
@@ -1477,7 +1477,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1477 goto out_free; 1477 goto out_free;
1478 1478
1479 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1480 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1481 1481
1482 value = arg_eval(arg); 1482 value = arg_eval(arg);
1483 field->value = strdup(value); 1483 field->value = strdup(value);
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index 51e833fd58c3..6d6d76b8a21e 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -32,9 +32,6 @@
32 32
33void xs_init(pTHX); 33void xs_init(pTHX);
34 34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37
38void xs_init(pTHX) 35void xs_init(pTHX)
39{ 36{
40 const char *file = __FILE__; 37 const char *file = __FILE__;
@@ -270,7 +267,7 @@ int common_lock_depth(struct scripting_context *context)
270} 267}
271 268
272static void perl_process_event(int cpu, void *data, 269static void perl_process_event(int cpu, void *data,
273 int size __attribute((unused)), 270 int size __unused,
274 unsigned long long nsecs, char *comm) 271 unsigned long long nsecs, char *comm)
275{ 272{
276 struct format_field *field; 273 struct format_field *field;
@@ -362,28 +359,46 @@ static void run_start_sub(void)
362/* 359/*
363 * Start trace script 360 * Start trace script
364 */ 361 */
365static int perl_start_script(const char *script) 362static int perl_start_script(const char *script, int argc, const char **argv)
366{ 363{
367 const char *command_line[2] = { "", NULL }; 364 const char **command_line;
365 int i, err = 0;
368 366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
369 command_line[1] = script; 369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
370 372
371 my_perl = perl_alloc(); 373 my_perl = perl_alloc();
372 perl_construct(my_perl); 374 perl_construct(my_perl);
373 375
374 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
375 (char **)NULL)) 377 (char **)NULL)) {
376 return -1; 378 err = -1;
379 goto error;
380 }
377 381
378 perl_run(my_perl); 382 if (perl_run(my_perl)) {
379 if (SvTRUE(ERRSV)) 383 err = -1;
380 return -1; 384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
381 391
382 run_start_sub(); 392 run_start_sub();
383 393
394 free(command_line);
384 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);
385
386 return 0; 396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
387} 402}
388 403
389/* 404/*
@@ -573,26 +588,74 @@ struct scripting_ops perl_scripting_ops = {
573 .generate_script = perl_generate_script, 588 .generate_script = perl_generate_script,
574}; 589};
575 590
576#ifdef NO_LIBPERL 591static void print_unsupported_msg(void)
577void setup_perl_scripting(void)
578{ 592{
579 fprintf(stderr, "Perl scripting not supported." 593 fprintf(stderr, "Perl scripting not supported."
580 " Install libperl and rebuild perf to enable it. e.g. " 594 " Install libperl and rebuild perf to enable it.\n"
581 "apt-get install libperl-dev (ubuntu), yum install " 595 "For example:\n # apt-get install libperl-dev (ubuntu)"
582 "perl-ExtUtils-Embed (Fedora), etc.\n"); 596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
583} 598}
584#else 599
585void setup_perl_scripting(void) 600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
586{ 638{
587 int err; 639 int err;
588 err = script_spec_register("Perl", &perl_scripting_ops); 640 err = script_spec_register("Perl", scripting_ops);
589 if (err) 641 if (err)
590 die("error registering Perl script extension"); 642 die("error registering Perl script extension");
591 643
592 err = script_spec_register("pl", &perl_scripting_ops); 644 err = script_spec_register("pl", scripting_ops);
593 if (err) 645 if (err)
594 die("error registering pl script extension"); 646 die("error registering pl script extension");
595 647
596 scripting_context = malloc(sizeof(struct scripting_context)); 648 scripting_context = malloc(sizeof(struct scripting_context));
597} 649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
598#endif 661#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
index 8fe0d866fe1a..e88fb26137bb 100644
--- a/tools/perf/util/trace-event-perl.h
+++ b/tools/perf/util/trace-event-perl.h
@@ -34,9 +34,13 @@ typedef int INTERP;
34#define dXSUB_SYS 34#define dXSUB_SYS
35#define pTHX_ 35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {} 36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
37#else 39#else
38#include <EXTERN.h> 40#include <EXTERN.h>
39#include <perl.h> 41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
40typedef PerlInterpreter * INTERP; 44typedef PerlInterpreter * INTERP;
41#endif 45#endif
42 46
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 342dfdd43f87..1744422cafcb 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void)
145 if (!size) 145 if (!size)
146 return; 146 return;
147 147
148 buf = malloc_or_die(size); 148 buf = malloc_or_die(size + 1);
149 read_or_die(buf, size); 149 read_or_die(buf, size);
150 buf[size] = '\0';
150 151
151 parse_proc_kallsyms(buf, size); 152 parse_proc_kallsyms(buf, size);
152 153
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81698d5e6503..6ad405620c9b 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);