aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore3
-rw-r--r--tools/perf/Documentation/perf-archive.txt22
-rw-r--r--tools/perf/Documentation/perf-bench.txt120
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt34
-rw-r--r--tools/perf/Documentation/perf-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-kmem.txt47
-rw-r--r--tools/perf/Documentation/perf-lock.txt29
-rw-r--r--tools/perf/Documentation/perf-probe.txt129
-rw-r--r--tools/perf/Documentation/perf-record.txt16
-rw-r--r--tools/perf/Documentation/perf-report.txt12
-rw-r--r--tools/perf/Documentation/perf-timechart.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt219
-rw-r--r--tools/perf/Documentation/perf-trace-python.txt625
-rw-r--r--tools/perf/Documentation/perf-trace.txt49
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/Makefile222
-rw-r--r--tools/perf/bench/bench.h17
-rw-r--r--tools/perf/bench/mem-memcpy.c193
-rw-r--r--tools/perf/bench/sched-messaging.c338
-rw-r--r--tools/perf/bench/sched-pipe.c127
-rw-r--r--tools/perf/builtin-annotate.c1012
-rw-r--r--tools/perf/builtin-bench.c245
-rw-r--r--tools/perf/builtin-buildid-cache.c133
-rw-r--r--tools/perf/builtin-buildid-list.c60
-rw-r--r--tools/perf/builtin-diff.c239
-rw-r--r--tools/perf/builtin-help.c21
-rw-r--r--tools/perf/builtin-kmem.c774
-rw-r--r--tools/perf/builtin-lock.c822
-rw-r--r--tools/perf/builtin-probe.c361
-rw-r--r--tools/perf/builtin-record.c469
-rw-r--r--tools/perf/builtin-report.c1614
-rw-r--r--tools/perf/builtin-sched.c565
-rw-r--r--tools/perf/builtin-stat.c138
-rw-r--r--tools/perf/builtin-timechart.c356
-rw-r--r--tools/perf/builtin-top.c597
-rw-r--r--tools/perf/builtin-trace.c713
-rw-r--r--tools/perf/builtin.h7
-rw-r--r--tools/perf/command-list.txt8
-rw-r--r--tools/perf/design.txt18
-rw-r--r--tools/perf/perf-archive.sh33
-rw-r--r--tools/perf/perf.c112
-rw-r--r--tools/perf/perf.h22
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c135
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs42
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL17
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/README59
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm55
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm192
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm88
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/typemap1
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report4
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report7
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report6
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record6
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report6
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report7
-rw-r--r--tools/perf/scripts/perl/check-perf-trace.pl106
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl38
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl106
-rw-r--r--tools/perf/scripts/perl/rw-by-pid.pl170
-rw-r--r--tools/perf/scripts/perl/wakeup-latency.pl103
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c88
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py91
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py25
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report4
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report4
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report4
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py83
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py68
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py64
-rw-r--r--tools/perf/scripts/python/syscall-counts.py58
-rw-r--r--tools/perf/util/build-id.c39
-rw-r--r--tools/perf/util/build-id.h8
-rw-r--r--tools/perf/util/cache.h11
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/ctype.c8
-rw-r--r--tools/perf/util/debug.c5
-rw-r--r--tools/perf/util/debug.h9
-rw-r--r--tools/perf/util/debugfs.c240
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c612
-rw-r--r--tools/perf/util/event.h82
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c640
-rw-r--r--tools/perf/util/header.h83
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c662
-rw-r--r--tools/perf/util/hist.h27
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/bug.h22
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/bitops.h29
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h77
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/include/linux/types.h9
-rw-r--r--tools/perf/util/levenshtein.h6
-rw-r--r--tools/perf/util/map.c162
-rw-r--r--tools/perf/util/map.h94
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c214
-rw-r--r--tools/perf/util/parse-events.h8
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/probe-event.c802
-rw-r--r--tools/perf/util/probe-event.h24
-rw-r--r--tools/perf/util/probe-finder.c833
-rw-r--r--tools/perf/util/probe-finder.h93
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c568
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c573
-rw-r--r--tools/perf/util/session.c573
-rw-r--r--tools/perf/util/session.h88
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c316
-rw-r--r--tools/perf/util/sort.h107
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c305
-rw-r--r--tools/perf/util/string.h13
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h47
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c1553
-rw-r--r--tools/perf/util/symbol.h145
-rw-r--r--tools/perf/util/thread.c288
-rw-r--r--tools/perf/util/thread.h78
-rw-r--r--tools/perf/util/trace-event-info.c90
-rw-r--r--tools/perf/util/trace-event-parse.c601
-rw-r--r--tools/perf/util/trace-event-read.c32
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h72
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h34
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/values.h6
-rw-r--r--tools/perf/util/wrapper.c61
158 files changed, 18566 insertions, 5197 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 0854f110bf7f..e1d60d780784 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -12,6 +12,9 @@ perf*.1
12perf*.xml 12perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data
16perf.data.old
17perf-archive
15tags 18tags
16TAGS 19TAGS
17cscope* 20cscope*
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
new file mode 100644
index 000000000000..fae174dc7d01
--- /dev/null
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -0,0 +1,22 @@
1perf-archive(1)
2===============
3
4NAME
5----
6perf-archive - Create archive with object files with build-ids found in perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf archive' [file]
12
13DESCRIPTION
14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible
17on another machine.
18
19
20SEE ALSO
21--------
22linkperf:perf-record[1], linkperf:perf-buildid-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
new file mode 100644
index 000000000000..ae525ac5a2ce
--- /dev/null
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -0,0 +1,120 @@
1perf-bench(1)
2============
3
4NAME
5----
6perf-bench - General framework for benchmark suites
7
8SYNOPSIS
9--------
10[verse]
11'perf bench' [<common options>] <subsystem> <suite> [<options>]
12
13DESCRIPTION
14-----------
15This 'perf bench' command is general framework for benchmark suites.
16
17COMMON OPTIONS
18--------------
19-f::
20--format=::
21Specify format style.
22Current available format styles are,
23
24'default'::
25Default style. This is mainly for human reading.
26---------------------
27% perf bench sched pipe # with no style specify
28(executing 1000000 pipe operations between two tasks)
29 Total time:5.855 sec
30 5.855061 usecs/op
31 170792 ops/sec
32---------------------
33
34'simple'::
35This simple style is friendly for automated
36processing by scripts.
37---------------------
38% perf bench --format=simple sched pipe # specified simple
395.988
40---------------------
41
42SUBSYSTEM
43---------
44
45'sched'::
46 Scheduler and IPC mechanisms.
47
48SUITES FOR 'sched'
49~~~~~~~~~~~~~~~~~~
50*messaging*::
51Suite for evaluating performance of scheduler and IPC mechanisms.
52Based on hackbench by Rusty Russell.
53
54Options of *pipe*
55^^^^^^^^^^^^^^^^^
56-p::
57--pipe::
58Use pipe() instead of socketpair()
59
60-t::
61--thread::
62Be multi thread instead of multi process
63
64-g::
65--group=::
66Specify number of groups
67
68-l::
69--loop=::
70Specify number of loops
71
72Example of *messaging*
73^^^^^^^^^^^^^^^^^^^^^^
74
75---------------------
76% perf bench sched messaging # run with default
77options (20 sender and receiver processes per group)
78(10 groups == 400 processes run)
79
80 Total time:0.308 sec
81
82% perf bench sched messaging -t -g 20 # be multi-thread,with 20 groups
83(20 sender and receiver threads per group)
84(20 groups == 800 threads run)
85
86 Total time:0.582 sec
87---------------------
88
89*pipe*::
90Suite for pipe() system call.
91Based on pipe-test-1m.c by Ingo Molnar.
92
93Options of *pipe*
94^^^^^^^^^^^^^^^^^
95-l::
96--loop=::
97Specify number of loops.
98
99Example of *pipe*
100^^^^^^^^^^^^^^^^^
101
102---------------------
103% perf bench sched pipe
104(executing 1000000 pipe operations between two tasks)
105
106 Total time:8.091 sec
107 8.091833 usecs/op
108 123581 ops/sec
109
110% perf bench sched pipe -l 1000 # loop 1000
111(executing 1000 pipe operations between two tasks)
112
113 Total time:0.016 sec
114 16.948000 usecs/op
115 59004 ops/sec
116---------------------
117
118SEE ALSO
119--------
120linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
new file mode 100644
index 000000000000..88bc3b519746
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -0,0 +1,33 @@
1perf-buildid-cache(1)
2=====================
3
4NAME
5----
6perf-buildid-cache - Manage build-id cache.
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command manages the build-id cache. It can add and remove files to the
16cache. In the future it should as well purge older entries, set upper limits
17for the space used by the cache, etc.
18
19OPTIONS
20-------
21-a::
22--add=::
23 Add specified file to the cache.
24-r::
25--remove=::
26 Remove specified file to the cache.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
new file mode 100644
index 000000000000..01b642c0bf8f
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -0,0 +1,34 @@
1perf-buildid-list(1)
2====================
3
4NAME
5----
6perf-buildid-list - List the buildids in a perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by
17perf report.
18
19OPTIONS
20-------
21-i::
22--input=::
23 Input file name. (default: perf.data)
24-f::
25--force::
26 Don't do ownership validation.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-top[1],
34linkperf:perf-report[1]
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
new file mode 100644
index 000000000000..eac4d852e7cd
--- /dev/null
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -0,0 +1,47 @@
1perf-kmem(1)
2==============
3
4NAME
5----
6perf-kmem - Tool to trace/measure kernel memory(slab) properties
7
8SYNOPSIS
9--------
10[verse]
11'perf kmem' {record|stat} [<options>]
12
13DESCRIPTION
14-----------
15There are two variants of perf kmem:
16
17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload.
19
20 'perf kmem stat' to report kernel memory statistics.
21
22OPTIONS
23-------
24-i <file>::
25--input=<file>::
26 Select the input file (default: perf.data)
27
28--caller::
29 Show per-callsite statistics
30
31--alloc::
32 Show per-allocation statistics
33
34-s <key[,key2...]>::
35--sort=<key[,key2...]>::
36 Sort the output (default: frag,hit,bytes)
37
38-l <num>::
39--line=<num>::
40 Print n lines only
41
42--raw-ip::
43 Print raw ip instead of symbol
44
45SEE ALSO
46--------
47linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
new file mode 100644
index 000000000000..b317102138c8
--- /dev/null
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -0,0 +1,29 @@
1perf-lock(1)
2============
3
4NAME
5----
6perf-lock - Analyze lock events
7
8SYNOPSIS
9--------
10[verse]
11'perf lock' {record|report|trace}
12
13DESCRIPTION
14-----------
15You can analyze various lock behaviours
16and statistics with this 'perf lock' command.
17
18 'perf lock record <command>' records lock events
19 between start and end <command>. And this command
20 produces the file "perf.data" which contains tracing
21 results of lock events.
22
23 'perf lock trace' shows raw lock events.
24
25 'perf lock report' reports statistical data.
26
27SEE ALSO
28--------
29linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644
index 000000000000..34202b1be0bb
--- /dev/null
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -0,0 +1,129 @@
1perf-probe(1)
2=============
3
4NAME
5----
6perf-probe - Define new dynamic tracepoints
7
8SYNOPSIS
9--------
10[verse]
11'perf probe' [options] --add='PROBE' [...]
12or
13'perf probe' [options] PROBE
14or
15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or
17'perf probe' --list
18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20
21DESCRIPTION
22-----------
23This command defines dynamic tracepoint events, by symbol and registers
24without debuginfo, or by C expressions (C line numbers, C function names,
25and C local variables) with debuginfo.
26
27
28OPTIONS
29-------
30-k::
31--vmlinux=PATH::
32 Specify vmlinux path which has debuginfo (Dwarf binary).
33
34-v::
35--verbose::
36 Be more verbose (show parsed arguments, etc).
37
38-a::
39--add=::
40 Define a probe event (see PROBE SYNTAX for detail).
41
42-d::
43--del=::
44 Delete probe events. This accepts glob wildcards('*', '?') and character
45 classes(e.g. [a-z], [!A-Z]).
46
47-l::
48--list::
49 List up current probe events.
50
51-L::
52--line=::
53 Show source code lines which can be probed. This needs an argument
54 which specifies a range of the source code. (see LINE SYNTAX for detail)
55
56-f::
57--force::
58 Forcibly add events with existing name.
59
60PROBE SYNTAX
61------------
62Probe points are defined by following syntax.
63
64 1) Define event based on function name
65 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
66
67 2) Define event based on source file with line number
68 [EVENT=]SRC:ALN [ARG ...]
69
70 3) Define event based on source file with lazy pattern
71 [EVENT=]SRC;PTN [ARG ...]
72
73
74'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'.
75'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. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function.
76It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
77'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).
78
79LINE SYNTAX
80-----------
81Line range is descripted by following syntax.
82
83 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]"
84
85FUNC specifies the function name of showing lines. 'RLN' is the start line
86number from function entry line, and 'RLN2' is the end line number. As same as
87probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
88and 'ALN2' is end line number in the file. It is also possible to specify how
89many lines to show by using 'NUM'.
90So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
91
92LAZY MATCHING
93-------------
94 The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]).
95
96e.g.
97 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
98
99This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
100
101
102EXAMPLES
103--------
104Display which lines in schedule() can be probed:
105
106 ./perf probe --line schedule
107
108Add a probe on schedule() function 12th line with recording cpu local variable:
109
110 ./perf probe schedule:12 cpu
111 or
112 ./perf probe --add='schedule:12 cpu'
113
114 this will add one or more probes which has the name start with "schedule".
115
116 Add probes on lines in schedule() function which calls update_rq_clock().
117
118 ./perf probe 'schedule;update_rq_clock*'
119 or
120 ./perf probe --add='schedule;update_rq_clock*'
121
122Delete all probes on schedule().
123
124 ./perf probe --del='schedule*'
125
126
127SEE ALSO
128--------
129linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 0ff23de9e453..fc46c0b40f6e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -26,11 +26,19 @@ OPTIONS
26 26
27-e:: 27-e::
28--event=:: 28--event=::
29 Select the PMU event. Selection can be a symbolic event name 29 Select the PMU event. Selection can be:
30 (use 'perf list' to list all events) or a raw PMU
31 event (eventsel+umask) in the form of rNNN where NNN is a
32 hexadecimal event descriptor.
33 30
31 - a symbolic event name (use 'perf list' to list all events)
32
33 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
34 hexadecimal event descriptor.
35
36 - a hardware breakpoint event in the form of '\mem:addr[:access]'
37 where addr is the address in memory you want to break in.
38 Access is the memory access type (read, write, execute) it can
39 be passed as follows: '\mem:addr[:[r][w][x]]'.
40 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'.
34-a:: 42-a::
35 System-wide collection. 43 System-wide collection.
36 44
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 59f0b846cd71..abfabe9147a4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -24,11 +24,11 @@ OPTIONS
24--dsos=:: 24--dsos=::
25 Only consider symbols in these dsos. CSV that understands 25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries. 26 file://filename entries.
27-n 27-n::
28--show-nr-samples 28--show-nr-samples::
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T 30-T::
31--threads 31--threads::
32 Show per-thread event counters 32 Show per-thread event counters
33-C:: 33-C::
34--comms=:: 34--comms=::
@@ -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-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index a7910099d6fd..4b1788355eca 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -31,9 +31,12 @@ OPTIONS
31-w:: 31-w::
32--width=:: 32--width=::
33 Select the width of the SVG file (default: 1000) 33 Select the width of the SVG file (default: 1000)
34-p:: 34-P::
35--power-only:: 35--power-only::
36 Only output the CPU power section of the diagram 36 Only output the CPU power section of the diagram
37-p::
38--process::
39 Select the processes to display, by name or PID
37 40
38 41
39SEE ALSO 42SEE ALSO
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a7d558dc309..785b9fc32a46 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -74,7 +74,7 @@ OPTIONS
74 74
75-s <symbol>:: 75-s <symbol>::
76--sym-annotate=<symbol>:: 76--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option. 77 Annotate this symbol.
78 78
79-v:: 79-v::
80--verbose:: 80--verbose::
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
new file mode 100644
index 000000000000..d729cee8d987
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace-perl.txt
@@ -0,0 +1,219 @@
1perf-trace-perl(1)
2==================
3
4NAME
5----
6perf-trace-perl - Process trace data with a Perl script
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-s [Perl]:script[.pl] ]
12
13DESCRIPTION
14-----------
15
16This perf trace option is used to process perf trace data using perf's
17built-in Perl interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given
19Perl script, if any.
20
21STARTER SCRIPTS
22---------------
23
24You can avoid reading the rest of this document by running 'perf trace
25-g perl' in the same directory as an existing perf.data trace file.
26That will generate a starter script containing a handler for each of
27the event types in the trace file; it simply prints every available
28field for each event in the trace file.
29
30You can also look at the existing scripts in
31~/libexec/perf-core/scripts/perl for typical examples showing how to
32do basic things like aggregate event data, print results, etc. Also,
33the check-perf-trace.pl script, while not interesting for its results,
34attempts to exercise all of the main scripting features.
35
36EVENT HANDLERS
37--------------
38
39When perf trace is invoked using a trace script, a user-defined
40'handler function' is called for each event in the trace. If there's
41no handler function defined for a given event type, the event is
42ignored (or passed to a 'trace_handled' function, see below) and the
43next event is processed.
44
45Most of the event's field values are passed as arguments to the
46handler function; some of the less common ones aren't - those are
47available as calls back into the perf executable (see below).
48
49As an example, the following perf record command can be used to record
50all sched_wakeup events in the system:
51
52 # perf record -c 1 -f -a -M -R -e sched:sched_wakeup
53
54Traces meant to be processed using a script should be recorded with
55the above options: -c 1 says to sample every event, -a to enable
56system-wide collection, -M to multiplex the output, and -R to collect
57raw samples.
58
59The format file for the sched_wakep event defines the following fields
60(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
61
62----
63 format:
64 field:unsigned short common_type;
65 field:unsigned char common_flags;
66 field:unsigned char common_preempt_count;
67 field:int common_pid;
68 field:int common_lock_depth;
69
70 field:char comm[TASK_COMM_LEN];
71 field:pid_t pid;
72 field:int prio;
73 field:int success;
74 field:int target_cpu;
75----
76
77The handler function for this event would be defined as:
78
79----
80sub sched::sched_wakeup
81{
82 my ($event_name, $context, $common_cpu, $common_secs,
83 $common_nsecs, $common_pid, $common_comm,
84 $comm, $pid, $prio, $success, $target_cpu) = @_;
85}
86----
87
88The handler function takes the form subsystem::event_name.
89
90The $common_* arguments in the handler's argument list are the set of
91arguments passed to all event handlers; some of the fields correspond
92to the common_* fields in the format file, but some are synthesized,
93and some of the common_* fields aren't common enough to to be passed
94to every event as arguments but are available as library functions.
95
96Here's a brief description of each of the invariant event args:
97
98 $event_name the name of the event as text
99 $context an opaque 'cookie' used in calls back into perf
100 $common_cpu the cpu the event occurred on
101 $common_secs the secs portion of the event timestamp
102 $common_nsecs the nsecs portion of the event timestamp
103 $common_pid the pid of the current task
104 $common_comm the name of the current process
105
106All of the remaining fields in the event's format file have
107counterparts as handler function arguments of the same name, as can be
108seen in the example above.
109
110The above provides the basics needed to directly access every field of
111every event in a trace, which covers 90% of what you need to know to
112write a useful trace script. The sections below cover the rest.
113
114SCRIPT LAYOUT
115-------------
116
117Every perf trace Perl script should start by setting up a Perl module
118search path and 'use'ing a few support modules (see module
119descriptions below):
120
121----
122 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
123 use lib "./Perf-Trace-Util/lib";
124 use Perf::Trace::Core;
125 use Perf::Trace::Context;
126 use Perf::Trace::Util;
127----
128
129The rest of the script can contain handler functions and support
130functions in any order.
131
132Aside from the event handler functions discussed above, every script
133can implement a set of optional functions:
134
135*trace_begin*, if defined, is called before any event is processed and
136gives scripts a chance to do setup tasks:
137
138----
139 sub trace_begin
140 {
141 }
142----
143
144*trace_end*, if defined, is called after all events have been
145 processed and gives scripts a chance to do end-of-script tasks, such
146 as display results:
147
148----
149sub trace_end
150{
151}
152----
153
154*trace_unhandled*, if defined, is called after for any event that
155 doesn't have a handler explicitly defined for it. The standard set
156 of common arguments are passed into it:
157
158----
159sub trace_unhandled
160{
161 my ($event_name, $context, $common_cpu, $common_secs,
162 $common_nsecs, $common_pid, $common_comm) = @_;
163}
164----
165
166The remaining sections provide descriptions of each of the available
167built-in perf trace Perl modules and their associated functions.
168
169AVAILABLE MODULES AND FUNCTIONS
170-------------------------------
171
172The following sections describe the functions and variables available
173via the various Perf::Trace::* Perl modules. To use the functions and
174variables from the given module, add the corresponding 'use
175Perf::Trace::XXX' line to your perf trace script.
176
177Perf::Trace::Core Module
178~~~~~~~~~~~~~~~~~~~~~~~~
179
180These functions provide some essential functions to user scripts.
181
182The *flag_str* and *symbol_str* functions provide human-readable
183strings for flag and symbolic fields. These correspond to the strings
184and values parsed from the 'print fmt' fields of the event format
185files:
186
187 flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name
188 symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name
189
190Perf::Trace::Context Module
191~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
193Some of the 'common' fields in the event format file aren't all that
194common, but need to be made accessible to user scripts nonetheless.
195
196Perf::Trace::Context defines a set of functions that can be used to
197access this data in the context of the current event. Each of these
198functions expects a $context variable, which is the same as the
199$context variable passed into every event handler as the second
200argument.
201
202 common_pc($context) - returns common_preempt count for the current event
203 common_flags($context) - returns common_flags for the current event
204 common_lock_depth($context) - returns common_lock_depth for the current event
205
206Perf::Trace::Util Module
207~~~~~~~~~~~~~~~~~~~~~~~~
208
209Various utility functions for use with perf trace:
210
211 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
212 nsecs_secs($nsecs) - returns whole secs portion given nsecs
213 nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
214 nsecs_str($nsecs) - returns printable string in the form secs.nsecs
215 avg($total, $n) - returns average given a sum and a total number of values
216
217SEE ALSO
218--------
219linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-trace-python.txt
new file mode 100644
index 000000000000..a241aca77184
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace-python.txt
@@ -0,0 +1,625 @@
1perf-trace-python(1)
2==================
3
4NAME
5----
6perf-trace-python - Process trace data with a Python script
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-s [Python]:script[.py] ]
12
13DESCRIPTION
14-----------
15
16This perf trace option is used to process perf trace data using perf's
17built-in Python interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given
19Python script, if any.
20
21A QUICK EXAMPLE
22---------------
23
24This section shows the process, start to finish, of creating a working
25Python script that aggregates and extracts useful information from a
26raw perf trace stream. You can avoid reading the rest of this
27document if an example is enough for you; the rest of the document
28provides more details on each step and lists the library functions
29available to script writers.
30
31This example actually details the steps that were used to create the
32'syscall-counts' script you see when you list the available perf trace
33scripts via 'perf trace -l'. As such, this script also shows how to
34integrate your script into the list of general-purpose 'perf trace'
35scripts listed by that command.
36
37The syscall-counts script is a simple script, but demonstrates all the
38basic ideas necessary to create a useful script. Here's an example
39of its output (syscall names are not yet supported, they will appear
40as numbers):
41
42----
43syscall events:
44
45event count
46---------------------------------------- -----------
47sys_write 455067
48sys_getdents 4072
49sys_close 3037
50sys_swapoff 1769
51sys_read 923
52sys_sched_setparam 826
53sys_open 331
54sys_newfstat 326
55sys_mmap 217
56sys_munmap 216
57sys_futex 141
58sys_select 102
59sys_poll 84
60sys_setitimer 12
61sys_writev 8
6215 8
63sys_lseek 7
64sys_rt_sigprocmask 6
65sys_wait4 3
66sys_ioctl 3
67sys_set_robust_list 1
68sys_exit 1
6956 1
70sys_access 1
71----
72
73Basically our task is to keep a per-syscall tally that gets updated
74every time a system call occurs in the system. Our script will do
75that, but first we need to record the data that will be processed by
76that script. Theoretically, there are a couple of ways we could do
77that:
78
79- we could enable every event under the tracing/events/syscalls
80 directory, but this is over 600 syscalls, well beyond the number
81 allowable by perf. These individual syscall events will however be
82 useful if we want to later use the guidance we get from the
83 general-purpose scripts to drill down and get more detail about
84 individual syscalls of interest.
85
86- we can enable the sys_enter and/or sys_exit syscalls found under
87 tracing/events/raw_syscalls. These are called for all syscalls; the
88 'id' field can be used to distinguish between individual syscall
89 numbers.
90
91For this script, we only need to know that a syscall was entered; we
92don't care how it exited, so we'll use 'perf record' to record only
93the sys_enter events:
94
95----
96# perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
97
98^C[ perf record: Woken up 1 times to write data ]
99[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
100----
101
102The options basically say to collect data for every syscall event
103system-wide and multiplex the per-cpu output into a single stream.
104That single stream will be recorded in a file in the current directory
105called perf.data.
106
107Once we have a perf.data file containing our data, we can use the -g
108'perf trace' option to generate a Python script that will contain a
109callback handler for each event type found in the perf.data trace
110stream (for more details, see the STARTER SCRIPTS section).
111
112----
113# perf trace -g python
114generated Python script: perf-trace.py
115
116The output file created also in the current directory is named
117perf-trace.py. Here's the file in its entirety:
118
119# perf trace event handlers, generated by perf trace -g python
120# Licensed under the terms of the GNU GPL License version 2
121
122# The common_* event handler fields are the most useful fields common to
123# all events. They don't necessarily correspond to the 'common_*' fields
124# in the format files. Those fields not available as handler params can
125# be retrieved using Python functions of the form common_*(context).
126# See the perf-trace-python Documentation for the list of available functions.
127
128import os
129import sys
130
131sys.path.append(os.environ['PERF_EXEC_PATH'] + \
132 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
133
134from perf_trace_context import *
135from Core import *
136
137def trace_begin():
138 print "in trace_begin"
139
140def trace_end():
141 print "in trace_end"
142
143def raw_syscalls__sys_enter(event_name, context, common_cpu,
144 common_secs, common_nsecs, common_pid, common_comm,
145 id, args):
146 print_header(event_name, common_cpu, common_secs, common_nsecs,
147 common_pid, common_comm)
148
149 print "id=%d, args=%s\n" % \
150 (id, args),
151
152def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
153 common_pid, common_comm):
154 print_header(event_name, common_cpu, common_secs, common_nsecs,
155 common_pid, common_comm)
156
157def print_header(event_name, cpu, secs, nsecs, pid, comm):
158 print "%-20s %5u %05u.%09u %8u %-20s " % \
159 (event_name, cpu, secs, nsecs, pid, comm),
160----
161
162At the top is a comment block followed by some import statements and a
163path append which every perf trace script should include.
164
165Following that are a couple generated functions, trace_begin() and
166trace_end(), which are called at the beginning and the end of the
167script respectively (for more details, see the SCRIPT_LAYOUT section
168below).
169
170Following those are the 'event handler' functions generated one for
171every event in the 'perf record' output. The handler functions take
172the form subsystem__event_name, and contain named parameters, one for
173each field in the event; in this case, there's only one event,
174raw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for
175more info on event handlers).
176
177The final couple of functions are, like the begin and end functions,
178generated for every script. The first, trace_unhandled(), is called
179every time the script finds an event in the perf.data file that
180doesn't correspond to any event handler in the script. This could
181mean either that the record step recorded event types that it wasn't
182really interested in, or the script was run against a trace file that
183doesn't correspond to the script.
184
185The script generated by -g option option simply prints a line for each
186event found in the trace stream i.e. it basically just dumps the event
187and its parameter values to stdout. The print_header() function is
188simply a utility function used for that purpose. Let's rename the
189script and run it to see the default output:
190
191----
192# mv perf-trace.py syscall-counts.py
193# perf trace -s syscall-counts.py
194
195raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
196raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
197raw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args=
198raw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args=
199raw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args=
200raw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args=
201raw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args=
202raw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args=
203.
204.
205.
206----
207
208Of course, for this script, we're not interested in printing every
209trace event, but rather aggregating it in a useful way. So we'll get
210rid of everything to do with printing as well as the trace_begin() and
211trace_unhandled() functions, which we won't be using. That leaves us
212with this minimalistic skeleton:
213
214----
215import os
216import sys
217
218sys.path.append(os.environ['PERF_EXEC_PATH'] + \
219 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
220
221from perf_trace_context import *
222from Core import *
223
224def trace_end():
225 print "in trace_end"
226
227def raw_syscalls__sys_enter(event_name, context, common_cpu,
228 common_secs, common_nsecs, common_pid, common_comm,
229 id, args):
230----
231
232In trace_end(), we'll simply print the results, but first we need to
233generate some results to print. To do that we need to have our
234sys_enter() handler do the necessary tallying until all events have
235been counted. A hash table indexed by syscall id is a good way to
236store that information; every time the sys_enter() handler is called,
237we simply increment a count associated with that hash entry indexed by
238that syscall id:
239
240----
241 syscalls = autodict()
242
243 try:
244 syscalls[id] += 1
245 except TypeError:
246 syscalls[id] = 1
247----
248
249The syscalls 'autodict' object is a special kind of Python dictionary
250(implemented in Core.py) that implements Perl's 'autovivifying' hashes
251in Python i.e. with autovivifying hashes, you can assign nested hash
252values without having to go to the trouble of creating intermediate
253levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
254the intermediate hash levels and finally assign the value 1 to the
255hash entry for 'id' (because the value being assigned isn't a hash
256object itself, the initial value is assigned in the TypeError
257exception. Well, there may be a better way to do this in Python but
258that's what works for now).
259
260Putting that code into the raw_syscalls__sys_enter() handler, we
261effectively end up with a single-level dictionary keyed on syscall id
262and having the counts we've tallied as values.
263
264The print_syscall_totals() function iterates over the entries in the
265dictionary and displays a line for each entry containing the syscall
266name (the dictonary keys contain the syscall ids, which are passed to
267the Util function syscall_name(), which translates the raw syscall
268numbers to the corresponding syscall name strings). The output is
269displayed after all the events in the trace have been processed, by
270calling the print_syscall_totals() function from the trace_end()
271handler called at the end of script processing.
272
273The final script producing the output shown above is shown in its
274entirety below (syscall_name() helper is not yet available, you can
275only deal with id's for now):
276
277----
278import os
279import sys
280
281sys.path.append(os.environ['PERF_EXEC_PATH'] + \
282 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
283
284from perf_trace_context import *
285from Core import *
286from Util import *
287
288syscalls = autodict()
289
290def trace_end():
291 print_syscall_totals()
292
293def raw_syscalls__sys_enter(event_name, context, common_cpu,
294 common_secs, common_nsecs, common_pid, common_comm,
295 id, args):
296 try:
297 syscalls[id] += 1
298 except TypeError:
299 syscalls[id] = 1
300
301def print_syscall_totals():
302 if for_comm is not None:
303 print "\nsyscall events for %s:\n\n" % (for_comm),
304 else:
305 print "\nsyscall events:\n\n",
306
307 print "%-40s %10s\n" % ("event", "count"),
308 print "%-40s %10s\n" % ("----------------------------------------", \
309 "-----------"),
310
311 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
312 reverse = True):
313 print "%-40s %10d\n" % (syscall_name(id), val),
314----
315
316The script can be run just as before:
317
318 # perf trace -s syscall-counts.py
319
320So those are the essential steps in writing and running a script. The
321process can be generalized to any tracepoint or set of tracepoints
322you're interested in - basically find the tracepoint(s) you're
323interested in by looking at the list of available events shown by
324'perf list' and/or look in /sys/kernel/debug/tracing events for
325detailed event and field info, record the corresponding trace data
326using 'perf record', passing it the list of interesting events,
327generate a skeleton script using 'perf trace -g python' and modify the
328code to aggregate and display it for your particular needs.
329
330After you've done that you may end up with a general-purpose script
331that you want to keep around and have available for future use. By
332writing a couple of very simple shell scripts and putting them in the
333right place, you can have your script listed alongside the other
334scripts listed by the 'perf trace -l' command e.g.:
335
336----
337root@tropicana:~# perf trace -l
338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity
343----
344
345A nice side effect of doing this is that you also then capture the
346probably lengthy 'perf record' command needed to record the events for
347the script.
348
349To have the script appear as a 'built-in' script, you write two simple
350scripts, one for recording and one for 'reporting'.
351
352The 'record' script is a shell script with the same base name as your
353script, but with -record appended. The shell script should be put
354into the perf/scripts/python/bin directory in the kernel source tree.
355In that script, you write the 'perf record' command-line needed for
356your script:
357
358----
359# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
360
361#!/bin/bash
362perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
363----
364
365The 'report' script is also a shell script with the same base name as
366your script, but with -report appended. It should also be located in
367the perf/scripts/python/bin directory. In that script, you write the
368'perf trace -s' command-line needed for running your script:
369
370----
371# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
372
373#!/bin/bash
374# description: system-wide syscall counts
375perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py
376----
377
378Note that the location of the Python script given in the shell script
379is in the libexec/perf-core/scripts/python directory - this is where
380the script will be copied by 'make install' when you install perf.
381For the installation to install your script there, your script needs
382to be located in the perf/scripts/python directory in the kernel
383source tree:
384
385----
386# ls -al kernel-source/tools/perf/scripts/python
387
388root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
389total 32
390drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-trace.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-Util
395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
396----
397
398Once you've done that (don't forget to do a new 'make install',
399otherwise your script won't show up at run-time), 'perf trace -l'
400should show a new entry for your script:
401
402----
403root@tropicana:~# perf trace -l
404List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity
409 syscall-counts system-wide syscall counts
410----
411
412You can now perform the record step via 'perf trace record':
413
414 # perf trace record syscall-counts
415
416and display the output using 'perf trace report':
417
418 # perf trace report syscall-counts
419
420STARTER SCRIPTS
421---------------
422
423You can quickly get started writing a script for a particular set of
424trace data by generating a skeleton script using 'perf trace -g
425python' in the same directory as an existing perf.data trace file.
426That will generate a starter script containing a handler for each of
427the event types in the trace file; it simply prints every available
428field for each event in the trace file.
429
430You can also look at the existing scripts in
431~/libexec/perf-core/scripts/python for typical examples showing how to
432do basic things like aggregate event data, print results, etc. Also,
433the check-perf-trace.py script, while not interesting for its results,
434attempts to exercise all of the main scripting features.
435
436EVENT HANDLERS
437--------------
438
439When perf trace is invoked using a trace script, a user-defined
440'handler function' is called for each event in the trace. If there's
441no handler function defined for a given event type, the event is
442ignored (or passed to a 'trace_handled' function, see below) and the
443next event is processed.
444
445Most of the event's field values are passed as arguments to the
446handler function; some of the less common ones aren't - those are
447available as calls back into the perf executable (see below).
448
449As an example, the following perf record command can be used to record
450all sched_wakeup events in the system:
451
452 # perf record -c 1 -f -a -M -R -e sched:sched_wakeup
453
454Traces meant to be processed using a script should be recorded with
455the above options: -c 1 says to sample every event, -a to enable
456system-wide collection, -M to multiplex the output, and -R to collect
457raw samples.
458
459The format file for the sched_wakep event defines the following fields
460(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
461
462----
463 format:
464 field:unsigned short common_type;
465 field:unsigned char common_flags;
466 field:unsigned char common_preempt_count;
467 field:int common_pid;
468 field:int common_lock_depth;
469
470 field:char comm[TASK_COMM_LEN];
471 field:pid_t pid;
472 field:int prio;
473 field:int success;
474 field:int target_cpu;
475----
476
477The handler function for this event would be defined as:
478
479----
480def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
481 common_nsecs, common_pid, common_comm,
482 comm, pid, prio, success, target_cpu):
483 pass
484----
485
486The handler function takes the form subsystem__event_name.
487
488The common_* arguments in the handler's argument list are the set of
489arguments passed to all event handlers; some of the fields correspond
490to the common_* fields in the format file, but some are synthesized,
491and some of the common_* fields aren't common enough to to be passed
492to every event as arguments but are available as library functions.
493
494Here's a brief description of each of the invariant event args:
495
496 event_name the name of the event as text
497 context an opaque 'cookie' used in calls back into perf
498 common_cpu the cpu the event occurred on
499 common_secs the secs portion of the event timestamp
500 common_nsecs the nsecs portion of the event timestamp
501 common_pid the pid of the current task
502 common_comm the name of the current process
503
504All of the remaining fields in the event's format file have
505counterparts as handler function arguments of the same name, as can be
506seen in the example above.
507
508The above provides the basics needed to directly access every field of
509every event in a trace, which covers 90% of what you need to know to
510write a useful trace script. The sections below cover the rest.
511
512SCRIPT LAYOUT
513-------------
514
515Every perf trace Python script should start by setting up a Python
516module search path and 'import'ing a few support modules (see module
517descriptions below):
518
519----
520 import os
521 import sys
522
523 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
524 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
525
526 from perf_trace_context import *
527 from Core import *
528----
529
530The rest of the script can contain handler functions and support
531functions in any order.
532
533Aside from the event handler functions discussed above, every script
534can implement a set of optional functions:
535
536*trace_begin*, if defined, is called before any event is processed and
537gives scripts a chance to do setup tasks:
538
539----
540def trace_begin:
541 pass
542----
543
544*trace_end*, if defined, is called after all events have been
545 processed and gives scripts a chance to do end-of-script tasks, such
546 as display results:
547
548----
549def trace_end:
550 pass
551----
552
553*trace_unhandled*, if defined, is called after for any event that
554 doesn't have a handler explicitly defined for it. The standard set
555 of common arguments are passed into it:
556
557----
558def trace_unhandled(event_name, context, common_cpu, common_secs,
559 common_nsecs, common_pid, common_comm):
560 pass
561----
562
563The remaining sections provide descriptions of each of the available
564built-in perf trace Python modules and their associated functions.
565
566AVAILABLE MODULES AND FUNCTIONS
567-------------------------------
568
569The following sections describe the functions and variables available
570via the various perf trace Python modules. To use the functions and
571variables from the given module, add the corresponding 'from XXXX
572import' line to your perf trace script.
573
574Core.py Module
575~~~~~~~~~~~~~~
576
577These functions provide some essential functions to user scripts.
578
579The *flag_str* and *symbol_str* functions provide human-readable
580strings for flag and symbolic fields. These correspond to the strings
581and values parsed from the 'print fmt' fields of the event format
582files:
583
584 flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name
585 symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name
586
587The *autodict* function returns a special special kind of Python
588dictionary that implements Perl's 'autovivifying' hashes in Python
589i.e. with autovivifying hashes, you can assign nested hash values
590without having to go to the trouble of creating intermediate levels if
591they don't exist.
592
593 autodict() - returns an autovivifying dictionary instance
594
595
596perf_trace_context Module
597~~~~~~~~~~~~~~~~~~~~~~~~~
598
599Some of the 'common' fields in the event format file aren't all that
600common, but need to be made accessible to user scripts nonetheless.
601
602perf_trace_context defines a set of functions that can be used to
603access this data in the context of the current event. Each of these
604functions expects a context variable, which is the same as the
605context variable passed into every event handler as the second
606argument.
607
608 common_pc(context) - returns common_preempt count for the current event
609 common_flags(context) - returns common_flags for the current event
610 common_lock_depth(context) - returns common_lock_depth for the current event
611
612Util.py Module
613~~~~~~~~~~~~~~
614
615Various utility functions for use with perf trace:
616
617 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
618 nsecs_secs(nsecs) - returns whole secs portion given nsecs
619 nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
620 nsecs_str(nsecs) - returns printable string in the form secs.nsecs
621 avg(total, n) - returns average given a sum and a total number of values
622
623SEE ALSO
624--------
625linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 41ed75398ca9..8879299cd9df 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,18 +8,63 @@ 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 You can also run a set of pre-canned scripts that aggregate and
23 summarize the raw trace data in various ways (the list of scripts is
24 available via 'perf trace -l'). The following variants allow you to
25 record and run those scripts:
26
27 'perf trace record <script>' to record the events required for 'perf
28 trace report'. <script> is the name displayed in the output of
29 'perf trace --list' i.e. the actual script name minus any language
30 extension.
31
32 'perf trace report <script>' to run and display the results of
33 <script>. <script> is the name displayed in the output of 'perf
34 trace --list' i.e. the actual script name minus any language
35 extension. The perf.data output from a previous run of 'perf trace
36 record <script>' is used and should be present for this command to
37 succeed.
38
39 See the 'SEE ALSO' section for links to language-specific
40 information on how to write and run your own trace scripts.
41
17OPTIONS 42OPTIONS
18------- 43-------
19-D:: 44-D::
20--dump-raw-trace=:: 45--dump-raw-trace=::
21 Display verbose dump of the trace data. 46 Display verbose dump of the trace data.
22 47
48-L::
49--Latency=::
50 Show latency attributes (irqs/preemption disabled, etc).
51
52-l::
53--list=::
54 Display a list of available trace scripts.
55
56-s ['lang']::
57--script=::
58 Process trace data with the given script ([lang]:script[.ext]).
59 If the string 'lang' is specified in place of a script name, a
60 list of supported languages will be displayed instead.
61
62-g::
63--gen-script=::
64 Generate perf-trace.[ext] starter script for given language,
65 using current perf.data.
66
23SEE ALSO 67SEE ALSO
24-------- 68--------
25linkperf:perf-record[1] 69linkperf:perf-record[1], linkperf:perf-trace-perl[1],
70linkperf:perf-trace-python[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 69c832557199..0eeb247dc7d2 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15Performance counters for Linux are are a new kernel-based subsystem 15Performance counters for Linux are a new kernel-based subsystem
16that provide a framework for all things performance analysis. It 16that provide a framework for all things performance analysis. It
17covers hardware level (CPU/PMU, Performance Monitoring Unit) features 17covers hardware level (CPU/PMU, Performance Monitoring Unit) features
18and software features (software counters, tracepoints) as well. 18and software features (software counters, tracepoints) as well.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7e190d522cd5..2d537382c686 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -2,6 +2,7 @@
2all:: 2all::
3 3
4# Define V=1 to have a more verbose compile. 4# Define V=1 to have a more verbose compile.
5# Define V=2 to have an even more verbose compile.
5# 6#
6# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() 7# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
7# or vsnprintf() return -1 instead of number of characters which would 8# or vsnprintf() return -1 instead of number of characters which would
@@ -145,6 +146,10 @@ all::
145# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call 146# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
146# your external grep (e.g., if your system lacks grep, if its grep is 147# your external grep (e.g., if your system lacks grep, if its grep is
147# broken, or spawning external process is slower than built-in grep perf has). 148# broken, or spawning external process is slower than built-in grep perf has).
149#
150# Define LDFLAGS=-static to build a static binary.
151#
152# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
148 153
149PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 154PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
150 @$(SHELL_PATH) util/PERF-VERSION-GEN 155 @$(SHELL_PATH) util/PERF-VERSION-GEN
@@ -157,20 +162,6 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 162uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 163uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 164
160#
161# Add -m32 for cross-builds:
162#
163ifdef NO_64BIT
164 MBITS := -m32
165else
166 #
167 # If we're on a 64-bit kernel, use -m64:
168 #
169 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
170 MBITS := -m64
171 endif
172endif
173
174# CFLAGS and LDFLAGS are for the users to override from the command line. 165# CFLAGS and LDFLAGS are for the users to override from the command line.
175 166
176# 167#
@@ -200,8 +191,15 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
200EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes 191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement 192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
202 193
203CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) 194ifeq ("$(origin DEBUG)", "command line")
204LDFLAGS = -lpthread -lrt -lelf -lm 195 PERF_DEBUG = $(DEBUG)
196endif
197ifndef PERF_DEBUG
198 CFLAGS_OPTIMIZE = -O6
199endif
200
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm
205ALL_CFLAGS = $(CFLAGS) 203ALL_CFLAGS = $(CFLAGS)
206ALL_LDFLAGS = $(LDFLAGS) 204ALL_LDFLAGS = $(LDFLAGS)
207STRIP ?= strip 205STRIP ?= strip
@@ -239,8 +237,8 @@ lib = lib
239 237
240export prefix bindir sharedir sysconfdir 238export prefix bindir sharedir sysconfdir
241 239
242CC = gcc 240CC = $(CROSS_COMPILE)gcc
243AR = ar 241AR = $(CROSS_COMPILE)ar
244RM = rm -f 242RM = rm -f
245TAR = tar 243TAR = tar
246FIND = find 244FIND = find
@@ -252,6 +250,21 @@ PTHREAD_LIBS = -lpthread
252# explicitly what architecture to check for. Fix this up for yours.. 250# explicitly what architecture to check for. Fix this up for yours..
253SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
254 252
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)
266 CFLAGS := $(CFLAGS) -fstack-protector-all
267endif
255 268
256 269
257### --- END CONFIGURATION SECTION --- 270### --- END CONFIGURATION SECTION ---
@@ -273,11 +286,7 @@ SCRIPT_PERL =
273SCRIPT_SH = 286SCRIPT_SH =
274TEST_PROGRAMS = 287TEST_PROGRAMS =
275 288
276# 289SCRIPT_SH += perf-archive.sh
277# No scripts right now:
278#
279
280# SCRIPT_SH += perf-am.sh
281 290
282# 291#
283# No Perl scripts right now: 292# No Perl scripts right now:
@@ -302,9 +311,6 @@ PROGRAMS += perf
302# List built-in command $C whose implementation cmd_$C() is not in 311# List built-in command $C whose implementation cmd_$C() is not in
303# builtin-$C.o but is linked in as part of some other command. 312# builtin-$C.o but is linked in as part of some other command.
304# 313#
305# None right now:
306#
307# BUILT_INS += perf-init $X
308 314
309# what 'all' will build and 'install' will install, in perfexecdir 315# what 'all' will build and 'install' will install, in perfexecdir
310ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 316ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -327,30 +333,69 @@ LIB_FILE=libperf.a
327LIB_H += ../../include/linux/perf_event.h 333LIB_H += ../../include/linux/perf_event.h
328LIB_H += ../../include/linux/rbtree.h 334LIB_H += ../../include/linux/rbtree.h
329LIB_H += ../../include/linux/list.h 335LIB_H += ../../include/linux/list.h
336LIB_H += ../../include/linux/hash.h
337LIB_H += ../../include/linux/stringify.h
338LIB_H += util/include/linux/bitmap.h
339LIB_H += util/include/linux/bitops.h
340LIB_H += util/include/linux/compiler.h
341LIB_H += util/include/linux/ctype.h
342LIB_H += util/include/linux/kernel.h
330LIB_H += util/include/linux/list.h 343LIB_H += util/include/linux/list.h
344LIB_H += util/include/linux/module.h
345LIB_H += util/include/linux/poison.h
346LIB_H += util/include/linux/prefetch.h
347LIB_H += util/include/linux/rbtree.h
348LIB_H += util/include/linux/string.h
349LIB_H += util/include/linux/types.h
350LIB_H += util/include/asm/asm-offsets.h
351LIB_H += util/include/asm/bitops.h
352LIB_H += util/include/asm/bug.h
353LIB_H += util/include/asm/byteorder.h
354LIB_H += util/include/asm/swab.h
355LIB_H += util/include/asm/system.h
356LIB_H += util/include/asm/uaccess.h
331LIB_H += perf.h 357LIB_H += perf.h
358LIB_H += util/cache.h
359LIB_H += util/callchain.h
360LIB_H += util/build-id.h
361LIB_H += util/debug.h
362LIB_H += util/debugfs.h
363LIB_H += util/event.h
364LIB_H += util/exec_cmd.h
332LIB_H += util/types.h 365LIB_H += util/types.h
333LIB_H += util/levenshtein.h 366LIB_H += util/levenshtein.h
367LIB_H += util/map.h
334LIB_H += util/parse-options.h 368LIB_H += util/parse-options.h
335LIB_H += util/parse-events.h 369LIB_H += util/parse-events.h
336LIB_H += util/quote.h 370LIB_H += util/quote.h
337LIB_H += util/util.h 371LIB_H += util/util.h
372LIB_H += util/header.h
338LIB_H += util/help.h 373LIB_H += util/help.h
374LIB_H += util/session.h
339LIB_H += util/strbuf.h 375LIB_H += util/strbuf.h
340LIB_H += util/string.h 376LIB_H += util/string.h
341LIB_H += util/strlist.h 377LIB_H += util/strlist.h
378LIB_H += util/svghelper.h
342LIB_H += util/run-command.h 379LIB_H += util/run-command.h
343LIB_H += util/sigchain.h 380LIB_H += util/sigchain.h
344LIB_H += util/symbol.h 381LIB_H += util/symbol.h
345LIB_H += util/module.h
346LIB_H += util/color.h 382LIB_H += util/color.h
347LIB_H += util/values.h 383LIB_H += util/values.h
384LIB_H += util/sort.h
385LIB_H += util/hist.h
386LIB_H += util/thread.h
387LIB_H += util/trace-event.h
388LIB_H += util/probe-finder.h
389LIB_H += util/probe-event.h
348 390
349LIB_OBJS += util/abspath.o 391LIB_OBJS += util/abspath.o
350LIB_OBJS += util/alias.o 392LIB_OBJS += util/alias.o
393LIB_OBJS += util/build-id.o
351LIB_OBJS += util/config.o 394LIB_OBJS += util/config.o
352LIB_OBJS += util/ctype.o 395LIB_OBJS += util/ctype.o
396LIB_OBJS += util/debugfs.o
353LIB_OBJS += util/environment.o 397LIB_OBJS += util/environment.o
398LIB_OBJS += util/event.o
354LIB_OBJS += util/exec_cmd.o 399LIB_OBJS += util/exec_cmd.o
355LIB_OBJS += util/help.o 400LIB_OBJS += util/help.o
356LIB_OBJS += util/levenshtein.o 401LIB_OBJS += util/levenshtein.o
@@ -358,6 +403,9 @@ LIB_OBJS += util/parse-options.o
358LIB_OBJS += util/parse-events.o 403LIB_OBJS += util/parse-events.o
359LIB_OBJS += util/path.o 404LIB_OBJS += util/path.o
360LIB_OBJS += util/rbtree.o 405LIB_OBJS += util/rbtree.o
406LIB_OBJS += util/bitmap.o
407LIB_OBJS += util/hweight.o
408LIB_OBJS += util/find_next_bit.o
361LIB_OBJS += util/run-command.o 409LIB_OBJS += util/run-command.o
362LIB_OBJS += util/quote.o 410LIB_OBJS += util/quote.o
363LIB_OBJS += util/strbuf.o 411LIB_OBJS += util/strbuf.o
@@ -367,7 +415,6 @@ LIB_OBJS += util/usage.o
367LIB_OBJS += util/wrapper.o 415LIB_OBJS += util/wrapper.o
368LIB_OBJS += util/sigchain.o 416LIB_OBJS += util/sigchain.o
369LIB_OBJS += util/symbol.o 417LIB_OBJS += util/symbol.o
370LIB_OBJS += util/module.o
371LIB_OBJS += util/color.o 418LIB_OBJS += util/color.o
372LIB_OBJS += util/pager.o 419LIB_OBJS += util/pager.o
373LIB_OBJS += util/header.o 420LIB_OBJS += util/header.o
@@ -375,15 +422,32 @@ LIB_OBJS += util/callchain.o
375LIB_OBJS += util/values.o 422LIB_OBJS += util/values.o
376LIB_OBJS += util/debug.o 423LIB_OBJS += util/debug.o
377LIB_OBJS += util/map.o 424LIB_OBJS += util/map.o
425LIB_OBJS += util/session.o
378LIB_OBJS += util/thread.o 426LIB_OBJS += util/thread.o
379LIB_OBJS += util/trace-event-parse.o 427LIB_OBJS += util/trace-event-parse.o
380LIB_OBJS += util/trace-event-read.o 428LIB_OBJS += util/trace-event-read.o
381LIB_OBJS += util/trace-event-info.o 429LIB_OBJS += util/trace-event-info.o
430LIB_OBJS += util/trace-event-scripting.o
382LIB_OBJS += util/svghelper.o 431LIB_OBJS += util/svghelper.o
432LIB_OBJS += util/sort.o
433LIB_OBJS += util/hist.o
434LIB_OBJS += util/probe-event.o
435LIB_OBJS += util/util.o
383 436
384BUILTIN_OBJS += builtin-annotate.o 437BUILTIN_OBJS += builtin-annotate.o
438
439BUILTIN_OBJS += builtin-bench.o
440
441# Benchmark modules
442BUILTIN_OBJS += bench/sched-messaging.o
443BUILTIN_OBJS += bench/sched-pipe.o
444BUILTIN_OBJS += bench/mem-memcpy.o
445
446BUILTIN_OBJS += builtin-diff.o
385BUILTIN_OBJS += builtin-help.o 447BUILTIN_OBJS += builtin-help.o
386BUILTIN_OBJS += builtin-sched.o 448BUILTIN_OBJS += builtin-sched.o
449BUILTIN_OBJS += builtin-buildid-list.o
450BUILTIN_OBJS += builtin-buildid-cache.o
387BUILTIN_OBJS += builtin-list.o 451BUILTIN_OBJS += builtin-list.o
388BUILTIN_OBJS += builtin-record.o 452BUILTIN_OBJS += builtin-record.o
389BUILTIN_OBJS += builtin-report.o 453BUILTIN_OBJS += builtin-report.o
@@ -391,6 +455,9 @@ BUILTIN_OBJS += builtin-stat.o
391BUILTIN_OBJS += builtin-timechart.o 455BUILTIN_OBJS += builtin-timechart.o
392BUILTIN_OBJS += builtin-top.o 456BUILTIN_OBJS += builtin-top.o
393BUILTIN_OBJS += builtin-trace.o 457BUILTIN_OBJS += builtin-trace.o
458BUILTIN_OBJS += builtin-probe.o
459BUILTIN_OBJS += builtin-kmem.o
460BUILTIN_OBJS += builtin-lock.o
394 461
395PERFLIBS = $(LIB_FILE) 462PERFLIBS = $(LIB_FILE)
396 463
@@ -421,36 +488,75 @@ ifeq ($(uname_S),Darwin)
421 PTHREAD_LIBS = 488 PTHREAD_LIBS =
422endif 489endif
423 490
424ifeq ($(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) > /dev/null 2>&1 && echo y"), y) 491ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
425 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) > /dev/null 2>&1 && echo y"), y) 492ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
493 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
494endif
495
496 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
426 BASIC_CFLAGS += -DLIBELF_NO_MMAP 497 BASIC_CFLAGS += -DLIBELF_NO_MMAP
427 endif 498 endif
428else 499else
429 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 500 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
430endif 501endif
431 502
503ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
504 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
505 BASIC_CFLAGS += -DNO_DWARF_SUPPORT
506else
507 BASIC_CFLAGS += -I/usr/include/elfutils
508 EXTLIBS += -lelf -ldw
509 LIB_OBJS += util/probe-finder.o
510endif
511
512ifndef NO_LIBPERL
513PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
514PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
515endif
516
517ifneq ($(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)
518 BASIC_CFLAGS += -DNO_LIBPERL
519else
520 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
521 LIB_OBJS += util/scripting-engines/trace-event-perl.o
522 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
523endif
524
525ifndef NO_LIBPYTHON
526PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
527PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
528endif
529
530ifneq ($(shell sh -c "(echo '\#include <Python.h>'; echo 'int main(void) { Py_Initialize(); return 0; }') | $(CC) -x c - $(PYTHON_EMBED_CCOPTS) -o /dev/null $(PYTHON_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
531 BASIC_CFLAGS += -DNO_LIBPYTHON
532else
533 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
534 LIB_OBJS += util/scripting-engines/trace-event-python.o
535 LIB_OBJS += scripts/python/Perf-Trace-Util/Context.o
536endif
537
432ifdef NO_DEMANGLE 538ifdef NO_DEMANGLE
433 BASIC_CFLAGS += -DNO_DEMANGLE 539 BASIC_CFLAGS += -DNO_DEMANGLE
434else 540else
435 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) -lbfd > /dev/null 2>&1 && echo y") 541 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")
436 542
437 ifeq ($(has_bfd),y) 543 ifeq ($(has_bfd),y)
438 EXTLIBS += -lbfd 544 EXTLIBS += -lbfd
439 else 545 else
440 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) -lbfd -liberty > /dev/null 2>&1 && echo y") 546 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")
441 ifeq ($(has_bfd_iberty),y) 547 ifeq ($(has_bfd_iberty),y)
442 EXTLIBS += -lbfd -liberty 548 EXTLIBS += -lbfd -liberty
443 else 549 else
444 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) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") 550 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")
445 ifeq ($(has_bfd_iberty_z),y) 551 ifeq ($(has_bfd_iberty_z),y)
446 EXTLIBS += -lbfd -liberty -lz 552 EXTLIBS += -lbfd -liberty -lz
447 else 553 else
448 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) -liberty > /dev/null 2>&1 && echo y") 554 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")
449 ifeq ($(has_cplus_demangle),y) 555 ifeq ($(has_cplus_demangle),y)
450 EXTLIBS += -liberty 556 EXTLIBS += -liberty
451 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 557 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
452 else 558 else
453 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) 559 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
454 BASIC_CFLAGS += -DNO_DEMANGLE 560 BASIC_CFLAGS += -DNO_DEMANGLE
455 endif 561 endif
456 endif 562 endif
@@ -693,7 +799,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
693 799
694SHELL = $(SHELL_PATH) 800SHELL = $(SHELL_PATH)
695 801
696all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 802all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
697ifneq (,$X) 803ifneq (,$X)
698 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 804 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
699endif 805endif
@@ -787,6 +893,31 @@ util/config.o: util/config.c PERF-CFLAGS
787util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 893util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
788 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 894 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
789 895
896# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
897# from <string.h> that comes from kernel headers wrapping.
898KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
899
900util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
901 $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
902
903util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
904 $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
905
906util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
907 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
908
909util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c PERF-CFLAGS
910 $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
911
912scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
913 $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
914
915util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c PERF-CFLAGS
916 $(QUIET_CC)$(CC) -o util/scripting-engines/trace-event-python.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
917
918scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c PERF-CFLAGS
919 $(QUIET_CC)$(CC) -o scripts/python/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
920
790perf-%$X: %.o $(PERFLIBS) 921perf-%$X: %.o $(PERFLIBS)
791 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 922 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
792 923
@@ -894,6 +1025,18 @@ export perfexec_instdir
894install: all 1025install: all
895 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1026 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
896 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1027 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
1028 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1029 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1030 $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1031 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1032 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
1033 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1034 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1035 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1036 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1037 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1038 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1039
897ifdef BUILT_INS 1040ifdef BUILT_INS
898 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1041 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
899 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1042 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -979,7 +1122,7 @@ distclean: clean
979# $(RM) configure 1122# $(RM) configure
980 1123
981clean: 1124clean:
982 $(RM) *.o */*.o $(LIB_FILE) 1125 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
983 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1126 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
984 $(RM) $(TEST_PROGRAMS) 1127 $(RM) $(TEST_PROGRAMS)
985 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1128 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
@@ -996,6 +1139,11 @@ clean:
996.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1139.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
997.PHONY: .FORCE-PERF-BUILD-OPTIONS 1140.PHONY: .FORCE-PERF-BUILD-OPTIONS
998 1141
1142.perf.dev.null:
1143 touch .perf.dev.null
1144
1145.INTERMEDIATE: .perf.dev.null
1146
999### Make sure built-ins do not have dups and listed in perf.c 1147### Make sure built-ins do not have dups and listed in perf.c
1000# 1148#
1001check-builtins:: 1149check-builtins::
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
new file mode 100644
index 000000000000..f7781c6267c0
--- /dev/null
+++ b/tools/perf/bench/bench.h
@@ -0,0 +1,17 @@
1#ifndef BENCH_H
2#define BENCH_H
3
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
7
8#define BENCH_FORMAT_DEFAULT_STR "default"
9#define BENCH_FORMAT_DEFAULT 0
10#define BENCH_FORMAT_SIMPLE_STR "simple"
11#define BENCH_FORMAT_SIMPLE 1
12
13#define BENCH_FORMAT_UNKNOWN -1
14
15extern int bench_format;
16
17#endif
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
new file mode 100644
index 000000000000..89773178e894
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy.c
@@ -0,0 +1,193 @@
1/*
2 * mem-memcpy.c
3 *
4 * memcpy: Simple memory copy in various ways
5 *
6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
7 */
8#include <ctype.h>
9
10#include "../perf.h"
11#include "../util/util.h"
12#include "../util/parse-options.h"
13#include "../util/string.h"
14#include "../util/header.h"
15#include "bench.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <errno.h>
22
23#define K 1024
24
25static const char *length_str = "1MB";
26static const char *routine = "default";
27static int use_clock = 0;
28static int clock_fd;
29
30static const struct option options[] = {
31 OPT_STRING('l', "length", &length_str, "1MB",
32 "Specify length of memory to copy. "
33 "available unit: B, MB, GB (upper and lower)"),
34 OPT_STRING('r', "routine", &routine, "default",
35 "Specify routine to copy"),
36 OPT_BOOLEAN('c', "clock", &use_clock,
37 "Use CPU clock for measuring"),
38 OPT_END()
39};
40
41struct routine {
42 const char *name;
43 const char *desc;
44 void * (*fn)(void *dst, const void *src, size_t len);
45};
46
47struct routine routines[] = {
48 { "default",
49 "Default memcpy() provided by glibc",
50 memcpy },
51 { NULL,
52 NULL,
53 NULL }
54};
55
56static const char * const bench_mem_memcpy_usage[] = {
57 "perf bench mem memcpy <options>",
58 NULL
59};
60
61static struct perf_event_attr clock_attr = {
62 .type = PERF_TYPE_HARDWARE,
63 .config = PERF_COUNT_HW_CPU_CYCLES
64};
65
66static void init_clock(void)
67{
68 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
69
70 if (clock_fd < 0 && errno == ENOSYS)
71 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
72 else
73 BUG_ON(clock_fd < 0);
74}
75
76static u64 get_clock(void)
77{
78 int ret;
79 u64 clk;
80
81 ret = read(clock_fd, &clk, sizeof(u64));
82 BUG_ON(ret != sizeof(u64));
83
84 return clk;
85}
86
87static double timeval2double(struct timeval *ts)
88{
89 return (double)ts->tv_sec +
90 (double)ts->tv_usec / (double)1000000;
91}
92
93int bench_mem_memcpy(int argc, const char **argv,
94 const char *prefix __used)
95{
96 int i;
97 void *dst, *src;
98 size_t length;
99 double bps = 0.0;
100 struct timeval tv_start, tv_end, tv_diff;
101 u64 clock_start, clock_end, clock_diff;
102
103 clock_start = clock_end = clock_diff = 0ULL;
104 argc = parse_options(argc, argv, options,
105 bench_mem_memcpy_usage, 0);
106
107 tv_diff.tv_sec = 0;
108 tv_diff.tv_usec = 0;
109 length = (size_t)perf_atoll((char *)length_str);
110
111 if ((s64)length <= 0) {
112 fprintf(stderr, "Invalid length:%s\n", length_str);
113 return 1;
114 }
115
116 for (i = 0; routines[i].name; i++) {
117 if (!strcmp(routines[i].name, routine))
118 break;
119 }
120 if (!routines[i].name) {
121 printf("Unknown routine:%s\n", routine);
122 printf("Available routines...\n");
123 for (i = 0; routines[i].name; i++) {
124 printf("\t%s ... %s\n",
125 routines[i].name, routines[i].desc);
126 }
127 return 1;
128 }
129
130 dst = zalloc(length);
131 if (!dst)
132 die("memory allocation failed - maybe length is too large?\n");
133
134 src = zalloc(length);
135 if (!src)
136 die("memory allocation failed - maybe length is too large?\n");
137
138 if (bench_format == BENCH_FORMAT_DEFAULT) {
139 printf("# Copying %s Bytes from %p to %p ...\n\n",
140 length_str, src, dst);
141 }
142
143 if (use_clock) {
144 init_clock();
145 clock_start = get_clock();
146 } else {
147 BUG_ON(gettimeofday(&tv_start, NULL));
148 }
149
150 routines[i].fn(dst, src, length);
151
152 if (use_clock) {
153 clock_end = get_clock();
154 clock_diff = clock_end - clock_start;
155 } else {
156 BUG_ON(gettimeofday(&tv_end, NULL));
157 timersub(&tv_end, &tv_start, &tv_diff);
158 bps = (double)((double)length / timeval2double(&tv_diff));
159 }
160
161 switch (bench_format) {
162 case BENCH_FORMAT_DEFAULT:
163 if (use_clock) {
164 printf(" %14lf Clock/Byte\n",
165 (double)clock_diff / (double)length);
166 } else {
167 if (bps < K)
168 printf(" %14lf B/Sec\n", bps);
169 else if (bps < K * K)
170 printf(" %14lfd KB/Sec\n", bps / 1024);
171 else if (bps < K * K * K)
172 printf(" %14lf MB/Sec\n", bps / 1024 / 1024);
173 else {
174 printf(" %14lf GB/Sec\n",
175 bps / 1024 / 1024 / 1024);
176 }
177 }
178 break;
179 case BENCH_FORMAT_SIMPLE:
180 if (use_clock) {
181 printf("%14lf\n",
182 (double)clock_diff / (double)length);
183 } else
184 printf("%lf\n", bps);
185 break;
186 default:
187 /* reaching this means there's some disaster: */
188 die("unknown format: %d\n", bench_format);
189 break;
190 }
191
192 return 0;
193}
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
new file mode 100644
index 000000000000..81cee78181fa
--- /dev/null
+++ b/tools/perf/bench/sched-messaging.c
@@ -0,0 +1,338 @@
1/*
2 *
3 * sched-messaging.c
4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms
6 *
7 * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au>
8 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
9 *
10 */
11
12#include "../perf.h"
13#include "../util/util.h"
14#include "../util/parse-options.h"
15#include "../builtin.h"
16#include "bench.h"
17
18/* Test groups of 20 processes spraying to 20 receivers */
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <sys/poll.h>
30#include <limits.h>
31
32#define DATASIZE 100
33
34static int use_pipes = 0;
35static unsigned int loops = 100;
36static unsigned int thread_mode = 0;
37static unsigned int num_groups = 10;
38
39struct sender_context {
40 unsigned int num_fds;
41 int ready_out;
42 int wakefd;
43 int out_fds[0];
44};
45
46struct receiver_context {
47 unsigned int num_packets;
48 int in_fds[2];
49 int ready_out;
50 int wakefd;
51};
52
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2])
60{
61 if (use_pipes) {
62 if (pipe(fds) == 0)
63 return;
64 } else {
65 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
66 return;
67 }
68
69 barf(use_pipes ? "pipe()" : "socketpair()");
70}
71
72/* Block until we're ready to go */
73static void ready(int ready_out, int wakefd)
74{
75 char dummy;
76 struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
77
78 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write");
81
82 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll");
85}
86
87/* Sender sprays loops messages down each file descriptor */
88static void *sender(struct sender_context *ctx)
89{
90 char data[DATASIZE];
91 unsigned int i, j;
92
93 ready(ctx->ready_out, ctx->wakefd);
94
95 /* Now pump to every receiver. */
96 for (i = 0; i < loops; i++) {
97 for (j = 0; j < ctx->num_fds; j++) {
98 int ret, done = 0;
99
100again:
101 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done);
103 if (ret < 0)
104 barf("SENDER: write");
105 done += ret;
106 if (done < DATASIZE)
107 goto again;
108 }
109 }
110
111 return NULL;
112}
113
114
115/* One receiver per fd */
116static void *receiver(struct receiver_context* ctx)
117{
118 unsigned int i;
119
120 if (!thread_mode)
121 close(ctx->in_fds[1]);
122
123 /* Wait for start... */
124 ready(ctx->ready_out, ctx->wakefd);
125
126 /* Receive them all */
127 for (i = 0; i < ctx->num_packets; i++) {
128 char data[DATASIZE];
129 int ret, done = 0;
130
131again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0)
134 barf("SERVER: read");
135 done += ret;
136 if (done < DATASIZE)
137 goto again;
138 }
139
140 return NULL;
141}
142
143static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{
145 pthread_attr_t attr;
146 pthread_t childid;
147 int err;
148
149 if (!thread_mode) {
150 /* process mode */
151 /* Fork the receiver. */
152 switch (fork()) {
153 case -1:
154 barf("fork()");
155 break;
156 case 0:
157 (*func) (ctx);
158 exit(0);
159 break;
160 default:
161 break;
162 }
163
164 return (pthread_t)0;
165 }
166
167 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:");
169
170#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize");
173#endif
174
175 err = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) {
177 fprintf(stderr, "pthread_create failed: %s (%d)\n",
178 strerror(err), err);
179 exit(-1);
180 }
181 return childid;
182}
183
184static void reap_worker(pthread_t id)
185{
186 int proc_status;
187 void *thread_status;
188
189 if (!thread_mode) {
190 /* process mode */
191 wait(&proc_status);
192 if (!WIFEXITED(proc_status))
193 exit(1);
194 } else {
195 pthread_join(id, &thread_status);
196 }
197}
198
199/* One group of senders and receivers */
200static unsigned int group(pthread_t *pth,
201 unsigned int num_fds,
202 int ready_out,
203 int wakefd)
204{
205 unsigned int i;
206 struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)
207 + num_fds * sizeof(int));
208
209 if (!snd_ctx)
210 barf("malloc()");
211
212 for (i = 0; i < num_fds; i++) {
213 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx));
215
216 if (!ctx)
217 barf("malloc()");
218
219
220 /* Create the pipe between client and server */
221 fdpair(fds);
222
223 ctx->num_packets = num_fds * loops;
224 ctx->in_fds[0] = fds[0];
225 ctx->in_fds[1] = fds[1];
226 ctx->ready_out = ready_out;
227 ctx->wakefd = wakefd;
228
229 pth[i] = create_worker(ctx, (void *)receiver);
230
231 snd_ctx->out_fds[i] = fds[1];
232 if (!thread_mode)
233 close(fds[0]);
234 }
235
236 /* Now we have all the fds, fork the senders */
237 for (i = 0; i < num_fds; i++) {
238 snd_ctx->ready_out = ready_out;
239 snd_ctx->wakefd = wakefd;
240 snd_ctx->num_fds = num_fds;
241
242 pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);
243 }
244
245 /* Close the fds we have left */
246 if (!thread_mode)
247 for (i = 0; i < num_fds; i++)
248 close(snd_ctx->out_fds[i]);
249
250 /* Return number of children to reap */
251 return num_fds * 2;
252}
253
254static const struct option options[] = {
255 OPT_BOOLEAN('p', "pipe", &use_pipes,
256 "Use pipe() instead of socketpair()"),
257 OPT_BOOLEAN('t', "thread", &thread_mode,
258 "Be multi thread instead of multi process"),
259 OPT_INTEGER('g', "group", &num_groups,
260 "Specify number of groups"),
261 OPT_INTEGER('l', "loop", &loops,
262 "Specify number of loops"),
263 OPT_END()
264};
265
266static const char * const bench_sched_message_usage[] = {
267 "perf bench sched messaging <options>",
268 NULL
269};
270
271int bench_sched_messaging(int argc, const char **argv,
272 const char *prefix __used)
273{
274 unsigned int i, total_children;
275 struct timeval start, stop, diff;
276 unsigned int num_fds = 20;
277 int readyfds[2], wakefds[2];
278 char dummy;
279 pthread_t *pth_tab;
280
281 argc = parse_options(argc, argv, options,
282 bench_sched_message_usage, 0);
283
284 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
285 if (!pth_tab)
286 barf("main:malloc()");
287
288 fdpair(readyfds);
289 fdpair(wakefds);
290
291 total_children = 0;
292 for (i = 0; i < num_groups; i++)
293 total_children += group(pth_tab+total_children, num_fds,
294 readyfds[1], wakefds[0]);
295
296 /* Wait for everyone to be ready */
297 for (i = 0; i < total_children; i++)
298 if (read(readyfds[0], &dummy, 1) != 1)
299 barf("Reading for readyfds");
300
301 gettimeofday(&start, NULL);
302
303 /* Kick them off */
304 if (write(wakefds[1], &dummy, 1) != 1)
305 barf("Writing to start them");
306
307 /* Reap them all */
308 for (i = 0; i < total_children; i++)
309 reap_worker(pth_tab[i]);
310
311 gettimeofday(&stop, NULL);
312
313 timersub(&stop, &start, &diff);
314
315 switch (bench_format) {
316 case BENCH_FORMAT_DEFAULT:
317 printf("# %d sender and receiver %s per group\n",
318 num_fds, thread_mode ? "threads" : "processes");
319 printf("# %d groups == %d %s run\n\n",
320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec,
324 (unsigned long) (diff.tv_usec/1000));
325 break;
326 case BENCH_FORMAT_SIMPLE:
327 printf("%lu.%03lu\n", diff.tv_sec,
328 (unsigned long) (diff.tv_usec/1000));
329 break;
330 default:
331 /* reaching here is something disaster */
332 fprintf(stderr, "Unknown format:%d\n", bench_format);
333 exit(1);
334 break;
335 }
336
337 return 0;
338}
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
new file mode 100644
index 000000000000..4f77c7c27640
--- /dev/null
+++ b/tools/perf/bench/sched-pipe.c
@@ -0,0 +1,127 @@
1/*
2 *
3 * sched-pipe.c
4 *
5 * pipe: Benchmark for pipe()
6 *
7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
10 *
11 */
12
13#include "../perf.h"
14#include "../util/util.h"
15#include "../util/parse-options.h"
16#include "../builtin.h"
17#include "bench.h"
18
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <signal.h>
23#include <sys/wait.h>
24#include <linux/unistd.h>
25#include <string.h>
26#include <errno.h>
27#include <assert.h>
28#include <sys/time.h>
29#include <sys/types.h>
30
31#define LOOPS_DEFAULT 1000000
32static int loops = LOOPS_DEFAULT;
33
34static const struct option options[] = {
35 OPT_INTEGER('l', "loop", &loops,
36 "Specify number of loops"),
37 OPT_END()
38};
39
40static const char * const bench_sched_pipe_usage[] = {
41 "perf bench sched pipe <options>",
42 NULL
43};
44
45int bench_sched_pipe(int argc, const char **argv,
46 const char *prefix __used)
47{
48 int pipe_1[2], pipe_2[2];
49 int m = 0, i;
50 struct timeval start, stop, diff;
51 unsigned long long result_usec = 0;
52
53 /*
54 * why does "ret" exist?
55 * discarding returned value of read(), write()
56 * causes error in building environment for perf
57 */
58 int ret, wait_stat;
59 pid_t pid, retpid;
60
61 argc = parse_options(argc, argv, options,
62 bench_sched_pipe_usage, 0);
63
64 assert(!pipe(pipe_1));
65 assert(!pipe(pipe_2));
66
67 pid = fork();
68 assert(pid >= 0);
69
70 gettimeofday(&start, NULL);
71
72 if (!pid) {
73 for (i = 0; i < loops; i++) {
74 ret = read(pipe_1[0], &m, sizeof(int));
75 ret = write(pipe_2[1], &m, sizeof(int));
76 }
77 } else {
78 for (i = 0; i < loops; i++) {
79 ret = write(pipe_1[1], &m, sizeof(int));
80 ret = read(pipe_2[0], &m, sizeof(int));
81 }
82 }
83
84 gettimeofday(&stop, NULL);
85 timersub(&stop, &start, &diff);
86
87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 } else {
91 exit(0);
92 }
93
94 switch (bench_format) {
95 case BENCH_FORMAT_DEFAULT:
96 printf("# Extecuted %d pipe operations between two tasks\n\n",
97 loops);
98
99 result_usec = diff.tv_sec * 1000000;
100 result_usec += diff.tv_usec;
101
102 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
103 diff.tv_sec,
104 (unsigned long) (diff.tv_usec/1000));
105
106 printf(" %14lf usecs/op\n",
107 (double)result_usec / (double)loops);
108 printf(" %14d ops/sec\n",
109 (int)((double)loops /
110 ((double)result_usec / (double)1000000)));
111 break;
112
113 case BENCH_FORMAT_SIMPLE:
114 printf("%lu.%03lu\n",
115 diff.tv_sec,
116 (unsigned long) (diff.tv_usec / 1000));
117 break;
118
119 default:
120 /* reaching here is something disaster */
121 fprintf(stderr, "Unknown format:%d\n", bench_format);
122 exit(1);
123 break;
124 }
125
126 return 0;
127}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1ec741615814..5ec5de995872 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,29 +19,26 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/event.h"
22#include "util/parse-options.h" 23#include "util/parse-options.h"
23#include "util/parse-events.h" 24#include "util/parse-events.h"
24#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h"
27#include "util/hist.h"
28#include "util/session.h"
25 29
26static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
27 31
28static char default_sort_order[] = "comm,symbol";
29static char *sort_order = default_sort_order;
30
31static int force; 32static int force;
32static int input;
33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
34 33
35static int full_paths; 34static int full_paths;
36 35
37static int print_line; 36static int print_line;
38 37
39static unsigned long page_size; 38struct sym_hist {
40static unsigned long mmap_window = 32; 39 u64 sum;
41 40 u64 ip[0];
42static struct rb_root threads; 41};
43static struct thread *last_match;
44
45 42
46struct sym_ext { 43struct sym_ext {
47 struct rb_node node; 44 struct rb_node node;
@@ -49,636 +46,157 @@ struct sym_ext {
49 char *path; 46 char *path;
50}; 47};
51 48
52/* 49struct sym_priv {
53 * histogram, sorted on item, collects counts 50 struct sym_hist *hist;
54 */ 51 struct sym_ext *ext;
55
56static struct rb_root hist;
57
58struct hist_entry {
59 struct rb_node rb_node;
60
61 struct thread *thread;
62 struct map *map;
63 struct dso *dso;
64 struct symbol *sym;
65 u64 ip;
66 char level;
67
68 uint32_t count;
69};
70
71/*
72 * configurable sorting bits
73 */
74
75struct sort_entry {
76 struct list_head list;
77
78 const char *header;
79
80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
82 size_t (*print)(FILE *fp, struct hist_entry *);
83};
84
85/* --sort pid */
86
87static int64_t
88sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
89{
90 return right->thread->pid - left->thread->pid;
91}
92
93static size_t
94sort__thread_print(FILE *fp, struct hist_entry *self)
95{
96 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
97}
98
99static struct sort_entry sort_thread = {
100 .header = " Command: Pid",
101 .cmp = sort__thread_cmp,
102 .print = sort__thread_print,
103};
104
105/* --sort comm */
106
107static int64_t
108sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
109{
110 return right->thread->pid - left->thread->pid;
111}
112
113static int64_t
114sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
115{
116 char *comm_l = left->thread->comm;
117 char *comm_r = right->thread->comm;
118
119 if (!comm_l || !comm_r) {
120 if (!comm_l && !comm_r)
121 return 0;
122 else if (!comm_l)
123 return -1;
124 else
125 return 1;
126 }
127
128 return strcmp(comm_l, comm_r);
129}
130
131static size_t
132sort__comm_print(FILE *fp, struct hist_entry *self)
133{
134 return fprintf(fp, "%16s", self->thread->comm);
135}
136
137static struct sort_entry sort_comm = {
138 .header = " Command",
139 .cmp = sort__comm_cmp,
140 .collapse = sort__comm_collapse,
141 .print = sort__comm_print,
142};
143
144/* --sort dso */
145
146static int64_t
147sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
148{
149 struct dso *dso_l = left->dso;
150 struct dso *dso_r = right->dso;
151
152 if (!dso_l || !dso_r) {
153 if (!dso_l && !dso_r)
154 return 0;
155 else if (!dso_l)
156 return -1;
157 else
158 return 1;
159 }
160
161 return strcmp(dso_l->name, dso_r->name);
162}
163
164static size_t
165sort__dso_print(FILE *fp, struct hist_entry *self)
166{
167 if (self->dso)
168 return fprintf(fp, "%-25s", self->dso->name);
169
170 return fprintf(fp, "%016llx ", (u64)self->ip);
171}
172
173static struct sort_entry sort_dso = {
174 .header = "Shared Object ",
175 .cmp = sort__dso_cmp,
176 .print = sort__dso_print,
177};
178
179/* --sort symbol */
180
181static int64_t
182sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183{
184 u64 ip_l, ip_r;
185
186 if (left->sym == right->sym)
187 return 0;
188
189 ip_l = left->sym ? left->sym->start : left->ip;
190 ip_r = right->sym ? right->sym->start : right->ip;
191
192 return (int64_t)(ip_r - ip_l);
193}
194
195static size_t
196sort__sym_print(FILE *fp, struct hist_entry *self)
197{
198 size_t ret = 0;
199
200 if (verbose)
201 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
202
203 if (self->sym) {
204 ret += fprintf(fp, "[%c] %s",
205 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
206 } else {
207 ret += fprintf(fp, "%#016llx", (u64)self->ip);
208 }
209
210 return ret;
211}
212
213static struct sort_entry sort_sym = {
214 .header = "Symbol",
215 .cmp = sort__sym_cmp,
216 .print = sort__sym_print,
217};
218
219static int sort__need_collapse = 0;
220
221struct sort_dimension {
222 const char *name;
223 struct sort_entry *entry;
224 int taken;
225}; 52};
226 53
227static struct sort_dimension sort_dimensions[] = { 54static const char *sym_hist_filter;
228 { .name = "pid", .entry = &sort_thread, },
229 { .name = "comm", .entry = &sort_comm, },
230 { .name = "dso", .entry = &sort_dso, },
231 { .name = "symbol", .entry = &sort_sym, },
232};
233
234static LIST_HEAD(hist_entry__sort_list);
235
236static int sort_dimension__add(char *tok)
237{
238 unsigned int i;
239
240 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
241 struct sort_dimension *sd = &sort_dimensions[i];
242
243 if (sd->taken)
244 continue;
245
246 if (strncasecmp(tok, sd->name, strlen(tok)))
247 continue;
248
249 if (sd->entry->collapse)
250 sort__need_collapse = 1;
251
252 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
253 sd->taken = 1;
254
255 return 0;
256 }
257
258 return -ESRCH;
259}
260
261static int64_t
262hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
263{
264 struct sort_entry *se;
265 int64_t cmp = 0;
266
267 list_for_each_entry(se, &hist_entry__sort_list, list) {
268 cmp = se->cmp(left, right);
269 if (cmp)
270 break;
271 }
272
273 return cmp;
274}
275 55
276static int64_t 56static int sym__alloc_hist(struct symbol *self)
277hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
278{ 57{
279 struct sort_entry *se; 58 struct sym_priv *priv = symbol__priv(self);
280 int64_t cmp = 0; 59 const int size = (sizeof(*priv->hist) +
60 (self->end - self->start) * sizeof(u64));
281 61
282 list_for_each_entry(se, &hist_entry__sort_list, list) { 62 priv->hist = zalloc(size);
283 int64_t (*f)(struct hist_entry *, struct hist_entry *); 63 return priv->hist == NULL ? -1 : 0;
284
285 f = se->collapse ?: se->cmp;
286
287 cmp = f(left, right);
288 if (cmp)
289 break;
290 }
291
292 return cmp;
293} 64}
294 65
295/* 66/*
296 * collect histogram counts 67 * collect histogram counts
297 */ 68 */
298static void hist_hit(struct hist_entry *he, u64 ip) 69static int annotate__hist_hit(struct hist_entry *he, u64 ip)
299{ 70{
300 unsigned int sym_size, offset; 71 unsigned int sym_size, offset;
301 struct symbol *sym = he->sym; 72 struct symbol *sym = he->sym;
73 struct sym_priv *priv;
74 struct sym_hist *h;
302 75
303 he->count++; 76 he->count++;
304 77
305 if (!sym || !sym->hist) 78 if (!sym || !he->map)
306 return; 79 return 0;
80
81 priv = symbol__priv(sym);
82 if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
83 return -ENOMEM;
307 84
308 sym_size = sym->end - sym->start; 85 sym_size = sym->end - sym->start;
309 offset = ip - sym->start; 86 offset = ip - sym->start;
310 87
88 pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip));
89
311 if (offset >= sym_size) 90 if (offset >= sym_size)
312 return; 91 return 0;
313 92
314 sym->hist_sum++; 93 h = priv->hist;
315 sym->hist[offset]++; 94 h->sum++;
95 h->ip[offset]++;
316 96
317 if (verbose >= 3) 97 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start,
318 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 98 he->sym->name, ip, ip - he->sym->start, h->ip[offset]);
319 (void *)(unsigned long)he->sym->start, 99 return 0;
320 he->sym->name,
321 (void *)(unsigned long)ip, ip - he->sym->start,
322 sym->hist[offset]);
323} 100}
324 101
325static int 102static int perf_session__add_hist_entry(struct perf_session *self,
326hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 103 struct addr_location *al, u64 count)
327 struct symbol *sym, u64 ip, char level)
328{ 104{
329 struct rb_node **p = &hist.rb_node; 105 bool hit;
330 struct rb_node *parent = NULL;
331 struct hist_entry *he; 106 struct hist_entry *he;
332 struct hist_entry entry = {
333 .thread = thread,
334 .map = map,
335 .dso = dso,
336 .sym = sym,
337 .ip = ip,
338 .level = level,
339 .count = 1,
340 };
341 int cmp;
342
343 while (*p != NULL) {
344 parent = *p;
345 he = rb_entry(parent, struct hist_entry, rb_node);
346
347 cmp = hist_entry__cmp(&entry, he);
348
349 if (!cmp) {
350 hist_hit(he, ip);
351 107
352 return 0; 108 if (sym_hist_filter != NULL &&
109 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
110 /* We're only interested in a symbol named sym_hist_filter */
111 if (al->sym != NULL) {
112 rb_erase(&al->sym->rb_node,
113 &al->map->dso->symbols[al->map->type]);
114 symbol__delete(al->sym);
353 } 115 }
354 116 return 0;
355 if (cmp < 0)
356 p = &(*p)->rb_left;
357 else
358 p = &(*p)->rb_right;
359 } 117 }
360 118
361 he = malloc(sizeof(*he)); 119 he = __perf_session__add_hist_entry(self, al, NULL, count, &hit);
362 if (!he) 120 if (he == NULL)
363 return -ENOMEM; 121 return -ENOMEM;
364 *he = entry;
365 rb_link_node(&he->rb_node, parent, p);
366 rb_insert_color(&he->rb_node, &hist);
367
368 return 0;
369}
370
371static void hist_entry__free(struct hist_entry *he)
372{
373 free(he);
374}
375
376/*
377 * collapse the histogram
378 */
379
380static struct rb_root collapse_hists;
381
382static void collapse__insert_entry(struct hist_entry *he)
383{
384 struct rb_node **p = &collapse_hists.rb_node;
385 struct rb_node *parent = NULL;
386 struct hist_entry *iter;
387 int64_t cmp;
388
389 while (*p != NULL) {
390 parent = *p;
391 iter = rb_entry(parent, struct hist_entry, rb_node);
392
393 cmp = hist_entry__collapse(iter, he);
394
395 if (!cmp) {
396 iter->count += he->count;
397 hist_entry__free(he);
398 return;
399 }
400
401 if (cmp < 0)
402 p = &(*p)->rb_left;
403 else
404 p = &(*p)->rb_right;
405 }
406
407 rb_link_node(&he->rb_node, parent, p);
408 rb_insert_color(&he->rb_node, &collapse_hists);
409}
410
411static void collapse__resort(void)
412{
413 struct rb_node *next;
414 struct hist_entry *n;
415
416 if (!sort__need_collapse)
417 return;
418
419 next = rb_first(&hist);
420 while (next) {
421 n = rb_entry(next, struct hist_entry, rb_node);
422 next = rb_next(&n->rb_node);
423
424 rb_erase(&n->rb_node, &hist);
425 collapse__insert_entry(n);
426 }
427}
428
429/*
430 * reverse the map, sort on count.
431 */
432
433static struct rb_root output_hists;
434
435static void output__insert_entry(struct hist_entry *he)
436{
437 struct rb_node **p = &output_hists.rb_node;
438 struct rb_node *parent = NULL;
439 struct hist_entry *iter;
440
441 while (*p != NULL) {
442 parent = *p;
443 iter = rb_entry(parent, struct hist_entry, rb_node);
444
445 if (he->count > iter->count)
446 p = &(*p)->rb_left;
447 else
448 p = &(*p)->rb_right;
449 }
450 122
451 rb_link_node(&he->rb_node, parent, p); 123 return annotate__hist_hit(he, al->addr);
452 rb_insert_color(&he->rb_node, &output_hists);
453} 124}
454 125
455static void output__resort(void) 126static int process_sample_event(event_t *event, struct perf_session *session)
456{ 127{
457 struct rb_node *next; 128 struct addr_location al;
458 struct hist_entry *n;
459 struct rb_root *tree = &hist;
460
461 if (sort__need_collapse)
462 tree = &collapse_hists;
463
464 next = rb_first(tree);
465
466 while (next) {
467 n = rb_entry(next, struct hist_entry, rb_node);
468 next = rb_next(&n->rb_node);
469
470 rb_erase(&n->rb_node, tree);
471 output__insert_entry(n);
472 }
473}
474 129
475static unsigned long total = 0, 130 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
476 total_mmap = 0, 131 event->ip.pid, event->ip.ip);
477 total_comm = 0,
478 total_fork = 0,
479 total_unknown = 0;
480 132
481static int 133 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
482process_sample_event(event_t *event, unsigned long offset, unsigned long head) 134 pr_warning("problem processing %d event, skipping it.\n",
483{ 135 event->header.type);
484 char level;
485 int show = 0;
486 struct dso *dso = NULL;
487 struct thread *thread;
488 u64 ip = event->ip.ip;
489 struct map *map = NULL;
490
491 thread = threads__findnew(event->ip.pid, &threads, &last_match);
492
493 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
494 (void *)(offset + head),
495 (void *)(long)(event->header.size),
496 event->header.misc,
497 event->ip.pid,
498 (void *)(long)ip);
499
500 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
501
502 if (thread == NULL) {
503 fprintf(stderr, "problem processing %d event, skipping it.\n",
504 event->header.type);
505 return -1; 136 return -1;
506 } 137 }
507 138
508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 139 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
509 show = SHOW_KERNEL; 140 pr_warning("problem incrementing symbol count, "
510 level = 'k'; 141 "skipping event\n");
511 142 return -1;
512 dso = kernel_dso;
513
514 dump_printf(" ...... dso: %s\n", dso->name);
515
516 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
517
518 show = SHOW_USER;
519 level = '.';
520
521 map = thread__find_map(thread, ip);
522 if (map != NULL) {
523 ip = map->map_ip(map, ip);
524 dso = map->dso;
525 } else {
526 /*
527 * If this is outside of all known maps,
528 * and is a negative address, try to look it
529 * up in the kernel dso, as it might be a
530 * vsyscall (which executes in user-mode):
531 */
532 if ((long long)ip < 0)
533 dso = kernel_dso;
534 }
535 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
536
537 } else {
538 show = SHOW_HV;
539 level = 'H';
540 dump_printf(" ...... dso: [hypervisor]\n");
541 }
542
543 if (show & show_mask) {
544 struct symbol *sym = NULL;
545
546 if (dso)
547 sym = dso->find_symbol(dso, ip);
548
549 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
550 fprintf(stderr,
551 "problem incrementing symbol count, skipping event\n");
552 return -1;
553 }
554 } 143 }
555 total++;
556 144
557 return 0; 145 return 0;
558} 146}
559 147
560static int 148struct objdump_line {
561process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 149 struct list_head node;
562{ 150 s64 offset;
563 struct thread *thread; 151 char *line;
564 struct map *map = map__new(&event->mmap, NULL, 0); 152};
565
566 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
567
568 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
569 (void *)(offset + head),
570 (void *)(long)(event->header.size),
571 event->mmap.pid,
572 (void *)(long)event->mmap.start,
573 (void *)(long)event->mmap.len,
574 (void *)(long)event->mmap.pgoff,
575 event->mmap.filename);
576
577 if (thread == NULL || map == NULL) {
578 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
579 return 0;
580 }
581
582 thread__insert_map(thread, map);
583 total_mmap++;
584
585 return 0;
586}
587 153
588static int 154static struct objdump_line *objdump_line__new(s64 offset, char *line)
589process_comm_event(event_t *event, unsigned long offset, unsigned long head)
590{ 155{
591 struct thread *thread; 156 struct objdump_line *self = malloc(sizeof(*self));
592 157
593 thread = threads__findnew(event->comm.pid, &threads, &last_match); 158 if (self != NULL) {
594 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 159 self->offset = offset;
595 (void *)(offset + head), 160 self->line = line;
596 (void *)(long)(event->header.size),
597 event->comm.comm, event->comm.pid);
598
599 if (thread == NULL ||
600 thread__set_comm(thread, event->comm.comm)) {
601 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
602 return -1;
603 } 161 }
604 total_comm++;
605 162
606 return 0; 163 return self;
607} 164}
608 165
609static int 166static void objdump_line__free(struct objdump_line *self)
610process_fork_event(event_t *event, unsigned long offset, unsigned long head)
611{ 167{
612 struct thread *thread; 168 free(self->line);
613 struct thread *parent; 169 free(self);
614
615 thread = threads__findnew(event->fork.pid, &threads, &last_match);
616 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
617 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
618 (void *)(offset + head),
619 (void *)(long)(event->header.size),
620 event->fork.pid, event->fork.ppid);
621
622 /*
623 * A thread clone will have the same PID for both
624 * parent and child.
625 */
626 if (thread == parent)
627 return 0;
628
629 if (!thread || !parent || thread__fork(thread, parent)) {
630 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
631 return -1;
632 }
633 total_fork++;
634
635 return 0;
636} 170}
637 171
638static int 172static void objdump__add_line(struct list_head *head, struct objdump_line *line)
639process_event(event_t *event, unsigned long offset, unsigned long head)
640{ 173{
641 switch (event->header.type) { 174 list_add_tail(&line->node, head);
642 case PERF_RECORD_SAMPLE: 175}
643 return process_sample_event(event, offset, head);
644
645 case PERF_RECORD_MMAP:
646 return process_mmap_event(event, offset, head);
647
648 case PERF_RECORD_COMM:
649 return process_comm_event(event, offset, head);
650
651 case PERF_RECORD_FORK:
652 return process_fork_event(event, offset, head);
653 /*
654 * We dont process them right now but they are fine:
655 */
656
657 case PERF_RECORD_THROTTLE:
658 case PERF_RECORD_UNTHROTTLE:
659 return 0;
660 176
661 default: 177static struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
662 return -1; 178 struct objdump_line *pos)
663 } 179{
180 list_for_each_entry_continue(pos, head, node)
181 if (pos->offset >= 0)
182 return pos;
664 183
665 return 0; 184 return NULL;
666} 185}
667 186
668static int 187static int parse_line(FILE *file, struct hist_entry *he,
669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len) 188 struct list_head *head)
670{ 189{
190 struct symbol *sym = he->sym;
191 struct objdump_line *objdump_line;
671 char *line = NULL, *tmp, *tmp2; 192 char *line = NULL, *tmp, *tmp2;
672 static const char *prev_line;
673 static const char *prev_color;
674 unsigned int offset;
675 size_t line_len; 193 size_t line_len;
676 s64 line_ip; 194 s64 line_ip, offset = -1;
677 int ret;
678 char *c; 195 char *c;
679 196
680 if (getline(&line, &line_len, file) < 0) 197 if (getline(&line, &line_len, file) < 0)
681 return -1; 198 return -1;
199
682 if (!line) 200 if (!line)
683 return -1; 201 return -1;
684 202
@@ -687,8 +205,6 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
687 *c = 0; 205 *c = 0;
688 206
689 line_ip = -1; 207 line_ip = -1;
690 offset = 0;
691 ret = -2;
692 208
693 /* 209 /*
694 * Strip leading spaces: 210 * Strip leading spaces:
@@ -710,21 +226,53 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
710 } 226 }
711 227
712 if (line_ip != -1) { 228 if (line_ip != -1) {
229 u64 start = map__rip_2objdump(he->map, sym->start);
230 offset = line_ip - start;
231 }
232
233 objdump_line = objdump_line__new(offset, line);
234 if (objdump_line == NULL) {
235 free(line);
236 return -1;
237 }
238 objdump__add_line(head, objdump_line);
239
240 return 0;
241}
242
243static int objdump_line__print(struct objdump_line *self,
244 struct list_head *head,
245 struct hist_entry *he, u64 len)
246{
247 struct symbol *sym = he->sym;
248 static const char *prev_line;
249 static const char *prev_color;
250
251 if (self->offset != -1) {
713 const char *path = NULL; 252 const char *path = NULL;
714 unsigned int hits = 0; 253 unsigned int hits = 0;
715 double percent = 0.0; 254 double percent = 0.0;
716 const char *color; 255 const char *color;
717 struct sym_ext *sym_ext = sym->priv; 256 struct sym_priv *priv = symbol__priv(sym);
718 257 struct sym_ext *sym_ext = priv->ext;
719 offset = line_ip - start; 258 struct sym_hist *h = priv->hist;
720 if (offset < len) 259 s64 offset = self->offset;
721 hits = sym->hist[offset]; 260 struct objdump_line *next = objdump__get_next_ip_line(head, self);
261
262 while (offset < (s64)len &&
263 (next == NULL || offset < next->offset)) {
264 if (sym_ext) {
265 if (path == NULL)
266 path = sym_ext[offset].path;
267 percent += sym_ext[offset].percent;
268 } else
269 hits += h->ip[offset];
270
271 ++offset;
272 }
722 273
723 if (offset < len && sym_ext) { 274 if (sym_ext == NULL && h->sum)
724 path = sym_ext[offset].path; 275 percent = 100.0 * hits / h->sum;
725 percent = sym_ext[offset].percent;
726 } else if (sym->hist_sum)
727 percent = 100.0 * hits / sym->hist_sum;
728 276
729 color = get_percent_color(percent); 277 color = get_percent_color(percent);
730 278
@@ -744,12 +292,12 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
744 292
745 color_fprintf(stdout, color, " %7.2f", percent); 293 color_fprintf(stdout, color, " %7.2f", percent);
746 printf(" : "); 294 printf(" : ");
747 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
748 } else { 296 } else {
749 if (!*line) 297 if (!*self->line)
750 printf(" :\n"); 298 printf(" :\n");
751 else 299 else
752 printf(" : %s\n", line); 300 printf(" : %s\n", self->line);
753 } 301 }
754 302
755 return 0; 303 return 0;
@@ -777,9 +325,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
777 rb_insert_color(&sym_ext->node, &root_sym_ext); 325 rb_insert_color(&sym_ext->node, &root_sym_ext);
778} 326}
779 327
780static void free_source_line(struct symbol *sym, int len) 328static void free_source_line(struct hist_entry *he, int len)
781{ 329{
782 struct sym_ext *sym_ext = sym->priv; 330 struct sym_priv *priv = symbol__priv(he->sym);
331 struct sym_ext *sym_ext = priv->ext;
783 int i; 332 int i;
784 333
785 if (!sym_ext) 334 if (!sym_ext)
@@ -789,26 +338,30 @@ static void free_source_line(struct symbol *sym, int len)
789 free(sym_ext[i].path); 338 free(sym_ext[i].path);
790 free(sym_ext); 339 free(sym_ext);
791 340
792 sym->priv = NULL; 341 priv->ext = NULL;
793 root_sym_ext = RB_ROOT; 342 root_sym_ext = RB_ROOT;
794} 343}
795 344
796/* Get the filename:line for the colored entries */ 345/* Get the filename:line for the colored entries */
797static void 346static void
798get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 347get_source_line(struct hist_entry *he, int len, const char *filename)
799{ 348{
349 struct symbol *sym = he->sym;
350 u64 start;
800 int i; 351 int i;
801 char cmd[PATH_MAX * 2]; 352 char cmd[PATH_MAX * 2];
802 struct sym_ext *sym_ext; 353 struct sym_ext *sym_ext;
354 struct sym_priv *priv = symbol__priv(sym);
355 struct sym_hist *h = priv->hist;
803 356
804 if (!sym->hist_sum) 357 if (!h->sum)
805 return; 358 return;
806 359
807 sym->priv = calloc(len, sizeof(struct sym_ext)); 360 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
808 if (!sym->priv) 361 if (!priv->ext)
809 return; 362 return;
810 363
811 sym_ext = sym->priv; 364 start = he->map->unmap_ip(he->map, sym->start);
812 365
813 for (i = 0; i < len; i++) { 366 for (i = 0; i < len; i++) {
814 char *path = NULL; 367 char *path = NULL;
@@ -816,7 +369,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
816 u64 offset; 369 u64 offset;
817 FILE *fp; 370 FILE *fp;
818 371
819 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 372 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
820 if (sym_ext[i].percent <= 0.5) 373 if (sym_ext[i].percent <= 0.5)
821 continue; 374 continue;
822 375
@@ -870,33 +423,48 @@ static void print_summary(const char *filename)
870 } 423 }
871} 424}
872 425
873static void annotate_sym(struct dso *dso, struct symbol *sym) 426static void hist_entry__print_hits(struct hist_entry *self)
427{
428 struct symbol *sym = self->sym;
429 struct sym_priv *priv = symbol__priv(sym);
430 struct sym_hist *h = priv->hist;
431 u64 len = sym->end - sym->start, offset;
432
433 for (offset = 0; offset < len; ++offset)
434 if (h->ip[offset] != 0)
435 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
436 sym->start + offset, h->ip[offset]);
437 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
438}
439
440static void annotate_sym(struct hist_entry *he)
874{ 441{
875 const char *filename = dso->name, *d_filename; 442 struct map *map = he->map;
876 u64 start, end, len; 443 struct dso *dso = map->dso;
444 struct symbol *sym = he->sym;
445 const char *filename = dso->long_name, *d_filename;
446 u64 len;
877 char command[PATH_MAX*2]; 447 char command[PATH_MAX*2];
878 FILE *file; 448 FILE *file;
449 LIST_HEAD(head);
450 struct objdump_line *pos, *n;
879 451
880 if (!filename) 452 if (!filename)
881 return; 453 return;
882 if (sym->module) 454
883 filename = sym->module->path; 455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
884 else if (dso == kernel_dso) 456 filename, sym->name, map->unmap_ip(map, sym->start),
885 filename = vmlinux_name; 457 map->unmap_ip(map, sym->end));
886 458
887 start = sym->obj_start;
888 if (!start)
889 start = sym->start;
890 if (full_paths) 459 if (full_paths)
891 d_filename = filename; 460 d_filename = filename;
892 else 461 else
893 d_filename = basename(filename); 462 d_filename = basename(filename);
894 463
895 end = start + sym->end - sym->start + 1;
896 len = sym->end - sym->start; 464 len = sym->end - sym->start;
897 465
898 if (print_line) { 466 if (print_line) {
899 get_source_line(sym, start, len, filename); 467 get_source_line(he, len, filename);
900 print_summary(filename); 468 print_summary(filename);
901 } 469 }
902 470
@@ -905,10 +473,13 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
905 printf("------------------------------------------------\n"); 473 printf("------------------------------------------------\n");
906 474
907 if (verbose >= 2) 475 if (verbose >= 2)
908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 476 printf("annotating [%p] %30s : [%p] %30s\n",
477 dso, dso->long_name, sym, sym->name);
909 478
910 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 479 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
911 (u64)start, (u64)end, filename, filename); 480 map__rip_2objdump(map, sym->start),
481 map__rip_2objdump(map, sym->end),
482 filename, filename);
912 483
913 if (verbose >= 3) 484 if (verbose >= 3)
914 printf("doing: %s\n", command); 485 printf("doing: %s\n", command);
@@ -918,159 +489,88 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
918 return; 489 return;
919 490
920 while (!feof(file)) { 491 while (!feof(file)) {
921 if (parse_line(file, sym, start, len) < 0) 492 if (parse_line(file, he, &head) < 0)
922 break; 493 break;
923 } 494 }
924 495
925 pclose(file); 496 pclose(file);
926 if (print_line)
927 free_source_line(sym, len);
928}
929 497
930static void find_annotations(void) 498 if (verbose)
931{ 499 hist_entry__print_hits(he);
932 struct rb_node *nd;
933 struct dso *dso;
934 int count = 0;
935
936 list_for_each_entry(dso, &dsos, node) {
937
938 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
939 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
940 500
941 if (sym->hist) { 501 list_for_each_entry_safe(pos, n, &head, node) {
942 annotate_sym(dso, sym); 502 objdump_line__print(pos, &head, he, len);
943 count++; 503 list_del(&pos->node);
944 } 504 objdump_line__free(pos);
945 }
946 } 505 }
947 506
948 if (!count) 507 if (print_line)
949 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter); 508 free_source_line(he, len);
950} 509}
951 510
952static int __cmd_annotate(void) 511static void perf_session__find_annotations(struct perf_session *self)
953{ 512{
954 int ret, rc = EXIT_FAILURE; 513 struct rb_node *nd;
955 unsigned long offset = 0;
956 unsigned long head = 0;
957 struct stat input_stat;
958 event_t *event;
959 uint32_t size;
960 char *buf;
961
962 register_idle_thread(&threads, &last_match);
963
964 input = open(input_name, O_RDONLY);
965 if (input < 0) {
966 perror("failed to open file");
967 exit(-1);
968 }
969
970 ret = fstat(input, &input_stat);
971 if (ret < 0) {
972 perror("failed to stat file");
973 exit(-1);
974 }
975
976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
978 exit(-1);
979 }
980
981 if (!input_stat.st_size) {
982 fprintf(stderr, "zero-sized file, nothing to do!\n");
983 exit(0);
984 }
985
986 if (load_kernel() < 0) {
987 perror("failed to load kernel symbols");
988 return EXIT_FAILURE;
989 }
990
991remap:
992 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
993 MAP_SHARED, input, offset);
994 if (buf == MAP_FAILED) {
995 perror("failed to mmap file");
996 exit(-1);
997 }
998
999more:
1000 event = (event_t *)(buf + head);
1001
1002 size = event->header.size;
1003 if (!size)
1004 size = 8;
1005
1006 if (head + event->header.size >= page_size * mmap_window) {
1007 unsigned long shift = page_size * (head / page_size);
1008 int munmap_ret;
1009
1010 munmap_ret = munmap(buf, page_size * mmap_window);
1011 assert(munmap_ret == 0);
1012
1013 offset += shift;
1014 head -= shift;
1015 goto remap;
1016 }
1017
1018 size = event->header.size;
1019
1020 dump_printf("%p [%p]: event: %d\n",
1021 (void *)(offset + head),
1022 (void *)(long)event->header.size,
1023 event->header.type);
1024 514
1025 if (!size || process_event(event, offset, head) < 0) { 515 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
516 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
517 struct sym_priv *priv;
1026 518
1027 dump_printf("%p [%p]: skipping unknown header type: %d\n", 519 if (he->sym == NULL)
1028 (void *)(offset + head), 520 continue;
1029 (void *)(long)(event->header.size),
1030 event->header.type);
1031 521
1032 total_unknown++; 522 priv = symbol__priv(he->sym);
523 if (priv->hist == NULL)
524 continue;
1033 525
526 annotate_sym(he);
1034 /* 527 /*
1035 * assume we lost track of the stream, check alignment, and 528 * Since we have a hist_entry per IP for the same symbol, free
1036 * increment a single u64 in the hope to catch on again 'soon'. 529 * he->sym->hist to signal we already processed this symbol.
1037 */ 530 */
1038 531 free(priv->hist);
1039 if (unlikely(head & 7)) 532 priv->hist = NULL;
1040 head &= ~7ULL;
1041
1042 size = 8;
1043 } 533 }
534}
1044 535
1045 head += size; 536static struct perf_event_ops event_ops = {
537 .sample = process_sample_event,
538 .mmap = event__process_mmap,
539 .comm = event__process_comm,
540 .fork = event__process_task,
541};
1046 542
1047 if (offset + head < (unsigned long)input_stat.st_size) 543static int __cmd_annotate(void)
1048 goto more; 544{
545 int ret;
546 struct perf_session *session;
1049 547
1050 rc = EXIT_SUCCESS; 548 session = perf_session__new(input_name, O_RDONLY, force);
1051 close(input); 549 if (session == NULL)
550 return -ENOMEM;
1052 551
1053 dump_printf(" IP events: %10ld\n", total); 552 ret = perf_session__process_events(session, &event_ops);
1054 dump_printf(" mmap events: %10ld\n", total_mmap); 553 if (ret)
1055 dump_printf(" comm events: %10ld\n", total_comm); 554 goto out_delete;
1056 dump_printf(" fork events: %10ld\n", total_fork);
1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1058 555
1059 if (dump_trace) 556 if (dump_trace) {
1060 return 0; 557 event__print_totals();
558 goto out_delete;
559 }
1061 560
1062 if (verbose >= 3) 561 if (verbose > 3)
1063 threads__fprintf(stdout, &threads); 562 perf_session__fprintf(session, stdout);
1064 563
1065 if (verbose >= 2) 564 if (verbose > 2)
1066 dsos__fprintf(stdout); 565 dsos__fprintf(stdout);
1067 566
1068 collapse__resort(); 567 perf_session__collapse_resort(session);
1069 output__resort(); 568 perf_session__output_resort(session, session->event_total[0]);
569 perf_session__find_annotations(session);
570out_delete:
571 perf_session__delete(session);
1070 572
1071 find_annotations(); 573 return ret;
1072
1073 return rc;
1074} 574}
1075 575
1076static const char * const annotate_usage[] = { 576static const char * const annotate_usage[] = {
@@ -1088,8 +588,9 @@ static const struct option options[] = {
1088 "be more verbose (show symbol address, etc)"), 588 "be more verbose (show symbol address, etc)"),
1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 589 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1090 "dump raw trace in ASCII"), 590 "dump raw trace in ASCII"),
1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 591 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1092 OPT_BOOLEAN('m', "modules", &modules, 592 "file", "vmlinux pathname"),
593 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1093 "load module symbols - WARNING: use only with -k and LIVE kernel"), 594 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1094 OPT_BOOLEAN('l', "print-line", &print_line, 595 OPT_BOOLEAN('l', "print-line", &print_line,
1095 "print matching source lines (may be slow)"), 596 "print matching source lines (may be slow)"),
@@ -1098,30 +599,17 @@ static const struct option options[] = {
1098 OPT_END() 599 OPT_END()
1099}; 600};
1100 601
1101static void setup_sorting(void)
1102{
1103 char *tmp, *tok, *str = strdup(sort_order);
1104
1105 for (tok = strtok_r(str, ", ", &tmp);
1106 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1107 if (sort_dimension__add(tok) < 0) {
1108 error("Unknown --sort key: `%s'", tok);
1109 usage_with_options(annotate_usage, options);
1110 }
1111 }
1112
1113 free(str);
1114}
1115
1116int cmd_annotate(int argc, const char **argv, const char *prefix __used) 602int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1117{ 603{
1118 symbol__init(); 604 argc = parse_options(argc, argv, options, annotate_usage, 0);
1119 605
1120 page_size = getpagesize(); 606 symbol_conf.priv_size = sizeof(struct sym_priv);
607 symbol_conf.try_vmlinux_path = true;
1121 608
1122 argc = parse_options(argc, argv, options, annotate_usage, 0); 609 if (symbol__init() < 0)
610 return -1;
1123 611
1124 setup_sorting(); 612 setup_sorting(annotate_usage, options);
1125 613
1126 if (argc) { 614 if (argc) {
1127 /* 615 /*
@@ -1134,10 +622,12 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1134 sym_hist_filter = argv[0]; 622 sym_hist_filter = argv[0];
1135 } 623 }
1136 624
1137 if (!sym_hist_filter)
1138 usage_with_options(annotate_usage, options);
1139
1140 setup_pager(); 625 setup_pager();
1141 626
627 if (field_sep && *field_sep == '.') {
628 pr_err("'.' is the only non valid --field-separator argument\n");
629 return -1;
630 }
631
1142 return __cmd_annotate(); 632 return __cmd_annotate();
1143} 633}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
new file mode 100644
index 000000000000..46996774e559
--- /dev/null
+++ b/tools/perf/builtin-bench.c
@@ -0,0 +1,245 @@
1/*
2 *
3 * builtin-bench.c
4 *
5 * General benchmarking subsystem provided by perf
6 *
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8 *
9 */
10
11/*
12 *
13 * Available subsystem list:
14 * sched ... scheduler and IPC mechanism
15 * mem ... memory access performance
16 *
17 */
18
19#include "perf.h"
20#include "util/util.h"
21#include "util/parse-options.h"
22#include "builtin.h"
23#include "bench/bench.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29struct bench_suite {
30 const char *name;
31 const char *summary;
32 int (*fn)(int, const char **, const char *);
33};
34 \
35/* sentinel: easy for help */
36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
37
38static struct bench_suite sched_suites[] = {
39 { "messaging",
40 "Benchmark for scheduler and IPC mechanisms",
41 bench_sched_messaging },
42 { "pipe",
43 "Flood of communication over pipe() between two processes",
44 bench_sched_pipe },
45 suite_all,
46 { NULL,
47 NULL,
48 NULL }
49};
50
51static struct bench_suite mem_suites[] = {
52 { "memcpy",
53 "Simple memory copy in various ways",
54 bench_mem_memcpy },
55 suite_all,
56 { NULL,
57 NULL,
58 NULL }
59};
60
61struct bench_subsys {
62 const char *name;
63 const char *summary;
64 struct bench_suite *suites;
65};
66
67static struct bench_subsys subsystems[] = {
68 { "sched",
69 "scheduler and IPC mechanism",
70 sched_suites },
71 { "mem",
72 "memory access performance",
73 mem_suites },
74 { "all", /* sentinel: easy for help */
75 "test all subsystem (pseudo subsystem)",
76 NULL },
77 { NULL,
78 NULL,
79 NULL }
80};
81
82static void dump_suites(int subsys_index)
83{
84 int i;
85
86 printf("# List of available suites for %s...\n\n",
87 subsystems[subsys_index].name);
88
89 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
90 printf("%14s: %s\n",
91 subsystems[subsys_index].suites[i].name,
92 subsystems[subsys_index].suites[i].summary);
93
94 printf("\n");
95 return;
96}
97
98static char *bench_format_str;
99int bench_format = BENCH_FORMAT_DEFAULT;
100
101static const struct option bench_options[] = {
102 OPT_STRING('f', "format", &bench_format_str, "default",
103 "Specify format style"),
104 OPT_END()
105};
106
107static const char * const bench_usage[] = {
108 "perf bench [<common options>] <subsystem> <suite> [<options>]",
109 NULL
110};
111
112static void print_usage(void)
113{
114 int i;
115
116 printf("Usage: \n");
117 for (i = 0; bench_usage[i]; i++)
118 printf("\t%s\n", bench_usage[i]);
119 printf("\n");
120
121 printf("# List of available subsystems...\n\n");
122
123 for (i = 0; subsystems[i].name; i++)
124 printf("%14s: %s\n",
125 subsystems[i].name, subsystems[i].summary);
126 printf("\n");
127}
128
129static int bench_str2int(char *str)
130{
131 if (!str)
132 return BENCH_FORMAT_DEFAULT;
133
134 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
135 return BENCH_FORMAT_DEFAULT;
136 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
137 return BENCH_FORMAT_SIMPLE;
138
139 return BENCH_FORMAT_UNKNOWN;
140}
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
173int cmd_bench(int argc, const char **argv, const char *prefix __used)
174{
175 int i, j, status = 0;
176
177 if (argc < 2) {
178 /* No subsystem specified. */
179 print_usage();
180 goto end;
181 }
182
183 argc = parse_options(argc, argv, bench_options, bench_usage,
184 PARSE_OPT_STOP_AT_NON_OPTION);
185
186 bench_format = bench_str2int(bench_format_str);
187 if (bench_format == BENCH_FORMAT_UNKNOWN) {
188 printf("Unknown format descriptor:%s\n", bench_format_str);
189 goto end;
190 }
191
192 if (argc < 1) {
193 print_usage();
194 goto end;
195 }
196
197 if (!strcmp(argv[0], "all")) {
198 all_subsystem();
199 goto end;
200 }
201
202 for (i = 0; subsystems[i].name; i++) {
203 if (strcmp(subsystems[i].name, argv[0]))
204 continue;
205
206 if (argc < 2) {
207 /* No suite specified. */
208 dump_suites(i);
209 goto end;
210 }
211
212 if (!strcmp(argv[1], "all")) {
213 all_suite(&subsystems[i]);
214 goto end;
215 }
216
217 for (j = 0; subsystems[i].suites[j].name; j++) {
218 if (strcmp(subsystems[i].suites[j].name, argv[1]))
219 continue;
220
221 if (bench_format == BENCH_FORMAT_DEFAULT)
222 printf("# Running %s/%s benchmark...\n",
223 subsystems[i].name,
224 subsystems[i].suites[j].name);
225 status = subsystems[i].suites[j].fn(argc - 1,
226 argv + 1, prefix);
227 goto end;
228 }
229
230 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
231 dump_suites(i);
232 goto end;
233 }
234
235 printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
236 status = 1;
237 goto end;
238 }
239
240 printf("Unknown subsystem:%s\n", argv[0]);
241 status = 1;
242
243end:
244 return status;
245}
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
new file mode 100644
index 000000000000..30a05f552c96
--- /dev/null
+++ b/tools/perf/builtin-buildid-cache.c
@@ -0,0 +1,133 @@
1/*
2 * builtin-buildid-cache.c
3 *
4 * Builtin buildid-cache command: Manages build-id cache
5 *
6 * Copyright (C) 2010, Red Hat Inc.
7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/debug.h"
13#include "util/header.h"
14#include "util/parse-options.h"
15#include "util/strlist.h"
16#include "util/symbol.h"
17
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static const struct option buildid_cache_options[] = {
26 OPT_STRING('a', "add", &add_name_list_str,
27 "file list", "file(s) to add"),
28 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
29 "file(s) to remove"),
30 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose"),
31 OPT_END()
32};
33
34static int build_id_cache__add_file(const char *filename, const char *debugdir)
35{
36 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
37 u8 build_id[BUILD_ID_SIZE];
38 int err;
39
40 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
41 pr_debug("Couldn't read a build-id in %s\n", filename);
42 return -1;
43 }
44
45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
47 if (verbose)
48 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
49 err ? "FAIL" : "Ok");
50 return err;
51}
52
53static int build_id_cache__remove_file(const char *filename __used,
54 const char *debugdir __used)
55{
56 u8 build_id[BUILD_ID_SIZE];
57 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
58
59 int err;
60
61 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
62 pr_debug("Couldn't read a build-id in %s\n", filename);
63 return -1;
64 }
65
66 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
67 err = build_id_cache__remove_s(sbuild_id, debugdir);
68 if (verbose)
69 pr_info("Removing %s %s: %s\n", sbuild_id, filename,
70 err ? "FAIL" : "Ok");
71
72 return err;
73}
74
75static int __cmd_buildid_cache(void)
76{
77 struct strlist *list;
78 struct str_node *pos;
79 char debugdir[PATH_MAX];
80
81 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
82 DEBUG_CACHE_DIR);
83
84 if (add_name_list_str) {
85 list = strlist__new(true, add_name_list_str);
86 if (list) {
87 strlist__for_each(pos, list)
88 if (build_id_cache__add_file(pos->s, debugdir)) {
89 if (errno == EEXIST) {
90 pr_debug("%s already in the cache\n",
91 pos->s);
92 continue;
93 }
94 pr_warning("Couldn't add %s: %s\n",
95 pos->s, strerror(errno));
96 }
97
98 strlist__delete(list);
99 }
100 }
101
102 if (remove_name_list_str) {
103 list = strlist__new(true, remove_name_list_str);
104 if (list) {
105 strlist__for_each(pos, list)
106 if (build_id_cache__remove_file(pos->s, debugdir)) {
107 if (errno == ENOENT) {
108 pr_debug("%s wasn't in the cache\n",
109 pos->s);
110 continue;
111 }
112 pr_warning("Couldn't remove %s: %s\n",
113 pos->s, strerror(errno));
114 }
115
116 strlist__delete(list);
117 }
118 }
119
120 return 0;
121}
122
123int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
124{
125 argc = parse_options(argc, argv, buildid_cache_options,
126 buildid_cache_usage, 0);
127
128 if (symbol__init() < 0)
129 return -1;
130
131 setup_pager();
132 return __cmd_buildid_cache();
133}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
new file mode 100644
index 000000000000..d0675c02f81e
--- /dev/null
+++ b/tools/perf/builtin-buildid-list.c
@@ -0,0 +1,60 @@
1/*
2 * builtin-buildid-list.c
3 *
4 * Builtin buildid-list command: list buildids in perf.data
5 *
6 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/build-id.h"
12#include "util/cache.h"
13#include "util/debug.h"
14#include "util/parse-options.h"
15#include "util/session.h"
16#include "util/symbol.h"
17
18static char const *input_name = "perf.data";
19static int force;
20static bool with_hits;
21
22static const char * const buildid_list_usage[] = {
23 "perf buildid-list [<options>]",
24 NULL
25};
26
27static const struct option options[] = {
28 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
29 OPT_STRING('i', "input", &input_name, "file",
30 "input file name"),
31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
32 OPT_BOOLEAN('v', "verbose", &verbose,
33 "be more verbose"),
34 OPT_END()
35};
36
37static int __cmd_buildid_list(void)
38{
39 int err = -1;
40 struct perf_session *session;
41
42 session = perf_session__new(input_name, O_RDONLY, force);
43 if (session == NULL)
44 return -1;
45
46 if (with_hits)
47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
48
49 dsos__fprintf_buildid(stdout, with_hits);
50
51 perf_session__delete(session);
52 return err;
53}
54
55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
56{
57 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
58 setup_pager();
59 return __cmd_buildid_list();
60}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
new file mode 100644
index 000000000000..18b3f505f9db
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,239 @@
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: %#Lx\n", event->header.misc,
46 event->ip.pid, 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 || al.sym == NULL)
55 return 0;
56
57 event__parse_sample(event, session->sample_type, &data);
58
59 if (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 .sample = diff__process_sample_event,
70 .mmap = event__process_mmap,
71 .comm = event__process_comm,
72 .exit = event__process_task,
73 .fork = event__process_task,
74 .lost = 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 parent = *p;
86 iter = rb_entry(parent, struct hist_entry, rb_node);
87 if (hist_entry__cmp(he, iter) < 0)
88 p = &(*p)->rb_left;
89 else
90 p = &(*p)->rb_right;
91 }
92
93 rb_link_node(&he->rb_node, parent, p);
94 rb_insert_color(&he->rb_node, root);
95}
96
97static void perf_session__resort_hist_entries(struct perf_session *self)
98{
99 unsigned long position = 1;
100 struct rb_root tmp = RB_ROOT;
101 struct rb_node *next = rb_first(&self->hists);
102
103 while (next != NULL) {
104 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
105
106 next = rb_next(&n->rb_node);
107 rb_erase(&n->rb_node, &self->hists);
108 n->position = position++;
109 perf_session__insert_hist_entry_by_name(&tmp, n);
110 }
111
112 self->hists = tmp;
113}
114
115static void perf_session__set_hist_entries_positions(struct perf_session *self)
116{
117 perf_session__output_resort(self, self->events_stats.total);
118 perf_session__resort_hist_entries(self);
119}
120
121static struct hist_entry *
122perf_session__find_hist_entry(struct perf_session *self,
123 struct hist_entry *he)
124{
125 struct rb_node *n = self->hists.rb_node;
126
127 while (n) {
128 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
129 int64_t cmp = hist_entry__cmp(he, iter);
130
131 if (cmp < 0)
132 n = n->rb_left;
133 else if (cmp > 0)
134 n = n->rb_right;
135 else
136 return iter;
137 }
138
139 return NULL;
140}
141
142static void perf_session__match_hists(struct perf_session *old_session,
143 struct perf_session *new_session)
144{
145 struct rb_node *nd;
146
147 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
148 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
149 pos->pair = perf_session__find_hist_entry(old_session, pos);
150 }
151}
152
153static int __cmd_diff(void)
154{
155 int ret, i;
156 struct perf_session *session[2];
157
158 session[0] = perf_session__new(input_old, O_RDONLY, force);
159 session[1] = perf_session__new(input_new, O_RDONLY, force);
160 if (session[0] == NULL || session[1] == NULL)
161 return -ENOMEM;
162
163 for (i = 0; i < 2; ++i) {
164 ret = perf_session__process_events(session[i], &event_ops);
165 if (ret)
166 goto out_delete;
167 }
168
169 perf_session__output_resort(session[1], session[1]->events_stats.total);
170 if (show_displacement)
171 perf_session__set_hist_entries_positions(session[0]);
172
173 perf_session__match_hists(session[0], session[1]);
174 perf_session__fprintf_hists(session[1], session[0],
175 show_displacement, stdout);
176out_delete:
177 for (i = 0; i < 2; ++i)
178 perf_session__delete(session[i]);
179 return ret;
180}
181
182static const char * const diff_usage[] = {
183 "perf diff [<options>] [old_file] [new_file]",
184 NULL,
185};
186
187static const struct option options[] = {
188 OPT_BOOLEAN('v', "verbose", &verbose,
189 "be more verbose (show symbol address, etc)"),
190 OPT_BOOLEAN('m', "displacement", &show_displacement,
191 "Show position displacement relative to baseline"),
192 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
193 "dump raw trace in ASCII"),
194 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
195 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
196 "load module symbols - WARNING: use only with -k and LIVE kernel"),
197 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
198 "Don't shorten the pathnames taking into account the cwd"),
199 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
200 "only consider symbols in these dsos"),
201 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
202 "only consider symbols in these comms"),
203 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
204 "only consider these symbols"),
205 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
206 "sort by key(s): pid, comm, dso, symbol, parent"),
207 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
208 "separator for columns, no spaces will be added between "
209 "columns '.' is reserved."),
210 OPT_END()
211};
212
213int cmd_diff(int argc, const char **argv, const char *prefix __used)
214{
215 sort_order = diff__default_sort_order;
216 argc = parse_options(argc, argv, options, diff_usage, 0);
217 if (argc) {
218 if (argc > 2)
219 usage_with_options(diff_usage, options);
220 if (argc == 2) {
221 input_old = argv[0];
222 input_new = argv[1];
223 } else
224 input_new = argv[0];
225 }
226
227 symbol_conf.exclude_other = false;
228 if (symbol__init() < 0)
229 return -1;
230
231 setup_sorting(diff_usage, options);
232 setup_pager();
233
234 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
235 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
236 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
237
238 return __cmd_diff();
239}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 4fb8734a796e..215b584007b1 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -61,8 +61,7 @@ static const char *get_man_viewer_info(const char *name)
61{ 61{
62 struct man_viewer_info_list *viewer; 62 struct man_viewer_info_list *viewer;
63 63
64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) 64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) {
65 {
66 if (!strcasecmp(name, viewer->name)) 65 if (!strcasecmp(name, viewer->name))
67 return viewer->info; 66 return viewer->info;
68 } 67 }
@@ -115,7 +114,7 @@ static int check_emacsclient_version(void)
115 return 0; 114 return 0;
116} 115}
117 116
118static void exec_woman_emacs(const char* path, const char *page) 117static void exec_woman_emacs(const char *path, const char *page)
119{ 118{
120 if (!check_emacsclient_version()) { 119 if (!check_emacsclient_version()) {
121 /* This works only with emacsclient version >= 22. */ 120 /* This works only with emacsclient version >= 22. */
@@ -129,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
129 } 128 }
130} 129}
131 130
132static void exec_man_konqueror(const char* path, const char *page) 131static void exec_man_konqueror(const char *path, const char *page)
133{ 132{
134 const char *display = getenv("DISPLAY"); 133 const char *display = getenv("DISPLAY");
135 if (display && *display) { 134 if (display && *display) {
@@ -157,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
157 } 156 }
158} 157}
159 158
160static void exec_man_man(const char* path, const char *page) 159static void exec_man_man(const char *path, const char *page)
161{ 160{
162 if (!path) 161 if (!path)
163 path = "man"; 162 path = "man";
@@ -180,7 +179,7 @@ static void add_man_viewer(const char *name)
180 179
181 while (*p) 180 while (*p)
182 p = &((*p)->next); 181 p = &((*p)->next);
183 *p = calloc(1, (sizeof(**p) + len + 1)); 182 *p = zalloc(sizeof(**p) + len + 1);
184 strncpy((*p)->name, name, len); 183 strncpy((*p)->name, name, len);
185} 184}
186 185
@@ -195,7 +194,7 @@ static void do_add_man_viewer_info(const char *name,
195 size_t len, 194 size_t len,
196 const char *value) 195 const char *value)
197{ 196{
198 struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); 197 struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1);
199 198
200 strncpy(new->name, name, len); 199 strncpy(new->name, name, len);
201 new->info = strdup(value); 200 new->info = strdup(value);
@@ -287,8 +286,7 @@ void list_common_cmds_help(void)
287 286
288 puts(" The most commonly used perf commands are:"); 287 puts(" The most commonly used perf commands are:");
289 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
290 printf(" %s ", common_cmds[i].name); 289 printf(" %-*s ", longest, common_cmds[i].name);
291 mput_char(' ', longest - strlen(common_cmds[i].name));
292 puts(common_cmds[i].help); 290 puts(common_cmds[i].help);
293 } 291 }
294} 292}
@@ -315,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd)
315 return "perf"; 313 return "perf";
316 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
317 return perf_cmd; 315 return perf_cmd;
318 else if (is_perf_command(perf_cmd))
319 return prepend("perf-", perf_cmd);
320 else 316 else
321 return prepend("perf-", perf_cmd); 317 return prepend("perf-", perf_cmd);
322} 318}
@@ -364,9 +360,8 @@ static void show_man_page(const char *perf_cmd)
364 360
365 setup_man_path(); 361 setup_man_path();
366 for (viewer = man_viewer_list; viewer; viewer = viewer->next) 362 for (viewer = man_viewer_list; viewer; viewer = viewer->next)
367 {
368 exec_viewer(viewer->name, page); /* will return when unable */ 363 exec_viewer(viewer->name, page); /* will return when unable */
369 } 364
370 if (fallback) 365 if (fallback)
371 exec_viewer(fallback, page); 366 exec_viewer(fallback, page);
372 exec_viewer("man", page); 367 exec_viewer("man", page);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
new file mode 100644
index 000000000000..924a9518931a
--- /dev/null
+++ b/tools/perf/builtin-kmem.c
@@ -0,0 +1,774 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9#include "util/session.h"
10
11#include "util/parse-options.h"
12#include "util/trace-event.h"
13
14#include "util/debug.h"
15
16#include <linux/rbtree.h>
17
18struct alloc_stat;
19typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20
21static char const *input_name = "perf.data";
22
23static int alloc_flag;
24static int caller_flag;
25
26static int alloc_lines = -1;
27static int caller_lines = -1;
28
29static bool raw_ip;
30
31static char default_sort_order[] = "frag,hit,bytes";
32
33static int *cpunode_map;
34static int max_cpu_num;
35
36struct alloc_stat {
37 u64 call_site;
38 u64 ptr;
39 u64 bytes_req;
40 u64 bytes_alloc;
41 u32 hit;
42 u32 pingpong;
43
44 short alloc_cpu;
45
46 struct rb_node node;
47};
48
49static struct rb_root root_alloc_stat;
50static struct rb_root root_alloc_sorted;
51static struct rb_root root_caller_stat;
52static struct rb_root root_caller_sorted;
53
54static unsigned long total_requested, total_allocated;
55static unsigned long nr_allocs, nr_cross_allocs;
56
57#define PATH_SYS_NODE "/sys/devices/system/node"
58
59static void init_cpunode_map(void)
60{
61 FILE *fp;
62 int i;
63
64 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
65 if (!fp) {
66 max_cpu_num = 4096;
67 return;
68 }
69
70 if (fscanf(fp, "%d", &max_cpu_num) < 1)
71 die("Failed to read 'kernel_max' from sysfs");
72 max_cpu_num++;
73
74 cpunode_map = calloc(max_cpu_num, sizeof(int));
75 if (!cpunode_map)
76 die("calloc");
77 for (i = 0; i < max_cpu_num; i++)
78 cpunode_map[i] = -1;
79 fclose(fp);
80}
81
82static void setup_cpunode_map(void)
83{
84 struct dirent *dent1, *dent2;
85 DIR *dir1, *dir2;
86 unsigned int cpu, mem;
87 char buf[PATH_MAX];
88
89 init_cpunode_map();
90
91 dir1 = opendir(PATH_SYS_NODE);
92 if (!dir1)
93 return;
94
95 while ((dent1 = readdir(dir1)) != NULL) {
96 if (dent1->d_type != DT_DIR ||
97 sscanf(dent1->d_name, "node%u", &mem) < 1)
98 continue;
99
100 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
101 dir2 = opendir(buf);
102 if (!dir2)
103 continue;
104 while ((dent2 = readdir(dir2)) != NULL) {
105 if (dent2->d_type != DT_LNK ||
106 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
107 continue;
108 cpunode_map[cpu] = mem;
109 }
110 }
111}
112
113static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
114 int bytes_req, int bytes_alloc, int cpu)
115{
116 struct rb_node **node = &root_alloc_stat.rb_node;
117 struct rb_node *parent = NULL;
118 struct alloc_stat *data = NULL;
119
120 while (*node) {
121 parent = *node;
122 data = rb_entry(*node, struct alloc_stat, node);
123
124 if (ptr > data->ptr)
125 node = &(*node)->rb_right;
126 else if (ptr < data->ptr)
127 node = &(*node)->rb_left;
128 else
129 break;
130 }
131
132 if (data && data->ptr == ptr) {
133 data->hit++;
134 data->bytes_req += bytes_req;
135 data->bytes_alloc += bytes_alloc;
136 } else {
137 data = malloc(sizeof(*data));
138 if (!data)
139 die("malloc");
140 data->ptr = ptr;
141 data->pingpong = 0;
142 data->hit = 1;
143 data->bytes_req = bytes_req;
144 data->bytes_alloc = bytes_alloc;
145
146 rb_link_node(&data->node, parent, node);
147 rb_insert_color(&data->node, &root_alloc_stat);
148 }
149 data->call_site = call_site;
150 data->alloc_cpu = cpu;
151}
152
153static void insert_caller_stat(unsigned long call_site,
154 int bytes_req, int bytes_alloc)
155{
156 struct rb_node **node = &root_caller_stat.rb_node;
157 struct rb_node *parent = NULL;
158 struct alloc_stat *data = NULL;
159
160 while (*node) {
161 parent = *node;
162 data = rb_entry(*node, struct alloc_stat, node);
163
164 if (call_site > data->call_site)
165 node = &(*node)->rb_right;
166 else if (call_site < data->call_site)
167 node = &(*node)->rb_left;
168 else
169 break;
170 }
171
172 if (data && data->call_site == call_site) {
173 data->hit++;
174 data->bytes_req += bytes_req;
175 data->bytes_alloc += bytes_alloc;
176 } else {
177 data = malloc(sizeof(*data));
178 if (!data)
179 die("malloc");
180 data->call_site = call_site;
181 data->pingpong = 0;
182 data->hit = 1;
183 data->bytes_req = bytes_req;
184 data->bytes_alloc = bytes_alloc;
185
186 rb_link_node(&data->node, parent, node);
187 rb_insert_color(&data->node, &root_caller_stat);
188 }
189}
190
191static void process_alloc_event(void *data,
192 struct event *event,
193 int cpu,
194 u64 timestamp __used,
195 struct thread *thread __used,
196 int node)
197{
198 unsigned long call_site;
199 unsigned long ptr;
200 int bytes_req;
201 int bytes_alloc;
202 int node1, node2;
203
204 ptr = raw_field_value(event, "ptr", data);
205 call_site = raw_field_value(event, "call_site", data);
206 bytes_req = raw_field_value(event, "bytes_req", data);
207 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
208
209 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
210 insert_caller_stat(call_site, bytes_req, bytes_alloc);
211
212 total_requested += bytes_req;
213 total_allocated += bytes_alloc;
214
215 if (node) {
216 node1 = cpunode_map[cpu];
217 node2 = raw_field_value(event, "node", data);
218 if (node1 != node2)
219 nr_cross_allocs++;
220 }
221 nr_allocs++;
222}
223
224static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
225static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
226
227static struct alloc_stat *search_alloc_stat(unsigned long ptr,
228 unsigned long call_site,
229 struct rb_root *root,
230 sort_fn_t sort_fn)
231{
232 struct rb_node *node = root->rb_node;
233 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
234
235 while (node) {
236 struct alloc_stat *data;
237 int cmp;
238
239 data = rb_entry(node, struct alloc_stat, node);
240
241 cmp = sort_fn(&key, data);
242 if (cmp < 0)
243 node = node->rb_left;
244 else if (cmp > 0)
245 node = node->rb_right;
246 else
247 return data;
248 }
249 return NULL;
250}
251
252static void process_free_event(void *data,
253 struct event *event,
254 int cpu,
255 u64 timestamp __used,
256 struct thread *thread __used)
257{
258 unsigned long ptr;
259 struct alloc_stat *s_alloc, *s_caller;
260
261 ptr = raw_field_value(event, "ptr", data);
262
263 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
264 if (!s_alloc)
265 return;
266
267 if (cpu != s_alloc->alloc_cpu) {
268 s_alloc->pingpong++;
269
270 s_caller = search_alloc_stat(0, s_alloc->call_site,
271 &root_caller_stat, callsite_cmp);
272 assert(s_caller);
273 s_caller->pingpong++;
274 }
275 s_alloc->alloc_cpu = -1;
276}
277
278static void
279process_raw_event(event_t *raw_event __used, void *data,
280 int cpu, u64 timestamp, struct thread *thread)
281{
282 struct event *event;
283 int type;
284
285 type = trace_parse_common_type(data);
286 event = trace_find_event(type);
287
288 if (!strcmp(event->name, "kmalloc") ||
289 !strcmp(event->name, "kmem_cache_alloc")) {
290 process_alloc_event(data, event, cpu, timestamp, thread, 0);
291 return;
292 }
293
294 if (!strcmp(event->name, "kmalloc_node") ||
295 !strcmp(event->name, "kmem_cache_alloc_node")) {
296 process_alloc_event(data, event, cpu, timestamp, thread, 1);
297 return;
298 }
299
300 if (!strcmp(event->name, "kfree") ||
301 !strcmp(event->name, "kmem_cache_free")) {
302 process_free_event(data, event, cpu, timestamp, thread);
303 return;
304 }
305}
306
307static int process_sample_event(event_t *event, struct perf_session *session)
308{
309 struct sample_data data;
310 struct thread *thread;
311
312 memset(&data, 0, sizeof(data));
313 data.time = -1;
314 data.cpu = -1;
315 data.period = 1;
316
317 event__parse_sample(event, session->sample_type, &data);
318
319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
320 data.pid, data.tid, data.ip, data.period);
321
322 thread = perf_session__findnew(session, event->ip.pid);
323 if (thread == NULL) {
324 pr_debug("problem processing %d event, skipping it.\n",
325 event->header.type);
326 return -1;
327 }
328
329 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
330
331 process_raw_event(event, data.raw_data, data.cpu,
332 data.time, thread);
333
334 return 0;
335}
336
337static struct perf_event_ops event_ops = {
338 .sample = process_sample_event,
339 .comm = event__process_comm,
340};
341
342static double fragmentation(unsigned long n_req, unsigned long n_alloc)
343{
344 if (n_alloc == 0)
345 return 0.0;
346 else
347 return 100.0 - (100.0 * n_req / n_alloc);
348}
349
350static void __print_result(struct rb_root *root, struct perf_session *session,
351 int n_lines, int is_caller)
352{
353 struct rb_node *next;
354
355 printf("%.102s\n", graph_dotted_line);
356 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
357 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
358 printf("%.102s\n", graph_dotted_line);
359
360 next = rb_first(root);
361
362 while (next && n_lines--) {
363 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
364 node);
365 struct symbol *sym = NULL;
366 char buf[BUFSIZ];
367 u64 addr;
368
369 if (is_caller) {
370 addr = data->call_site;
371 if (!raw_ip)
372 sym = map_groups__find_function(&session->kmaps, addr, NULL);
373 } else
374 addr = data->ptr;
375
376 if (sym != NULL)
377 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
378 addr - sym->start);
379 else
380 snprintf(buf, sizeof(buf), "%#Lx", addr);
381 printf(" %-34s |", buf);
382
383 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
384 (unsigned long long)data->bytes_alloc,
385 (unsigned long)data->bytes_alloc / data->hit,
386 (unsigned long long)data->bytes_req,
387 (unsigned long)data->bytes_req / data->hit,
388 (unsigned long)data->hit,
389 (unsigned long)data->pingpong,
390 fragmentation(data->bytes_req, data->bytes_alloc));
391
392 next = rb_next(next);
393 }
394
395 if (n_lines == -1)
396 printf(" ... | ... | ... | ... | ... | ... \n");
397
398 printf("%.102s\n", graph_dotted_line);
399}
400
401static void print_summary(void)
402{
403 printf("\nSUMMARY\n=======\n");
404 printf("Total bytes requested: %lu\n", total_requested);
405 printf("Total bytes allocated: %lu\n", total_allocated);
406 printf("Total bytes wasted on internal fragmentation: %lu\n",
407 total_allocated - total_requested);
408 printf("Internal fragmentation: %f%%\n",
409 fragmentation(total_requested, total_allocated));
410 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
411}
412
413static void print_result(struct perf_session *session)
414{
415 if (caller_flag)
416 __print_result(&root_caller_sorted, session, caller_lines, 1);
417 if (alloc_flag)
418 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
419 print_summary();
420}
421
422struct sort_dimension {
423 const char name[20];
424 sort_fn_t cmp;
425 struct list_head list;
426};
427
428static LIST_HEAD(caller_sort);
429static LIST_HEAD(alloc_sort);
430
431static void sort_insert(struct rb_root *root, struct alloc_stat *data,
432 struct list_head *sort_list)
433{
434 struct rb_node **new = &(root->rb_node);
435 struct rb_node *parent = NULL;
436 struct sort_dimension *sort;
437
438 while (*new) {
439 struct alloc_stat *this;
440 int cmp = 0;
441
442 this = rb_entry(*new, struct alloc_stat, node);
443 parent = *new;
444
445 list_for_each_entry(sort, sort_list, list) {
446 cmp = sort->cmp(data, this);
447 if (cmp)
448 break;
449 }
450
451 if (cmp > 0)
452 new = &((*new)->rb_left);
453 else
454 new = &((*new)->rb_right);
455 }
456
457 rb_link_node(&data->node, parent, new);
458 rb_insert_color(&data->node, root);
459}
460
461static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
462 struct list_head *sort_list)
463{
464 struct rb_node *node;
465 struct alloc_stat *data;
466
467 for (;;) {
468 node = rb_first(root);
469 if (!node)
470 break;
471
472 rb_erase(node, root);
473 data = rb_entry(node, struct alloc_stat, node);
474 sort_insert(root_sorted, data, sort_list);
475 }
476}
477
478static void sort_result(void)
479{
480 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
481 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
482}
483
484static int __cmd_kmem(void)
485{
486 int err = -EINVAL;
487 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
488 if (session == NULL)
489 return -ENOMEM;
490
491 if (!perf_session__has_traces(session, "kmem record"))
492 goto out_delete;
493
494 setup_pager();
495 err = perf_session__process_events(session, &event_ops);
496 if (err != 0)
497 goto out_delete;
498 sort_result();
499 print_result(session);
500out_delete:
501 perf_session__delete(session);
502 return err;
503}
504
505static const char * const kmem_usage[] = {
506 "perf kmem [<options>] {record|stat}",
507 NULL
508};
509
510static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
511{
512 if (l->ptr < r->ptr)
513 return -1;
514 else if (l->ptr > r->ptr)
515 return 1;
516 return 0;
517}
518
519static struct sort_dimension ptr_sort_dimension = {
520 .name = "ptr",
521 .cmp = ptr_cmp,
522};
523
524static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
525{
526 if (l->call_site < r->call_site)
527 return -1;
528 else if (l->call_site > r->call_site)
529 return 1;
530 return 0;
531}
532
533static struct sort_dimension callsite_sort_dimension = {
534 .name = "callsite",
535 .cmp = callsite_cmp,
536};
537
538static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
539{
540 if (l->hit < r->hit)
541 return -1;
542 else if (l->hit > r->hit)
543 return 1;
544 return 0;
545}
546
547static struct sort_dimension hit_sort_dimension = {
548 .name = "hit",
549 .cmp = hit_cmp,
550};
551
552static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
553{
554 if (l->bytes_alloc < r->bytes_alloc)
555 return -1;
556 else if (l->bytes_alloc > r->bytes_alloc)
557 return 1;
558 return 0;
559}
560
561static struct sort_dimension bytes_sort_dimension = {
562 .name = "bytes",
563 .cmp = bytes_cmp,
564};
565
566static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
567{
568 double x, y;
569
570 x = fragmentation(l->bytes_req, l->bytes_alloc);
571 y = fragmentation(r->bytes_req, r->bytes_alloc);
572
573 if (x < y)
574 return -1;
575 else if (x > y)
576 return 1;
577 return 0;
578}
579
580static struct sort_dimension frag_sort_dimension = {
581 .name = "frag",
582 .cmp = frag_cmp,
583};
584
585static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
586{
587 if (l->pingpong < r->pingpong)
588 return -1;
589 else if (l->pingpong > r->pingpong)
590 return 1;
591 return 0;
592}
593
594static struct sort_dimension pingpong_sort_dimension = {
595 .name = "pingpong",
596 .cmp = pingpong_cmp,
597};
598
599static struct sort_dimension *avail_sorts[] = {
600 &ptr_sort_dimension,
601 &callsite_sort_dimension,
602 &hit_sort_dimension,
603 &bytes_sort_dimension,
604 &frag_sort_dimension,
605 &pingpong_sort_dimension,
606};
607
608#define NUM_AVAIL_SORTS \
609 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
610
611static int sort_dimension__add(const char *tok, struct list_head *list)
612{
613 struct sort_dimension *sort;
614 int i;
615
616 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
617 if (!strcmp(avail_sorts[i]->name, tok)) {
618 sort = malloc(sizeof(*sort));
619 if (!sort)
620 die("malloc");
621 memcpy(sort, avail_sorts[i], sizeof(*sort));
622 list_add_tail(&sort->list, list);
623 return 0;
624 }
625 }
626
627 return -1;
628}
629
630static int setup_sorting(struct list_head *sort_list, const char *arg)
631{
632 char *tok;
633 char *str = strdup(arg);
634
635 if (!str)
636 die("strdup");
637
638 while (true) {
639 tok = strsep(&str, ",");
640 if (!tok)
641 break;
642 if (sort_dimension__add(tok, sort_list) < 0) {
643 error("Unknown --sort key: '%s'", tok);
644 return -1;
645 }
646 }
647
648 free(str);
649 return 0;
650}
651
652static int parse_sort_opt(const struct option *opt __used,
653 const char *arg, int unset __used)
654{
655 if (!arg)
656 return -1;
657
658 if (caller_flag > alloc_flag)
659 return setup_sorting(&caller_sort, arg);
660 else
661 return setup_sorting(&alloc_sort, arg);
662
663 return 0;
664}
665
666static int parse_caller_opt(const struct option *opt __used,
667 const char *arg __used, int unset __used)
668{
669 caller_flag = (alloc_flag + 1);
670 return 0;
671}
672
673static int parse_alloc_opt(const struct option *opt __used,
674 const char *arg __used, int unset __used)
675{
676 alloc_flag = (caller_flag + 1);
677 return 0;
678}
679
680static int parse_line_opt(const struct option *opt __used,
681 const char *arg, int unset __used)
682{
683 int lines;
684
685 if (!arg)
686 return -1;
687
688 lines = strtoul(arg, NULL, 10);
689
690 if (caller_flag > alloc_flag)
691 caller_lines = lines;
692 else
693 alloc_lines = lines;
694
695 return 0;
696}
697
698static const struct option kmem_options[] = {
699 OPT_STRING('i', "input", &input_name, "file",
700 "input file name"),
701 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
702 "show per-callsite statistics",
703 parse_caller_opt),
704 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
705 "show per-allocation statistics",
706 parse_alloc_opt),
707 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
708 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
709 parse_sort_opt),
710 OPT_CALLBACK('l', "line", NULL, "num",
711 "show n lines",
712 parse_line_opt),
713 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
714 OPT_END()
715};
716
717static const char *record_args[] = {
718 "record",
719 "-a",
720 "-R",
721 "-M",
722 "-f",
723 "-c", "1",
724 "-e", "kmem:kmalloc",
725 "-e", "kmem:kmalloc_node",
726 "-e", "kmem:kfree",
727 "-e", "kmem:kmem_cache_alloc",
728 "-e", "kmem:kmem_cache_alloc_node",
729 "-e", "kmem:kmem_cache_free",
730};
731
732static int __cmd_record(int argc, const char **argv)
733{
734 unsigned int rec_argc, i, j;
735 const char **rec_argv;
736
737 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
738 rec_argv = calloc(rec_argc + 1, sizeof(char *));
739
740 for (i = 0; i < ARRAY_SIZE(record_args); i++)
741 rec_argv[i] = strdup(record_args[i]);
742
743 for (j = 1; j < (unsigned int)argc; j++, i++)
744 rec_argv[i] = argv[j];
745
746 return cmd_record(i, rec_argv, NULL);
747}
748
749int cmd_kmem(int argc, const char **argv, const char *prefix __used)
750{
751 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
752
753 if (!argc)
754 usage_with_options(kmem_usage, kmem_options);
755
756 symbol__init();
757
758 if (!strncmp(argv[0], "rec", 3)) {
759 return __cmd_record(argc, argv);
760 } else if (!strcmp(argv[0], "stat")) {
761 setup_cpunode_map();
762
763 if (list_empty(&caller_sort))
764 setup_sorting(&caller_sort, default_sort_order);
765 if (list_empty(&alloc_sort))
766 setup_sorting(&alloc_sort, default_sort_order);
767
768 return __cmd_kmem();
769 } else
770 usage_with_options(kmem_usage, kmem_options);
771
772 return 0;
773}
774
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
new file mode 100644
index 000000000000..e12c844df1e2
--- /dev/null
+++ b/tools/perf/builtin-lock.c
@@ -0,0 +1,822 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9
10#include "util/parse-options.h"
11#include "util/trace-event.h"
12
13#include "util/debug.h"
14#include "util/session.h"
15
16#include <sys/types.h>
17#include <sys/prctl.h>
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21#include <limits.h>
22
23#include <linux/list.h>
24#include <linux/hash.h>
25
26/* based on kernel/lockdep.c */
27#define LOCKHASH_BITS 12
28#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
29
30static struct list_head lockhash_table[LOCKHASH_SIZE];
31
32#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
33#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
34
35#define LOCK_STATE_UNLOCKED 0 /* initial state */
36#define LOCK_STATE_LOCKED 1
37
38struct lock_stat {
39 struct list_head hash_entry;
40 struct rb_node rb; /* used for sorting */
41
42 /*
43 * FIXME: raw_field_value() returns unsigned long long,
44 * so address of lockdep_map should be dealed as 64bit.
45 * Is there more better solution?
46 */
47 void *addr; /* address of lockdep_map, used as ID */
48 char *name; /* for strcpy(), we cannot use const */
49
50 int state;
51 u64 prev_event_time; /* timestamp of previous event */
52
53 unsigned int nr_acquired;
54 unsigned int nr_acquire;
55 unsigned int nr_contended;
56 unsigned int nr_release;
57
58 /* these times are in nano sec. */
59 u64 wait_time_total;
60 u64 wait_time_min;
61 u64 wait_time_max;
62};
63
64/* build simple key function one is bigger than two */
65#define SINGLE_KEY(member) \
66 static int lock_stat_key_ ## member(struct lock_stat *one, \
67 struct lock_stat *two) \
68 { \
69 return one->member > two->member; \
70 }
71
72SINGLE_KEY(nr_acquired)
73SINGLE_KEY(nr_contended)
74SINGLE_KEY(wait_time_total)
75SINGLE_KEY(wait_time_min)
76SINGLE_KEY(wait_time_max)
77
78struct lock_key {
79 /*
80 * name: the value for specify by user
81 * this should be simpler than raw name of member
82 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
83 */
84 const char *name;
85 int (*key)(struct lock_stat*, struct lock_stat*);
86};
87
88static const char *sort_key = "acquired";
89
90static int (*compare)(struct lock_stat *, struct lock_stat *);
91
92static struct rb_root result; /* place to store sorted data */
93
94#define DEF_KEY_LOCK(name, fn_suffix) \
95 { #name, lock_stat_key_ ## fn_suffix }
96struct lock_key keys[] = {
97 DEF_KEY_LOCK(acquired, nr_acquired),
98 DEF_KEY_LOCK(contended, nr_contended),
99 DEF_KEY_LOCK(wait_total, wait_time_total),
100 DEF_KEY_LOCK(wait_min, wait_time_min),
101 DEF_KEY_LOCK(wait_max, wait_time_max),
102
103 /* extra comparisons much complicated should be here */
104
105 { NULL, NULL }
106};
107
108static void select_key(void)
109{
110 int i;
111
112 for (i = 0; keys[i].name; i++) {
113 if (!strcmp(keys[i].name, sort_key)) {
114 compare = keys[i].key;
115 return;
116 }
117 }
118
119 die("Unknown compare key:%s\n", sort_key);
120}
121
122static void insert_to_result(struct lock_stat *st,
123 int (*bigger)(struct lock_stat *, struct lock_stat *))
124{
125 struct rb_node **rb = &result.rb_node;
126 struct rb_node *parent = NULL;
127 struct lock_stat *p;
128
129 while (*rb) {
130 p = container_of(*rb, struct lock_stat, rb);
131 parent = *rb;
132
133 if (bigger(st, p))
134 rb = &(*rb)->rb_left;
135 else
136 rb = &(*rb)->rb_right;
137 }
138
139 rb_link_node(&st->rb, parent, rb);
140 rb_insert_color(&st->rb, &result);
141}
142
143/* returns left most element of result, and erase it */
144static struct lock_stat *pop_from_result(void)
145{
146 struct rb_node *node = result.rb_node;
147
148 if (!node)
149 return NULL;
150
151 while (node->rb_left)
152 node = node->rb_left;
153
154 rb_erase(node, &result);
155 return container_of(node, struct lock_stat, rb);
156}
157
158static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
159{
160 struct list_head *entry = lockhashentry(addr);
161 struct lock_stat *ret, *new;
162
163 list_for_each_entry(ret, entry, hash_entry) {
164 if (ret->addr == addr)
165 return ret;
166 }
167
168 new = zalloc(sizeof(struct lock_stat));
169 if (!new)
170 goto alloc_failed;
171
172 new->addr = addr;
173 new->name = zalloc(sizeof(char) * strlen(name) + 1);
174 if (!new->name)
175 goto alloc_failed;
176 strcpy(new->name, name);
177
178 /* LOCK_STATE_UNLOCKED == 0 isn't guaranteed forever */
179 new->state = LOCK_STATE_UNLOCKED;
180 new->wait_time_min = ULLONG_MAX;
181
182 list_add(&new->hash_entry, entry);
183 return new;
184
185alloc_failed:
186 die("memory allocation failed\n");
187}
188
189static char const *input_name = "perf.data";
190
191static int profile_cpu = -1;
192
193struct raw_event_sample {
194 u32 size;
195 char data[0];
196};
197
198struct trace_acquire_event {
199 void *addr;
200 const char *name;
201};
202
203struct trace_acquired_event {
204 void *addr;
205 const char *name;
206};
207
208struct trace_contended_event {
209 void *addr;
210 const char *name;
211};
212
213struct trace_release_event {
214 void *addr;
215 const char *name;
216};
217
218struct trace_lock_handler {
219 void (*acquire_event)(struct trace_acquire_event *,
220 struct event *,
221 int cpu,
222 u64 timestamp,
223 struct thread *thread);
224
225 void (*acquired_event)(struct trace_acquired_event *,
226 struct event *,
227 int cpu,
228 u64 timestamp,
229 struct thread *thread);
230
231 void (*contended_event)(struct trace_contended_event *,
232 struct event *,
233 int cpu,
234 u64 timestamp,
235 struct thread *thread);
236
237 void (*release_event)(struct trace_release_event *,
238 struct event *,
239 int cpu,
240 u64 timestamp,
241 struct thread *thread);
242};
243
244static void
245report_lock_acquire_event(struct trace_acquire_event *acquire_event,
246 struct event *__event __used,
247 int cpu __used,
248 u64 timestamp,
249 struct thread *thread __used)
250{
251 struct lock_stat *st;
252
253 st = lock_stat_findnew(acquire_event->addr, acquire_event->name);
254
255 switch (st->state) {
256 case LOCK_STATE_UNLOCKED:
257 break;
258 case LOCK_STATE_LOCKED:
259 break;
260 default:
261 BUG_ON(1);
262 break;
263 }
264
265 st->prev_event_time = timestamp;
266}
267
268static void
269report_lock_acquired_event(struct trace_acquired_event *acquired_event,
270 struct event *__event __used,
271 int cpu __used,
272 u64 timestamp,
273 struct thread *thread __used)
274{
275 struct lock_stat *st;
276
277 st = lock_stat_findnew(acquired_event->addr, acquired_event->name);
278
279 switch (st->state) {
280 case LOCK_STATE_UNLOCKED:
281 st->state = LOCK_STATE_LOCKED;
282 st->nr_acquired++;
283 break;
284 case LOCK_STATE_LOCKED:
285 break;
286 default:
287 BUG_ON(1);
288 break;
289 }
290
291 st->prev_event_time = timestamp;
292}
293
294static void
295report_lock_contended_event(struct trace_contended_event *contended_event,
296 struct event *__event __used,
297 int cpu __used,
298 u64 timestamp,
299 struct thread *thread __used)
300{
301 struct lock_stat *st;
302
303 st = lock_stat_findnew(contended_event->addr, contended_event->name);
304
305 switch (st->state) {
306 case LOCK_STATE_UNLOCKED:
307 break;
308 case LOCK_STATE_LOCKED:
309 st->nr_contended++;
310 break;
311 default:
312 BUG_ON(1);
313 break;
314 }
315
316 st->prev_event_time = timestamp;
317}
318
319static void
320report_lock_release_event(struct trace_release_event *release_event,
321 struct event *__event __used,
322 int cpu __used,
323 u64 timestamp,
324 struct thread *thread __used)
325{
326 struct lock_stat *st;
327 u64 hold_time;
328
329 st = lock_stat_findnew(release_event->addr, release_event->name);
330
331 switch (st->state) {
332 case LOCK_STATE_UNLOCKED:
333 break;
334 case LOCK_STATE_LOCKED:
335 st->state = LOCK_STATE_UNLOCKED;
336 hold_time = timestamp - st->prev_event_time;
337
338 if (timestamp < st->prev_event_time) {
339 /* terribly, this can happen... */
340 goto end;
341 }
342
343 if (st->wait_time_min > hold_time)
344 st->wait_time_min = hold_time;
345 if (st->wait_time_max < hold_time)
346 st->wait_time_max = hold_time;
347 st->wait_time_total += hold_time;
348
349 st->nr_release++;
350 break;
351 default:
352 BUG_ON(1);
353 break;
354 }
355
356end:
357 st->prev_event_time = timestamp;
358}
359
360/* lock oriented handlers */
361/* TODO: handlers for CPU oriented, thread oriented */
362static struct trace_lock_handler report_lock_ops = {
363 .acquire_event = report_lock_acquire_event,
364 .acquired_event = report_lock_acquired_event,
365 .contended_event = report_lock_contended_event,
366 .release_event = report_lock_release_event,
367};
368
369static struct trace_lock_handler *trace_handler;
370
371static void
372process_lock_acquire_event(void *data,
373 struct event *event __used,
374 int cpu __used,
375 u64 timestamp __used,
376 struct thread *thread __used)
377{
378 struct trace_acquire_event acquire_event;
379 u64 tmp; /* this is required for casting... */
380
381 tmp = raw_field_value(event, "lockdep_addr", data);
382 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
383 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
384
385 if (trace_handler->acquire_event)
386 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
387}
388
389static void
390process_lock_acquired_event(void *data,
391 struct event *event __used,
392 int cpu __used,
393 u64 timestamp __used,
394 struct thread *thread __used)
395{
396 struct trace_acquired_event acquired_event;
397 u64 tmp; /* this is required for casting... */
398
399 tmp = raw_field_value(event, "lockdep_addr", data);
400 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
401 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
402
403 if (trace_handler->acquire_event)
404 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
405}
406
407static void
408process_lock_contended_event(void *data,
409 struct event *event __used,
410 int cpu __used,
411 u64 timestamp __used,
412 struct thread *thread __used)
413{
414 struct trace_contended_event contended_event;
415 u64 tmp; /* this is required for casting... */
416
417 tmp = raw_field_value(event, "lockdep_addr", data);
418 memcpy(&contended_event.addr, &tmp, sizeof(void *));
419 contended_event.name = (char *)raw_field_ptr(event, "name", data);
420
421 if (trace_handler->acquire_event)
422 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
423}
424
425static void
426process_lock_release_event(void *data,
427 struct event *event __used,
428 int cpu __used,
429 u64 timestamp __used,
430 struct thread *thread __used)
431{
432 struct trace_release_event release_event;
433 u64 tmp; /* this is required for casting... */
434
435 tmp = raw_field_value(event, "lockdep_addr", data);
436 memcpy(&release_event.addr, &tmp, sizeof(void *));
437 release_event.name = (char *)raw_field_ptr(event, "name", data);
438
439 if (trace_handler->acquire_event)
440 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
441}
442
443static void
444process_raw_event(void *data, int cpu,
445 u64 timestamp, struct thread *thread)
446{
447 struct event *event;
448 int type;
449
450 type = trace_parse_common_type(data);
451 event = trace_find_event(type);
452
453 if (!strcmp(event->name, "lock_acquire"))
454 process_lock_acquire_event(data, event, cpu, timestamp, thread);
455 if (!strcmp(event->name, "lock_acquired"))
456 process_lock_acquired_event(data, event, cpu, timestamp, thread);
457 if (!strcmp(event->name, "lock_contended"))
458 process_lock_contended_event(data, event, cpu, timestamp, thread);
459 if (!strcmp(event->name, "lock_release"))
460 process_lock_release_event(data, event, cpu, timestamp, thread);
461}
462
463struct raw_event_queue {
464 u64 timestamp;
465 int cpu;
466 void *data;
467 struct thread *thread;
468 struct list_head list;
469};
470
471static LIST_HEAD(raw_event_head);
472
473#define FLUSH_PERIOD (5 * NSEC_PER_SEC)
474
475static u64 flush_limit = ULLONG_MAX;
476static u64 last_flush = 0;
477struct raw_event_queue *last_inserted;
478
479static void flush_raw_event_queue(u64 limit)
480{
481 struct raw_event_queue *tmp, *iter;
482
483 list_for_each_entry_safe(iter, tmp, &raw_event_head, list) {
484 if (iter->timestamp > limit)
485 return;
486
487 if (iter == last_inserted)
488 last_inserted = NULL;
489
490 process_raw_event(iter->data, iter->cpu, iter->timestamp,
491 iter->thread);
492
493 last_flush = iter->timestamp;
494 list_del(&iter->list);
495 free(iter->data);
496 free(iter);
497 }
498}
499
500static void __queue_raw_event_end(struct raw_event_queue *new)
501{
502 struct raw_event_queue *iter;
503
504 list_for_each_entry_reverse(iter, &raw_event_head, list) {
505 if (iter->timestamp < new->timestamp) {
506 list_add(&new->list, &iter->list);
507 return;
508 }
509 }
510
511 list_add(&new->list, &raw_event_head);
512}
513
514static void __queue_raw_event_before(struct raw_event_queue *new,
515 struct raw_event_queue *iter)
516{
517 list_for_each_entry_continue_reverse(iter, &raw_event_head, list) {
518 if (iter->timestamp < new->timestamp) {
519 list_add(&new->list, &iter->list);
520 return;
521 }
522 }
523
524 list_add(&new->list, &raw_event_head);
525}
526
527static void __queue_raw_event_after(struct raw_event_queue *new,
528 struct raw_event_queue *iter)
529{
530 list_for_each_entry_continue(iter, &raw_event_head, list) {
531 if (iter->timestamp > new->timestamp) {
532 list_add_tail(&new->list, &iter->list);
533 return;
534 }
535 }
536 list_add_tail(&new->list, &raw_event_head);
537}
538
539/* The queue is ordered by time */
540static void __queue_raw_event(struct raw_event_queue *new)
541{
542 if (!last_inserted) {
543 __queue_raw_event_end(new);
544 return;
545 }
546
547 /*
548 * Most of the time the current event has a timestamp
549 * very close to the last event inserted, unless we just switched
550 * to another event buffer. Having a sorting based on a list and
551 * on the last inserted event that is close to the current one is
552 * probably more efficient than an rbtree based sorting.
553 */
554 if (last_inserted->timestamp >= new->timestamp)
555 __queue_raw_event_before(new, last_inserted);
556 else
557 __queue_raw_event_after(new, last_inserted);
558}
559
560static void queue_raw_event(void *data, int raw_size, int cpu,
561 u64 timestamp, struct thread *thread)
562{
563 struct raw_event_queue *new;
564
565 if (flush_limit == ULLONG_MAX)
566 flush_limit = timestamp + FLUSH_PERIOD;
567
568 if (timestamp < last_flush) {
569 printf("Warning: Timestamp below last timeslice flush\n");
570 return;
571 }
572
573 new = malloc(sizeof(*new));
574 if (!new)
575 die("Not enough memory\n");
576
577 new->timestamp = timestamp;
578 new->cpu = cpu;
579 new->thread = thread;
580
581 new->data = malloc(raw_size);
582 if (!new->data)
583 die("Not enough memory\n");
584
585 memcpy(new->data, data, raw_size);
586
587 __queue_raw_event(new);
588 last_inserted = new;
589
590 /*
591 * We want to have a slice of events covering 2 * FLUSH_PERIOD
592 * If FLUSH_PERIOD is big enough, it ensures every events that occured
593 * in the first half of the timeslice have all been buffered and there
594 * are none remaining (we need that because of the weakly ordered
595 * event recording we have). Then once we reach the 2 * FLUSH_PERIOD
596 * timeslice, we flush the first half to be gentle with the memory
597 * (the second half can still get new events in the middle, so wait
598 * another period to flush it)
599 */
600 if (new->timestamp > flush_limit &&
601 new->timestamp - flush_limit > FLUSH_PERIOD) {
602 flush_limit += FLUSH_PERIOD;
603 flush_raw_event_queue(flush_limit);
604 }
605}
606
607static int process_sample_event(event_t *event, struct perf_session *session)
608{
609 struct thread *thread;
610 struct sample_data data;
611
612 bzero(&data, sizeof(struct sample_data));
613 event__parse_sample(event, session->sample_type, &data);
614 thread = perf_session__findnew(session, data.pid);
615
616 if (thread == NULL) {
617 pr_debug("problem processing %d event, skipping it.\n",
618 event->header.type);
619 return -1;
620 }
621
622 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
623
624 if (profile_cpu != -1 && profile_cpu != (int) data.cpu)
625 return 0;
626
627 queue_raw_event(data.raw_data, data.raw_size, data.cpu, data.time, thread);
628
629 return 0;
630}
631
632/* TODO: various way to print, coloring, nano or milli sec */
633static void print_result(void)
634{
635 struct lock_stat *st;
636 char cut_name[20];
637
638 printf("%18s ", "ID");
639 printf("%20s ", "Name");
640 printf("%10s ", "acquired");
641 printf("%10s ", "contended");
642
643 printf("%15s ", "total wait (ns)");
644 printf("%15s ", "max wait (ns)");
645 printf("%15s ", "min wait (ns)");
646
647 printf("\n\n");
648
649 while ((st = pop_from_result())) {
650 bzero(cut_name, 20);
651
652 printf("%p ", st->addr);
653
654 if (strlen(st->name) < 16) {
655 /* output raw name */
656 printf("%20s ", st->name);
657 } else {
658 strncpy(cut_name, st->name, 16);
659 cut_name[16] = '.';
660 cut_name[17] = '.';
661 cut_name[18] = '.';
662 cut_name[19] = '\0';
663 /* cut off name for saving output style */
664 printf("%20s ", cut_name);
665 }
666
667 printf("%10u ", st->nr_acquired);
668 printf("%10u ", st->nr_contended);
669
670 printf("%15llu ", st->wait_time_total);
671 printf("%15llu ", st->wait_time_max);
672 printf("%15llu ", st->wait_time_min == ULLONG_MAX ?
673 0 : st->wait_time_min);
674 printf("\n");
675 }
676}
677
678static void dump_map(void)
679{
680 unsigned int i;
681 struct lock_stat *st;
682
683 for (i = 0; i < LOCKHASH_SIZE; i++) {
684 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
685 printf("%p: %s\n", st->addr, st->name);
686 }
687 }
688}
689
690static struct perf_event_ops eops = {
691 .sample = process_sample_event,
692 .comm = event__process_comm,
693};
694
695static struct perf_session *session;
696
697static int read_events(void)
698{
699 session = perf_session__new(input_name, O_RDONLY, 0);
700 if (!session)
701 die("Initializing perf session failed\n");
702
703 return perf_session__process_events(session, &eops);
704}
705
706static void sort_result(void)
707{
708 unsigned int i;
709 struct lock_stat *st;
710
711 for (i = 0; i < LOCKHASH_SIZE; i++) {
712 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
713 insert_to_result(st, compare);
714 }
715 }
716}
717
718static void __cmd_report(void)
719{
720 setup_pager();
721 select_key();
722 read_events();
723 flush_raw_event_queue(ULLONG_MAX);
724 sort_result();
725 print_result();
726}
727
728static const char * const report_usage[] = {
729 "perf lock report [<options>]",
730 NULL
731};
732
733static const struct option report_options[] = {
734 OPT_STRING('k', "key", &sort_key, "acquired",
735 "key for sorting"),
736 /* TODO: type */
737 OPT_END()
738};
739
740static const char * const lock_usage[] = {
741 "perf lock [<options>] {record|trace|report}",
742 NULL
743};
744
745static const struct option lock_options[] = {
746 OPT_STRING('i', "input", &input_name, "file", "input file name"),
747 OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
748 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
749 OPT_END()
750};
751
752static const char *record_args[] = {
753 "record",
754 "-a",
755 "-R",
756 "-f",
757 "-m", "1024",
758 "-c", "1",
759 "-e", "lock:lock_acquire:r",
760 "-e", "lock:lock_acquired:r",
761 "-e", "lock:lock_contended:r",
762 "-e", "lock:lock_release:r",
763};
764
765static int __cmd_record(int argc, const char **argv)
766{
767 unsigned int rec_argc, i, j;
768 const char **rec_argv;
769
770 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
771 rec_argv = calloc(rec_argc + 1, sizeof(char *));
772
773 for (i = 0; i < ARRAY_SIZE(record_args); i++)
774 rec_argv[i] = strdup(record_args[i]);
775
776 for (j = 1; j < (unsigned int)argc; j++, i++)
777 rec_argv[i] = argv[j];
778
779 BUG_ON(i != rec_argc);
780
781 return cmd_record(i, rec_argv, NULL);
782}
783
784int cmd_lock(int argc, const char **argv, const char *prefix __used)
785{
786 unsigned int i;
787
788 symbol__init();
789 for (i = 0; i < LOCKHASH_SIZE; i++)
790 INIT_LIST_HEAD(lockhash_table + i);
791
792 argc = parse_options(argc, argv, lock_options, lock_usage,
793 PARSE_OPT_STOP_AT_NON_OPTION);
794 if (!argc)
795 usage_with_options(lock_usage, lock_options);
796
797 if (!strncmp(argv[0], "rec", 3)) {
798 return __cmd_record(argc, argv);
799 } else if (!strncmp(argv[0], "report", 6)) {
800 trace_handler = &report_lock_ops;
801 if (argc) {
802 argc = parse_options(argc, argv,
803 report_options, report_usage, 0);
804 if (argc)
805 usage_with_options(report_usage, report_options);
806 }
807 __cmd_report();
808 } else if (!strcmp(argv[0], "trace")) {
809 /* Aliased to 'perf trace' */
810 return cmd_trace(argc, argv, prefix);
811 } else if (!strcmp(argv[0], "map")) {
812 /* recycling report_lock_ops */
813 trace_handler = &report_lock_ops;
814 setup_pager();
815 read_events();
816 dump_map();
817 } else {
818 usage_with_options(lock_usage, lock_options);
819 }
820
821 return 0;
822}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644
index 000000000000..c30a33592340
--- /dev/null
+++ b/tools/perf/builtin-probe.c
@@ -0,0 +1,361 @@
1/*
2 * builtin-probe.c
3 *
4 * Builtin probe command: Set up probe events by C expression
5 *
6 * Written by Masami Hiramatsu <mhiramat@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 */
23#define _GNU_SOURCE
24#include <sys/utsname.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#undef _GNU_SOURCE
35#include "perf.h"
36#include "builtin.h"
37#include "util/util.h"
38#include "util/strlist.h"
39#include "util/event.h"
40#include "util/debug.h"
41#include "util/debugfs.h"
42#include "util/symbol.h"
43#include "util/thread.h"
44#include "util/parse-options.h"
45#include "util/parse-events.h" /* For debugfs_path */
46#include "util/probe-finder.h"
47#include "util/probe-event.h"
48
49#define MAX_PATH_LEN 256
50#define MAX_PROBES 128
51
52/* Session management structure */
53static struct {
54 bool need_dwarf;
55 bool list_events;
56 bool force_add;
57 bool show_lines;
58 int nr_probe;
59 struct probe_point probes[MAX_PROBES];
60 struct strlist *dellist;
61 struct map_groups kmap_groups;
62 struct map *kmaps[MAP__NR_TYPES];
63 struct line_range line_range;
64} session;
65
66
67/* Parse an event definition. Note that any error must die. */
68static void parse_probe_event(const char *str)
69{
70 struct probe_point *pp = &session.probes[session.nr_probe];
71
72 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
73 if (++session.nr_probe == MAX_PROBES)
74 die("Too many probes (> %d) are specified.", MAX_PROBES);
75
76 /* Parse perf-probe event into probe_point */
77 parse_perf_probe_event(str, pp, &session.need_dwarf);
78
79 pr_debug("%d arguments\n", pp->nr_args);
80}
81
82static void parse_probe_event_argv(int argc, const char **argv)
83{
84 int i, len;
85 char *buf;
86
87 /* Bind up rest arguments */
88 len = 0;
89 for (i = 0; i < argc; i++)
90 len += strlen(argv[i]) + 1;
91 buf = zalloc(len + 1);
92 if (!buf)
93 die("Failed to allocate memory for binding arguments.");
94 len = 0;
95 for (i = 0; i < argc; i++)
96 len += sprintf(&buf[len], "%s ", argv[i]);
97 parse_probe_event(buf);
98 free(buf);
99}
100
101static int opt_add_probe_event(const struct option *opt __used,
102 const char *str, int unset __used)
103{
104 if (str)
105 parse_probe_event(str);
106 return 0;
107}
108
109static int opt_del_probe_event(const struct option *opt __used,
110 const char *str, int unset __used)
111{
112 if (str) {
113 if (!session.dellist)
114 session.dellist = strlist__new(true, NULL);
115 strlist__add(session.dellist, str);
116 }
117 return 0;
118}
119
120/* Currently just checking function name from symbol map */
121static void evaluate_probe_point(struct probe_point *pp)
122{
123 struct symbol *sym;
124 sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION],
125 pp->function, NULL);
126 if (!sym)
127 die("Kernel symbol \'%s\' not found - probe not added.",
128 pp->function);
129}
130
131#ifndef NO_DWARF_SUPPORT
132static int open_vmlinux(void)
133{
134 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
135 pr_debug("Failed to load kernel map.\n");
136 return -EINVAL;
137 }
138 pr_debug("Try to open %s\n",
139 session.kmaps[MAP__FUNCTION]->dso->long_name);
140 return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
141}
142
143static int opt_show_lines(const struct option *opt __used,
144 const char *str, int unset __used)
145{
146 if (str)
147 parse_line_range_desc(str, &session.line_range);
148 INIT_LIST_HEAD(&session.line_range.line_list);
149 session.show_lines = true;
150 return 0;
151}
152#endif
153
154static const char * const probe_usage[] = {
155 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
158 "perf probe --list",
159#ifndef NO_DWARF_SUPPORT
160 "perf probe --line 'LINEDESC'",
161#endif
162 NULL
163};
164
165static const struct option options[] = {
166 OPT_BOOLEAN('v', "verbose", &verbose,
167 "be more verbose (show parsed arguments, etc)"),
168#ifndef NO_DWARF_SUPPORT
169 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
170 "file", "vmlinux pathname"),
171#endif
172 OPT_BOOLEAN('l', "list", &session.list_events,
173 "list up current probe events"),
174 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
175 opt_del_probe_event),
176 OPT_CALLBACK('a', "add", NULL,
177#ifdef NO_DWARF_SUPPORT
178 "[EVENT=]FUNC[+OFF|%return] [ARG ...]",
179#else
180 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
181 " [ARG ...]",
182#endif
183 "probe point definition, where\n"
184 "\t\tGROUP:\tGroup name (optional)\n"
185 "\t\tEVENT:\tEvent name\n"
186 "\t\tFUNC:\tFunction name\n"
187 "\t\tOFF:\tOffset from function entry (in byte)\n"
188 "\t\t%return:\tPut the probe at function return\n"
189#ifdef NO_DWARF_SUPPORT
190 "\t\tARG:\tProbe argument (only \n"
191#else
192 "\t\tSRC:\tSource code path\n"
193 "\t\tRL:\tRelative line number from function entry.\n"
194 "\t\tAL:\tAbsolute line number in file.\n"
195 "\t\tPT:\tLazy expression of line code.\n"
196 "\t\tARG:\tProbe argument (local variable name or\n"
197#endif
198 "\t\t\tkprobe-tracer argument format.)\n",
199 opt_add_probe_event),
200 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
201 " with existing name"),
202#ifndef NO_DWARF_SUPPORT
203 OPT_CALLBACK('L', "line", NULL,
204 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
205 "Show source code lines.", opt_show_lines),
206#endif
207 OPT_END()
208};
209
210/* Initialize symbol maps for vmlinux */
211static void init_vmlinux(void)
212{
213 symbol_conf.sort_by_name = true;
214 if (symbol_conf.vmlinux_name == NULL)
215 symbol_conf.try_vmlinux_path = true;
216 else
217 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
218 if (symbol__init() < 0)
219 die("Failed to init symbol map.");
220
221 map_groups__init(&session.kmap_groups);
222 if (map_groups__create_kernel_maps(&session.kmap_groups,
223 session.kmaps) < 0)
224 die("Failed to create kernel maps.");
225}
226
227int cmd_probe(int argc, const char **argv, const char *prefix __used)
228{
229 int i, ret;
230#ifndef NO_DWARF_SUPPORT
231 int fd;
232#endif
233 struct probe_point *pp;
234
235 argc = parse_options(argc, argv, options, probe_usage,
236 PARSE_OPT_STOP_AT_NON_OPTION);
237 if (argc > 0) {
238 if (strcmp(argv[0], "-") == 0) {
239 pr_warning(" Error: '-' is not supported.\n");
240 usage_with_options(probe_usage, options);
241 }
242 parse_probe_event_argv(argc, argv);
243 }
244
245 if ((!session.nr_probe && !session.dellist && !session.list_events &&
246 !session.show_lines))
247 usage_with_options(probe_usage, options);
248
249 if (debugfs_valid_mountpoint(debugfs_path) < 0)
250 die("Failed to find debugfs path.");
251
252 if (session.list_events) {
253 if (session.nr_probe != 0 || session.dellist) {
254 pr_warning(" Error: Don't use --list with"
255 " --add/--del.\n");
256 usage_with_options(probe_usage, options);
257 }
258 if (session.show_lines) {
259 pr_warning(" Error: Don't use --list with --line.\n");
260 usage_with_options(probe_usage, options);
261 }
262 show_perf_probe_events();
263 return 0;
264 }
265
266#ifndef NO_DWARF_SUPPORT
267 if (session.show_lines) {
268 if (session.nr_probe != 0 || session.dellist) {
269 pr_warning(" Error: Don't use --line with"
270 " --add/--del.\n");
271 usage_with_options(probe_usage, options);
272 }
273 init_vmlinux();
274 fd = open_vmlinux();
275 if (fd < 0)
276 die("Could not open debuginfo file.");
277 ret = find_line_range(fd, &session.line_range);
278 if (ret <= 0)
279 die("Source line is not found.\n");
280 close(fd);
281 show_line_range(&session.line_range);
282 return 0;
283 }
284#endif
285
286 if (session.dellist) {
287 del_trace_kprobe_events(session.dellist);
288 strlist__delete(session.dellist);
289 if (session.nr_probe == 0)
290 return 0;
291 }
292
293 /* Add probes */
294 init_vmlinux();
295
296 if (session.need_dwarf)
297#ifdef NO_DWARF_SUPPORT
298 die("Debuginfo-analysis is not supported");
299#else /* !NO_DWARF_SUPPORT */
300 pr_debug("Some probes require debuginfo.\n");
301
302 fd = open_vmlinux();
303 if (fd < 0) {
304 if (session.need_dwarf)
305 die("Could not open debuginfo file.");
306
307 pr_debug("Could not open vmlinux/module file."
308 " Try to use symbols.\n");
309 goto end_dwarf;
310 }
311
312 /* Searching probe points */
313 for (i = 0; i < session.nr_probe; i++) {
314 pp = &session.probes[i];
315 if (pp->found)
316 continue;
317
318 lseek(fd, SEEK_SET, 0);
319 ret = find_probe_point(fd, pp);
320 if (ret > 0)
321 continue;
322 if (ret == 0) { /* No error but failed to find probe point. */
323 synthesize_perf_probe_point(pp);
324 die("Probe point '%s' not found. - probe not added.",
325 pp->probes[0]);
326 }
327 /* Error path */
328 if (session.need_dwarf) {
329 if (ret == -ENOENT)
330 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
331 die("Could not analyze debuginfo.");
332 }
333 pr_debug("An error occurred in debuginfo analysis."
334 " Try to use symbols.\n");
335 break;
336 }
337 close(fd);
338
339end_dwarf:
340#endif /* !NO_DWARF_SUPPORT */
341
342 /* Synthesize probes without dwarf */
343 for (i = 0; i < session.nr_probe; i++) {
344 pp = &session.probes[i];
345 if (pp->found) /* This probe is already found. */
346 continue;
347
348 evaluate_probe_point(pp);
349 ret = synthesize_trace_kprobe_event(pp);
350 if (ret == -E2BIG)
351 die("probe point definition becomes too long.");
352 else if (ret < 0)
353 die("Failed to synthesize a probe point.");
354 }
355
356 /* Settng up probe points */
357 add_trace_kprobe_events(session.probes, session.nr_probe,
358 session.force_add);
359 return 0;
360}
361
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a4be453fc8a9..771533ced6a8 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,10 +5,13 @@
5 * (or a CPU, or a PID) into the perf.data output file - for 5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report. 6 * later analysis via perf report.
7 */ 7 */
8#define _FILE_OFFSET_BITS 64
9
8#include "builtin.h" 10#include "builtin.h"
9 11
10#include "perf.h" 12#include "perf.h"
11 13
14#include "util/build-id.h"
12#include "util/util.h" 15#include "util/util.h"
13#include "util/parse-options.h" 16#include "util/parse-options.h"
14#include "util/parse-events.h" 17#include "util/parse-events.h"
@@ -17,55 +20,54 @@
17#include "util/header.h" 20#include "util/header.h"
18#include "util/event.h" 21#include "util/event.h"
19#include "util/debug.h" 22#include "util/debug.h"
20#include "util/trace-event.h" 23#include "util/session.h"
24#include "util/symbol.h"
21 25
22#include <unistd.h> 26#include <unistd.h>
23#include <sched.h> 27#include <sched.h>
24 28
25#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
26#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
27
28static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 29static int fd[MAX_NR_CPUS][MAX_COUNTERS];
29 30
30static long default_interval = 100000; 31static long default_interval = 0;
31 32
32static int nr_cpus = 0; 33static int nr_cpus = 0;
33static unsigned int page_size; 34static unsigned int page_size;
34static unsigned int mmap_pages = 128; 35static unsigned int mmap_pages = 128;
35static int freq = 0; 36static int freq = 1000;
36static int output; 37static int output;
37static const char *output_name = "perf.data"; 38static const char *output_name = "perf.data";
38static int group = 0; 39static int group = 0;
39static unsigned int realtime_prio = 0; 40static unsigned int realtime_prio = 0;
40static int raw_samples = 0; 41static int raw_samples = 0;
41static int system_wide = 0; 42static int system_wide = 0;
42static int profile_cpu = -1; 43static int profile_cpu = -1;
43static pid_t target_pid = -1; 44static pid_t target_pid = -1;
44static pid_t child_pid = -1; 45static pid_t child_pid = -1;
45static int inherit = 1; 46static int inherit = 1;
46static int force = 0; 47static int force = 0;
47static int append_file = 0; 48static int append_file = 0;
48static int call_graph = 0; 49static int call_graph = 0;
49static int inherit_stat = 0; 50static int inherit_stat = 0;
50static int no_samples = 0; 51static int no_samples = 0;
51static int sample_address = 0; 52static int sample_address = 0;
52static int multiplex = 0; 53static int multiplex = 0;
53static int multiplex_fd = -1; 54static int multiplex_fd = -1;
54 55
55static long samples; 56static long samples = 0;
56static struct timeval last_read; 57static struct timeval last_read;
57static struct timeval this_read; 58static struct timeval this_read;
58 59
59static u64 bytes_written; 60static u64 bytes_written = 0;
60 61
61static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 62static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
62 63
63static int nr_poll; 64static int nr_poll = 0;
64static int nr_cpu; 65static int nr_cpu = 0;
65 66
66static int file_new = 1; 67static int file_new = 1;
68static off_t post_processing_offset;
67 69
68struct perf_header *header; 70static struct perf_session *session;
69 71
70struct mmap_data { 72struct mmap_data {
71 int counter; 73 int counter;
@@ -113,6 +115,13 @@ static void write_output(void *buf, size_t size)
113 } 115 }
114} 116}
115 117
118static int process_synthesized_event(event_t *event,
119 struct perf_session *self __used)
120{
121 write_output(event, event->header.size);
122 return 0;
123}
124
116static void mmap_read(struct mmap_data *md) 125static void mmap_read(struct mmap_data *md)
117{ 126{
118 unsigned int head = mmap_read_head(md); 127 unsigned int head = mmap_read_head(md);
@@ -195,179 +204,21 @@ static void sig_atexit(void)
195 kill(getpid(), signr); 204 kill(getpid(), signr);
196} 205}
197 206
198static pid_t pid_synthesize_comm_event(pid_t pid, int full)
199{
200 struct comm_event comm_ev;
201 char filename[PATH_MAX];
202 char bf[BUFSIZ];
203 FILE *fp;
204 size_t size = 0;
205 DIR *tasks;
206 struct dirent dirent, *next;
207 pid_t tgid = 0;
208
209 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
210
211 fp = fopen(filename, "r");
212 if (fp == NULL) {
213 /*
214 * We raced with a task exiting - just return:
215 */
216 if (verbose)
217 fprintf(stderr, "couldn't open %s\n", filename);
218 return 0;
219 }
220
221 memset(&comm_ev, 0, sizeof(comm_ev));
222 while (!comm_ev.comm[0] || !comm_ev.pid) {
223 if (fgets(bf, sizeof(bf), fp) == NULL)
224 goto out_failure;
225
226 if (memcmp(bf, "Name:", 5) == 0) {
227 char *name = bf + 5;
228 while (*name && isspace(*name))
229 ++name;
230 size = strlen(name) - 1;
231 memcpy(comm_ev.comm, name, size++);
232 } else if (memcmp(bf, "Tgid:", 5) == 0) {
233 char *tgids = bf + 5;
234 while (*tgids && isspace(*tgids))
235 ++tgids;
236 tgid = comm_ev.pid = atoi(tgids);
237 }
238 }
239
240 comm_ev.header.type = PERF_RECORD_COMM;
241 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
243
244 if (!full) {
245 comm_ev.tid = pid;
246
247 write_output(&comm_ev, comm_ev.header.size);
248 goto out_fclose;
249 }
250
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
252
253 tasks = opendir(filename);
254 while (!readdir_r(tasks, &dirent, &next) && next) {
255 char *end;
256 pid = strtol(dirent.d_name, &end, 10);
257 if (*end)
258 continue;
259
260 comm_ev.tid = pid;
261
262 write_output(&comm_ev, comm_ev.header.size);
263 }
264 closedir(tasks);
265
266out_fclose:
267 fclose(fp);
268 return tgid;
269
270out_failure:
271 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
272 filename);
273 exit(EXIT_FAILURE);
274}
275
276static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
277{
278 char filename[PATH_MAX];
279 FILE *fp;
280
281 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
282
283 fp = fopen(filename, "r");
284 if (fp == NULL) {
285 /*
286 * We raced with a task exiting - just return:
287 */
288 if (verbose)
289 fprintf(stderr, "couldn't open %s\n", filename);
290 return;
291 }
292 while (1) {
293 char bf[BUFSIZ], *pbf = bf;
294 struct mmap_event mmap_ev = {
295 .header = { .type = PERF_RECORD_MMAP },
296 };
297 int n;
298 size_t size;
299 if (fgets(bf, sizeof(bf), fp) == NULL)
300 break;
301
302 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
303 n = hex2u64(pbf, &mmap_ev.start);
304 if (n < 0)
305 continue;
306 pbf += n + 1;
307 n = hex2u64(pbf, &mmap_ev.len);
308 if (n < 0)
309 continue;
310 pbf += n + 3;
311 if (*pbf == 'x') { /* vm_exec */
312 char *execname = strchr(bf, '/');
313
314 /* Catch VDSO */
315 if (execname == NULL)
316 execname = strstr(bf, "[vdso]");
317
318 if (execname == NULL)
319 continue;
320
321 size = strlen(execname);
322 execname[size - 1] = '\0'; /* Remove \n */
323 memcpy(mmap_ev.filename, execname, size);
324 size = ALIGN(size, sizeof(u64));
325 mmap_ev.len -= mmap_ev.start;
326 mmap_ev.header.size = (sizeof(mmap_ev) -
327 (sizeof(mmap_ev.filename) - size));
328 mmap_ev.pid = tgid;
329 mmap_ev.tid = pid;
330
331 write_output(&mmap_ev, mmap_ev.header.size);
332 }
333 }
334
335 fclose(fp);
336}
337
338static void synthesize_all(void)
339{
340 DIR *proc;
341 struct dirent dirent, *next;
342
343 proc = opendir("/proc");
344
345 while (!readdir_r(proc, &dirent, &next) && next) {
346 char *end;
347 pid_t pid, tgid;
348
349 pid = strtol(dirent.d_name, &end, 10);
350 if (*end) /* only interested in proper numerical dirents */
351 continue;
352
353 tgid = pid_synthesize_comm_event(pid, 1);
354 pid_synthesize_mmap_samples(pid, tgid);
355 }
356
357 closedir(proc);
358}
359
360static int group_fd; 207static int group_fd;
361 208
362static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 209static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
363{ 210{
364 struct perf_header_attr *h_attr; 211 struct perf_header_attr *h_attr;
365 212
366 if (nr < header->attrs) { 213 if (nr < session->header.attrs) {
367 h_attr = header->attr[nr]; 214 h_attr = session->header.attr[nr];
368 } else { 215 } else {
369 h_attr = perf_header_attr__new(a); 216 h_attr = perf_header_attr__new(a);
370 perf_header__add_attr(header, h_attr); 217 if (h_attr != NULL)
218 if (perf_header__add_attr(&session->header, h_attr) < 0) {
219 perf_header_attr__delete(h_attr);
220 h_attr = NULL;
221 }
371 } 222 }
372 223
373 return h_attr; 224 return h_attr;
@@ -375,9 +226,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
375 226
376static void create_counter(int counter, int cpu, pid_t pid) 227static void create_counter(int counter, int cpu, pid_t pid)
377{ 228{
229 char *filter = filters[counter];
378 struct perf_event_attr *attr = attrs + counter; 230 struct perf_event_attr *attr = attrs + counter;
379 struct perf_header_attr *h_attr; 231 struct perf_header_attr *h_attr;
380 int track = !counter; /* only the first counter needs these */ 232 int track = !counter; /* only the first counter needs these */
233 int ret;
381 struct { 234 struct {
382 u64 count; 235 u64 count;
383 u64 time_enabled; 236 u64 time_enabled;
@@ -417,7 +270,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
417 270
418 attr->mmap = track; 271 attr->mmap = track;
419 attr->comm = track; 272 attr->comm = track;
420 attr->inherit = (cpu < 0) && inherit; 273 attr->inherit = inherit;
421 attr->disabled = 1; 274 attr->disabled = 1;
422 275
423try_again: 276try_again:
@@ -448,11 +301,19 @@ try_again:
448 printf("\n"); 301 printf("\n");
449 error("perfcounter syscall returned with %d (%s)\n", 302 error("perfcounter syscall returned with %d (%s)\n",
450 fd[nr_cpu][counter], strerror(err)); 303 fd[nr_cpu][counter], strerror(err));
304
305#if defined(__i386__) || defined(__x86_64__)
306 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
307 die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n");
308#endif
309
451 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 310 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
452 exit(-1); 311 exit(-1);
453 } 312 }
454 313
455 h_attr = get_header_attr(attr, counter); 314 h_attr = get_header_attr(attr, counter);
315 if (h_attr == NULL)
316 die("nomem\n");
456 317
457 if (!file_new) { 318 if (!file_new) {
458 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 319 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +327,10 @@ try_again:
466 exit(-1); 327 exit(-1);
467 } 328 }
468 329
469 perf_header_attr__add_id(h_attr, read_data.id); 330 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
331 pr_warning("Not enough memory to add id\n");
332 exit(-1);
333 }
470 334
471 assert(fd[nr_cpu][counter] >= 0); 335 assert(fd[nr_cpu][counter] >= 0);
472 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 336 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +344,6 @@ try_again:
480 multiplex_fd = fd[nr_cpu][counter]; 344 multiplex_fd = fd[nr_cpu][counter];
481 345
482 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 346 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
483 int ret;
484 347
485 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 348 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
486 assert(ret != -1); 349 assert(ret != -1);
@@ -500,6 +363,16 @@ try_again:
500 } 363 }
501 } 364 }
502 365
366 if (filter != NULL) {
367 ret = ioctl(fd[nr_cpu][counter],
368 PERF_EVENT_IOC_SET_FILTER, filter);
369 if (ret) {
370 error("failed to set filter with %d (%s)\n", errno,
371 strerror(errno));
372 exit(-1);
373 }
374 }
375
503 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 376 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
504} 377}
505 378
@@ -514,11 +387,22 @@ static void open_counters(int cpu, pid_t pid)
514 nr_cpu++; 387 nr_cpu++;
515} 388}
516 389
390static int process_buildids(void)
391{
392 u64 size = lseek(output, 0, SEEK_CUR);
393
394 session->fd = output;
395 return __perf_session__process_events(session, post_processing_offset,
396 size - post_processing_offset,
397 size, &build_id__mark_dso_hit_ops);
398}
399
517static void atexit_header(void) 400static void atexit_header(void)
518{ 401{
519 header->data_size += bytes_written; 402 session->header.data_size += bytes_written;
520 403
521 perf_header__write(header, output); 404 process_buildids();
405 perf_header__write(&session->header, output, true);
522} 406}
523 407
524static int __cmd_record(int argc, const char **argv) 408static int __cmd_record(int argc, const char **argv)
@@ -527,8 +411,11 @@ static int __cmd_record(int argc, const char **argv)
527 struct stat st; 411 struct stat st;
528 pid_t pid = 0; 412 pid_t pid = 0;
529 int flags; 413 int flags;
530 int ret; 414 int err;
531 unsigned long waking = 0; 415 unsigned long waking = 0;
416 int child_ready_pipe[2], go_pipe[2];
417 const bool forks = target_pid == -1 && argc > 0;
418 char buf;
532 419
533 page_size = sysconf(_SC_PAGE_SIZE); 420 page_size = sysconf(_SC_PAGE_SIZE);
534 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 421 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -539,11 +426,25 @@ static int __cmd_record(int argc, const char **argv)
539 signal(SIGCHLD, sig_handler); 426 signal(SIGCHLD, sig_handler);
540 signal(SIGINT, sig_handler); 427 signal(SIGINT, sig_handler);
541 428
429 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
430 perror("failed to create pipes");
431 exit(-1);
432 }
433
542 if (!stat(output_name, &st) && st.st_size) { 434 if (!stat(output_name, &st) && st.st_size) {
543 if (!force && !append_file) { 435 if (!force) {
544 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 436 if (!append_file) {
545 output_name); 437 pr_err("Error, output file %s exists, use -A "
546 exit(-1); 438 "to append or -f to overwrite.\n",
439 output_name);
440 exit(-1);
441 }
442 } else {
443 char oldname[PATH_MAX];
444 snprintf(oldname, sizeof(oldname), "%s.old",
445 output_name);
446 unlink(oldname);
447 rename(output_name, oldname);
547 } 448 }
548 } else { 449 } else {
549 append_file = 0; 450 append_file = 0;
@@ -561,73 +462,135 @@ static int __cmd_record(int argc, const char **argv)
561 exit(-1); 462 exit(-1);
562 } 463 }
563 464
564 if (!file_new) 465 session = perf_session__new(output_name, O_WRONLY, force);
565 header = perf_header__read(output); 466 if (session == NULL) {
566 else 467 pr_err("Not enough memory for reading perf file header\n");
567 header = perf_header__new(); 468 return -1;
469 }
568 470
471 if (!file_new) {
472 err = perf_header__read(&session->header, output);
473 if (err < 0)
474 return err;
475 }
569 476
570 if (raw_samples) { 477 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 478 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
572 } else { 479 } else {
573 for (i = 0; i < nr_counters; i++) { 480 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 481 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 482 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
576 break; 483 break;
577 } 484 }
578 } 485 }
579 } 486 }
487
580 atexit(atexit_header); 488 atexit(atexit_header);
581 489
582 if (!system_wide) { 490 if (forks) {
583 pid = target_pid; 491 pid = fork();
584 if (pid == -1) 492 if (pid < 0) {
585 pid = getpid(); 493 perror("failed to fork");
494 exit(-1);
495 }
496
497 if (!pid) {
498 close(child_ready_pipe[0]);
499 close(go_pipe[1]);
500 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
501
502 /*
503 * Do a dummy execvp to get the PLT entry resolved,
504 * so we avoid the resolver overhead on the real
505 * execvp call.
506 */
507 execvp("", (char **)argv);
508
509 /*
510 * Tell the parent we're ready to go
511 */
512 close(child_ready_pipe[1]);
513
514 /*
515 * Wait until the parent tells us to go.
516 */
517 if (read(go_pipe[0], &buf, 1) == -1)
518 perror("unable to read pipe");
519
520 execvp(argv[0], (char **)argv);
521
522 perror(argv[0]);
523 exit(-1);
524 }
586 525
587 open_counters(profile_cpu, pid); 526 child_pid = pid;
588 } else { 527
589 if (profile_cpu != -1) { 528 if (!system_wide)
590 open_counters(profile_cpu, target_pid); 529 target_pid = pid;
591 } else { 530
592 for (i = 0; i < nr_cpus; i++) 531 close(child_ready_pipe[1]);
593 open_counters(i, target_pid); 532 close(go_pipe[0]);
533 /*
534 * wait for child to settle
535 */
536 if (read(child_ready_pipe[0], &buf, 1) == -1) {
537 perror("unable to read pipe");
538 exit(-1);
594 } 539 }
540 close(child_ready_pipe[0]);
595 } 541 }
596 542
597 if (file_new)
598 perf_header__write(header, output);
599 543
600 if (!system_wide) { 544 if ((!system_wide && !inherit) || profile_cpu != -1) {
601 pid_t tgid = pid_synthesize_comm_event(pid, 0); 545 open_counters(profile_cpu, target_pid);
602 pid_synthesize_mmap_samples(pid, tgid); 546 } else {
603 } else 547 for (i = 0; i < nr_cpus; i++)
604 synthesize_all(); 548 open_counters(i, target_pid);
549 }
605 550
606 if (target_pid == -1 && argc) { 551 if (file_new) {
607 pid = fork(); 552 err = perf_header__write(&session->header, output, false);
608 if (pid < 0) 553 if (err < 0)
609 perror("failed to fork"); 554 return err;
555 }
610 556
611 if (!pid) { 557 post_processing_offset = lseek(output, 0, SEEK_CUR);
612 if (execvp(argv[0], (char **)argv)) {
613 perror(argv[0]);
614 exit(-1);
615 }
616 }
617 558
618 child_pid = pid; 559 err = event__synthesize_kernel_mmap(process_synthesized_event,
560 session, "_text");
561 if (err < 0) {
562 pr_err("Couldn't record kernel reference relocation symbol.\n");
563 return err;
564 }
565
566 err = event__synthesize_modules(process_synthesized_event, session);
567 if (err < 0) {
568 pr_err("Couldn't record kernel reference relocation symbol.\n");
569 return err;
619 } 570 }
620 571
572 if (!system_wide && profile_cpu == -1)
573 event__synthesize_thread(target_pid, process_synthesized_event,
574 session);
575 else
576 event__synthesize_threads(process_synthesized_event, session);
577
621 if (realtime_prio) { 578 if (realtime_prio) {
622 struct sched_param param; 579 struct sched_param param;
623 580
624 param.sched_priority = realtime_prio; 581 param.sched_priority = realtime_prio;
625 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 582 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
626 printf("Could not set realtime priority.\n"); 583 pr_err("Could not set realtime priority.\n");
627 exit(-1); 584 exit(-1);
628 } 585 }
629 } 586 }
630 587
588 /*
589 * Let the child rip
590 */
591 if (forks)
592 close(go_pipe[1]);
593
631 for (;;) { 594 for (;;) {
632 int hits = samples; 595 int hits = samples;
633 596
@@ -641,7 +604,7 @@ static int __cmd_record(int argc, const char **argv)
641 if (hits == samples) { 604 if (hits == samples) {
642 if (done) 605 if (done)
643 break; 606 break;
644 ret = poll(event_array, nr_poll, -1); 607 err = poll(event_array, nr_poll, -1);
645 waking++; 608 waking++;
646 } 609 }
647 610
@@ -677,6 +640,8 @@ static const struct option options[] = {
677 OPT_CALLBACK('e', "event", NULL, "event", 640 OPT_CALLBACK('e', "event", NULL, "event",
678 "event selector. use 'perf list' to list available events", 641 "event selector. use 'perf list' to list available events",
679 parse_events), 642 parse_events),
643 OPT_CALLBACK(0, "filter", NULL, "filter",
644 "event filter", parse_filter),
680 OPT_INTEGER('p', "pid", &target_pid, 645 OPT_INTEGER('p', "pid", &target_pid,
681 "record events on existing pid"), 646 "record events on existing pid"),
682 OPT_INTEGER('r', "realtime", &realtime_prio, 647 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -721,16 +686,30 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
721 int counter; 686 int counter;
722 687
723 argc = parse_options(argc, argv, options, record_usage, 688 argc = parse_options(argc, argv, options, record_usage,
724 PARSE_OPT_STOP_AT_NON_OPTION); 689 PARSE_OPT_STOP_AT_NON_OPTION);
725 if (!argc && target_pid == -1 && !system_wide) 690 if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1)
726 usage_with_options(record_usage, options); 691 usage_with_options(record_usage, options);
727 692
693 symbol__init();
694
728 if (!nr_counters) { 695 if (!nr_counters) {
729 nr_counters = 1; 696 nr_counters = 1;
730 attrs[0].type = PERF_TYPE_HARDWARE; 697 attrs[0].type = PERF_TYPE_HARDWARE;
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 698 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 699 }
733 700
701 /*
702 * User specified count overrides default frequency.
703 */
704 if (default_interval)
705 freq = 0;
706 else if (freq) {
707 default_interval = freq;
708 } else {
709 fprintf(stderr, "frequency and count are zero, aborting\n");
710 exit(EXIT_FAILURE);
711 }
712
734 for (counter = 0; counter < nr_counters; counter++) { 713 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 714 if (attrs[counter].sample_period)
736 continue; 715 continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..cfc655d40bb7 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -22,27 +22,20 @@
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/thread.h" 30#include "util/thread.h"
31#include "util/sort.h"
32#include "util/hist.h"
30 33
31static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
32 35
33static char default_sort_order[] = "comm,dso,symbol";
34static char *sort_order = default_sort_order;
35static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
39
40static int force; 36static int force;
41static int input; 37static bool hide_unresolved;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 38static bool dont_use_callchains;
43
44static int full_paths;
45static int show_nr_samples;
46 39
47static int show_threads; 40static int show_threads;
48static struct perf_read_values show_threads_values; 41static struct perf_read_values show_threads_values;
@@ -50,1043 +43,36 @@ static struct perf_read_values show_threads_values;
50static char default_pretty_printing_style[] = "normal"; 43static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style; 44static char *pretty_printing_style = default_pretty_printing_style;
52 45
53static unsigned long page_size;
54static unsigned long mmap_window = 32;
55
56static char default_parent_pattern[] = "^sys_|^do_page_fault";
57static char *parent_pattern = default_parent_pattern;
58static regex_t parent_regex;
59
60static int exclude_other = 1;
61
62static char callchain_default_opt[] = "fractal,0.5"; 46static char callchain_default_opt[] = "fractal,0.5";
63 47
64static int callchain; 48static int perf_session__add_hist_entry(struct perf_session *self,
65 49 struct addr_location *al,
66static char __cwd[PATH_MAX]; 50 struct ip_callchain *chain, u64 count)
67static char *cwd = __cwd;
68static int cwdlen;
69
70static struct rb_root threads;
71static struct thread *last_match;
72
73static struct perf_header *header;
74
75static
76struct callchain_param callchain_param = {
77 .mode = CHAIN_GRAPH_REL,
78 .min_percent = 0.5
79};
80
81static u64 sample_type;
82
83static int repsep_fprintf(FILE *fp, const char *fmt, ...)
84{
85 int n;
86 va_list ap;
87
88 va_start(ap, fmt);
89 if (!field_sep)
90 n = vfprintf(fp, fmt, ap);
91 else {
92 char *bf = NULL;
93 n = vasprintf(&bf, fmt, ap);
94 if (n > 0) {
95 char *sep = bf;
96
97 while (1) {
98 sep = strchr(sep, *field_sep);
99 if (sep == NULL)
100 break;
101 *sep = '.';
102 }
103 }
104 fputs(bf, fp);
105 free(bf);
106 }
107 va_end(ap);
108 return n;
109}
110
111static unsigned int dsos__col_width,
112 comms__col_width,
113 threads__col_width;
114
115/*
116 * histogram, sorted on item, collects counts
117 */
118
119static struct rb_root hist;
120
121struct hist_entry {
122 struct rb_node rb_node;
123
124 struct thread *thread;
125 struct map *map;
126 struct dso *dso;
127 struct symbol *sym;
128 struct symbol *parent;
129 u64 ip;
130 char level;
131 struct callchain_node callchain;
132 struct rb_root sorted_chain;
133
134 u64 count;
135};
136
137/*
138 * configurable sorting bits
139 */
140
141struct sort_entry {
142 struct list_head list;
143
144 const char *header;
145
146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
148 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 unsigned int *width;
150 bool elide;
151};
152
153static int64_t cmp_null(void *l, void *r)
154{
155 if (!l && !r)
156 return 0;
157 else if (!l)
158 return -1;
159 else
160 return 1;
161}
162
163/* --sort pid */
164
165static int64_t
166sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
167{
168 return right->thread->pid - left->thread->pid;
169}
170
171static size_t
172sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
173{
174 return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 self->thread->comm ?: "", self->thread->pid);
176}
177
178static struct sort_entry sort_thread = {
179 .header = "Command: Pid",
180 .cmp = sort__thread_cmp,
181 .print = sort__thread_print,
182 .width = &threads__col_width,
183};
184
185/* --sort comm */
186
187static int64_t
188sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
189{
190 return right->thread->pid - left->thread->pid;
191}
192
193static int64_t
194sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
195{
196 char *comm_l = left->thread->comm;
197 char *comm_r = right->thread->comm;
198
199 if (!comm_l || !comm_r)
200 return cmp_null(comm_l, comm_r);
201
202 return strcmp(comm_l, comm_r);
203}
204
205static size_t
206sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
207{
208 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
209}
210
211static struct sort_entry sort_comm = {
212 .header = "Command",
213 .cmp = sort__comm_cmp,
214 .collapse = sort__comm_collapse,
215 .print = sort__comm_print,
216 .width = &comms__col_width,
217};
218
219/* --sort dso */
220
221static int64_t
222sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
223{
224 struct dso *dso_l = left->dso;
225 struct dso *dso_r = right->dso;
226
227 if (!dso_l || !dso_r)
228 return cmp_null(dso_l, dso_r);
229
230 return strcmp(dso_l->name, dso_r->name);
231}
232
233static size_t
234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
235{
236 if (self->dso)
237 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
238
239 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
240}
241
242static struct sort_entry sort_dso = {
243 .header = "Shared Object",
244 .cmp = sort__dso_cmp,
245 .print = sort__dso_print,
246 .width = &dsos__col_width,
247};
248
249/* --sort symbol */
250
251static int64_t
252sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
253{
254 u64 ip_l, ip_r;
255
256 if (left->sym == right->sym)
257 return 0;
258
259 ip_l = left->sym ? left->sym->start : left->ip;
260 ip_r = right->sym ? right->sym->start : right->ip;
261
262 return (int64_t)(ip_r - ip_l);
263}
264
265static size_t
266sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
267{
268 size_t ret = 0;
269
270 if (verbose)
271 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 dso__symtab_origin(self->dso));
273
274 ret += repsep_fprintf(fp, "[%c] ", self->level);
275 if (self->sym) {
276 ret += repsep_fprintf(fp, "%s", self->sym->name);
277
278 if (self->sym->module)
279 ret += repsep_fprintf(fp, "\t[%s]",
280 self->sym->module->name);
281 } else {
282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 }
284
285 return ret;
286}
287
288static struct sort_entry sort_sym = {
289 .header = "Symbol",
290 .cmp = sort__sym_cmp,
291 .print = sort__sym_print,
292};
293
294/* --sort parent */
295
296static int64_t
297sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
298{
299 struct symbol *sym_l = left->parent;
300 struct symbol *sym_r = right->parent;
301
302 if (!sym_l || !sym_r)
303 return cmp_null(sym_l, sym_r);
304
305 return strcmp(sym_l->name, sym_r->name);
306}
307
308static size_t
309sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
310{
311 return repsep_fprintf(fp, "%-*s", width,
312 self->parent ? self->parent->name : "[other]");
313}
314
315static unsigned int parent_symbol__col_width;
316
317static struct sort_entry sort_parent = {
318 .header = "Parent symbol",
319 .cmp = sort__parent_cmp,
320 .print = sort__parent_print,
321 .width = &parent_symbol__col_width,
322};
323
324static int sort__need_collapse = 0;
325static int sort__has_parent = 0;
326
327struct sort_dimension {
328 const char *name;
329 struct sort_entry *entry;
330 int taken;
331};
332
333static struct sort_dimension sort_dimensions[] = {
334 { .name = "pid", .entry = &sort_thread, },
335 { .name = "comm", .entry = &sort_comm, },
336 { .name = "dso", .entry = &sort_dso, },
337 { .name = "symbol", .entry = &sort_sym, },
338 { .name = "parent", .entry = &sort_parent, },
339};
340
341static LIST_HEAD(hist_entry__sort_list);
342
343static int sort_dimension__add(const char *tok)
344{
345 unsigned int i;
346
347 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
348 struct sort_dimension *sd = &sort_dimensions[i];
349
350 if (sd->taken)
351 continue;
352
353 if (strncasecmp(tok, sd->name, strlen(tok)))
354 continue;
355
356 if (sd->entry->collapse)
357 sort__need_collapse = 1;
358
359 if (sd->entry == &sort_parent) {
360 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
361 if (ret) {
362 char err[BUFSIZ];
363
364 regerror(ret, &parent_regex, err, sizeof(err));
365 fprintf(stderr, "Invalid regex: %s\n%s",
366 parent_pattern, err);
367 exit(-1);
368 }
369 sort__has_parent = 1;
370 }
371
372 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
373 sd->taken = 1;
374
375 return 0;
376 }
377
378 return -ESRCH;
379}
380
381static int64_t
382hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct sort_entry *se;
385 int64_t cmp = 0;
386
387 list_for_each_entry(se, &hist_entry__sort_list, list) {
388 cmp = se->cmp(left, right);
389 if (cmp)
390 break;
391 }
392
393 return cmp;
394}
395
396static int64_t
397hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
398{
399 struct sort_entry *se;
400 int64_t cmp = 0;
401
402 list_for_each_entry(se, &hist_entry__sort_list, list) {
403 int64_t (*f)(struct hist_entry *, struct hist_entry *);
404
405 f = se->collapse ?: se->cmp;
406
407 cmp = f(left, right);
408 if (cmp)
409 break;
410 }
411
412 return cmp;
413}
414
415static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416{
417 int i;
418 size_t ret = 0;
419
420 ret += fprintf(fp, "%s", " ");
421
422 for (i = 0; i < depth; i++)
423 if (depth_mask & (1 << i))
424 ret += fprintf(fp, "| ");
425 else
426 ret += fprintf(fp, " ");
427
428 ret += fprintf(fp, "\n");
429
430 return ret;
431}
432static size_t
433ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 int depth_mask, int count, u64 total_samples,
435 int hits)
436{
437 int i;
438 size_t ret = 0;
439
440 ret += fprintf(fp, "%s", " ");
441 for (i = 0; i < depth; i++) {
442 if (depth_mask & (1 << i))
443 ret += fprintf(fp, "|");
444 else
445 ret += fprintf(fp, " ");
446 if (!count && i == depth - 1) {
447 double percent;
448
449 percent = hits * 100.0 / total_samples;
450 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
451 } else
452 ret += fprintf(fp, "%s", " ");
453 }
454 if (chain->sym)
455 ret += fprintf(fp, "%s\n", chain->sym->name);
456 else
457 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
458
459 return ret;
460}
461
462static struct symbol *rem_sq_bracket;
463static struct callchain_list rem_hits;
464
465static void init_rem_hits(void)
466{
467 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
468 if (!rem_sq_bracket) {
469 fprintf(stderr, "Not enough memory to display remaining hits\n");
470 return;
471 }
472
473 strcpy(rem_sq_bracket->name, "[...]");
474 rem_hits.sym = rem_sq_bracket;
475}
476
477static size_t
478callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 u64 total_samples, int depth, int depth_mask)
480{
481 struct rb_node *node, *next;
482 struct callchain_node *child;
483 struct callchain_list *chain;
484 int new_depth_mask = depth_mask;
485 u64 new_total;
486 u64 remaining;
487 size_t ret = 0;
488 int i;
489
490 if (callchain_param.mode == CHAIN_GRAPH_REL)
491 new_total = self->children_hit;
492 else
493 new_total = total_samples;
494
495 remaining = new_total;
496
497 node = rb_first(&self->rb_root);
498 while (node) {
499 u64 cumul;
500
501 child = rb_entry(node, struct callchain_node, rb_node);
502 cumul = cumul_hits(child);
503 remaining -= cumul;
504
505 /*
506 * The depth mask manages the output of pipes that show
507 * the depth. We don't want to keep the pipes of the current
508 * level for the last child of this depth.
509 * Except if we have remaining filtered hits. They will
510 * supersede the last child
511 */
512 next = rb_next(node);
513 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
514 new_depth_mask &= ~(1 << (depth - 1));
515
516 /*
517 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child
519 */
520 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
521 i = 0;
522 list_for_each_entry(chain, &child->val, list) {
523 if (chain->ip >= PERF_CONTEXT_MAX)
524 continue;
525 ret += ipchain__fprintf_graph(fp, chain, depth,
526 new_depth_mask, i++,
527 new_total,
528 cumul);
529 }
530 ret += callchain__fprintf_graph(fp, child, new_total,
531 depth + 1,
532 new_depth_mask | (1 << depth));
533 node = next;
534 }
535
536 if (callchain_param.mode == CHAIN_GRAPH_REL &&
537 remaining && remaining != new_total) {
538
539 if (!rem_sq_bracket)
540 return ret;
541
542 new_depth_mask &= ~(1 << (depth - 1));
543
544 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 new_depth_mask, 0, new_total,
546 remaining);
547 }
548
549 return ret;
550}
551
552static size_t
553callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
554 u64 total_samples)
555{
556 struct callchain_list *chain;
557 size_t ret = 0;
558
559 if (!self)
560 return 0;
561
562 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
563
564
565 list_for_each_entry(chain, &self->val, list) {
566 if (chain->ip >= PERF_CONTEXT_MAX)
567 continue;
568 if (chain->sym)
569 ret += fprintf(fp, " %s\n", chain->sym->name);
570 else
571 ret += fprintf(fp, " %p\n",
572 (void *)(long)chain->ip);
573 }
574
575 return ret;
576}
577
578static size_t
579hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 u64 total_samples)
581{
582 struct rb_node *rb_node;
583 struct callchain_node *chain;
584 size_t ret = 0;
585
586 rb_node = rb_first(&self->sorted_chain);
587 while (rb_node) {
588 double percent;
589
590 chain = rb_entry(rb_node, struct callchain_node, rb_node);
591 percent = chain->hit * 100.0 / total_samples;
592 switch (callchain_param.mode) {
593 case CHAIN_FLAT:
594 ret += percent_color_fprintf(fp, " %6.2f%%\n",
595 percent);
596 ret += callchain__fprintf_flat(fp, chain, total_samples);
597 break;
598 case CHAIN_GRAPH_ABS: /* Falldown */
599 case CHAIN_GRAPH_REL:
600 ret += callchain__fprintf_graph(fp, chain,
601 total_samples, 1, 1);
602 case CHAIN_NONE:
603 default:
604 break;
605 }
606 ret += fprintf(fp, "\n");
607 rb_node = rb_next(rb_node);
608 }
609
610 return ret;
611}
612
613
614static size_t
615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616{
617 struct sort_entry *se;
618 size_t ret;
619
620 if (exclude_other && !self->parent)
621 return 0;
622
623 if (total_samples)
624 ret = percent_color_fprintf(fp,
625 field_sep ? "%.2f" : " %6.2f%%",
626 (self->count * 100.0) / total_samples);
627 else
628 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
629
630 if (show_nr_samples) {
631 if (field_sep)
632 fprintf(fp, "%c%lld", *field_sep, self->count);
633 else
634 fprintf(fp, "%11lld", self->count);
635 }
636
637 list_for_each_entry(se, &hist_entry__sort_list, list) {
638 if (se->elide)
639 continue;
640
641 fprintf(fp, "%s", field_sep ?: " ");
642 ret += se->print(fp, self, se->width ? *se->width : 0);
643 }
644
645 ret += fprintf(fp, "\n");
646
647 if (callchain)
648 hist_entry_callchain__fprintf(fp, self, total_samples);
649
650 return ret;
651}
652
653/*
654 *
655 */
656
657static void dso__calc_col_width(struct dso *self)
658{
659 if (!col_width_list_str && !field_sep &&
660 (!dso_list || strlist__has_entry(dso_list, self->name))) {
661 unsigned int slen = strlen(self->name);
662 if (slen > dsos__col_width)
663 dsos__col_width = slen;
664 }
665
666 self->slen_calculated = 1;
667}
668
669static void thread__comm_adjust(struct thread *self)
670{
671 char *comm = self->comm;
672
673 if (!col_width_list_str && !field_sep &&
674 (!comm_list || strlist__has_entry(comm_list, comm))) {
675 unsigned int slen = strlen(comm);
676
677 if (slen > comms__col_width) {
678 comms__col_width = slen;
679 threads__col_width = slen + 6;
680 }
681 }
682}
683
684static int thread__set_comm_adjust(struct thread *self, const char *comm)
685{
686 int ret = thread__set_comm(self, comm);
687
688 if (ret)
689 return ret;
690
691 thread__comm_adjust(self);
692
693 return 0;
694}
695
696
697static struct symbol *
698resolve_symbol(struct thread *thread, struct map **mapp,
699 struct dso **dsop, u64 *ipp)
700{
701 struct dso *dso = dsop ? *dsop : NULL;
702 struct map *map = mapp ? *mapp : NULL;
703 u64 ip = *ipp;
704
705 if (!thread)
706 return NULL;
707
708 if (dso)
709 goto got_dso;
710
711 if (map)
712 goto got_map;
713
714 map = thread__find_map(thread, ip);
715 if (map != NULL) {
716 /*
717 * We have to do this here as we may have a dso
718 * with no symbol hit that has a name longer than
719 * the ones with symbols sampled.
720 */
721 if (!sort_dso.elide && !map->dso->slen_calculated)
722 dso__calc_col_width(map->dso);
723
724 if (mapp)
725 *mapp = map;
726got_map:
727 ip = map->map_ip(map, ip);
728
729 dso = map->dso;
730 } else {
731 /*
732 * If this is outside of all known maps,
733 * and is a negative address, try to look it
734 * up in the kernel dso, as it might be a
735 * vsyscall (which executes in user-mode):
736 */
737 if ((long long)ip < 0)
738 dso = kernel_dso;
739 }
740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 *ipp = ip;
743
744 if (dsop)
745 *dsop = dso;
746
747 if (!dso)
748 return NULL;
749got_dso:
750 return dso->find_symbol(dso, ip);
751}
752
753static int call__match(struct symbol *sym)
754{
755 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
756 return 1;
757
758 return 0;
759}
760
761static struct symbol **
762resolve_callchain(struct thread *thread, struct map *map __used,
763 struct ip_callchain *chain, struct hist_entry *entry)
764{
765 u64 context = PERF_CONTEXT_MAX;
766 struct symbol **syms = NULL;
767 unsigned int i;
768
769 if (callchain) {
770 syms = calloc(chain->nr, sizeof(*syms));
771 if (!syms) {
772 fprintf(stderr, "Can't allocate memory for symbols\n");
773 exit(-1);
774 }
775 }
776
777 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i];
779 struct dso *dso = NULL;
780 struct symbol *sym;
781
782 if (ip >= PERF_CONTEXT_MAX) {
783 context = ip;
784 continue;
785 }
786
787 switch (context) {
788 case PERF_CONTEXT_HV:
789 dso = hypervisor_dso;
790 break;
791 case PERF_CONTEXT_KERNEL:
792 dso = kernel_dso;
793 break;
794 default:
795 break;
796 }
797
798 sym = resolve_symbol(thread, NULL, &dso, &ip);
799
800 if (sym) {
801 if (sort__has_parent && call__match(sym) &&
802 !entry->parent)
803 entry->parent = sym;
804 if (!callchain)
805 break;
806 syms[i] = sym;
807 }
808 }
809
810 return syms;
811}
812
813/*
814 * collect histogram counts
815 */
816
817static int
818hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
819 struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 char level, u64 count)
821{ 51{
822 struct rb_node **p = &hist.rb_node; 52 struct symbol **syms = NULL, *parent = NULL;
823 struct rb_node *parent = NULL; 53 bool hit;
824 struct hist_entry *he; 54 struct hist_entry *he;
825 struct symbol **syms = NULL;
826 struct hist_entry entry = {
827 .thread = thread,
828 .map = map,
829 .dso = dso,
830 .sym = sym,
831 .ip = ip,
832 .level = level,
833 .count = count,
834 .parent = NULL,
835 .sorted_chain = RB_ROOT
836 };
837 int cmp;
838
839 if ((sort__has_parent || callchain) && chain)
840 syms = resolve_callchain(thread, map, chain, &entry);
841
842 while (*p != NULL) {
843 parent = *p;
844 he = rb_entry(parent, struct hist_entry, rb_node);
845
846 cmp = hist_entry__cmp(&entry, he);
847
848 if (!cmp) {
849 he->count += count;
850 if (callchain) {
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
854 return 0;
855 }
856
857 if (cmp < 0)
858 p = &(*p)->rb_left;
859 else
860 p = &(*p)->rb_right;
861 }
862 55
863 he = malloc(sizeof(*he)); 56 if ((sort__has_parent || symbol_conf.use_callchain) && chain)
864 if (!he) 57 syms = perf_session__resolve_callchain(self, al->thread,
58 chain, &parent);
59 he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
60 if (he == NULL)
865 return -ENOMEM; 61 return -ENOMEM;
866 *he = entry; 62
867 if (callchain) { 63 if (hit)
868 callchain_init(&he->callchain); 64 he->count += count;
65
66 if (symbol_conf.use_callchain) {
67 if (!hit)
68 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms); 69 append_chain(&he->callchain, chain, syms);
870 free(syms); 70 free(syms);
871 } 71 }
872 rb_link_node(&he->rb_node, parent, p);
873 rb_insert_color(&he->rb_node, &hist);
874 72
875 return 0; 73 return 0;
876} 74}
877 75
878static void hist_entry__free(struct hist_entry *he)
879{
880 free(he);
881}
882
883/*
884 * collapse the histogram
885 */
886
887static struct rb_root collapse_hists;
888
889static void collapse__insert_entry(struct hist_entry *he)
890{
891 struct rb_node **p = &collapse_hists.rb_node;
892 struct rb_node *parent = NULL;
893 struct hist_entry *iter;
894 int64_t cmp;
895
896 while (*p != NULL) {
897 parent = *p;
898 iter = rb_entry(parent, struct hist_entry, rb_node);
899
900 cmp = hist_entry__collapse(iter, he);
901
902 if (!cmp) {
903 iter->count += he->count;
904 hist_entry__free(he);
905 return;
906 }
907
908 if (cmp < 0)
909 p = &(*p)->rb_left;
910 else
911 p = &(*p)->rb_right;
912 }
913
914 rb_link_node(&he->rb_node, parent, p);
915 rb_insert_color(&he->rb_node, &collapse_hists);
916}
917
918static void collapse__resort(void)
919{
920 struct rb_node *next;
921 struct hist_entry *n;
922
923 if (!sort__need_collapse)
924 return;
925
926 next = rb_first(&hist);
927 while (next) {
928 n = rb_entry(next, struct hist_entry, rb_node);
929 next = rb_next(&n->rb_node);
930
931 rb_erase(&n->rb_node, &hist);
932 collapse__insert_entry(n);
933 }
934}
935
936/*
937 * reverse the map, sort on count.
938 */
939
940static struct rb_root output_hists;
941
942static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
943{
944 struct rb_node **p = &output_hists.rb_node;
945 struct rb_node *parent = NULL;
946 struct hist_entry *iter;
947
948 if (callchain)
949 callchain_param.sort(&he->sorted_chain, &he->callchain,
950 min_callchain_hits, &callchain_param);
951
952 while (*p != NULL) {
953 parent = *p;
954 iter = rb_entry(parent, struct hist_entry, rb_node);
955
956 if (he->count > iter->count)
957 p = &(*p)->rb_left;
958 else
959 p = &(*p)->rb_right;
960 }
961
962 rb_link_node(&he->rb_node, parent, p);
963 rb_insert_color(&he->rb_node, &output_hists);
964}
965
966static void output__resort(u64 total_samples)
967{
968 struct rb_node *next;
969 struct hist_entry *n;
970 struct rb_root *tree = &hist;
971 u64 min_callchain_hits;
972
973 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
974
975 if (sort__need_collapse)
976 tree = &collapse_hists;
977
978 next = rb_first(tree);
979
980 while (next) {
981 n = rb_entry(next, struct hist_entry, rb_node);
982 next = rb_next(&n->rb_node);
983
984 rb_erase(&n->rb_node, tree);
985 output__insert_entry(n, min_callchain_hits);
986 }
987}
988
989static size_t output__fprintf(FILE *fp, u64 total_samples)
990{
991 struct hist_entry *pos;
992 struct sort_entry *se;
993 struct rb_node *nd;
994 size_t ret = 0;
995 unsigned int width;
996 char *col_width = col_width_list_str;
997 int raw_printing_style;
998
999 raw_printing_style = !strcmp(pretty_printing_style, "raw");
1000
1001 init_rem_hits();
1002
1003 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1004 fprintf(fp, "#\n");
1005
1006 fprintf(fp, "# Overhead");
1007 if (show_nr_samples) {
1008 if (field_sep)
1009 fprintf(fp, "%cSamples", *field_sep);
1010 else
1011 fputs(" Samples ", fp);
1012 }
1013 list_for_each_entry(se, &hist_entry__sort_list, list) {
1014 if (se->elide)
1015 continue;
1016 if (field_sep) {
1017 fprintf(fp, "%c%s", *field_sep, se->header);
1018 continue;
1019 }
1020 width = strlen(se->header);
1021 if (se->width) {
1022 if (col_width_list_str) {
1023 if (col_width) {
1024 *se->width = atoi(col_width);
1025 col_width = strchr(col_width, ',');
1026 if (col_width)
1027 ++col_width;
1028 }
1029 }
1030 width = *se->width = max(*se->width, width);
1031 }
1032 fprintf(fp, " %*s", width, se->header);
1033 }
1034 fprintf(fp, "\n");
1035
1036 if (field_sep)
1037 goto print_entries;
1038
1039 fprintf(fp, "# ........");
1040 if (show_nr_samples)
1041 fprintf(fp, " ..........");
1042 list_for_each_entry(se, &hist_entry__sort_list, list) {
1043 unsigned int i;
1044
1045 if (se->elide)
1046 continue;
1047
1048 fprintf(fp, " ");
1049 if (se->width)
1050 width = *se->width;
1051 else
1052 width = strlen(se->header);
1053 for (i = 0; i < width; i++)
1054 fprintf(fp, ".");
1055 }
1056 fprintf(fp, "\n");
1057
1058 fprintf(fp, "#\n");
1059
1060print_entries:
1061 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1062 pos = rb_entry(nd, struct hist_entry, rb_node);
1063 ret += hist_entry__fprintf(fp, pos, total_samples);
1064 }
1065
1066 if (sort_order == default_sort_order &&
1067 parent_pattern == default_parent_pattern) {
1068 fprintf(fp, "#\n");
1069 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1070 fprintf(fp, "#\n");
1071 }
1072 fprintf(fp, "\n");
1073
1074 free(rem_sq_bracket);
1075
1076 if (show_threads)
1077 perf_read_values_display(fp, &show_threads_values,
1078 raw_printing_style);
1079
1080 return ret;
1081}
1082
1083static unsigned long total = 0,
1084 total_mmap = 0,
1085 total_comm = 0,
1086 total_fork = 0,
1087 total_unknown = 0,
1088 total_lost = 0;
1089
1090static int validate_chain(struct ip_callchain *chain, event_t *event) 76static int validate_chain(struct ip_callchain *chain, event_t *event)
1091{ 77{
1092 unsigned int chain_size; 78 unsigned int chain_size;
@@ -1100,214 +86,57 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1100 return 0; 86 return 0;
1101} 87}
1102 88
1103static int 89static int process_sample_event(event_t *event, struct perf_session *session)
1104process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105{ 90{
1106 char level; 91 struct sample_data data = { .period = 1, };
1107 int show = 0; 92 struct addr_location al;
1108 struct dso *dso = NULL;
1109 struct thread *thread;
1110 u64 ip = event->ip.ip;
1111 u64 period = 1;
1112 struct map *map = NULL;
1113 void *more_data = event->ip.__more_data;
1114 struct ip_callchain *chain = NULL;
1115 int cpumode;
1116
1117 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1118
1119 if (sample_type & PERF_SAMPLE_PERIOD) {
1120 period = *(u64 *)more_data;
1121 more_data += sizeof(u64);
1122 }
1123 93
1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 94 event__parse_sample(event, session->sample_type, &data);
1125 (void *)(offset + head),
1126 (void *)(long)(event->header.size),
1127 event->header.misc,
1128 event->ip.pid, event->ip.tid,
1129 (void *)(long)ip,
1130 (long long)period);
1131 95
1132 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 96 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1133 unsigned int i; 97 data.pid, data.tid, data.ip, data.period);
1134 98
1135 chain = (void *)more_data; 99 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
100 unsigned int i;
1136 101
1137 dump_printf("... chain: nr:%Lu\n", chain->nr); 102 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
1138 103
1139 if (validate_chain(chain, event) < 0) { 104 if (validate_chain(data.callchain, event) < 0) {
1140 eprintf("call-chain problem with event, skipping it.\n"); 105 pr_debug("call-chain problem with event, "
106 "skipping it.\n");
1141 return 0; 107 return 0;
1142 } 108 }
1143 109
1144 if (dump_trace) { 110 if (dump_trace) {
1145 for (i = 0; i < chain->nr; i++) 111 for (i = 0; i < data.callchain->nr; i++)
1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 112 dump_printf("..... %2d: %016Lx\n",
113 i, data.callchain->ips[i]);
1147 } 114 }
1148 } 115 }
1149 116
1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 117 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
1151 118 fprintf(stderr, "problem processing %d event, skipping it.\n",
1152 if (thread == NULL) {
1153 eprintf("problem processing %d event, skipping it.\n",
1154 event->header.type); 119 event->header.type);
1155 return -1; 120 return -1;
1156 } 121 }
1157 122
1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 123 if (al.filtered || (hide_unresolved && al.sym == NULL))
1159 return 0;
1160
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1164 show = SHOW_KERNEL;
1165 level = 'k';
1166
1167 dso = kernel_dso;
1168
1169 dump_printf(" ...... dso: %s\n", dso->name);
1170
1171 } else if (cpumode == PERF_RECORD_MISC_USER) {
1172
1173 show = SHOW_USER;
1174 level = '.';
1175
1176 } else {
1177 show = SHOW_HV;
1178 level = 'H';
1179
1180 dso = hypervisor_dso;
1181
1182 dump_printf(" ...... dso: [hypervisor]\n");
1183 }
1184
1185 if (show & show_mask) {
1186 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1187
1188 if (dso_list && (!dso || !dso->name ||
1189 !strlist__has_entry(dso_list, dso->name)))
1190 return 0;
1191
1192 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1193 return 0;
1194
1195 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1196 eprintf("problem incrementing symbol count, skipping event\n");
1197 return -1;
1198 }
1199 }
1200 total += period;
1201
1202 return 0;
1203}
1204
1205static int
1206process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1207{
1208 struct thread *thread;
1209 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1210
1211 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1212
1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1214 (void *)(offset + head),
1215 (void *)(long)(event->header.size),
1216 event->mmap.pid,
1217 event->mmap.tid,
1218 (void *)(long)event->mmap.start,
1219 (void *)(long)event->mmap.len,
1220 (void *)(long)event->mmap.pgoff,
1221 event->mmap.filename);
1222
1223 if (thread == NULL || map == NULL) {
1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1225 return 0; 124 return 0;
1226 }
1227
1228 thread__insert_map(thread, map);
1229 total_mmap++;
1230
1231 return 0;
1232}
1233
1234static int
1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1236{
1237 struct thread *thread;
1238
1239 thread = threads__findnew(event->comm.pid, &threads, &last_match);
1240 125
1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 126 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
1242 (void *)(offset + head), 127 pr_debug("problem incrementing symbol count, skipping event\n");
1243 (void *)(long)(event->header.size),
1244 event->comm.comm, event->comm.pid);
1245
1246 if (thread == NULL ||
1247 thread__set_comm_adjust(thread, event->comm.comm)) {
1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1249 return -1; 128 return -1;
1250 } 129 }
1251 total_comm++;
1252 130
131 session->events_stats.total += data.period;
1253 return 0; 132 return 0;
1254} 133}
1255 134
1256static int 135static int process_read_event(event_t *event, struct perf_session *session __used)
1257process_task_event(event_t *event, unsigned long offset, unsigned long head)
1258{
1259 struct thread *thread;
1260 struct thread *parent;
1261
1262 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1263 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
1264
1265 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1266 (void *)(offset + head),
1267 (void *)(long)(event->header.size),
1268 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
1269 event->fork.pid, event->fork.tid,
1270 event->fork.ppid, event->fork.ptid);
1271
1272 /*
1273 * A thread clone will have the same PID for both
1274 * parent and child.
1275 */
1276 if (thread == parent)
1277 return 0;
1278
1279 if (event->header.type == PERF_RECORD_EXIT)
1280 return 0;
1281
1282 if (!thread || !parent || thread__fork(thread, parent)) {
1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1284 return -1;
1285 }
1286 total_fork++;
1287
1288 return 0;
1289}
1290
1291static int
1292process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1293{
1294 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1295 (void *)(offset + head),
1296 (void *)(long)(event->header.size),
1297 event->lost.id,
1298 event->lost.lost);
1299
1300 total_lost += event->lost.lost;
1301
1302 return 0;
1303}
1304
1305static int
1306process_read_event(event_t *event, unsigned long offset, unsigned long head)
1307{ 136{
1308 struct perf_event_attr *attr; 137 struct perf_event_attr *attr;
1309 138
1310 attr = perf_header__find_attr(event->read.id, header); 139 attr = perf_header__find_attr(event->read.id, &session->header);
1311 140
1312 if (show_threads) { 141 if (show_threads) {
1313 const char *name = attr ? __event_name(attr->type, attr->config) 142 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -1319,248 +148,117 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1319 event->read.value); 148 event->read.value);
1320 } 149 }
1321 150
1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", 151 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
1323 (void *)(offset + head), 152 attr ? __event_name(attr->type, attr->config) : "FAIL",
1324 (void *)(long)(event->header.size), 153 event->read.value);
1325 event->read.pid,
1326 event->read.tid,
1327 attr ? __event_name(attr->type, attr->config)
1328 : "FAIL",
1329 event->read.value);
1330
1331 return 0;
1332}
1333
1334static int
1335process_event(event_t *event, unsigned long offset, unsigned long head)
1336{
1337 trace_event(event);
1338
1339 switch (event->header.type) {
1340 case PERF_RECORD_SAMPLE:
1341 return process_sample_event(event, offset, head);
1342
1343 case PERF_RECORD_MMAP:
1344 return process_mmap_event(event, offset, head);
1345
1346 case PERF_RECORD_COMM:
1347 return process_comm_event(event, offset, head);
1348
1349 case PERF_RECORD_FORK:
1350 case PERF_RECORD_EXIT:
1351 return process_task_event(event, offset, head);
1352
1353 case PERF_RECORD_LOST:
1354 return process_lost_event(event, offset, head);
1355
1356 case PERF_RECORD_READ:
1357 return process_read_event(event, offset, head);
1358
1359 /*
1360 * We dont process them right now but they are fine:
1361 */
1362
1363 case PERF_RECORD_THROTTLE:
1364 case PERF_RECORD_UNTHROTTLE:
1365 return 0;
1366
1367 default:
1368 return -1;
1369 }
1370 154
1371 return 0; 155 return 0;
1372} 156}
1373 157
1374static int __cmd_report(void) 158static int perf_session__setup_sample_type(struct perf_session *self)
1375{ 159{
1376 int ret, rc = EXIT_FAILURE; 160 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
1377 unsigned long offset = 0;
1378 unsigned long head, shift;
1379 struct stat input_stat;
1380 struct thread *idle;
1381 event_t *event;
1382 uint32_t size;
1383 char *buf;
1384
1385 idle = register_idle_thread(&threads, &last_match);
1386 thread__comm_adjust(idle);
1387
1388 if (show_threads)
1389 perf_read_values_init(&show_threads_values);
1390
1391 input = open(input_name, O_RDONLY);
1392 if (input < 0) {
1393 fprintf(stderr, " failed to open file: %s", input_name);
1394 if (!strcmp(input_name, "perf.data"))
1395 fprintf(stderr, " (try 'perf record' first)");
1396 fprintf(stderr, "\n");
1397 exit(-1);
1398 }
1399
1400 ret = fstat(input, &input_stat);
1401 if (ret < 0) {
1402 perror("failed to stat file");
1403 exit(-1);
1404 }
1405
1406 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1407 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1408 exit(-1);
1409 }
1410
1411 if (!input_stat.st_size) {
1412 fprintf(stderr, "zero-sized file, nothing to do!\n");
1413 exit(0);
1414 }
1415
1416 header = perf_header__read(input);
1417 head = header->data_offset;
1418
1419 sample_type = perf_header__sample_type(header);
1420
1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 if (sort__has_parent) { 161 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no" 162 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call" 163 " callchain data. Did you call"
1425 " perf record without -g?\n"); 164 " perf record without -g?\n");
1426 exit(-1); 165 return -EINVAL;
1427 } 166 }
1428 if (callchain) { 167 if (symbol_conf.use_callchain) {
1429 fprintf(stderr, "selected -g but no callchain data." 168 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without" 169 " Did you call perf record without"
1431 " -g?\n"); 170 " -g?\n");
1432 exit(-1); 171 return -1;
1433 } 172 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 173 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
1435 callchain = 1; 174 !symbol_conf.use_callchain) {
175 symbol_conf.use_callchain = true;
1436 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
1438 " params\n"); 178 " params\n");
1439 exit(-1); 179 return -EINVAL;
1440 } 180 }
1441 } 181 }
1442 182
1443 if (load_kernel() < 0) { 183 return 0;
1444 perror("failed to load kernel symbols"); 184}
1445 return EXIT_FAILURE;
1446 }
1447
1448 if (!full_paths) {
1449 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1450 perror("failed to get the current directory");
1451 return EXIT_FAILURE;
1452 }
1453 cwdlen = strlen(cwd);
1454 } else {
1455 cwd = NULL;
1456 cwdlen = 0;
1457 }
1458
1459 shift = page_size * (head / page_size);
1460 offset += shift;
1461 head -= shift;
1462
1463remap:
1464 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1465 MAP_SHARED, input, offset);
1466 if (buf == MAP_FAILED) {
1467 perror("failed to mmap file");
1468 exit(-1);
1469 }
1470
1471more:
1472 event = (event_t *)(buf + head);
1473
1474 size = event->header.size;
1475 if (!size)
1476 size = 8;
1477
1478 if (head + event->header.size >= page_size * mmap_window) {
1479 int munmap_ret;
1480
1481 shift = page_size * (head / page_size);
1482
1483 munmap_ret = munmap(buf, page_size * mmap_window);
1484 assert(munmap_ret == 0);
1485
1486 offset += shift;
1487 head -= shift;
1488 goto remap;
1489 }
1490
1491 size = event->header.size;
1492 185
1493 dump_printf("\n%p [%p]: event: %d\n", 186static struct perf_event_ops event_ops = {
1494 (void *)(offset + head), 187 .sample = process_sample_event,
1495 (void *)(long)event->header.size, 188 .mmap = event__process_mmap,
1496 event->header.type); 189 .comm = event__process_comm,
190 .exit = event__process_task,
191 .fork = event__process_task,
192 .lost = event__process_lost,
193 .read = process_read_event,
194};
1497 195
1498 if (!size || process_event(event, offset, head) < 0) { 196static int __cmd_report(void)
197{
198 int ret = -EINVAL;
199 struct perf_session *session;
1499 200
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n", 201 session = perf_session__new(input_name, O_RDONLY, force);
1501 (void *)(offset + head), 202 if (session == NULL)
1502 (void *)(long)(event->header.size), 203 return -ENOMEM;
1503 event->header.type);
1504 204
1505 total_unknown++; 205 if (show_threads)
206 perf_read_values_init(&show_threads_values);
1506 207
1507 /* 208 ret = perf_session__setup_sample_type(session);
1508 * assume we lost track of the stream, check alignment, and 209 if (ret)
1509 * increment a single u64 in the hope to catch on again 'soon'. 210 goto out_delete;
1510 */
1511 211
1512 if (unlikely(head & 7)) 212 ret = perf_session__process_events(session, &event_ops);
1513 head &= ~7ULL; 213 if (ret)
214 goto out_delete;
1514 215
1515 size = 8; 216 if (dump_trace) {
217 event__print_totals();
218 goto out_delete;
1516 } 219 }
1517 220
1518 head += size; 221 if (verbose > 3)
1519 222 perf_session__fprintf(session, stdout);
1520 if (offset + head >= header->data_offset + header->data_size)
1521 goto done;
1522 223
1523 if (offset + head < (unsigned long)input_stat.st_size) 224 if (verbose > 2)
1524 goto more;
1525
1526done:
1527 rc = EXIT_SUCCESS;
1528 close(input);
1529
1530 dump_printf(" IP events: %10ld\n", total);
1531 dump_printf(" mmap events: %10ld\n", total_mmap);
1532 dump_printf(" comm events: %10ld\n", total_comm);
1533 dump_printf(" fork events: %10ld\n", total_fork);
1534 dump_printf(" lost events: %10ld\n", total_lost);
1535 dump_printf(" unknown events: %10ld\n", total_unknown);
1536
1537 if (dump_trace)
1538 return 0;
1539
1540 if (verbose >= 3)
1541 threads__fprintf(stdout, &threads);
1542
1543 if (verbose >= 2)
1544 dsos__fprintf(stdout); 225 dsos__fprintf(stdout);
1545 226
1546 collapse__resort(); 227 perf_session__collapse_resort(session);
1547 output__resort(total); 228 perf_session__output_resort(session, session->events_stats.total);
1548 output__fprintf(stdout, total); 229 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total);
230 perf_session__fprintf_hists(session, NULL, false, stdout);
231 if (sort_order == default_sort_order &&
232 parent_pattern == default_parent_pattern)
233 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
1549 234
1550 if (show_threads) 235 if (show_threads) {
236 bool raw_printing_style = !strcmp(pretty_printing_style, "raw");
237 perf_read_values_display(stdout, &show_threads_values,
238 raw_printing_style);
1551 perf_read_values_destroy(&show_threads_values); 239 perf_read_values_destroy(&show_threads_values);
1552 240 }
1553 return rc; 241out_delete:
242 perf_session__delete(session);
243 return ret;
1554} 244}
1555 245
1556static int 246static int
1557parse_callchain_opt(const struct option *opt __used, const char *arg, 247parse_callchain_opt(const struct option *opt __used, const char *arg,
1558 int unset __used) 248 int unset)
1559{ 249{
1560 char *tok; 250 char *tok;
1561 char *endptr; 251 char *endptr;
1562 252
1563 callchain = 1; 253 /*
254 * --no-call-graph
255 */
256 if (unset) {
257 dont_use_callchains = true;
258 return 0;
259 }
260
261 symbol_conf.use_callchain = true;
1564 262
1565 if (!arg) 263 if (!arg)
1566 return 0; 264 return 0;
@@ -1581,7 +279,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1581 279
1582 else if (!strncmp(tok, "none", strlen(arg))) { 280 else if (!strncmp(tok, "none", strlen(arg))) {
1583 callchain_param.mode = CHAIN_NONE; 281 callchain_param.mode = CHAIN_NONE;
1584 callchain = 0; 282 symbol_conf.use_callchain = false;
1585 283
1586 return 0; 284 return 0;
1587 } 285 }
@@ -1618,11 +316,12 @@ static const struct option options[] = {
1618 "be more verbose (show symbol address, etc)"), 316 "be more verbose (show symbol address, etc)"),
1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 317 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1620 "dump raw trace in ASCII"), 318 "dump raw trace in ASCII"),
1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 319 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
320 "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 321 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules, 322 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"), 323 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 324 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1626 "Show a column with the number of samples"), 325 "Show a column with the number of samples"),
1627 OPT_BOOLEAN('T', "threads", &show_threads, 326 OPT_BOOLEAN('T', "threads", &show_threads,
1628 "Show per-thread event counters"), 327 "Show per-thread event counters"),
@@ -1630,79 +329,48 @@ static const struct option options[] = {
1630 "pretty printing style key: normal raw"), 329 "pretty printing style key: normal raw"),
1631 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 330 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1632 "sort by key(s): pid, comm, dso, symbol, parent"), 331 "sort by key(s): pid, comm, dso, symbol, parent"),
1633 OPT_BOOLEAN('P', "full-paths", &full_paths, 332 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
1634 "Don't shorten the pathnames taking into account the cwd"), 333 "Don't shorten the pathnames taking into account the cwd"),
1635 OPT_STRING('p', "parent", &parent_pattern, "regex", 334 OPT_STRING('p', "parent", &parent_pattern, "regex",
1636 "regex filter to identify parent, see: '--sort parent'"), 335 "regex filter to identify parent, see: '--sort parent'"),
1637 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 336 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
1638 "Only display entries with parent-match"), 337 "Only display entries with parent-match"),
1639 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 338 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1640 "Display callchains using output_type and min percent threshold. " 339 "Display callchains using output_type and min percent threshold. "
1641 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 340 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1642 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 341 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1643 "only consider symbols in these dsos"), 342 "only consider symbols in these dsos"),
1644 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 343 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1645 "only consider symbols in these comms"), 344 "only consider symbols in these comms"),
1646 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 345 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1647 "only consider these symbols"), 346 "only consider these symbols"),
1648 OPT_STRING('w', "column-widths", &col_width_list_str, 347 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1649 "width[,width...]", 348 "width[,width...]",
1650 "don't try to adjust column width, use these fixed values"), 349 "don't try to adjust column width, use these fixed values"),
1651 OPT_STRING('t', "field-separator", &field_sep, "separator", 350 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
1652 "separator for columns, no spaces will be added between " 351 "separator for columns, no spaces will be added between "
1653 "columns '.' is reserved."), 352 "columns '.' is reserved."),
353 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
354 "Only display entries resolved to a symbol"),
1654 OPT_END() 355 OPT_END()
1655}; 356};
1656 357
1657static void setup_sorting(void)
1658{
1659 char *tmp, *tok, *str = strdup(sort_order);
1660
1661 for (tok = strtok_r(str, ", ", &tmp);
1662 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1663 if (sort_dimension__add(tok) < 0) {
1664 error("Unknown --sort key: `%s'", tok);
1665 usage_with_options(report_usage, options);
1666 }
1667 }
1668
1669 free(str);
1670}
1671
1672static void setup_list(struct strlist **list, const char *list_str,
1673 struct sort_entry *se, const char *list_name,
1674 FILE *fp)
1675{
1676 if (list_str) {
1677 *list = strlist__new(true, list_str);
1678 if (!*list) {
1679 fprintf(stderr, "problems parsing %s list\n",
1680 list_name);
1681 exit(129);
1682 }
1683 if (strlist__nr_entries(*list) == 1) {
1684 fprintf(fp, "# %s: %s\n", list_name,
1685 strlist__entry(*list, 0)->s);
1686 se->elide = true;
1687 }
1688 }
1689}
1690
1691int cmd_report(int argc, const char **argv, const char *prefix __used) 358int cmd_report(int argc, const char **argv, const char *prefix __used)
1692{ 359{
1693 symbol__init(); 360 argc = parse_options(argc, argv, options, report_usage, 0);
1694 361
1695 page_size = getpagesize(); 362 setup_pager();
1696 363
1697 argc = parse_options(argc, argv, options, report_usage, 0); 364 if (symbol__init() < 0)
365 return -1;
1698 366
1699 setup_sorting(); 367 setup_sorting(report_usage, options);
1700 368
1701 if (parent_pattern != default_parent_pattern) { 369 if (parent_pattern != default_parent_pattern) {
1702 sort_dimension__add("parent"); 370 sort_dimension__add("parent");
1703 sort_parent.elide = 1; 371 sort_parent.elide = 1;
1704 } else 372 } else
1705 exclude_other = 0; 373 symbol_conf.exclude_other = false;
1706 374
1707 /* 375 /*
1708 * Any (unrecognized) arguments left? 376 * Any (unrecognized) arguments left?
@@ -1710,17 +378,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1710 if (argc) 378 if (argc)
1711 usage_with_options(report_usage, options); 379 usage_with_options(report_usage, options);
1712 380
1713 setup_pager(); 381 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1714 382 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1715 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 383 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1716 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1717 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
1718
1719 if (field_sep && *field_sep == '.') {
1720 fputs("'.' is the only non valid --field-separator argument\n",
1721 stderr);
1722 exit(129);
1723 }
1724 384
1725 return __cmd_report(); 385 return __cmd_report();
1726} 386}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ce2d5be4f30e..4f5a03e43444 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,13 +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 15
15#include <sys/types.h>
16#include <sys/prctl.h> 16#include <sys/prctl.h>
17 17
18#include <semaphore.h> 18#include <semaphore.h>
@@ -20,26 +20,15 @@
20#include <math.h> 20#include <math.h>
21 21
22static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31
32static struct perf_header *header;
33static u64 sample_type;
34 23
35static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
37 26
27static int profile_cpu = -1;
28
38#define PR_SET_NAME 15 /* Set process name */ 29#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096 30#define MAX_CPUS 4096
40 31
41#define BUG_ON(x) assert(!(x))
42
43static u64 run_measurement_overhead; 32static u64 run_measurement_overhead;
44static u64 sleep_measurement_overhead; 33static u64 sleep_measurement_overhead;
45 34
@@ -74,6 +63,7 @@ enum sched_event_type {
74 SCHED_EVENT_RUN, 63 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP, 64 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP, 65 SCHED_EVENT_WAKEUP,
66 SCHED_EVENT_MIGRATION,
77}; 67};
78 68
79struct sched_atom { 69struct sched_atom {
@@ -147,6 +137,7 @@ struct work_atoms {
147 struct thread *thread; 137 struct thread *thread;
148 struct rb_node node; 138 struct rb_node node;
149 u64 max_lat; 139 u64 max_lat;
140 u64 max_lat_at;
150 u64 total_lat; 141 u64 total_lat;
151 u64 nb_atoms; 142 u64 nb_atoms;
152 u64 total_runtime; 143 u64 total_runtime;
@@ -226,7 +217,7 @@ static void calibrate_sleep_measurement_overhead(void)
226static struct sched_atom * 217static struct sched_atom *
227get_new_event(struct task_desc *task, u64 timestamp) 218get_new_event(struct task_desc *task, u64 timestamp)
228{ 219{
229 struct sched_atom *event = calloc(1, sizeof(*event)); 220 struct sched_atom *event = zalloc(sizeof(*event));
230 unsigned long idx = task->nr_events; 221 unsigned long idx = task->nr_events;
231 size_t size; 222 size_t size;
232 223
@@ -294,7 +285,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
294 return; 285 return;
295 } 286 }
296 287
297 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); 288 wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
298 sem_init(wakee_event->wait_sem, 0, 0); 289 sem_init(wakee_event->wait_sem, 0, 0);
299 wakee_event->specific_wait = 1; 290 wakee_event->specific_wait = 1;
300 event->wait_sem = wakee_event->wait_sem; 291 event->wait_sem = wakee_event->wait_sem;
@@ -324,7 +315,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
324 if (task) 315 if (task)
325 return task; 316 return task;
326 317
327 task = calloc(1, sizeof(*task)); 318 task = zalloc(sizeof(*task));
328 task->pid = pid; 319 task->pid = pid;
329 task->nr = nr_tasks; 320 task->nr = nr_tasks;
330 strcpy(task->comm, comm); 321 strcpy(task->comm, comm);
@@ -398,6 +389,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
398 ret = sem_post(atom->wait_sem); 389 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret); 390 BUG_ON(ret);
400 break; 391 break;
392 case SCHED_EVENT_MIGRATION:
393 break;
401 default: 394 default:
402 BUG_ON(1); 395 BUG_ON(1);
403 } 396 }
@@ -418,34 +411,33 @@ static u64 get_cpu_usage_nsec_parent(void)
418 return sum; 411 return sum;
419} 412}
420 413
421static u64 get_cpu_usage_nsec_self(void) 414static int self_open_counters(void)
422{ 415{
423 char filename [] = "/proc/1234567890/sched"; 416 struct perf_event_attr attr;
424 unsigned long msecs, nsecs; 417 int fd;
425 char *line = NULL;
426 u64 total = 0;
427 size_t len = 0;
428 ssize_t chars;
429 FILE *file;
430 int ret;
431 418
432 sprintf(filename, "/proc/%d/sched", getpid()); 419 memset(&attr, 0, sizeof(attr));
433 file = fopen(filename, "r");
434 BUG_ON(!file);
435 420
436 while ((chars = getline(&line, &len, file)) != -1) { 421 attr.type = PERF_TYPE_SOFTWARE;
437 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", 422 attr.config = PERF_COUNT_SW_TASK_CLOCK;
438 &msecs, &nsecs); 423
439 if (ret == 2) { 424 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
440 total = msecs*1e6 + nsecs;
441 break;
442 }
443 }
444 if (line)
445 free(line);
446 fclose(file);
447 425
448 return total; 426 if (fd < 0)
427 die("Error: sys_perf_event_open() syscall returned"
428 "with %d (%s)\n", fd, strerror(errno));
429 return fd;
430}
431
432static u64 get_cpu_usage_nsec_self(int fd)
433{
434 u64 runtime;
435 int ret;
436
437 ret = read(fd, &runtime, sizeof(runtime));
438 BUG_ON(ret != sizeof(runtime));
439
440 return runtime;
449} 441}
450 442
451static void *thread_func(void *ctx) 443static void *thread_func(void *ctx)
@@ -454,9 +446,11 @@ static void *thread_func(void *ctx)
454 u64 cpu_usage_0, cpu_usage_1; 446 u64 cpu_usage_0, cpu_usage_1;
455 unsigned long i, ret; 447 unsigned long i, ret;
456 char comm2[22]; 448 char comm2[22];
449 int fd;
457 450
458 sprintf(comm2, ":%s", this_task->comm); 451 sprintf(comm2, ":%s", this_task->comm);
459 prctl(PR_SET_NAME, comm2); 452 prctl(PR_SET_NAME, comm2);
453 fd = self_open_counters();
460 454
461again: 455again:
462 ret = sem_post(&this_task->ready_for_work); 456 ret = sem_post(&this_task->ready_for_work);
@@ -466,16 +460,15 @@ again:
466 ret = pthread_mutex_unlock(&start_work_mutex); 460 ret = pthread_mutex_unlock(&start_work_mutex);
467 BUG_ON(ret); 461 BUG_ON(ret);
468 462
469 cpu_usage_0 = get_cpu_usage_nsec_self(); 463 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
470 464
471 for (i = 0; i < this_task->nr_events; i++) { 465 for (i = 0; i < this_task->nr_events; i++) {
472 this_task->curr_event = i; 466 this_task->curr_event = i;
473 process_sched_event(this_task, this_task->atoms[i]); 467 process_sched_event(this_task, this_task->atoms[i]);
474 } 468 }
475 469
476 cpu_usage_1 = get_cpu_usage_nsec_self(); 470 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
477 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 471 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
478
479 ret = sem_post(&this_task->work_done_sem); 472 ret = sem_post(&this_task->work_done_sem);
480 BUG_ON(ret); 473 BUG_ON(ret);
481 474
@@ -632,34 +625,6 @@ static void test_calibrations(void)
632 printf("the sleep test took %Ld nsecs\n", T1-T0); 625 printf("the sleep test took %Ld nsecs\n", T1-T0);
633} 626}
634 627
635static int
636process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{
638 struct thread *thread;
639
640 thread = threads__findnew(event->comm.pid, &threads, &last_match);
641
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head),
644 (void *)(long)(event->header.size),
645 event->comm.comm, event->comm.pid);
646
647 if (thread == NULL ||
648 thread__set_comm(thread, event->comm.comm)) {
649 dump_printf("problem processing perf_event_comm, skipping event.\n");
650 return -1;
651 }
652 total_comm++;
653
654 return 0;
655}
656
657
658struct raw_event_sample {
659 u32 size;
660 char data[0];
661};
662
663#define FILL_FIELD(ptr, field, event, data) \ 628#define FILL_FIELD(ptr, field, event, data) \
664 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) 629 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
665 630
@@ -745,20 +710,39 @@ struct trace_fork_event {
745 u32 child_pid; 710 u32 child_pid;
746}; 711};
747 712
713struct trace_migrate_task_event {
714 u32 size;
715
716 u16 common_type;
717 u8 common_flags;
718 u8 common_preempt_count;
719 u32 common_pid;
720 u32 common_tgid;
721
722 char comm[16];
723 u32 pid;
724
725 u32 prio;
726 u32 cpu;
727};
728
748struct trace_sched_handler { 729struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
750 struct event *, 732 struct event *,
751 int cpu, 733 int cpu,
752 u64 timestamp, 734 u64 timestamp,
753 struct thread *thread); 735 struct thread *thread);
754 736
755 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
756 struct event *, 739 struct event *,
757 int cpu, 740 int cpu,
758 u64 timestamp, 741 u64 timestamp,
759 struct thread *thread); 742 struct thread *thread);
760 743
761 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
762 struct event *, 746 struct event *,
763 int cpu, 747 int cpu,
764 u64 timestamp, 748 u64 timestamp,
@@ -769,11 +753,19 @@ struct trace_sched_handler {
769 int cpu, 753 int cpu,
770 u64 timestamp, 754 u64 timestamp,
771 struct thread *thread); 755 struct thread *thread);
756
757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
759 struct event *,
760 int cpu,
761 u64 timestamp,
762 struct thread *thread);
772}; 763};
773 764
774 765
775static void 766static void
776replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
777 struct event *event, 769 struct event *event,
778 int cpu __used, 770 int cpu __used,
779 u64 timestamp __used, 771 u64 timestamp __used,
@@ -800,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
800 792
801static void 793static void
802replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
803 struct event *event, 796 struct event *event,
804 int cpu, 797 int cpu,
805 u64 timestamp, 798 u64 timestamp,
@@ -941,9 +934,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
941 934
942static void thread_atoms_insert(struct thread *thread) 935static void thread_atoms_insert(struct thread *thread)
943{ 936{
944 struct work_atoms *atoms; 937 struct work_atoms *atoms = zalloc(sizeof(*atoms));
945
946 atoms = calloc(sizeof(*atoms), 1);
947 if (!atoms) 938 if (!atoms)
948 die("No memory"); 939 die("No memory");
949 940
@@ -975,9 +966,7 @@ add_sched_out_event(struct work_atoms *atoms,
975 char run_state, 966 char run_state,
976 u64 timestamp) 967 u64 timestamp)
977{ 968{
978 struct work_atom *atom; 969 struct work_atom *atom = zalloc(sizeof(*atom));
979
980 atom = calloc(sizeof(*atom), 1);
981 if (!atom) 970 if (!atom)
982 die("Non memory"); 971 die("Non memory");
983 972
@@ -1028,13 +1017,16 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1028 1017
1029 delta = atom->sched_in_time - atom->wake_up_time; 1018 delta = atom->sched_in_time - atom->wake_up_time;
1030 atoms->total_lat += delta; 1019 atoms->total_lat += delta;
1031 if (delta > atoms->max_lat) 1020 if (delta > atoms->max_lat) {
1032 atoms->max_lat = delta; 1021 atoms->max_lat = delta;
1022 atoms->max_lat_at = timestamp;
1023 }
1033 atoms->nb_atoms++; 1024 atoms->nb_atoms++;
1034} 1025}
1035 1026
1036static void 1027static void
1037latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1038 struct event *event __used, 1030 struct event *event __used,
1039 int cpu, 1031 int cpu,
1040 u64 timestamp, 1032 u64 timestamp,
@@ -1058,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1058 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1059 1051
1060 1052
1061 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1062 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1063 1055
1064 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1065 if (!out_events) { 1057 if (!out_events) {
@@ -1087,18 +1079,16 @@ latency_switch_event(struct trace_switch_event *switch_event,
1087 1079
1088static void 1080static void
1089latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1090 struct event *event __used, 1083 struct event *event __used,
1091 int cpu, 1084 int cpu,
1092 u64 timestamp, 1085 u64 timestamp,
1093 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1094{ 1087{
1095 struct work_atoms *atoms; 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1096 struct thread *thread; 1089 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1097 1090
1098 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1099
1100 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1101 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1102 if (!atoms) { 1092 if (!atoms) {
1103 thread_atoms_insert(thread); 1093 thread_atoms_insert(thread);
1104 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1094 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1112,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1112 1102
1113static void 1103static void
1114latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1115 struct event *__event __used, 1106 struct event *__event __used,
1116 int cpu __used, 1107 int cpu __used,
1117 u64 timestamp, 1108 u64 timestamp,
@@ -1125,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1125 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1126 return; 1117 return;
1127 1118
1128 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1129 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1130 if (!atoms) { 1121 if (!atoms) {
1131 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1139,7 +1130,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1139 1130
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1131 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141 1132
1142 if (atom->state != THREAD_SLEEPING) 1133 /*
1134 * You WILL be missing events if you've recorded only
1135 * one CPU, or are only looking at only one, so don't
1136 * make useless noise.
1137 */
1138 if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++; 1139 nr_state_machine_bugs++;
1144 1140
1145 nr_timestamps++; 1141 nr_timestamps++;
@@ -1152,11 +1148,52 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1152 atom->wake_up_time = timestamp; 1148 atom->wake_up_time = timestamp;
1153} 1149}
1154 1150
1151static void
1152latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1153 struct perf_session *session,
1154 struct event *__event __used,
1155 int cpu __used,
1156 u64 timestamp,
1157 struct thread *thread __used)
1158{
1159 struct work_atoms *atoms;
1160 struct work_atom *atom;
1161 struct thread *migrant;
1162
1163 /*
1164 * Only need to worry about migration when profiling one CPU.
1165 */
1166 if (profile_cpu == -1)
1167 return;
1168
1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1171 if (!atoms) {
1172 thread_atoms_insert(migrant);
1173 register_pid(migrant->pid, migrant->comm);
1174 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1175 if (!atoms)
1176 die("migration-event: Internal tree error");
1177 add_sched_out_event(atoms, 'R', timestamp);
1178 }
1179
1180 BUG_ON(list_empty(&atoms->work_list));
1181
1182 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1183 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1184
1185 nr_timestamps++;
1186
1187 if (atom->sched_out_time > timestamp)
1188 nr_unordered_timestamps++;
1189}
1190
1155static struct trace_sched_handler lat_ops = { 1191static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event, 1192 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event, 1193 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event, 1194 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event, 1195 .fork_event = latency_fork_event,
1196 .migrate_task_event = latency_migrate_task_event,
1160}; 1197};
1161 1198
1162static void output_lat_thread(struct work_atoms *work_list) 1199static void output_lat_thread(struct work_atoms *work_list)
@@ -1183,10 +1220,11 @@ static void output_lat_thread(struct work_atoms *work_list)
1183 1220
1184 avg = work_list->total_lat / work_list->nb_atoms; 1221 avg = work_list->total_lat / work_list->nb_atoms;
1185 1222
1186 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",
1187 (double)work_list->total_runtime / 1e6, 1224 (double)work_list->total_runtime / 1e6,
1188 work_list->nb_atoms, (double)avg / 1e6, 1225 work_list->nb_atoms, (double)avg / 1e6,
1189 (double)work_list->max_lat / 1e6); 1226 (double)work_list->max_lat / 1e6,
1227 (double)work_list->max_lat_at / 1e9);
1190} 1228}
1191 1229
1192static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1230static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1323,7 +1361,7 @@ static void sort_lat(void)
1323static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1324 1362
1325static void 1363static void
1326process_sched_wakeup_event(struct raw_event_sample *raw, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1327 struct event *event, 1365 struct event *event,
1328 int cpu __used, 1366 int cpu __used,
1329 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1331,16 +1369,17 @@ process_sched_wakeup_event(struct raw_event_sample *raw,
1331{ 1369{
1332 struct trace_wakeup_event wakeup_event; 1370 struct trace_wakeup_event wakeup_event;
1333 1371
1334 FILL_COMMON_FIELDS(wakeup_event, event, raw->data); 1372 FILL_COMMON_FIELDS(wakeup_event, event, data);
1335 1373
1336 FILL_ARRAY(wakeup_event, comm, event, raw->data); 1374 FILL_ARRAY(wakeup_event, comm, event, data);
1337 FILL_FIELD(wakeup_event, pid, event, raw->data); 1375 FILL_FIELD(wakeup_event, pid, event, data);
1338 FILL_FIELD(wakeup_event, prio, event, raw->data); 1376 FILL_FIELD(wakeup_event, prio, event, data);
1339 FILL_FIELD(wakeup_event, success, event, raw->data); 1377 FILL_FIELD(wakeup_event, success, event, data);
1340 FILL_FIELD(wakeup_event, cpu, event, raw->data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1341 1379
1342 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1343 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1344} 1383}
1345 1384
1346/* 1385/*
@@ -1358,6 +1397,7 @@ static char next_shortname2 = '0';
1358 1397
1359static void 1398static void
1360map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1361 struct event *event __used, 1401 struct event *event __used,
1362 int this_cpu, 1402 int this_cpu,
1363 u64 timestamp, 1403 u64 timestamp,
@@ -1385,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1385 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1386 1426
1387 1427
1388 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1389 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1390 1430
1391 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1392 1432
@@ -1436,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1436 1476
1437 1477
1438static void 1478static void
1439process_sched_switch_event(struct raw_event_sample *raw, 1479process_sched_switch_event(void *data, struct perf_session *session,
1440 struct event *event, 1480 struct event *event,
1441 int this_cpu, 1481 int this_cpu,
1442 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1444,15 +1484,15 @@ process_sched_switch_event(struct raw_event_sample *raw,
1444{ 1484{
1445 struct trace_switch_event switch_event; 1485 struct trace_switch_event switch_event;
1446 1486
1447 FILL_COMMON_FIELDS(switch_event, event, raw->data); 1487 FILL_COMMON_FIELDS(switch_event, event, data);
1448 1488
1449 FILL_ARRAY(switch_event, prev_comm, event, raw->data); 1489 FILL_ARRAY(switch_event, prev_comm, event, data);
1450 FILL_FIELD(switch_event, prev_pid, event, raw->data); 1490 FILL_FIELD(switch_event, prev_pid, event, data);
1451 FILL_FIELD(switch_event, prev_prio, event, raw->data); 1491 FILL_FIELD(switch_event, prev_prio, event, data);
1452 FILL_FIELD(switch_event, prev_state, event, raw->data); 1492 FILL_FIELD(switch_event, prev_state, event, data);
1453 FILL_ARRAY(switch_event, next_comm, event, raw->data); 1493 FILL_ARRAY(switch_event, next_comm, event, data);
1454 FILL_FIELD(switch_event, next_pid, event, raw->data); 1494 FILL_FIELD(switch_event, next_pid, event, data);
1455 FILL_FIELD(switch_event, next_prio, event, raw->data); 1495 FILL_FIELD(switch_event, next_prio, event, data);
1456 1496
1457 if (curr_pid[this_cpu] != (u32)-1) { 1497 if (curr_pid[this_cpu] != (u32)-1) {
1458 /* 1498 /*
@@ -1463,13 +1503,14 @@ process_sched_switch_event(struct raw_event_sample *raw,
1463 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1464 } 1504 }
1465 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1466 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);
1467 1508
1468 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1469} 1510}
1470 1511
1471static void 1512static void
1472process_sched_runtime_event(struct raw_event_sample *raw, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1473 struct event *event, 1514 struct event *event,
1474 int cpu __used, 1515 int cpu __used,
1475 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1477,17 +1518,17 @@ process_sched_runtime_event(struct raw_event_sample *raw,
1477{ 1518{
1478 struct trace_runtime_event runtime_event; 1519 struct trace_runtime_event runtime_event;
1479 1520
1480 FILL_ARRAY(runtime_event, comm, event, raw->data); 1521 FILL_ARRAY(runtime_event, comm, event, data);
1481 FILL_FIELD(runtime_event, pid, event, raw->data); 1522 FILL_FIELD(runtime_event, pid, event, data);
1482 FILL_FIELD(runtime_event, runtime, event, raw->data); 1523 FILL_FIELD(runtime_event, runtime, event, data);
1483 FILL_FIELD(runtime_event, vruntime, event, raw->data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1484 1525
1485 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1486 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1487} 1528}
1488 1529
1489static void 1530static void
1490process_sched_fork_event(struct raw_event_sample *raw, 1531process_sched_fork_event(void *data,
1491 struct event *event, 1532 struct event *event,
1492 int cpu __used, 1533 int cpu __used,
1493 u64 timestamp __used, 1534 u64 timestamp __used,
@@ -1495,15 +1536,16 @@ process_sched_fork_event(struct raw_event_sample *raw,
1495{ 1536{
1496 struct trace_fork_event fork_event; 1537 struct trace_fork_event fork_event;
1497 1538
1498 FILL_COMMON_FIELDS(fork_event, event, raw->data); 1539 FILL_COMMON_FIELDS(fork_event, event, data);
1499 1540
1500 FILL_ARRAY(fork_event, parent_comm, event, raw->data); 1541 FILL_ARRAY(fork_event, parent_comm, event, data);
1501 FILL_FIELD(fork_event, parent_pid, event, raw->data); 1542 FILL_FIELD(fork_event, parent_pid, event, data);
1502 FILL_ARRAY(fork_event, child_comm, event, raw->data); 1543 FILL_ARRAY(fork_event, child_comm, event, data);
1503 FILL_FIELD(fork_event, child_pid, event, raw->data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1504 1545
1505 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1506 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1507} 1549}
1508 1550
1509static void 1551static void
@@ -1517,233 +1559,115 @@ process_sched_exit_event(struct event *event,
1517} 1559}
1518 1560
1519static void 1561static void
1520process_raw_event(event_t *raw_event __used, void *more_data, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1521 int cpu, u64 timestamp, struct thread *thread) 1563 struct event *event,
1564 int cpu __used,
1565 u64 timestamp __used,
1566 struct thread *thread __used)
1567{
1568 struct trace_migrate_task_event migrate_task_event;
1569
1570 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1571
1572 FILL_ARRAY(migrate_task_event, comm, event, data);
1573 FILL_FIELD(migrate_task_event, pid, event, data);
1574 FILL_FIELD(migrate_task_event, prio, event, data);
1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1576
1577 if (trace_handler->migrate_task_event)
1578 trace_handler->migrate_task_event(&migrate_task_event, session,
1579 event, cpu, timestamp, thread);
1580}
1581
1582static void
1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1522{ 1585{
1523 struct raw_event_sample *raw = more_data;
1524 struct event *event; 1586 struct event *event;
1525 int type; 1587 int type;
1526 1588
1527 type = trace_parse_common_type(raw->data); 1589
1590 type = trace_parse_common_type(data);
1528 event = trace_find_event(type); 1591 event = trace_find_event(type);
1529 1592
1530 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1531 process_sched_switch_event(raw, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1532 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1533 process_sched_runtime_event(raw, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1534 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1535 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1536 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1537 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1538 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1605 if (!strcmp(event->name, "sched_migrate_task"))
1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1542} 1607}
1543 1608
1544static int 1609static int process_sample_event(event_t *event, struct perf_session *session)
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{ 1610{
1547 char level; 1611 struct sample_data data;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread; 1612 struct thread *thread;
1551 u64 ip = event->ip.ip;
1552 u64 timestamp = -1;
1553 u32 cpu = -1;
1554 u64 period = 1;
1555 void *more_data = event->ip.__more_data;
1556 int cpumode;
1557
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559
1560 if (sample_type & PERF_SAMPLE_TIME) {
1561 timestamp = *(u64 *)more_data;
1562 more_data += sizeof(u64);
1563 }
1564 1613
1565 if (sample_type & PERF_SAMPLE_CPU) { 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1566 cpu = *(u32 *)more_data; 1615 return 0;
1567 more_data += sizeof(u32);
1568 more_data += sizeof(u32); /* reserved */
1569 }
1570 1616
1571 if (sample_type & PERF_SAMPLE_PERIOD) { 1617 memset(&data, 0, sizeof(data));
1572 period = *(u64 *)more_data; 1618 data.time = -1;
1573 more_data += sizeof(u64); 1619 data.cpu = -1;
1574 } 1620 data.period = -1;
1575 1621
1576 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 1622 event__parse_sample(event, session->sample_type, &data);
1577 (void *)(offset + head),
1578 (void *)(long)(event->header.size),
1579 event->header.misc,
1580 event->ip.pid, event->ip.tid,
1581 (void *)(long)ip,
1582 (long long)period);
1583 1623
1584 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1625 data.pid, data.tid, data.ip, data.period);
1585 1626
1627 thread = perf_session__findnew(session, data.pid);
1586 if (thread == NULL) { 1628 if (thread == NULL) {
1587 eprintf("problem processing %d event, skipping it.\n", 1629 pr_debug("problem processing %d event, skipping it.\n",
1588 event->header.type); 1630 event->header.type);
1589 return -1; 1631 return -1;
1590 } 1632 }
1591 1633
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1634 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1593
1594 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1595 show = SHOW_KERNEL;
1596 level = 'k';
1597
1598 dso = kernel_dso;
1599
1600 dump_printf(" ...... dso: %s\n", dso->name);
1601
1602 } else if (cpumode == PERF_RECORD_MISC_USER) {
1603
1604 show = SHOW_USER;
1605 level = '.';
1606
1607 } else {
1608 show = SHOW_HV;
1609 level = 'H';
1610
1611 dso = hypervisor_dso;
1612 1635
1613 dump_printf(" ...... dso: [hypervisor]\n"); 1636 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1614 } 1637 return 0;
1615 1638
1616 if (sample_type & PERF_SAMPLE_RAW) 1639 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618 1640
1619 return 0; 1641 return 0;
1620} 1642}
1621 1643
1622static int 1644static int process_lost_event(event_t *event __used,
1623process_event(event_t *event, unsigned long offset, unsigned long head) 1645 struct perf_session *session __used)
1624{ 1646{
1625 trace_event(event); 1647 nr_lost_chunks++;
1626 1648 nr_lost_events += event->lost.lost;
1627 nr_events++;
1628 switch (event->header.type) {
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635
1636 case PERF_RECORD_COMM:
1637 return process_comm_event(event, offset, head);
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641
1642 case PERF_RECORD_SAMPLE:
1643 return process_sample_event(event, offset, head);
1644
1645 case PERF_RECORD_MAX:
1646 default:
1647 return -1;
1648 }
1649 1649
1650 return 0; 1650 return 0;
1651} 1651}
1652 1652
1653static struct perf_event_ops event_ops = {
1654 .sample = process_sample_event,
1655 .comm = event__process_comm,
1656 .lost = process_lost_event,
1657};
1658
1653static int read_events(void) 1659static int read_events(void)
1654{ 1660{
1655 int ret, rc = EXIT_FAILURE; 1661 int err = -EINVAL;
1656 unsigned long offset = 0; 1662 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1657 unsigned long head = 0; 1663 if (session == NULL)
1658 struct stat perf_stat; 1664 return -ENOMEM;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match);
1665
1666 input = open(input_name, O_RDONLY);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721
1722 size = event->header.size;
1723 1665
1666 if (perf_session__has_traces(session, "record -R"))
1667 err = perf_session__process_events(session, &event_ops);
1724 1668
1725 if (!size || process_event(event, offset, head) < 0) { 1669 perf_session__delete(session);
1726 1670 return err;
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745
1746 return rc;
1747} 1671}
1748 1672
1749static void print_bad_events(void) 1673static void print_bad_events(void)
@@ -1784,9 +1708,9 @@ static void __cmd_lat(void)
1784 read_events(); 1708 read_events();
1785 sort_lat(); 1709 sort_lat();
1786 1710
1787 printf("\n -----------------------------------------------------------------------------------------\n"); 1711 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1712 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n"); 1713 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1790 1714
1791 next = rb_first(&sorted_atom_root); 1715 next = rb_first(&sorted_atom_root);
1792 1716
@@ -1883,6 +1807,8 @@ static const struct option latency_options[] = {
1883 "sort by key(s): runtime, switch, avg, max"), 1807 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose, 1808 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"), 1809 "be more verbose (show symbol address, etc)"),
1810 OPT_INTEGER('C', "CPU", &profile_cpu,
1811 "CPU to profile on"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1812 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"), 1813 "dump raw trace in ASCII"),
1888 OPT_END() 1814 OPT_END()
@@ -1960,14 +1886,18 @@ static int __cmd_record(int argc, const char **argv)
1960 1886
1961int cmd_sched(int argc, const char **argv, const char *prefix __used) 1887int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{ 1888{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage, 1889 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION); 1890 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc) 1891 if (!argc)
1969 usage_with_options(sched_usage, sched_options); 1892 usage_with_options(sched_usage, sched_options);
1970 1893
1894 /*
1895 * Aliased to 'perf trace' for now:
1896 */
1897 if (!strcmp(argv[0], "trace"))
1898 return cmd_trace(argc, argv, prefix);
1899
1900 symbol__init();
1971 if (!strncmp(argv[0], "rec", 3)) { 1901 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv); 1902 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) { 1903 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1991,11 +1921,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1991 usage_with_options(replay_usage, replay_options); 1921 usage_with_options(replay_usage, replay_options);
1992 } 1922 }
1993 __cmd_replay(); 1923 __cmd_replay();
1994 } else if (!strcmp(argv[0], "trace")) {
1995 /*
1996 * Aliased to 'perf trace' for now:
1997 */
1998 return cmd_trace(argc, argv, prefix);
1999 } else { 1924 } else {
2000 usage_with_options(sched_usage, sched_options); 1925 usage_with_options(sched_usage, sched_options);
2001 } 1926 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3db31e7bf173..e8c85d5aec41 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -44,21 +44,24 @@
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/debug.h" 46#include "util/debug.h"
47#include "util/header.h"
47 48
48#include <sys/prctl.h> 49#include <sys/prctl.h>
49#include <math.h> 50#include <math.h>
50 51
51static struct perf_event_attr default_attrs[] = { 52static struct perf_event_attr default_attrs[] = {
52 53
53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, 55 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
55 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, 56 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
56 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 57 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
57 58
58 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 59 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
59 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 60 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
60 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES}, 61 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
61 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, 62 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
63 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
64 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
62 65
63}; 66};
64 67
@@ -77,6 +80,8 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS];
77 80
78static int event_scaled[MAX_COUNTERS]; 81static int event_scaled[MAX_COUNTERS];
79 82
83static volatile int done = 0;
84
80struct stats 85struct stats
81{ 86{
82 double n, mean, M2; 87 double n, mean, M2;
@@ -125,6 +130,7 @@ struct stats event_res_stats[MAX_COUNTERS][3];
125struct stats runtime_nsecs_stats; 130struct stats runtime_nsecs_stats;
126struct stats walltime_nsecs_stats; 131struct stats walltime_nsecs_stats;
127struct stats runtime_cycles_stats; 132struct stats runtime_cycles_stats;
133struct stats runtime_branches_stats;
128 134
129#define MATCH_EVENT(t, c, counter) \ 135#define MATCH_EVENT(t, c, counter) \
130 (attrs[counter].type == PERF_TYPE_##t && \ 136 (attrs[counter].type == PERF_TYPE_##t && \
@@ -235,6 +241,8 @@ static void read_counter(int counter)
235 update_stats(&runtime_nsecs_stats, count[0]); 241 update_stats(&runtime_nsecs_stats, count[0]);
236 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 242 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
237 update_stats(&runtime_cycles_stats, count[0]); 243 update_stats(&runtime_cycles_stats, count[0]);
244 if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
245 update_stats(&runtime_branches_stats, count[0]);
238} 246}
239 247
240static int run_perf_stat(int argc __used, const char **argv) 248static int run_perf_stat(int argc __used, const char **argv)
@@ -242,61 +250,64 @@ static int run_perf_stat(int argc __used, const char **argv)
242 unsigned long long t0, t1; 250 unsigned long long t0, t1;
243 int status = 0; 251 int status = 0;
244 int counter; 252 int counter;
245 int pid; 253 int pid = target_pid;
246 int child_ready_pipe[2], go_pipe[2]; 254 int child_ready_pipe[2], go_pipe[2];
255 const bool forks = (target_pid == -1 && argc > 0);
247 char buf; 256 char buf;
248 257
249 if (!system_wide) 258 if (!system_wide)
250 nr_cpus = 1; 259 nr_cpus = 1;
251 260
252 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { 261 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
253 perror("failed to create pipes"); 262 perror("failed to create pipes");
254 exit(1); 263 exit(1);
255 } 264 }
256 265
257 if ((pid = fork()) < 0) 266 if (forks) {
258 perror("failed to fork"); 267 if ((pid = fork()) < 0)
259 268 perror("failed to fork");
260 if (!pid) { 269
261 close(child_ready_pipe[0]); 270 if (!pid) {
262 close(go_pipe[1]); 271 close(child_ready_pipe[0]);
263 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 272 close(go_pipe[1]);
273 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
274
275 /*
276 * Do a dummy execvp to get the PLT entry resolved,
277 * so we avoid the resolver overhead on the real
278 * execvp call.
279 */
280 execvp("", (char **)argv);
281
282 /*
283 * Tell the parent we're ready to go
284 */
285 close(child_ready_pipe[1]);
286
287 /*
288 * Wait until the parent tells us to go.
289 */
290 if (read(go_pipe[0], &buf, 1) == -1)
291 perror("unable to read pipe");
292
293 execvp(argv[0], (char **)argv);
294
295 perror(argv[0]);
296 exit(-1);
297 }
264 298
265 /* 299 child_pid = pid;
266 * Do a dummy execvp to get the PLT entry resolved,
267 * so we avoid the resolver overhead on the real
268 * execvp call.
269 */
270 execvp("", (char **)argv);
271 300
272 /* 301 /*
273 * Tell the parent we're ready to go 302 * Wait for the child to be ready to exec.
274 */ 303 */
275 close(child_ready_pipe[1]); 304 close(child_ready_pipe[1]);
276 305 close(go_pipe[0]);
277 /* 306 if (read(child_ready_pipe[0], &buf, 1) == -1)
278 * Wait until the parent tells us to go.
279 */
280 if (read(go_pipe[0], &buf, 1) == -1)
281 perror("unable to read pipe"); 307 perror("unable to read pipe");
282 308 close(child_ready_pipe[0]);
283 execvp(argv[0], (char **)argv);
284
285 perror(argv[0]);
286 exit(-1);
287 } 309 }
288 310
289 child_pid = pid;
290
291 /*
292 * Wait for the child to be ready to exec.
293 */
294 close(child_ready_pipe[1]);
295 close(go_pipe[0]);
296 if (read(child_ready_pipe[0], &buf, 1) == -1)
297 perror("unable to read pipe");
298 close(child_ready_pipe[0]);
299
300 for (counter = 0; counter < nr_counters; counter++) 311 for (counter = 0; counter < nr_counters; counter++)
301 create_perf_stat_counter(counter, pid); 312 create_perf_stat_counter(counter, pid);
302 313
@@ -305,8 +316,12 @@ static int run_perf_stat(int argc __used, const char **argv)
305 */ 316 */
306 t0 = rdclock(); 317 t0 = rdclock();
307 318
308 close(go_pipe[1]); 319 if (forks) {
309 wait(&status); 320 close(go_pipe[1]);
321 wait(&status);
322 } else {
323 while(!done);
324 }
310 325
311 t1 = rdclock(); 326 t1 = rdclock();
312 327
@@ -352,7 +367,16 @@ static void abs_printout(int counter, double avg)
352 ratio = avg / total; 367 ratio = avg / total;
353 368
354 fprintf(stderr, " # %10.3f IPC ", ratio); 369 fprintf(stderr, " # %10.3f IPC ", ratio);
355 } else { 370 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) &&
371 runtime_branches_stats.n != 0) {
372 total = avg_stats(&runtime_branches_stats);
373
374 if (total)
375 ratio = avg * 100 / total;
376
377 fprintf(stderr, " # %10.3f %% ", ratio);
378
379 } else if (runtime_nsecs_stats.n != 0) {
356 total = avg_stats(&runtime_nsecs_stats); 380 total = avg_stats(&runtime_nsecs_stats);
357 381
358 if (total) 382 if (total)
@@ -403,10 +427,13 @@ static void print_stat(int argc, const char **argv)
403 fflush(stdout); 427 fflush(stdout);
404 428
405 fprintf(stderr, "\n"); 429 fprintf(stderr, "\n");
406 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 430 fprintf(stderr, " Performance counter stats for ");
407 431 if(target_pid == -1) {
408 for (i = 1; i < argc; i++) 432 fprintf(stderr, "\'%s", argv[0]);
409 fprintf(stderr, " %s", argv[i]); 433 for (i = 1; i < argc; i++)
434 fprintf(stderr, " %s", argv[i]);
435 }else
436 fprintf(stderr, "task pid \'%d", target_pid);
410 437
411 fprintf(stderr, "\'"); 438 fprintf(stderr, "\'");
412 if (run_count > 1) 439 if (run_count > 1)
@@ -431,6 +458,9 @@ static volatile int signr = -1;
431 458
432static void skip_signal(int signo) 459static void skip_signal(int signo)
433{ 460{
461 if(target_pid != -1)
462 done = 1;
463
434 signr = signo; 464 signr = signo;
435} 465}
436 466
@@ -447,7 +477,7 @@ static void sig_atexit(void)
447} 477}
448 478
449static const char * const stat_usage[] = { 479static const char * const stat_usage[] = {
450 "perf stat [<options>] <command>", 480 "perf stat [<options>] [<command>]",
451 NULL 481 NULL
452}; 482};
453 483
@@ -478,7 +508,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
478 508
479 argc = parse_options(argc, argv, options, stat_usage, 509 argc = parse_options(argc, argv, options, stat_usage,
480 PARSE_OPT_STOP_AT_NON_OPTION); 510 PARSE_OPT_STOP_AT_NON_OPTION);
481 if (!argc) 511 if (!argc && target_pid == -1)
482 usage_with_options(stat_usage, options); 512 usage_with_options(stat_usage, options);
483 if (run_count <= 0) 513 if (run_count <= 0)
484 usage_with_options(stat_usage, options); 514 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index e8a510d935e5..0d4d8ff7914b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -29,16 +29,13 @@
29#include "util/header.h" 29#include "util/header.h"
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"
33#include "util/session.h"
32#include "util/svghelper.h" 34#include "util/svghelper.h"
33 35
34static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
35static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
36 38
37
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
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 */
@@ -49,8 +46,6 @@ static u64 first_time, last_time;
49static int power_only; 46static int power_only;
50 47
51 48
52static struct perf_header *header;
53
54struct per_pid; 49struct per_pid;
55struct per_pidcomm; 50struct per_pidcomm;
56 51
@@ -153,6 +148,17 @@ static struct wake_event *wake_events;
153 148
154struct sample_wrapper *all_samples; 149struct sample_wrapper *all_samples;
155 150
151
152struct process_filter;
153struct process_filter {
154 char *name;
155 int pid;
156 struct process_filter *next;
157};
158
159static struct process_filter *process_filter;
160
161
156static struct per_pid *find_create_pid(int pid) 162static struct per_pid *find_create_pid(int pid)
157{ 163{
158 struct per_pid *cursor = all_data; 164 struct per_pid *cursor = all_data;
@@ -272,33 +278,30 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 278static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 279static u64 cpus_pstate_state[MAX_CPUS];
274 280
275static int 281static int process_comm_event(event_t *event, struct perf_session *session __used)
276process_comm_event(event_t *event)
277{ 282{
278 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.tid, event->comm.comm);
279 return 0; 284 return 0;
280} 285}
281static int 286
282process_fork_event(event_t *event) 287static int process_fork_event(event_t *event, struct perf_session *session __used)
283{ 288{
284 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
285 return 0; 290 return 0;
286} 291}
287 292
288static int 293static int process_exit_event(event_t *event, struct perf_session *session __used)
289process_exit_event(event_t *event)
290{ 294{
291 pid_exit(event->fork.pid, event->fork.time); 295 pid_exit(event->fork.pid, event->fork.time);
292 return 0; 296 return 0;
293} 297}
294 298
295struct trace_entry { 299struct trace_entry {
296 u32 size;
297 unsigned short type; 300 unsigned short type;
298 unsigned char flags; 301 unsigned char flags;
299 unsigned char preempt_count; 302 unsigned char preempt_count;
300 int pid; 303 int pid;
301 int tgid; 304 int lock_depth;
302}; 305};
303 306
304struct power_entry { 307struct power_entry {
@@ -472,46 +475,24 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
472} 475}
473 476
474 477
475static int 478static int process_sample_event(event_t *event, struct perf_session *session)
476process_sample_event(event_t *event)
477{ 479{
478 int cursor = 0; 480 struct sample_data data;
479 u64 addr = 0;
480 u64 stamp = 0;
481 u32 cpu = 0;
482 u32 pid = 0;
483 struct trace_entry *te; 481 struct trace_entry *te;
484 482
485 if (sample_type & PERF_SAMPLE_IP) 483 memset(&data, 0, sizeof(data));
486 cursor++;
487
488 if (sample_type & PERF_SAMPLE_TID) {
489 pid = event->sample.array[cursor]>>32;
490 cursor++;
491 }
492 if (sample_type & PERF_SAMPLE_TIME) {
493 stamp = event->sample.array[cursor++];
494 484
495 if (!first_time || first_time > stamp) 485 event__parse_sample(event, session->sample_type, &data);
496 first_time = stamp;
497 if (last_time < stamp)
498 last_time = stamp;
499 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;
500 } 492 }
501 if (sample_type & PERF_SAMPLE_ADDR)
502 addr = event->sample.array[cursor++];
503 if (sample_type & PERF_SAMPLE_ID)
504 cursor++;
505 if (sample_type & PERF_SAMPLE_STREAM_ID)
506 cursor++;
507 if (sample_type & PERF_SAMPLE_CPU)
508 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
509 if (sample_type & PERF_SAMPLE_PERIOD)
510 cursor++;
511
512 te = (void *)&event->sample.array[cursor];
513 493
514 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) {
515 char *event_str; 496 char *event_str;
516 struct power_entry *pe; 497 struct power_entry *pe;
517 498
@@ -523,19 +504,19 @@ process_sample_event(event_t *event)
523 return 0; 504 return 0;
524 505
525 if (strcmp(event_str, "power:power_start") == 0) 506 if (strcmp(event_str, "power:power_start") == 0)
526 c_state_start(cpu, stamp, pe->value); 507 c_state_start(data.cpu, data.time, pe->value);
527 508
528 if (strcmp(event_str, "power:power_end") == 0) 509 if (strcmp(event_str, "power:power_end") == 0)
529 c_state_end(cpu, stamp); 510 c_state_end(data.cpu, data.time);
530 511
531 if (strcmp(event_str, "power:power_frequency") == 0) 512 if (strcmp(event_str, "power:power_frequency") == 0)
532 p_state_change(cpu, stamp, pe->value); 513 p_state_change(data.cpu, data.time, pe->value);
533 514
534 if (strcmp(event_str, "sched:sched_wakeup") == 0) 515 if (strcmp(event_str, "sched:sched_wakeup") == 0)
535 sched_wakeup(cpu, stamp, pid, te); 516 sched_wakeup(data.cpu, data.time, data.pid, te);
536 517
537 if (strcmp(event_str, "sched:sched_switch") == 0) 518 if (strcmp(event_str, "sched:sched_switch") == 0)
538 sched_switch(cpu, stamp, te); 519 sched_switch(data.cpu, data.time, te);
539 } 520 }
540 return 0; 521 return 0;
541} 522}
@@ -588,16 +569,16 @@ static void end_sample_processing(void)
588 } 569 }
589} 570}
590 571
591static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
592{ 573{
593 int cursor; 574 int cursor;
594 575
595 cursor = 0; 576 cursor = 0;
596 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
597 cursor++; 578 cursor++;
598 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
599 cursor++; 580 cursor++;
600 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
601 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
602 return 0; 583 return 0;
603} 584}
@@ -607,8 +588,7 @@ static u64 sample_time(event_t *event)
607 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
608 * The order will get flipped later. 589 * The order will get flipped later.
609 */ 590 */
610static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
611queue_sample_event(event_t *event)
612{ 592{
613 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
614 int size; 594 int size;
@@ -622,7 +602,7 @@ queue_sample_event(event_t *event)
622 memset(copy, 0, size); 602 memset(copy, 0, size);
623 603
624 copy->next = NULL; 604 copy->next = NULL;
625 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
626 606
627 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
628 608
@@ -763,11 +743,11 @@ static void draw_wakeups(void)
763 c = p->all; 743 c = p->all;
764 while (c) { 744 while (c) {
765 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { 745 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
766 if (p->pid == we->waker) { 746 if (p->pid == we->waker && !from) {
767 from = c->Y; 747 from = c->Y;
768 task_from = strdup(c->comm); 748 task_from = strdup(c->comm);
769 } 749 }
770 if (p->pid == we->wakee) { 750 if (p->pid == we->wakee && !to) {
771 to = c->Y; 751 to = c->Y;
772 task_to = strdup(c->comm); 752 task_to = strdup(c->comm);
773 } 753 }
@@ -882,12 +862,89 @@ static void draw_process_bars(void)
882 } 862 }
883} 863}
884 864
865static void add_process_filter(const char *string)
866{
867 struct process_filter *filt;
868 int pid;
869
870 pid = strtoull(string, NULL, 10);
871 filt = malloc(sizeof(struct process_filter));
872 if (!filt)
873 return;
874
875 filt->name = strdup(string);
876 filt->pid = pid;
877 filt->next = process_filter;
878
879 process_filter = filt;
880}
881
882static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
883{
884 struct process_filter *filt;
885 if (!process_filter)
886 return 1;
887
888 filt = process_filter;
889 while (filt) {
890 if (filt->pid && p->pid == filt->pid)
891 return 1;
892 if (strcmp(filt->name, c->comm) == 0)
893 return 1;
894 filt = filt->next;
895 }
896 return 0;
897}
898
899static int determine_display_tasks_filtered(void)
900{
901 struct per_pid *p;
902 struct per_pidcomm *c;
903 int count = 0;
904
905 p = all_data;
906 while (p) {
907 p->display = 0;
908 if (p->start_time == 1)
909 p->start_time = first_time;
910
911 /* no exit marker, task kept running to the end */
912 if (p->end_time == 0)
913 p->end_time = last_time;
914
915 c = p->all;
916
917 while (c) {
918 c->display = 0;
919
920 if (c->start_time == 1)
921 c->start_time = first_time;
922
923 if (passes_filter(p, c)) {
924 c->display = 1;
925 p->display = 1;
926 count++;
927 }
928
929 if (c->end_time == 0)
930 c->end_time = last_time;
931
932 c = c->next;
933 }
934 p = p->next;
935 }
936 return count;
937}
938
885static int determine_display_tasks(u64 threshold) 939static int determine_display_tasks(u64 threshold)
886{ 940{
887 struct per_pid *p; 941 struct per_pid *p;
888 struct per_pidcomm *c; 942 struct per_pidcomm *c;
889 int count = 0; 943 int count = 0;
890 944
945 if (process_filter)
946 return determine_display_tasks_filtered();
947
891 p = all_data; 948 p = all_data;
892 while (p) { 949 while (p) {
893 p->display = 0; 950 p->display = 0;
@@ -957,37 +1014,7 @@ static void write_svg_file(const char *filename)
957 svg_close(); 1014 svg_close();
958} 1015}
959 1016
960static int 1017static void process_samples(struct perf_session *session)
961process_event(event_t *event)
962{
963
964 switch (event->header.type) {
965
966 case PERF_RECORD_COMM:
967 return process_comm_event(event);
968 case PERF_RECORD_FORK:
969 return process_fork_event(event);
970 case PERF_RECORD_EXIT:
971 return process_exit_event(event);
972 case PERF_RECORD_SAMPLE:
973 return queue_sample_event(event);
974
975 /*
976 * We dont process them right now but they are fine:
977 */
978 case PERF_RECORD_MMAP:
979 case PERF_RECORD_THROTTLE:
980 case PERF_RECORD_UNTHROTTLE:
981 return 0;
982
983 default:
984 return -1;
985 }
986
987 return 0;
988}
989
990static void process_samples(void)
991{ 1018{
992 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
993 event_t *event; 1020 event_t *event;
@@ -998,113 +1025,33 @@ static void process_samples(void)
998 while (cursor) { 1025 while (cursor) {
999 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1000 cursor = cursor->next; 1027 cursor = cursor->next;
1001 process_sample_event(event); 1028 process_sample_event(event, session);
1002 } 1029 }
1003} 1030}
1004 1031
1032static struct perf_event_ops event_ops = {
1033 .comm = process_comm_event,
1034 .fork = process_fork_event,
1035 .exit = process_exit_event,
1036 .sample = queue_sample_event,
1037};
1005 1038
1006static int __cmd_timechart(void) 1039static int __cmd_timechart(void)
1007{ 1040{
1008 int ret, rc = EXIT_FAILURE; 1041 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1009 unsigned long offset = 0; 1042 int ret = -EINVAL;
1010 unsigned long head, shift;
1011 struct stat statbuf;
1012 event_t *event;
1013 uint32_t size;
1014 char *buf;
1015 int input;
1016
1017 input = open(input_name, O_RDONLY);
1018 if (input < 0) {
1019 fprintf(stderr, " failed to open file: %s", input_name);
1020 if (!strcmp(input_name, "perf.data"))
1021 fprintf(stderr, " (try 'perf record' first)");
1022 fprintf(stderr, "\n");
1023 exit(-1);
1024 }
1025
1026 ret = fstat(input, &statbuf);
1027 if (ret < 0) {
1028 perror("failed to stat file");
1029 exit(-1);
1030 }
1031
1032 if (!statbuf.st_size) {
1033 fprintf(stderr, "zero-sized file, nothing to do!\n");
1034 exit(0);
1035 }
1036 1043
1037 header = perf_header__read(input); 1044 if (session == NULL)
1038 head = header->data_offset; 1045 return -ENOMEM;
1039 1046
1040 sample_type = perf_header__sample_type(header); 1047 if (!perf_session__has_traces(session, "timechart record"))
1048 goto out_delete;
1041 1049
1042 shift = page_size * (head / page_size); 1050 ret = perf_session__process_events(session, &event_ops);
1043 offset += shift; 1051 if (ret)
1044 head -= shift; 1052 goto out_delete;
1045 1053
1046remap: 1054 process_samples(session);
1047 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1048 MAP_SHARED, input, offset);
1049 if (buf == MAP_FAILED) {
1050 perror("failed to mmap file");
1051 exit(-1);
1052 }
1053
1054more:
1055 event = (event_t *)(buf + head);
1056
1057 size = event->header.size;
1058 if (!size)
1059 size = 8;
1060
1061 if (head + event->header.size >= page_size * mmap_window) {
1062 int ret2;
1063
1064 shift = page_size * (head / page_size);
1065
1066 ret2 = munmap(buf, page_size * mmap_window);
1067 assert(ret2 == 0);
1068
1069 offset += shift;
1070 head -= shift;
1071 goto remap;
1072 }
1073
1074 size = event->header.size;
1075
1076 if (!size || process_event(event) < 0) {
1077
1078 printf("%p [%p]: skipping unknown header type: %d\n",
1079 (void *)(offset + head),
1080 (void *)(long)(event->header.size),
1081 event->header.type);
1082
1083 /*
1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087
1088 if (unlikely(head & 7))
1089 head &= ~7ULL;
1090
1091 size = 8;
1092 }
1093
1094 head += size;
1095
1096 if (offset + head >= header->data_offset + header->data_size)
1097 goto done;
1098
1099 if (offset + head < (unsigned long)statbuf.st_size)
1100 goto more;
1101
1102done:
1103 rc = EXIT_SUCCESS;
1104 close(input);
1105
1106
1107 process_samples();
1108 1055
1109 end_sample_processing(); 1056 end_sample_processing();
1110 1057
@@ -1112,9 +1059,11 @@ done:
1112 1059
1113 write_svg_file(output_name); 1060 write_svg_file(output_name);
1114 1061
1115 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1062 pr_info("Written %2.1f seconds of trace to %s.\n",
1116 1063 (last_time - first_time) / 1000000000.0, output_name);
1117 return rc; 1064out_delete:
1065 perf_session__delete(session);
1066 return ret;
1118} 1067}
1119 1068
1120static const char * const timechart_usage[] = { 1069static const char * const timechart_usage[] = {
@@ -1153,6 +1102,14 @@ static int __cmd_record(int argc, const char **argv)
1153 return cmd_record(i, rec_argv, NULL); 1102 return cmd_record(i, rec_argv, NULL);
1154} 1103}
1155 1104
1105static int
1106parse_process(const struct option *opt __used, const char *arg, int __used unset)
1107{
1108 if (arg)
1109 add_process_filter(arg);
1110 return 0;
1111}
1112
1156static const struct option options[] = { 1113static const struct option options[] = {
1157 OPT_STRING('i', "input", &input_name, "file", 1114 OPT_STRING('i', "input", &input_name, "file",
1158 "input file name"), 1115 "input file name"),
@@ -1160,21 +1117,22 @@ static const struct option options[] = {
1160 "output file name"), 1117 "output file name"),
1161 OPT_INTEGER('w', "width", &svg_page_width, 1118 OPT_INTEGER('w', "width", &svg_page_width,
1162 "page width"), 1119 "page width"),
1163 OPT_BOOLEAN('p', "power-only", &power_only, 1120 OPT_BOOLEAN('P', "power-only", &power_only,
1164 "output power data only"), 1121 "output power data only"),
1122 OPT_CALLBACK('p', "process", NULL, "process",
1123 "process selector. Pass a pid or process name.",
1124 parse_process),
1165 OPT_END() 1125 OPT_END()
1166}; 1126};
1167 1127
1168 1128
1169int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1129int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1170{ 1130{
1171 symbol__init();
1172
1173 page_size = getpagesize();
1174
1175 argc = parse_options(argc, argv, options, timechart_usage, 1131 argc = parse_options(argc, argv, options, timechart_usage,
1176 PARSE_OPT_STOP_AT_NON_OPTION); 1132 PARSE_OPT_STOP_AT_NON_OPTION);
1177 1133
1134 symbol__init();
1135
1178 if (argc && !strncmp(argv[0], "rec", 3)) 1136 if (argc && !strncmp(argv[0], "rec", 3))
1179 return __cmd_record(argc, argv); 1137 return __cmd_record(argc, argv);
1180 else if (argc) 1138 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e23bc74e734f..31f2e597800c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,8 +20,10 @@
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"
26#include "util/thread.h"
25#include "util/util.h" 27#include "util/util.h"
26#include <linux/rbtree.h> 28#include <linux/rbtree.h>
27#include "util/parse-options.h" 29#include "util/parse-options.h"
@@ -54,26 +56,30 @@
54 56
55static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 57static int fd[MAX_NR_CPUS][MAX_COUNTERS];
56 58
57static int system_wide = 0; 59static int system_wide = 0;
58 60
59static int default_interval = 100000; 61static int default_interval = 0;
60 62
61static int count_filter = 5; 63static int count_filter = 5;
62static int print_entries = 15; 64static int print_entries;
63 65
64static int target_pid = -1; 66static int target_pid = -1;
65static int inherit = 0; 67static int inherit = 0;
66static int profile_cpu = -1; 68static int profile_cpu = -1;
67static int nr_cpus = 0; 69static int nr_cpus = 0;
68static unsigned int realtime_prio = 0; 70static unsigned int realtime_prio = 0;
69static int group = 0; 71static int group = 0;
70static unsigned int page_size; 72static unsigned int page_size;
71static unsigned int mmap_pages = 16; 73static unsigned int mmap_pages = 16;
72static int freq = 0; 74static int freq = 1000; /* 1 KHz */
73 75
74static int delay_secs = 2; 76static int delay_secs = 2;
75static int zero; 77static int zero = 0;
76static int dump_symtab; 78static int dump_symtab = 0;
79
80static bool hide_kernel_symbols = false;
81static bool hide_user_symbols = false;
82static struct winsize winsize;
77 83
78/* 84/*
79 * Source 85 * Source
@@ -86,87 +92,130 @@ struct source_line {
86 struct source_line *next; 92 struct source_line *next;
87}; 93};
88 94
89static char *sym_filter = NULL; 95static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL; 96struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5; 97struct sym_entry *sym_filter_entry_sched = NULL;
92static int sym_counter = 0; 98static int sym_pcnt_filter = 5;
93static int display_weighted = -1; 99static int sym_counter = 0;
100static int display_weighted = -1;
94 101
95/* 102/*
96 * Symbols 103 * Symbols
97 */ 104 */
98 105
99static u64 min_ip; 106struct sym_entry_source {
100static u64 max_ip = -1ll; 107 struct source_line *source;
108 struct source_line *lines;
109 struct source_line **lines_tail;
110 pthread_mutex_t lock;
111};
101 112
102struct sym_entry { 113struct sym_entry {
103 struct rb_node rb_node; 114 struct rb_node rb_node;
104 struct list_head node; 115 struct list_head node;
105 unsigned long count[MAX_COUNTERS];
106 unsigned long snap_count; 116 unsigned long snap_count;
107 double weight; 117 double weight;
108 int skip; 118 int skip;
109 struct source_line *source; 119 u16 name_len;
110 struct source_line *lines; 120 u8 origin;
111 struct source_line **lines_tail; 121 struct map *map;
112 pthread_mutex_t source_lock; 122 struct sym_entry_source *src;
123 unsigned long count[0];
113}; 124};
114 125
115/* 126/*
116 * Source functions 127 * Source functions
117 */ 128 */
118 129
130static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
131{
132 return ((void *)self) + symbol_conf.priv_size;
133}
134
135static void get_term_dimensions(struct winsize *ws)
136{
137 char *s = getenv("LINES");
138
139 if (s != NULL) {
140 ws->ws_row = atoi(s);
141 s = getenv("COLUMNS");
142 if (s != NULL) {
143 ws->ws_col = atoi(s);
144 if (ws->ws_row && ws->ws_col)
145 return;
146 }
147 }
148#ifdef TIOCGWINSZ
149 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
150 ws->ws_row && ws->ws_col)
151 return;
152#endif
153 ws->ws_row = 25;
154 ws->ws_col = 80;
155}
156
157static void update_print_entries(struct winsize *ws)
158{
159 print_entries = ws->ws_row;
160
161 if (print_entries > 9)
162 print_entries -= 9;
163}
164
165static void sig_winch_handler(int sig __used)
166{
167 get_term_dimensions(&winsize);
168 update_print_entries(&winsize);
169}
170
119static void parse_source(struct sym_entry *syme) 171static void parse_source(struct sym_entry *syme)
120{ 172{
121 struct symbol *sym; 173 struct symbol *sym;
122 struct module *module; 174 struct sym_entry_source *source;
123 struct section *section = NULL; 175 struct map *map;
124 FILE *file; 176 FILE *file;
125 char command[PATH_MAX*2]; 177 char command[PATH_MAX*2];
126 const char *path = vmlinux_name; 178 const char *path;
127 u64 start, end, len; 179 u64 len;
128 180
129 if (!syme) 181 if (!syme)
130 return; 182 return;
131 183
132 if (syme->lines) { 184 if (syme->src == NULL) {
133 pthread_mutex_lock(&syme->source_lock); 185 syme->src = zalloc(sizeof(*source));
134 goto out_assign; 186 if (syme->src == NULL)
187 return;
188 pthread_mutex_init(&syme->src->lock, NULL);
135 } 189 }
136 190
137 sym = (struct symbol *)(syme + 1); 191 source = syme->src;
138 module = sym->module;
139
140 if (module)
141 path = module->path;
142 if (!path)
143 return;
144 192
145 start = sym->obj_start; 193 if (source->lines) {
146 if (!start) 194 pthread_mutex_lock(&source->lock);
147 start = sym->start; 195 goto out_assign;
148
149 if (module) {
150 section = module->sections->find_section(module->sections, ".text");
151 if (section)
152 start -= section->vma;
153 } 196 }
154 197
155 end = start + sym->end - sym->start + 1; 198 sym = sym_entry__symbol(syme);
199 map = syme->map;
200 path = map->dso->long_name;
201
156 len = sym->end - sym->start; 202 len = sym->end - sym->start;
157 203
158 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); 204 sprintf(command,
205 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
206 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
207 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
159 208
160 file = popen(command, "r"); 209 file = popen(command, "r");
161 if (!file) 210 if (!file)
162 return; 211 return;
163 212
164 pthread_mutex_lock(&syme->source_lock); 213 pthread_mutex_lock(&source->lock);
165 syme->lines_tail = &syme->lines; 214 source->lines_tail = &source->lines;
166 while (!feof(file)) { 215 while (!feof(file)) {
167 struct source_line *src; 216 struct source_line *src;
168 size_t dummy = 0; 217 size_t dummy = 0;
169 char *c; 218 char *c, *sep;
170 219
171 src = malloc(sizeof(struct source_line)); 220 src = malloc(sizeof(struct source_line));
172 assert(src != NULL); 221 assert(src != NULL);
@@ -182,24 +231,19 @@ static void parse_source(struct sym_entry *syme)
182 *c = 0; 231 *c = 0;
183 232
184 src->next = NULL; 233 src->next = NULL;
185 *syme->lines_tail = src; 234 *source->lines_tail = src;
186 syme->lines_tail = &src->next; 235 source->lines_tail = &src->next;
187 236
188 if (strlen(src->line)>8 && src->line[8] == ':') { 237 src->eip = strtoull(src->line, &sep, 16);
189 src->eip = strtoull(src->line, NULL, 16); 238 if (*sep == ':')
190 if (section) 239 src->eip = map__objdump_2ip(map, src->eip);
191 src->eip += section->vma; 240 else /* this line has no ip info (e.g. source line) */
192 } 241 src->eip = 0;
193 if (strlen(src->line)>8 && src->line[16] == ':') {
194 src->eip = strtoull(src->line, NULL, 16);
195 if (section)
196 src->eip += section->vma;
197 }
198 } 242 }
199 pclose(file); 243 pclose(file);
200out_assign: 244out_assign:
201 sym_filter_entry = syme; 245 sym_filter_entry = syme;
202 pthread_mutex_unlock(&syme->source_lock); 246 pthread_mutex_unlock(&source->lock);
203} 247}
204 248
205static void __zero_source_counters(struct sym_entry *syme) 249static void __zero_source_counters(struct sym_entry *syme)
@@ -207,7 +251,7 @@ static void __zero_source_counters(struct sym_entry *syme)
207 int i; 251 int i;
208 struct source_line *line; 252 struct source_line *line;
209 253
210 line = syme->lines; 254 line = syme->src->lines;
211 while (line) { 255 while (line) {
212 for (i = 0; i < nr_counters; i++) 256 for (i = 0; i < nr_counters; i++)
213 line->count[i] = 0; 257 line->count[i] = 0;
@@ -222,13 +266,16 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
222 if (syme != sym_filter_entry) 266 if (syme != sym_filter_entry)
223 return; 267 return;
224 268
225 if (pthread_mutex_trylock(&syme->source_lock)) 269 if (pthread_mutex_trylock(&syme->src->lock))
226 return; 270 return;
227 271
228 if (!syme->source) 272 if (syme->src == NULL || syme->src->source == NULL)
229 goto out_unlock; 273 goto out_unlock;
230 274
231 for (line = syme->lines; line; line = line->next) { 275 for (line = syme->src->lines; line; line = line->next) {
276 /* skip lines without IP info */
277 if (line->eip == 0)
278 continue;
232 if (line->eip == ip) { 279 if (line->eip == ip) {
233 line->count[counter]++; 280 line->count[counter]++;
234 break; 281 break;
@@ -237,32 +284,28 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
237 break; 284 break;
238 } 285 }
239out_unlock: 286out_unlock:
240 pthread_mutex_unlock(&syme->source_lock); 287 pthread_mutex_unlock(&syme->src->lock);
241} 288}
242 289
290#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
291
243static void lookup_sym_source(struct sym_entry *syme) 292static void lookup_sym_source(struct sym_entry *syme)
244{ 293{
245 struct symbol *symbol = (struct symbol *)(syme + 1); 294 struct symbol *symbol = sym_entry__symbol(syme);
246 struct source_line *line; 295 struct source_line *line;
247 char pattern[PATH_MAX]; 296 char pattern[PATTERN_LEN + 1];
248 char *idx;
249 297
250 sprintf(pattern, "<%s>:", symbol->name); 298 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
299 map__rip_2objdump(syme->map, symbol->start));
251 300
252 if (symbol->module) { 301 pthread_mutex_lock(&syme->src->lock);
253 idx = strstr(pattern, "\t"); 302 for (line = syme->src->lines; line; line = line->next) {
254 if (idx) 303 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
255 *idx = 0; 304 syme->src->source = line;
256 }
257
258 pthread_mutex_lock(&syme->source_lock);
259 for (line = syme->lines; line; line = line->next) {
260 if (strstr(line->line, pattern)) {
261 syme->source = line;
262 break; 305 break;
263 } 306 }
264 } 307 }
265 pthread_mutex_unlock(&syme->source_lock); 308 pthread_mutex_unlock(&syme->src->lock);
266} 309}
267 310
268static void show_lines(struct source_line *queue, int count, int total) 311static void show_lines(struct source_line *queue, int count, int total)
@@ -292,24 +335,24 @@ static void show_details(struct sym_entry *syme)
292 if (!syme) 335 if (!syme)
293 return; 336 return;
294 337
295 if (!syme->source) 338 if (!syme->src->source)
296 lookup_sym_source(syme); 339 lookup_sym_source(syme);
297 340
298 if (!syme->source) 341 if (!syme->src->source)
299 return; 342 return;
300 343
301 symbol = (struct symbol *)(syme + 1); 344 symbol = sym_entry__symbol(syme);
302 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 345 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
303 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 346 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
304 347
305 pthread_mutex_lock(&syme->source_lock); 348 pthread_mutex_lock(&syme->src->lock);
306 line = syme->source; 349 line = syme->src->source;
307 while (line) { 350 while (line) {
308 total += line->count[sym_counter]; 351 total += line->count[sym_counter];
309 line = line->next; 352 line = line->next;
310 } 353 }
311 354
312 line = syme->source; 355 line = syme->src->source;
313 while (line) { 356 while (line) {
314 float pcnt = 0.0; 357 float pcnt = 0.0;
315 358
@@ -334,13 +377,13 @@ static void show_details(struct sym_entry *syme)
334 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; 377 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
335 line = line->next; 378 line = line->next;
336 } 379 }
337 pthread_mutex_unlock(&syme->source_lock); 380 pthread_mutex_unlock(&syme->src->lock);
338 if (more) 381 if (more)
339 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 382 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
340} 383}
341 384
342/* 385/*
343 * Symbols will be added here in record_ip and will get out 386 * Symbols will be added here in event__process_sample and will get out
344 * after decayed. 387 * after decayed.
345 */ 388 */
346static LIST_HEAD(active_symbols); 389static LIST_HEAD(active_symbols);
@@ -411,6 +454,8 @@ static void print_sym_table(void)
411 struct sym_entry *syme, *n; 454 struct sym_entry *syme, *n;
412 struct rb_root tmp = RB_ROOT; 455 struct rb_root tmp = RB_ROOT;
413 struct rb_node *nd; 456 struct rb_node *nd;
457 int sym_width = 0, dso_width = 0, max_dso_width;
458 const int win_width = winsize.ws_col - 1;
414 459
415 samples = userspace_samples = 0; 460 samples = userspace_samples = 0;
416 461
@@ -422,6 +467,14 @@ static void print_sym_table(void)
422 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 467 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
423 syme->snap_count = syme->count[snap]; 468 syme->snap_count = syme->count[snap];
424 if (syme->snap_count != 0) { 469 if (syme->snap_count != 0) {
470
471 if ((hide_user_symbols &&
472 syme->origin == PERF_RECORD_MISC_USER) ||
473 (hide_kernel_symbols &&
474 syme->origin == PERF_RECORD_MISC_KERNEL)) {
475 list_remove_active_sym(syme);
476 continue;
477 }
425 syme->weight = sym_weight(syme); 478 syme->weight = sym_weight(syme);
426 rb_insert_active_sym(&tmp, syme); 479 rb_insert_active_sym(&tmp, syme);
427 sum_ksamples += syme->snap_count; 480 sum_ksamples += syme->snap_count;
@@ -434,8 +487,7 @@ static void print_sym_table(void)
434 487
435 puts(CONSOLE_CLEAR); 488 puts(CONSOLE_CLEAR);
436 489
437 printf( 490 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
438"------------------------------------------------------------------------------\n");
439 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 491 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
440 samples_per_sec, 492 samples_per_sec,
441 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 493 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
@@ -473,33 +525,57 @@ static void print_sym_table(void)
473 printf(", %d CPUs)\n", nr_cpus); 525 printf(", %d CPUs)\n", nr_cpus);
474 } 526 }
475 527
476 printf("------------------------------------------------------------------------------\n\n"); 528 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
477 529
478 if (sym_filter_entry) { 530 if (sym_filter_entry) {
479 show_details(sym_filter_entry); 531 show_details(sym_filter_entry);
480 return; 532 return;
481 } 533 }
482 534
535 /*
536 * Find the longest symbol name that will be displayed
537 */
538 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
539 syme = rb_entry(nd, struct sym_entry, rb_node);
540 if (++printed > print_entries ||
541 (int)syme->snap_count < count_filter)
542 continue;
543
544 if (syme->map->dso->long_name_len > dso_width)
545 dso_width = syme->map->dso->long_name_len;
546
547 if (syme->name_len > sym_width)
548 sym_width = syme->name_len;
549 }
550
551 printed = 0;
552
553 max_dso_width = winsize.ws_col - sym_width - 29;
554 if (dso_width > max_dso_width)
555 dso_width = max_dso_width;
556 putchar('\n');
483 if (nr_counters == 1) 557 if (nr_counters == 1)
484 printf(" samples pcnt"); 558 printf(" samples pcnt");
485 else 559 else
486 printf(" weight samples pcnt"); 560 printf(" weight samples pcnt");
487 561
488 if (verbose) 562 if (verbose)
489 printf(" RIP "); 563 printf(" RIP ");
490 printf(" kernel function\n"); 564 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
491 printf(" %s _______ _____", 565 printf(" %s _______ _____",
492 nr_counters == 1 ? " " : "______"); 566 nr_counters == 1 ? " " : "______");
493 if (verbose) 567 if (verbose)
494 printf(" ________________"); 568 printf(" ________________");
495 printf(" _______________\n\n"); 569 printf(" %-*.*s", sym_width, sym_width, graph_line);
570 printf(" %-*.*s", dso_width, dso_width, graph_line);
571 puts("\n");
496 572
497 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 573 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
498 struct symbol *sym; 574 struct symbol *sym;
499 double pcnt; 575 double pcnt;
500 576
501 syme = rb_entry(nd, struct sym_entry, rb_node); 577 syme = rb_entry(nd, struct sym_entry, rb_node);
502 sym = (struct symbol *)(syme + 1); 578 sym = sym_entry__symbol(syme);
503 579
504 if (++printed > print_entries || (int)syme->snap_count < count_filter) 580 if (++printed > print_entries || (int)syme->snap_count < count_filter)
505 continue; 581 continue;
@@ -508,17 +584,18 @@ static void print_sym_table(void)
508 sum_ksamples)); 584 sum_ksamples));
509 585
510 if (nr_counters == 1 || !display_weighted) 586 if (nr_counters == 1 || !display_weighted)
511 printf("%20.2f - ", syme->weight); 587 printf("%20.2f ", syme->weight);
512 else 588 else
513 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 589 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
514 590
515 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 591 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
516 if (verbose) 592 if (verbose)
517 printf(" - %016llx", sym->start); 593 printf(" %016llx", sym->start);
518 printf(" : %s", sym->name); 594 printf(" %-*.*s", sym_width, sym_width, sym->name);
519 if (sym->module) 595 printf(" %-*.*s\n", dso_width, dso_width,
520 printf("\t[%s]", sym->module->name); 596 dso_width >= syme->map->dso->long_name_len ?
521 printf("\n"); 597 syme->map->dso->long_name :
598 syme->map->dso->short_name);
522 } 599 }
523} 600}
524 601
@@ -565,10 +642,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
565 642
566 /* zero counters of active symbol */ 643 /* zero counters of active symbol */
567 if (syme) { 644 if (syme) {
568 pthread_mutex_lock(&syme->source_lock); 645 pthread_mutex_lock(&syme->src->lock);
569 __zero_source_counters(syme); 646 __zero_source_counters(syme);
570 *target = NULL; 647 *target = NULL;
571 pthread_mutex_unlock(&syme->source_lock); 648 pthread_mutex_unlock(&syme->src->lock);
572 } 649 }
573 650
574 fprintf(stdout, "\n%s: ", msg); 651 fprintf(stdout, "\n%s: ", msg);
@@ -584,7 +661,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
584 pthread_mutex_unlock(&active_symbols_lock); 661 pthread_mutex_unlock(&active_symbols_lock);
585 662
586 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 663 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
587 struct symbol *sym = (struct symbol *)(syme + 1); 664 struct symbol *sym = sym_entry__symbol(syme);
588 665
589 if (!strcmp(buf, sym->name)) { 666 if (!strcmp(buf, sym->name)) {
590 found = syme; 667 found = syme;
@@ -593,7 +670,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
593 } 670 }
594 671
595 if (!found) { 672 if (!found) {
596 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 673 fprintf(stderr, "Sorry, %s is not active.\n", buf);
597 sleep(1); 674 sleep(1);
598 return; 675 return;
599 } else 676 } else
@@ -608,7 +685,7 @@ static void print_mapped_keys(void)
608 char *name = NULL; 685 char *name = NULL;
609 686
610 if (sym_filter_entry) { 687 if (sym_filter_entry) {
611 struct symbol *sym = (struct symbol *)(sym_filter_entry+1); 688 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
612 name = sym->name; 689 name = sym->name;
613 } 690 }
614 691
@@ -621,15 +698,19 @@ static void print_mapped_keys(void)
621 698
622 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 699 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
623 700
624 if (vmlinux_name) { 701 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
625 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 702 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
626 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 703 fprintf(stdout, "\t[S] stop annotation.\n");
627 fprintf(stdout, "\t[S] stop annotation.\n");
628 }
629 704
630 if (nr_counters > 1) 705 if (nr_counters > 1)
631 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 706 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
632 707
708 fprintf(stdout,
709 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
710 hide_kernel_symbols ? "yes" : "no");
711 fprintf(stdout,
712 "\t[U] hide user symbols. \t(%s)\n",
713 hide_user_symbols ? "yes" : "no");
633 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 714 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
634 fprintf(stdout, "\t[qQ] quit.\n"); 715 fprintf(stdout, "\t[qQ] quit.\n");
635} 716}
@@ -643,14 +724,15 @@ static int key_mapped(int c)
643 case 'z': 724 case 'z':
644 case 'q': 725 case 'q':
645 case 'Q': 726 case 'Q':
727 case 'K':
728 case 'U':
729 case 'F':
730 case 's':
731 case 'S':
646 return 1; 732 return 1;
647 case 'E': 733 case 'E':
648 case 'w': 734 case 'w':
649 return nr_counters > 1 ? 1 : 0; 735 return nr_counters > 1 ? 1 : 0;
650 case 'F':
651 case 's':
652 case 'S':
653 return vmlinux_name ? 1 : 0;
654 default: 736 default:
655 break; 737 break;
656 } 738 }
@@ -691,6 +773,11 @@ static void handle_keypress(int c)
691 break; 773 break;
692 case 'e': 774 case 'e':
693 prompt_integer(&print_entries, "Enter display entries (lines)"); 775 prompt_integer(&print_entries, "Enter display entries (lines)");
776 if (print_entries == 0) {
777 sig_winch_handler(SIGWINCH);
778 signal(SIGWINCH, sig_winch_handler);
779 } else
780 signal(SIGWINCH, SIG_DFL);
694 break; 781 break;
695 case 'E': 782 case 'E':
696 if (nr_counters > 1) { 783 if (nr_counters > 1) {
@@ -715,9 +802,14 @@ static void handle_keypress(int c)
715 case 'F': 802 case 'F':
716 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 803 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
717 break; 804 break;
805 case 'K':
806 hide_kernel_symbols = !hide_kernel_symbols;
807 break;
718 case 'q': 808 case 'q':
719 case 'Q': 809 case 'Q':
720 printf("exiting.\n"); 810 printf("exiting.\n");
811 if (dump_symtab)
812 dsos__fprintf(stderr);
721 exit(0); 813 exit(0);
722 case 's': 814 case 's':
723 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 815 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -728,12 +820,15 @@ static void handle_keypress(int c)
728 else { 820 else {
729 struct sym_entry *syme = sym_filter_entry; 821 struct sym_entry *syme = sym_filter_entry;
730 822
731 pthread_mutex_lock(&syme->source_lock); 823 pthread_mutex_lock(&syme->src->lock);
732 sym_filter_entry = NULL; 824 sym_filter_entry = NULL;
733 __zero_source_counters(syme); 825 __zero_source_counters(syme);
734 pthread_mutex_unlock(&syme->source_lock); 826 pthread_mutex_unlock(&syme->src->lock);
735 } 827 }
736 break; 828 break;
829 case 'U':
830 hide_user_symbols = !hide_user_symbols;
831 break;
737 case 'w': 832 case 'w':
738 display_weighted = ~display_weighted; 833 display_weighted = ~display_weighted;
739 break; 834 break;
@@ -790,7 +885,7 @@ static const char *skip_symbols[] = {
790 NULL 885 NULL
791}; 886};
792 887
793static int symbol_filter(struct dso *self, struct symbol *sym) 888static int symbol_filter(struct map *map, struct symbol *sym)
794{ 889{
795 struct sym_entry *syme; 890 struct sym_entry *syme;
796 const char *name = sym->name; 891 const char *name = sym->name;
@@ -812,10 +907,15 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
812 strstr(name, "_text_end")) 907 strstr(name, "_text_end"))
813 return 1; 908 return 1;
814 909
815 syme = dso__sym_priv(self, sym); 910 syme = symbol__priv(sym);
816 pthread_mutex_init(&syme->source_lock, NULL); 911 syme->map = map;
817 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 912 syme->src = NULL;
818 sym_filter_entry = syme; 913
914 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
915 /* schedule initial sym_filter_entry setup */
916 sym_filter_entry_sched = syme;
917 sym_filter = NULL;
918 }
819 919
820 for (i = 0; skip_symbols[i]; i++) { 920 for (i = 0; skip_symbols[i]; i++) {
821 if (!strcmp(skip_symbols[i], name)) { 921 if (!strcmp(skip_symbols[i], name)) {
@@ -824,75 +924,99 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
824 } 924 }
825 } 925 }
826 926
927 if (!syme->skip)
928 syme->name_len = strlen(sym->name);
929
827 return 0; 930 return 0;
828} 931}
829 932
830static int parse_symbols(void) 933static void event__process_sample(const event_t *self,
934 struct perf_session *session, int counter)
831{ 935{
832 struct rb_node *node; 936 u64 ip = self->ip.ip;
833 struct symbol *sym; 937 struct sym_entry *syme;
834 int use_modules = vmlinux_name ? 1 : 0; 938 struct addr_location al;
835 939 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
836 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
837 if (kernel_dso == NULL)
838 return -1;
839
840 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
841 goto out_delete_dso;
842 940
843 node = rb_first(&kernel_dso->syms); 941 ++samples;
844 sym = rb_entry(node, struct symbol, rb_node);
845 min_ip = sym->start;
846 942
847 node = rb_last(&kernel_dso->syms); 943 switch (origin) {
848 sym = rb_entry(node, struct symbol, rb_node); 944 case PERF_RECORD_MISC_USER:
849 max_ip = sym->end; 945 ++userspace_samples;
946 if (hide_user_symbols)
947 return;
948 break;
949 case PERF_RECORD_MISC_KERNEL:
950 if (hide_kernel_symbols)
951 return;
952 break;
953 default:
954 return;
955 }
850 956
851 if (dump_symtab) 957 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
852 dso__fprintf(kernel_dso, stderr); 958 al.filtered)
959 return;
853 960
854 return 0; 961 if (al.sym == NULL) {
962 /*
963 * As we do lazy loading of symtabs we only will know if the
964 * specified vmlinux file is invalid when we actually have a
965 * hit in kernel space and then try to load it. So if we get
966 * here and there are _no_ symbols in the DSO backing the
967 * kernel map, bail out.
968 *
969 * We may never get here, for instance, if we use -K/
970 * --hide-kernel-symbols, even if the user specifies an
971 * invalid --vmlinux ;-)
972 */
973 if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
974 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
975 pr_err("The %s file can't be used\n",
976 symbol_conf.vmlinux_name);
977 exit(1);
978 }
855 979
856out_delete_dso: 980 return;
857 dso__delete(kernel_dso); 981 }
858 kernel_dso = NULL;
859 return -1;
860}
861 982
862/* 983 /* let's see, whether we need to install initial sym_filter_entry */
863 * Binary search in the histogram table and record the hit: 984 if (sym_filter_entry_sched) {
864 */ 985 sym_filter_entry = sym_filter_entry_sched;
865static void record_ip(u64 ip, int counter) 986 sym_filter_entry_sched = NULL;
866{ 987 parse_source(sym_filter_entry);
867 struct symbol *sym = dso__find_symbol(kernel_dso, ip);
868
869 if (sym != NULL) {
870 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
871
872 if (!syme->skip) {
873 syme->count[counter]++;
874 record_precise_ip(syme, counter, ip);
875 pthread_mutex_lock(&active_symbols_lock);
876 if (list_empty(&syme->node) || !syme->node.next)
877 __list_insert_active_sym(syme);
878 pthread_mutex_unlock(&active_symbols_lock);
879 return;
880 }
881 } 988 }
882 989
883 samples--; 990 syme = symbol__priv(al.sym);
991 if (!syme->skip) {
992 syme->count[counter]++;
993 syme->origin = origin;
994 record_precise_ip(syme, counter, ip);
995 pthread_mutex_lock(&active_symbols_lock);
996 if (list_empty(&syme->node) || !syme->node.next)
997 __list_insert_active_sym(syme);
998 pthread_mutex_unlock(&active_symbols_lock);
999 }
884} 1000}
885 1001
886static void process_event(u64 ip, int counter, int user) 1002static int event__process(event_t *event, struct perf_session *session)
887{ 1003{
888 samples++; 1004 switch (event->header.type) {
889 1005 case PERF_RECORD_COMM:
890 if (user) { 1006 event__process_comm(event, session);
891 userspace_samples++; 1007 break;
892 return; 1008 case PERF_RECORD_MMAP:
1009 event__process_mmap(event, session);
1010 break;
1011 case PERF_RECORD_FORK:
1012 case PERF_RECORD_EXIT:
1013 event__process_task(event, session);
1014 break;
1015 default:
1016 break;
893 } 1017 }
894 1018
895 record_ip(ip, counter); 1019 return 0;
896} 1020}
897 1021
898struct mmap_data { 1022struct mmap_data {
@@ -913,17 +1037,14 @@ static unsigned int mmap_read_head(struct mmap_data *md)
913 return head; 1037 return head;
914} 1038}
915 1039
916struct timeval last_read, this_read; 1040static void perf_session__mmap_read_counter(struct perf_session *self,
917 1041 struct mmap_data *md)
918static void mmap_read_counter(struct mmap_data *md)
919{ 1042{
920 unsigned int head = mmap_read_head(md); 1043 unsigned int head = mmap_read_head(md);
921 unsigned int old = md->prev; 1044 unsigned int old = md->prev;
922 unsigned char *data = md->base + page_size; 1045 unsigned char *data = md->base + page_size;
923 int diff; 1046 int diff;
924 1047
925 gettimeofday(&this_read, NULL);
926
927 /* 1048 /*
928 * If we're further behind than half the buffer, there's a chance 1049 * If we're further behind than half the buffer, there's a chance
929 * the writer will bite our tail and mess up the samples under us. 1050 * the writer will bite our tail and mess up the samples under us.
@@ -934,14 +1055,7 @@ static void mmap_read_counter(struct mmap_data *md)
934 */ 1055 */
935 diff = head - old; 1056 diff = head - old;
936 if (diff > md->mask / 2 || diff < 0) { 1057 if (diff > md->mask / 2 || diff < 0) {
937 struct timeval iv; 1058 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
938 unsigned long msecs;
939
940 timersub(&this_read, &last_read, &iv);
941 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
942
943 fprintf(stderr, "WARNING: failed to keep up with mmap data."
944 " Last read %lu msecs ago.\n", msecs);
945 1059
946 /* 1060 /*
947 * head points to a known good entry, start there. 1061 * head points to a known good entry, start there.
@@ -949,8 +1063,6 @@ static void mmap_read_counter(struct mmap_data *md)
949 old = head; 1063 old = head;
950 } 1064 }
951 1065
952 last_read = this_read;
953
954 for (; old != head;) { 1066 for (; old != head;) {
955 event_t *event = (event_t *)&data[old & md->mask]; 1067 event_t *event = (event_t *)&data[old & md->mask];
956 1068
@@ -978,13 +1090,11 @@ static void mmap_read_counter(struct mmap_data *md)
978 event = &event_copy; 1090 event = &event_copy;
979 } 1091 }
980 1092
1093 if (event->header.type == PERF_RECORD_SAMPLE)
1094 event__process_sample(event, self, md->counter);
1095 else
1096 event__process(event, self);
981 old += size; 1097 old += size;
982
983 if (event->header.type == PERF_RECORD_SAMPLE) {
984 int user =
985 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
986 process_event(event->ip.ip, md->counter, user);
987 }
988 } 1098 }
989 1099
990 md->prev = old; 1100 md->prev = old;
@@ -993,13 +1103,13 @@ static void mmap_read_counter(struct mmap_data *md)
993static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1103static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
994static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1104static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
995 1105
996static void mmap_read(void) 1106static void perf_session__mmap_read(struct perf_session *self)
997{ 1107{
998 int i, counter; 1108 int i, counter;
999 1109
1000 for (i = 0; i < nr_cpus; i++) { 1110 for (i = 0; i < nr_cpus; i++) {
1001 for (counter = 0; counter < nr_counters; counter++) 1111 for (counter = 0; counter < nr_counters; counter++)
1002 mmap_read_counter(&mmap_array[i][counter]); 1112 perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
1003 } 1113 }
1004} 1114}
1005 1115
@@ -1018,8 +1128,15 @@ static void start_counter(int i, int counter)
1018 attr = attrs + counter; 1128 attr = attrs + counter;
1019 1129
1020 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1130 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1021 attr->freq = freq; 1131
1132 if (freq) {
1133 attr->sample_type |= PERF_SAMPLE_PERIOD;
1134 attr->freq = 1;
1135 attr->sample_freq = freq;
1136 }
1137
1022 attr->inherit = (cpu < 0) && inherit; 1138 attr->inherit = (cpu < 0) && inherit;
1139 attr->mmap = 1;
1023 1140
1024try_again: 1141try_again:
1025 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1142 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1077,6 +1194,18 @@ static int __cmd_top(void)
1077 pthread_t thread; 1194 pthread_t thread;
1078 int i, counter; 1195 int i, counter;
1079 int ret; 1196 int ret;
1197 /*
1198 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1199 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1200 */
1201 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
1202 if (session == NULL)
1203 return -ENOMEM;
1204
1205 if (target_pid != -1)
1206 event__synthesize_thread(target_pid, event__process, session);
1207 else
1208 event__synthesize_threads(event__process, session);
1080 1209
1081 for (i = 0; i < nr_cpus; i++) { 1210 for (i = 0; i < nr_cpus; i++) {
1082 group_fd = -1; 1211 group_fd = -1;
@@ -1087,7 +1216,7 @@ static int __cmd_top(void)
1087 /* Wait for a minimal set of events before starting the snapshot */ 1216 /* Wait for a minimal set of events before starting the snapshot */
1088 poll(event_array, nr_poll, 100); 1217 poll(event_array, nr_poll, 100);
1089 1218
1090 mmap_read(); 1219 perf_session__mmap_read(session);
1091 1220
1092 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1221 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1093 printf("Could not create display thread.\n"); 1222 printf("Could not create display thread.\n");
@@ -1107,7 +1236,7 @@ static int __cmd_top(void)
1107 while (1) { 1236 while (1) {
1108 int hits = samples; 1237 int hits = samples;
1109 1238
1110 mmap_read(); 1239 perf_session__mmap_read(session);
1111 1240
1112 if (hits == samples) 1241 if (hits == samples)
1113 ret = poll(event_array, nr_poll, 100); 1242 ret = poll(event_array, nr_poll, 100);
@@ -1133,7 +1262,10 @@ static const struct option options[] = {
1133 "system-wide collection from all CPUs"), 1262 "system-wide collection from all CPUs"),
1134 OPT_INTEGER('C', "CPU", &profile_cpu, 1263 OPT_INTEGER('C', "CPU", &profile_cpu,
1135 "CPU to profile on"), 1264 "CPU to profile on"),
1136 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1265 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1266 "file", "vmlinux pathname"),
1267 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1268 "hide kernel symbols"),
1137 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1269 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1138 "number of mmap data pages"), 1270 "number of mmap data pages"),
1139 OPT_INTEGER('r', "realtime", &realtime_prio, 1271 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1149,13 +1281,15 @@ static const struct option options[] = {
1149 OPT_BOOLEAN('i', "inherit", &inherit, 1281 OPT_BOOLEAN('i', "inherit", &inherit,
1150 "child tasks inherit counters"), 1282 "child tasks inherit counters"),
1151 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1283 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1152 "symbol to annotate - requires -k option"), 1284 "symbol to annotate"),
1153 OPT_BOOLEAN('z', "zero", &zero, 1285 OPT_BOOLEAN('z', "zero", &zero,
1154 "zero history across updates"), 1286 "zero history across updates"),
1155 OPT_INTEGER('F', "freq", &freq, 1287 OPT_INTEGER('F', "freq", &freq,
1156 "profile at this frequency"), 1288 "profile at this frequency"),
1157 OPT_INTEGER('E', "entries", &print_entries, 1289 OPT_INTEGER('E', "entries", &print_entries,
1158 "display this many functions"), 1290 "display this many functions"),
1291 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1292 "hide user symbols"),
1159 OPT_BOOLEAN('v', "verbose", &verbose, 1293 OPT_BOOLEAN('v', "verbose", &verbose,
1160 "be more verbose (show counter open errors, etc)"), 1294 "be more verbose (show counter open errors, etc)"),
1161 OPT_END() 1295 OPT_END()
@@ -1165,19 +1299,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1165{ 1299{
1166 int counter; 1300 int counter;
1167 1301
1168 symbol__init();
1169
1170 page_size = sysconf(_SC_PAGE_SIZE); 1302 page_size = sysconf(_SC_PAGE_SIZE);
1171 1303
1172 argc = parse_options(argc, argv, options, top_usage, 0); 1304 argc = parse_options(argc, argv, options, top_usage, 0);
1173 if (argc) 1305 if (argc)
1174 usage_with_options(top_usage, options); 1306 usage_with_options(top_usage, options);
1175 1307
1176 if (freq) {
1177 default_interval = freq;
1178 freq = 1;
1179 }
1180
1181 /* CPU and PID are mutually exclusive */ 1308 /* CPU and PID are mutually exclusive */
1182 if (target_pid != -1 && profile_cpu != -1) { 1309 if (target_pid != -1 && profile_cpu != -1) {
1183 printf("WARNING: PID switch overriding CPU\n"); 1310 printf("WARNING: PID switch overriding CPU\n");
@@ -1188,11 +1315,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1188 if (!nr_counters) 1315 if (!nr_counters)
1189 nr_counters = 1; 1316 nr_counters = 1;
1190 1317
1318 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1319 (nr_counters + 1) * sizeof(unsigned long));
1320
1321 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1322 if (symbol__init() < 0)
1323 return -1;
1324
1191 if (delay_secs < 1) 1325 if (delay_secs < 1)
1192 delay_secs = 1; 1326 delay_secs = 1;
1193 1327
1194 parse_symbols(); 1328 /*
1195 parse_source(sym_filter_entry); 1329 * User specified count overrides default frequency.
1330 */
1331 if (default_interval)
1332 freq = 0;
1333 else if (freq) {
1334 default_interval = freq;
1335 } else {
1336 fprintf(stderr, "frequency and count are zero, aborting\n");
1337 exit(EXIT_FAILURE);
1338 }
1196 1339
1197 /* 1340 /*
1198 * Fill in the ones not specifically initialized via -c: 1341 * Fill in the ones not specifically initialized via -c:
@@ -1211,5 +1354,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1211 if (target_pid != -1 || profile_cpu != -1) 1354 if (target_pid != -1 || profile_cpu != -1)
1212 nr_cpus = 1; 1355 nr_cpus = 1;
1213 1356
1357 get_term_dimensions(&winsize);
1358 if (print_entries == 0) {
1359 update_print_entries(&winsize);
1360 signal(SIGWINCH, sig_winch_handler);
1361 }
1362
1214 return __cmd_top(); 1363 return __cmd_top();
1215} 1364}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0c5e4f72f2ba..407041d20de0 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -5,259 +5,499 @@
5#include "util/symbol.h" 5#include "util/symbol.h"
6#include "util/thread.h" 6#include "util/thread.h"
7#include "util/header.h" 7#include "util/header.h"
8#include "util/exec_cmd.h"
9#include "util/trace-event.h"
10#include "util/session.h"
8 11
9#include "util/parse-options.h" 12static char const *script_name;
13static char const *generate_script_lang;
10 14
11#include "perf.h" 15static int default_start_script(const char *script __unused,
12#include "util/debug.h" 16 int argc __unused,
17 const char **argv __unused)
18{
19 return 0;
20}
13 21
14#include "util/trace-event.h" 22static int default_stop_script(void)
23{
24 return 0;
25}
26
27static int default_generate_script(const char *outfile __unused)
28{
29 return 0;
30}
31
32static struct scripting_ops default_scripting_ops = {
33 .start_script = default_start_script,
34 .stop_script = default_stop_script,
35 .process_event = print_event,
36 .generate_script = default_generate_script,
37};
38
39static struct scripting_ops *scripting_ops;
40
41static void setup_scripting(void)
42{
43 /* make sure PERF_EXEC_PATH is set for scripts */
44 perf_set_argv_exec_path(perf_exec_path());
45
46 setup_perl_scripting();
47 setup_python_scripting();
15 48
16static char const *input_name = "perf.data"; 49 scripting_ops = &default_scripting_ops;
17static int input; 50}
18static unsigned long page_size; 51
19static unsigned long mmap_window = 32; 52static int cleanup_scripting(void)
53{
54 return scripting_ops->stop_script();
55}
20 56
21static unsigned long total = 0; 57#include "util/parse-options.h"
22static unsigned long total_comm = 0;
23 58
24static struct rb_root threads; 59#include "perf.h"
25static struct thread *last_match; 60#include "util/debug.h"
26 61
27static struct perf_header *header; 62#include "util/trace-event.h"
28static u64 sample_type; 63#include "util/exec_cmd.h"
29 64
65static char const *input_name = "perf.data";
30 66
31static int 67static int process_sample_event(event_t *event, struct perf_session *session)
32process_comm_event(event_t *event, unsigned long offset, unsigned long head)
33{ 68{
69 struct sample_data data;
34 struct thread *thread; 70 struct thread *thread;
35 71
36 thread = threads__findnew(event->comm.pid, &threads, &last_match); 72 memset(&data, 0, sizeof(data));
73 data.time = -1;
74 data.cpu = -1;
75 data.period = 1;
37 76
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 77 event__parse_sample(event, session->sample_type, &data);
39 (void *)(offset + head),
40 (void *)(long)(event->header.size),
41 event->comm.comm, event->comm.pid);
42 78
43 if (thread == NULL || 79 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
44 thread__set_comm(thread, event->comm.comm)) { 80 data.pid, data.tid, data.ip, data.period);
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 81
82 thread = perf_session__findnew(session, event->ip.pid);
83 if (thread == NULL) {
84 pr_debug("problem processing %d event, skipping it.\n",
85 event->header.type);
46 return -1; 86 return -1;
47 } 87 }
48 total_comm++;
49 88
89 if (session->sample_type & PERF_SAMPLE_RAW) {
90 /*
91 * FIXME: better resolve from pid from the struct trace_entry
92 * field, although it should be the same than this perf
93 * event pid
94 */
95 scripting_ops->process_event(data.cpu, data.raw_data,
96 data.raw_size,
97 data.time, thread->comm);
98 }
99
100 session->events_stats.total += data.period;
50 return 0; 101 return 0;
51} 102}
52 103
53static int 104static struct perf_event_ops event_ops = {
54process_sample_event(event_t *event, unsigned long offset, unsigned long head) 105 .sample = process_sample_event,
106 .comm = event__process_comm,
107};
108
109static int __cmd_trace(struct perf_session *session)
55{ 110{
56 char level; 111 return perf_session__process_events(session, &event_ops);
57 int show = 0; 112}
58 struct dso *dso = NULL;
59 struct thread *thread;
60 u64 ip = event->ip.ip;
61 u64 timestamp = -1;
62 u32 cpu = -1;
63 u64 period = 1;
64 void *more_data = event->ip.__more_data;
65 int cpumode;
66
67 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68
69 if (sample_type & PERF_SAMPLE_TIME) {
70 timestamp = *(u64 *)more_data;
71 more_data += sizeof(u64);
72 }
73 113
74 if (sample_type & PERF_SAMPLE_CPU) { 114struct script_spec {
75 cpu = *(u32 *)more_data; 115 struct list_head node;
76 more_data += sizeof(u32); 116 struct scripting_ops *ops;
77 more_data += sizeof(u32); /* reserved */ 117 char spec[0];
78 } 118};
119
120LIST_HEAD(script_specs);
121
122static struct script_spec *script_spec__new(const char *spec,
123 struct scripting_ops *ops)
124{
125 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
79 126
80 if (sample_type & PERF_SAMPLE_PERIOD) { 127 if (s != NULL) {
81 period = *(u64 *)more_data; 128 strcpy(s->spec, spec);
82 more_data += sizeof(u64); 129 s->ops = ops;
83 } 130 }
84 131
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 132 return s;
86 (void *)(offset + head), 133}
87 (void *)(long)(event->header.size),
88 event->header.misc,
89 event->ip.pid, event->ip.tid,
90 (void *)(long)ip,
91 (long long)period);
92 134
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 135static void script_spec__delete(struct script_spec *s)
136{
137 free(s->spec);
138 free(s);
139}
94 140
95 if (thread == NULL) { 141static void script_spec__add(struct script_spec *s)
96 eprintf("problem processing %d event, skipping it.\n", 142{
97 event->header.type); 143 list_add_tail(&s->node, &script_specs);
98 return -1; 144}
99 } 145
146static struct script_spec *script_spec__find(const char *spec)
147{
148 struct script_spec *s;
100 149
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 150 list_for_each_entry(s, &script_specs, node)
151 if (strcasecmp(s->spec, spec) == 0)
152 return s;
153 return NULL;
154}
102 155
103 if (cpumode == PERF_RECORD_MISC_KERNEL) { 156static struct script_spec *script_spec__findnew(const char *spec,
104 show = SHOW_KERNEL; 157 struct scripting_ops *ops)
105 level = 'k'; 158{
159 struct script_spec *s = script_spec__find(spec);
106 160
107 dso = kernel_dso; 161 if (s)
162 return s;
108 163
109 dump_printf(" ...... dso: %s\n", dso->name); 164 s = script_spec__new(spec, ops);
165 if (!s)
166 goto out_delete_spec;
110 167
111 } else if (cpumode == PERF_RECORD_MISC_USER) { 168 script_spec__add(s);
112 169
113 show = SHOW_USER; 170 return s;
114 level = '.';
115 171
116 } else { 172out_delete_spec:
117 show = SHOW_HV; 173 script_spec__delete(s);
118 level = 'H';
119 174
120 dso = hypervisor_dso; 175 return NULL;
176}
121 177
122 dump_printf(" ...... dso: [hypervisor]\n"); 178int script_spec_register(const char *spec, struct scripting_ops *ops)
123 } 179{
180 struct script_spec *s;
124 181
125 if (sample_type & PERF_SAMPLE_RAW) { 182 s = script_spec__find(spec);
126 struct { 183 if (s)
127 u32 size; 184 return -1;
128 char data[0];
129 } *raw = more_data;
130 185
131 /* 186 s = script_spec__findnew(spec, ops);
132 * FIXME: better resolve from pid from the struct trace_entry 187 if (!s)
133 * field, although it should be the same than this perf 188 return -1;
134 * event pid
135 */
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm);
137 }
138 total += period;
139 189
140 return 0; 190 return 0;
141} 191}
142 192
143static int 193static struct scripting_ops *script_spec__lookup(const char *spec)
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{ 194{
146 trace_event(event); 195 struct script_spec *s = script_spec__find(spec);
196 if (!s)
197 return NULL;
147 198
148 switch (event->header.type) { 199 return s->ops;
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST: 200}
150 return 0;
151 201
152 case PERF_RECORD_COMM: 202static void list_available_languages(void)
153 return process_comm_event(event, offset, head); 203{
204 struct script_spec *s;
154 205
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ: 206 fprintf(stderr, "\n");
156 return 0; 207 fprintf(stderr, "Scripting language extensions (used in "
208 "perf trace -s [spec:]script.[spec]):\n\n");
157 209
158 case PERF_RECORD_SAMPLE: 210 list_for_each_entry(s, &script_specs, node)
159 return process_sample_event(event, offset, head); 211 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
160 212
161 case PERF_RECORD_MAX: 213 fprintf(stderr, "\n");
162 default: 214}
163 return -1; 215
216static int parse_scriptname(const struct option *opt __used,
217 const char *str, int unset __used)
218{
219 char spec[PATH_MAX];
220 const char *script, *ext;
221 int len;
222
223 if (strcmp(str, "lang") == 0) {
224 list_available_languages();
225 exit(0);
226 }
227
228 script = strchr(str, ':');
229 if (script) {
230 len = script - str;
231 if (len >= PATH_MAX) {
232 fprintf(stderr, "invalid language specifier");
233 return -1;
234 }
235 strncpy(spec, str, len);
236 spec[len] = '\0';
237 scripting_ops = script_spec__lookup(spec);
238 if (!scripting_ops) {
239 fprintf(stderr, "invalid language specifier");
240 return -1;
241 }
242 script++;
243 } else {
244 script = str;
245 ext = strchr(script, '.');
246 if (!ext) {
247 fprintf(stderr, "invalid script extension");
248 return -1;
249 }
250 scripting_ops = script_spec__lookup(++ext);
251 if (!scripting_ops) {
252 fprintf(stderr, "invalid script extension");
253 return -1;
254 }
164 } 255 }
165 256
257 script_name = strdup(script);
258
166 return 0; 259 return 0;
167} 260}
168 261
169static int __cmd_trace(void) 262#define for_each_lang(scripts_dir, lang_dirent, lang_next) \
263 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
264 lang_next) \
265 if (lang_dirent.d_type == DT_DIR && \
266 (strcmp(lang_dirent.d_name, ".")) && \
267 (strcmp(lang_dirent.d_name, "..")))
268
269#define for_each_script(lang_dir, script_dirent, script_next) \
270 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
271 script_next) \
272 if (script_dirent.d_type != DT_DIR)
273
274
275#define RECORD_SUFFIX "-record"
276#define REPORT_SUFFIX "-report"
277
278struct script_desc {
279 struct list_head node;
280 char *name;
281 char *half_liner;
282 char *args;
283};
284
285LIST_HEAD(script_descs);
286
287static struct script_desc *script_desc__new(const char *name)
170{ 288{
171 int ret, rc = EXIT_FAILURE; 289 struct script_desc *s = zalloc(sizeof(*s));
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187 290
188 ret = fstat(input, &perf_stat); 291 if (s != NULL)
189 if (ret < 0) { 292 s->name = strdup(name);
190 perror("failed to stat file");
191 exit(-1);
192 }
193 293
194 if (!perf_stat.st_size) { 294 return s;
195 fprintf(stderr, "zero-sized file, nothing to do!\n"); 295}
196 exit(0); 296
197 } 297static void script_desc__delete(struct script_desc *s)
198 header = perf_header__read(input); 298{
199 head = header->data_offset; 299 free(s->name);
200 sample_type = perf_header__sample_type(header); 300 free(s);
301}
302
303static void script_desc__add(struct script_desc *s)
304{
305 list_add_tail(&s->node, &script_descs);
306}
307
308static struct script_desc *script_desc__find(const char *name)
309{
310 struct script_desc *s;
311
312 list_for_each_entry(s, &script_descs, node)
313 if (strcasecmp(s->name, name) == 0)
314 return s;
315 return NULL;
316}
317
318static struct script_desc *script_desc__findnew(const char *name)
319{
320 struct script_desc *s = script_desc__find(name);
321
322 if (s)
323 return s;
324
325 s = script_desc__new(name);
326 if (!s)
327 goto out_delete_desc;
328
329 script_desc__add(s);
330
331 return s;
201 332
202 if (!(sample_type & PERF_SAMPLE_RAW)) 333out_delete_desc:
203 die("No trace sample to read. Did you call perf record " 334 script_desc__delete(s);
204 "without -R?");
205 335
206 if (load_kernel() < 0) { 336 return NULL;
207 perror("failed to load kernel symbols"); 337}
208 return EXIT_FAILURE; 338
339static char *ends_with(char *str, const char *suffix)
340{
341 size_t suffix_len = strlen(suffix);
342 char *p = str;
343
344 if (strlen(str) > suffix_len) {
345 p = str + strlen(str) - suffix_len;
346 if (!strncmp(p, suffix, suffix_len))
347 return p;
209 } 348 }
210 349
211remap: 350 return NULL;
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 351}
213 MAP_SHARED, input, offset); 352
214 if (buf == MAP_FAILED) { 353static char *ltrim(char *str)
215 perror("failed to mmap file"); 354{
216 exit(-1); 355 int len = strlen(str);
356
357 while (len && isspace(*str)) {
358 len--;
359 str++;
217 } 360 }
218 361
219more: 362 return str;
220 event = (event_t *)(buf + head); 363}
221 364
222 if (head + event->header.size >= page_size * mmap_window) { 365static int read_script_info(struct script_desc *desc, const char *filename)
223 unsigned long shift = page_size * (head / page_size); 366{
224 int res; 367 char line[BUFSIZ], *p;
368 FILE *fp;
225 369
226 res = munmap(buf, page_size * mmap_window); 370 fp = fopen(filename, "r");
227 assert(res == 0); 371 if (!fp)
372 return -1;
228 373
229 offset += shift; 374 while (fgets(line, sizeof(line), fp)) {
230 head -= shift; 375 p = ltrim(line);
231 goto remap; 376 if (strlen(p) == 0)
377 continue;
378 if (*p != '#')
379 continue;
380 p++;
381 if (strlen(p) && *p == '!')
382 continue;
383
384 p = ltrim(p);
385 if (strlen(p) && p[strlen(p) - 1] == '\n')
386 p[strlen(p) - 1] = '\0';
387
388 if (!strncmp(p, "description:", strlen("description:"))) {
389 p += strlen("description:");
390 desc->half_liner = strdup(ltrim(p));
391 continue;
392 }
393
394 if (!strncmp(p, "args:", strlen("args:"))) {
395 p += strlen("args:");
396 desc->args = strdup(ltrim(p));
397 continue;
398 }
232 } 399 }
233 400
234 size = event->header.size; 401 fclose(fp);
235
236 if (!size || process_event(event, offset, head) < 0) {
237 402
238 /* 403 return 0;
239 * assume we lost track of the stream, check alignment, and 404}
240 * increment a single u64 in the hope to catch on again 'soon'.
241 */
242 405
243 if (unlikely(head & 7)) 406static int list_available_scripts(const struct option *opt __used,
244 head &= ~7ULL; 407 const char *s __used, int unset __used)
408{
409 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
410 char scripts_path[MAXPATHLEN];
411 DIR *scripts_dir, *lang_dir;
412 char script_path[MAXPATHLEN];
413 char lang_path[MAXPATHLEN];
414 struct script_desc *desc;
415 char first_half[BUFSIZ];
416 char *script_root;
417 char *str;
418
419 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
420
421 scripts_dir = opendir(scripts_path);
422 if (!scripts_dir)
423 return -1;
245 424
246 size = 8; 425 for_each_lang(scripts_dir, lang_dirent, lang_next) {
426 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
427 lang_dirent.d_name);
428 lang_dir = opendir(lang_path);
429 if (!lang_dir)
430 continue;
431
432 for_each_script(lang_dir, script_dirent, script_next) {
433 script_root = strdup(script_dirent.d_name);
434 str = ends_with(script_root, REPORT_SUFFIX);
435 if (str) {
436 *str = '\0';
437 desc = script_desc__findnew(script_root);
438 snprintf(script_path, MAXPATHLEN, "%s/%s",
439 lang_path, script_dirent.d_name);
440 read_script_info(desc, script_path);
441 }
442 free(script_root);
443 }
247 } 444 }
248 445
249 head += size; 446 fprintf(stdout, "List of available trace scripts:\n");
447 list_for_each_entry(desc, &script_descs, node) {
448 sprintf(first_half, "%s %s", desc->name,
449 desc->args ? desc->args : "");
450 fprintf(stdout, " %-36s %s\n", first_half,
451 desc->half_liner ? desc->half_liner : "");
452 }
250 453
251 if (offset + head < (unsigned long)perf_stat.st_size) 454 exit(0);
252 goto more; 455}
253 456
254 rc = EXIT_SUCCESS; 457static char *get_script_path(const char *script_root, const char *suffix)
255 close(input); 458{
459 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
460 char scripts_path[MAXPATHLEN];
461 char script_path[MAXPATHLEN];
462 DIR *scripts_dir, *lang_dir;
463 char lang_path[MAXPATHLEN];
464 char *str, *__script_root;
465 char *path = NULL;
466
467 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
468
469 scripts_dir = opendir(scripts_path);
470 if (!scripts_dir)
471 return NULL;
472
473 for_each_lang(scripts_dir, lang_dirent, lang_next) {
474 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
475 lang_dirent.d_name);
476 lang_dir = opendir(lang_path);
477 if (!lang_dir)
478 continue;
479
480 for_each_script(lang_dir, script_dirent, script_next) {
481 __script_root = strdup(script_dirent.d_name);
482 str = ends_with(__script_root, suffix);
483 if (str) {
484 *str = '\0';
485 if (strcmp(__script_root, script_root))
486 continue;
487 snprintf(script_path, MAXPATHLEN, "%s/%s",
488 lang_path, script_dirent.d_name);
489 path = strdup(script_path);
490 free(__script_root);
491 break;
492 }
493 free(__script_root);
494 }
495 }
256 496
257 return rc; 497 return path;
258} 498}
259 499
260static const char * const annotate_usage[] = { 500static const char * const trace_usage[] = {
261 "perf trace [<options>] <command>", 501 "perf trace [<options>] <command>",
262 NULL 502 NULL
263}; 503};
@@ -267,25 +507,122 @@ static const struct option options[] = {
267 "dump raw trace in ASCII"), 507 "dump raw trace in ASCII"),
268 OPT_BOOLEAN('v', "verbose", &verbose, 508 OPT_BOOLEAN('v', "verbose", &verbose,
269 "be more verbose (show symbol address, etc)"), 509 "be more verbose (show symbol address, etc)"),
510 OPT_BOOLEAN('L', "Latency", &latency_format,
511 "show latency attributes (irqs/preemption disabled, etc)"),
512 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
513 list_available_scripts),
514 OPT_CALLBACK('s', "script", NULL, "name",
515 "script file name (lang:script name, script name, or *)",
516 parse_scriptname),
517 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
518 "generate perf-trace.xx script in specified language"),
519 OPT_STRING('i', "input", &input_name, "file",
520 "input file name"),
521
270 OPT_END() 522 OPT_END()
271}; 523};
272 524
273int cmd_trace(int argc, const char **argv, const char *prefix __used) 525int cmd_trace(int argc, const char **argv, const char *prefix __used)
274{ 526{
275 symbol__init(); 527 struct perf_session *session;
276 page_size = getpagesize(); 528 const char *suffix = NULL;
529 const char **__argv;
530 char *script_path;
531 int i, err;
532
533 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
534 if (argc < 3) {
535 fprintf(stderr,
536 "Please specify a record script\n");
537 return -1;
538 }
539 suffix = RECORD_SUFFIX;
540 }
277 541
278 argc = parse_options(argc, argv, options, annotate_usage, 0); 542 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
279 if (argc) { 543 if (argc < 3) {
280 /* 544 fprintf(stderr,
281 * Special case: if there's an argument left then assume tha 545 "Please specify a report script\n");
282 * it's a symbol filter: 546 return -1;
283 */ 547 }
284 if (argc > 1) 548 suffix = REPORT_SUFFIX;
285 usage_with_options(annotate_usage, options); 549 }
550
551 if (suffix) {
552 script_path = get_script_path(argv[2], suffix);
553 if (!script_path) {
554 fprintf(stderr, "script not found\n");
555 return -1;
556 }
557
558 __argv = malloc((argc + 1) * sizeof(const char *));
559 __argv[0] = "/bin/sh";
560 __argv[1] = script_path;
561 for (i = 3; i < argc; i++)
562 __argv[i - 1] = argv[i];
563 __argv[argc - 1] = NULL;
564
565 execvp("/bin/sh", (char **)__argv);
566 exit(-1);
567 }
568
569 setup_scripting();
570
571 argc = parse_options(argc, argv, options, trace_usage,
572 PARSE_OPT_STOP_AT_NON_OPTION);
573
574 if (symbol__init() < 0)
575 return -1;
576 if (!script_name)
577 setup_pager();
578
579 session = perf_session__new(input_name, O_RDONLY, 0);
580 if (session == NULL)
581 return -ENOMEM;
582
583 if (!perf_session__has_traces(session, "record -R"))
584 return -EINVAL;
585
586 if (generate_script_lang) {
587 struct stat perf_stat;
588
589 int input = open(input_name, O_RDONLY);
590 if (input < 0) {
591 perror("failed to open file");
592 exit(-1);
593 }
594
595 err = fstat(input, &perf_stat);
596 if (err < 0) {
597 perror("failed to stat file");
598 exit(-1);
599 }
600
601 if (!perf_stat.st_size) {
602 fprintf(stderr, "zero-sized file, nothing to do!\n");
603 exit(0);
604 }
605
606 scripting_ops = script_spec__lookup(generate_script_lang);
607 if (!scripting_ops) {
608 fprintf(stderr, "invalid language specifier");
609 return -1;
610 }
611
612 err = scripting_ops->generate_script("perf-trace");
613 goto out;
614 }
615
616 if (script_name) {
617 err = scripting_ops->start_script(script_name, argc, argv);
618 if (err)
619 goto out;
286 } 620 }
287 621
288 setup_pager(); 622 err = __cmd_trace(session);
289 623
290 return __cmd_trace(); 624 perf_session__delete(session);
625 cleanup_scripting();
626out:
627 return err;
291} 628}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index e11d8d231c3b..10fe49e7048a 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -15,6 +15,10 @@ extern int read_line_with_nul(char *buf, int size, FILE *file);
15extern int check_pager_config(const char *cmd); 15extern int check_pager_config(const char *cmd);
16 16
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);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
21extern int cmd_diff(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix); 23extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix); 24extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -25,5 +29,8 @@ extern int cmd_timechart(int argc, const char **argv, const char *prefix);
25extern int cmd_top(int argc, const char **argv, const char *prefix); 29extern int cmd_top(int argc, const char **argv, const char *prefix);
26extern int cmd_trace(int argc, const char **argv, const char *prefix); 30extern int cmd_trace(int argc, const char **argv, const char *prefix);
27extern int cmd_version(int argc, const char **argv, const char *prefix); 31extern int cmd_version(int argc, const char **argv, const char *prefix);
32extern int cmd_probe(int argc, const char **argv, const char *prefix);
33extern int cmd_kmem(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix);
28 35
29#endif 36#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00326e230d87..db6ee94d4a8e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,6 +3,11 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-archive mainporcelain common
7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common
10perf-diff mainporcelain common
6perf-list mainporcelain common 11perf-list mainporcelain common
7perf-sched mainporcelain common 12perf-sched mainporcelain common
8perf-record mainporcelain common 13perf-record mainporcelain common
@@ -11,3 +16,6 @@ perf-stat mainporcelain common
11perf-timechart mainporcelain common 16perf-timechart mainporcelain common
12perf-top mainporcelain common 17perf-top mainporcelain common
13perf-trace mainporcelain common 18perf-trace mainporcelain common
19perf-probe mainporcelain common
20perf-kmem mainporcelain common
21perf-lock mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index fdd42a824c98..bd0bb1b1279b 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
@@ -101,10 +101,10 @@ enum hw_event_ids {
101 */ 101 */
102 PERF_COUNT_HW_CPU_CYCLES = 0, 102 PERF_COUNT_HW_CPU_CYCLES = 0,
103 PERF_COUNT_HW_INSTRUCTIONS = 1, 103 PERF_COUNT_HW_INSTRUCTIONS = 1,
104 PERF_COUNT_HW_CACHE_REFERENCES = 2, 104 PERF_COUNT_HW_CACHE_REFERENCES = 2,
105 PERF_COUNT_HW_CACHE_MISSES = 3, 105 PERF_COUNT_HW_CACHE_MISSES = 3,
106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, 106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_HW_BRANCH_MISSES = 5, 107 PERF_COUNT_HW_BRANCH_MISSES = 5,
108 PERF_COUNT_HW_BUS_CYCLES = 6, 108 PERF_COUNT_HW_BUS_CYCLES = 6,
109}; 109};
110 110
@@ -131,12 +131,14 @@ software events, selected by 'event_id':
131 */ 131 */
132enum sw_event_ids { 132enum sw_event_ids {
133 PERF_COUNT_SW_CPU_CLOCK = 0, 133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1, 134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2, 135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3, 136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, 139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
140 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
141 PERF_COUNT_SW_EMULATION_FAULTS = 8,
140}; 142};
141 143
142Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event 144Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event
@@ -397,7 +399,7 @@ Notification of new events is possible through poll()/select()/epoll() and
397fcntl() managing signals. 399fcntl() managing signals.
398 400
399Normally a notification is generated for every page filled, however one can 401Normally a notification is generated for every page filled, however one can
400additionally set perf_event_hw_event.wakeup_events to generate one every 402additionally set perf_event_attr.wakeup_events to generate one every
401so many counter overflow events. 403so many counter overflow events.
402 404
403Future 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-archive.sh b/tools/perf/perf-archive.sh
new file mode 100644
index 000000000000..910468e6e01c
--- /dev/null
+++ b/tools/perf/perf-archive.sh
@@ -0,0 +1,33 @@
1#!/bin/bash
2# perf archive
3# Arnaldo Carvalho de Melo <acme@redhat.com>
4
5PERF_DATA=perf.data
6if [ $# -ne 0 ] ; then
7 PERF_DATA=$1
8fi
9
10DEBUGDIR=~/.debug/
11BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
12NOBUILDID=0000000000000000000000000000000000000000
13
14perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
15if [ ! -s $BUILDIDS ] ; then
16 echo "perf archive: no build-ids found"
17 rm -f $BUILDIDS
18 exit 1
19fi
20
21MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
22
23cut -d ' ' -f 1 $BUILDIDS | \
24while read build_id ; do
25 linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2}
26 filename=$(readlink -f $linkname)
27 echo ${linkname#$DEBUGDIR} >> $MANIFEST
28 echo ${filename#$DEBUGDIR} >> $MANIFEST
29done
30
31tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST
32rm -f $MANIFEST $BUILDIDS
33exit 0
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 19fc7feb9d59..cd32c200cdb3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -14,6 +14,7 @@
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/string.h" 16#include "util/string.h"
17#include "util/debugfs.h"
17 18
18const char perf_usage_string[] = 19const char perf_usage_string[] =
19 "perf [--version] [--help] COMMAND [ARGS]"; 20 "perf [--version] [--help] COMMAND [ARGS]";
@@ -47,7 +48,8 @@ int check_pager_config(const char *cmd)
47 return c.val; 48 return c.val;
48} 49}
49 50
50static void commit_pager_choice(void) { 51static void commit_pager_choice(void)
52{
51 switch (use_pager) { 53 switch (use_pager) {
52 case 0: 54 case 0:
53 setenv("PERF_PAGER", "cat", 1); 55 setenv("PERF_PAGER", "cat", 1);
@@ -69,7 +71,7 @@ static void set_debugfs_path(void)
69 "tracing/events"); 71 "tracing/events");
70} 72}
71 73
72static int handle_options(const char*** argv, int* argc, int* envchanged) 74static int handle_options(const char ***argv, int *argc, int *envchanged)
73{ 75{
74 int handled = 0; 76 int handled = 0;
75 77
@@ -89,8 +91,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
89 /* 91 /*
90 * Check remaining flags. 92 * Check remaining flags.
91 */ 93 */
92 if (!prefixcmp(cmd, "--exec-path")) { 94 if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
93 cmd += 11; 95 cmd += strlen(CMD_EXEC_PATH);
94 if (*cmd == '=') 96 if (*cmd == '=')
95 perf_set_argv_exec_path(cmd + 1); 97 perf_set_argv_exec_path(cmd + 1);
96 else { 98 else {
@@ -108,7 +110,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
108 *envchanged = 1; 110 *envchanged = 1;
109 } else if (!strcmp(cmd, "--perf-dir")) { 111 } else if (!strcmp(cmd, "--perf-dir")) {
110 if (*argc < 2) { 112 if (*argc < 2) {
111 fprintf(stderr, "No directory given for --perf-dir.\n" ); 113 fprintf(stderr, "No directory given for --perf-dir.\n");
112 usage(perf_usage_string); 114 usage(perf_usage_string);
113 } 115 }
114 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); 116 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
@@ -117,13 +119,13 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
117 (*argv)++; 119 (*argv)++;
118 (*argc)--; 120 (*argc)--;
119 handled++; 121 handled++;
120 } else if (!prefixcmp(cmd, "--perf-dir=")) { 122 } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
121 setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1); 123 setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
122 if (envchanged) 124 if (envchanged)
123 *envchanged = 1; 125 *envchanged = 1;
124 } else if (!strcmp(cmd, "--work-tree")) { 126 } else if (!strcmp(cmd, "--work-tree")) {
125 if (*argc < 2) { 127 if (*argc < 2) {
126 fprintf(stderr, "No directory given for --work-tree.\n" ); 128 fprintf(stderr, "No directory given for --work-tree.\n");
127 usage(perf_usage_string); 129 usage(perf_usage_string);
128 } 130 }
129 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); 131 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
@@ -131,8 +133,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
131 *envchanged = 1; 133 *envchanged = 1;
132 (*argv)++; 134 (*argv)++;
133 (*argc)--; 135 (*argc)--;
134 } else if (!prefixcmp(cmd, "--work-tree=")) { 136 } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
135 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 137 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
136 if (envchanged) 138 if (envchanged)
137 *envchanged = 1; 139 *envchanged = 1;
138 } else if (!strcmp(cmd, "--debugfs-dir")) { 140 } else if (!strcmp(cmd, "--debugfs-dir")) {
@@ -146,8 +148,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
146 *envchanged = 1; 148 *envchanged = 1;
147 (*argv)++; 149 (*argv)++;
148 (*argc)--; 150 (*argc)--;
149 } else if (!prefixcmp(cmd, "--debugfs-dir=")) { 151 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
150 strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN); 152 strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
151 debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 153 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
152 if (envchanged) 154 if (envchanged)
153 *envchanged = 1; 155 *envchanged = 1;
@@ -167,7 +169,7 @@ static int handle_alias(int *argcp, const char ***argv)
167{ 169{
168 int envchanged = 0, ret = 0, saved_errno = errno; 170 int envchanged = 0, ret = 0, saved_errno = errno;
169 int count, option_count; 171 int count, option_count;
170 const char** new_argv; 172 const char **new_argv;
171 const char *alias_command; 173 const char *alias_command;
172 char *alias_string; 174 char *alias_string;
173 175
@@ -209,11 +211,11 @@ static int handle_alias(int *argcp, const char ***argv)
209 if (!strcmp(alias_command, new_argv[0])) 211 if (!strcmp(alias_command, new_argv[0]))
210 die("recursive alias: %s", alias_command); 212 die("recursive alias: %s", alias_command);
211 213
212 new_argv = realloc(new_argv, sizeof(char*) * 214 new_argv = realloc(new_argv, sizeof(char *) *
213 (count + *argcp + 1)); 215 (count + *argcp + 1));
214 /* insert after command name */ 216 /* insert after command name */
215 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); 217 memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
216 new_argv[count+*argcp] = NULL; 218 new_argv[count + *argcp] = NULL;
217 219
218 *argv = new_argv; 220 *argv = new_argv;
219 *argcp += count - 1; 221 *argcp += count - 1;
@@ -284,17 +286,24 @@ static void handle_internal_command(int argc, const char **argv)
284{ 286{
285 const char *cmd = argv[0]; 287 const char *cmd = argv[0];
286 static struct cmd_struct commands[] = { 288 static struct cmd_struct commands[] = {
287 { "help", cmd_help, 0 }, 289 { "buildid-cache", cmd_buildid_cache, 0 },
288 { "list", cmd_list, 0 }, 290 { "buildid-list", cmd_buildid_list, 0 },
289 { "record", cmd_record, 0 }, 291 { "diff", cmd_diff, 0 },
290 { "report", cmd_report, 0 }, 292 { "help", cmd_help, 0 },
291 { "stat", cmd_stat, 0 }, 293 { "list", cmd_list, 0 },
292 { "timechart", cmd_timechart, 0 }, 294 { "record", cmd_record, 0 },
293 { "top", cmd_top, 0 }, 295 { "report", cmd_report, 0 },
294 { "annotate", cmd_annotate, 0 }, 296 { "bench", cmd_bench, 0 },
295 { "version", cmd_version, 0 }, 297 { "stat", cmd_stat, 0 },
296 { "trace", cmd_trace, 0 }, 298 { "timechart", cmd_timechart, 0 },
297 { "sched", cmd_sched, 0 }, 299 { "top", cmd_top, 0 },
300 { "annotate", cmd_annotate, 0 },
301 { "version", cmd_version, 0 },
302 { "trace", cmd_trace, 0 },
303 { "sched", cmd_sched, 0 },
304 { "probe", cmd_probe, 0 },
305 { "kmem", cmd_kmem, 0 },
306 { "lock", cmd_lock, 0 },
298 }; 307 };
299 unsigned int i; 308 unsigned int i;
300 static const char ext[] = STRIP_EXTENSION; 309 static const char ext[] = STRIP_EXTENSION;
@@ -382,45 +391,12 @@ static int run_argv(int *argcp, const char ***argv)
382/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 391/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
383static void get_debugfs_mntpt(void) 392static void get_debugfs_mntpt(void)
384{ 393{
385 FILE *file; 394 const char *path = debugfs_mount(NULL);
386 char fs_type[100];
387 char debugfs[MAXPATHLEN];
388
389 /*
390 * try the standard location
391 */
392 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) {
393 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
394 return;
395 }
396
397 /*
398 * try the sane location
399 */
400 if (valid_debugfs_mount("/debug/") == 0) {
401 strcpy(debugfs_mntpt, "/debug/");
402 return;
403 }
404 395
405 /* 396 if (path)
406 * give up and parse /proc/mounts 397 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
407 */ 398 else
408 file = fopen("/proc/mounts", "r"); 399 debugfs_mntpt[0] = '\0';
409 if (file == NULL)
410 return;
411
412 while (fscanf(file, "%*s %"
413 STR(MAXPATHLEN)
414 "s %99s %*s %*d %*d\n",
415 debugfs, fs_type) == 2) {
416 if (strcmp(fs_type, "debugfs") == 0)
417 break;
418 }
419 fclose(file);
420 if (strcmp(fs_type, "debugfs") == 0) {
421 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
422 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
423 }
424} 400}
425 401
426int main(int argc, const char **argv) 402int main(int argc, const char **argv)
@@ -469,15 +445,15 @@ int main(int argc, const char **argv)
469 445
470 /* 446 /*
471 * We use PATH to find perf commands, but we prepend some higher 447 * We use PATH to find perf commands, but we prepend some higher
472 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 448 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
473 * environment, and the $(perfexecdir) from the Makefile at build 449 * environment, and the $(perfexecdir) from the Makefile at build
474 * time. 450 * time.
475 */ 451 */
476 setup_path(); 452 setup_path();
477 453
478 while (1) { 454 while (1) {
479 static int done_help = 0; 455 static int done_help;
480 static int was_alias = 0; 456 static int was_alias;
481 457
482 was_alias = run_argv(&argc, &argv); 458 was_alias = run_argv(&argc, &argv);
483 if (errno != ENOENT) 459 if (errno != ENOENT)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 8cc4623afd6f..6fb379bc1d1f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -47,6 +47,28 @@
47#define cpu_relax() asm volatile("":::"memory") 47#define cpu_relax() asm volatile("":::"memory")
48#endif 48#endif
49 49
50#ifdef __alpha__
51#include "../../arch/alpha/include/asm/unistd.h"
52#define rmb() asm volatile("mb" ::: "memory")
53#define cpu_relax() asm volatile("" ::: "memory")
54#endif
55
56#ifdef __ia64__
57#include "../../arch/ia64/include/asm/unistd.h"
58#define rmb() asm volatile ("mf" ::: "memory")
59#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
60#endif
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() ((void(*)(void))0xffff0fa0)()
69#define cpu_relax() asm volatile("":::"memory")
70#endif
71
50#include <time.h> 72#include <time.h>
51#include <unistd.h> 73#include <unistd.h>
52#include <sys/types.h> 74#include <sys/types.h>
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
new file mode 100644
index 000000000000..01a64ad693f2
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -0,0 +1,135 @@
1/*
2 * This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
3 * contents of Context.xs. Do not edit this file, edit Context.xs instead.
4 *
5 * ANY CHANGES MADE HERE WILL BE LOST!
6 *
7 */
8
9#line 1 "Context.xs"
10/*
11 * Context.xs. XS interfaces for perf trace.
12 *
13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 */
30
31#include "EXTERN.h"
32#include "perl.h"
33#include "XSUB.h"
34#include "../../../perf.h"
35#include "../../../util/trace-event.h"
36
37#ifndef PERL_UNUSED_VAR
38# define PERL_UNUSED_VAR(var) if (0) var = var
39#endif
40
41#line 42 "Context.c"
42
43XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
44XS(XS_Perf__Trace__Context_common_pc)
45{
46#ifdef dVAR
47 dVAR; dXSARGS;
48#else
49 dXSARGS;
50#endif
51 if (items != 1)
52 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_pc", "context");
53 PERL_UNUSED_VAR(cv); /* -W */
54 {
55 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
56 int RETVAL;
57 dXSTARG;
58
59 RETVAL = common_pc(context);
60 XSprePUSH; PUSHi((IV)RETVAL);
61 }
62 XSRETURN(1);
63}
64
65
66XS(XS_Perf__Trace__Context_common_flags); /* prototype to pass -Wmissing-prototypes */
67XS(XS_Perf__Trace__Context_common_flags)
68{
69#ifdef dVAR
70 dVAR; dXSARGS;
71#else
72 dXSARGS;
73#endif
74 if (items != 1)
75 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_flags", "context");
76 PERL_UNUSED_VAR(cv); /* -W */
77 {
78 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
79 int RETVAL;
80 dXSTARG;
81
82 RETVAL = common_flags(context);
83 XSprePUSH; PUSHi((IV)RETVAL);
84 }
85 XSRETURN(1);
86}
87
88
89XS(XS_Perf__Trace__Context_common_lock_depth); /* prototype to pass -Wmissing-prototypes */
90XS(XS_Perf__Trace__Context_common_lock_depth)
91{
92#ifdef dVAR
93 dVAR; dXSARGS;
94#else
95 dXSARGS;
96#endif
97 if (items != 1)
98 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_lock_depth", "context");
99 PERL_UNUSED_VAR(cv); /* -W */
100 {
101 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
102 int RETVAL;
103 dXSTARG;
104
105 RETVAL = common_lock_depth(context);
106 XSprePUSH; PUSHi((IV)RETVAL);
107 }
108 XSRETURN(1);
109}
110
111#ifdef __cplusplus
112extern "C"
113#endif
114XS(boot_Perf__Trace__Context); /* prototype to pass -Wmissing-prototypes */
115XS(boot_Perf__Trace__Context)
116{
117#ifdef dVAR
118 dVAR; dXSARGS;
119#else
120 dXSARGS;
121#endif
122 const char* file = __FILE__;
123
124 PERL_UNUSED_VAR(cv); /* -W */
125 PERL_UNUSED_VAR(items); /* -W */
126 XS_VERSION_BOOTCHECK ;
127
128 newXSproto("Perf::Trace::Context::common_pc", XS_Perf__Trace__Context_common_pc, file, "$");
129 newXSproto("Perf::Trace::Context::common_flags", XS_Perf__Trace__Context_common_flags, file, "$");
130 newXSproto("Perf::Trace::Context::common_lock_depth", XS_Perf__Trace__Context_common_lock_depth, file, "$");
131 if (PL_unitcheckav)
132 call_list(PL_scopestack_ix, PL_unitcheckav);
133 XSRETURN_YES;
134}
135
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
new file mode 100644
index 000000000000..549cf0467d30
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -0,0 +1,42 @@
1/*
2 * Context.xs. XS interfaces for perf trace.
3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "EXTERN.h"
23#include "perl.h"
24#include "XSUB.h"
25#include "../../../perf.h"
26#include "../../../util/trace-event.h"
27
28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
29PROTOTYPES: ENABLE
30
31int
32common_pc(context)
33 struct scripting_context * context
34
35int
36common_flags(context)
37 struct scripting_context * context
38
39int
40common_lock_depth(context)
41 struct scripting_context * context
42
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
new file mode 100644
index 000000000000..decdeb0f6789
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
@@ -0,0 +1,17 @@
1use 5.010000;
2use ExtUtils::MakeMaker;
3# See lib/ExtUtils/MakeMaker.pm for details of how to influence
4# the contents of the Makefile that is written.
5WriteMakefile(
6 NAME => 'Perf::Trace::Context',
7 VERSION_FROM => 'lib/Perf/Trace/Context.pm', # finds $VERSION
8 PREREQ_PM => {}, # e.g., Module::Name => 1.1
9 ($] >= 5.005 ? ## Add these new keywords supported since 5.005
10 (ABSTRACT_FROM => 'lib/Perf/Trace/Context.pm', # retrieve abstract from module
11 AUTHOR => 'Tom Zanussi <tzanussi@gmail.com>') : ()),
12 LIBS => [''], # e.g., '-lm'
13 DEFINE => '-I ../..', # e.g., '-DHAVE_SOMETHING'
14 INC => '-I.', # e.g., '-I. -I/usr/include/other'
15 # Un-comment this if you add C files to link with later:
16 OBJECT => 'Context.o', # link all the C files too
17);
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
new file mode 100644
index 000000000000..9a9707630791
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/README
@@ -0,0 +1,59 @@
1Perf-Trace-Util version 0.01
2============================
3
4This module contains utility functions for use with perf trace.
5
6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
7that the core perf support for Perl calls on and should always be
8'used', while Util.pm contains useful but optional utility functions
9that scripts may want to use. Context.pm contains the Perl->C
10interface that allows scripts to access data in the embedding perf
11executable; scripts wishing to do that should 'use Context.pm'.
12
13The Perl->C perf interface is completely driven by Context.xs. If you
14want to add new Perl functions that end up accessing C data in the
15perf executable, you add desciptions of the new functions here.
16scripting_context is a pointer to the perf data in the perf executable
17that you want to access - it's passed as the second parameter,
18$context, to all handler functions.
19
20After you do that:
21
22 perl Makefile.PL # to create a Makefile for the next step
23 make # to create Context.c
24
25 edit Context.c to add const to the char* file = __FILE__ line in
26 XS(boot_Perf__Trace__Context) to silence a warning/error.
27
28 You can delete the Makefile, object files and anything else that was
29 generated e.g. blib and shared library, etc, except for of course
30 Context.c
31
32 You should then be able to run the normal perf make as usual.
33
34INSTALLATION
35
36Building perf with perf trace Perl scripting should install this
37module in the right place.
38
39You should make sure libperl and ExtUtils/Embed.pm are installed first
40e.g. apt-get install libperl-dev or yum install perl-ExtUtils-Embed.
41
42DEPENDENCIES
43
44This module requires these other modules and libraries:
45
46 None
47
48COPYRIGHT AND LICENCE
49
50Copyright (C) 2009 by Tom Zanussi <tzanussi@gmail.com>
51
52This library is free software; you can redistribute it and/or modify
53it under the same terms as Perl itself, either Perl version 5.10.0 or,
54at your option, any later version of Perl 5 you may have available.
55
56Alternatively, this software may be distributed under the terms of the
57GNU General Public License ("GPL") version 2 as published by the Free
58Software Foundation.
59
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
new file mode 100644
index 000000000000..6c7f3659cb17
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
@@ -0,0 +1,55 @@
1package Perf::Trace::Context;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17 common_pc common_flags common_lock_depth
18);
19
20our $VERSION = '0.01';
21
22require XSLoader;
23XSLoader::load('Perf::Trace::Context', $VERSION);
24
251;
26__END__
27=head1 NAME
28
29Perf::Trace::Context - Perl extension for accessing functions in perf.
30
31=head1 SYNOPSIS
32
33 use Perf::Trace::Context;
34
35=head1 SEE ALSO
36
37Perf (trace) documentation
38
39=head1 AUTHOR
40
41Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
42
43=head1 COPYRIGHT AND LICENSE
44
45Copyright (C) 2009 by Tom Zanussi
46
47This library is free software; you can redistribute it and/or modify
48it under the same terms as Perl itself, either Perl version 5.10.0 or,
49at your option, any later version of Perl 5 you may have available.
50
51Alternatively, this software may be distributed under the terms of the
52GNU General Public License ("GPL") version 2 as published by the Free
53Software Foundation.
54
55=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
new file mode 100644
index 000000000000..9df376a9f629
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
@@ -0,0 +1,192 @@
1package Perf::Trace::Core;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17define_flag_field define_flag_value flag_str dump_flag_fields
18define_symbolic_field define_symbolic_value symbol_str dump_symbolic_fields
19trace_flag_str
20);
21
22our $VERSION = '0.01';
23
24my %trace_flags = (0x00 => "NONE",
25 0x01 => "IRQS_OFF",
26 0x02 => "IRQS_NOSUPPORT",
27 0x04 => "NEED_RESCHED",
28 0x08 => "HARDIRQ",
29 0x10 => "SOFTIRQ");
30
31sub trace_flag_str
32{
33 my ($value) = @_;
34
35 my $string;
36
37 my $print_delim = 0;
38
39 foreach my $idx (sort {$a <=> $b} keys %trace_flags) {
40 if (!$value && !$idx) {
41 $string .= "NONE";
42 last;
43 }
44
45 if ($idx && ($value & $idx) == $idx) {
46 if ($print_delim) {
47 $string .= " | ";
48 }
49 $string .= "$trace_flags{$idx}";
50 $print_delim = 1;
51 $value &= ~$idx;
52 }
53 }
54
55 return $string;
56}
57
58my %flag_fields;
59my %symbolic_fields;
60
61sub flag_str
62{
63 my ($event_name, $field_name, $value) = @_;
64
65 my $string;
66
67 if ($flag_fields{$event_name}{$field_name}) {
68 my $print_delim = 0;
69 foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event_name}{$field_name}{"values"}}) {
70 if (!$value && !$idx) {
71 $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
72 last;
73 }
74 if ($idx && ($value & $idx) == $idx) {
75 if ($print_delim && $flag_fields{$event_name}{$field_name}{'delim'}) {
76 $string .= " $flag_fields{$event_name}{$field_name}{'delim'} ";
77 }
78 $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
79 $print_delim = 1;
80 $value &= ~$idx;
81 }
82 }
83 }
84
85 return $string;
86}
87
88sub define_flag_field
89{
90 my ($event_name, $field_name, $delim) = @_;
91
92 $flag_fields{$event_name}{$field_name}{"delim"} = $delim;
93}
94
95sub define_flag_value
96{
97 my ($event_name, $field_name, $value, $field_str) = @_;
98
99 $flag_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
100}
101
102sub dump_flag_fields
103{
104 for my $event (keys %flag_fields) {
105 print "event $event:\n";
106 for my $field (keys %{$flag_fields{$event}}) {
107 print " field: $field:\n";
108 print " delim: $flag_fields{$event}{$field}{'delim'}\n";
109 foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event}{$field}{"values"}}) {
110 print " value $idx: $flag_fields{$event}{$field}{'values'}{$idx}\n";
111 }
112 }
113 }
114}
115
116sub symbol_str
117{
118 my ($event_name, $field_name, $value) = @_;
119
120 if ($symbolic_fields{$event_name}{$field_name}) {
121 foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event_name}{$field_name}{"values"}}) {
122 if (!$value && !$idx) {
123 return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
124 last;
125 }
126 if ($value == $idx) {
127 return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
128 }
129 }
130 }
131
132 return undef;
133}
134
135sub define_symbolic_field
136{
137 my ($event_name, $field_name) = @_;
138
139 # nothing to do, really
140}
141
142sub define_symbolic_value
143{
144 my ($event_name, $field_name, $value, $field_str) = @_;
145
146 $symbolic_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
147}
148
149sub dump_symbolic_fields
150{
151 for my $event (keys %symbolic_fields) {
152 print "event $event:\n";
153 for my $field (keys %{$symbolic_fields{$event}}) {
154 print " field: $field:\n";
155 foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event}{$field}{"values"}}) {
156 print " value $idx: $symbolic_fields{$event}{$field}{'values'}{$idx}\n";
157 }
158 }
159 }
160}
161
1621;
163__END__
164=head1 NAME
165
166Perf::Trace::Core - Perl extension for perf trace
167
168=head1 SYNOPSIS
169
170 use Perf::Trace::Core
171
172=head1 SEE ALSO
173
174Perf (trace) documentation
175
176=head1 AUTHOR
177
178Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
179
180=head1 COPYRIGHT AND LICENSE
181
182Copyright (C) 2009 by Tom Zanussi
183
184This library is free software; you can redistribute it and/or modify
185it under the same terms as Perl itself, either Perl version 5.10.0 or,
186at your option, any later version of Perl 5 you may have available.
187
188Alternatively, this software may be distributed under the terms of the
189GNU General Public License ("GPL") version 2 as published by the Free
190Software Foundation.
191
192=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
new file mode 100644
index 000000000000..f869c48dc9b0
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
@@ -0,0 +1,88 @@
1package Perf::Trace::Util;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
18);
19
20our $VERSION = '0.01';
21
22sub avg
23{
24 my ($total, $n) = @_;
25
26 return $total / $n;
27}
28
29my $NSECS_PER_SEC = 1000000000;
30
31sub nsecs
32{
33 my ($secs, $nsecs) = @_;
34
35 return $secs * $NSECS_PER_SEC + $nsecs;
36}
37
38sub nsecs_secs {
39 my ($nsecs) = @_;
40
41 return $nsecs / $NSECS_PER_SEC;
42}
43
44sub nsecs_nsecs {
45 my ($nsecs) = @_;
46
47 return $nsecs % $NSECS_PER_SEC;
48}
49
50sub nsecs_str {
51 my ($nsecs) = @_;
52
53 my $str = sprintf("%5u.%09u", nsecs_secs($nsecs), nsecs_nsecs($nsecs));
54
55 return $str;
56}
57
581;
59__END__
60=head1 NAME
61
62Perf::Trace::Util - Perl extension for perf trace
63
64=head1 SYNOPSIS
65
66 use Perf::Trace::Util;
67
68=head1 SEE ALSO
69
70Perf (trace) documentation
71
72=head1 AUTHOR
73
74Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
75
76=head1 COPYRIGHT AND LICENSE
77
78Copyright (C) 2009 by Tom Zanussi
79
80This library is free software; you can redistribute it and/or modify
81it under the same terms as Perl itself, either Perl version 5.10.0 or,
82at your option, any later version of Perl 5 you may have available.
83
84Alternatively, this software may be distributed under the terms of the
85GNU General Public License ("GPL") version 2 as published by the Free
86Software Foundation.
87
88=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/typemap b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
new file mode 100644
index 000000000000..840836804aa7
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
@@ -0,0 +1 @@
struct scripting_context * T_PTR
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
new file mode 100644
index 000000000000..e6cb1474f8e8
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
new file mode 100644
index 000000000000..f8885d389e6f
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
new file mode 100644
index 000000000000..8bfc660e5056
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide failed syscalls
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $1
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
new file mode 100644
index 000000000000..b25056ebf963
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
new file mode 100644
index 000000000000..eddb9ccce6a5
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -0,0 +1,7 @@
1#!/bin/bash
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
5
6
7
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
new file mode 100644
index 000000000000..8903979c5b6c
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
new file mode 100644
index 000000000000..7f44c25cc857
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2# description: system-wide r/w activity
3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
new file mode 100644
index 000000000000..6abedda911a4
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -0,0 +1,6 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup
3
4
5
6
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
new file mode 100644
index 000000000000..fce3adcb3249
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency
3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
new file mode 100644
index 000000000000..fce6637b19ba
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
new file mode 100644
index 000000000000..71cfbd182fb9
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -0,0 +1,7 @@
1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
4
5
6
7
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
new file mode 100644
index 000000000000..4e7dc0a407a5
--- /dev/null
+++ b/tools/perf/scripts/perl/check-perf-trace.pl
@@ -0,0 +1,106 @@
1# perf trace event handlers, generated by perf trace -g perl
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, perl scripting support should be ok.
9
10use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
11use lib "./Perf-Trace-Util/lib";
12use Perf::Trace::Core;
13use Perf::Trace::Context;
14use Perf::Trace::Util;
15
16sub trace_begin
17{
18 print "trace_begin\n";
19}
20
21sub trace_end
22{
23 print "trace_end\n";
24
25 print_unhandled();
26}
27
28sub irq::softirq_entry
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $vec) = @_;
33
34 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
35 $common_pid, $common_comm);
36
37 print_uncommon($context);
38
39 printf("vec=%s\n",
40 symbol_str("irq::softirq_entry", "vec", $vec));
41}
42
43sub kmem::kmalloc
44{
45 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
46 $common_pid, $common_comm,
47 $call_site, $ptr, $bytes_req, $bytes_alloc,
48 $gfp_flags) = @_;
49
50 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
51 $common_pid, $common_comm);
52
53 print_uncommon($context);
54
55 printf("call_site=%p, ptr=%p, bytes_req=%u, bytes_alloc=%u, ".
56 "gfp_flags=%s\n",
57 $call_site, $ptr, $bytes_req, $bytes_alloc,
58
59 flag_str("kmem::kmalloc", "gfp_flags", $gfp_flags));
60}
61
62# print trace fields not included in handler args
63sub print_uncommon
64{
65 my ($context) = @_;
66
67 printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
68 common_pc($context), trace_flag_str(common_flags($context)),
69 common_lock_depth($context));
70
71}
72
73my %unhandled;
74
75sub print_unhandled
76{
77 if ((scalar keys %unhandled) == 0) {
78 return;
79 }
80
81 print "\nunhandled events:\n\n";
82
83 printf("%-40s %10s\n", "event", "count");
84 printf("%-40s %10s\n", "----------------------------------------",
85 "-----------");
86
87 foreach my $event_name (keys %unhandled) {
88 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
89 }
90}
91
92sub trace_unhandled
93{
94 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
95 $common_pid, $common_comm) = @_;
96
97 $unhandled{$event_name}++;
98}
99
100sub print_header
101{
102 my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
103
104 printf("%-20s %5u %05u.%09u %8u %-20s ",
105 $event_name, $cpu, $secs, $nsecs, $pid, $comm);
106}
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
new file mode 100644
index 000000000000..c18e7e27a84b
--- /dev/null
+++ b/tools/perf/scripts/perl/failed-syscalls.pl
@@ -0,0 +1,38 @@
1# failed system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
9use lib "./Perf-Trace-Util/lib";
10use Perf::Trace::Core;
11use Perf::Trace::Context;
12use Perf::Trace::Util;
13
14my %failed_syscalls;
15
16sub raw_syscalls::sys_exit
17{
18 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
19 $common_pid, $common_comm,
20 $id, $ret) = @_;
21
22 if ($ret < 0) {
23 $failed_syscalls{$common_comm}++;
24 }
25}
26
27sub trace_end
28{
29 printf("\nfailed syscalls by comm:\n\n");
30
31 printf("%-20s %10s\n", "comm", "# errors");
32 printf("%-20s %6s %10s\n", "--------------------", "----------");
33
34 foreach my $comm (sort {$failed_syscalls{$b} <=> $failed_syscalls{$a}}
35 keys %failed_syscalls) {
36 printf("%-20s %10s\n", $comm, $failed_syscalls{$comm});
37 }
38}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
new file mode 100644
index 000000000000..2a39097687b9
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -0,0 +1,106 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for files read/written to for a given program
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my $usage = "perf trace -s rw-by-file.pl <comm>\n";
22
23my $for_comm = shift or die $usage;
24
25my %reads;
26my %writes;
27
28sub syscalls::sys_enter_read
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
32
33 if ($common_comm eq $for_comm) {
34 $reads{$fd}{bytes_requested} += $count;
35 $reads{$fd}{total_reads}++;
36 }
37}
38
39sub syscalls::sys_enter_write
40{
41 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
42 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
43
44 if ($common_comm eq $for_comm) {
45 $writes{$fd}{bytes_written} += $count;
46 $writes{$fd}{total_writes}++;
47 }
48}
49
50sub trace_end
51{
52 printf("file read counts for $for_comm:\n\n");
53
54 printf("%6s %10s %10s\n", "fd", "# reads", "bytes_requested");
55 printf("%6s %10s %10s\n", "------", "----------", "-----------");
56
57 foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
58 $reads{$a}{bytes_requested}} keys %reads) {
59 my $total_reads = $reads{$fd}{total_reads};
60 my $bytes_requested = $reads{$fd}{bytes_requested};
61 printf("%6u %10u %10u\n", $fd, $total_reads, $bytes_requested);
62 }
63
64 printf("\nfile write counts for $for_comm:\n\n");
65
66 printf("%6s %10s %10s\n", "fd", "# writes", "bytes_written");
67 printf("%6s %10s %10s\n", "------", "----------", "-----------");
68
69 foreach my $fd (sort {$writes{$b}{bytes_written} <=>
70 $writes{$a}{bytes_written}} keys %writes) {
71 my $total_writes = $writes{$fd}{total_writes};
72 my $bytes_written = $writes{$fd}{bytes_written};
73 printf("%6u %10u %10u\n", $fd, $total_writes, $bytes_written);
74 }
75
76 print_unhandled();
77}
78
79my %unhandled;
80
81sub print_unhandled
82{
83 if ((scalar keys %unhandled) == 0) {
84 return;
85 }
86
87 print "\nunhandled events:\n\n";
88
89 printf("%-40s %10s\n", "event", "count");
90 printf("%-40s %10s\n", "----------------------------------------",
91 "-----------");
92
93 foreach my $event_name (keys %unhandled) {
94 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
95 }
96}
97
98sub trace_unhandled
99{
100 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
101 $common_pid, $common_comm) = @_;
102
103 $unhandled{$event_name}++;
104}
105
106
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
new file mode 100644
index 000000000000..da601fae1a00
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-pid.pl
@@ -0,0 +1,170 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for all processes
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %reads;
22my %writes;
23
24sub syscalls::sys_exit_read
25{
26 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
27 $common_pid, $common_comm,
28 $nr, $ret) = @_;
29
30 if ($ret > 0) {
31 $reads{$common_pid}{bytes_read} += $ret;
32 } else {
33 if (!defined ($reads{$common_pid}{bytes_read})) {
34 $reads{$common_pid}{bytes_read} = 0;
35 }
36 $reads{$common_pid}{errors}{$ret}++;
37 }
38}
39
40sub syscalls::sys_enter_read
41{
42 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
43 $common_pid, $common_comm,
44 $nr, $fd, $buf, $count) = @_;
45
46 $reads{$common_pid}{bytes_requested} += $count;
47 $reads{$common_pid}{total_reads}++;
48 $reads{$common_pid}{comm} = $common_comm;
49}
50
51sub syscalls::sys_exit_write
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $nr, $ret) = @_;
56
57 if ($ret <= 0) {
58 $writes{$common_pid}{errors}{$ret}++;
59 }
60}
61
62sub syscalls::sys_enter_write
63{
64 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
65 $common_pid, $common_comm,
66 $nr, $fd, $buf, $count) = @_;
67
68 $writes{$common_pid}{bytes_written} += $count;
69 $writes{$common_pid}{total_writes}++;
70 $writes{$common_pid}{comm} = $common_comm;
71}
72
73sub trace_end
74{
75 printf("read counts by pid:\n\n");
76
77 printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
78 "# reads", "bytes_requested", "bytes_read");
79 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
80 "-----------", "----------", "----------");
81
82 foreach my $pid (sort {$reads{$b}{bytes_read} <=>
83 $reads{$a}{bytes_read}} keys %reads) {
84 my $comm = $reads{$pid}{comm};
85 my $total_reads = $reads{$pid}{total_reads};
86 my $bytes_requested = $reads{$pid}{bytes_requested};
87 my $bytes_read = $reads{$pid}{bytes_read};
88
89 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
90 $total_reads, $bytes_requested, $bytes_read);
91 }
92
93 printf("\nfailed reads by pid:\n\n");
94
95 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
96 printf("%6s %20s %6s %10s\n", "------", "--------------------",
97 "------", "----------");
98
99 foreach my $pid (keys %reads) {
100 my $comm = $reads{$pid}{comm};
101 foreach my $err (sort {$reads{$b}{comm} cmp $reads{$a}{comm}}
102 keys %{$reads{$pid}{errors}}) {
103 my $errors = $reads{$pid}{errors}{$err};
104
105 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
106 }
107 }
108
109 printf("\nwrite counts by pid:\n\n");
110
111 printf("%6s %20s %10s %10s\n", "pid", "comm",
112 "# writes", "bytes_written");
113 printf("%6s %-20s %10s %10s\n", "------", "--------------------",
114 "-----------", "----------");
115
116 foreach my $pid (sort {$writes{$b}{bytes_written} <=>
117 $writes{$a}{bytes_written}} keys %writes) {
118 my $comm = $writes{$pid}{comm};
119 my $total_writes = $writes{$pid}{total_writes};
120 my $bytes_written = $writes{$pid}{bytes_written};
121
122 printf("%6s %-20s %10s %10s\n", $pid, $comm,
123 $total_writes, $bytes_written);
124 }
125
126 printf("\nfailed writes by pid:\n\n");
127
128 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
129 printf("%6s %20s %6s %10s\n", "------", "--------------------",
130 "------", "----------");
131
132 foreach my $pid (keys %writes) {
133 my $comm = $writes{$pid}{comm};
134 foreach my $err (sort {$writes{$b}{comm} cmp $writes{$a}{comm}}
135 keys %{$writes{$pid}{errors}}) {
136 my $errors = $writes{$pid}{errors}{$err};
137
138 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
139 }
140 }
141
142 print_unhandled();
143}
144
145my %unhandled;
146
147sub print_unhandled
148{
149 if ((scalar keys %unhandled) == 0) {
150 return;
151 }
152
153 print "\nunhandled events:\n\n";
154
155 printf("%-40s %10s\n", "event", "count");
156 printf("%-40s %10s\n", "----------------------------------------",
157 "-----------");
158
159 foreach my $event_name (keys %unhandled) {
160 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
161 }
162}
163
164sub trace_unhandled
165{
166 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
167 $common_pid, $common_comm) = @_;
168
169 $unhandled{$event_name}++;
170}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
new file mode 100644
index 000000000000..ed58ef284e23
--- /dev/null
+++ b/tools/perf/scripts/perl/wakeup-latency.pl
@@ -0,0 +1,103 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display avg/min/max wakeup latency
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %last_wakeup;
22
23my $max_wakeup_latency;
24my $min_wakeup_latency;
25my $total_wakeup_latency;
26my $total_wakeups;
27
28sub sched::sched_switch
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
33 $next_prio) = @_;
34
35 my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
36 if ($wakeup_ts) {
37 my $switch_ts = nsecs($common_secs, $common_nsecs);
38 my $wakeup_latency = $switch_ts - $wakeup_ts;
39 if ($wakeup_latency > $max_wakeup_latency) {
40 $max_wakeup_latency = $wakeup_latency;
41 }
42 if ($wakeup_latency < $min_wakeup_latency) {
43 $min_wakeup_latency = $wakeup_latency;
44 }
45 $total_wakeup_latency += $wakeup_latency;
46 $total_wakeups++;
47 }
48 $last_wakeup{$common_cpu}{ts} = 0;
49}
50
51sub sched::sched_wakeup
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $comm, $pid, $prio, $success, $target_cpu) = @_;
56
57 $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
58}
59
60sub trace_begin
61{
62 $min_wakeup_latency = 1000000000;
63 $max_wakeup_latency = 0;
64}
65
66sub trace_end
67{
68 printf("wakeup_latency stats:\n\n");
69 print "total_wakeups: $total_wakeups\n";
70 printf("avg_wakeup_latency (ns): %u\n",
71 avg($total_wakeup_latency, $total_wakeups));
72 printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
73 printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
74
75 print_unhandled();
76}
77
78my %unhandled;
79
80sub print_unhandled
81{
82 if ((scalar keys %unhandled) == 0) {
83 return;
84 }
85
86 print "\nunhandled events:\n\n";
87
88 printf("%-40s %10s\n", "event", "count");
89 printf("%-40s %10s\n", "----------------------------------------",
90 "-----------");
91
92 foreach my $event_name (keys %unhandled) {
93 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
94 }
95}
96
97sub trace_unhandled
98{
99 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
100 $common_pid, $common_comm) = @_;
101
102 $unhandled{$event_name}++;
103}
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
new file mode 100644
index 000000000000..511302c8a494
--- /dev/null
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -0,0 +1,129 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'};
75 my $exe = $$wqhash{'executed'};
76 my $comm = $$wqhash{'comm'};
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'};
91 my $destroyed = $$wqhash{'destroyed'};
92 my $comm = $$wqhash{'comm'};
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
new file mode 100644
index 000000000000..957085dd5d8d
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -0,0 +1,88 @@
1/*
2 * Context.c. Python interfaces for perf trace.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23#include "../../../perf.h"
24#include "../../../util/trace-event.h"
25
26PyMODINIT_FUNC initperf_trace_context(void);
27
28static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
29{
30 static struct scripting_context *scripting_context;
31 PyObject *context;
32 int retval;
33
34 if (!PyArg_ParseTuple(args, "O", &context))
35 return NULL;
36
37 scripting_context = PyCObject_AsVoidPtr(context);
38 retval = common_pc(scripting_context);
39
40 return Py_BuildValue("i", retval);
41}
42
43static PyObject *perf_trace_context_common_flags(PyObject *self,
44 PyObject *args)
45{
46 static struct scripting_context *scripting_context;
47 PyObject *context;
48 int retval;
49
50 if (!PyArg_ParseTuple(args, "O", &context))
51 return NULL;
52
53 scripting_context = PyCObject_AsVoidPtr(context);
54 retval = common_flags(scripting_context);
55
56 return Py_BuildValue("i", retval);
57}
58
59static PyObject *perf_trace_context_common_lock_depth(PyObject *self,
60 PyObject *args)
61{
62 static struct scripting_context *scripting_context;
63 PyObject *context;
64 int retval;
65
66 if (!PyArg_ParseTuple(args, "O", &context))
67 return NULL;
68
69 scripting_context = PyCObject_AsVoidPtr(context);
70 retval = common_lock_depth(scripting_context);
71
72 return Py_BuildValue("i", retval);
73}
74
75static PyMethodDef ContextMethods[] = {
76 { "common_pc", perf_trace_context_common_pc, METH_VARARGS,
77 "Get the common preempt count event field value."},
78 { "common_flags", perf_trace_context_common_flags, METH_VARARGS,
79 "Get the common flags event field value."},
80 { "common_lock_depth", perf_trace_context_common_lock_depth,
81 METH_VARARGS, "Get the common lock depth event field value."},
82 { NULL, NULL, 0, NULL}
83};
84
85PyMODINIT_FUNC initperf_trace_context(void)
86{
87 (void) Py_InitModule("perf_trace_context", ContextMethods);
88}
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
new file mode 100644
index 000000000000..1dc464ee2ca8
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -0,0 +1,91 @@
1# Core.py - Python extension for perf trace, core functions
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9from collections import defaultdict
10
11def autodict():
12 return defaultdict(autodict)
13
14flag_fields = autodict()
15symbolic_fields = autodict()
16
17def define_flag_field(event_name, field_name, delim):
18 flag_fields[event_name][field_name]['delim'] = delim
19
20def define_flag_value(event_name, field_name, value, field_str):
21 flag_fields[event_name][field_name]['values'][value] = field_str
22
23def define_symbolic_field(event_name, field_name):
24 # nothing to do, really
25 pass
26
27def define_symbolic_value(event_name, field_name, value, field_str):
28 symbolic_fields[event_name][field_name]['values'][value] = field_str
29
30def flag_str(event_name, field_name, value):
31 string = ""
32
33 if flag_fields[event_name][field_name]:
34 print_delim = 0
35 keys = flag_fields[event_name][field_name]['values'].keys()
36 keys.sort()
37 for idx in keys:
38 if not value and not idx:
39 string += flag_fields[event_name][field_name]['values'][idx]
40 break
41 if idx and (value & idx) == idx:
42 if print_delim and flag_fields[event_name][field_name]['delim']:
43 string += " " + flag_fields[event_name][field_name]['delim'] + " "
44 string += flag_fields[event_name][field_name]['values'][idx]
45 print_delim = 1
46 value &= ~idx
47
48 return string
49
50def symbol_str(event_name, field_name, value):
51 string = ""
52
53 if symbolic_fields[event_name][field_name]:
54 keys = symbolic_fields[event_name][field_name]['values'].keys()
55 keys.sort()
56 for idx in keys:
57 if not value and not idx:
58 string = symbolic_fields[event_name][field_name]['values'][idx]
59 break
60 if (value == idx):
61 string = symbolic_fields[event_name][field_name]['values'][idx]
62 break
63
64 return string
65
66trace_flags = { 0x00: "NONE", \
67 0x01: "IRQS_OFF", \
68 0x02: "IRQS_NOSUPPORT", \
69 0x04: "NEED_RESCHED", \
70 0x08: "HARDIRQ", \
71 0x10: "SOFTIRQ" }
72
73def trace_flag_str(value):
74 string = ""
75 print_delim = 0
76
77 keys = trace_flags.keys()
78
79 for idx in keys:
80 if not value and not idx:
81 string += "NONE"
82 break
83
84 if idx and (value & idx) == idx:
85 if print_delim:
86 string += " | ";
87 string += trace_flags[idx]
88 print_delim = 1
89 value &= ~idx
90
91 return string
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
new file mode 100644
index 000000000000..83e91435ed09
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -0,0 +1,25 @@
1# Util.py - Python extension for perf trace, miscellaneous utility code
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9NSECS_PER_SEC = 1000000000
10
11def avg(total, n):
12 return total / n
13
14def nsecs(secs, nsecs):
15 return secs * NSECS_PER_SEC + nsecs
16
17def nsecs_secs(nsecs):
18 return nsecs / NSECS_PER_SEC
19
20def nsecs_nsecs(nsecs):
21 return nsecs % NSECS_PER_SEC
22
23def nsecs_str(nsecs):
24 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
25 return str
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
new file mode 100644
index 000000000000..f8885d389e6f
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e raw_syscalls:sys_exit
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
new file mode 100644
index 000000000000..1e0c0a860c87
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide failed syscalls, by pid
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $1
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
new file mode 100644
index 000000000000..45a8c50359da
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
new file mode 100644
index 000000000000..f8044d192271
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide syscall counts, by pid
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $1
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
new file mode 100644
index 000000000000..45a8c50359da
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e raw_syscalls:sys_enter
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report
new file mode 100644
index 000000000000..a366aa61612f
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: system-wide syscall counts
3# args: [comm]
4perf trace -s ~/libexec/perf-core/scripts/python/syscall-counts.py $1
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
new file mode 100644
index 000000000000..964d934395ff
--- /dev/null
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -0,0 +1,83 @@
1# perf trace event handlers, generated by perf trace -g python
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, Python scripting support should be ok.
9
10import os
11import sys
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from Core import *
17from perf_trace_context import *
18
19unhandled = autodict()
20
21def trace_begin():
22 print "trace_begin"
23 pass
24
25def trace_end():
26 print_unhandled()
27
28def irq__softirq_entry(event_name, context, common_cpu,
29 common_secs, common_nsecs, common_pid, common_comm,
30 vec):
31 print_header(event_name, common_cpu, common_secs, common_nsecs,
32 common_pid, common_comm)
33
34 print_uncommon(context)
35
36 print "vec=%s\n" % \
37 (symbol_str("irq__softirq_entry", "vec", vec)),
38
39def kmem__kmalloc(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm,
41 call_site, ptr, bytes_req, bytes_alloc,
42 gfp_flags):
43 print_header(event_name, common_cpu, common_secs, common_nsecs,
44 common_pid, common_comm)
45
46 print_uncommon(context)
47
48 print "call_site=%u, ptr=%u, bytes_req=%u, " \
49 "bytes_alloc=%u, gfp_flags=%s\n" % \
50 (call_site, ptr, bytes_req, bytes_alloc,
51
52 flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)),
53
54def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
55 common_pid, common_comm):
56 try:
57 unhandled[event_name] += 1
58 except TypeError:
59 unhandled[event_name] = 1
60
61def print_header(event_name, cpu, secs, nsecs, pid, comm):
62 print "%-20s %5u %05u.%09u %8u %-20s " % \
63 (event_name, cpu, secs, nsecs, pid, comm),
64
65# print trace fields not included in handler args
66def print_uncommon(context):
67 print "common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, " \
68 % (common_pc(context), trace_flag_str(common_flags(context)), \
69 common_lock_depth(context))
70
71def print_unhandled():
72 keys = unhandled.keys()
73 if not keys:
74 return
75
76 print "\nunhandled events:\n\n",
77
78 print "%-40s %10s\n" % ("event", "count"),
79 print "%-40s %10s\n" % ("----------------------------------------", \
80 "-----------"),
81
82 for event_name in keys:
83 print "%-40s %10d\n" % (event_name, unhandled[event_name])
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
new file mode 100644
index 000000000000..0ca02278fe69
--- /dev/null
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -0,0 +1,68 @@
1# failed system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals, broken down by pid.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_error_totals()
34
35def raw_syscalls__sys_exit(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, ret):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41
42 if ret < 0:
43 try:
44 syscalls[common_comm][common_pid][id][ret] += 1
45 except TypeError:
46 syscalls[common_comm][common_pid][id][ret] = 1
47
48def print_error_totals():
49 if for_comm is not None:
50 print "\nsyscall errors for %s:\n\n" % (for_comm),
51 else:
52 print "\nsyscall errors:\n\n",
53
54 print "%-30s %10s\n" % ("comm [pid]", "count"),
55 print "%-30s %10s\n" % ("------------------------------", \
56 "----------"),
57
58 comm_keys = syscalls.keys()
59 for comm in comm_keys:
60 pid_keys = syscalls[comm].keys()
61 for pid in pid_keys:
62 print "\n%s [%d]\n" % (comm, pid),
63 id_keys = syscalls[comm][pid].keys()
64 for id in id_keys:
65 print " syscall: %-16d\n" % (id),
66 ret_keys = syscalls[comm][pid][id].keys()
67 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
68 print " err = %-20d %10d\n" % (ret, val),
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
new file mode 100644
index 000000000000..af722d6a4b3f
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -0,0 +1,64 @@
1# system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[common_comm][common_pid][id] += 1
43 except TypeError:
44 syscalls[common_comm][common_pid][id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events by comm/pid:\n\n",
51
52 print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "----------"),
55
56 comm_keys = syscalls.keys()
57 for comm in comm_keys:
58 pid_keys = syscalls[comm].keys()
59 for pid in pid_keys:
60 print "\n%s [%d]\n" % (comm, pid),
61 id_keys = syscalls[comm][pid].keys()
62 for id, val in sorted(syscalls[comm][pid].iteritems(), \
63 key = lambda(k, v): (v, k), reverse = True):
64 print " %-38d %10d\n" % (id, val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
new file mode 100644
index 000000000000..f977e85ff049
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -0,0 +1,58 @@
1# system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16
17usage = "perf trace -s syscall-counts.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[id] += 1
43 except TypeError:
44 syscalls[id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events:\n\n",
51
52 print "%-40s %10s\n" % ("event", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "-----------"),
55
56 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
57 reverse = True):
58 print "%-40d %10d\n" % (id, val),
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..04904b35ba81
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,39 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "build-id.h"
10#include "event.h"
11#include "symbol.h"
12#include <linux/kernel.h>
13
14static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
15{
16 struct addr_location al;
17 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
18 struct thread *thread = perf_session__findnew(session, event->ip.pid);
19
20 if (thread == NULL) {
21 pr_err("problem processing %d event, skipping it.\n",
22 event->header.type);
23 return -1;
24 }
25
26 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
27 event->ip.ip, &al);
28
29 if (al.map != NULL)
30 al.map->dso->hit = 1;
31
32 return 0;
33}
34
35struct perf_event_ops build_id__mark_dso_hit_ops = {
36 .sample = build_id__mark_dso_hit,
37 .mmap = event__process_mmap,
38 .fork = event__process_task,
39};
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..1d981d63cf9a
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,8 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,10 +1,15 @@
1#ifndef CACHE_H 1#ifndef __PERF_CACHE_H
2#define CACHE_H 2#define __PERF_CACHE_H
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h" 6#include "../perf.h"
7 7
8#define CMD_EXEC_PATH "--exec-path"
9#define CMD_PERF_DIR "--perf-dir="
10#define CMD_WORK_TREE "--work-tree="
11#define CMD_DEBUGFS_DIR "--debugfs-dir="
12
8#define PERF_DIR_ENVIRONMENT "PERF_DIR" 13#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
117 122
118extern size_t strlcpy(char *dest, const char *src, size_t size); 123extern size_t strlcpy(char *dest, const char *src, size_t size);
119 124
120#endif /* CACHE_H */ 125#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
206 } 206 }
207 node->val_nr = chain->nr - start; 207 node->val_nr = chain->nr - start;
208 if (!node->val_nr) 208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n"); 209 pr_warning("Warning: empty node in callchain tree\n");
210} 210}
211 211
212static void 212static void
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
1#ifndef COLOR_H 1#ifndef __PERF_COLOR_H
2#define COLOR_H 2#define __PERF_COLOR_H
3 3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 5#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
41 41
42#endif /* COLOR_H */ 42#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 0b791bd346bc..35073621e5de 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -29,3 +29,11 @@ unsigned char sane_ctype[256] = {
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ 29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */ 30 /* Nothing in the 128.. range */
31}; 31};
32
33const char *graph_line =
34 "_____________________________________________________________________"
35 "_____________________________________________________________________";
36const char *graph_dotted_line =
37 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------";
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,16 +9,17 @@
9#include "color.h" 9#include "color.h"
10#include "event.h" 10#include "event.h"
11#include "debug.h" 11#include "debug.h"
12#include "util.h"
12 13
13int verbose = 0; 14int verbose = 0;
14int dump_trace = 0; 15int dump_trace = 0;
15 16
16int eprintf(const char *fmt, ...) 17int eprintf(int level, const char *fmt, ...)
17{ 18{
18 va_list args; 19 va_list args;
19 int ret = 0; 20 int ret = 0;
20 21
21 if (verbose) { 22 if (verbose >= level) {
22 va_start(args, fmt); 23 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 24 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 25 va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 437eea58ce40..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,8 +1,15 @@
1/* For debugging general purposes */ 1/* For debugging general purposes */
2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H
4
5#include "event.h"
2 6
3extern int verbose; 7extern int verbose;
4extern int dump_trace; 8extern int dump_trace;
5 9
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event); 13void trace_event(event_t *event);
14
15#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..a88fefc0cc0a
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,240 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1];
7
8static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/",
10 "/debug/",
11 0,
12};
13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
40static int debugfs_found;
41
42/* find the path to the mounted debugfs */
43const char *debugfs_find_mountpoint(void)
44{
45 const char **ptr;
46 char type[100];
47 FILE *fp;
48
49 if (debugfs_found)
50 return (const char *) debugfs_mountpoint;
51
52 ptr = debugfs_known_mountpoints;
53 while (*ptr) {
54 if (debugfs_valid_mountpoint(*ptr) == 0) {
55 debugfs_found = 1;
56 strcpy(debugfs_mountpoint, *ptr);
57 return debugfs_mountpoint;
58 }
59 ptr++;
60 }
61
62 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL)
65 die("Can't open /proc/mounts for read");
66
67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0)
72 break;
73 }
74 fclose(fp);
75
76 if (strcmp(type, "debugfs") != 0)
77 return NULL;
78
79 debugfs_found = 1;
80
81 return debugfs_mountpoint;
82}
83
84/* verify that a mountpoint is actually a debugfs instance */
85
86int debugfs_valid_mountpoint(const char *debugfs)
87{
88 struct statfs st_fs;
89
90 if (statfs(debugfs, &st_fs) < 0)
91 return -ENOENT;
92 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
93 return -ENOENT;
94
95 return 0;
96}
97
98
99int debugfs_valid_entry(const char *path)
100{
101 struct stat st;
102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
107}
108
109/* mount the debugfs somewhere if it's not mounted */
110
111char *debugfs_mount(const char *mountpoint)
112{
113 /* see if it's already mounted */
114 if (debugfs_find_mountpoint()) {
115 debugfs_premounted = 1;
116 return debugfs_mountpoint;
117 }
118
119 /* if not mounted and no argument */
120 if (mountpoint == NULL) {
121 /* see if environment variable set */
122 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
123 /* if no environment variable, use default */
124 if (mountpoint == NULL)
125 mountpoint = "/sys/kernel/debug";
126 }
127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
131 /* save the mountpoint */
132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
134
135 return debugfs_mountpoint;
136}
137
138/* umount the debugfs */
139
140int debugfs_umount(void)
141{
142 char umountcmd[128];
143 int ret;
144
145 /* if it was already mounted, leave it */
146 if (debugfs_premounted)
147 return 0;
148
149 /* make sure it's a valid mount point */
150 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
151 if (ret)
152 return ret;
153
154 snprintf(umountcmd, sizeof(umountcmd),
155 "/bin/umount %s", debugfs_mountpoint);
156 return system(umountcmd);
157}
158
159int debugfs_write(const char *entry, const char *value)
160{
161 char path[MAX_PATH+1];
162 int ret, count;
163 int fd;
164
165 /* construct the path */
166 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
167
168 /* verify that it exists */
169 ret = debugfs_valid_entry(path);
170 if (ret)
171 return ret;
172
173 /* get how many chars we're going to write */
174 count = strlen(value);
175
176 /* open the debugfs entry */
177 fd = open(path, O_RDWR);
178 if (fd < 0)
179 return -errno;
180
181 while (count > 0) {
182 /* write it */
183 ret = write(fd, value, count);
184 if (ret <= 0) {
185 if (ret == EAGAIN)
186 continue;
187 close(fd);
188 return -errno;
189 }
190 count -= ret;
191 }
192
193 /* close it */
194 close(fd);
195
196 /* return success */
197 return 0;
198}
199
200/*
201 * read a debugfs entry
202 * returns the number of chars read or a negative errno
203 */
204int debugfs_read(const char *entry, char *buffer, size_t size)
205{
206 char path[MAX_PATH+1];
207 int ret;
208 int fd;
209
210 /* construct the path */
211 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
212
213 /* verify that it exists */
214 ret = debugfs_valid_entry(path);
215 if (ret)
216 return ret;
217
218 /* open the debugfs entry */
219 fd = open(path, O_RDONLY);
220 if (fd < 0)
221 return -errno;
222
223 do {
224 /* read it */
225 ret = read(fd, buffer, size);
226 if (ret == 0) {
227 close(fd);
228 return EOF;
229 }
230 } while (ret < 0 && errno == EAGAIN);
231
232 /* close it */
233 close(fd);
234
235 /* make *sure* there's a null character at the end */
236 buffer[ret] = '\0';
237
238 /* return the number of chars read */
239 return ret;
240}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..83a02879745f
--- /dev/null
+++ b/tools/perf/util/debugfs.h
@@ -0,0 +1,25 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4#include <sys/mount.h>
5
6#ifndef MAX_PATH
7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24
25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..705ec63548b4
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,612 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "session.h"
5#include "sort.h"
6#include "string.h"
7#include "strlist.h"
8#include "thread.h"
9
10static pid_t event__synthesize_comm(pid_t pid, int full,
11 event__handler_t process,
12 struct perf_session *session)
13{
14 event_t ev;
15 char filename[PATH_MAX];
16 char bf[BUFSIZ];
17 FILE *fp;
18 size_t size = 0;
19 DIR *tasks;
20 struct dirent dirent, *next;
21 pid_t tgid = 0;
22
23 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
24
25 fp = fopen(filename, "r");
26 if (fp == NULL) {
27out_race:
28 /*
29 * We raced with a task exiting - just return:
30 */
31 pr_debug("couldn't open %s\n", filename);
32 return 0;
33 }
34
35 memset(&ev.comm, 0, sizeof(ev.comm));
36 while (!ev.comm.comm[0] || !ev.comm.pid) {
37 if (fgets(bf, sizeof(bf), fp) == NULL)
38 goto out_failure;
39
40 if (memcmp(bf, "Name:", 5) == 0) {
41 char *name = bf + 5;
42 while (*name && isspace(*name))
43 ++name;
44 size = strlen(name) - 1;
45 memcpy(ev.comm.comm, name, size++);
46 } else if (memcmp(bf, "Tgid:", 5) == 0) {
47 char *tgids = bf + 5;
48 while (*tgids && isspace(*tgids))
49 ++tgids;
50 tgid = ev.comm.pid = atoi(tgids);
51 }
52 }
53
54 ev.comm.header.type = PERF_RECORD_COMM;
55 size = ALIGN(size, sizeof(u64));
56 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
57
58 if (!full) {
59 ev.comm.tid = pid;
60
61 process(&ev, session);
62 goto out_fclose;
63 }
64
65 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
66
67 tasks = opendir(filename);
68 if (tasks == NULL)
69 goto out_race;
70
71 while (!readdir_r(tasks, &dirent, &next) && next) {
72 char *end;
73 pid = strtol(dirent.d_name, &end, 10);
74 if (*end)
75 continue;
76
77 ev.comm.tid = pid;
78
79 process(&ev, session);
80 }
81 closedir(tasks);
82
83out_fclose:
84 fclose(fp);
85 return tgid;
86
87out_failure:
88 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
89 return -1;
90}
91
92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
93 event__handler_t process,
94 struct perf_session *session)
95{
96 char filename[PATH_MAX];
97 FILE *fp;
98
99 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
100
101 fp = fopen(filename, "r");
102 if (fp == NULL) {
103 /*
104 * We raced with a task exiting - just return:
105 */
106 pr_debug("couldn't open %s\n", filename);
107 return -1;
108 }
109
110 while (1) {
111 char bf[BUFSIZ], *pbf = bf;
112 event_t ev = {
113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
117 };
118 int n;
119 size_t size;
120 if (fgets(bf, sizeof(bf), fp) == NULL)
121 break;
122
123 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
124 n = hex2u64(pbf, &ev.mmap.start);
125 if (n < 0)
126 continue;
127 pbf += n + 1;
128 n = hex2u64(pbf, &ev.mmap.len);
129 if (n < 0)
130 continue;
131 pbf += n + 3;
132 if (*pbf == 'x') { /* vm_exec */
133 char *execname = strchr(bf, '/');
134
135 /* Catch VDSO */
136 if (execname == NULL)
137 execname = strstr(bf, "[vdso]");
138
139 if (execname == NULL)
140 continue;
141
142 size = strlen(execname);
143 execname[size - 1] = '\0'; /* Remove \n */
144 memcpy(ev.mmap.filename, execname, size);
145 size = ALIGN(size, sizeof(u64));
146 ev.mmap.len -= ev.mmap.start;
147 ev.mmap.header.size = (sizeof(ev.mmap) -
148 (sizeof(ev.mmap.filename) - size));
149 ev.mmap.pid = tgid;
150 ev.mmap.tid = pid;
151
152 process(&ev, session);
153 }
154 }
155
156 fclose(fp);
157 return 0;
158}
159
160int event__synthesize_modules(event__handler_t process,
161 struct perf_session *session)
162{
163 struct rb_node *nd;
164
165 for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
166 nd; nd = rb_next(nd)) {
167 event_t ev;
168 size_t size;
169 struct map *pos = rb_entry(nd, struct map, rb_node);
170
171 if (pos->dso->kernel)
172 continue;
173
174 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
175 memset(&ev, 0, sizeof(ev));
176 ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
177 ev.mmap.header.type = PERF_RECORD_MMAP;
178 ev.mmap.header.size = (sizeof(ev.mmap) -
179 (sizeof(ev.mmap.filename) - size));
180 ev.mmap.start = pos->start;
181 ev.mmap.len = pos->end - pos->start;
182
183 memcpy(ev.mmap.filename, pos->dso->long_name,
184 pos->dso->long_name_len + 1);
185 process(&ev, session);
186 }
187
188 return 0;
189}
190
191int event__synthesize_thread(pid_t pid, event__handler_t process,
192 struct perf_session *session)
193{
194 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
195 if (tgid == -1)
196 return -1;
197 return event__synthesize_mmap_events(pid, tgid, process, session);
198}
199
200void event__synthesize_threads(event__handler_t process,
201 struct perf_session *session)
202{
203 DIR *proc;
204 struct dirent dirent, *next;
205
206 proc = opendir("/proc");
207
208 while (!readdir_r(proc, &dirent, &next) && next) {
209 char *end;
210 pid_t pid = strtol(dirent.d_name, &end, 10);
211
212 if (*end) /* only interested in proper numerical dirents */
213 continue;
214
215 event__synthesize_thread(pid, process, session);
216 }
217
218 closedir(proc);
219}
220
221struct process_symbol_args {
222 const char *name;
223 u64 start;
224};
225
226static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
227{
228 struct process_symbol_args *args = arg;
229
230 /*
231 * Must be a function or at least an alias, as in PARISC64, where "_text" is
232 * an 'A' to the same address as "_stext".
233 */
234 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
235 type == 'A') || strcmp(name, args->name))
236 return 0;
237
238 args->start = start;
239 return 1;
240}
241
242int event__synthesize_kernel_mmap(event__handler_t process,
243 struct perf_session *session,
244 const char *symbol_name)
245{
246 size_t size;
247 event_t ev = {
248 .header = {
249 .type = PERF_RECORD_MMAP,
250 .misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
251 },
252 };
253 /*
254 * We should get this from /sys/kernel/sections/.text, but till that is
255 * available use this, and after it is use this as a fallback for older
256 * kernels.
257 */
258 struct process_symbol_args args = { .name = symbol_name, };
259
260 if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
261 return -ENOENT;
262
263 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
264 "[kernel.kallsyms.%s]", symbol_name) + 1;
265 size = ALIGN(size, sizeof(u64));
266 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
267 ev.mmap.pgoff = args.start;
268 ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
269 ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
270
271 return process(&ev, session);
272}
273
274static void thread__comm_adjust(struct thread *self)
275{
276 char *comm = self->comm;
277
278 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
279 (!symbol_conf.comm_list ||
280 strlist__has_entry(symbol_conf.comm_list, comm))) {
281 unsigned int slen = strlen(comm);
282
283 if (slen > comms__col_width) {
284 comms__col_width = slen;
285 threads__col_width = slen + 6;
286 }
287 }
288}
289
290static int thread__set_comm_adjust(struct thread *self, const char *comm)
291{
292 int ret = thread__set_comm(self, comm);
293
294 if (ret)
295 return ret;
296
297 thread__comm_adjust(self);
298
299 return 0;
300}
301
302int event__process_comm(event_t *self, struct perf_session *session)
303{
304 struct thread *thread = perf_session__findnew(session, self->comm.pid);
305
306 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
307
308 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
309 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
310 return -1;
311 }
312
313 return 0;
314}
315
316int event__process_lost(event_t *self, struct perf_session *session)
317{
318 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
319 session->events_stats.lost += self->lost.lost;
320 return 0;
321}
322
323int event__process_mmap(event_t *self, struct perf_session *session)
324{
325 struct thread *thread;
326 struct map *map;
327
328 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
329 self->mmap.pid, self->mmap.tid, self->mmap.start,
330 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
331
332 if (self->mmap.pid == 0) {
333 static const char kmmap_prefix[] = "[kernel.kallsyms.";
334
335 if (self->mmap.filename[0] == '/') {
336 char short_module_name[1024];
337 char *name = strrchr(self->mmap.filename, '/'), *dot;
338
339 if (name == NULL)
340 goto out_problem;
341
342 ++name; /* skip / */
343 dot = strrchr(name, '.');
344 if (dot == NULL)
345 goto out_problem;
346
347 snprintf(short_module_name, sizeof(short_module_name),
348 "[%.*s]", (int)(dot - name), name);
349 strxfrchar(short_module_name, '-', '_');
350
351 map = perf_session__new_module_map(session,
352 self->mmap.start,
353 self->mmap.filename);
354 if (map == NULL)
355 goto out_problem;
356
357 name = strdup(short_module_name);
358 if (name == NULL)
359 goto out_problem;
360
361 map->dso->short_name = name;
362 map->end = map->start + self->mmap.len;
363 } else if (memcmp(self->mmap.filename, kmmap_prefix,
364 sizeof(kmmap_prefix) - 1) == 0) {
365 const char *symbol_name = (self->mmap.filename +
366 sizeof(kmmap_prefix) - 1);
367 /*
368 * Should be there already, from the build-id table in
369 * the header.
370 */
371 struct dso *kernel = __dsos__findnew(&dsos__kernel,
372 "[kernel.kallsyms]");
373 if (kernel == NULL)
374 goto out_problem;
375
376 kernel->kernel = 1;
377 if (__perf_session__create_kernel_maps(session, kernel) < 0)
378 goto out_problem;
379
380 session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
381 session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
382 /*
383 * Be a bit paranoid here, some perf.data file came with
384 * a zero sized synthesized MMAP event for the kernel.
385 */
386 if (session->vmlinux_maps[MAP__FUNCTION]->end == 0)
387 session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
388
389 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
390 self->mmap.pgoff);
391 }
392 return 0;
393 }
394
395 thread = perf_session__findnew(session, self->mmap.pid);
396 map = map__new(&self->mmap, MAP__FUNCTION,
397 session->cwd, session->cwdlen);
398
399 if (thread == NULL || map == NULL)
400 goto out_problem;
401
402 thread__insert_map(thread, map);
403 return 0;
404
405out_problem:
406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
407 return 0;
408}
409
410int event__process_task(event_t *self, struct perf_session *session)
411{
412 struct thread *thread = perf_session__findnew(session, self->fork.pid);
413 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
414
415 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
416 self->fork.ppid, self->fork.ptid);
417 /*
418 * A thread clone will have the same PID for both parent and child.
419 */
420 if (thread == parent)
421 return 0;
422
423 if (self->header.type == PERF_RECORD_EXIT)
424 return 0;
425
426 if (thread == NULL || parent == NULL ||
427 thread__fork(thread, parent) < 0) {
428 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
429 return -1;
430 }
431
432 return 0;
433}
434
435void thread__find_addr_map(struct thread *self,
436 struct perf_session *session, u8 cpumode,
437 enum map_type type, u64 addr,
438 struct addr_location *al)
439{
440 struct map_groups *mg = &self->mg;
441
442 al->thread = self;
443 al->addr = addr;
444
445 if (cpumode == PERF_RECORD_MISC_KERNEL) {
446 al->level = 'k';
447 mg = &session->kmaps;
448 } else if (cpumode == PERF_RECORD_MISC_USER)
449 al->level = '.';
450 else {
451 al->level = 'H';
452 al->map = NULL;
453 return;
454 }
455try_again:
456 al->map = map_groups__find(mg, type, al->addr);
457 if (al->map == NULL) {
458 /*
459 * If this is outside of all known maps, and is a negative
460 * address, try to look it up in the kernel dso, as it might be
461 * a vsyscall or vdso (which executes in user-mode).
462 *
463 * XXX This is nasty, we should have a symbol list in the
464 * "[vdso]" dso, but for now lets use the old trick of looking
465 * in the whole kernel symbol list.
466 */
467 if ((long long)al->addr < 0 && mg != &session->kmaps) {
468 mg = &session->kmaps;
469 goto try_again;
470 }
471 } else
472 al->addr = al->map->map_ip(al->map, al->addr);
473}
474
475void thread__find_addr_location(struct thread *self,
476 struct perf_session *session, u8 cpumode,
477 enum map_type type, u64 addr,
478 struct addr_location *al,
479 symbol_filter_t filter)
480{
481 thread__find_addr_map(self, session, cpumode, type, addr, al);
482 if (al->map != NULL)
483 al->sym = map__find_symbol(al->map, al->addr, filter);
484 else
485 al->sym = NULL;
486}
487
488static void dso__calc_col_width(struct dso *self)
489{
490 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
491 (!symbol_conf.dso_list ||
492 strlist__has_entry(symbol_conf.dso_list, self->name))) {
493 unsigned int slen = strlen(self->name);
494 if (slen > dsos__col_width)
495 dsos__col_width = slen;
496 }
497
498 self->slen_calculated = 1;
499}
500
501int event__preprocess_sample(const event_t *self, struct perf_session *session,
502 struct addr_location *al, symbol_filter_t filter)
503{
504 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
505 struct thread *thread = perf_session__findnew(session, self->ip.pid);
506
507 if (thread == NULL)
508 return -1;
509
510 if (symbol_conf.comm_list &&
511 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
512 goto out_filtered;
513
514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
515
516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
517 self->ip.ip, al, filter);
518 dump_printf(" ...... dso: %s\n",
519 al->map ? al->map->dso->long_name :
520 al->level == 'H' ? "[hypervisor]" : "<not found>");
521 /*
522 * We have to do this here as we may have a dso with no symbol hit that
523 * has a name longer than the ones with symbols sampled.
524 */
525 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
526 dso__calc_col_width(al->map->dso);
527
528 if (symbol_conf.dso_list &&
529 (!al->map || !al->map->dso ||
530 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
531 (al->map->dso->short_name != al->map->dso->long_name &&
532 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
533 goto out_filtered;
534
535 if (symbol_conf.sym_list && al->sym &&
536 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
537 goto out_filtered;
538
539 al->filtered = false;
540 return 0;
541
542out_filtered:
543 al->filtered = true;
544 return 0;
545}
546
547int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
548{
549 u64 *array = event->sample.array;
550
551 if (type & PERF_SAMPLE_IP) {
552 data->ip = event->ip.ip;
553 array++;
554 }
555
556 if (type & PERF_SAMPLE_TID) {
557 u32 *p = (u32 *)array;
558 data->pid = p[0];
559 data->tid = p[1];
560 array++;
561 }
562
563 if (type & PERF_SAMPLE_TIME) {
564 data->time = *array;
565 array++;
566 }
567
568 if (type & PERF_SAMPLE_ADDR) {
569 data->addr = *array;
570 array++;
571 }
572
573 if (type & PERF_SAMPLE_ID) {
574 data->id = *array;
575 array++;
576 }
577
578 if (type & PERF_SAMPLE_STREAM_ID) {
579 data->stream_id = *array;
580 array++;
581 }
582
583 if (type & PERF_SAMPLE_CPU) {
584 u32 *p = (u32 *)array;
585 data->cpu = *p;
586 array++;
587 }
588
589 if (type & PERF_SAMPLE_PERIOD) {
590 data->period = *array;
591 array++;
592 }
593
594 if (type & PERF_SAMPLE_READ) {
595 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
596 return -1;
597 }
598
599 if (type & PERF_SAMPLE_CALLCHAIN) {
600 data->callchain = (struct ip_callchain *)array;
601 array += 1 + data->callchain->nr;
602 }
603
604 if (type & PERF_SAMPLE_RAW) {
605 u32 *p = (u32 *)array;
606 data->raw_size = *p;
607 p++;
608 data->raw_data = p;
609 }
610
611 return 0;
612}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..50a7132887f5 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6 3
7enum { 4#include <limits.h>
8 SHOW_KERNEL = 1, 5
9 SHOW_USER = 2, 6#include "../perf.h"
10 SHOW_HV = 4, 7#include "map.h"
11};
12 8
13/* 9/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -60,11 +56,32 @@ struct read_event {
60 u64 id; 56 u64 id;
61}; 57};
62 58
63struct sample_event{ 59struct sample_event {
64 struct perf_event_header header; 60 struct perf_event_header header;
65 u64 array[]; 61 u64 array[];
66}; 62};
67 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
78#define BUILD_ID_SIZE 20
79
80struct build_id_event {
81 struct perf_event_header header;
82 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
83 char filename[];
84};
68 85
69typedef union event_union { 86typedef union event_union {
70 struct perf_event_header header; 87 struct perf_event_header header;
@@ -77,28 +94,35 @@ typedef union event_union {
77 struct sample_event sample; 94 struct sample_event sample;
78} event_t; 95} event_t;
79 96
80struct map { 97struct events_stats {
81 struct list_head node; 98 u64 total;
82 u64 start; 99 u64 lost;
83 u64 end;
84 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64);
86 struct dso *dso;
87}; 100};
88 101
89static inline u64 map__map_ip(struct map *map, u64 ip) 102void event__print_totals(void);
90{ 103
91 return ip - map->start + map->pgoff; 104struct perf_session;
92} 105
106typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
107
108int event__synthesize_thread(pid_t pid, event__handler_t process,
109 struct perf_session *session);
110void event__synthesize_threads(event__handler_t process,
111 struct perf_session *session);
112int event__synthesize_kernel_mmap(event__handler_t process,
113 struct perf_session *session,
114 const char *symbol_name);
115int event__synthesize_modules(event__handler_t process,
116 struct perf_session *session);
93 117
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 118int event__process_comm(event_t *self, struct perf_session *session);
95{ 119int event__process_lost(event_t *self, struct perf_session *session);
96 return ip; 120int event__process_mmap(event_t *self, struct perf_session *session);
97} 121int event__process_task(event_t *self, struct perf_session *session);
98 122
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 123struct addr_location;
100struct map *map__clone(struct map *self); 124int event__preprocess_sample(const event_t *self, struct perf_session *session,
101int map__overlap(struct map *l, struct map *r); 125 struct addr_location *al, symbol_filter_t filter);
102size_t map__fprintf(struct map *self, FILE *fp); 126int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
103 127
104#endif 128#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
1#ifndef PERF_EXEC_CMD_H 1#ifndef __PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H 2#define __PERF_EXEC_CMD_H
3 3
4extern void perf_set_argv_exec_path(const char *exec_path); 4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 11extern const char *system_path(const char *path);
12 12
13#endif /* PERF_EXEC_CMD_H */ 13#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..6c9aa16ee51f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,10 +1,20 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/list.h>
9#include <linux/kernel.h>
5 10
6#include "util.h" 11#include "util.h"
7#include "header.h" 12#include "header.h"
13#include "../perf.h"
14#include "trace-event.h"
15#include "session.h"
16#include "symbol.h"
17#include "debug.h"
8 18
9/* 19/*
10 * Create new perf.data header attribute: 20 * Create new perf.data header attribute:
@@ -13,75 +23,80 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{ 23{
14 struct perf_header_attr *self = malloc(sizeof(*self)); 24 struct perf_header_attr *self = malloc(sizeof(*self));
15 25
16 if (!self) 26 if (self != NULL) {
17 die("nomem"); 27 self->attr = *attr;
18 28 self->ids = 0;
19 self->attr = *attr; 29 self->size = 1;
20 self->ids = 0; 30 self->id = malloc(sizeof(u64));
21 self->size = 1; 31 if (self->id == NULL) {
22 self->id = malloc(sizeof(u64)); 32 free(self);
23 33 self = NULL;
24 if (!self->id) 34 }
25 die("nomem"); 35 }
26 36
27 return self; 37 return self;
28} 38}
29 39
30void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 40void perf_header_attr__delete(struct perf_header_attr *self)
41{
42 free(self->id);
43 free(self);
44}
45
46int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
31{ 47{
32 int pos = self->ids; 48 int pos = self->ids;
33 49
34 self->ids++; 50 self->ids++;
35 if (self->ids > self->size) { 51 if (self->ids > self->size) {
36 self->size *= 2; 52 int nsize = self->size * 2;
37 self->id = realloc(self->id, self->size * sizeof(u64)); 53 u64 *nid = realloc(self->id, nsize * sizeof(u64));
38 if (!self->id) 54
39 die("nomem"); 55 if (nid == NULL)
56 return -1;
57
58 self->size = nsize;
59 self->id = nid;
40 } 60 }
41 self->id[pos] = id; 61 self->id[pos] = id;
62 return 0;
42} 63}
43 64
44/* 65int perf_header__init(struct perf_header *self)
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{ 66{
49 struct perf_header *self = malloc(sizeof(*self));
50
51 if (!self)
52 die("nomem");
53
54 self->frozen = 0;
55
56 self->attrs = 0;
57 self->size = 1; 67 self->size = 1;
58 self->attr = malloc(sizeof(void *)); 68 self->attr = malloc(sizeof(void *));
59 69 return self->attr == NULL ? -ENOMEM : 0;
60 if (!self->attr)
61 die("nomem");
62
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self;
67} 70}
68 71
69void perf_header__add_attr(struct perf_header *self, 72void perf_header__exit(struct perf_header *self)
70 struct perf_header_attr *attr)
71{ 73{
72 int pos = self->attrs; 74 int i;
75 for (i = 0; i < self->attrs; ++i)
76 perf_header_attr__delete(self->attr[i]);
77 free(self->attr);
78}
73 79
80int perf_header__add_attr(struct perf_header *self,
81 struct perf_header_attr *attr)
82{
74 if (self->frozen) 83 if (self->frozen)
75 die("frozen"); 84 return -1;
76 85
77 self->attrs++; 86 if (self->attrs == self->size) {
78 if (self->attrs > self->size) { 87 int nsize = self->size * 2;
79 self->size *= 2; 88 struct perf_header_attr **nattr;
80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 89
81 if (!self->attr) 90 nattr = realloc(self->attr, nsize * sizeof(void *));
82 die("nomem"); 91 if (nattr == NULL)
92 return -1;
93
94 self->size = nsize;
95 self->attr = nattr;
83 } 96 }
84 self->attr[pos] = attr; 97
98 self->attr[self->attrs++] = attr;
99 return 0;
85} 100}
86 101
87#define MAX_EVENT_NAME 64 102#define MAX_EVENT_NAME 64
@@ -94,24 +109,28 @@ struct perf_trace_event_type {
94static int event_count; 109static int event_count;
95static struct perf_trace_event_type *events; 110static struct perf_trace_event_type *events;
96 111
97void perf_header__push_event(u64 id, const char *name) 112int perf_header__push_event(u64 id, const char *name)
98{ 113{
99 if (strlen(name) > MAX_EVENT_NAME) 114 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 115 pr_warning("Event %s will be truncated\n", name);
101 116
102 if (!events) { 117 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 118 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events) 119 if (events == NULL)
105 die("nomem"); 120 return -ENOMEM;
106 } else { 121 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 122 struct perf_trace_event_type *nevents;
108 if (!events) 123
109 die("nomem"); 124 nevents = realloc(events, (event_count + 1) * sizeof(*events));
125 if (nevents == NULL)
126 return -ENOMEM;
127 events = nevents;
110 } 128 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 129 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id; 130 events[event_count].event_id = id;
113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 131 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114 event_count++; 132 event_count++;
133 return 0;
115} 134}
116 135
117char *perf_header__find_event(u64 id) 136char *perf_header__find_event(u64 id)
@@ -128,44 +147,292 @@ static const char *__perf_magic = "PERFFILE";
128 147
129#define PERF_MAGIC (*(u64 *)__perf_magic) 148#define PERF_MAGIC (*(u64 *)__perf_magic)
130 149
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr { 150struct perf_file_attr {
137 struct perf_event_attr attr; 151 struct perf_event_attr attr;
138 struct perf_file_section ids; 152 struct perf_file_section ids;
139}; 153};
140 154
141struct perf_file_header { 155void perf_header__set_feat(struct perf_header *self, int feat)
142 u64 magic; 156{
143 u64 size; 157 set_bit(feat, self->adds_features);
144 u64 attr_size; 158}
145 struct perf_file_section attrs;
146 struct perf_file_section data;
147 struct perf_file_section event_types;
148};
149 159
150static void do_write(int fd, void *buf, size_t size) 160bool perf_header__has_feat(const struct perf_header *self, int feat)
161{
162 return test_bit(feat, self->adds_features);
163}
164
165static int do_write(int fd, const void *buf, size_t size)
151{ 166{
152 while (size) { 167 while (size) {
153 int ret = write(fd, buf, size); 168 int ret = write(fd, buf, size);
154 169
155 if (ret < 0) 170 if (ret < 0)
156 die("failed to write"); 171 return -errno;
157 172
158 size -= ret; 173 size -= ret;
159 buf += ret; 174 buf += ret;
160 } 175 }
176
177 return 0;
178}
179
180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
184{
185 static const char zero_buf[NAME_ALIGN];
186 int err = do_write(fd, bf, count);
187
188 if (!err)
189 err = do_write(fd, zero_buf, count_aligned - count);
190
191 return err;
192}
193
194#define dsos__for_each_with_build_id(pos, head) \
195 list_for_each_entry(pos, head, node) \
196 if (!pos->has_build_id) \
197 continue; \
198 else
199
200static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
201{
202 struct dso *pos;
203
204 dsos__for_each_with_build_id(pos, head) {
205 int err;
206 struct build_id_event b;
207 size_t len;
208
209 if (!pos->hit)
210 continue;
211 len = pos->long_name_len + 1;
212 len = ALIGN(len, NAME_ALIGN);
213 memset(&b, 0, sizeof(b));
214 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
215 b.header.misc = misc;
216 b.header.size = sizeof(b) + len;
217 err = do_write(fd, &b, sizeof(b));
218 if (err < 0)
219 return err;
220 err = write_padded(fd, pos->long_name,
221 pos->long_name_len + 1, len);
222 if (err < 0)
223 return err;
224 }
225
226 return 0;
227}
228
229static int dsos__write_buildid_table(int fd)
230{
231 int err = __dsos__write_buildid_table(&dsos__kernel,
232 PERF_RECORD_MISC_KERNEL, fd);
233 if (err == 0)
234 err = __dsos__write_buildid_table(&dsos__user,
235 PERF_RECORD_MISC_USER, fd);
236 return err;
237}
238
239int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
240 const char *name, bool is_kallsyms)
241{
242 const size_t size = PATH_MAX;
243 char *filename = malloc(size),
244 *linkname = malloc(size), *targetname;
245 int len, err = -1;
246
247 if (filename == NULL || linkname == NULL)
248 goto out_free;
249
250 len = snprintf(filename, size, "%s%s%s",
251 debugdir, is_kallsyms ? "/" : "", name);
252 if (mkdir_p(filename, 0755))
253 goto out_free;
254
255 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
256
257 if (access(filename, F_OK)) {
258 if (is_kallsyms) {
259 if (copyfile("/proc/kallsyms", filename))
260 goto out_free;
261 } else if (link(name, filename) && copyfile(name, filename))
262 goto out_free;
263 }
264
265 len = snprintf(linkname, size, "%s/.build-id/%.2s",
266 debugdir, sbuild_id);
267
268 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
269 goto out_free;
270
271 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
272 targetname = filename + strlen(debugdir) - 5;
273 memcpy(targetname, "../..", 5);
274
275 if (symlink(targetname, linkname) == 0)
276 err = 0;
277out_free:
278 free(filename);
279 free(linkname);
280 return err;
281}
282
283static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
284 const char *name, const char *debugdir,
285 bool is_kallsyms)
286{
287 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
288
289 build_id__sprintf(build_id, build_id_size, sbuild_id);
290
291 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
292}
293
294int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
295{
296 const size_t size = PATH_MAX;
297 char *filename = malloc(size),
298 *linkname = malloc(size);
299 int err = -1;
300
301 if (filename == NULL || linkname == NULL)
302 goto out_free;
303
304 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
305 debugdir, sbuild_id, sbuild_id + 2);
306
307 if (access(linkname, F_OK))
308 goto out_free;
309
310 if (readlink(linkname, filename, size) < 0)
311 goto out_free;
312
313 if (unlink(linkname))
314 goto out_free;
315
316 /*
317 * Since the link is relative, we must make it absolute:
318 */
319 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
320 debugdir, sbuild_id, filename);
321
322 if (unlink(linkname))
323 goto out_free;
324
325 err = 0;
326out_free:
327 free(filename);
328 free(linkname);
329 return err;
330}
331
332static int dso__cache_build_id(struct dso *self, const char *debugdir)
333{
334 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
335
336 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
337 self->long_name, debugdir, is_kallsyms);
338}
339
340static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
341{
342 struct dso *pos;
343 int err = 0;
344
345 dsos__for_each_with_build_id(pos, head)
346 if (dso__cache_build_id(pos, debugdir))
347 err = -1;
348
349 return err;
350}
351
352static int dsos__cache_build_ids(void)
353{
354 int err_kernel, err_user;
355 char debugdir[PATH_MAX];
356
357 snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
358 DEBUG_CACHE_DIR);
359
360 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
361 return -1;
362
363 err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
364 err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
365 return err_kernel || err_user ? -1 : 0;
366}
367
368static int perf_header__adds_write(struct perf_header *self, int fd)
369{
370 int nr_sections;
371 struct perf_file_section *feat_sec;
372 int sec_size;
373 u64 sec_start;
374 int idx = 0, err;
375
376 if (dsos__read_build_ids(true))
377 perf_header__set_feat(self, HEADER_BUILD_ID);
378
379 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
380 if (!nr_sections)
381 return 0;
382
383 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
384 if (feat_sec == NULL)
385 return -ENOMEM;
386
387 sec_size = sizeof(*feat_sec) * nr_sections;
388
389 sec_start = self->data_offset + self->data_size;
390 lseek(fd, sec_start + sec_size, SEEK_SET);
391
392 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
393 struct perf_file_section *trace_sec;
394
395 trace_sec = &feat_sec[idx++];
396
397 /* Write trace info */
398 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
399 read_tracing_data(fd, attrs, nr_counters);
400 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
401 }
402
403
404 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
405 struct perf_file_section *buildid_sec;
406
407 buildid_sec = &feat_sec[idx++];
408
409 /* Write build-ids */
410 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
411 err = dsos__write_buildid_table(fd);
412 if (err < 0) {
413 pr_debug("failed to write buildid table\n");
414 goto out_free;
415 }
416 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
417 buildid_sec->offset;
418 dsos__cache_build_ids();
419 }
420
421 lseek(fd, sec_start, SEEK_SET);
422 err = do_write(fd, feat_sec, sec_size);
423 if (err < 0)
424 pr_debug("failed to write feature section\n");
425out_free:
426 free(feat_sec);
427 return err;
161} 428}
162 429
163void perf_header__write(struct perf_header *self, int fd) 430int perf_header__write(struct perf_header *self, int fd, bool at_exit)
164{ 431{
165 struct perf_file_header f_header; 432 struct perf_file_header f_header;
166 struct perf_file_attr f_attr; 433 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr; 434 struct perf_header_attr *attr;
168 int i; 435 int i, err;
169 436
170 lseek(fd, sizeof(f_header), SEEK_SET); 437 lseek(fd, sizeof(f_header), SEEK_SET);
171 438
@@ -174,7 +441,11 @@ void perf_header__write(struct perf_header *self, int fd)
174 attr = self->attr[i]; 441 attr = self->attr[i];
175 442
176 attr->id_offset = lseek(fd, 0, SEEK_CUR); 443 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); 444 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
445 if (err < 0) {
446 pr_debug("failed to write perf header\n");
447 return err;
448 }
178 } 449 }
179 450
180 451
@@ -190,17 +461,31 @@ void perf_header__write(struct perf_header *self, int fd)
190 .size = attr->ids * sizeof(u64), 461 .size = attr->ids * sizeof(u64),
191 } 462 }
192 }; 463 };
193 do_write(fd, &f_attr, sizeof(f_attr)); 464 err = do_write(fd, &f_attr, sizeof(f_attr));
465 if (err < 0) {
466 pr_debug("failed to write perf header attribute\n");
467 return err;
468 }
194 } 469 }
195 470
196 self->event_offset = lseek(fd, 0, SEEK_CUR); 471 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 472 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events) 473 if (events) {
199 do_write(fd, events, self->event_size); 474 err = do_write(fd, events, self->event_size);
200 475 if (err < 0) {
476 pr_debug("failed to write perf header events\n");
477 return err;
478 }
479 }
201 480
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 481 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 482
483 if (at_exit) {
484 err = perf_header__adds_write(self, fd);
485 if (err < 0)
486 return err;
487 }
488
204 f_header = (struct perf_file_header){ 489 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC, 490 .magic = PERF_MAGIC,
206 .size = sizeof(f_header), 491 .size = sizeof(f_header),
@@ -219,44 +504,175 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 504 },
220 }; 505 };
221 506
507 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
508
222 lseek(fd, 0, SEEK_SET); 509 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 510 err = do_write(fd, &f_header, sizeof(f_header));
511 if (err < 0) {
512 pr_debug("failed to write perf header\n");
513 return err;
514 }
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 515 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225 516
226 self->frozen = 1; 517 self->frozen = 1;
518 return 0;
227} 519}
228 520
229static void do_read(int fd, void *buf, size_t size) 521static int do_read(int fd, void *buf, size_t size)
230{ 522{
231 while (size) { 523 while (size) {
232 int ret = read(fd, buf, size); 524 int ret = read(fd, buf, size);
233 525
234 if (ret < 0) 526 if (ret <= 0)
235 die("failed to read"); 527 return -1;
236 if (ret == 0)
237 die("failed to read: missing data");
238 528
239 size -= ret; 529 size -= ret;
240 buf += ret; 530 buf += ret;
241 } 531 }
532
533 return 0;
242} 534}
243 535
244struct perf_header *perf_header__read(int fd) 536static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size)
245{ 538{
246 struct perf_header *self = perf_header__new(); 539 if (do_read(fd, buf, size))
247 struct perf_file_header f_header; 540 return -1;
248 struct perf_file_attr f_attr;
249 u64 f_id;
250 541
251 int nr_attrs, nr_ids, i, j; 542 if (self->needs_swap)
543 mem_bswap_64(buf, size);
544
545 return 0;
546}
547
548int perf_header__process_sections(struct perf_header *self, int fd,
549 int (*process)(struct perf_file_section *self,
550 struct perf_header *ph,
551 int feat, int fd))
552{
553 struct perf_file_section *feat_sec;
554 int nr_sections;
555 int sec_size;
556 int idx = 0;
557 int err = -1, feat = 1;
558
559 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
560 if (!nr_sections)
561 return 0;
562
563 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
564 if (!feat_sec)
565 return -1;
566
567 sec_size = sizeof(*feat_sec) * nr_sections;
568
569 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
570
571 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
572 goto out_free;
573
574 err = 0;
575 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
576 if (perf_header__has_feat(self, feat)) {
577 struct perf_file_section *sec = &feat_sec[idx++];
578
579 err = process(sec, self, feat, fd);
580 if (err < 0)
581 break;
582 }
583 ++feat;
584 }
585out_free:
586 free(feat_sec);
587 return err;
588}
252 589
590int perf_file_header__read(struct perf_file_header *self,
591 struct perf_header *ph, int fd)
592{
253 lseek(fd, 0, SEEK_SET); 593 lseek(fd, 0, SEEK_SET);
254 do_read(fd, &f_header, sizeof(f_header));
255 594
256 if (f_header.magic != PERF_MAGIC || 595 if (do_read(fd, self, sizeof(*self)) ||
257 f_header.size != sizeof(f_header) || 596 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
258 f_header.attr_size != sizeof(f_attr)) 597 return -1;
259 die("incompatible file format"); 598
599 if (self->attr_size != sizeof(struct perf_file_attr)) {
600 u64 attr_size = bswap_64(self->attr_size);
601
602 if (attr_size != sizeof(struct perf_file_attr))
603 return -1;
604
605 mem_bswap_64(self, offsetof(struct perf_file_header,
606 adds_features));
607 ph->needs_swap = true;
608 }
609
610 if (self->size != sizeof(*self)) {
611 /* Support the previous format */
612 if (self->size == offsetof(typeof(*self), adds_features))
613 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
614 else
615 return -1;
616 }
617
618 memcpy(&ph->adds_features, &self->adds_features,
619 sizeof(ph->adds_features));
620 /*
621 * FIXME: hack that assumes that if we need swap the perf.data file
622 * may be coming from an arch with a different word-size, ergo different
623 * DEFINE_BITMAP format, investigate more later, but for now its mostly
624 * safe to assume that we have a build-id section. Trace files probably
625 * have several other issues in this realm anyway...
626 */
627 if (ph->needs_swap) {
628 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
629 perf_header__set_feat(ph, HEADER_BUILD_ID);
630 }
631
632 ph->event_offset = self->event_types.offset;
633 ph->event_size = self->event_types.size;
634 ph->data_offset = self->data.offset;
635 ph->data_size = self->data.size;
636 return 0;
637}
638
639static int perf_file_section__process(struct perf_file_section *self,
640 struct perf_header *ph,
641 int feat, int fd)
642{
643 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
644 pr_debug("Failed to lseek to %Ld offset for feature %d, "
645 "continuing...\n", self->offset, feat);
646 return 0;
647 }
648
649 switch (feat) {
650 case HEADER_TRACE_INFO:
651 trace_report(fd);
652 break;
653
654 case HEADER_BUILD_ID:
655 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
656 pr_debug("Failed to read buildids, continuing...\n");
657 break;
658 default:
659 pr_debug("unknown feature %d, continuing...\n", feat);
660 }
661
662 return 0;
663}
664
665int perf_header__read(struct perf_header *self, int fd)
666{
667 struct perf_file_header f_header;
668 struct perf_file_attr f_attr;
669 u64 f_id;
670 int nr_attrs, nr_ids, i, j;
671
672 if (perf_file_header__read(&f_header, self, fd) < 0) {
673 pr_debug("incompatible file format\n");
674 return -EINVAL;
675 }
260 676
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 677 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 678 lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -265,42 +681,54 @@ struct perf_header *perf_header__read(int fd)
265 struct perf_header_attr *attr; 681 struct perf_header_attr *attr;
266 off_t tmp; 682 off_t tmp;
267 683
268 do_read(fd, &f_attr, sizeof(f_attr)); 684 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
685 goto out_errno;
686
269 tmp = lseek(fd, 0, SEEK_CUR); 687 tmp = lseek(fd, 0, SEEK_CUR);
270 688
271 attr = perf_header_attr__new(&f_attr.attr); 689 attr = perf_header_attr__new(&f_attr.attr);
690 if (attr == NULL)
691 return -ENOMEM;
272 692
273 nr_ids = f_attr.ids.size / sizeof(u64); 693 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET); 694 lseek(fd, f_attr.ids.offset, SEEK_SET);
275 695
276 for (j = 0; j < nr_ids; j++) { 696 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id)); 697 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
698 goto out_errno;
278 699
279 perf_header_attr__add_id(attr, f_id); 700 if (perf_header_attr__add_id(attr, f_id) < 0) {
701 perf_header_attr__delete(attr);
702 return -ENOMEM;
703 }
704 }
705 if (perf_header__add_attr(self, attr) < 0) {
706 perf_header_attr__delete(attr);
707 return -ENOMEM;
280 } 708 }
281 perf_header__add_attr(self, attr); 709
282 lseek(fd, tmp, SEEK_SET); 710 lseek(fd, tmp, SEEK_SET);
283 } 711 }
284 712
285 if (f_header.event_types.size) { 713 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET); 714 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size); 715 events = malloc(f_header.event_types.size);
288 if (!events) 716 if (events == NULL)
289 die("nomem"); 717 return -ENOMEM;
290 do_read(fd, events, f_header.event_types.size); 718 if (perf_header__getbuffer64(self, fd, events,
719 f_header.event_types.size))
720 goto out_errno;
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 721 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 722 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295 723
296 self->data_offset = f_header.data.offset; 724 perf_header__process_sections(self, fd, perf_file_section__process);
297 self->data_size = f_header.data.size;
298 725
299 lseek(fd, self->data_offset, SEEK_SET); 726 lseek(fd, self->data_offset, SEEK_SET);
300 727
301 self->frozen = 1; 728 self->frozen = 1;
302 729 return 0;
303 return self; 730out_errno:
731 return -errno;
304} 732}
305 733
306u64 perf_header__sample_type(struct perf_header *header) 734u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,9 +1,13 @@
1#ifndef _PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define _PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
8#include "event.h"
9
10#include <linux/bitmap.h>
7 11
8struct perf_header_attr { 12struct perf_header_attr {
9 struct perf_event_attr attr; 13 struct perf_event_attr attr;
@@ -12,36 +16,77 @@ struct perf_header_attr {
12 off_t id_offset; 16 off_t id_offset;
13}; 17};
14 18
19enum {
20 HEADER_TRACE_INFO = 1,
21 HEADER_BUILD_ID,
22 HEADER_LAST_FEATURE,
23};
24
25#define HEADER_FEAT_BITS 256
26
27struct perf_file_section {
28 u64 offset;
29 u64 size;
30};
31
32struct perf_file_header {
33 u64 magic;
34 u64 size;
35 u64 attr_size;
36 struct perf_file_section attrs;
37 struct perf_file_section data;
38 struct perf_file_section event_types;
39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
40};
41
42struct perf_header;
43
44int perf_file_header__read(struct perf_file_header *self,
45 struct perf_header *ph, int fd);
46
15struct perf_header { 47struct perf_header {
16 int frozen; 48 int frozen;
17 int attrs, size; 49 int attrs, size;
18 struct perf_header_attr **attr; 50 struct perf_header_attr **attr;
19 s64 attr_offset; 51 s64 attr_offset;
20 u64 data_offset; 52 u64 data_offset;
21 u64 data_size; 53 u64 data_size;
22 u64 event_offset; 54 u64 event_offset;
23 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
24}; 58};
25 59
26struct perf_header *perf_header__read(int fd); 60int perf_header__init(struct perf_header *self);
27void perf_header__write(struct perf_header *self, int fd); 61void perf_header__exit(struct perf_header *self);
62
63int perf_header__read(struct perf_header *self, int fd);
64int perf_header__write(struct perf_header *self, int fd, bool at_exit);
28 65
29void perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
31 68
32void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
34 71
72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
73void perf_header_attr__delete(struct perf_header_attr *self);
35 74
36struct perf_header_attr * 75int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
37perf_header_attr__new(struct perf_event_attr *attr);
38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39 76
40u64 perf_header__sample_type(struct perf_header *header); 77u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 78struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 79perf_header__find_attr(u64 id, struct perf_header *header);
80void perf_header__set_feat(struct perf_header *self, int feat);
81bool perf_header__has_feat(const struct perf_header *self, int feat);
43 82
83int perf_header__process_sections(struct perf_header *self, int fd,
84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
86 int feat, int fd));
44 87
45struct perf_header *perf_header__new(void); 88int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
89 const char *name, bool is_kallsyms);
90int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
46 91
47#endif /* _PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
1#ifndef HELP_H 1#ifndef __PERF_HELP_H
2#define HELP_H 2#define __PERF_HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 size_t alloc; 5 size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 27 struct cmdnames *other_cmds);
28 28
29#endif /* HELP_H */ 29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..44408c2621cf
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,662 @@
1#include "hist.h"
2#include "session.h"
3#include "sort.h"
4#include <math.h>
5
6struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5
9};
10
11/*
12 * histogram, sorted on item, collects counts
13 */
14
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
16 struct addr_location *al,
17 struct symbol *sym_parent,
18 u64 count, bool *hit)
19{
20 struct rb_node **p = &self->hists.rb_node;
21 struct rb_node *parent = NULL;
22 struct hist_entry *he;
23 struct hist_entry entry = {
24 .thread = al->thread,
25 .map = al->map,
26 .sym = al->sym,
27 .ip = al->addr,
28 .level = al->level,
29 .count = count,
30 .parent = sym_parent,
31 };
32 int cmp;
33
34 while (*p != NULL) {
35 parent = *p;
36 he = rb_entry(parent, struct hist_entry, rb_node);
37
38 cmp = hist_entry__cmp(&entry, he);
39
40 if (!cmp) {
41 *hit = true;
42 return he;
43 }
44
45 if (cmp < 0)
46 p = &(*p)->rb_left;
47 else
48 p = &(*p)->rb_right;
49 }
50
51 he = malloc(sizeof(*he));
52 if (!he)
53 return NULL;
54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, &self->hists);
57 *hit = false;
58 return he;
59}
60
61int64_t
62hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
63{
64 struct sort_entry *se;
65 int64_t cmp = 0;
66
67 list_for_each_entry(se, &hist_entry__sort_list, list) {
68 cmp = se->cmp(left, right);
69 if (cmp)
70 break;
71 }
72
73 return cmp;
74}
75
76int64_t
77hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
78{
79 struct sort_entry *se;
80 int64_t cmp = 0;
81
82 list_for_each_entry(se, &hist_entry__sort_list, list) {
83 int64_t (*f)(struct hist_entry *, struct hist_entry *);
84
85 f = se->collapse ?: se->cmp;
86
87 cmp = f(left, right);
88 if (cmp)
89 break;
90 }
91
92 return cmp;
93}
94
95void hist_entry__free(struct hist_entry *he)
96{
97 free(he);
98}
99
100/*
101 * collapse the histogram
102 */
103
104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
105{
106 struct rb_node **p = &root->rb_node;
107 struct rb_node *parent = NULL;
108 struct hist_entry *iter;
109 int64_t cmp;
110
111 while (*p != NULL) {
112 parent = *p;
113 iter = rb_entry(parent, struct hist_entry, rb_node);
114
115 cmp = hist_entry__collapse(iter, he);
116
117 if (!cmp) {
118 iter->count += he->count;
119 hist_entry__free(he);
120 return;
121 }
122
123 if (cmp < 0)
124 p = &(*p)->rb_left;
125 else
126 p = &(*p)->rb_right;
127 }
128
129 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root);
131}
132
133void perf_session__collapse_resort(struct perf_session *self)
134{
135 struct rb_root tmp;
136 struct rb_node *next;
137 struct hist_entry *n;
138
139 if (!sort__need_collapse)
140 return;
141
142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
145 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node);
148
149 rb_erase(&n->rb_node, &self->hists);
150 collapse__insert_entry(&tmp, n);
151 }
152
153 self->hists = tmp;
154}
155
156/*
157 * reverse the map, sort on count.
158 */
159
160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
163{
164 struct rb_node **p = &root->rb_node;
165 struct rb_node *parent = NULL;
166 struct hist_entry *iter;
167
168 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain,
170 min_callchain_hits, &callchain_param);
171
172 while (*p != NULL) {
173 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node);
175
176 if (he->count > iter->count)
177 p = &(*p)->rb_left;
178 else
179 p = &(*p)->rb_right;
180 }
181
182 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root);
184}
185
186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
187{
188 struct rb_root tmp;
189 struct rb_node *next;
190 struct hist_entry *n;
191 u64 min_callchain_hits;
192
193 min_callchain_hits =
194 total_samples * (callchain_param.min_percent / 100);
195
196 tmp = RB_ROOT;
197 next = rb_first(&self->hists);
198
199 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node);
202
203 rb_erase(&n->rb_node, &self->hists);
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 separator
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);
657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..e5f99b24048b
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,27 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3
4#include <linux/types.h>
5#include "callchain.h"
6
7extern struct callchain_param callchain_param;
8
9struct perf_session;
10struct hist_entry;
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);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
20void hist_entry__free(struct hist_entry *);
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);
27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..94507639a8c4
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,3 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..8d63116e9435
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,29 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10#undef __KERNEL__
11
12static inline void set_bit(int nr, unsigned long *addr)
13{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15}
16
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{
19 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21}
22
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
24 long size, unsigned long offset);
25
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
27 long size, unsigned long offset);
28
29#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..a53d4ee1e0b7
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../util.h"
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..f2611655ab51 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -1,6 +1,16 @@
1#ifndef PERF_LINUX_KERNEL_H_ 1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_ 2#define PERF_LINUX_KERNEL_H_
3 3
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8
9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
10
11#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
12#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
13
4#ifndef offsetof 14#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif 16#endif
@@ -26,4 +36,71 @@
26 _max1 > _max2 ? _max1 : _max2; }) 36 _max1 > _max2 ? _max1 : _max2; })
27#endif 37#endif
28 38
39#ifndef min
40#define min(x, y) ({ \
41 typeof(x) _min1 = (x); \
42 typeof(y) _min2 = (y); \
43 (void) (&_min1 == &_min2); \
44 _min1 < _min2 ? _min1 : _min2; })
45#endif
46
47#ifndef BUG_ON
48#define BUG_ON(cond) assert(!(cond))
49#endif
50
51/*
52 * Both need more care to handle endianness
53 * (Don't use bitmap_copy_le() for now)
54 */
55#define cpu_to_le64(x) (x)
56#define cpu_to_le32(x) (x)
57
58static inline int
59vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
60{
61 int i;
62 ssize_t ssize = size;
63
64 i = vsnprintf(buf, size, fmt, args);
65
66 return (i >= ssize) ? (ssize - 1) : i;
67}
68
69static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
70{
71 va_list args;
72 ssize_t ssize = size;
73 int i;
74
75 va_start(args, fmt);
76 i = vsnprintf(buf, size, fmt, args);
77 va_end(args);
78
79 return (i >= ssize) ? (ssize - 1) : i;
80}
81
82static inline unsigned long
83simple_strtoul(const char *nptr, char **endptr, int base)
84{
85 return strtoul(nptr, endptr, base);
86}
87
88#ifndef pr_fmt
89#define pr_fmt(fmt) fmt
90#endif
91
92#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
94#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
96#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
98#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
105
29#endif 106#endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644
index 000000000000..3b2f5900276f
--- /dev/null
+++ b/tools/perf/util/include/linux/string.h
@@ -0,0 +1 @@
#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644
index 000000000000..196862a81a21
--- /dev/null
+++ b/tools/perf/util/include/linux/types.h
@@ -0,0 +1,9 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#define DECLARE_BITMAP(name,bits) \
7 unsigned long name[BITS_TO_LONGS(bits)]
8
9#endif
diff --git a/tools/perf/util/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
1#ifndef LEVENSHTEIN_H 1#ifndef __PERF_LEVENSHTEIN_H
2#define LEVENSHTEIN_H 2#define __PERF_LEVENSHTEIN_H
3 3
4int levenshtein(const char *string1, const char *string2, 4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty, 5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty); 6 int insertion_penalty, int deletion_penalty);
7 7
8#endif 8#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..e509cd59c67d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,12 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h"
7
8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions",
10 [MAP__VARIABLE] = "Variables",
11};
6 12
7static inline int is_anon_memory(const char *filename) 13static inline int is_anon_memory(const char *filename)
8{ 14{
@@ -19,13 +25,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 return n; 25 return n;
20} 26}
21 27
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) 28void map__init(struct map *self, enum map_type type,
29 u64 start, u64 end, u64 pgoff, struct dso *dso)
30{
31 self->type = type;
32 self->start = start;
33 self->end = end;
34 self->pgoff = pgoff;
35 self->dso = dso;
36 self->map_ip = map__map_ip;
37 self->unmap_ip = map__unmap_ip;
38 RB_CLEAR_NODE(&self->rb_node);
39}
40
41struct map *map__new(struct mmap_event *event, enum map_type type,
42 char *cwd, int cwdlen)
23{ 43{
24 struct map *self = malloc(sizeof(*self)); 44 struct map *self = malloc(sizeof(*self));
25 45
26 if (self != NULL) { 46 if (self != NULL) {
27 const char *filename = event->filename; 47 const char *filename = event->filename;
28 char newfilename[PATH_MAX]; 48 char newfilename[PATH_MAX];
49 struct dso *dso;
29 int anon; 50 int anon;
30 51
31 if (cwd) { 52 if (cwd) {
@@ -45,18 +66,20 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
45 filename = newfilename; 66 filename = newfilename;
46 } 67 }
47 68
48 self->start = event->start; 69 dso = dsos__findnew(filename);
49 self->end = event->start + event->len; 70 if (dso == NULL)
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete; 71 goto out_delete;
55 72
56 if (self->dso == vdso || anon) 73 map__init(self, type, event->start, event->start + event->len,
57 self->map_ip = vdso__map_ip; 74 event->pgoff, dso);
58 else 75
59 self->map_ip = map__map_ip; 76 if (anon) {
77set_identity:
78 self->map_ip = self->unmap_ip = identity__map_ip;
79 } else if (strcmp(filename, "[vdso]") == 0) {
80 dso__set_loaded(dso, self->type);
81 goto set_identity;
82 }
60 } 83 }
61 return self; 84 return self;
62out_delete: 85out_delete:
@@ -64,6 +87,103 @@ out_delete:
64 return NULL; 87 return NULL;
65} 88}
66 89
90void map__delete(struct map *self)
91{
92 free(self);
93}
94
95void map__fixup_start(struct map *self)
96{
97 struct rb_root *symbols = &self->dso->symbols[self->type];
98 struct rb_node *nd = rb_first(symbols);
99 if (nd != NULL) {
100 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101 self->start = sym->start;
102 }
103}
104
105void map__fixup_end(struct map *self)
106{
107 struct rb_root *symbols = &self->dso->symbols[self->type];
108 struct rb_node *nd = rb_last(symbols);
109 if (nd != NULL) {
110 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
111 self->end = sym->end;
112 }
113}
114
115#define DSO__DELETED "(deleted)"
116
117int map__load(struct map *self, symbol_filter_t filter)
118{
119 const char *name = self->dso->long_name;
120 int nr;
121
122 if (dso__loaded(self->dso, self->type))
123 return 0;
124
125 nr = dso__load(self->dso, self, filter);
126 if (nr < 0) {
127 if (self->dso->has_build_id) {
128 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
129
130 build_id__sprintf(self->dso->build_id,
131 sizeof(self->dso->build_id),
132 sbuild_id);
133 pr_warning("%s with build id %s not found",
134 name, sbuild_id);
135 } else
136 pr_warning("Failed to open %s", name);
137
138 pr_warning(", continuing without symbols\n");
139 return -1;
140 } else if (nr == 0) {
141 const size_t len = strlen(name);
142 const size_t real_len = len - sizeof(DSO__DELETED);
143
144 if (len > sizeof(DSO__DELETED) &&
145 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
146 pr_warning("%.*s was updated, restart the long "
147 "running apps that use it!\n",
148 (int)real_len, name);
149 } else {
150 pr_warning("no symbols found in %s, maybe install "
151 "a debug package?\n", name);
152 }
153
154 return -1;
155 }
156 /*
157 * Only applies to the kernel, as its symtabs aren't relative like the
158 * module ones.
159 */
160 if (self->dso->kernel)
161 map__reloc_vmlinux(self);
162
163 return 0;
164}
165
166struct symbol *map__find_symbol(struct map *self, u64 addr,
167 symbol_filter_t filter)
168{
169 if (map__load(self, filter) < 0)
170 return NULL;
171
172 return dso__find_symbol(self->dso, self->type, addr);
173}
174
175struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
176 symbol_filter_t filter)
177{
178 if (map__load(self, filter) < 0)
179 return NULL;
180
181 if (!dso__sorted_by_name(self->dso, self->type))
182 dso__sort_by_name(self->dso, self->type);
183
184 return dso__find_symbol_by_name(self->dso, self->type, name);
185}
186
67struct map *map__clone(struct map *self) 187struct map *map__clone(struct map *self)
68{ 188{
69 struct map *map = malloc(sizeof(*self)); 189 struct map *map = malloc(sizeof(*self));
@@ -95,3 +215,23 @@ size_t map__fprintf(struct map *self, FILE *fp)
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 215 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name); 216 self->start, self->end, self->pgoff, self->dso->name);
97} 217}
218
219/*
220 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
221 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
222 */
223u64 map__rip_2objdump(struct map *map, u64 rip)
224{
225 u64 addr = map->dso->adjust_symbols ?
226 map->unmap_ip(map, rip) : /* RIP -> IP */
227 rip;
228 return addr;
229}
230
231u64 map__objdump_2ip(struct map *map, u64 addr)
232{
233 u64 ip = map->dso->adjust_symbols ?
234 addr :
235 map->unmap_ip(map, addr); /* RIP -> IP */
236 return ip;
237}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..b756368076c6
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,94 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <linux/types.h>
8
9enum map_type {
10 MAP__FUNCTION = 0,
11 MAP__VARIABLE,
12};
13
14#define MAP__NR_TYPES (MAP__VARIABLE + 1)
15
16extern const char *map_type__name[MAP__NR_TYPES];
17
18struct dso;
19struct ref_reloc_sym;
20struct map_groups;
21
22struct map {
23 union {
24 struct rb_node rb_node;
25 struct list_head node;
26 };
27 u64 start;
28 u64 end;
29 enum map_type type;
30 u64 pgoff;
31
32 /* ip -> dso rip */
33 u64 (*map_ip)(struct map *, u64);
34 /* dso rip -> ip */
35 u64 (*unmap_ip)(struct map *, u64);
36
37 struct dso *dso;
38};
39
40struct kmap {
41 struct ref_reloc_sym *ref_reloc_sym;
42 struct map_groups *kmaps;
43};
44
45static inline struct kmap *map__kmap(struct map *self)
46{
47 return (struct kmap *)(self + 1);
48}
49
50static inline u64 map__map_ip(struct map *map, u64 ip)
51{
52 return ip - map->start + map->pgoff;
53}
54
55static inline u64 map__unmap_ip(struct map *map, u64 ip)
56{
57 return ip + map->start - map->pgoff;
58}
59
60static inline u64 identity__map_ip(struct map *map __used, u64 ip)
61{
62 return ip;
63}
64
65
66/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
67u64 map__rip_2objdump(struct map *map, u64 rip);
68u64 map__objdump_2ip(struct map *map, u64 addr);
69
70struct symbol;
71struct mmap_event;
72
73typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
74
75void map__init(struct map *self, enum map_type type,
76 u64 start, u64 end, u64 pgoff, struct dso *dso);
77struct map *map__new(struct mmap_event *event, enum map_type,
78 char *cwd, int cwdlen);
79void map__delete(struct map *self);
80struct map *map__clone(struct map *self);
81int map__overlap(struct map *l, struct map *r);
82size_t map__fprintf(struct map *self, FILE *fp);
83
84int map__load(struct map *self, symbol_filter_t filter);
85struct symbol *map__find_symbol(struct map *self,
86 u64 addr, symbol_filter_t filter);
87struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
88 symbol_filter_t filter);
89void map__fixup_start(struct map *self);
90void map__fixup_end(struct map *self);
91
92void map__reloc_vmlinux(struct map *self);
93
94#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
1 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
@@ -7,10 +7,12 @@
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10#include "debugfs.h"
10 11
11int nr_counters; 12int nr_counters;
12 13
13struct perf_event_attr attrs[MAX_COUNTERS]; 14struct perf_event_attr attrs[MAX_COUNTERS];
15char *filters[MAX_COUNTERS];
14 16
15struct event_symbol { 17struct event_symbol {
16 u8 type; 18 u8 type;
@@ -46,6 +48,8 @@ static struct event_symbol event_symbols[] = {
46 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
47 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
49}; 53};
50 54
51#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -74,6 +78,8 @@ static const char *sw_event_names[] = {
74 "CPU-migrations", 78 "CPU-migrations",
75 "minor-faults", 79 "minor-faults",
76 "major-faults", 80 "major-faults",
81 "alignment-faults",
82 "emulation-faults",
77}; 83};
78 84
79#define MAX_ALIASES 8 85#define MAX_ALIASES 8
@@ -148,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
148 154
149#define MAX_EVENT_LENGTH 512 155#define MAX_EVENT_LENGTH 512
150 156
151int valid_debugfs_mount(const char *debugfs)
152{
153 struct statfs st_fs;
154
155 if (statfs(debugfs, &st_fs) < 0)
156 return -ENOENT;
157 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
158 return -ENOENT;
159 return 0;
160}
161 157
162struct tracepoint_path *tracepoint_id_to_path(u64 config) 158struct tracepoint_path *tracepoint_id_to_path(u64 config)
163{ 159{
@@ -170,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
170 char evt_path[MAXPATHLEN]; 166 char evt_path[MAXPATHLEN];
171 char dir_path[MAXPATHLEN]; 167 char dir_path[MAXPATHLEN];
172 168
173 if (valid_debugfs_mount(debugfs_path)) 169 if (debugfs_valid_mountpoint(debugfs_path))
174 return NULL; 170 return NULL;
175 171
176 sys_dir = opendir(debugfs_path); 172 sys_dir = opendir(debugfs_path);
@@ -201,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
201 if (id == config) { 197 if (id == config) {
202 closedir(evt_dir); 198 closedir(evt_dir);
203 closedir(sys_dir); 199 closedir(sys_dir);
204 path = calloc(1, sizeof(path)); 200 path = zalloc(sizeof(*path));
205 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
206 if (!path->system) { 202 if (!path->system) {
207 free(path); 203 free(path);
@@ -454,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
454/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
455#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
456static enum event_result 452static enum event_result
457parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
458{ 455{
459 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
460 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -471,7 +468,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
471 while ((evt_ent = readdir(evt_dir))) { 468 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1]; 469 char event_opt[MAX_EVOPT_LEN + 1];
473 int len; 470 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475 471
476 if (!strcmp(evt_ent->d_name, ".") 472 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..") 473 || !strcmp(evt_ent->d_name, "..")
@@ -479,20 +475,15 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
479 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
480 continue; 476 continue;
481 477
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 478 if (!strglobmatch(evt_ent->d_name, evt_exp))
483 evt_ent->d_name); 479 continue;
480
481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
482 evt_ent->d_name, flags ? ":" : "",
483 flags ?: "");
484 if (len < 0) 484 if (len < 0)
485 return EVT_FAILED; 485 return EVT_FAILED;
486 486
487 rem -= len;
488 if (flags) {
489 if (rem < strlen(flags) + 1)
490 return EVT_FAILED;
491
492 strcat(event_opt, ":");
493 strcat(event_opt, flags);
494 }
495
496 if (parse_events(NULL, event_opt, 0)) 487 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED; 488 return EVT_FAILED;
498 } 489 }
@@ -509,7 +500,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
509 char sys_name[MAX_EVENT_LENGTH]; 500 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length; 501 unsigned int sys_length, evt_length;
511 502
512 if (valid_debugfs_mount(debugfs_path)) 503 if (debugfs_valid_mountpoint(debugfs_path))
513 return 0; 504 return 0;
514 505
515 evt_name = strchr(*strp, ':'); 506 evt_name = strchr(*strp, ':');
@@ -535,15 +526,91 @@ static enum event_result parse_tracepoint_event(const char **strp,
535 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
536 return EVT_FAILED; 527 return EVT_FAILED;
537 528
538 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
539 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
540 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
541 } else 533 } else
542 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
543 evt_length, flags, 535 evt_length, flags,
544 attr, strp); 536 attr, strp);
545} 537}
546 538
539static enum event_result
540parse_breakpoint_type(const char *type, const char **strp,
541 struct perf_event_attr *attr)
542{
543 int i;
544
545 for (i = 0; i < 3; i++) {
546 if (!type[i])
547 break;
548
549 switch (type[i]) {
550 case 'r':
551 attr->bp_type |= HW_BREAKPOINT_R;
552 break;
553 case 'w':
554 attr->bp_type |= HW_BREAKPOINT_W;
555 break;
556 case 'x':
557 attr->bp_type |= HW_BREAKPOINT_X;
558 break;
559 default:
560 return EVT_FAILED;
561 }
562 }
563 if (!attr->bp_type) /* Default */
564 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
565
566 *strp = type + i;
567
568 return EVT_HANDLED;
569}
570
571static enum event_result
572parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
573{
574 const char *target;
575 const char *type;
576 char *endaddr;
577 u64 addr;
578 enum event_result err;
579
580 target = strchr(*strp, ':');
581 if (!target)
582 return EVT_FAILED;
583
584 if (strncmp(*strp, "mem", target - *strp) != 0)
585 return EVT_FAILED;
586
587 target++;
588
589 addr = strtoull(target, &endaddr, 0);
590 if (target == endaddr)
591 return EVT_FAILED;
592
593 attr->bp_addr = addr;
594 *strp = endaddr;
595
596 type = strchr(target, ':');
597
598 /* If no type is defined, just rw as default */
599 if (!type) {
600 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
601 } else {
602 err = parse_breakpoint_type(++type, strp, attr);
603 if (err == EVT_FAILED)
604 return EVT_FAILED;
605 }
606
607 /* We should find a nice way to override the access type */
608 attr->bp_len = HW_BREAKPOINT_LEN_4;
609 attr->type = PERF_TYPE_BREAKPOINT;
610
611 return EVT_HANDLED;
612}
613
547static int check_events(const char *str, unsigned int i) 614static int check_events(const char *str, unsigned int i)
548{ 615{
549 int n; 616 int n;
@@ -677,6 +744,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
677 if (ret != EVT_FAILED) 744 if (ret != EVT_FAILED)
678 goto modifier; 745 goto modifier;
679 746
747 ret = parse_breakpoint_event(str, attr);
748 if (ret != EVT_FAILED)
749 goto modifier;
750
751 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
752 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
680 return EVT_FAILED; 753 return EVT_FAILED;
681 754
682modifier: 755modifier:
@@ -685,11 +758,11 @@ modifier:
685 return ret; 758 return ret;
686} 759}
687 760
688static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
689{ 762{
690 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
691 FILE *file; 764 FILE *file;
692 int id; 765 int id, n;
693 766
694 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
695 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -701,21 +774,24 @@ static void store_event_type(const char *orgname)
701 774
702 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
703 if (!file) 776 if (!file)
704 return; 777 return 0;
705 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
706 die("cannot store event ID");
707 fclose(file); 779 fclose(file);
708 perf_header__push_event(id, orgname); 780 if (n < 1) {
781 pr_err("cannot store event ID\n");
782 return -EINVAL;
783 }
784 return perf_header__push_event(id, orgname);
709} 785}
710 786
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 787int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 788{
714 struct perf_event_attr attr; 789 struct perf_event_attr attr;
715 enum event_result ret; 790 enum event_result ret;
716 791
717 if (strchr(str, ':')) 792 if (strchr(str, ':'))
718 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
719 795
720 for (;;) { 796 for (;;) {
721 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -745,12 +821,35 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 821 return 0;
746} 822}
747 823
824int parse_filter(const struct option *opt __used, const char *str,
825 int unset __used)
826{
827 int i = nr_counters - 1;
828 int len = strlen(str);
829
830 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
831 fprintf(stderr,
832 "-F option should follow a -e tracepoint option\n");
833 return -1;
834 }
835
836 filters[i] = malloc(len + 1);
837 if (!filters[i]) {
838 fprintf(stderr, "not enough memory to hold filter string\n");
839 return -1;
840 }
841 strcpy(filters[i], str);
842
843 return 0;
844}
845
748static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
749 "",
750 "Hardware event", 847 "Hardware event",
751 "Software event", 848 "Software event",
752 "Tracepoint event", 849 "Tracepoint event",
753 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
754}; 853};
755 854
756/* 855/*
@@ -764,7 +863,7 @@ static void print_tracepoint_events(void)
764 char evt_path[MAXPATHLEN]; 863 char evt_path[MAXPATHLEN];
765 char dir_path[MAXPATHLEN]; 864 char dir_path[MAXPATHLEN];
766 865
767 if (valid_debugfs_mount(debugfs_path)) 866 if (debugfs_valid_mountpoint(debugfs_path))
768 return; 867 return;
769 868
770 sys_dir = opendir(debugfs_path); 869 sys_dir = opendir(debugfs_path);
@@ -782,8 +881,8 @@ static void print_tracepoint_events(void)
782 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 881 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
783 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
784 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
785 fprintf(stderr, " %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
786 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
787 } 886 }
788 closedir(evt_dir); 887 closedir(evt_dir);
789 } 888 }
@@ -799,28 +898,26 @@ void print_events(void)
799 unsigned int i, type, op, prev_type = -1; 898 unsigned int i, type, op, prev_type = -1;
800 char name[40]; 899 char name[40];
801 900
802 fprintf(stderr, "\n"); 901 printf("\n");
803 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
804 903
805 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
806 type = syms->type + 1; 905 type = syms->type;
807 if (type >= ARRAY_SIZE(event_type_descriptors))
808 type = 0;
809 906
810 if (type != prev_type) 907 if (type != prev_type)
811 fprintf(stderr, "\n"); 908 printf("\n");
812 909
813 if (strlen(syms->alias)) 910 if (strlen(syms->alias))
814 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 911 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
815 else 912 else
816 strcpy(name, syms->symbol); 913 strcpy(name, syms->symbol);
817 fprintf(stderr, " %-42s [%s]\n", name, 914 printf(" %-42s [%s]\n", name,
818 event_type_descriptors[type]); 915 event_type_descriptors[type]);
819 916
820 prev_type = type; 917 prev_type = type;
821 } 918 }
822 919
823 fprintf(stderr, "\n"); 920 printf("\n");
824 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 921 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
825 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 922 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
826 /* skip invalid cache type */ 923 /* skip invalid cache type */
@@ -828,17 +925,22 @@ void print_events(void)
828 continue; 925 continue;
829 926
830 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
831 fprintf(stderr, " %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
832 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
833 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
834 } 931 }
835 } 932 }
836 } 933 }
837 934
838 fprintf(stderr, "\n"); 935 printf("\n");
839 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
840 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
841 fprintf(stderr, "\n"); 938 printf("\n");
939
940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
943 printf("\n");
842 944
843 print_tracepoint_events(); 945 print_tracepoint_events();
844 946
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
1#ifndef _PARSE_EVENTS_H 1#ifndef __PERF_PARSE_EVENTS_H
2#define _PARSE_EVENTS_H 2#define __PERF_PARSE_EVENTS_H
3/* 3/*
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
17extern int nr_counters; 17extern int nr_counters;
18 18
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
20extern char *filters[MAX_COUNTERS];
20 21
21extern const char *event_name(int ctr); 22extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config); 23extern const char *__event_name(int type, u64 config);
23 24
24extern int parse_events(const struct option *opt, const char *str, int unset); 25extern int parse_events(const struct option *opt, const char *str, int unset);
26extern int parse_filter(const struct option *opt, const char *str, int unset);
25 27
26#define EVENTS_HELP_MAX (128*1024) 28#define EVENTS_HELP_MAX (128*1024)
27 29
@@ -31,4 +33,4 @@ extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs); 33extern int valid_debugfs_mount(const char *debugfs);
32 34
33 35
34#endif /* _PARSE_EVENTS_H */ 36#endif /* __PERF_PARSE_EVENTS_H */
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/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
1#ifndef PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4enum parse_opt_type { 4enum parse_opt_type {
5 /* special types */ 5 /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
174 174
175extern const char *parse_options_fix_filename(const char *prefix, const char *file); 175extern const char *parse_options_fix_filename(const char *prefix, const char *file);
176 176
177#endif 177#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644
index 000000000000..53181dbfe4a8
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,802 @@
1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#define _GNU_SOURCE
23#include <sys/utsname.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <limits.h>
34
35#undef _GNU_SOURCE
36#include "event.h"
37#include "string.h"
38#include "strlist.h"
39#include "debug.h"
40#include "cache.h"
41#include "color.h"
42#include "parse-events.h" /* For debugfs_path */
43#include "probe-event.h"
44
45#define MAX_CMDLEN 256
46#define MAX_PROBE_ARGS 128
47#define PERFPROBE_GROUP "probe"
48
49#define semantic_error(msg ...) die("Semantic error :" msg)
50
51/* If there is no space to write, returns -E2BIG. */
52static int e_snprintf(char *str, size_t size, const char *format, ...)
53 __attribute__((format(printf, 3, 4)));
54
55static int e_snprintf(char *str, size_t size, const char *format, ...)
56{
57 int ret;
58 va_list ap;
59 va_start(ap, format);
60 ret = vsnprintf(str, size, format, ap);
61 va_end(ap);
62 if (ret >= (int)size)
63 ret = -E2BIG;
64 return ret;
65}
66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
103/* Check the name is good for event/group */
104static bool check_event_name(const char *name)
105{
106 if (!isalpha(*name) && *name != '_')
107 return false;
108 while (*++name != '\0') {
109 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
110 return false;
111 }
112 return true;
113}
114
115/* Parse probepoint definition. */
116static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
117{
118 char *ptr, *tmp;
119 char c, nc = 0;
120 /*
121 * <Syntax>
122 * perf probe [EVENT=]SRC[:LN|;PTN]
123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 *
125 * TODO:Group name support
126 */
127
128 ptr = strpbrk(arg, ";=@+%");
129 if (ptr && *ptr == '=') { /* Event name */
130 *ptr = '\0';
131 tmp = ptr + 1;
132 ptr = strchr(arg, ':');
133 if (ptr) /* Group name is not supported yet. */
134 semantic_error("Group name is not supported yet.");
135 if (!check_event_name(arg))
136 semantic_error("%s is bad for event name -it must "
137 "follow C symbol-naming rule.", arg);
138 pp->event = strdup(arg);
139 arg = tmp;
140 }
141
142 ptr = strpbrk(arg, ";:+@%");
143 if (ptr) {
144 nc = *ptr;
145 *ptr++ = '\0';
146 }
147
148 /* Check arg is function or file and copy it */
149 if (strchr(arg, '.')) /* File */
150 pp->file = strdup(arg);
151 else /* Function */
152 pp->function = strdup(arg);
153 DIE_IF(pp->file == NULL && pp->function == NULL);
154
155 /* Parse other options */
156 while (ptr) {
157 arg = ptr;
158 c = nc;
159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
164 if (ptr) {
165 nc = *ptr;
166 *ptr++ = '\0';
167 }
168 switch (c) {
169 case ':': /* Line number */
170 pp->line = strtoul(arg, &tmp, 0);
171 if (*tmp != '\0')
172 semantic_error("There is non-digit char"
173 " in line number.");
174 break;
175 case '+': /* Byte offset from a symbol */
176 pp->offset = strtoul(arg, &tmp, 0);
177 if (*tmp != '\0')
178 semantic_error("There is non-digit character"
179 " in offset.");
180 break;
181 case '@': /* File name */
182 if (pp->file)
183 semantic_error("SRC@SRC is not allowed.");
184 pp->file = strdup(arg);
185 DIE_IF(pp->file == NULL);
186 break;
187 case '%': /* Probe places */
188 if (strcmp(arg, "return") == 0) {
189 pp->retprobe = 1;
190 } else /* Others not supported yet */
191 semantic_error("%%%s is not supported.", arg);
192 break;
193 default:
194 DIE_IF("Program has a bug.");
195 break;
196 }
197 }
198
199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
206 if (pp->line && pp->offset)
207 semantic_error("Offset can't be used with line number.");
208
209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
210 semantic_error("File always requires line number or "
211 "lazy pattern.");
212
213 if (pp->offset && !pp->function)
214 semantic_error("Offset requires an entry function.");
215
216 if (pp->retprobe && !pp->function)
217 semantic_error("Return probe requires an entry function.");
218
219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
222
223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
226}
227
228/* Parse perf-probe event definition */
229void parse_perf_probe_event(const char *str, struct probe_point *pp,
230 bool *need_dwarf)
231{
232 char **argv;
233 int argc, i;
234
235 *need_dwarf = false;
236
237 argv = argv_split(str, &argc);
238 if (!argv)
239 die("argv_split failed.");
240 if (argc > MAX_PROBE_ARGS + 1)
241 semantic_error("Too many arguments");
242
243 /* Parse probe point */
244 parse_perf_probe_probepoint(argv[0], pp);
245 if (pp->file || pp->line)
246 *need_dwarf = true;
247
248 /* Copy arguments and ensure return probe has no C argument */
249 pp->nr_args = argc - 1;
250 pp->args = zalloc(sizeof(char *) * pp->nr_args);
251 for (i = 0; i < pp->nr_args; i++) {
252 pp->args[i] = strdup(argv[i + 1]);
253 if (!pp->args[i])
254 die("Failed to copy argument.");
255 if (is_c_varname(pp->args[i])) {
256 if (pp->retprobe)
257 semantic_error("You can't specify local"
258 " variable for kretprobe");
259 *need_dwarf = true;
260 }
261 }
262
263 argv_free(argv);
264}
265
266/* Parse kprobe_events event into struct probe_point */
267void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
268{
269 char pr;
270 char *p;
271 int ret, i, argc;
272 char **argv;
273
274 pr_debug("Parsing kprobe_events: %s\n", str);
275 argv = argv_split(str, &argc);
276 if (!argv)
277 die("argv_split failed.");
278 if (argc < 2)
279 semantic_error("Too less arguments.");
280
281 /* Scan event and group name. */
282 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
283 &pr, (float *)(void *)&pp->group,
284 (float *)(void *)&pp->event);
285 if (ret != 3)
286 semantic_error("Failed to parse event name: %s", argv[0]);
287 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
288
289 pp->retprobe = (pr == 'r');
290
291 /* Scan function name and offset */
292 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
293 &pp->offset);
294 if (ret == 1)
295 pp->offset = 0;
296
297 /* kprobe_events doesn't have this information */
298 pp->line = 0;
299 pp->file = NULL;
300
301 pp->nr_args = argc - 2;
302 pp->args = zalloc(sizeof(char *) * pp->nr_args);
303 for (i = 0; i < pp->nr_args; i++) {
304 p = strchr(argv[i + 2], '=');
305 if (p) /* We don't need which register is assigned. */
306 *p = '\0';
307 pp->args[i] = strdup(argv[i + 2]);
308 if (!pp->args[i])
309 die("Failed to copy argument.");
310 }
311
312 argv_free(argv);
313}
314
315/* Synthesize only probe point (not argument) */
316int synthesize_perf_probe_point(struct probe_point *pp)
317{
318 char *buf;
319 char offs[64] = "", line[64] = "";
320 int ret;
321
322 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
323 pp->found = 1;
324 if (!buf)
325 die("Failed to allocate memory by zalloc.");
326 if (pp->offset) {
327 ret = e_snprintf(offs, 64, "+%d", pp->offset);
328 if (ret <= 0)
329 goto error;
330 }
331 if (pp->line) {
332 ret = e_snprintf(line, 64, ":%d", pp->line);
333 if (ret <= 0)
334 goto error;
335 }
336
337 if (pp->function)
338 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
339 offs, pp->retprobe ? "%return" : "", line);
340 else
341 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
342 if (ret <= 0) {
343error:
344 free(pp->probes[0]);
345 pp->probes[0] = NULL;
346 pp->found = 0;
347 }
348 return ret;
349}
350
351int synthesize_perf_probe_event(struct probe_point *pp)
352{
353 char *buf;
354 int i, len, ret;
355
356 len = synthesize_perf_probe_point(pp);
357 if (len < 0)
358 return 0;
359
360 buf = pp->probes[0];
361 for (i = 0; i < pp->nr_args; i++) {
362 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
363 pp->args[i]);
364 if (ret <= 0)
365 goto error;
366 len += ret;
367 }
368 pp->found = 1;
369
370 return pp->found;
371error:
372 free(pp->probes[0]);
373 pp->probes[0] = NULL;
374
375 return ret;
376}
377
378int synthesize_trace_kprobe_event(struct probe_point *pp)
379{
380 char *buf;
381 int i, len, ret;
382
383 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
384 if (!buf)
385 die("Failed to allocate memory by zalloc.");
386 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
387 if (ret <= 0)
388 goto error;
389 len = ret;
390
391 for (i = 0; i < pp->nr_args; i++) {
392 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
393 pp->args[i]);
394 if (ret <= 0)
395 goto error;
396 len += ret;
397 }
398 pp->found = 1;
399
400 return pp->found;
401error:
402 free(pp->probes[0]);
403 pp->probes[0] = NULL;
404
405 return ret;
406}
407
408static int open_kprobe_events(int flags, int mode)
409{
410 char buf[PATH_MAX];
411 int ret;
412
413 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
414 if (ret < 0)
415 die("Failed to make kprobe_events path.");
416
417 ret = open(buf, flags, mode);
418 if (ret < 0) {
419 if (errno == ENOENT)
420 die("kprobe_events file does not exist -"
421 " please rebuild with CONFIG_KPROBE_EVENT.");
422 else
423 die("Could not open kprobe_events file: %s",
424 strerror(errno));
425 }
426 return ret;
427}
428
429/* Get raw string list of current kprobe_events */
430static struct strlist *get_trace_kprobe_event_rawlist(int fd)
431{
432 int ret, idx;
433 FILE *fp;
434 char buf[MAX_CMDLEN];
435 char *p;
436 struct strlist *sl;
437
438 sl = strlist__new(true, NULL);
439
440 fp = fdopen(dup(fd), "r");
441 while (!feof(fp)) {
442 p = fgets(buf, MAX_CMDLEN, fp);
443 if (!p)
444 break;
445
446 idx = strlen(p) - 1;
447 if (p[idx] == '\n')
448 p[idx] = '\0';
449 ret = strlist__add(sl, buf);
450 if (ret < 0)
451 die("strlist__add failed: %s", strerror(-ret));
452 }
453 fclose(fp);
454
455 return sl;
456}
457
458/* Free and zero clear probe_point */
459static void clear_probe_point(struct probe_point *pp)
460{
461 int i;
462
463 if (pp->event)
464 free(pp->event);
465 if (pp->group)
466 free(pp->group);
467 if (pp->function)
468 free(pp->function);
469 if (pp->file)
470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
473 for (i = 0; i < pp->nr_args; i++)
474 free(pp->args[i]);
475 if (pp->args)
476 free(pp->args);
477 for (i = 0; i < pp->found; i++)
478 free(pp->probes[i]);
479 memset(pp, 0, sizeof(*pp));
480}
481
482/* Show an event */
483static void show_perf_probe_event(const char *event, const char *place,
484 struct probe_point *pp)
485{
486 int i, ret;
487 char buf[128];
488
489 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
490 if (ret < 0)
491 die("Failed to copy event: %s", strerror(-ret));
492 printf(" %-40s (on %s", buf, place);
493
494 if (pp->nr_args > 0) {
495 printf(" with");
496 for (i = 0; i < pp->nr_args; i++)
497 printf(" %s", pp->args[i]);
498 }
499 printf(")\n");
500}
501
502/* List up current perf-probe events */
503void show_perf_probe_events(void)
504{
505 int fd;
506 struct probe_point pp;
507 struct strlist *rawlist;
508 struct str_node *ent;
509
510 setup_pager();
511 memset(&pp, 0, sizeof(pp));
512
513 fd = open_kprobe_events(O_RDONLY, 0);
514 rawlist = get_trace_kprobe_event_rawlist(fd);
515 close(fd);
516
517 strlist__for_each(ent, rawlist) {
518 parse_trace_kprobe_event(ent->s, &pp);
519 /* Synthesize only event probe point */
520 synthesize_perf_probe_point(&pp);
521 /* Show an event */
522 show_perf_probe_event(pp.event, pp.probes[0], &pp);
523 clear_probe_point(&pp);
524 }
525
526 strlist__delete(rawlist);
527}
528
529/* Get current perf-probe event names */
530static struct strlist *get_perf_event_names(int fd, bool include_group)
531{
532 char buf[128];
533 struct strlist *sl, *rawlist;
534 struct str_node *ent;
535 struct probe_point pp;
536
537 memset(&pp, 0, sizeof(pp));
538 rawlist = get_trace_kprobe_event_rawlist(fd);
539
540 sl = strlist__new(true, NULL);
541 strlist__for_each(ent, rawlist) {
542 parse_trace_kprobe_event(ent->s, &pp);
543 if (include_group) {
544 if (e_snprintf(buf, 128, "%s:%s", pp.group,
545 pp.event) < 0)
546 die("Failed to copy group:event name.");
547 strlist__add(sl, buf);
548 } else
549 strlist__add(sl, pp.event);
550 clear_probe_point(&pp);
551 }
552
553 strlist__delete(rawlist);
554
555 return sl;
556}
557
558static void write_trace_kprobe_event(int fd, const char *buf)
559{
560 int ret;
561
562 pr_debug("Writing event: %s\n", buf);
563 ret = write(fd, buf, strlen(buf));
564 if (ret <= 0)
565 die("Failed to write event: %s", strerror(errno));
566}
567
568static void get_new_event_name(char *buf, size_t len, const char *base,
569 struct strlist *namelist, bool allow_suffix)
570{
571 int i, ret;
572
573 /* Try no suffix */
574 ret = e_snprintf(buf, len, "%s", base);
575 if (ret < 0)
576 die("snprintf() failed: %s", strerror(-ret));
577 if (!strlist__has_entry(namelist, buf))
578 return;
579
580 if (!allow_suffix) {
581 pr_warning("Error: event \"%s\" already exists. "
582 "(Use -f to force duplicates.)\n", base);
583 die("Can't add new event.");
584 }
585
586 /* Try to add suffix */
587 for (i = 1; i < MAX_EVENT_INDEX; i++) {
588 ret = e_snprintf(buf, len, "%s_%d", base, i);
589 if (ret < 0)
590 die("snprintf() failed: %s", strerror(-ret));
591 if (!strlist__has_entry(namelist, buf))
592 break;
593 }
594 if (i == MAX_EVENT_INDEX)
595 die("Too many events are on the same function.");
596}
597
598void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
599 bool force_add)
600{
601 int i, j, fd;
602 struct probe_point *pp;
603 char buf[MAX_CMDLEN];
604 char event[64];
605 struct strlist *namelist;
606 bool allow_suffix;
607
608 fd = open_kprobe_events(O_RDWR, O_APPEND);
609 /* Get current event names */
610 namelist = get_perf_event_names(fd, false);
611
612 for (j = 0; j < nr_probes; j++) {
613 pp = probes + j;
614 if (!pp->event)
615 pp->event = strdup(pp->function);
616 if (!pp->group)
617 pp->group = strdup(PERFPROBE_GROUP);
618 DIE_IF(!pp->event || !pp->group);
619 /* If force_add is true, suffix search is allowed */
620 allow_suffix = force_add;
621 for (i = 0; i < pp->found; i++) {
622 /* Get an unused new event name */
623 get_new_event_name(event, 64, pp->event, namelist,
624 allow_suffix);
625 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
626 pp->retprobe ? 'r' : 'p',
627 pp->group, event,
628 pp->probes[i]);
629 write_trace_kprobe_event(fd, buf);
630 printf("Added new event:\n");
631 /* Get the first parameter (probe-point) */
632 sscanf(pp->probes[i], "%s", buf);
633 show_perf_probe_event(event, buf, pp);
634 /* Add added event name to namelist */
635 strlist__add(namelist, event);
636 /*
637 * Probes after the first probe which comes from same
638 * user input are always allowed to add suffix, because
639 * there might be several addresses corresponding to
640 * one code line.
641 */
642 allow_suffix = true;
643 }
644 }
645 /* Show how to use the event. */
646 printf("\nYou can now use it on all perf tools, such as:\n\n");
647 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
648
649 strlist__delete(namelist);
650 close(fd);
651}
652
653static void __del_trace_kprobe_event(int fd, struct str_node *ent)
654{
655 char *p;
656 char buf[128];
657
658 /* Convert from perf-probe event to trace-kprobe event */
659 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
660 die("Failed to copy event.");
661 p = strchr(buf + 2, ':');
662 if (!p)
663 die("Internal error: %s should have ':' but not.", ent->s);
664 *p = '/';
665
666 write_trace_kprobe_event(fd, buf);
667 printf("Remove event: %s\n", ent->s);
668}
669
670static void del_trace_kprobe_event(int fd, const char *group,
671 const char *event, struct strlist *namelist)
672{
673 char buf[128];
674 struct str_node *ent, *n;
675 int found = 0;
676
677 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
678 die("Failed to copy event.");
679
680 if (strpbrk(buf, "*?")) { /* Glob-exp */
681 strlist__for_each_safe(ent, n, namelist)
682 if (strglobmatch(ent->s, buf)) {
683 found++;
684 __del_trace_kprobe_event(fd, ent);
685 strlist__remove(namelist, ent);
686 }
687 } else {
688 ent = strlist__find(namelist, buf);
689 if (ent) {
690 found++;
691 __del_trace_kprobe_event(fd, ent);
692 strlist__remove(namelist, ent);
693 }
694 }
695 if (found == 0)
696 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
697}
698
699void del_trace_kprobe_events(struct strlist *dellist)
700{
701 int fd;
702 const char *group, *event;
703 char *p, *str;
704 struct str_node *ent;
705 struct strlist *namelist;
706
707 fd = open_kprobe_events(O_RDWR, O_APPEND);
708 /* Get current event names */
709 namelist = get_perf_event_names(fd, true);
710
711 strlist__for_each(ent, dellist) {
712 str = strdup(ent->s);
713 if (!str)
714 die("Failed to copy event.");
715 pr_debug("Parsing: %s\n", str);
716 p = strchr(str, ':');
717 if (p) {
718 group = str;
719 *p = '\0';
720 event = p + 1;
721 } else {
722 group = "*";
723 event = str;
724 }
725 pr_debug("Group: %s, Event: %s\n", group, event);
726 del_trace_kprobe_event(fd, group, event, namelist);
727 free(str);
728 }
729 strlist__delete(namelist);
730 close(fd);
731}
732
733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
735
736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
737{
738 char buf[LINEBUF_SIZE];
739 const char *color = PERF_COLOR_BLUE;
740
741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
742 goto error;
743 if (!skip) {
744 if (show_num)
745 fprintf(stdout, "%7u %s", l, buf);
746 else
747 color_fprintf(stdout, color, " %s", buf);
748 }
749
750 while (strlen(buf) == LINEBUF_SIZE - 1 &&
751 buf[LINEBUF_SIZE - 2] != '\n') {
752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
753 goto error;
754 if (!skip) {
755 if (show_num)
756 fprintf(stdout, "%s", buf);
757 else
758 color_fprintf(stdout, color, "%s", buf);
759 }
760 }
761 return;
762error:
763 if (feof(fp))
764 die("Source file is shorter than expected.");
765 else
766 die("File read error: %s", strerror(errno));
767}
768
769void show_line_range(struct line_range *lr)
770{
771 unsigned int l = 1;
772 struct line_node *ln;
773 FILE *fp;
774
775 setup_pager();
776
777 if (lr->function)
778 fprintf(stdout, "<%s:%d>\n", lr->function,
779 lr->start - lr->offset);
780 else
781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
782
783 fp = fopen(lr->path, "r");
784 if (fp == NULL)
785 die("Failed to open %s: %s", lr->path, strerror(errno));
786 /* Skip to starting line number */
787 while (l < lr->start)
788 show_one_line(fp, l++, true, false);
789
790 list_for_each_entry(ln, &lr->line_list, list) {
791 while (ln->line > l)
792 show_one_line(fp, (l++) - lr->offset, false, false);
793 show_one_line(fp, (l++) - lr->offset, false, true);
794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
801 fclose(fp);
802}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..711287d4baea
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,24 @@
1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H
3
4#include <stdbool.h>
5#include "probe-finder.h"
6#include "strlist.h"
7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
10 bool *need_dwarf);
11extern int synthesize_perf_probe_point(struct probe_point *pp);
12extern int synthesize_perf_probe_event(struct probe_point *pp);
13extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
14extern int synthesize_trace_kprobe_event(struct probe_point *pp);
15extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
16 bool force_add);
17extern void del_trace_kprobe_events(struct strlist *dellist);
18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
20
21/* Maximum index number of event-name postfix */
22#define MAX_EVENT_INDEX 1024
23
24#endif /*_PROBE_EVENT_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
new file mode 100644
index 000000000000..e77dc886760e
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,833 @@
1/*
2 * probe-finder.c : C expression to kprobe event converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <sys/utsname.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <ctype.h>
34
35#include "string.h"
36#include "event.h"
37#include "debug.h"
38#include "util.h"
39#include "probe-finder.h"
40
41
42/*
43 * Generic dwarf analysis helpers
44 */
45
46#define X86_32_MAX_REGS 8
47const char *x86_32_regs_table[X86_32_MAX_REGS] = {
48 "%ax",
49 "%cx",
50 "%dx",
51 "%bx",
52 "$stack", /* Stack address instead of %sp */
53 "%bp",
54 "%si",
55 "%di",
56};
57
58#define X86_64_MAX_REGS 16
59const char *x86_64_regs_table[X86_64_MAX_REGS] = {
60 "%ax",
61 "%dx",
62 "%cx",
63 "%bx",
64 "%si",
65 "%di",
66 "%bp",
67 "%sp",
68 "%r8",
69 "%r9",
70 "%r10",
71 "%r11",
72 "%r12",
73 "%r13",
74 "%r14",
75 "%r15",
76};
77
78/* TODO: switching by dwarf address size */
79#ifdef __x86_64__
80#define ARCH_MAX_REGS X86_64_MAX_REGS
81#define arch_regs_table x86_64_regs_table
82#else
83#define ARCH_MAX_REGS X86_32_MAX_REGS
84#define arch_regs_table x86_32_regs_table
85#endif
86
87/* Return architecture dependent register string (for kprobe-tracer) */
88static const char *get_arch_regstr(unsigned int n)
89{
90 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
91}
92
93/*
94 * Compare the tail of two strings.
95 * Return 0 if whole of either string is same as another's tail part.
96 */
97static int strtailcmp(const char *s1, const char *s2)
98{
99 int i1 = strlen(s1);
100 int i2 = strlen(s2);
101 while (--i1 >= 0 && --i2 >= 0) {
102 if (s1[i1] != s2[i2])
103 return s1[i1] - s2[i2];
104 }
105 return 0;
106}
107
108/* Line number list operations */
109
110/* Add a line to line number list */
111static void line_list__add_line(struct list_head *head, unsigned int line)
112{
113 struct line_node *ln;
114 struct list_head *p;
115
116 /* Reverse search, because new line will be the last one */
117 list_for_each_entry_reverse(ln, head, list) {
118 if (ln->line < line) {
119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
123 }
124 /* List is empty, or the smallest entry */
125 p = head;
126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
133}
134
135/* Check if the line in line number list */
136static int line_list__has_line(struct list_head *head, unsigned int line)
137{
138 struct line_node *ln;
139
140 /* Reverse search, because new line will be the last one */
141 list_for_each_entry(ln, head, list)
142 if (ln->line == line)
143 return 1;
144
145 return 0;
146}
147
148/* Init line number list */
149static void line_list__init(struct list_head *head)
150{
151 INIT_LIST_HEAD(head);
152}
153
154/* Free line number list */
155static void line_list__free(struct list_head *head)
156{
157 struct line_node *ln;
158 while (!list_empty(head)) {
159 ln = list_first_entry(head, struct line_node, list);
160 list_del(&ln->list);
161 free(ln);
162 }
163}
164
165/* Dwarf wrappers */
166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
169{
170 Dwarf_Files *files;
171 size_t nfiles, i;
172 const char *src;
173 int ret;
174
175 if (!fname)
176 return NULL;
177
178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
179 if (ret != 0)
180 return NULL;
181
182 for (i = 0; i < nfiles; i++) {
183 src = dwarf_filesrc(files, i, NULL, NULL);
184 if (strtailcmp(src, fname) == 0)
185 break;
186 }
187 return src;
188}
189
190struct __addr_die_search_param {
191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
196{
197 struct __addr_die_search_param *ad = data;
198
199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
200 dwarf_haspc(fn_die, ad->addr)) {
201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
202 return DWARF_CB_ABORT;
203 }
204 return DWARF_CB_OK;
205}
206
207/* Search a real subprogram including this line, */
208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
209 Dwarf_Die *die_mem)
210{
211 struct __addr_die_search_param ad;
212 ad.addr = addr;
213 ad.die_mem = die_mem;
214 /* dwarf_getscopes can't find subprogram. */
215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
216 return NULL;
217 else
218 return die_mem;
219}
220
221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
223 Dwarf_Die *die_mem)
224{
225 Dwarf_Die child_die;
226 int ret;
227
228 ret = dwarf_child(sp_die, die_mem);
229 if (ret != 0)
230 return NULL;
231
232 do {
233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
234 dwarf_haspc(die_mem, addr))
235 return die_mem;
236
237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
239 return die_mem;
240 }
241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
242
243 return NULL;
244}
245
246/* Compare diename and tname */
247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
248{
249 const char *name;
250 name = dwarf_diename(dw_die);
251 DIE_IF(name == NULL);
252 return strcmp(tname, name);
253}
254
255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
257{
258 Dwarf_Addr epc;
259 int ret;
260
261 ret = dwarf_entrypc(dw_die, &epc);
262 DIE_IF(ret == -1);
263 return epc;
264}
265
266/* Get a variable die */
267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
269{
270 Dwarf_Die child_die;
271 int tag;
272 int ret;
273
274 ret = dwarf_child(sp_die, die_mem);
275 if (ret != 0)
276 return NULL;
277
278 do {
279 tag = dwarf_tag(die_mem);
280 if ((tag == DW_TAG_formal_parameter ||
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284
285 if (die_find_variable(die_mem, name, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290
291 return NULL;
292}
293
294/*
295 * Probe finder related functions
296 */
297
298/* Show a location */
299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
300{
301 unsigned int regn;
302 Dwarf_Word offs = 0;
303 int deref = 0, ret;
304 const char *regs;
305
306 /* TODO: support CFA */
307 /* If this is based on frame buffer, set the offset */
308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
311 deref = 1;
312 offs = op->number;
313 op = &pf->fb_ops[0];
314 }
315
316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
317 regn = op->atom - DW_OP_breg0;
318 offs += op->number;
319 deref = 1;
320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
321 regn = op->atom - DW_OP_reg0;
322 } else if (op->atom == DW_OP_bregx) {
323 regn = op->number;
324 offs += op->number2;
325 deref = 1;
326 } else if (op->atom == DW_OP_regx) {
327 regn = op->number;
328 } else
329 die("DW_OP %d is not supported.", op->atom);
330
331 regs = get_arch_regstr(regn);
332 if (!regs)
333 die("%u exceeds max register number.", regn);
334
335 if (deref)
336 ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)",
337 pf->var, (uintmax_t)offs, regs);
338 else
339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
340 DIE_IF(ret < 0);
341 DIE_IF(ret >= pf->len);
342}
343
344/* Show a variables in kprobe event format */
345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
346{
347 Dwarf_Attribute attr;
348 Dwarf_Op *expr;
349 size_t nexpr;
350 int ret;
351
352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
353 goto error;
354 /* TODO: handle more than 1 exprs */
355 ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base),
356 &expr, &nexpr, 1);
357 if (ret <= 0 || nexpr == 0)
358 goto error;
359
360 show_location(expr, pf);
361 /* *expr will be cached in libdw. Don't free it. */
362 return ;
363error:
364 /* TODO: Support const_value */
365 die("Failed to find the location of %s at this address.\n"
366 " Perhaps, it has been optimized out.", pf->var);
367}
368
369/* Find a variable in a subprogram die */
370static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
371{
372 int ret;
373 Dwarf_Die vr_die;
374
375 /* TODO: Support struct members and arrays */
376 if (!is_c_varname(pf->var)) {
377 /* Output raw parameters */
378 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
379 DIE_IF(ret < 0);
380 DIE_IF(ret >= pf->len);
381 return ;
382 }
383
384 pr_debug("Searching '%s' variable in context.\n", pf->var);
385 /* Search child die for local variables and parameters. */
386 if (!die_find_variable(sp_die, pf->var, &vr_die))
387 die("Failed to find '%s' in this function.", pf->var);
388
389 show_variable(&vr_die, pf);
390}
391
392/* Show a probe point to output buffer */
393static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
394{
395 struct probe_point *pp = pf->pp;
396 Dwarf_Addr eaddr;
397 Dwarf_Die die_mem;
398 const char *name;
399 char tmp[MAX_PROBE_BUFFER];
400 int ret, i, len;
401 Dwarf_Attribute fb_attr;
402 size_t nops;
403
404 /* If no real subprogram, find a real one */
405 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
406 sp_die = die_get_real_subprogram(&pf->cu_die,
407 pf->addr, &die_mem);
408 if (!sp_die)
409 die("Probe point is not found in subprograms.");
410 }
411
412 /* Output name of probe point */
413 name = dwarf_diename(sp_die);
414 if (name) {
415 dwarf_entrypc(sp_die, &eaddr);
416 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
417 (unsigned long)(pf->addr - eaddr));
418 /* Copy the function name if possible */
419 if (!pp->function) {
420 pp->function = strdup(name);
421 pp->offset = (size_t)(pf->addr - eaddr);
422 }
423 } else {
424 /* This function has no name. */
425 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
426 (uintmax_t)pf->addr);
427 if (!pp->function) {
428 /* TODO: Use _stext */
429 pp->function = strdup("");
430 pp->offset = (size_t)pf->addr;
431 }
432 }
433 DIE_IF(ret < 0);
434 DIE_IF(ret >= MAX_PROBE_BUFFER);
435 len = ret;
436 pr_debug("Probe point found: %s\n", tmp);
437
438 /* Get the frame base attribute/ops */
439 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
440 ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base),
441 &pf->fb_ops, &nops, 1);
442 if (ret <= 0 || nops == 0)
443 pf->fb_ops = NULL;
444
445 /* Find each argument */
446 /* TODO: use dwarf_cfi_addrframe */
447 for (i = 0; i < pp->nr_args; i++) {
448 pf->var = pp->args[i];
449 pf->buf = &tmp[len];
450 pf->len = MAX_PROBE_BUFFER - len;
451 find_variable(sp_die, pf);
452 len += strlen(pf->buf);
453 }
454
455 /* *pf->fb_ops will be cached in libdw. Don't free it. */
456 pf->fb_ops = NULL;
457
458 pp->probes[pp->found] = strdup(tmp);
459 pp->found++;
460}
461
462/* Find probe point from its line number */
463static void find_probe_point_by_line(struct probe_finder *pf)
464{
465 Dwarf_Lines *lines;
466 Dwarf_Line *line;
467 size_t nlines, i;
468 Dwarf_Addr addr;
469 int lineno;
470 int ret;
471
472 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
473 DIE_IF(ret != 0);
474
475 for (i = 0; i < nlines; i++) {
476 line = dwarf_onesrcline(lines, i);
477 dwarf_lineno(line, &lineno);
478 if (lineno != pf->lno)
479 continue;
480
481 /* TODO: Get fileno from line, but how? */
482 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
483 continue;
484
485 ret = dwarf_lineaddr(line, &addr);
486 DIE_IF(ret != 0);
487 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
488 (int)i, lineno, (uintmax_t)addr);
489 pf->addr = addr;
490
491 show_probe_point(NULL, pf);
492 /* Continuing, because target line might be inlined. */
493 }
494}
495
496/* Find lines which match lazy pattern */
497static int find_lazy_match_lines(struct list_head *head,
498 const char *fname, const char *pat)
499{
500 char *fbuf, *p1, *p2;
501 int fd, line, nlines = 0;
502 struct stat st;
503
504 fd = open(fname, O_RDONLY);
505 if (fd < 0)
506 die("failed to open %s", fname);
507 DIE_IF(fstat(fd, &st) < 0);
508 fbuf = malloc(st.st_size + 2);
509 DIE_IF(fbuf == NULL);
510 DIE_IF(read(fd, fbuf, st.st_size) < 0);
511 close(fd);
512 fbuf[st.st_size] = '\n'; /* Dummy line */
513 fbuf[st.st_size + 1] = '\0';
514 p1 = fbuf;
515 line = 1;
516 while ((p2 = strchr(p1, '\n')) != NULL) {
517 *p2 = '\0';
518 if (strlazymatch(p1, pat)) {
519 line_list__add_line(head, line);
520 nlines++;
521 }
522 line++;
523 p1 = p2 + 1;
524 }
525 free(fbuf);
526 return nlines;
527}
528
529/* Find probe points from lazy pattern */
530static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
531{
532 Dwarf_Lines *lines;
533 Dwarf_Line *line;
534 size_t nlines, i;
535 Dwarf_Addr addr;
536 Dwarf_Die die_mem;
537 int lineno;
538 int ret;
539
540 if (list_empty(&pf->lcache)) {
541 /* Matching lazy line pattern */
542 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
543 pf->pp->lazy_line);
544 if (ret <= 0)
545 die("No matched lines found in %s.", pf->fname);
546 }
547
548 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
549 DIE_IF(ret != 0);
550 for (i = 0; i < nlines; i++) {
551 line = dwarf_onesrcline(lines, i);
552
553 dwarf_lineno(line, &lineno);
554 if (!line_list__has_line(&pf->lcache, lineno))
555 continue;
556
557 /* TODO: Get fileno from line, but how? */
558 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
559 continue;
560
561 ret = dwarf_lineaddr(line, &addr);
562 DIE_IF(ret != 0);
563 if (sp_die) {
564 /* Address filtering 1: does sp_die include addr? */
565 if (!dwarf_haspc(sp_die, addr))
566 continue;
567 /* Address filtering 2: No child include addr? */
568 if (die_get_inlinefunc(sp_die, addr, &die_mem))
569 continue;
570 }
571
572 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
573 (int)i, lineno, (unsigned long long)addr);
574 pf->addr = addr;
575
576 show_probe_point(sp_die, pf);
577 /* Continuing, because target line might be inlined. */
578 }
579 /* TODO: deallocate lines, but how? */
580}
581
582static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
583{
584 struct probe_finder *pf = (struct probe_finder *)data;
585 struct probe_point *pp = pf->pp;
586
587 if (pp->lazy_line)
588 find_probe_point_lazy(in_die, pf);
589 else {
590 /* Get probe address */
591 pf->addr = die_get_entrypc(in_die);
592 pf->addr += pp->offset;
593 pr_debug("found inline addr: 0x%jx\n",
594 (uintmax_t)pf->addr);
595
596 show_probe_point(in_die, pf);
597 }
598
599 return DWARF_CB_OK;
600}
601
602/* Search function from function name */
603static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
604{
605 struct probe_finder *pf = (struct probe_finder *)data;
606 struct probe_point *pp = pf->pp;
607
608 /* Check tag and diename */
609 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
610 die_compare_name(sp_die, pp->function) != 0)
611 return 0;
612
613 pf->fname = dwarf_decl_file(sp_die);
614 if (pp->line) { /* Function relative line */
615 dwarf_decl_line(sp_die, &pf->lno);
616 pf->lno += pp->line;
617 find_probe_point_by_line(pf);
618 } else if (!dwarf_func_inline(sp_die)) {
619 /* Real function */
620 if (pp->lazy_line)
621 find_probe_point_lazy(sp_die, pf);
622 else {
623 pf->addr = die_get_entrypc(sp_die);
624 pf->addr += pp->offset;
625 /* TODO: Check the address in this function */
626 show_probe_point(sp_die, pf);
627 }
628 } else
629 /* Inlined function: search instances */
630 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
631
632 return 1; /* Exit; no same symbol in this CU. */
633}
634
635static void find_probe_point_by_func(struct probe_finder *pf)
636{
637 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
638}
639
640/* Find a probe point */
641int find_probe_point(int fd, struct probe_point *pp)
642{
643 struct probe_finder pf = {.pp = pp};
644 int ret;
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
649
650 dbg = dwarf_begin(fd, DWARF_C_READ);
651 if (!dbg)
652 return -ENOENT;
653
654 pp->found = 0;
655 off = 0;
656 line_list__init(&pf.lcache);
657 /* Loop on CUs (Compilation Unit) */
658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
659 /* Get the DIE(Debugging Information Entry) of this CU */
660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
661 if (!diep)
662 continue;
663
664 /* Check if target file is included. */
665 if (pp->file)
666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
667 else
668 pf.fname = NULL;
669
670 if (!pp->file || pf.fname) {
671 /* Save CU base address (for frame_base) */
672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
673 if (ret != 0)
674 pf.cu_base = 0;
675 if (pp->function)
676 find_probe_point_by_func(&pf);
677 else if (pp->lazy_line)
678 find_probe_point_lazy(NULL, &pf);
679 else {
680 pf.lno = pp->line;
681 find_probe_point_by_line(&pf);
682 }
683 }
684 off = noff;
685 }
686 line_list__free(&pf.lcache);
687 dwarf_end(dbg);
688
689 return pp->found;
690}
691
692/* Find line range from its line number */
693static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
694{
695 Dwarf_Lines *lines;
696 Dwarf_Line *line;
697 size_t nlines, i;
698 Dwarf_Addr addr;
699 int lineno;
700 int ret;
701 const char *src;
702 Dwarf_Die die_mem;
703
704 line_list__init(&lf->lr->line_list);
705 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
706 DIE_IF(ret != 0);
707
708 for (i = 0; i < nlines; i++) {
709 line = dwarf_onesrcline(lines, i);
710 ret = dwarf_lineno(line, &lineno);
711 DIE_IF(ret != 0);
712 if (lf->lno_s > lineno || lf->lno_e < lineno)
713 continue;
714
715 if (sp_die) {
716 /* Address filtering 1: does sp_die include addr? */
717 ret = dwarf_lineaddr(line, &addr);
718 DIE_IF(ret != 0);
719 if (!dwarf_haspc(sp_die, addr))
720 continue;
721
722 /* Address filtering 2: No child include addr? */
723 if (die_get_inlinefunc(sp_die, addr, &die_mem))
724 continue;
725 }
726
727 /* TODO: Get fileno from line, but how? */
728 src = dwarf_linesrc(line, NULL, NULL);
729 if (strtailcmp(src, lf->fname) != 0)
730 continue;
731
732 /* Copy real path */
733 if (!lf->lr->path)
734 lf->lr->path = strdup(src);
735 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
736 }
737 /* Update status */
738 if (!list_empty(&lf->lr->line_list))
739 lf->found = 1;
740 else {
741 free(lf->lr->path);
742 lf->lr->path = NULL;
743 }
744}
745
746static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
747{
748 find_line_range_by_line(in_die, (struct line_finder *)data);
749 return DWARF_CB_ABORT; /* No need to find other instances */
750}
751
752/* Search function from function name */
753static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
754{
755 struct line_finder *lf = (struct line_finder *)data;
756 struct line_range *lr = lf->lr;
757
758 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
759 die_compare_name(sp_die, lr->function) == 0) {
760 lf->fname = dwarf_decl_file(sp_die);
761 dwarf_decl_line(sp_die, &lr->offset);
762 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
763 lf->lno_s = lr->offset + lr->start;
764 if (!lr->end)
765 lf->lno_e = INT_MAX;
766 else
767 lf->lno_e = lr->offset + lr->end;
768 lr->start = lf->lno_s;
769 lr->end = lf->lno_e;
770 if (dwarf_func_inline(sp_die))
771 dwarf_func_inline_instances(sp_die,
772 line_range_inline_cb, lf);
773 else
774 find_line_range_by_line(sp_die, lf);
775 return 1;
776 }
777 return 0;
778}
779
780static void find_line_range_by_func(struct line_finder *lf)
781{
782 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
783}
784
785int find_line_range(int fd, struct line_range *lr)
786{
787 struct line_finder lf = {.lr = lr, .found = 0};
788 int ret;
789 Dwarf_Off off = 0, noff;
790 size_t cuhl;
791 Dwarf_Die *diep;
792 Dwarf *dbg;
793
794 dbg = dwarf_begin(fd, DWARF_C_READ);
795 if (!dbg)
796 return -ENOENT;
797
798 /* Loop on CUs (Compilation Unit) */
799 while (!lf.found) {
800 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
801 if (ret != 0)
802 break;
803
804 /* Get the DIE(Debugging Information Entry) of this CU */
805 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
806 if (!diep)
807 continue;
808
809 /* Check if target file is included. */
810 if (lr->file)
811 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
812 else
813 lf.fname = 0;
814
815 if (!lr->file || lf.fname) {
816 if (lr->function)
817 find_line_range_by_func(&lf);
818 else {
819 lf.lno_s = lr->start;
820 if (!lr->end)
821 lf.lno_e = INT_MAX;
822 else
823 lf.lno_e = lr->end;
824 find_line_range_by_line(NULL, &lf);
825 }
826 }
827 off = noff;
828 }
829 pr_debug("path: %lx\n", (unsigned long)lr->path);
830 dwarf_end(dbg);
831 return lf.found;
832}
833
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..d1a651793ba6
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,93 @@
1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H
3
4#include <stdbool.h>
5#include "util.h"
6
7#define MAX_PATH_LEN 256
8#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128
10
11static inline int is_c_varname(const char *name)
12{
13 /* TODO */
14 return isalpha(name[0]) || name[0] == '_';
15}
16
17struct probe_point {
18 char *event; /* Event name */
19 char *group; /* Event group */
20
21 /* Inputs */
22 char *file; /* File name */
23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
25
26 char *function; /* Function name */
27 int offset; /* Offset bytes */
28
29 int nr_args; /* Number of arguments */
30 char **args; /* Arguments */
31
32 int retprobe; /* Return probe */
33
34 /* Output */
35 int found; /* Number of found probe points */
36 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
37};
38
39/* Line number container */
40struct line_node {
41 struct list_head list;
42 unsigned int line;
43};
44
45/* Line range */
46struct line_range {
47 char *file; /* File name */
48 char *function; /* Function name */
49 unsigned int start; /* Start line number */
50 unsigned int end; /* End line number */
51 int offset; /* Start line offset */
52 char *path; /* Real path name */
53 struct list_head line_list; /* Visible lines */
54};
55
56#ifndef NO_DWARF_SUPPORT
57extern int find_probe_point(int fd, struct probe_point *pp);
58extern int find_line_range(int fd, struct line_range *lr);
59
60#include <dwarf.h>
61#include <libdw.h>
62
63struct probe_finder {
64 struct probe_point *pp; /* Target probe point */
65
66 /* For function searching */
67 Dwarf_Addr addr; /* Address */
68 const char *fname; /* File name */
69 int lno; /* Line number */
70 Dwarf_Die cu_die; /* Current CU */
71
72 /* For variable searching */
73 Dwarf_Op *fb_ops; /* Frame base attribute */
74 Dwarf_Addr cu_base; /* Current CU base address */
75 const char *var; /* Current variable name */
76 char *buf; /* Current output buffer */
77 int len; /* Length of output buffer */
78 struct list_head lcache; /* Line cache for lazy match */
79};
80
81struct line_finder {
82 struct line_range *lr; /* Target line range */
83
84 const char *fname; /* File name */
85 int lno_s; /* Start line number */
86 int lno_e; /* End line number */
87 Dwarf_Die cu_die; /* Current CU */
88 int found;
89};
90
91#endif /* NO_DWARF_SUPPORT */
92
93#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
1#ifndef QUOTE_H 1#ifndef __PERF_QUOTE_H
2#define QUOTE_H 2#define __PERF_QUOTE_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <stdio.h> 5#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src); 65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src); 66extern void tcl_quote_print(FILE *stream, const char *src);
67 67
68#endif 68#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
1#ifndef RUN_COMMAND_H 1#ifndef __PERF_RUN_COMMAND_H
2#define RUN_COMMAND_H 2#define __PERF_RUN_COMMAND_H
3 3
4enum { 4enum {
5 ERR_RUN_COMMAND_FORK = 10000, 5 ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
85int start_async(struct async *async); 85int start_async(struct async *async);
86int finish_async(struct async *async); 86int finish_async(struct async *async);
87 87
88#endif 88#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
new file mode 100644
index 000000000000..5376378e0cfc
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -0,0 +1,568 @@
1/*
2 * trace-event-perl. Feed perf trace events to an embedded Perl interpreter.
3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../../perf.h"
29#include "../util.h"
30#include "../trace-event.h"
31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
38
39void xs_init(pTHX);
40
41void xs_init(pTHX)
42{
43 const char *file = __FILE__;
44 dXSUB_SYS;
45
46 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
47 file);
48 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
49}
50
51INTERP my_perl;
52
53#define FTRACE_MAX_EVENT \
54 ((1 << (sizeof(unsigned short) * 8)) - 1)
55
56struct event *events[FTRACE_MAX_EVENT];
57
58extern struct scripting_context *scripting_context;
59
60static char *cur_field_name;
61static int zero_flag_atom;
62
63static void define_symbolic_value(const char *ev_name,
64 const char *field_name,
65 const char *field_value,
66 const char *field_str)
67{
68 unsigned long long value;
69 dSP;
70
71 value = eval_flag(field_value);
72
73 ENTER;
74 SAVETMPS;
75 PUSHMARK(SP);
76
77 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
78 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
79 XPUSHs(sv_2mortal(newSVuv(value)));
80 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
81
82 PUTBACK;
83 if (get_cv("main::define_symbolic_value", 0))
84 call_pv("main::define_symbolic_value", G_SCALAR);
85 SPAGAIN;
86 PUTBACK;
87 FREETMPS;
88 LEAVE;
89}
90
91static void define_symbolic_values(struct print_flag_sym *field,
92 const char *ev_name,
93 const char *field_name)
94{
95 define_symbolic_value(ev_name, field_name, field->value, field->str);
96 if (field->next)
97 define_symbolic_values(field->next, ev_name, field_name);
98}
99
100static void define_symbolic_field(const char *ev_name,
101 const char *field_name)
102{
103 dSP;
104
105 ENTER;
106 SAVETMPS;
107 PUSHMARK(SP);
108
109 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
110 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
111
112 PUTBACK;
113 if (get_cv("main::define_symbolic_field", 0))
114 call_pv("main::define_symbolic_field", G_SCALAR);
115 SPAGAIN;
116 PUTBACK;
117 FREETMPS;
118 LEAVE;
119}
120
121static void define_flag_value(const char *ev_name,
122 const char *field_name,
123 const char *field_value,
124 const char *field_str)
125{
126 unsigned long long value;
127 dSP;
128
129 value = eval_flag(field_value);
130
131 ENTER;
132 SAVETMPS;
133 PUSHMARK(SP);
134
135 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
136 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
137 XPUSHs(sv_2mortal(newSVuv(value)));
138 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
139
140 PUTBACK;
141 if (get_cv("main::define_flag_value", 0))
142 call_pv("main::define_flag_value", G_SCALAR);
143 SPAGAIN;
144 PUTBACK;
145 FREETMPS;
146 LEAVE;
147}
148
149static void define_flag_values(struct print_flag_sym *field,
150 const char *ev_name,
151 const char *field_name)
152{
153 define_flag_value(ev_name, field_name, field->value, field->str);
154 if (field->next)
155 define_flag_values(field->next, ev_name, field_name);
156}
157
158static void define_flag_field(const char *ev_name,
159 const char *field_name,
160 const char *delim)
161{
162 dSP;
163
164 ENTER;
165 SAVETMPS;
166 PUSHMARK(SP);
167
168 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
169 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
170 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
171
172 PUTBACK;
173 if (get_cv("main::define_flag_field", 0))
174 call_pv("main::define_flag_field", G_SCALAR);
175 SPAGAIN;
176 PUTBACK;
177 FREETMPS;
178 LEAVE;
179}
180
181static void define_event_symbols(struct event *event,
182 const char *ev_name,
183 struct print_arg *args)
184{
185 switch (args->type) {
186 case PRINT_NULL:
187 break;
188 case PRINT_ATOM:
189 define_flag_value(ev_name, cur_field_name, "0",
190 args->atom.atom);
191 zero_flag_atom = 0;
192 break;
193 case PRINT_FIELD:
194 if (cur_field_name)
195 free(cur_field_name);
196 cur_field_name = strdup(args->field.name);
197 break;
198 case PRINT_FLAGS:
199 define_event_symbols(event, ev_name, args->flags.field);
200 define_flag_field(ev_name, cur_field_name, args->flags.delim);
201 define_flag_values(args->flags.flags, ev_name, cur_field_name);
202 break;
203 case PRINT_SYMBOL:
204 define_event_symbols(event, ev_name, args->symbol.field);
205 define_symbolic_field(ev_name, cur_field_name);
206 define_symbolic_values(args->symbol.symbols, ev_name,
207 cur_field_name);
208 break;
209 case PRINT_STRING:
210 break;
211 case PRINT_TYPE:
212 define_event_symbols(event, ev_name, args->typecast.item);
213 break;
214 case PRINT_OP:
215 if (strcmp(args->op.op, ":") == 0)
216 zero_flag_atom = 1;
217 define_event_symbols(event, ev_name, args->op.left);
218 define_event_symbols(event, ev_name, args->op.right);
219 break;
220 default:
221 /* we should warn... */
222 return;
223 }
224
225 if (args->next)
226 define_event_symbols(event, ev_name, args->next);
227}
228
229static inline struct event *find_cache_event(int type)
230{
231 static char ev_name[256];
232 struct event *event;
233
234 if (events[type])
235 return events[type];
236
237 events[type] = event = trace_find_event(type);
238 if (!event)
239 return NULL;
240
241 sprintf(ev_name, "%s::%s", event->system, event->name);
242
243 define_event_symbols(event, ev_name, event->print_fmt.args);
244
245 return event;
246}
247
248static void perl_process_event(int cpu, void *data,
249 int size __unused,
250 unsigned long long nsecs, char *comm)
251{
252 struct format_field *field;
253 static char handler[256];
254 unsigned long long val;
255 unsigned long s, ns;
256 struct event *event;
257 int type;
258 int pid;
259
260 dSP;
261
262 type = trace_parse_common_type(data);
263
264 event = find_cache_event(type);
265 if (!event)
266 die("ug! no event found for type %d", type);
267
268 pid = trace_parse_common_pid(data);
269
270 sprintf(handler, "%s::%s", event->system, event->name);
271
272 s = nsecs / NSECS_PER_SEC;
273 ns = nsecs - s * NSECS_PER_SEC;
274
275 scripting_context->event_data = data;
276
277 ENTER;
278 SAVETMPS;
279 PUSHMARK(SP);
280
281 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
282 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
283 XPUSHs(sv_2mortal(newSVuv(cpu)));
284 XPUSHs(sv_2mortal(newSVuv(s)));
285 XPUSHs(sv_2mortal(newSVuv(ns)));
286 XPUSHs(sv_2mortal(newSViv(pid)));
287 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
288
289 /* common fields other than pid can be accessed via xsub fns */
290
291 for (field = event->format.fields; field; field = field->next) {
292 if (field->flags & FIELD_IS_STRING) {
293 int offset;
294 if (field->flags & FIELD_IS_DYNAMIC) {
295 offset = *(int *)(data + field->offset);
296 offset &= 0xffff;
297 } else
298 offset = field->offset;
299 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
300 } else { /* FIELD_IS_NUMERIC */
301 val = read_size(data + field->offset, field->size);
302 if (field->flags & FIELD_IS_SIGNED) {
303 XPUSHs(sv_2mortal(newSViv(val)));
304 } else {
305 XPUSHs(sv_2mortal(newSVuv(val)));
306 }
307 }
308 }
309
310 PUTBACK;
311
312 if (get_cv(handler, 0))
313 call_pv(handler, G_SCALAR);
314 else if (get_cv("main::trace_unhandled", 0)) {
315 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
316 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
317 XPUSHs(sv_2mortal(newSVuv(cpu)));
318 XPUSHs(sv_2mortal(newSVuv(nsecs)));
319 XPUSHs(sv_2mortal(newSViv(pid)));
320 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
321 call_pv("main::trace_unhandled", G_SCALAR);
322 }
323 SPAGAIN;
324 PUTBACK;
325 FREETMPS;
326 LEAVE;
327}
328
329static void run_start_sub(void)
330{
331 dSP; /* access to Perl stack */
332 PUSHMARK(SP);
333
334 if (get_cv("main::trace_begin", 0))
335 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
336}
337
338/*
339 * Start trace script
340 */
341static int perl_start_script(const char *script, int argc, const char **argv)
342{
343 const char **command_line;
344 int i, err = 0;
345
346 command_line = malloc((argc + 2) * sizeof(const char *));
347 command_line[0] = "";
348 command_line[1] = script;
349 for (i = 2; i < argc + 2; i++)
350 command_line[i] = argv[i - 2];
351
352 my_perl = perl_alloc();
353 perl_construct(my_perl);
354
355 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
356 (char **)NULL)) {
357 err = -1;
358 goto error;
359 }
360
361 if (perl_run(my_perl)) {
362 err = -1;
363 goto error;
364 }
365
366 if (SvTRUE(ERRSV)) {
367 err = -1;
368 goto error;
369 }
370
371 run_start_sub();
372
373 free(command_line);
374 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
375 return 0;
376error:
377 perl_free(my_perl);
378 free(command_line);
379
380 return err;
381}
382
383/*
384 * Stop trace script
385 */
386static int perl_stop_script(void)
387{
388 dSP; /* access to Perl stack */
389 PUSHMARK(SP);
390
391 if (get_cv("main::trace_end", 0))
392 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
393
394 perl_destruct(my_perl);
395 perl_free(my_perl);
396
397 fprintf(stderr, "\nperf trace Perl script stopped\n");
398
399 return 0;
400}
401
402static int perl_generate_script(const char *outfile)
403{
404 struct event *event = NULL;
405 struct format_field *f;
406 char fname[PATH_MAX];
407 int not_first, count;
408 FILE *ofp;
409
410 sprintf(fname, "%s.pl", outfile);
411 ofp = fopen(fname, "w");
412 if (ofp == NULL) {
413 fprintf(stderr, "couldn't open %s\n", fname);
414 return -1;
415 }
416
417 fprintf(ofp, "# perf trace event handlers, "
418 "generated by perf trace -g perl\n");
419
420 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
421 " License version 2\n\n");
422
423 fprintf(ofp, "# The common_* event handler fields are the most useful "
424 "fields common to\n");
425
426 fprintf(ofp, "# all events. They don't necessarily correspond to "
427 "the 'common_*' fields\n");
428
429 fprintf(ofp, "# in the format files. Those fields not available as "
430 "handler params can\n");
431
432 fprintf(ofp, "# be retrieved using Perl functions of the form "
433 "common_*($context).\n");
434
435 fprintf(ofp, "# See Context.pm for the list of available "
436 "functions.\n\n");
437
438 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
439 "Perf-Trace-Util/lib\";\n");
440
441 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
442 fprintf(ofp, "use Perf::Trace::Core;\n");
443 fprintf(ofp, "use Perf::Trace::Context;\n");
444 fprintf(ofp, "use Perf::Trace::Util;\n\n");
445
446 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
447 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
448
449 while ((event = trace_find_next_event(event))) {
450 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
451 fprintf(ofp, "\tmy (");
452
453 fprintf(ofp, "$event_name, ");
454 fprintf(ofp, "$context, ");
455 fprintf(ofp, "$common_cpu, ");
456 fprintf(ofp, "$common_secs, ");
457 fprintf(ofp, "$common_nsecs,\n");
458 fprintf(ofp, "\t $common_pid, ");
459 fprintf(ofp, "$common_comm,\n\t ");
460
461 not_first = 0;
462 count = 0;
463
464 for (f = event->format.fields; f; f = f->next) {
465 if (not_first++)
466 fprintf(ofp, ", ");
467 if (++count % 5 == 0)
468 fprintf(ofp, "\n\t ");
469
470 fprintf(ofp, "$%s", f->name);
471 }
472 fprintf(ofp, ") = @_;\n\n");
473
474 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
475 "$common_secs, $common_nsecs,\n\t "
476 "$common_pid, $common_comm);\n\n");
477
478 fprintf(ofp, "\tprintf(\"");
479
480 not_first = 0;
481 count = 0;
482
483 for (f = event->format.fields; f; f = f->next) {
484 if (not_first++)
485 fprintf(ofp, ", ");
486 if (count && count % 4 == 0) {
487 fprintf(ofp, "\".\n\t \"");
488 }
489 count++;
490
491 fprintf(ofp, "%s=", f->name);
492 if (f->flags & FIELD_IS_STRING ||
493 f->flags & FIELD_IS_FLAG ||
494 f->flags & FIELD_IS_SYMBOLIC)
495 fprintf(ofp, "%%s");
496 else if (f->flags & FIELD_IS_SIGNED)
497 fprintf(ofp, "%%d");
498 else
499 fprintf(ofp, "%%u");
500 }
501
502 fprintf(ofp, "\\n\",\n\t ");
503
504 not_first = 0;
505 count = 0;
506
507 for (f = event->format.fields; f; f = f->next) {
508 if (not_first++)
509 fprintf(ofp, ", ");
510
511 if (++count % 5 == 0)
512 fprintf(ofp, "\n\t ");
513
514 if (f->flags & FIELD_IS_FLAG) {
515 if ((count - 1) % 5 != 0) {
516 fprintf(ofp, "\n\t ");
517 count = 4;
518 }
519 fprintf(ofp, "flag_str(\"");
520 fprintf(ofp, "%s::%s\", ", event->system,
521 event->name);
522 fprintf(ofp, "\"%s\", $%s)", f->name,
523 f->name);
524 } else if (f->flags & FIELD_IS_SYMBOLIC) {
525 if ((count - 1) % 5 != 0) {
526 fprintf(ofp, "\n\t ");
527 count = 4;
528 }
529 fprintf(ofp, "symbol_str(\"");
530 fprintf(ofp, "%s::%s\", ", event->system,
531 event->name);
532 fprintf(ofp, "\"%s\", $%s)", f->name,
533 f->name);
534 } else
535 fprintf(ofp, "$%s", f->name);
536 }
537
538 fprintf(ofp, ");\n");
539 fprintf(ofp, "}\n\n");
540 }
541
542 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
543 "$common_cpu, $common_secs, $common_nsecs,\n\t "
544 "$common_pid, $common_comm) = @_;\n\n");
545
546 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
547 "$common_secs, $common_nsecs,\n\t $common_pid, "
548 "$common_comm);\n}\n\n");
549
550 fprintf(ofp, "sub print_header\n{\n"
551 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
552 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
553 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
554
555 fclose(ofp);
556
557 fprintf(stderr, "generated Perl script: %s\n", fname);
558
559 return 0;
560}
561
562struct scripting_ops perl_scripting_ops = {
563 .name = "Perl",
564 .start_script = perl_start_script,
565 .stop_script = perl_stop_script,
566 .process_event = perl_process_event,
567 .generate_script = perl_generate_script,
568};
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..33a414bbba3e
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,573 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 s = nsecs / NSECS_PER_SEC;
236 ns = nsecs - s * NSECS_PER_SEC;
237
238 scripting_context->event_data = data;
239
240 context = PyCObject_FromVoidPtr(scripting_context, NULL);
241
242 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
243 PyTuple_SetItem(t, n++,
244 PyCObject_FromVoidPtr(scripting_context, NULL));
245 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
246 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
247 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
248 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
249 PyTuple_SetItem(t, n++, PyString_FromString(comm));
250
251 for (field = event->format.fields; field; field = field->next) {
252 if (field->flags & FIELD_IS_STRING) {
253 int offset;
254 if (field->flags & FIELD_IS_DYNAMIC) {
255 offset = *(int *)(data + field->offset);
256 offset &= 0xffff;
257 } else
258 offset = field->offset;
259 PyTuple_SetItem(t, n++,
260 PyString_FromString((char *)data + offset));
261 } else { /* FIELD_IS_NUMERIC */
262 val = read_size(data + field->offset, field->size);
263 if (field->flags & FIELD_IS_SIGNED) {
264 PyTuple_SetItem(t, n++, PyInt_FromLong(val));
265 } else {
266 PyTuple_SetItem(t, n++, PyInt_FromLong(val));
267 }
268 }
269 }
270
271 if (_PyTuple_Resize(&t, n) == -1)
272 Py_FatalError("error resizing Python tuple");
273
274 handler = PyDict_GetItemString(main_dict, handler_name);
275 if (handler && PyCallable_Check(handler)) {
276 retval = PyObject_CallObject(handler, t);
277 if (retval == NULL)
278 handler_call_die(handler_name);
279 } else {
280 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
281 if (handler && PyCallable_Check(handler)) {
282 if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1)
283 Py_FatalError("error resizing Python tuple");
284
285 retval = PyObject_CallObject(handler, t);
286 if (retval == NULL)
287 handler_call_die("trace_unhandled");
288 }
289 }
290
291 Py_DECREF(t);
292}
293
294static int run_start_sub(void)
295{
296 PyObject *handler, *retval;
297 int err = 0;
298
299 main_module = PyImport_AddModule("__main__");
300 if (main_module == NULL)
301 return -1;
302 Py_INCREF(main_module);
303
304 main_dict = PyModule_GetDict(main_module);
305 if (main_dict == NULL) {
306 err = -1;
307 goto error;
308 }
309 Py_INCREF(main_dict);
310
311 handler = PyDict_GetItemString(main_dict, "trace_begin");
312 if (handler == NULL || !PyCallable_Check(handler))
313 goto out;
314
315 retval = PyObject_CallObject(handler, NULL);
316 if (retval == NULL)
317 handler_call_die("trace_begin");
318
319 Py_DECREF(retval);
320 return err;
321error:
322 Py_XDECREF(main_dict);
323 Py_XDECREF(main_module);
324out:
325 return err;
326}
327
328/*
329 * Start trace script
330 */
331static int python_start_script(const char *script, int argc, const char **argv)
332{
333 const char **command_line;
334 char buf[PATH_MAX];
335 int i, err = 0;
336 FILE *fp;
337
338 command_line = malloc((argc + 1) * sizeof(const char *));
339 command_line[0] = script;
340 for (i = 1; i < argc + 1; i++)
341 command_line[i] = argv[i - 1];
342
343 Py_Initialize();
344
345 initperf_trace_context();
346
347 PySys_SetArgv(argc + 1, (char **)command_line);
348
349 fp = fopen(script, "r");
350 if (!fp) {
351 sprintf(buf, "Can't open python script \"%s\"", script);
352 perror(buf);
353 err = -1;
354 goto error;
355 }
356
357 err = PyRun_SimpleFile(fp, script);
358 if (err) {
359 fprintf(stderr, "Error running python script %s\n", script);
360 goto error;
361 }
362
363 err = run_start_sub();
364 if (err) {
365 fprintf(stderr, "Error starting python script %s\n", script);
366 goto error;
367 }
368
369 free(command_line);
370 fprintf(stderr, "perf trace started with Python script %s\n\n",
371 script);
372
373 return err;
374error:
375 Py_Finalize();
376 free(command_line);
377
378 return err;
379}
380
381/*
382 * Stop trace script
383 */
384static int python_stop_script(void)
385{
386 PyObject *handler, *retval;
387 int err = 0;
388
389 handler = PyDict_GetItemString(main_dict, "trace_end");
390 if (handler == NULL || !PyCallable_Check(handler))
391 goto out;
392
393 retval = PyObject_CallObject(handler, NULL);
394 if (retval == NULL)
395 handler_call_die("trace_end");
396 else
397 Py_DECREF(retval);
398out:
399 Py_XDECREF(main_dict);
400 Py_XDECREF(main_module);
401 Py_Finalize();
402
403 fprintf(stderr, "\nperf trace Python script stopped\n");
404
405 return err;
406}
407
408static int python_generate_script(const char *outfile)
409{
410 struct event *event = NULL;
411 struct format_field *f;
412 char fname[PATH_MAX];
413 int not_first, count;
414 FILE *ofp;
415
416 sprintf(fname, "%s.py", outfile);
417 ofp = fopen(fname, "w");
418 if (ofp == NULL) {
419 fprintf(stderr, "couldn't open %s\n", fname);
420 return -1;
421 }
422 fprintf(ofp, "# perf trace event handlers, "
423 "generated by perf trace -g python\n");
424
425 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
426 " License version 2\n\n");
427
428 fprintf(ofp, "# The common_* event handler fields are the most useful "
429 "fields common to\n");
430
431 fprintf(ofp, "# all events. They don't necessarily correspond to "
432 "the 'common_*' fields\n");
433
434 fprintf(ofp, "# in the format files. Those fields not available as "
435 "handler params can\n");
436
437 fprintf(ofp, "# be retrieved using Python functions of the form "
438 "common_*(context).\n");
439
440 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
441 "of available functions.\n\n");
442
443 fprintf(ofp, "import os\n");
444 fprintf(ofp, "import sys\n\n");
445
446 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
447 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
448 fprintf(ofp, "\nfrom perf_trace_context import *\n");
449 fprintf(ofp, "from Core import *\n\n\n");
450
451 fprintf(ofp, "def trace_begin():\n");
452 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
453
454 fprintf(ofp, "def trace_end():\n");
455 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
456
457 while ((event = trace_find_next_event(event))) {
458 fprintf(ofp, "def %s__%s(", event->system, event->name);
459 fprintf(ofp, "event_name, ");
460 fprintf(ofp, "context, ");
461 fprintf(ofp, "common_cpu,\n");
462 fprintf(ofp, "\tcommon_secs, ");
463 fprintf(ofp, "common_nsecs, ");
464 fprintf(ofp, "common_pid, ");
465 fprintf(ofp, "common_comm,\n\t");
466
467 not_first = 0;
468 count = 0;
469
470 for (f = event->format.fields; f; f = f->next) {
471 if (not_first++)
472 fprintf(ofp, ", ");
473 if (++count % 5 == 0)
474 fprintf(ofp, "\n\t");
475
476 fprintf(ofp, "%s", f->name);
477 }
478 fprintf(ofp, "):\n");
479
480 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
481 "common_secs, common_nsecs,\n\t\t\t"
482 "common_pid, common_comm)\n\n");
483
484 fprintf(ofp, "\t\tprint \"");
485
486 not_first = 0;
487 count = 0;
488
489 for (f = event->format.fields; f; f = f->next) {
490 if (not_first++)
491 fprintf(ofp, ", ");
492 if (count && count % 3 == 0) {
493 fprintf(ofp, "\" \\\n\t\t\"");
494 }
495 count++;
496
497 fprintf(ofp, "%s=", f->name);
498 if (f->flags & FIELD_IS_STRING ||
499 f->flags & FIELD_IS_FLAG ||
500 f->flags & FIELD_IS_SYMBOLIC)
501 fprintf(ofp, "%%s");
502 else if (f->flags & FIELD_IS_SIGNED)
503 fprintf(ofp, "%%d");
504 else
505 fprintf(ofp, "%%u");
506 }
507
508 fprintf(ofp, "\\n\" %% \\\n\t\t(");
509
510 not_first = 0;
511 count = 0;
512
513 for (f = event->format.fields; f; f = f->next) {
514 if (not_first++)
515 fprintf(ofp, ", ");
516
517 if (++count % 5 == 0)
518 fprintf(ofp, "\n\t\t");
519
520 if (f->flags & FIELD_IS_FLAG) {
521 if ((count - 1) % 5 != 0) {
522 fprintf(ofp, "\n\t\t");
523 count = 4;
524 }
525 fprintf(ofp, "flag_str(\"");
526 fprintf(ofp, "%s__%s\", ", event->system,
527 event->name);
528 fprintf(ofp, "\"%s\", %s)", f->name,
529 f->name);
530 } else if (f->flags & FIELD_IS_SYMBOLIC) {
531 if ((count - 1) % 5 != 0) {
532 fprintf(ofp, "\n\t\t");
533 count = 4;
534 }
535 fprintf(ofp, "symbol_str(\"");
536 fprintf(ofp, "%s__%s\", ", event->system,
537 event->name);
538 fprintf(ofp, "\"%s\", %s)", f->name,
539 f->name);
540 } else
541 fprintf(ofp, "%s", f->name);
542 }
543
544 fprintf(ofp, "),\n\n");
545 }
546
547 fprintf(ofp, "def trace_unhandled(event_name, context, "
548 "common_cpu, common_secs, common_nsecs,\n\t\t"
549 "common_pid, common_comm):\n");
550
551 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
552 "common_secs, common_nsecs,\n\t\tcommon_pid, "
553 "common_comm)\n\n");
554
555 fprintf(ofp, "def print_header("
556 "event_name, cpu, secs, nsecs, pid, comm):\n"
557 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
558 "(event_name, cpu, secs, nsecs, pid, comm),\n");
559
560 fclose(ofp);
561
562 fprintf(stderr, "generated Python script: %s\n", fname);
563
564 return 0;
565}
566
567struct scripting_ops python_scripting_ops = {
568 .name = "Python",
569 .start_script = python_start_script,
570 .stop_script = python_stop_script,
571 .process_event = python_process_event,
572 .generate_script = python_generate_script,
573};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..0de7258e70a5
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,573 @@
1#define _FILE_OFFSET_BITS 64
2
3#include <linux/kernel.h>
4
5#include <byteswap.h>
6#include <unistd.h>
7#include <sys/types.h>
8
9#include "session.h"
10#include "sort.h"
11#include "util.h"
12
13static int perf_session__open(struct perf_session *self, bool force)
14{
15 struct stat input_stat;
16
17 self->fd = open(self->filename, O_RDONLY);
18 if (self->fd < 0) {
19 pr_err("failed to open file: %s", self->filename);
20 if (!strcmp(self->filename, "perf.data"))
21 pr_err(" (try 'perf record' first)");
22 pr_err("\n");
23 return -errno;
24 }
25
26 if (fstat(self->fd, &input_stat) < 0)
27 goto out_close;
28
29 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
30 pr_err("file %s not owned by current user or root\n",
31 self->filename);
32 goto out_close;
33 }
34
35 if (!input_stat.st_size) {
36 pr_info("zero-sized file (%s), nothing to do!\n",
37 self->filename);
38 goto out_close;
39 }
40
41 if (perf_header__read(&self->header, self->fd) < 0) {
42 pr_err("incompatible file format");
43 goto out_close;
44 }
45
46 self->size = input_stat.st_size;
47 return 0;
48
49out_close:
50 close(self->fd);
51 self->fd = -1;
52 return -1;
53}
54
55static inline int perf_session__create_kernel_maps(struct perf_session *self)
56{
57 return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps);
58}
59
60struct perf_session *perf_session__new(const char *filename, int mode, bool force)
61{
62 size_t len = filename ? strlen(filename) + 1 : 0;
63 struct perf_session *self = zalloc(sizeof(*self) + len);
64
65 if (self == NULL)
66 goto out;
67
68 if (perf_header__init(&self->header) < 0)
69 goto out_free;
70
71 memcpy(self->filename, filename, len);
72 self->threads = RB_ROOT;
73 self->last_match = NULL;
74 self->mmap_window = 32;
75 self->cwd = NULL;
76 self->cwdlen = 0;
77 self->unknown_events = 0;
78 map_groups__init(&self->kmaps);
79
80 if (mode == O_RDONLY) {
81 if (perf_session__open(self, force) < 0)
82 goto out_delete;
83 } else if (mode == O_WRONLY) {
84 /*
85 * In O_RDONLY mode this will be performed when reading the
86 * kernel MMAP event, in event__process_mmap().
87 */
88 if (perf_session__create_kernel_maps(self) < 0)
89 goto out_delete;
90 }
91
92 self->sample_type = perf_header__sample_type(&self->header);
93out:
94 return self;
95out_free:
96 free(self);
97 return NULL;
98out_delete:
99 perf_session__delete(self);
100 return NULL;
101}
102
103void perf_session__delete(struct perf_session *self)
104{
105 perf_header__exit(&self->header);
106 close(self->fd);
107 free(self->cwd);
108 free(self);
109}
110
111static bool symbol__match_parent_regex(struct symbol *sym)
112{
113 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
114 return 1;
115
116 return 0;
117}
118
119struct symbol **perf_session__resolve_callchain(struct perf_session *self,
120 struct thread *thread,
121 struct ip_callchain *chain,
122 struct symbol **parent)
123{
124 u8 cpumode = PERF_RECORD_MISC_USER;
125 struct symbol **syms = NULL;
126 unsigned int i;
127
128 if (symbol_conf.use_callchain) {
129 syms = calloc(chain->nr, sizeof(*syms));
130 if (!syms) {
131 fprintf(stderr, "Can't allocate memory for symbols\n");
132 exit(-1);
133 }
134 }
135
136 for (i = 0; i < chain->nr; i++) {
137 u64 ip = chain->ips[i];
138 struct addr_location al;
139
140 if (ip >= PERF_CONTEXT_MAX) {
141 switch (ip) {
142 case PERF_CONTEXT_HV:
143 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
144 case PERF_CONTEXT_KERNEL:
145 cpumode = PERF_RECORD_MISC_KERNEL; break;
146 case PERF_CONTEXT_USER:
147 cpumode = PERF_RECORD_MISC_USER; break;
148 default:
149 break;
150 }
151 continue;
152 }
153
154 thread__find_addr_location(thread, self, cpumode,
155 MAP__FUNCTION, ip, &al, NULL);
156 if (al.sym != NULL) {
157 if (sort__has_parent && !*parent &&
158 symbol__match_parent_regex(al.sym))
159 *parent = al.sym;
160 if (!symbol_conf.use_callchain)
161 break;
162 syms[i] = al.sym;
163 }
164 }
165
166 return syms;
167}
168
169static int process_event_stub(event_t *event __used,
170 struct perf_session *session __used)
171{
172 dump_printf(": unhandled!\n");
173 return 0;
174}
175
176static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
177{
178 if (handler->sample == NULL)
179 handler->sample = process_event_stub;
180 if (handler->mmap == NULL)
181 handler->mmap = process_event_stub;
182 if (handler->comm == NULL)
183 handler->comm = process_event_stub;
184 if (handler->fork == NULL)
185 handler->fork = process_event_stub;
186 if (handler->exit == NULL)
187 handler->exit = process_event_stub;
188 if (handler->lost == NULL)
189 handler->lost = process_event_stub;
190 if (handler->read == NULL)
191 handler->read = process_event_stub;
192 if (handler->throttle == NULL)
193 handler->throttle = process_event_stub;
194 if (handler->unthrottle == NULL)
195 handler->unthrottle = process_event_stub;
196}
197
198static const char *event__name[] = {
199 [0] = "TOTAL",
200 [PERF_RECORD_MMAP] = "MMAP",
201 [PERF_RECORD_LOST] = "LOST",
202 [PERF_RECORD_COMM] = "COMM",
203 [PERF_RECORD_EXIT] = "EXIT",
204 [PERF_RECORD_THROTTLE] = "THROTTLE",
205 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
206 [PERF_RECORD_FORK] = "FORK",
207 [PERF_RECORD_READ] = "READ",
208 [PERF_RECORD_SAMPLE] = "SAMPLE",
209};
210
211unsigned long event__total[PERF_RECORD_MAX];
212
213void event__print_totals(void)
214{
215 int i;
216 for (i = 0; i < PERF_RECORD_MAX; ++i)
217 pr_info("%10s events: %10ld\n",
218 event__name[i], event__total[i]);
219}
220
221void mem_bswap_64(void *src, int byte_size)
222{
223 u64 *m = src;
224
225 while (byte_size > 0) {
226 *m = bswap_64(*m);
227 byte_size -= sizeof(u64);
228 ++m;
229 }
230}
231
232static void event__all64_swap(event_t *self)
233{
234 struct perf_event_header *hdr = &self->header;
235 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
236}
237
238static void event__comm_swap(event_t *self)
239{
240 self->comm.pid = bswap_32(self->comm.pid);
241 self->comm.tid = bswap_32(self->comm.tid);
242}
243
244static void event__mmap_swap(event_t *self)
245{
246 self->mmap.pid = bswap_32(self->mmap.pid);
247 self->mmap.tid = bswap_32(self->mmap.tid);
248 self->mmap.start = bswap_64(self->mmap.start);
249 self->mmap.len = bswap_64(self->mmap.len);
250 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
251}
252
253static void event__task_swap(event_t *self)
254{
255 self->fork.pid = bswap_32(self->fork.pid);
256 self->fork.tid = bswap_32(self->fork.tid);
257 self->fork.ppid = bswap_32(self->fork.ppid);
258 self->fork.ptid = bswap_32(self->fork.ptid);
259 self->fork.time = bswap_64(self->fork.time);
260}
261
262static void event__read_swap(event_t *self)
263{
264 self->read.pid = bswap_32(self->read.pid);
265 self->read.tid = bswap_32(self->read.tid);
266 self->read.value = bswap_64(self->read.value);
267 self->read.time_enabled = bswap_64(self->read.time_enabled);
268 self->read.time_running = bswap_64(self->read.time_running);
269 self->read.id = bswap_64(self->read.id);
270}
271
272typedef void (*event__swap_op)(event_t *self);
273
274static event__swap_op event__swap_ops[] = {
275 [PERF_RECORD_MMAP] = event__mmap_swap,
276 [PERF_RECORD_COMM] = event__comm_swap,
277 [PERF_RECORD_FORK] = event__task_swap,
278 [PERF_RECORD_EXIT] = event__task_swap,
279 [PERF_RECORD_LOST] = event__all64_swap,
280 [PERF_RECORD_READ] = event__read_swap,
281 [PERF_RECORD_SAMPLE] = event__all64_swap,
282 [PERF_RECORD_MAX] = NULL,
283};
284
285static int perf_session__process_event(struct perf_session *self,
286 event_t *event,
287 struct perf_event_ops *ops,
288 u64 offset, u64 head)
289{
290 trace_event(event);
291
292 if (event->header.type < PERF_RECORD_MAX) {
293 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
294 offset + head, event->header.size,
295 event__name[event->header.type]);
296 ++event__total[0];
297 ++event__total[event->header.type];
298 }
299
300 if (self->header.needs_swap && event__swap_ops[event->header.type])
301 event__swap_ops[event->header.type](event);
302
303 switch (event->header.type) {
304 case PERF_RECORD_SAMPLE:
305 return ops->sample(event, self);
306 case PERF_RECORD_MMAP:
307 return ops->mmap(event, self);
308 case PERF_RECORD_COMM:
309 return ops->comm(event, self);
310 case PERF_RECORD_FORK:
311 return ops->fork(event, self);
312 case PERF_RECORD_EXIT:
313 return ops->exit(event, self);
314 case PERF_RECORD_LOST:
315 return ops->lost(event, self);
316 case PERF_RECORD_READ:
317 return ops->read(event, self);
318 case PERF_RECORD_THROTTLE:
319 return ops->throttle(event, self);
320 case PERF_RECORD_UNTHROTTLE:
321 return ops->unthrottle(event, self);
322 default:
323 self->unknown_events++;
324 return -1;
325 }
326}
327
328void perf_event_header__bswap(struct perf_event_header *self)
329{
330 self->type = bswap_32(self->type);
331 self->misc = bswap_16(self->misc);
332 self->size = bswap_16(self->size);
333}
334
335int perf_header__read_build_ids(struct perf_header *self,
336 int input, u64 offset, u64 size)
337{
338 struct build_id_event bev;
339 char filename[PATH_MAX];
340 u64 limit = offset + size;
341 int err = -1;
342
343 while (offset < limit) {
344 struct dso *dso;
345 ssize_t len;
346 struct list_head *head = &dsos__user;
347
348 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
349 goto out;
350
351 if (self->needs_swap)
352 perf_event_header__bswap(&bev.header);
353
354 len = bev.header.size - sizeof(bev);
355 if (read(input, filename, len) != len)
356 goto out;
357
358 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
359 head = &dsos__kernel;
360
361 dso = __dsos__findnew(head, filename);
362 if (dso != NULL) {
363 dso__set_build_id(dso, &bev.build_id);
364 if (head == &dsos__kernel && filename[0] == '[')
365 dso->kernel = 1;
366 }
367
368 offset += bev.header.size;
369 }
370 err = 0;
371out:
372 return err;
373}
374
375static struct thread *perf_session__register_idle_thread(struct perf_session *self)
376{
377 struct thread *thread = perf_session__findnew(self, 0);
378
379 if (thread == NULL || thread__set_comm(thread, "swapper")) {
380 pr_err("problem inserting idle task.\n");
381 thread = NULL;
382 }
383
384 return thread;
385}
386
387int __perf_session__process_events(struct perf_session *self,
388 u64 data_offset, u64 data_size,
389 u64 file_size, struct perf_event_ops *ops)
390{
391 int err, mmap_prot, mmap_flags;
392 u64 head, shift;
393 u64 offset = 0;
394 size_t page_size;
395 event_t *event;
396 uint32_t size;
397 char *buf;
398
399 perf_event_ops__fill_defaults(ops);
400
401 page_size = sysconf(_SC_PAGESIZE);
402
403 head = data_offset;
404 shift = page_size * (head / page_size);
405 offset += shift;
406 head -= shift;
407
408 mmap_prot = PROT_READ;
409 mmap_flags = MAP_SHARED;
410
411 if (self->header.needs_swap) {
412 mmap_prot |= PROT_WRITE;
413 mmap_flags = MAP_PRIVATE;
414 }
415remap:
416 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
417 mmap_flags, self->fd, offset);
418 if (buf == MAP_FAILED) {
419 pr_err("failed to mmap file\n");
420 err = -errno;
421 goto out_err;
422 }
423
424more:
425 event = (event_t *)(buf + head);
426
427 if (self->header.needs_swap)
428 perf_event_header__bswap(&event->header);
429 size = event->header.size;
430 if (size == 0)
431 size = 8;
432
433 if (head + event->header.size >= page_size * self->mmap_window) {
434 int munmap_ret;
435
436 shift = page_size * (head / page_size);
437
438 munmap_ret = munmap(buf, page_size * self->mmap_window);
439 assert(munmap_ret == 0);
440
441 offset += shift;
442 head -= shift;
443 goto remap;
444 }
445
446 size = event->header.size;
447
448 dump_printf("\n%#Lx [%#x]: event: %d\n",
449 offset + head, event->header.size, event->header.type);
450
451 if (size == 0 ||
452 perf_session__process_event(self, event, ops, offset, head) < 0) {
453 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
454 offset + head, event->header.size,
455 event->header.type);
456 /*
457 * assume we lost track of the stream, check alignment, and
458 * increment a single u64 in the hope to catch on again 'soon'.
459 */
460 if (unlikely(head & 7))
461 head &= ~7ULL;
462
463 size = 8;
464 }
465
466 head += size;
467
468 if (offset + head >= data_offset + data_size)
469 goto done;
470
471 if (offset + head < file_size)
472 goto more;
473done:
474 err = 0;
475out_err:
476 return err;
477}
478
479int perf_session__process_events(struct perf_session *self,
480 struct perf_event_ops *ops)
481{
482 int err;
483
484 if (perf_session__register_idle_thread(self) == NULL)
485 return -ENOMEM;
486
487 if (!symbol_conf.full_paths) {
488 char bf[PATH_MAX];
489
490 if (getcwd(bf, sizeof(bf)) == NULL) {
491 err = -errno;
492out_getcwd_err:
493 pr_err("failed to get the current directory\n");
494 goto out_err;
495 }
496 self->cwd = strdup(bf);
497 if (self->cwd == NULL) {
498 err = -ENOMEM;
499 goto out_getcwd_err;
500 }
501 self->cwdlen = strlen(self->cwd);
502 }
503
504 err = __perf_session__process_events(self, self->header.data_offset,
505 self->header.data_size,
506 self->size, ops);
507out_err:
508 return err;
509}
510
511bool perf_session__has_traces(struct perf_session *self, const char *msg)
512{
513 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
514 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
515 return false;
516 }
517
518 return true;
519}
520
521int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
522 const char *symbol_name,
523 u64 addr)
524{
525 char *bracket;
526 enum map_type i;
527
528 self->ref_reloc_sym.name = strdup(symbol_name);
529 if (self->ref_reloc_sym.name == NULL)
530 return -ENOMEM;
531
532 bracket = strchr(self->ref_reloc_sym.name, ']');
533 if (bracket)
534 *bracket = '\0';
535
536 self->ref_reloc_sym.addr = addr;
537
538 for (i = 0; i < MAP__NR_TYPES; ++i) {
539 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
540 kmap->ref_reloc_sym = &self->ref_reloc_sym;
541 }
542
543 return 0;
544}
545
546static u64 map__reloc_map_ip(struct map *map, u64 ip)
547{
548 return ip + (s64)map->pgoff;
549}
550
551static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
552{
553 return ip - (s64)map->pgoff;
554}
555
556void map__reloc_vmlinux(struct map *self)
557{
558 struct kmap *kmap = map__kmap(self);
559 s64 reloc;
560
561 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
562 return;
563
564 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
565 kmap->ref_reloc_sym->addr);
566
567 if (!reloc)
568 return;
569
570 self->map_ip = map__reloc_map_ip;
571 self->unmap_ip = map__reloc_unmap_ip;
572 self->pgoff = reloc;
573}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..31950fcd8a4d
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,88 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "symbol.h"
7#include "thread.h"
8#include <linux/rbtree.h>
9#include "../../../include/linux/perf_event.h"
10
11struct ip_callchain;
12struct thread;
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 map *vmlinux_maps[MAP__NR_TYPES];
22 struct events_stats events_stats;
23 unsigned long event_total[PERF_RECORD_MAX];
24 unsigned long unknown_events;
25 struct rb_root hists;
26 u64 sample_type;
27 struct ref_reloc_sym ref_reloc_sym;
28 int fd;
29 int cwdlen;
30 char *cwd;
31 char filename[0];
32};
33
34typedef int (*event_op)(event_t *self, struct perf_session *session);
35
36struct perf_event_ops {
37 event_op sample,
38 mmap,
39 comm,
40 fork,
41 exit,
42 lost,
43 read,
44 throttle,
45 unthrottle;
46};
47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self);
50
51void perf_event_header__bswap(struct perf_event_header *self);
52
53int __perf_session__process_events(struct perf_session *self,
54 u64 data_offset, u64 data_size, u64 size,
55 struct perf_event_ops *ops);
56int perf_session__process_events(struct perf_session *self,
57 struct perf_event_ops *event_ops);
58
59struct symbol **perf_session__resolve_callchain(struct perf_session *self,
60 struct thread *thread,
61 struct ip_callchain *chain,
62 struct symbol **parent);
63
64bool perf_session__has_traces(struct perf_session *self, const char *msg);
65
66int perf_header__read_build_ids(struct perf_header *self, int input,
67 u64 offset, u64 file_size);
68
69int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
70 const char *symbol_name,
71 u64 addr);
72
73void mem_bswap_64(void *src, int byte_size);
74
75static inline int __perf_session__create_kernel_maps(struct perf_session *self,
76 struct dso *kernel)
77{
78 return __map_groups__create_kernel_maps(&self->kmaps,
79 self->vmlinux_maps, kernel);
80}
81
82static inline struct map *
83 perf_session__new_module_map(struct perf_session *self,
84 u64 start, const char *filename)
85{
86 return map_groups__new_module(&self->kmaps, start, filename);
87}
88#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..cb0f327de9e8
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,316 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
12
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep;
18
19LIST_HEAD(hist_entry__sort_list);
20
21struct sort_entry sort_thread = {
22 .header = "Command: Pid",
23 .cmp = sort__thread_cmp,
24 .print = sort__thread_print,
25 .width = &threads__col_width,
26};
27
28struct sort_entry sort_comm = {
29 .header = "Command",
30 .cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse,
32 .print = sort__comm_print,
33 .width = &comms__col_width,
34};
35
36struct sort_entry sort_dso = {
37 .header = "Shared Object",
38 .cmp = sort__dso_cmp,
39 .print = sort__dso_print,
40 .width = &dsos__col_width,
41};
42
43struct sort_entry sort_sym = {
44 .header = "Symbol",
45 .cmp = sort__sym_cmp,
46 .print = sort__sym_print,
47};
48
49struct sort_entry sort_parent = {
50 .header = "Parent symbol",
51 .cmp = sort__parent_cmp,
52 .print = sort__parent_print,
53 .width = &parent_symbol__col_width,
54};
55
56struct sort_dimension {
57 const char *name;
58 struct sort_entry *entry;
59 int taken;
60};
61
62static struct sort_dimension sort_dimensions[] = {
63 { .name = "pid", .entry = &sort_thread, },
64 { .name = "comm", .entry = &sort_comm, },
65 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, },
68};
69
70int64_t cmp_null(void *l, void *r)
71{
72 if (!l && !r)
73 return 0;
74 else if (!l)
75 return -1;
76 else
77 return 1;
78}
79
80/* --sort pid */
81
82int64_t
83sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
84{
85 return right->thread->pid - left->thread->pid;
86}
87
88int repsep_fprintf(FILE *fp, const char *fmt, ...)
89{
90 int n;
91 va_list ap;
92
93 va_start(ap, fmt);
94 if (!field_sep)
95 n = vfprintf(fp, fmt, ap);
96 else {
97 char *bf = NULL;
98 n = vasprintf(&bf, fmt, ap);
99 if (n > 0) {
100 char *sep = bf;
101
102 while (1) {
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 }
109 fputs(bf, fp);
110 free(bf);
111 }
112 va_end(ap);
113 return n;
114}
115
116size_t
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
118{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6,
120 self->thread->comm ?: "", self->thread->pid);
121}
122
123size_t
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
125{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
127}
128
129/* --sort dso */
130
131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL;
136 const char *dso_name_l, *dso_name_r;
137
138 if (!dso_l || !dso_r)
139 return cmp_null(dso_l, dso_r);
140
141 if (verbose) {
142 dso_name_l = dso_l->long_name;
143 dso_name_r = dso_r->long_name;
144 } else {
145 dso_name_l = dso_l->short_name;
146 dso_name_r = dso_r->short_name;
147 }
148
149 return strcmp(dso_name_l, dso_name_r);
150}
151
152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{
155 if (self->map && self->map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name :
157 self->map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 }
160
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
162}
163
164/* --sort symbol */
165
166int64_t
167sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{
169 u64 ip_l, ip_r;
170
171 if (left->sym == right->sym)
172 return 0;
173
174 ip_l = left->sym ? left->sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180
181size_t
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{
184 size_t ret = 0;
185
186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 }
190
191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name);
194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196
197 return ret;
198}
199
200/* --sort comm */
201
202int64_t
203sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
204{
205 return right->thread->pid - left->thread->pid;
206}
207
208int64_t
209sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
210{
211 char *comm_l = left->thread->comm;
212 char *comm_r = right->thread->comm;
213
214 if (!comm_l || !comm_r)
215 return cmp_null(comm_l, comm_r);
216
217 return strcmp(comm_l, comm_r);
218}
219
220/* --sort parent */
221
222int64_t
223sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
224{
225 struct symbol *sym_l = left->parent;
226 struct symbol *sym_r = right->parent;
227
228 if (!sym_l || !sym_r)
229 return cmp_null(sym_l, sym_r);
230
231 return strcmp(sym_l->name, sym_r->name);
232}
233
234size_t
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
236{
237 return repsep_fprintf(fp, "%-*s", width,
238 self->parent ? self->parent->name : "[other]");
239}
240
241int sort_dimension__add(const char *tok)
242{
243 unsigned int i;
244
245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
246 struct sort_dimension *sd = &sort_dimensions[i];
247
248 if (sd->taken)
249 continue;
250
251 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue;
253
254 if (sd->entry->collapse)
255 sort__need_collapse = 1;
256
257 if (sd->entry == &sort_parent) {
258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
259 if (ret) {
260 char err[BUFSIZ];
261
262 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s",
264 parent_pattern, err);
265 exit(-1);
266 }
267 sort__has_parent = 1;
268 }
269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
284 sd->taken = 1;
285
286 return 0;
287 }
288
289 return -ESRCH;
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
new file mode 100644
index 000000000000..753f9ea99fb0
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,107 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.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"
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
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension;
43
44struct hist_entry {
45 struct rb_node rb_node;
46 u64 count;
47 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip;
51 char level;
52 struct symbol *parent;
53 struct callchain_node callchain;
54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
59};
60
61enum sort_type {
62 SORT_PID,
63 SORT_COMM,
64 SORT_DSO,
65 SORT_SYM,
66 SORT_PARENT
67};
68
69/*
70 * configurable sorting bits
71 */
72
73struct sort_entry {
74 struct list_head list;
75
76 const char *header;
77
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
81 unsigned int *width;
82 bool elide;
83};
84
85extern struct sort_entry sort_thread;
86extern struct list_head hist_entry__sort_list;
87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
93extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
94extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
95extern int64_t cmp_null(void *, void *);
96extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
97extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
98extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
99extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
100extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
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);
106
107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,4 +1,5 @@
1#include "string.h" 1#include "string.h"
2#include "util.h"
2 3
3static int hex(char ch) 4static int hex(char ch)
4{ 5{
@@ -32,3 +33,307 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46
47#define K 1024LL
48/*
49 * perf_atoll()
50 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51 * and return its numeric value
52 */
53s64 perf_atoll(const char *str)
54{
55 unsigned int i;
56 s64 length = -1, unit = 1;
57
58 if (!isdigit(str[0]))
59 goto out_err;
60
61 for (i = 1; i < strlen(str); i++) {
62 switch (str[i]) {
63 case 'B':
64 case 'b':
65 break;
66 case 'K':
67 if (str[i + 1] != 'B')
68 goto out_err;
69 else
70 goto kilo;
71 case 'k':
72 if (str[i + 1] != 'b')
73 goto out_err;
74kilo:
75 unit = K;
76 break;
77 case 'M':
78 if (str[i + 1] != 'B')
79 goto out_err;
80 else
81 goto mega;
82 case 'm':
83 if (str[i + 1] != 'b')
84 goto out_err;
85mega:
86 unit = K * K;
87 break;
88 case 'G':
89 if (str[i + 1] != 'B')
90 goto out_err;
91 else
92 goto giga;
93 case 'g':
94 if (str[i + 1] != 'b')
95 goto out_err;
96giga:
97 unit = K * K * K;
98 break;
99 case 'T':
100 if (str[i + 1] != 'B')
101 goto out_err;
102 else
103 goto tera;
104 case 't':
105 if (str[i + 1] != 'b')
106 goto out_err;
107tera:
108 unit = K * K * K * K;
109 break;
110 case '\0': /* only specified figures */
111 unit = 1;
112 break;
113 default:
114 if (!isdigit(str[i]))
115 goto out_err;
116 break;
117 }
118 }
119
120 length = atoll(str) * unit;
121 goto out;
122
123out_err:
124 length = -1;
125out:
126 return length;
127}
128
129/*
130 * Helper function for splitting a string into an argv-like array.
131 * originaly copied from lib/argv_split.c
132 */
133static const char *skip_sep(const char *cp)
134{
135 while (*cp && isspace(*cp))
136 cp++;
137
138 return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143 while (*cp && !isspace(*cp))
144 cp++;
145
146 return cp;
147}
148
149static int count_argc(const char *str)
150{
151 int count = 0;
152
153 while (*str) {
154 str = skip_sep(str);
155 if (*str) {
156 count++;
157 str = skip_arg(str);
158 }
159 }
160
161 return count;
162}
163
164/**
165 * argv_free - free an argv
166 * @argv - the argument vector to be freed
167 *
168 * Frees an argv and the strings it points to.
169 */
170void argv_free(char **argv)
171{
172 char **p;
173 for (p = argv; *p; p++)
174 free(*p);
175
176 free(argv);
177}
178
179/**
180 * argv_split - split a string at whitespace, returning an argv
181 * @str: the string to be split
182 * @argcp: returned argument count
183 *
184 * Returns an array of pointers to strings which are split out from
185 * @str. This is performed by strictly splitting on white-space; no
186 * quote processing is performed. Multiple whitespace characters are
187 * considered to be a single argument separator. The returned array
188 * is always NULL-terminated. Returns NULL on memory allocation
189 * failure.
190 */
191char **argv_split(const char *str, int *argcp)
192{
193 int argc = count_argc(str);
194 char **argv = zalloc(sizeof(*argv) * (argc+1));
195 char **argvp;
196
197 if (argv == NULL)
198 goto out;
199
200 if (argcp)
201 *argcp = argc;
202
203 argvp = argv;
204
205 while (*str) {
206 str = skip_sep(str);
207
208 if (*str) {
209 const char *p = str;
210 char *t;
211
212 str = skip_arg(str);
213
214 t = strndup(p, str-p);
215 if (t == NULL)
216 goto fail;
217 *argvp++ = t;
218 }
219 }
220 *argvp = NULL;
221
222out:
223 return argv;
224
225fail:
226 argv_free(argv);
227 return NULL;
228}
229
230/* Character class matching */
231static bool __match_charclass(const char *pat, char c, const char **npat)
232{
233 bool complement = false, ret = true;
234
235 if (*pat == '!') {
236 complement = true;
237 pat++;
238 }
239 if (*pat++ == c) /* First character is special */
240 goto end;
241
242 while (*pat && *pat != ']') { /* Matching */
243 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
244 if (*(pat - 1) <= c && c <= *(pat + 1))
245 goto end;
246 if (*(pat - 1) > *(pat + 1))
247 goto error;
248 pat += 2;
249 } else if (*pat++ == c)
250 goto end;
251 }
252 if (!*pat)
253 goto error;
254 ret = false;
255
256end:
257 while (*pat && *pat != ']') /* Searching closing */
258 pat++;
259 if (!*pat)
260 goto error;
261 *npat = pat + 1;
262 return complement ? !ret : ret;
263
264error:
265 return false;
266}
267
268/* Glob/lazy pattern matching */
269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
270{
271 while (*str && *pat && *pat != '*') {
272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */
284 str++;
285 pat++;
286 continue;
287 } else if (*pat == '[') /* Character classes/Ranges */
288 if (__match_charclass(pat + 1, *str, &pat)) {
289 str++;
290 continue;
291 } else
292 return false;
293 else if (*pat == '\\') /* Escaped char match as normal char */
294 pat++;
295 if (*str++ != *pat++)
296 return false;
297 }
298 /* Check wild card */
299 if (*pat == '*') {
300 while (*pat == '*')
301 pat++;
302 if (!*pat) /* Tail wild card matches all */
303 return true;
304 while (*str)
305 if (strglobmatch(str++, pat))
306 return true;
307 }
308 return !*str && !*pat;
309}
310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,18 @@
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);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
7 14
8#define _STR(x) #x 15#define _STR(x) #x
9#define STR(x) _STR(x) 16#define STR(x) _STR(x)
10 17
11#endif 18#endif /* __PERF_STRING_H */
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 921818e44a54..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.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 /* STRLIST_H_ */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 226f44a2357d..323c0aea0a91 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,111 +1,226 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "sort.h"
3#include "string.h" 4#include "string.h"
4#include "symbol.h" 5#include "symbol.h"
6#include "thread.h"
5 7
6#include "debug.h" 8#include "debug.h"
7 9
10#include <asm/bug.h>
8#include <libelf.h> 11#include <libelf.h>
9#include <gelf.h> 12#include <gelf.h>
10#include <elf.h> 13#include <elf.h>
14#include <limits.h>
15#include <sys/utsname.h>
11 16
12const char *sym_hist_filter; 17#ifndef NT_GNU_BUILD_ID
18#define NT_GNU_BUILD_ID 3
19#endif
13 20
14enum dso_origin { 21enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 22 DSO__ORIG_KERNEL = 0,
16 DSO__ORIG_JAVA_JIT, 23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
17 DSO__ORIG_FEDORA, 25 DSO__ORIG_FEDORA,
18 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 30 DSO__ORIG_NOT_FOUND,
22}; 31};
23 32
24static struct symbol *symbol__new(u64 start, u64 len, 33static void dsos__add(struct list_head *head, struct dso *dso);
25 const char *name, unsigned int priv_size, 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
26 u64 obj_start, int v) 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 symbol_filter_t filter);
37static int vmlinux_path__nr_entries;
38static char **vmlinux_path;
39
40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
46bool dso__loaded(const struct dso *self, enum map_type type)
27{ 47{
28 size_t namelen = strlen(name) + 1; 48 return self->loaded & (1 << type);
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 49}
30 50
31 if (!self) 51bool dso__sorted_by_name(const struct dso *self, enum map_type type)
32 return NULL; 52{
53 return self->sorted_by_name & (1 << type);
54}
55
56static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
57{
58 self->sorted_by_name |= (1 << type);
59}
60
61bool symbol_type__is_a(char symbol_type, enum map_type map_type)
62{
63 switch (map_type) {
64 case MAP__FUNCTION:
65 return symbol_type == 'T' || symbol_type == 'W';
66 case MAP__VARIABLE:
67 return symbol_type == 'D' || symbol_type == 'd';
68 default:
69 return false;
70 }
71}
33 72
34 if (v >= 2) 73static void symbols__fixup_end(struct rb_root *self)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 74{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 75 struct rb_node *nd, *prevnd = rb_first(self);
76 struct symbol *curr, *prev;
37 77
38 self->obj_start= obj_start; 78 if (prevnd == NULL)
39 self->hist = NULL; 79 return;
40 self->hist_sum = 0;
41 80
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 81 curr = rb_entry(prevnd, struct symbol, rb_node);
43 self->hist = calloc(sizeof(u64), len);
44 82
45 if (priv_size) { 83 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
46 memset(self, 0, priv_size); 84 prev = curr;
47 self = ((void *)self) + priv_size; 85 curr = rb_entry(nd, struct symbol, rb_node);
86
87 if (prev->end == prev->start)
88 prev->end = curr->start - 1;
48 } 89 }
90
91 /* Last entry */
92 if (curr->end == curr->start)
93 curr->end = roundup(curr->start, 4096);
94}
95
96static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
97{
98 struct map *prev, *curr;
99 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
100
101 if (prevnd == NULL)
102 return;
103
104 curr = rb_entry(prevnd, struct map, rb_node);
105
106 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
107 prev = curr;
108 curr = rb_entry(nd, struct map, rb_node);
109 prev->end = curr->start - 1;
110 }
111
112 /*
113 * We still haven't the actual symbols, so guess the
114 * last map final address.
115 */
116 curr->end = ~0UL;
117}
118
119static void map_groups__fixup_end(struct map_groups *self)
120{
121 int i;
122 for (i = 0; i < MAP__NR_TYPES; ++i)
123 __map_groups__fixup_end(self, i);
124}
125
126static struct symbol *symbol__new(u64 start, u64 len, const char *name)
127{
128 size_t namelen = strlen(name) + 1;
129 struct symbol *self = zalloc(symbol_conf.priv_size +
130 sizeof(*self) + namelen);
131 if (self == NULL)
132 return NULL;
133
134 if (symbol_conf.priv_size)
135 self = ((void *)self) + symbol_conf.priv_size;
136
49 self->start = start; 137 self->start = start;
50 self->end = len ? start + len - 1 : start; 138 self->end = len ? start + len - 1 : start;
139
140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
141
51 memcpy(self->name, name, namelen); 142 memcpy(self->name, name, namelen);
52 143
53 return self; 144 return self;
54} 145}
55 146
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 147void symbol__delete(struct symbol *self)
57{ 148{
58 free(((void *)self) - priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
59} 150}
60 151
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 152static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 153{
63 if (!self->module) 154 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 155 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
69} 156}
70 157
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 158void dso__set_long_name(struct dso *self, char *name)
72{ 159{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 160 if (name == NULL)
161 return;
162 self->long_name = name;
163 self->long_name_len = strlen(name);
164}
165
166static void dso__set_basename(struct dso *self)
167{
168 self->short_name = basename(self->long_name);
169}
170
171struct dso *dso__new(const char *name)
172{
173 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
74 174
75 if (self != NULL) { 175 if (self != NULL) {
176 int i;
76 strcpy(self->name, name); 177 strcpy(self->name, name);
77 self->syms = RB_ROOT; 178 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 179 self->short_name = self->name;
79 self->find_symbol = dso__find_symbol; 180 for (i = 0; i < MAP__NR_TYPES; ++i)
181 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
80 self->slen_calculated = 0; 182 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 183 self->origin = DSO__ORIG_NOT_FOUND;
184 self->loaded = 0;
185 self->sorted_by_name = 0;
186 self->has_build_id = 0;
82 } 187 }
83 188
84 return self; 189 return self;
85} 190}
86 191
87static void dso__delete_symbols(struct dso *self) 192static void symbols__delete(struct rb_root *self)
88{ 193{
89 struct symbol *pos; 194 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 195 struct rb_node *next = rb_first(self);
91 196
92 while (next) { 197 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 198 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 199 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 200 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 201 symbol__delete(pos);
97 } 202 }
98} 203}
99 204
100void dso__delete(struct dso *self) 205void dso__delete(struct dso *self)
101{ 206{
102 dso__delete_symbols(self); 207 int i;
208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 symbols__delete(&self->symbols[i]);
210 if (self->long_name != self->name)
211 free(self->long_name);
103 free(self); 212 free(self);
104} 213}
105 214
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 215void dso__set_build_id(struct dso *self, void *build_id)
107{ 216{
108 struct rb_node **p = &self->syms.rb_node; 217 memcpy(self->build_id, build_id, sizeof(self->build_id));
218 self->has_build_id = 1;
219}
220
221static void symbols__insert(struct rb_root *self, struct symbol *sym)
222{
223 struct rb_node **p = &self->rb_node;
109 struct rb_node *parent = NULL; 224 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 225 const u64 ip = sym->start;
111 struct symbol *s; 226 struct symbol *s;
@@ -119,17 +234,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 234 p = &(*p)->rb_right;
120 } 235 }
121 rb_link_node(&sym->rb_node, parent, p); 236 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 237 rb_insert_color(&sym->rb_node, self);
123} 238}
124 239
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 240static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 241{
127 struct rb_node *n; 242 struct rb_node *n;
128 243
129 if (self == NULL) 244 if (self == NULL)
130 return NULL; 245 return NULL;
131 246
132 n = self->syms.rb_node; 247 n = self->rb_node;
133 248
134 while (n) { 249 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 250 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +260,120 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 260 return NULL;
146} 261}
147 262
148size_t dso__fprintf(struct dso *self, FILE *fp) 263struct symbol_name_rb_node {
264 struct rb_node rb_node;
265 struct symbol sym;
266};
267
268static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
149{ 269{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 270 struct rb_node **p = &self->rb_node;
271 struct rb_node *parent = NULL;
272 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
151 273
274 while (*p != NULL) {
275 parent = *p;
276 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
277 if (strcmp(sym->name, s->sym.name) < 0)
278 p = &(*p)->rb_left;
279 else
280 p = &(*p)->rb_right;
281 }
282 rb_link_node(&symn->rb_node, parent, p);
283 rb_insert_color(&symn->rb_node, self);
284}
285
286static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
287{
288 struct rb_node *nd;
289
290 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
291 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
292 symbols__insert_by_name(self, pos);
293 }
294}
295
296static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
297{
298 struct rb_node *n;
299
300 if (self == NULL)
301 return NULL;
302
303 n = self->rb_node;
304
305 while (n) {
306 struct symbol_name_rb_node *s;
307 int cmp;
308
309 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
310 cmp = strcmp(name, s->sym.name);
311
312 if (cmp < 0)
313 n = n->rb_left;
314 else if (cmp > 0)
315 n = n->rb_right;
316 else
317 return &s->sym;
318 }
319
320 return NULL;
321}
322
323struct symbol *dso__find_symbol(struct dso *self,
324 enum map_type type, u64 addr)
325{
326 return symbols__find(&self->symbols[type], addr);
327}
328
329struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
330 const char *name)
331{
332 return symbols__find_by_name(&self->symbol_names[type], name);
333}
334
335void dso__sort_by_name(struct dso *self, enum map_type type)
336{
337 dso__set_sorted_by_name(self, type);
338 return symbols__sort_by_name(&self->symbol_names[type],
339 &self->symbols[type]);
340}
341
342int build_id__sprintf(const u8 *self, int len, char *bf)
343{
344 char *bid = bf;
345 const u8 *raw = self;
346 int i;
347
348 for (i = 0; i < len; ++i) {
349 sprintf(bid, "%02x", *raw);
350 ++raw;
351 bid += 2;
352 }
353
354 return raw - self;
355}
356
357size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
358{
359 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
360
361 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
362 return fprintf(fp, "%s", sbuild_id);
363}
364
365size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
366{
152 struct rb_node *nd; 367 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 368 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
369
370 if (self->short_name != self->long_name)
371 ret += fprintf(fp, "%s, ", self->long_name);
372 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
373 self->loaded ? "" : "NOT ");
374 ret += dso__fprintf_buildid(self, fp);
375 ret += fprintf(fp, ")\n");
376 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 377 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 378 ret += symbol__fprintf(pos, fp);
156 } 379 }
@@ -158,22 +381,23 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 381 return ret;
159} 382}
160 383
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 384int kallsyms__parse(const char *filename, void *arg,
385 int (*process_symbol)(void *arg, const char *name,
386 char type, u64 start))
162{ 387{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 388 char *line = NULL;
165 size_t n; 389 size_t n;
166 FILE *file = fopen("/proc/kallsyms", "r"); 390 int err = 0;
167 int count = 0; 391 FILE *file = fopen(filename, "r");
168 392
169 if (file == NULL) 393 if (file == NULL)
170 goto out_failure; 394 goto out_failure;
171 395
172 while (!feof(file)) { 396 while (!feof(file)) {
173 u64 start; 397 u64 start;
174 struct symbol *sym;
175 int line_len, len; 398 int line_len, len;
176 char symbol_type; 399 char symbol_type;
400 char *symbol_name;
177 401
178 line_len = getline(&line, &n, file); 402 line_len = getline(&line, &n, file);
179 if (line_len < 0) 403 if (line_len < 0)
@@ -191,64 +415,168 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
191 continue; 415 continue;
192 416
193 symbol_type = toupper(line[len]); 417 symbol_type = toupper(line[len]);
194 /* 418 symbol_name = line + len + 2;
195 * We're interested only in code ('T'ext)
196 */
197 if (symbol_type != 'T' && symbol_type != 'W')
198 continue;
199 /*
200 * Well fix up the end later, when we have all sorted.
201 */
202 sym = symbol__new(start, 0xdead, line + len + 2,
203 self->sym_priv_size, 0, v);
204
205 if (sym == NULL)
206 goto out_delete_line;
207 419
208 if (filter && filter(self, sym)) 420 err = process_symbol(arg, symbol_name, symbol_type, start);
209 symbol__delete(sym, self->sym_priv_size); 421 if (err)
210 else { 422 break;
211 dso__insert_symbol(self, sym);
212 count++;
213 }
214 } 423 }
215 424
425 free(line);
426 fclose(file);
427 return err;
428
429out_failure:
430 return -1;
431}
432
433struct process_kallsyms_args {
434 struct map *map;
435 struct dso *dso;
436};
437
438static int map__process_kallsym_symbol(void *arg, const char *name,
439 char type, u64 start)
440{
441 struct symbol *sym;
442 struct process_kallsyms_args *a = arg;
443 struct rb_root *root = &a->dso->symbols[a->map->type];
444
445 if (!symbol_type__is_a(type, a->map->type))
446 return 0;
447
216 /* 448 /*
217 * Now that we have all sorted out, just set the ->end of all 449 * Will fix up the end later, when we have all symbols sorted.
218 * symbols
219 */ 450 */
220 prevnd = rb_first(&self->syms); 451 sym = symbol__new(start, 0, name);
221 452
222 if (prevnd == NULL) 453 if (sym == NULL)
223 goto out_delete_line; 454 return -ENOMEM;
455 /*
456 * We will pass the symbols to the filter later, in
457 * map__split_kallsyms, when we have split the maps per module
458 */
459 symbols__insert(root, sym);
460 return 0;
461}
224 462
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 463/*
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 464 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
227 *curr = rb_entry(nd, struct symbol, rb_node); 465 * so that we can in the next step set the symbol ->end address and then
466 * call kernel_maps__split_kallsyms.
467 */
468static int dso__load_all_kallsyms(struct dso *self, const char *filename,
469 struct map *map)
470{
471 struct process_kallsyms_args args = { .map = map, .dso = self, };
472 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
473}
228 474
229 prev->end = curr->start - 1; 475/*
230 prevnd = nd; 476 * Split the symbols into maps, making sure there are no overlaps, i.e. the
231 } 477 * kernel range is broken in several maps, named [kernel].N, as we don't have
478 * the original ELF section names vmlinux have.
479 */
480static int dso__split_kallsyms(struct dso *self, struct map *map,
481 symbol_filter_t filter)
482{
483 struct map_groups *kmaps = map__kmap(map)->kmaps;
484 struct map *curr_map = map;
485 struct symbol *pos;
486 int count = 0;
487 struct rb_root *root = &self->symbols[map->type];
488 struct rb_node *next = rb_first(root);
489 int kernel_range = 0;
232 490
233 free(line); 491 while (next) {
234 fclose(file); 492 char *module;
493
494 pos = rb_entry(next, struct symbol, rb_node);
495 next = rb_next(&pos->rb_node);
496
497 module = strchr(pos->name, '\t');
498 if (module) {
499 if (!symbol_conf.use_modules)
500 goto discard_symbol;
501
502 *module++ = '\0';
503
504 if (strcmp(curr_map->dso->short_name, module)) {
505 curr_map = map_groups__find_by_name(kmaps, map->type, module);
506 if (curr_map == NULL) {
507 pr_debug("/proc/{kallsyms,modules} "
508 "inconsistency while looking "
509 "for \"%s\" module!\n", module);
510 return -1;
511 }
512
513 if (curr_map->dso->loaded)
514 goto discard_symbol;
515 }
516 /*
517 * So that we look just like we get from .ko files,
518 * i.e. not prelinked, relative to map->start.
519 */
520 pos->start = curr_map->map_ip(curr_map, pos->start);
521 pos->end = curr_map->map_ip(curr_map, pos->end);
522 } else if (curr_map != map) {
523 char dso_name[PATH_MAX];
524 struct dso *dso;
525
526 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
527 kernel_range++);
528
529 dso = dso__new(dso_name);
530 if (dso == NULL)
531 return -1;
532
533 curr_map = map__new2(pos->start, dso, map->type);
534 if (curr_map == NULL) {
535 dso__delete(dso);
536 return -1;
537 }
538
539 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
540 map_groups__insert(kmaps, curr_map);
541 ++kernel_range;
542 }
543
544 if (filter && filter(curr_map, pos)) {
545discard_symbol: rb_erase(&pos->rb_node, root);
546 symbol__delete(pos);
547 } else {
548 if (curr_map != map) {
549 rb_erase(&pos->rb_node, root);
550 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
551 }
552 count++;
553 }
554 }
235 555
236 return count; 556 return count;
557}
237 558
238out_delete_line: 559int dso__load_kallsyms(struct dso *self, const char *filename,
239 free(line); 560 struct map *map, symbol_filter_t filter)
240out_failure: 561{
241 return -1; 562 if (dso__load_all_kallsyms(self, filename, map) < 0)
563 return -1;
564
565 symbols__fixup_end(&self->symbols[map->type]);
566 self->origin = DSO__ORIG_KERNEL;
567
568 return dso__split_kallsyms(self, map, filter);
242} 569}
243 570
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 571static int dso__load_perf_map(struct dso *self, struct map *map,
572 symbol_filter_t filter)
245{ 573{
246 char *line = NULL; 574 char *line = NULL;
247 size_t n; 575 size_t n;
248 FILE *file; 576 FILE *file;
249 int nr_syms = 0; 577 int nr_syms = 0;
250 578
251 file = fopen(self->name, "r"); 579 file = fopen(self->long_name, "r");
252 if (file == NULL) 580 if (file == NULL)
253 goto out_failure; 581 goto out_failure;
254 582
@@ -278,16 +606,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 606 if (len + 2 >= line_len)
279 continue; 607 continue;
280 608
281 sym = symbol__new(start, size, line + len, 609 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 610
284 if (sym == NULL) 611 if (sym == NULL)
285 goto out_delete_line; 612 goto out_delete_line;
286 613
287 if (filter && filter(self, sym)) 614 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 615 symbol__delete(sym);
289 else { 616 else {
290 dso__insert_symbol(self, sym); 617 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 618 nr_syms++;
292 } 619 }
293 } 620 }
@@ -327,6 +654,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
327 sym->st_shndx != SHN_UNDEF; 654 sym->st_shndx != SHN_UNDEF;
328} 655}
329 656
657static inline bool elf_sym__is_object(const GElf_Sym *sym)
658{
659 return elf_sym__type(sym) == STT_OBJECT &&
660 sym->st_name != 0 &&
661 sym->st_shndx != SHN_UNDEF;
662}
663
330static inline int elf_sym__is_label(const GElf_Sym *sym) 664static inline int elf_sym__is_label(const GElf_Sym *sym)
331{ 665{
332 return elf_sym__type(sym) == STT_NOTYPE && 666 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -347,6 +681,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
347 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 681 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
348} 682}
349 683
684static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
685 const Elf_Data *secstrs)
686{
687 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
688}
689
350static inline const char *elf_sym__name(const GElf_Sym *sym, 690static inline const char *elf_sym__name(const GElf_Sym *sym,
351 const Elf_Data *symstrs) 691 const Elf_Data *symstrs)
352{ 692{
@@ -393,7 +733,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
393 * And always look at the original dso, not at debuginfo packages, that 733 * And always look at the original dso, not at debuginfo packages, that
394 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 734 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 735 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 736static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
737 symbol_filter_t filter)
397{ 738{
398 uint32_t nr_rel_entries, idx; 739 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 740 GElf_Sym sym;
@@ -409,7 +750,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 750 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 751 int nr = 0, symidx, fd, err = 0;
411 752
412 fd = open(self->name, O_RDONLY); 753 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 754 if (fd < 0)
414 goto out; 755 goto out;
415 756
@@ -477,12 +818,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 818 "%s@plt", elf_sym__name(&sym, symstrs));
478 819
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 820 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 821 sympltname);
481 if (!f) 822 if (!f)
482 goto out_elf_end; 823 goto out_elf_end;
483 824
484 dso__insert_symbol(self, f); 825 if (filter && filter(map, f))
485 ++nr; 826 symbol__delete(f);
827 else {
828 symbols__insert(&self->symbols[map->type], f);
829 ++nr;
830 }
486 } 831 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 832 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 833 GElf_Rel pos_mem, *pos;
@@ -495,12 +840,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 840 "%s@plt", elf_sym__name(&sym, symstrs));
496 841
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 842 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 843 sympltname);
499 if (!f) 844 if (!f)
500 goto out_elf_end; 845 goto out_elf_end;
501 846
502 dso__insert_symbol(self, f); 847 if (filter && filter(map, f))
503 ++nr; 848 symbol__delete(f);
849 else {
850 symbols__insert(&self->symbols[map->type], f);
851 ++nr;
852 }
504 } 853 }
505 } 854 }
506 855
@@ -513,14 +862,42 @@ out_close:
513 if (err == 0) 862 if (err == 0)
514 return nr; 863 return nr;
515out: 864out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 865 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 866 __func__, self->long_name);
518 return 0; 867 return 0;
519} 868}
520 869
521static int dso__load_sym(struct dso *self, int fd, const char *name, 870static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
522 symbol_filter_t filter, int v, struct module *mod) 871{
872 switch (type) {
873 case MAP__FUNCTION:
874 return elf_sym__is_function(self);
875 case MAP__VARIABLE:
876 return elf_sym__is_object(self);
877 default:
878 return false;
879 }
880}
881
882static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
523{ 883{
884 switch (type) {
885 case MAP__FUNCTION:
886 return elf_sec__is_text(self, secstrs);
887 case MAP__VARIABLE:
888 return elf_sec__is_data(self, secstrs);
889 default:
890 return false;
891 }
892}
893
894static int dso__load_sym(struct dso *self, struct map *map, const char *name,
895 int fd, symbol_filter_t filter, int kmodule)
896{
897 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
898 struct map *curr_map = map;
899 struct dso *curr_dso = self;
900 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 901 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 902 uint32_t nr_syms;
526 int err = -1; 903 int err = -1;
@@ -531,19 +908,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 908 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 909 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 910 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 911 int nr = 0;
535 912
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 913 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 914 if (elf == NULL) {
538 if (v) 915 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
539 fprintf(stderr, "%s: cannot read %s ELF file.\n",
540 __func__, name);
541 goto out_close; 916 goto out_close;
542 } 917 }
543 918
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 919 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 920 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 921 goto out_elf_end;
548 } 922 }
549 923
@@ -577,7 +951,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
577 nr_syms = shdr.sh_size / shdr.sh_entsize; 951 nr_syms = shdr.sh_size / shdr.sh_entsize;
578 952
579 memset(&sym, 0, sizeof(sym)); 953 memset(&sym, 0, sizeof(sym));
580 if (!kernel) { 954 if (!self->kernel) {
581 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 955 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
582 elf_section_by_name(elf, &ehdr, &shdr, 956 elf_section_by_name(elf, &ehdr, &shdr,
583 ".gnu.prelink_undo", 957 ".gnu.prelink_undo",
@@ -586,14 +960,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
586 960
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 961 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 962 struct symbol *f;
589 const char *elf_name; 963 const char *elf_name = elf_sym__name(&sym, symstrs);
590 char *demangled; 964 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 965 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 966 const char *section_name;
595 967
596 if (!is_label && !elf_sym__is_function(&sym)) 968 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
969 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
970 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
971
972 if (!is_label && !elf_sym__is_a(&sym, map->type))
597 continue; 973 continue;
598 974
599 sec = elf_getscn(elf, sym.st_shndx); 975 sec = elf_getscn(elf, sym.st_shndx);
@@ -602,55 +978,97 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
602 978
603 gelf_getshdr(sec, &shdr); 979 gelf_getshdr(sec, &shdr);
604 980
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 981 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
606 continue; 982 continue;
607 983
608 section_name = elf_sec__name(&shdr, secstrs); 984 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 985
611 if (self->adjust_symbols) { 986 if (self->kernel || kmodule) {
612 if (v >= 2) 987 char dso_name[PATH_MAX];
613 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615 988
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 989 if (strcmp(section_name,
617 } 990 curr_dso->short_name + dso_name_len) == 0)
991 goto new_symbol;
618 992
619 if (mod) { 993 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 994 curr_map = map;
621 if (section) 995 curr_dso = self;
622 sym.st_value += section->vma; 996 goto new_symbol;
623 else {
624 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
625 mod->name, section_name);
626 goto out_elf_end;
627 } 997 }
998
999 snprintf(dso_name, sizeof(dso_name),
1000 "%s%s", self->short_name, section_name);
1001
1002 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
1003 if (curr_map == NULL) {
1004 u64 start = sym.st_value;
1005
1006 if (kmodule)
1007 start += map->start + shdr.sh_offset;
1008
1009 curr_dso = dso__new(dso_name);
1010 if (curr_dso == NULL)
1011 goto out_elf_end;
1012 curr_map = map__new2(start, curr_dso,
1013 map->type);
1014 if (curr_map == NULL) {
1015 dso__delete(curr_dso);
1016 goto out_elf_end;
1017 }
1018 curr_map->map_ip = identity__map_ip;
1019 curr_map->unmap_ip = identity__map_ip;
1020 curr_dso->origin = DSO__ORIG_KERNEL;
1021 map_groups__insert(kmap->kmaps, curr_map);
1022 dsos__add(&dsos__kernel, curr_dso);
1023 dso__set_loaded(curr_dso, map->type);
1024 } else
1025 curr_dso = curr_map->dso;
1026
1027 goto new_symbol;
1028 }
1029
1030 if (curr_dso->adjust_symbols) {
1031 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1032 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1033 (u64)sym.st_value, (u64)shdr.sh_addr,
1034 (u64)shdr.sh_offset);
1035 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 1036 }
629 /* 1037 /*
630 * We need to figure out if the object was created from C++ sources 1038 * We need to figure out if the object was created from C++ sources
631 * DWARF DW_compile_unit has this, but we don't always have access 1039 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 1040 * to it...
633 */ 1041 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 1042 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 1043 if (demangled != NULL)
637 elf_name = demangled; 1044 elf_name = demangled;
638 1045new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 1046 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 1047 free(demangled);
642 if (!f) 1048 if (!f)
643 goto out_elf_end; 1049 goto out_elf_end;
644 1050
645 if (filter && filter(self, f)) 1051 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 1052 symbol__delete(f);
647 else { 1053 else {
648 f->module = mod; 1054 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 1055 nr++;
651 } 1056 }
652 } 1057 }
653 1058
1059 /*
1060 * For misannotated, zeroed, ASM function sizes.
1061 */
1062 if (nr > 0) {
1063 symbols__fixup_end(&self->symbols[map->type]);
1064 if (kmap) {
1065 /*
1066 * We need to fixup this here too because we create new
1067 * maps here, for things like vsyscall sections.
1068 */
1069 __map_groups__fixup_end(kmap->kmaps, map->type);
1070 }
1071 }
654 err = nr; 1072 err = nr;
655out_elf_end: 1073out_elf_end:
656 elf_end(elf); 1074 elf_end(elf);
@@ -658,63 +1076,157 @@ out_close:
658 return err; 1076 return err;
659} 1077}
660 1078
661#define BUILD_ID_SIZE 128 1079static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1080{
1081 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1082}
662 1083
663static char *dso__read_build_id(struct dso *self, int v) 1084static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
664{ 1085{
665 int i; 1086 bool have_build_id = false;
1087 struct dso *pos;
1088
1089 list_for_each_entry(pos, head, node) {
1090 if (with_hits && !pos->hit)
1091 continue;
1092 if (filename__read_build_id(pos->long_name, pos->build_id,
1093 sizeof(pos->build_id)) > 0) {
1094 have_build_id = true;
1095 pos->has_build_id = true;
1096 }
1097 }
1098
1099 return have_build_id;
1100}
1101
1102bool dsos__read_build_ids(bool with_hits)
1103{
1104 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1105 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
1106 return kbuildids || ubuildids;
1107}
1108
1109/*
1110 * Align offset to 4 bytes as needed for note name and descriptor data.
1111 */
1112#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1113
1114int filename__read_build_id(const char *filename, void *bf, size_t size)
1115{
1116 int fd, err = -1;
666 GElf_Ehdr ehdr; 1117 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 1118 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 1119 Elf_Data *data;
669 Elf_Scn *sec; 1120 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 1121 Elf_Kind ek;
671 unsigned char *raw; 1122 void *ptr;
672 Elf *elf; 1123 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 1124
1125 if (size < BUILD_ID_SIZE)
1126 goto out;
1127
1128 fd = open(filename, O_RDONLY);
675 if (fd < 0) 1129 if (fd < 0)
676 goto out; 1130 goto out;
677 1131
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1132 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 1133 if (elf == NULL) {
680 if (v) 1134 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
681 fprintf(stderr, "%s: cannot read %s ELF file.\n",
682 __func__, self->name);
683 goto out_close; 1135 goto out_close;
684 } 1136 }
685 1137
1138 ek = elf_kind(elf);
1139 if (ek != ELF_K_ELF)
1140 goto out_elf_end;
1141
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 1142 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 1143 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 1144 goto out_elf_end;
690 } 1145 }
691 1146
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 1147 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 1148 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 1149 if (sec == NULL) {
1150 sec = elf_section_by_name(elf, &ehdr, &shdr,
1151 ".notes", NULL);
1152 if (sec == NULL)
1153 goto out_elf_end;
1154 }
695 1155
696 build_id_data = elf_getdata(sec, NULL); 1156 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 1157 if (data == NULL)
698 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end; 1158 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 1159
705 for (i = 0; i < 20; ++i) { 1160 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 1161 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 1162 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1163 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1164 descsz = NOTE_ALIGN(nhdr->n_descsz);
1165 const char *name;
1166
1167 ptr += sizeof(*nhdr);
1168 name = ptr;
1169 ptr += namesz;
1170 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1171 nhdr->n_namesz == sizeof("GNU")) {
1172 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1173 memcpy(bf, ptr, BUILD_ID_SIZE);
1174 err = BUILD_ID_SIZE;
1175 break;
1176 }
1177 }
1178 ptr += descsz;
709 } 1179 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1180out_elf_end:
713 elf_end(elf); 1181 elf_end(elf);
714out_close: 1182out_close:
715 close(fd); 1183 close(fd);
716out: 1184out:
717 return build_id; 1185 return err;
1186}
1187
1188int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1189{
1190 int fd, err = -1;
1191
1192 if (size < BUILD_ID_SIZE)
1193 goto out;
1194
1195 fd = open(filename, O_RDONLY);
1196 if (fd < 0)
1197 goto out;
1198
1199 while (1) {
1200 char bf[BUFSIZ];
1201 GElf_Nhdr nhdr;
1202 int namesz, descsz;
1203
1204 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1205 break;
1206
1207 namesz = NOTE_ALIGN(nhdr.n_namesz);
1208 descsz = NOTE_ALIGN(nhdr.n_descsz);
1209 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1210 nhdr.n_namesz == sizeof("GNU")) {
1211 if (read(fd, bf, namesz) != namesz)
1212 break;
1213 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1214 if (read(fd, build_id,
1215 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1216 err = 0;
1217 break;
1218 }
1219 } else if (read(fd, bf, descsz) != descsz)
1220 break;
1221 } else {
1222 int n = namesz + descsz;
1223 if (read(fd, bf, n) != n)
1224 break;
1225 }
1226 }
1227 close(fd);
1228out:
1229 return err;
718} 1230}
719 1231
720char dso__symtab_origin(const struct dso *self) 1232char dso__symtab_origin(const struct dso *self)
@@ -722,10 +1234,12 @@ char dso__symtab_origin(const struct dso *self)
722 static const char origin[] = { 1234 static const char origin[] = {
723 [DSO__ORIG_KERNEL] = 'k', 1235 [DSO__ORIG_KERNEL] = 'k',
724 [DSO__ORIG_JAVA_JIT] = 'j', 1236 [DSO__ORIG_JAVA_JIT] = 'j',
1237 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
725 [DSO__ORIG_FEDORA] = 'f', 1238 [DSO__ORIG_FEDORA] = 'f',
726 [DSO__ORIG_UBUNTU] = 'u', 1239 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1240 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1241 [DSO__ORIG_DSO] = 'd',
1242 [DSO__ORIG_KMODULE] = 'K',
729 }; 1243 };
730 1244
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1245 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,60 +1247,90 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1247 return origin[self->origin];
734} 1248}
735 1249
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1250int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
737{ 1251{
738 int size = PATH_MAX; 1252 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1253 char *name;
1254 u8 build_id[BUILD_ID_SIZE];
1255 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
740 int ret = -1; 1256 int ret = -1;
741 int fd; 1257 int fd;
742 1258
1259 dso__set_loaded(self, map->type);
1260
1261 if (self->kernel)
1262 return dso__load_kernel_sym(self, map, filter);
1263
1264 name = malloc(size);
743 if (!name) 1265 if (!name)
744 return -1; 1266 return -1;
745 1267
746 self->adjust_symbols = 0; 1268 self->adjust_symbols = 0;
747 1269
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1270 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1271 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1272 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1273 DSO__ORIG_NOT_FOUND;
752 return ret; 1274 return ret;
753 } 1275 }
754 1276
755 self->origin = DSO__ORIG_FEDORA - 1; 1277 self->origin = DSO__ORIG_BUILD_ID_CACHE;
756 1278
1279 if (self->has_build_id) {
1280 build_id__sprintf(self->build_id, sizeof(self->build_id),
1281 build_id_hex);
1282 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1283 getenv("HOME"), DEBUG_CACHE_DIR,
1284 build_id_hex, build_id_hex + 2);
1285 goto open_file;
1286 }
757more: 1287more:
758 do { 1288 do {
759 self->origin++; 1289 self->origin++;
760 switch (self->origin) { 1290 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1291 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1292 snprintf(name, size, "/usr/lib/debug%s.debug",
1293 self->long_name);
763 break; 1294 break;
764 case DSO__ORIG_UBUNTU: 1295 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1296 snprintf(name, size, "/usr/lib/debug%s",
1297 self->long_name);
766 break; 1298 break;
767 case DSO__ORIG_BUILDID: 1299 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1300 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1301 sizeof(build_id))) {
1302 build_id__sprintf(build_id, sizeof(build_id),
1303 build_id_hex);
770 snprintf(name, size, 1304 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1305 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1306 build_id_hex, build_id_hex + 2);
773 free(build_id); 1307 if (self->has_build_id)
1308 goto compare_build_id;
774 break; 1309 break;
775 } 1310 }
776 self->origin++; 1311 self->origin++;
777 /* Fall thru */ 1312 /* Fall thru */
778 case DSO__ORIG_DSO: 1313 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1314 snprintf(name, size, "%s", self->long_name);
780 break; 1315 break;
781 1316
782 default: 1317 default:
783 goto out; 1318 goto out;
784 } 1319 }
785 1320
1321 if (self->has_build_id) {
1322 if (filename__read_build_id(name, build_id,
1323 sizeof(build_id)) < 0)
1324 goto more;
1325compare_build_id:
1326 if (!dso__build_id_equal(self, build_id))
1327 goto more;
1328 }
1329open_file:
786 fd = open(name, O_RDONLY); 1330 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1331 } while (fd < 0);
788 1332
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1333 ret = dso__load_sym(self, map, name, fd, filter, 0);
790 close(fd); 1334 close(fd);
791 1335
792 /* 1336 /*
@@ -796,7 +1340,7 @@ more:
796 goto more; 1340 goto more;
797 1341
798 if (ret > 0) { 1342 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1343 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1344 if (nr_plt > 0)
801 ret += nr_plt; 1345 ret += nr_plt;
802 } 1346 }
@@ -807,231 +1351,608 @@ out:
807 return ret; 1351 return ret;
808} 1352}
809 1353
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1354struct map *map_groups__find_by_name(struct map_groups *self,
811 symbol_filter_t filter, int v) 1355 enum map_type type, const char *name)
812{ 1356{
813 struct module *mod = mod_dso__find_module(mods, name); 1357 struct rb_node *nd;
814 int err = 0, fd;
815 1358
816 if (mod == NULL || !mod->active) 1359 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
817 return err; 1360 struct map *map = rb_entry(nd, struct map, rb_node);
818 1361
819 fd = open(mod->path, O_RDONLY); 1362 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1363 return map;
1364 }
820 1365
821 if (fd < 0) 1366 return NULL;
822 return err; 1367}
823 1368
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1369static int dso__kernel_module_get_build_id(struct dso *self)
825 close(fd); 1370{
1371 char filename[PATH_MAX];
1372 /*
1373 * kernel module short names are of the form "[module]" and
1374 * we need just "module" here.
1375 */
1376 const char *name = self->short_name + 1;
826 1377
827 return err; 1378 snprintf(filename, sizeof(filename),
1379 "/sys/module/%.*s/notes/.note.gnu.build-id",
1380 (int)strlen(name - 1), name);
1381
1382 if (sysfs__read_build_id(filename, self->build_id,
1383 sizeof(self->build_id)) == 0)
1384 self->has_build_id = true;
1385
1386 return 0;
828} 1387}
829 1388
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1389static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
831{ 1390{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1391 struct dirent *dent;
833 struct module *pos; 1392 DIR *dir = opendir(dirname);
834 struct rb_node *next;
835 int err, count = 0;
836 1393
837 err = mod_dso__load_modules(mods); 1394 if (!dir) {
1395 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1396 return -1;
1397 }
838 1398
839 if (err <= 0) 1399 while ((dent = readdir(dir)) != NULL) {
840 return err; 1400 char path[PATH_MAX];
1401
1402 if (dent->d_type == DT_DIR) {
1403 if (!strcmp(dent->d_name, ".") ||
1404 !strcmp(dent->d_name, ".."))
1405 continue;
1406
1407 snprintf(path, sizeof(path), "%s/%s",
1408 dirname, dent->d_name);
1409 if (map_groups__set_modules_path_dir(self, path) < 0)
1410 goto failure;
1411 } else {
1412 char *dot = strrchr(dent->d_name, '.'),
1413 dso_name[PATH_MAX];
1414 struct map *map;
1415 char *long_name;
1416
1417 if (dot == NULL || strcmp(dot, ".ko"))
1418 continue;
1419 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1420 (int)(dot - dent->d_name), dent->d_name);
1421
1422 strxfrchar(dso_name, '-', '_');
1423 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1424 if (map == NULL)
1425 continue;
1426
1427 snprintf(path, sizeof(path), "%s/%s",
1428 dirname, dent->d_name);
1429
1430 long_name = strdup(path);
1431 if (long_name == NULL)
1432 goto failure;
1433 dso__set_long_name(map->dso, long_name);
1434 dso__kernel_module_get_build_id(map->dso);
1435 }
1436 }
841 1437
842 /* 1438 return 0;
843 * Iterate over modules, and load active symbols. 1439failure:
844 */ 1440 closedir(dir);
845 next = rb_first(&mods->mods); 1441 return -1;
846 while (next) { 1442}
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849 1443
850 if (err < 0) 1444static int map_groups__set_modules_path(struct map_groups *self)
851 break; 1445{
1446 struct utsname uts;
1447 char modules_path[PATH_MAX];
852 1448
853 next = rb_next(&pos->rb_node); 1449 if (uname(&uts) < 0)
854 count += err; 1450 return -1;
855 }
856 1451
857 if (err < 0) { 1452 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
858 mod_dso__delete_modules(mods); 1453 uts.release);
859 mod_dso__delete_self(mods); 1454
860 return err; 1455 return map_groups__set_modules_path_dir(self, modules_path);
1456}
1457
1458/*
1459 * Constructor variant for modules (where we know from /proc/modules where
1460 * they are loaded) and for vmlinux, where only after we load all the
1461 * symbols we'll know where it starts and ends.
1462 */
1463static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1464{
1465 struct map *self = zalloc(sizeof(*self) +
1466 (dso->kernel ? sizeof(struct kmap) : 0));
1467 if (self != NULL) {
1468 /*
1469 * ->end will be filled after we load all the symbols
1470 */
1471 map__init(self, type, start, 0, 0, dso);
861 } 1472 }
862 1473
863 return count; 1474 return self;
864} 1475}
865 1476
866static inline void dso__fill_symbol_holes(struct dso *self) 1477struct map *map_groups__new_module(struct map_groups *self, u64 start,
1478 const char *filename)
867{ 1479{
868 struct symbol *prev = NULL; 1480 struct map *map;
869 struct rb_node *nd; 1481 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
870 1482
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1483 if (dso == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1484 return NULL;
873 1485
874 if (prev) { 1486 map = map__new2(start, dso, MAP__FUNCTION);
875 u64 hole = 0; 1487 if (map == NULL)
876 int alias = pos->start == prev->start; 1488 return NULL;
877 1489
878 if (!alias) 1490 dso->origin = DSO__ORIG_KMODULE;
879 hole = prev->start - pos->end - 1; 1491 map_groups__insert(self, map);
1492 return map;
1493}
880 1494
881 if (hole || alias) { 1495static int map_groups__create_modules(struct map_groups *self)
882 if (alias) 1496{
883 pos->end = prev->end; 1497 char *line = NULL;
884 else if (hole) 1498 size_t n;
885 pos->end = prev->start - 1; 1499 FILE *file = fopen("/proc/modules", "r");
886 } 1500 struct map *map;
887 } 1501
888 prev = pos; 1502 if (file == NULL)
1503 return -1;
1504
1505 while (!feof(file)) {
1506 char name[PATH_MAX];
1507 u64 start;
1508 char *sep;
1509 int line_len;
1510
1511 line_len = getline(&line, &n, file);
1512 if (line_len < 0)
1513 break;
1514
1515 if (!line)
1516 goto out_failure;
1517
1518 line[--line_len] = '\0'; /* \n */
1519
1520 sep = strrchr(line, 'x');
1521 if (sep == NULL)
1522 continue;
1523
1524 hex2u64(sep + 1, &start);
1525
1526 sep = strchr(line, ' ');
1527 if (sep == NULL)
1528 continue;
1529
1530 *sep = '\0';
1531
1532 snprintf(name, sizeof(name), "[%s]", line);
1533 map = map_groups__new_module(self, start, name);
1534 if (map == NULL)
1535 goto out_delete_line;
1536 dso__kernel_module_get_build_id(map->dso);
889 } 1537 }
1538
1539 free(line);
1540 fclose(file);
1541
1542 return map_groups__set_modules_path(self);
1543
1544out_delete_line:
1545 free(line);
1546out_failure:
1547 return -1;
890} 1548}
891 1549
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1550static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1551 const char *vmlinux, symbol_filter_t filter)
894{ 1552{
895 int err, fd = open(vmlinux, O_RDONLY); 1553 int err = -1, fd;
1554
1555 if (self->has_build_id) {
1556 u8 build_id[BUILD_ID_SIZE];
1557
1558 if (filename__read_build_id(vmlinux, build_id,
1559 sizeof(build_id)) < 0) {
1560 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1561 return -1;
1562 }
1563 if (!dso__build_id_equal(self, build_id)) {
1564 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1565 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1566
1567 build_id__sprintf(self->build_id,
1568 sizeof(self->build_id),
1569 expected_build_id);
1570 build_id__sprintf(build_id, sizeof(build_id),
1571 vmlinux_build_id);
1572 pr_debug("build_id in %s is %s while expected is %s, "
1573 "ignoring it\n", vmlinux, vmlinux_build_id,
1574 expected_build_id);
1575 return -1;
1576 }
1577 }
896 1578
1579 fd = open(vmlinux, O_RDONLY);
897 if (fd < 0) 1580 if (fd < 0)
898 return -1; 1581 return -1;
899 1582
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1583 dso__set_loaded(self, map->type);
1584 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1585 close(fd);
901 1586
902 if (err > 0) 1587 if (err > 0)
903 dso__fill_symbol_holes(self); 1588 pr_debug("Using %s for symbols\n", vmlinux);
904 1589
905 close(fd); 1590 return err;
1591}
1592
1593int dso__load_vmlinux_path(struct dso *self, struct map *map,
1594 symbol_filter_t filter)
1595{
1596 int i, err = 0;
1597
1598 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1599 vmlinux_path__nr_entries);
1600
1601 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1602 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1603 if (err > 0) {
1604 dso__set_long_name(self, strdup(vmlinux_path[i]));
1605 break;
1606 }
1607 }
906 1608
907 return err; 1609 return err;
908} 1610}
909 1611
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1612static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1613 symbol_filter_t filter)
912{ 1614{
913 int err = -1; 1615 int err;
1616 const char *kallsyms_filename = NULL;
1617 char *kallsyms_allocated_filename = NULL;
1618 /*
1619 * Step 1: if the user specified a vmlinux filename, use it and only
1620 * it, reporting errors to the user if it cannot be used.
1621 *
1622 * For instance, try to analyse an ARM perf.data file _without_ a
1623 * build-id, or if the user specifies the wrong path to the right
1624 * vmlinux file, obviously we can't fallback to another vmlinux (a
1625 * x86_86 one, on the machine where analysis is being performed, say),
1626 * or worse, /proc/kallsyms.
1627 *
1628 * If the specified file _has_ a build-id and there is a build-id
1629 * section in the perf.data file, we will still do the expected
1630 * validation in dso__load_vmlinux and will bail out if they don't
1631 * match.
1632 */
1633 if (symbol_conf.vmlinux_name != NULL) {
1634 err = dso__load_vmlinux(self, map,
1635 symbol_conf.vmlinux_name, filter);
1636 goto out_try_fixup;
1637 }
914 1638
915 if (vmlinux) { 1639 if (vmlinux_path != NULL) {
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1640 err = dso__load_vmlinux_path(self, map, filter);
917 if (err > 0 && use_modules) { 1641 if (err > 0)
918 int syms = dso__load_modules(self, filter, v); 1642 goto out_fixup;
1643 }
919 1644
920 if (syms < 0) { 1645 /*
921 fprintf(stderr, "dso__load_modules failed!\n"); 1646 * Say the kernel DSO was created when processing the build-id header table,
922 return syms; 1647 * we have a build-id, so check if it is the same as the running kernel,
1648 * using it if it is.
1649 */
1650 if (self->has_build_id) {
1651 u8 kallsyms_build_id[BUILD_ID_SIZE];
1652 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1653
1654 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1655 sizeof(kallsyms_build_id)) == 0) {
1656 if (dso__build_id_equal(self, kallsyms_build_id)) {
1657 kallsyms_filename = "/proc/kallsyms";
1658 goto do_kallsyms;
923 } 1659 }
924 err += syms;
925 } 1660 }
926 } 1661 /*
1662 * Now look if we have it on the build-id cache in
1663 * $HOME/.debug/[kernel.kallsyms].
1664 */
1665 build_id__sprintf(self->build_id, sizeof(self->build_id),
1666 sbuild_id);
1667
1668 if (asprintf(&kallsyms_allocated_filename,
1669 "%s/.debug/[kernel.kallsyms]/%s",
1670 getenv("HOME"), sbuild_id) == -1) {
1671 pr_err("Not enough memory for kallsyms file lookup\n");
1672 return -1;
1673 }
1674
1675 kallsyms_filename = kallsyms_allocated_filename;
927 1676
928 if (err <= 0) 1677 if (access(kallsyms_filename, F_OK)) {
929 err = dso__load_kallsyms(self, filter, v); 1678 pr_err("No kallsyms or vmlinux with build-id %s "
1679 "was found\n", sbuild_id);
1680 free(kallsyms_allocated_filename);
1681 return -1;
1682 }
1683 } else {
1684 /*
1685 * Last resort, if we don't have a build-id and couldn't find
1686 * any vmlinux file, try the running kernel kallsyms table.
1687 */
1688 kallsyms_filename = "/proc/kallsyms";
1689 }
930 1690
1691do_kallsyms:
1692 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
931 if (err > 0) 1693 if (err > 0)
932 self->origin = DSO__ORIG_KERNEL; 1694 pr_debug("Using %s for symbols\n", kallsyms_filename);
1695 free(kallsyms_allocated_filename);
1696
1697out_try_fixup:
1698 if (err > 0) {
1699out_fixup:
1700 if (kallsyms_filename != NULL)
1701 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1702 map__fixup_start(map);
1703 map__fixup_end(map);
1704 }
933 1705
934 return err; 1706 return err;
935} 1707}
936 1708
937LIST_HEAD(dsos); 1709LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1710LIST_HEAD(dsos__kernel);
939struct dso *vdso;
940struct dso *hypervisor_dso;
941
942const char *vmlinux_name = "vmlinux";
943int modules;
944 1711
945static void dsos__add(struct dso *dso) 1712static void dsos__add(struct list_head *head, struct dso *dso)
946{ 1713{
947 list_add_tail(&dso->node, &dsos); 1714 list_add_tail(&dso->node, head);
948} 1715}
949 1716
950static struct dso *dsos__find(const char *name) 1717static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1718{
952 struct dso *pos; 1719 struct dso *pos;
953 1720
954 list_for_each_entry(pos, &dsos, node) 1721 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1722 if (strcmp(pos->long_name, name) == 0)
956 return pos; 1723 return pos;
957 return NULL; 1724 return NULL;
958} 1725}
959 1726
960struct dso *dsos__findnew(const char *name) 1727struct dso *__dsos__findnew(struct list_head *head, const char *name)
961{ 1728{
962 struct dso *dso = dsos__find(name); 1729 struct dso *dso = dsos__find(head, name);
963 int nr;
964
965 if (dso)
966 return dso;
967
968 dso = dso__new(name, 0);
969 if (!dso)
970 goto out_delete_dso;
971 1730
972 nr = dso__load(dso, NULL, verbose); 1731 if (!dso) {
973 if (nr < 0) { 1732 dso = dso__new(name);
974 eprintf("Failed to open: %s\n", name); 1733 if (dso != NULL) {
975 goto out_delete_dso; 1734 dsos__add(head, dso);
1735 dso__set_basename(dso);
1736 }
976 } 1737 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1738
982 return dso; 1739 return dso;
1740}
983 1741
984out_delete_dso: 1742static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1743{
986 return NULL; 1744 struct dso *pos;
1745
1746 list_for_each_entry(pos, head, node) {
1747 int i;
1748 for (i = 0; i < MAP__NR_TYPES; ++i)
1749 dso__fprintf(pos, i, fp);
1750 }
987} 1751}
988 1752
989void dsos__fprintf(FILE *fp) 1753void dsos__fprintf(FILE *fp)
990{ 1754{
1755 __dsos__fprintf(&dsos__kernel, fp);
1756 __dsos__fprintf(&dsos__user, fp);
1757}
1758
1759static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1760 bool with_hits)
1761{
991 struct dso *pos; 1762 struct dso *pos;
1763 size_t ret = 0;
992 1764
993 list_for_each_entry(pos, &dsos, node) 1765 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1766 if (with_hits && !pos->hit)
1767 continue;
1768 ret += dso__fprintf_buildid(pos, fp);
1769 ret += fprintf(fp, " %s\n", pos->long_name);
1770 }
1771 return ret;
995} 1772}
996 1773
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1774size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
998{ 1775{
999 return dso__find_symbol(dso, ip); 1776 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1777 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1000} 1778}
1001 1779
1002int load_kernel(void) 1780struct dso *dso__new_kernel(const char *name)
1003{ 1781{
1004 int err; 1782 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1005 1783
1006 kernel_dso = dso__new("[kernel]", 0); 1784 if (self != NULL) {
1007 if (!kernel_dso) 1785 self->short_name = "[kernel]";
1008 return -1; 1786 self->kernel = 1;
1787 }
1009 1788
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1789 return self;
1011 if (err <= 0) { 1790}
1012 dso__delete(kernel_dso);
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1791
1017 vdso = dso__new("[vdso]", 0); 1792void dso__read_running_kernel_build_id(struct dso *self)
1018 if (!vdso) 1793{
1019 return -1; 1794 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1795 sizeof(self->build_id)) == 0)
1796 self->has_build_id = true;
1797}
1798
1799static struct dso *dsos__create_kernel(const char *vmlinux)
1800{
1801 struct dso *kernel = dso__new_kernel(vmlinux);
1802
1803 if (kernel != NULL) {
1804 dso__read_running_kernel_build_id(kernel);
1805 dsos__add(&dsos__kernel, kernel);
1806 }
1807
1808 return kernel;
1809}
1810
1811int __map_groups__create_kernel_maps(struct map_groups *self,
1812 struct map *vmlinux_maps[MAP__NR_TYPES],
1813 struct dso *kernel)
1814{
1815 enum map_type type;
1816
1817 for (type = 0; type < MAP__NR_TYPES; ++type) {
1818 struct kmap *kmap;
1819
1820 vmlinux_maps[type] = map__new2(0, kernel, type);
1821 if (vmlinux_maps[type] == NULL)
1822 return -1;
1823
1824 vmlinux_maps[type]->map_ip =
1825 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1826
1827 kmap = map__kmap(vmlinux_maps[type]);
1828 kmap->kmaps = self;
1829 map_groups__insert(self, vmlinux_maps[type]);
1830 }
1831
1832 return 0;
1833}
1834
1835static void vmlinux_path__exit(void)
1836{
1837 while (--vmlinux_path__nr_entries >= 0) {
1838 free(vmlinux_path[vmlinux_path__nr_entries]);
1839 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1840 }
1020 1841
1021 vdso->find_symbol = vdso__find_symbol; 1842 free(vmlinux_path);
1843 vmlinux_path = NULL;
1844}
1022 1845
1023 dsos__add(vdso); 1846static int vmlinux_path__init(void)
1847{
1848 struct utsname uts;
1849 char bf[PATH_MAX];
1024 1850
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1851 if (uname(&uts) < 0)
1026 if (!hypervisor_dso)
1027 return -1; 1852 return -1;
1028 dsos__add(hypervisor_dso);
1029 1853
1030 return err; 1854 vmlinux_path = malloc(sizeof(char *) * 5);
1855 if (vmlinux_path == NULL)
1856 return -1;
1857
1858 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1859 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1860 goto out_fail;
1861 ++vmlinux_path__nr_entries;
1862 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1863 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1864 goto out_fail;
1865 ++vmlinux_path__nr_entries;
1866 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1867 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1868 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1869 goto out_fail;
1870 ++vmlinux_path__nr_entries;
1871 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1872 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1873 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1874 goto out_fail;
1875 ++vmlinux_path__nr_entries;
1876 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1877 uts.release);
1878 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1879 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1880 goto out_fail;
1881 ++vmlinux_path__nr_entries;
1882
1883 return 0;
1884
1885out_fail:
1886 vmlinux_path__exit();
1887 return -1;
1031} 1888}
1032 1889
1890static int setup_list(struct strlist **list, const char *list_str,
1891 const char *list_name)
1892{
1893 if (list_str == NULL)
1894 return 0;
1895
1896 *list = strlist__new(true, list_str);
1897 if (!*list) {
1898 pr_err("problems parsing %s list\n", list_name);
1899 return -1;
1900 }
1901 return 0;
1902}
1033 1903
1034void symbol__init(void) 1904int symbol__init(void)
1035{ 1905{
1036 elf_version(EV_CURRENT); 1906 elf_version(EV_CURRENT);
1907 if (symbol_conf.sort_by_name)
1908 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1909 sizeof(struct symbol));
1910
1911 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1912 return -1;
1913
1914 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1915 pr_err("'.' is the only non valid --field-separator argument\n");
1916 return -1;
1917 }
1918
1919 if (setup_list(&symbol_conf.dso_list,
1920 symbol_conf.dso_list_str, "dso") < 0)
1921 return -1;
1922
1923 if (setup_list(&symbol_conf.comm_list,
1924 symbol_conf.comm_list_str, "comm") < 0)
1925 goto out_free_dso_list;
1926
1927 if (setup_list(&symbol_conf.sym_list,
1928 symbol_conf.sym_list_str, "symbol") < 0)
1929 goto out_free_comm_list;
1930
1931 return 0;
1932
1933out_free_dso_list:
1934 strlist__delete(symbol_conf.dso_list);
1935out_free_comm_list:
1936 strlist__delete(symbol_conf.comm_list);
1937 return -1;
1938}
1939
1940int map_groups__create_kernel_maps(struct map_groups *self,
1941 struct map *vmlinux_maps[MAP__NR_TYPES])
1942{
1943 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1944
1945 if (kernel == NULL)
1946 return -1;
1947
1948 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1949 return -1;
1950
1951 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
1952 pr_debug("Problems creating module maps, continuing anyway...\n");
1953 /*
1954 * Now that we have all the maps created, just set the ->end of them:
1955 */
1956 map_groups__fixup_end(self);
1957 return 0;
1037} 1958}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..280dadd32a08 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,13 +1,15 @@
1#ifndef _PERF_SYMBOL_ 1#ifndef __PERF_SYMBOL
2#define _PERF_SYMBOL_ 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h>
5#include "types.h" 6#include "types.h"
6#include <linux/list.h> 7#include <linux/list.h>
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h" 9#include "event.h"
10 10
11#define DEBUG_CACHE_DIR ".debug"
12
11#ifdef HAVE_CPLUS_DEMANGLE 13#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 14extern char *cplus_demangle(const char *, int);
13 15
@@ -46,57 +48,124 @@ struct symbol {
46 struct rb_node rb_node; 48 struct rb_node rb_node;
47 u64 start; 49 u64 start;
48 u64 end; 50 u64 end;
49 u64 obj_start;
50 u64 hist_sum;
51 u64 *hist;
52 struct module *module;
53 void *priv;
54 char name[0]; 51 char name[0];
55}; 52};
56 53
54void symbol__delete(struct symbol *self);
55
56struct strlist;
57
58struct symbol_conf {
59 unsigned short priv_size;
60 bool try_vmlinux_path,
61 use_modules,
62 sort_by_name,
63 show_nr_samples,
64 use_callchain,
65 exclude_other,
66 full_paths;
67 const char *vmlinux_name,
68 *field_sep;
69 char *dso_list_str,
70 *comm_list_str,
71 *sym_list_str,
72 *col_width_list_str;
73 struct strlist *dso_list,
74 *comm_list,
75 *sym_list;
76};
77
78extern struct symbol_conf symbol_conf;
79
80static inline void *symbol__priv(struct symbol *self)
81{
82 return ((void *)self) - symbol_conf.priv_size;
83}
84
85struct ref_reloc_sym {
86 const char *name;
87 u64 addr;
88 u64 unrelocated_addr;
89};
90
91struct addr_location {
92 struct thread *thread;
93 struct map *map;
94 struct symbol *sym;
95 u64 addr;
96 char level;
97 bool filtered;
98};
99
57struct dso { 100struct dso {
58 struct list_head node; 101 struct list_head node;
59 struct rb_root syms; 102 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 103 struct rb_root symbol_names[MAP__NR_TYPES];
61 unsigned int sym_priv_size; 104 u8 adjust_symbols:1;
62 unsigned char adjust_symbols; 105 u8 slen_calculated:1;
63 unsigned char slen_calculated; 106 u8 has_build_id:1;
107 u8 kernel:1;
108 u8 hit:1;
64 unsigned char origin; 109 unsigned char origin;
110 u8 sorted_by_name;
111 u8 loaded;
112 u8 build_id[BUILD_ID_SIZE];
113 u16 long_name_len;
114 const char *short_name;
115 char *long_name;
65 char name[0]; 116 char name[0];
66}; 117};
67 118
68extern const char *sym_hist_filter; 119struct dso *dso__new(const char *name);
69 120struct dso *dso__new_kernel(const char *name);
70typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
71
72struct dso *dso__new(const char *name, unsigned int sym_priv_size);
73void dso__delete(struct dso *self); 121void dso__delete(struct dso *self);
74 122
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 123bool dso__loaded(const struct dso *self, enum map_type type);
124bool dso__sorted_by_name(const struct dso *self, enum map_type type);
125
126static inline void dso__set_loaded(struct dso *self, enum map_type type)
76{ 127{
77 return ((void *)sym) - self->sym_priv_size; 128 self->loaded |= (1 << type);
78} 129}
79 130
80struct symbol *dso__find_symbol(struct dso *self, u64 ip); 131void dso__sort_by_name(struct dso *self, enum map_type type);
81 132
82int dso__load_kernel(struct dso *self, const char *vmlinux, 133extern struct list_head dsos__user, dsos__kernel;
83 symbol_filter_t filter, int verbose, int modules);
84int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
85int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
86struct dso *dsos__findnew(const char *name);
87void dsos__fprintf(FILE *fp);
88 134
89size_t dso__fprintf(struct dso *self, FILE *fp); 135struct dso *__dsos__findnew(struct list_head *head, const char *name);
90char dso__symtab_origin(const struct dso *self);
91 136
92int load_kernel(void); 137static inline struct dso *dsos__findnew(const char *name)
138{
139 return __dsos__findnew(&dsos__user, name);
140}
93 141
94void symbol__init(void); 142int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
143int dso__load_vmlinux_path(struct dso *self, struct map *map,
144 symbol_filter_t filter);
145int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
146 symbol_filter_t filter);
147void dsos__fprintf(FILE *fp);
148size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
95 149
96extern struct list_head dsos; 150size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
97extern struct dso *kernel_dso; 151size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
98extern struct dso *vdso; 152char dso__symtab_origin(const struct dso *self);
99extern struct dso *hypervisor_dso; 153void dso__set_long_name(struct dso *self, char *name);
100extern const char *vmlinux_name; 154void dso__set_build_id(struct dso *self, void *build_id);
101extern int modules; 155void dso__read_running_kernel_build_id(struct dso *self);
102#endif /* _PERF_SYMBOL_ */ 156struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
157struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
158 const char *name);
159
160int filename__read_build_id(const char *filename, void *bf, size_t size);
161int sysfs__read_build_id(const char *filename, void *bf, size_t size);
162bool dsos__read_build_ids(bool with_hits);
163int build_id__sprintf(const u8 *self, int len, char *bf);
164int kallsyms__parse(const char *filename, void *arg,
165 int (*process_symbol)(void *arg, const char *name,
166 char type, u64 start));
167
168int symbol__init(void);
169bool symbol_type__is_a(char symbol_type, enum map_type map_type);
170
171#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..21b92162282b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,48 +2,151 @@
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
10void map_groups__init(struct map_groups *self)
11{
12 int i;
13 for (i = 0; i < MAP__NR_TYPES; ++i) {
14 self->maps[i] = RB_ROOT;
15 INIT_LIST_HEAD(&self->removed_maps[i]);
16 }
17}
18
9static struct thread *thread__new(pid_t pid) 19static struct thread *thread__new(pid_t pid)
10{ 20{
11 struct thread *self = calloc(1, sizeof(*self)); 21 struct thread *self = zalloc(sizeof(*self));
12 22
13 if (self != NULL) { 23 if (self != NULL) {
24 map_groups__init(&self->mg);
14 self->pid = pid; 25 self->pid = pid;
15 self->comm = malloc(32); 26 self->comm = malloc(32);
16 if (self->comm) 27 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 28 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 } 29 }
20 30
21 return self; 31 return self;
22} 32}
23 33
34static void map_groups__flush(struct map_groups *self)
35{
36 int type;
37
38 for (type = 0; type < MAP__NR_TYPES; type++) {
39 struct rb_root *root = &self->maps[type];
40 struct rb_node *next = rb_first(root);
41
42 while (next) {
43 struct map *pos = rb_entry(next, struct map, rb_node);
44 next = rb_next(&pos->rb_node);
45 rb_erase(&pos->rb_node, root);
46 /*
47 * We may have references to this map, for
48 * instance in some hist_entry instances, so
49 * just move them to a separate list.
50 */
51 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
52 }
53 }
54}
55
24int thread__set_comm(struct thread *self, const char *comm) 56int thread__set_comm(struct thread *self, const char *comm)
25{ 57{
58 int err;
59
26 if (self->comm) 60 if (self->comm)
27 free(self->comm); 61 free(self->comm);
28 self->comm = strdup(comm); 62 self->comm = strdup(comm);
29 return self->comm ? 0 : -ENOMEM; 63 err = self->comm == NULL ? -ENOMEM : 0;
64 if (!err) {
65 self->comm_set = true;
66 map_groups__flush(&self->mg);
67 }
68 return err;
30} 69}
31 70
32static size_t thread__fprintf(struct thread *self, FILE *fp) 71int thread__comm_len(struct thread *self)
72{
73 if (!self->comm_len) {
74 if (!self->comm)
75 return 0;
76 self->comm_len = strlen(self->comm);
77 }
78
79 return self->comm_len;
80}
81
82static size_t __map_groups__fprintf_maps(struct map_groups *self,
83 enum map_type type, FILE *fp)
84{
85 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
86 struct rb_node *nd;
87
88 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
89 struct map *pos = rb_entry(nd, struct map, rb_node);
90 printed += fprintf(fp, "Map:");
91 printed += map__fprintf(pos, fp);
92 if (verbose > 1) {
93 printed += dso__fprintf(pos->dso, type, fp);
94 printed += fprintf(fp, "--\n");
95 }
96 }
97
98 return printed;
99}
100
101size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
102{
103 size_t printed = 0, i;
104 for (i = 0; i < MAP__NR_TYPES; ++i)
105 printed += __map_groups__fprintf_maps(self, i, fp);
106 return printed;
107}
108
109static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
110 enum map_type type, FILE *fp)
33{ 111{
34 struct map *pos; 112 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 113 size_t printed = 0;
114
115 list_for_each_entry(pos, &self->removed_maps[type], node) {
116 printed += fprintf(fp, "Map:");
117 printed += map__fprintf(pos, fp);
118 if (verbose > 1) {
119 printed += dso__fprintf(pos->dso, type, fp);
120 printed += fprintf(fp, "--\n");
121 }
122 }
123 return printed;
124}
125
126static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
127{
128 size_t printed = 0, i;
129 for (i = 0; i < MAP__NR_TYPES; ++i)
130 printed += __map_groups__fprintf_removed_maps(self, i, fp);
131 return printed;
132}
36 133
37 list_for_each_entry(pos, &self->maps, node) 134static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
38 ret += map__fprintf(pos, fp); 135{
136 size_t printed = map_groups__fprintf_maps(self, fp);
137 printed += fprintf(fp, "Removed maps:\n");
138 return printed + map_groups__fprintf_removed_maps(self, fp);
139}
39 140
40 return ret; 141static size_t thread__fprintf(struct thread *self, FILE *fp)
142{
143 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
144 map_groups__fprintf(&self->mg, fp);
41} 145}
42 146
43struct thread * 147struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 148{
46 struct rb_node **p = &threads->rb_node; 149 struct rb_node **p = &self->threads.rb_node;
47 struct rb_node *parent = NULL; 150 struct rb_node *parent = NULL;
48 struct thread *th; 151 struct thread *th;
49 152
@@ -52,15 +155,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
52 * so most of the time we dont have to look up 155 * so most of the time we dont have to look up
53 * the full rbtree: 156 * the full rbtree:
54 */ 157 */
55 if (*last_match && (*last_match)->pid == pid) 158 if (self->last_match && self->last_match->pid == pid)
56 return *last_match; 159 return self->last_match;
57 160
58 while (*p != NULL) { 161 while (*p != NULL) {
59 parent = *p; 162 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 163 th = rb_entry(parent, struct thread, rb_node);
61 164
62 if (th->pid == pid) { 165 if (th->pid == pid) {
63 *last_match = th; 166 self->last_match = th;
64 return th; 167 return th;
65 } 168 }
66 169
@@ -73,99 +176,130 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 176 th = thread__new(pid);
74 if (th != NULL) { 177 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 178 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 179 rb_insert_color(&th->rb_node, &self->threads);
77 *last_match = th; 180 self->last_match = th;
78 } 181 }
79 182
80 return th; 183 return th;
81} 184}
82 185
83struct thread * 186static void map_groups__remove_overlappings(struct map_groups *self,
84register_idle_thread(struct rb_root *threads, struct thread **last_match) 187 struct map *map)
85{ 188{
86 struct thread *thread = threads__findnew(0, threads, last_match); 189 struct rb_root *root = &self->maps[map->type];
190 struct rb_node *next = rb_first(root);
87 191
88 if (!thread || thread__set_comm(thread, "swapper")) { 192 while (next) {
89 fprintf(stderr, "problem inserting idle task.\n"); 193 struct map *pos = rb_entry(next, struct map, rb_node);
90 exit(-1); 194 next = rb_next(&pos->rb_node);
91 } 195
196 if (!map__overlap(pos, map))
197 continue;
92 198
93 return thread; 199 if (verbose >= 2) {
200 fputs("overlapping maps:\n", stderr);
201 map__fprintf(map, stderr);
202 map__fprintf(pos, stderr);
203 }
204
205 rb_erase(&pos->rb_node, root);
206 /*
207 * We may have references to this map, for instance in some
208 * hist_entry instances, so just move them to a separate
209 * list.
210 */
211 list_add_tail(&pos->node, &self->removed_maps[map->type]);
212 }
94} 213}
95 214
96void thread__insert_map(struct thread *self, struct map *map) 215void maps__insert(struct rb_root *maps, struct map *map)
97{ 216{
98 struct map *pos, *tmp; 217 struct rb_node **p = &maps->rb_node;
99 218 struct rb_node *parent = NULL;
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 219 const u64 ip = map->start;
101 if (map__overlap(pos, map)) { 220 struct map *m;
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 221
108 if (map->start <= pos->start && map->end > pos->start) 222 while (*p != NULL) {
109 pos->start = map->end; 223 parent = *p;
224 m = rb_entry(parent, struct map, rb_node);
225 if (ip < m->start)
226 p = &(*p)->rb_left;
227 else
228 p = &(*p)->rb_right;
229 }
110 230
111 if (map->end >= pos->end && map->start < pos->end) 231 rb_link_node(&map->rb_node, parent, p);
112 pos->end = map->start; 232 rb_insert_color(&map->rb_node, maps);
233}
113 234
114 if (verbose >= 2) { 235struct map *maps__find(struct rb_root *maps, u64 ip)
115 printf("after collision:\n"); 236{
116 map__fprintf(pos, stdout); 237 struct rb_node **p = &maps->rb_node;
117 } 238 struct rb_node *parent = NULL;
239 struct map *m;
118 240
119 if (pos->start >= pos->end) { 241 while (*p != NULL) {
120 list_del_init(&pos->node); 242 parent = *p;
121 free(pos); 243 m = rb_entry(parent, struct map, rb_node);
122 } 244 if (ip < m->start)
123 } 245 p = &(*p)->rb_left;
246 else if (ip > m->end)
247 p = &(*p)->rb_right;
248 else
249 return m;
124 } 250 }
125 251
126 list_add_tail(&map->node, &self->maps); 252 return NULL;
127} 253}
128 254
129int thread__fork(struct thread *self, struct thread *parent) 255void thread__insert_map(struct thread *self, struct map *map)
130{ 256{
131 struct map *map; 257 map_groups__remove_overlappings(&self->mg, map);
132 258 map_groups__insert(&self->mg, map);
133 if (self->comm) 259}
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138 260
139 list_for_each_entry(map, &parent->maps, node) { 261/*
262 * XXX This should not really _copy_ te maps, but refcount them.
263 */
264static int map_groups__clone(struct map_groups *self,
265 struct map_groups *parent, enum map_type type)
266{
267 struct rb_node *nd;
268 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
269 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 270 struct map *new = map__clone(map);
141 if (!new) 271 if (new == NULL)
142 return -ENOMEM; 272 return -ENOMEM;
143 thread__insert_map(self, new); 273 map_groups__insert(self, new);
144 } 274 }
145
146 return 0; 275 return 0;
147} 276}
148 277
149struct map *thread__find_map(struct thread *self, u64 ip) 278int thread__fork(struct thread *self, struct thread *parent)
150{ 279{
151 struct map *pos; 280 int i;
152
153 if (self == NULL)
154 return NULL;
155 281
156 list_for_each_entry(pos, &self->maps, node) 282 if (parent->comm_set) {
157 if (ip >= pos->start && ip <= pos->end) 283 if (self->comm)
158 return pos; 284 free(self->comm);
285 self->comm = strdup(parent->comm);
286 if (!self->comm)
287 return -ENOMEM;
288 self->comm_set = true;
289 }
159 290
160 return NULL; 291 for (i = 0; i < MAP__NR_TYPES; ++i)
292 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
293 return -ENOMEM;
294 return 0;
161} 295}
162 296
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 297size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
164{ 298{
165 size_t ret = 0; 299 size_t ret = 0;
166 struct rb_node *nd; 300 struct rb_node *nd;
167 301
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 302 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 303 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 304
171 ret += thread__fprintf(pos, fp); 305 ret += thread__fprintf(pos, fp);
@@ -173,3 +307,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 307
174 return ret; 308 return ret;
175} 309}
310
311struct symbol *map_groups__find_symbol(struct map_groups *self,
312 enum map_type type, u64 addr,
313 symbol_filter_t filter)
314{
315 struct map *map = map_groups__find(self, type, addr);
316
317 if (map != NULL)
318 return map__find_symbol(map, map->map_ip(map, addr), filter);
319
320 return NULL;
321}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..0a28f39de545 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,84 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
6struct thread { 13struct thread {
7 struct rb_node rb_node; 14 struct rb_node rb_node;
8 struct list_head maps; 15 struct map_groups mg;
9 pid_t pid; 16 pid_t pid;
10 char shortname[3]; 17 char shortname[3];
18 bool comm_set;
11 char *comm; 19 char *comm;
20 int comm_len;
12}; 21};
13 22
23void map_groups__init(struct map_groups *self);
14int thread__set_comm(struct thread *self, const char *comm); 24int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 25int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 26struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 27void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 28int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 29size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 30size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
31
32void maps__insert(struct rb_root *maps, struct map *map);
33struct map *maps__find(struct rb_root *maps, u64 addr);
34
35static inline void map_groups__insert(struct map_groups *self, struct map *map)
36{
37 maps__insert(&self->maps[map->type], map);
38}
39
40static inline struct map *map_groups__find(struct map_groups *self,
41 enum map_type type, u64 addr)
42{
43 return maps__find(&self->maps[type], addr);
44}
45
46static inline struct map *thread__find_map(struct thread *self,
47 enum map_type type, u64 addr)
48{
49 return self ? map_groups__find(&self->mg, type, addr) : NULL;
50}
51
52void thread__find_addr_map(struct thread *self,
53 struct perf_session *session, u8 cpumode,
54 enum map_type type, u64 addr,
55 struct addr_location *al);
56
57void thread__find_addr_location(struct thread *self,
58 struct perf_session *session, u8 cpumode,
59 enum map_type type, u64 addr,
60 struct addr_location *al,
61 symbol_filter_t filter);
62struct symbol *map_groups__find_symbol(struct map_groups *self,
63 enum map_type type, u64 addr,
64 symbol_filter_t filter);
65
66static inline struct symbol *map_groups__find_function(struct map_groups *self,
67 u64 addr,
68 symbol_filter_t filter)
69{
70 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
71}
72
73struct map *map_groups__find_by_name(struct map_groups *self,
74 enum map_type type, const char *name);
75
76int __map_groups__create_kernel_maps(struct map_groups *self,
77 struct map *vmlinux_maps[MAP__NR_TYPES],
78 struct dso *kernel);
79int map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES]);
81
82struct map *map_groups__new_module(struct map_groups *self, u64 start,
83 const char *filename);
84#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..5ea8973ad331 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -33,10 +34,11 @@
33#include <ctype.h> 34#include <ctype.h>
34#include <errno.h> 35#include <errno.h>
35#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/kernel.h>
36 38
37#include "../perf.h" 39#include "../perf.h"
38#include "trace-event.h" 40#include "trace-event.h"
39 41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -271,6 +253,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 253 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 254 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 255 check_size = copy_file_fd(fd);
256 close(fd);
257
274 if (size != check_size) 258 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 259 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 260 path, size, check_size);
@@ -289,6 +273,7 @@ static void read_header_files(void)
289 if (size != check_size) 273 if (size != check_size)
290 die("wrong size for '%s'", path); 274 die("wrong size for '%s'", path);
291 put_tracing_file(path); 275 put_tracing_file(path);
276 close(fd);
292} 277}
293 278
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 279static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +302,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 302 die("can't read directory '%s'", sys);
318 303
319 while ((dent = readdir(dir))) { 304 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 305 if (dent->d_type != DT_DIR ||
306 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 307 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 308 !name_in_tp_list(dent->d_name, tps))
323 continue; 309 continue;
@@ -334,7 +320,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 320
335 rewinddir(dir); 321 rewinddir(dir);
336 while ((dent = readdir(dir))) { 322 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 323 if (dent->d_type != DT_DIR ||
324 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 325 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 326 !name_in_tp_list(dent->d_name, tps))
340 continue; 327 continue;
@@ -353,6 +340,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 340
354 free(format); 341 free(format);
355 } 342 }
343 closedir(dir);
356} 344}
357 345
358static void read_ftrace_files(struct tracepoint_path *tps) 346static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +382,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 382 die("can't read directory '%s'", path);
395 383
396 while ((dent = readdir(dir))) { 384 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 385 if (dent->d_type != DT_DIR ||
386 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 387 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 388 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 389 !system_in_tp_list(dent->d_name, tps))
401 continue; 390 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 391 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 392 }
411 393
412 write_or_die(&count, 4); 394 write_or_die(&count, 4);
413 395
414 rewinddir(dir); 396 rewinddir(dir);
415 while ((dent = readdir(dir))) { 397 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 398 if (dent->d_type != DT_DIR ||
399 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 400 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 401 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 402 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +405,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 405 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 406 ret = stat(sys, &st);
424 if (ret >= 0) { 407 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 408 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 409 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 410 }
430 free(sys); 411 free(sys);
431 } 412 }
432 413
414 closedir(dir);
433 put_tracing_file(path); 415 put_tracing_file(path);
434} 416}
435 417
@@ -483,27 +465,33 @@ static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 465get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{ 466{
485 struct tracepoint_path path, *ppath = &path; 467 struct tracepoint_path path, *ppath = &path;
486 int i; 468 int i, nr_tracepoints = 0;
487 469
488 for (i = 0; i < nb_events; i++) { 470 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 471 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue; 472 continue;
473 ++nr_tracepoints;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config); 474 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next) 475 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list"); 476 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next; 477 ppath = ppath->next;
495 } 478 }
496 479
497 return path.next; 480 return nr_tracepoints > 0 ? path.next : NULL;
498} 481}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events) 482
483int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 484{
501 char buf[BUFSIZ]; 485 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 486 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
487
488 /*
489 * What? No tracepoints? No sense writing anything here, bail out.
490 */
491 if (tps == NULL)
492 return -1;
503 493
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 494 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 495
508 buf[0] = 23; 496 buf[0] = 23;
509 buf[1] = 8; 497 buf[1] = 8;
@@ -527,14 +515,14 @@ void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
527 write_or_die(buf, 1); 515 write_or_die(buf, 1);
528 516
529 /* save page_size */ 517 /* save page_size */
530 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
531 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
532 520
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files(); 521 read_header_files();
536 read_ftrace_files(tps); 522 read_ftrace_files(tps);
537 read_event_files(tps); 523 read_event_files(tps);
538 read_proc_kallsyms(); 524 read_proc_kallsyms();
539 read_ftrace_printk(); 525 read_ftrace_printk();
526
527 return 0;
540} 528}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..9b3c20f42f98 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,12 +40,19 @@ int header_page_size_size;
40int header_page_data_offset; 40int header_page_data_offset;
41int header_page_data_size; 41int header_page_data_size;
42 42
43int latency_format;
44
43static char *input_buf; 45static char *input_buf;
44static unsigned long long input_buf_ptr; 46static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz; 47static unsigned long long input_buf_siz;
46 48
47static int cpus; 49static int cpus;
48static int long_size; 50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
49 56
50static void init_input_buf(char *buf, unsigned long long size) 57static void init_input_buf(char *buf, unsigned long long size)
51{ 58{
@@ -170,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
170 func_count++; 177 func_count++;
171 } 178 }
172 179
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
174 181
175 i = 0; 182 i = 0;
176 while (list) { 183 while (list) {
@@ -284,18 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
284 char *line; 291 char *line;
285 char *next = NULL; 292 char *next = NULL;
286 char *addr_str; 293 char *addr_str;
287 int ret;
288 int i; 294 int i;
289 295
290 line = strtok_r(file, "\n", &next); 296 line = strtok_r(file, "\n", &next);
291 while (line) { 297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
292 item = malloc_or_die(sizeof(*item)); 303 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16); 304 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str); 305 /* fmt still has a space, skip it */
298 306 item->printk = strdup(line+1);
299 item->next = list; 307 item->next = list;
300 list = item; 308 list = item;
301 line = strtok_r(NULL, "\n", &next); 309 line = strtok_r(NULL, "\n", &next);
@@ -522,7 +530,10 @@ static enum event_type __read_token(char **tok)
522 last_ch = ch; 530 last_ch = ch;
523 ch = __read_char(); 531 ch = __read_char();
524 buf[i++] = ch; 532 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\'); 533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
526 /* remove the last quote */ 537 /* remove the last quote */
527 i--; 538 i--;
528 goto out; 539 goto out;
@@ -610,7 +621,7 @@ static enum event_type read_token_item(char **tok)
610static int test_type(enum event_type type, enum event_type expect) 621static int test_type(enum event_type type, enum event_type expect)
611{ 622{
612 if (type != expect) { 623 if (type != expect) {
613 die("Error: expected type %d but read %d", 624 warning("Error: expected type %d but read %d",
614 expect, type); 625 expect, type);
615 return -1; 626 return -1;
616 } 627 }
@@ -621,13 +632,13 @@ static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, const char *expect_tok) 632 enum event_type expect, const char *expect_tok)
622{ 633{
623 if (type != expect) { 634 if (type != expect) {
624 die("Error: expected type %d but read %d", 635 warning("Error: expected type %d but read %d",
625 expect, type); 636 expect, type);
626 return -1; 637 return -1;
627 } 638 }
628 639
629 if (strcmp(token, expect_tok) != 0) { 640 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'", 641 warning("Error: expected '%s' but read '%s'",
631 expect_tok, token); 642 expect_tok, token);
632 return -1; 643 return -1;
633 } 644 }
@@ -665,7 +676,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
665 676
666 free_token(token); 677 free_token(token);
667 678
668 return 0; 679 return ret;
669} 680}
670 681
671static int read_expected(enum event_type expect, const char *str) 682static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +693,10 @@ static char *event_read_name(void)
682{ 693{
683 char *token; 694 char *token;
684 695
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0) 696 if (read_expected(EVENT_ITEM, "name") < 0)
686 return NULL; 697 return NULL;
687 698
688 if (read_expected(EVENT_OP, (char *)":") < 0) 699 if (read_expected(EVENT_OP, ":") < 0)
689 return NULL; 700 return NULL;
690 701
691 if (read_expect_type(EVENT_ITEM, &token) < 0) 702 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +714,10 @@ static int event_read_id(void)
703 char *token; 714 char *token;
704 int id; 715 int id;
705 716
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) 717 if (read_expected_item(EVENT_ITEM, "ID") < 0)
707 return -1; 718 return -1;
708 719
709 if (read_expected(EVENT_OP, (char *)":") < 0) 720 if (read_expected(EVENT_OP, ":") < 0)
710 return -1; 721 return -1;
711 722
712 if (read_expect_type(EVENT_ITEM, &token) < 0) 723 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +732,24 @@ static int event_read_id(void)
721 return -1; 732 return -1;
722} 733}
723 734
735static int field_is_string(struct format_field *field)
736{
737 if ((field->flags & FIELD_IS_ARRAY) &&
738 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
739 !strstr(field->type, "s8")))
740 return 1;
741
742 return 0;
743}
744
745static int field_is_dynamic(struct format_field *field)
746{
747 if (!strcmp(field->type, "__data_loc"))
748 return 1;
749
750 return 0;
751}
752
724static int event_read_fields(struct event *event, struct format_field **fields) 753static int event_read_fields(struct event *event, struct format_field **fields)
725{ 754{
726 struct format_field *field = NULL; 755 struct format_field *field = NULL;
@@ -738,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
738 767
739 count++; 768 count++;
740 769
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) 770 if (test_type_token(type, token, EVENT_ITEM, "field"))
742 goto fail; 771 goto fail;
743 free_token(token); 772 free_token(token);
744 773
@@ -753,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
753 type = read_token(&token); 782 type = read_token(&token);
754 } 783 }
755 784
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) 785 if (test_type_token(type, token, EVENT_OP, ":") < 0)
757 return -1; 786 return -1;
758 787
759 if (read_expect_type(EVENT_ITEM, &token) < 0) 788 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +894,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
865 free(brackets); 894 free(brackets);
866 } 895 }
867 896
868 if (test_type_token(type, token, EVENT_OP, (char *)";")) 897 if (field_is_string(field)) {
898 field->flags |= FIELD_IS_STRING;
899 if (field_is_dynamic(field))
900 field->flags |= FIELD_IS_DYNAMIC;
901 }
902
903 if (test_type_token(type, token, EVENT_OP, ";"))
869 goto fail; 904 goto fail;
870 free_token(token); 905 free_token(token);
871 906
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 907 if (read_expected(EVENT_ITEM, "offset") < 0)
873 goto fail_expect; 908 goto fail_expect;
874 909
875 if (read_expected(EVENT_OP, (char *)":") < 0) 910 if (read_expected(EVENT_OP, ":") < 0)
876 goto fail_expect; 911 goto fail_expect;
877 912
878 if (read_expect_type(EVENT_ITEM, &token)) 913 if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
880 field->offset = strtoul(token, NULL, 0); 915 field->offset = strtoul(token, NULL, 0);
881 free_token(token); 916 free_token(token);
882 917
883 if (read_expected(EVENT_OP, (char *)";") < 0) 918 if (read_expected(EVENT_OP, ";") < 0)
884 goto fail_expect; 919 goto fail_expect;
885 920
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 921 if (read_expected(EVENT_ITEM, "size") < 0)
887 goto fail_expect; 922 goto fail_expect;
888 923
889 if (read_expected(EVENT_OP, (char *)":") < 0) 924 if (read_expected(EVENT_OP, ":") < 0)
890 goto fail_expect; 925 goto fail_expect;
891 926
892 if (read_expect_type(EVENT_ITEM, &token)) 927 if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +929,34 @@ static int event_read_fields(struct event *event, struct format_field **fields)
894 field->size = strtoul(token, NULL, 0); 929 field->size = strtoul(token, NULL, 0);
895 free_token(token); 930 free_token(token);
896 931
897 if (read_expected(EVENT_OP, (char *)";") < 0) 932 if (read_expected(EVENT_OP, ";") < 0)
898 goto fail_expect; 933 goto fail_expect;
899 934
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 935 type = read_token(&token);
901 goto fail; 936 if (type != EVENT_NEWLINE) {
937 /* newer versions of the kernel have a "signed" type */
938 if (test_type_token(type, token, EVENT_ITEM, "signed"))
939 goto fail;
940
941 free_token(token);
942
943 if (read_expected(EVENT_OP, ":") < 0)
944 goto fail_expect;
945
946 if (read_expect_type(EVENT_ITEM, &token))
947 goto fail;
948
949 if (strtoul(token, NULL, 0))
950 field->flags |= FIELD_IS_SIGNED;
951
952 free_token(token);
953 if (read_expected(EVENT_OP, ";") < 0)
954 goto fail_expect;
955
956 if (read_expect_type(EVENT_NEWLINE, &token))
957 goto fail;
958 }
959
902 free_token(token); 960 free_token(token);
903 961
904 *fields = field; 962 *fields = field;
@@ -921,10 +979,10 @@ static int event_read_format(struct event *event)
921 char *token; 979 char *token;
922 int ret; 980 int ret;
923 981
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) 982 if (read_expected_item(EVENT_ITEM, "format") < 0)
925 return -1; 983 return -1;
926 984
927 if (read_expected(EVENT_OP, (char *)":") < 0) 985 if (read_expected(EVENT_OP, ":") < 0)
928 return -1; 986 return -1;
929 987
930 if (read_expect_type(EVENT_NEWLINE, &token)) 988 if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
984 1042
985 *tok = NULL; 1043 *tok = NULL;
986 type = process_arg(event, left, &token); 1044 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":")) 1045 if (test_type_token(type, token, EVENT_OP, ":"))
988 goto out_free; 1046 goto out_free;
989 1047
990 arg->op.op = token; 1048 arg->op.op = token;
@@ -1004,6 +1062,35 @@ out_free:
1004 return EVENT_ERROR; 1062 return EVENT_ERROR;
1005} 1063}
1006 1064
1065static enum event_type
1066process_array(struct event *event, struct print_arg *top, char **tok)
1067{
1068 struct print_arg *arg;
1069 enum event_type type;
1070 char *token = NULL;
1071
1072 arg = malloc_or_die(sizeof(*arg));
1073 memset(arg, 0, sizeof(*arg));
1074
1075 *tok = NULL;
1076 type = process_arg(event, arg, &token);
1077 if (test_type_token(type, token, EVENT_OP, "]"))
1078 goto out_free;
1079
1080 top->op.right = arg;
1081
1082 free_token(token);
1083 type = read_token_item(&token);
1084 *tok = token;
1085
1086 return type;
1087
1088out_free:
1089 free_token(*tok);
1090 free_arg(arg);
1091 return EVENT_ERROR;
1092}
1093
1007static int get_op_prio(char *op) 1094static int get_op_prio(char *op)
1008{ 1095{
1009 if (!op[1]) { 1096 if (!op[1]) {
@@ -1128,6 +1215,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1128 strcmp(token, "*") == 0 || 1215 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 || 1216 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 || 1217 strcmp(token, "/") == 0 ||
1218 strcmp(token, "<") == 0 ||
1219 strcmp(token, ">") == 0 ||
1131 strcmp(token, "==") == 0 || 1220 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) { 1221 strcmp(token, "!=") == 0) {
1133 1222
@@ -1144,17 +1233,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1144 1233
1145 right = malloc_or_die(sizeof(*right)); 1234 right = malloc_or_die(sizeof(*right));
1146 1235
1147 type = process_arg(event, right, tok); 1236 type = read_token_item(&token);
1237 *tok = token;
1238
1239 /* could just be a type pointer */
1240 if ((strcmp(arg->op.op, "*") == 0) &&
1241 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1242 if (left->type != PRINT_ATOM)
1243 die("bad pointer type");
1244 left->atom.atom = realloc(left->atom.atom,
1245 sizeof(left->atom.atom) + 3);
1246 strcat(left->atom.atom, " *");
1247 *arg = *left;
1248 free(arg);
1249
1250 return type;
1251 }
1252
1253 type = process_arg_token(event, right, tok, type);
1148 1254
1149 arg->op.right = right; 1255 arg->op.right = right;
1150 1256
1257 } else if (strcmp(token, "[") == 0) {
1258
1259 left = malloc_or_die(sizeof(*left));
1260 *left = *arg;
1261
1262 arg->type = PRINT_OP;
1263 arg->op.op = token;
1264 arg->op.left = left;
1265
1266 arg->op.prio = 0;
1267 type = process_array(event, arg, tok);
1268
1151 } else { 1269 } else {
1152 die("unknown op '%s'", token); 1270 warning("unknown op '%s'", token);
1271 event->flags |= EVENT_FL_FAILED;
1153 /* the arg is now the left side */ 1272 /* the arg is now the left side */
1154 return EVENT_NONE; 1273 return EVENT_NONE;
1155 } 1274 }
1156 1275
1157
1158 if (type == EVENT_OP) { 1276 if (type == EVENT_OP) {
1159 int prio; 1277 int prio;
1160 1278
@@ -1178,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1178 char *field; 1296 char *field;
1179 char *token; 1297 char *token;
1180 1298
1181 if (read_expected(EVENT_OP, (char *)"->") < 0) 1299 if (read_expected(EVENT_OP, "->") < 0)
1182 return EVENT_ERROR; 1300 return EVENT_ERROR;
1183 1301
1184 if (read_expect_type(EVENT_ITEM, &token) < 0) 1302 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1188,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1188 arg->type = PRINT_FIELD; 1306 arg->type = PRINT_FIELD;
1189 arg->field.name = field; 1307 arg->field.name = field;
1190 1308
1309 if (is_flag_field) {
1310 arg->field.field = find_any_field(event, arg->field.name);
1311 arg->field.field->flags |= FIELD_IS_FLAG;
1312 is_flag_field = 0;
1313 } else if (is_symbolic_field) {
1314 arg->field.field = find_any_field(event, arg->field.name);
1315 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1316 is_symbolic_field = 0;
1317 }
1318
1191 type = read_token(&token); 1319 type = read_token(&token);
1192 *tok = token; 1320 *tok = token;
1193 1321
@@ -1338,25 +1466,25 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1338 do { 1466 do {
1339 free_token(token); 1467 free_token(token);
1340 type = read_token_item(&token); 1468 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{")) 1469 if (test_type_token(type, token, EVENT_OP, "{"))
1342 break; 1470 break;
1343 1471
1344 arg = malloc_or_die(sizeof(*arg)); 1472 arg = malloc_or_die(sizeof(*arg));
1345 1473
1346 free_token(token); 1474 free_token(token);
1347 type = process_arg(event, arg, &token); 1475 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1476 if (test_type_token(type, token, EVENT_DELIM, ","))
1349 goto out_free; 1477 goto out_free;
1350 1478
1351 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1353 1481
1354 value = arg_eval(arg); 1482 value = arg_eval(arg);
1355 field->value = strdup(value); 1483 field->value = strdup(value);
1356 1484
1357 free_token(token); 1485 free_token(token);
1358 type = process_arg(event, arg, &token); 1486 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}")) 1487 if (test_type_token(type, token, EVENT_OP, "}"))
1360 goto out_free; 1488 goto out_free;
1361 1489
1362 value = arg_eval(arg); 1490 value = arg_eval(arg);
@@ -1391,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1391 memset(arg, 0, sizeof(*arg)); 1519 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS; 1520 arg->type = PRINT_FLAGS;
1393 1521
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1522 if (read_expected_item(EVENT_DELIM, "(") < 0)
1395 return EVENT_ERROR; 1523 return EVENT_ERROR;
1396 1524
1397 field = malloc_or_die(sizeof(*field)); 1525 field = malloc_or_die(sizeof(*field));
1398 1526
1399 type = process_arg(event, field, &token); 1527 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1528 if (test_type_token(type, token, EVENT_DELIM, ","))
1401 goto out_free; 1529 goto out_free;
1402 1530
1403 arg->flags.field = field; 1531 arg->flags.field = field;
@@ -1408,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1408 type = read_token_item(&token); 1536 type = read_token_item(&token);
1409 } 1537 }
1410 1538
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1539 if (test_type_token(type, token, EVENT_DELIM, ","))
1412 goto out_free; 1540 goto out_free;
1413 1541
1414 type = process_fields(event, &arg->flags.flags, &token); 1542 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1543 if (test_type_token(type, token, EVENT_DELIM, ")"))
1416 goto out_free; 1544 goto out_free;
1417 1545
1418 free_token(token); 1546 free_token(token);
@@ -1434,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
1434 memset(arg, 0, sizeof(*arg)); 1562 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL; 1563 arg->type = PRINT_SYMBOL;
1436 1564
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1565 if (read_expected_item(EVENT_DELIM, "(") < 0)
1438 return EVENT_ERROR; 1566 return EVENT_ERROR;
1439 1567
1440 field = malloc_or_die(sizeof(*field)); 1568 field = malloc_or_die(sizeof(*field));
1441 1569
1442 type = process_arg(event, field, &token); 1570 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1571 if (test_type_token(type, token, EVENT_DELIM, ","))
1444 goto out_free; 1572 goto out_free;
1445 1573
1446 arg->symbol.field = field; 1574 arg->symbol.field = field;
1447 1575
1448 type = process_fields(event, &arg->symbol.symbols, &token); 1576 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1577 if (test_type_token(type, token, EVENT_DELIM, ")"))
1450 goto out_free; 1578 goto out_free;
1451 1579
1452 free_token(token); 1580 free_token(token);
@@ -1463,7 +1591,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{ 1591{
1464 struct print_arg *item_arg; 1592 struct print_arg *item_arg;
1465 enum event_type type; 1593 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token; 1594 char *token;
1468 1595
1469 type = process_arg(event, arg, &token); 1596 type = process_arg(event, arg, &token);
@@ -1471,28 +1598,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1471 if (type == EVENT_ERROR) 1598 if (type == EVENT_ERROR)
1472 return EVENT_ERROR; 1599 return EVENT_ERROR;
1473 1600
1474 if (type == EVENT_OP) { 1601 if (type == EVENT_OP)
1475 /* handle the ptr casts */ 1602 type = process_op(event, arg, &token);
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489 1603
1490 if (type == EVENT_ERROR) 1604 if (type == EVENT_ERROR)
1491 return EVENT_ERROR; 1605 return EVENT_ERROR;
1492 }
1493 }
1494 1606
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { 1607 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1496 free_token(token); 1608 free_token(token);
1497 return EVENT_ERROR; 1609 return EVENT_ERROR;
1498 } 1610 }
@@ -1516,13 +1628,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1516 item_arg = malloc_or_die(sizeof(*item_arg)); 1628 item_arg = malloc_or_die(sizeof(*item_arg));
1517 1629
1518 arg->type = PRINT_TYPE; 1630 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom; 1631 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg; 1632 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type); 1633 type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1540 enum event_type type; 1645 enum event_type type;
1541 char *token; 1646 char *token;
1542 1647
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0) 1648 if (read_expected(EVENT_DELIM, "(") < 0)
1544 return EVENT_ERROR; 1649 return EVENT_ERROR;
1545 1650
1546 if (read_expect_type(EVENT_ITEM, &token) < 0) 1651 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1550 arg->string.string = token; 1655 arg->string.string = token;
1551 arg->string.offset = -1; 1656 arg->string.offset = -1;
1552 1657
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0) 1658 if (read_expected(EVENT_DELIM, ")") < 0)
1554 return EVENT_ERROR; 1659 return EVENT_ERROR;
1555 1660
1556 type = read_token(&token); 1661 type = read_token(&token);
@@ -1578,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
1578 type = process_entry(event, arg, &token); 1683 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) { 1684 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token); 1685 free_token(token);
1686 is_flag_field = 1;
1581 type = process_flags(event, arg, &token); 1687 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) { 1688 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token); 1689 free_token(token);
1690 is_symbolic_field = 1;
1584 type = process_symbols(event, arg, &token); 1691 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) { 1692 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token); 1693 free_token(token);
@@ -1637,12 +1744,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
1637 1744
1638static int event_read_print_args(struct event *event, struct print_arg **list) 1745static int event_read_print_args(struct event *event, struct print_arg **list)
1639{ 1746{
1640 enum event_type type; 1747 enum event_type type = EVENT_ERROR;
1641 struct print_arg *arg; 1748 struct print_arg *arg;
1642 char *token; 1749 char *token;
1643 int args = 0; 1750 int args = 0;
1644 1751
1645 do { 1752 do {
1753 if (type == EVENT_NEWLINE) {
1754 free_token(token);
1755 type = read_token_item(&token);
1756 continue;
1757 }
1758
1646 arg = malloc_or_die(sizeof(*arg)); 1759 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg)); 1760 memset(arg, 0, sizeof(*arg));
1648 1761
@@ -1683,18 +1796,19 @@ static int event_read_print(struct event *event)
1683 char *token; 1796 char *token;
1684 int ret; 1797 int ret;
1685 1798
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) 1799 if (read_expected_item(EVENT_ITEM, "print") < 0)
1687 return -1; 1800 return -1;
1688 1801
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) 1802 if (read_expected(EVENT_ITEM, "fmt") < 0)
1690 return -1; 1803 return -1;
1691 1804
1692 if (read_expected(EVENT_OP, (char *)":") < 0) 1805 if (read_expected(EVENT_OP, ":") < 0)
1693 return -1; 1806 return -1;
1694 1807
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0) 1808 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail; 1809 goto fail;
1697 1810
1811 concat:
1698 event->print_fmt.format = token; 1812 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL; 1813 event->print_fmt.args = NULL;
1700 1814
@@ -1704,7 +1818,22 @@ static int event_read_print(struct event *event)
1704 if (type == EVENT_NONE) 1818 if (type == EVENT_NONE)
1705 return 0; 1819 return 0;
1706 1820
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1821 /* Handle concatination of print lines */
1822 if (type == EVENT_DQUOTE) {
1823 char *cat;
1824
1825 cat = malloc_or_die(strlen(event->print_fmt.format) +
1826 strlen(token) + 1);
1827 strcpy(cat, event->print_fmt.format);
1828 strcat(cat, token);
1829 free_token(token);
1830 free_token(event->print_fmt.format);
1831 event->print_fmt.format = NULL;
1832 token = cat;
1833 goto concat;
1834 }
1835
1836 if (test_type_token(type, token, EVENT_DELIM, ","))
1708 goto fail; 1837 goto fail;
1709 1838
1710 free_token(token); 1839 free_token(token);
@@ -1713,7 +1842,7 @@ static int event_read_print(struct event *event)
1713 if (ret < 0) 1842 if (ret < 0)
1714 return -1; 1843 return -1;
1715 1844
1716 return 0; 1845 return ret;
1717 1846
1718 fail: 1847 fail:
1719 free_token(token); 1848 free_token(token);
@@ -1759,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
1759 return find_field(event, name); 1888 return find_field(event, name);
1760} 1889}
1761 1890
1762static unsigned long long read_size(void *ptr, int size) 1891unsigned long long read_size(void *ptr, int size)
1763{ 1892{
1764 switch (size) { 1893 switch (size) {
1765 case 1: 1894 case 1:
@@ -1796,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1796 if (!field) 1925 if (!field)
1797 return NULL; 1926 return NULL;
1798 1927
1928 if (field->flags & FIELD_IS_STRING) {
1929 int offset;
1930
1931 offset = *(int *)(data + field->offset);
1932 offset &= 0xffff;
1933
1934 return data + offset;
1935 }
1936
1799 return data + field->offset; 1937 return data + field->offset;
1800} 1938}
1801 1939
@@ -1822,37 +1960,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1822 return 0; 1960 return 0;
1823} 1961}
1824 1962
1825int trace_parse_common_type(void *data) 1963static int __parse_common(void *data, int *size, int *offset,
1964 const char *name)
1826{ 1965{
1827 static int type_offset;
1828 static int type_size;
1829 int ret; 1966 int ret;
1830 1967
1831 if (!type_size) { 1968 if (!*size) {
1832 ret = get_common_info("common_type", 1969 ret = get_common_info(name, offset, size);
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0) 1970 if (ret < 0)
1836 return ret; 1971 return ret;
1837 } 1972 }
1838 return read_size(data + type_offset, type_size); 1973 return read_size(data + *offset, *size);
1839} 1974}
1840 1975
1841static int parse_common_pid(void *data) 1976int trace_parse_common_type(void *data)
1977{
1978 static int type_offset;
1979 static int type_size;
1980
1981 return __parse_common(data, &type_size, &type_offset,
1982 "common_type");
1983}
1984
1985int trace_parse_common_pid(void *data)
1842{ 1986{
1843 static int pid_offset; 1987 static int pid_offset;
1844 static int pid_size; 1988 static int pid_size;
1989
1990 return __parse_common(data, &pid_size, &pid_offset,
1991 "common_pid");
1992}
1993
1994int parse_common_pc(void *data)
1995{
1996 static int pc_offset;
1997 static int pc_size;
1998
1999 return __parse_common(data, &pc_size, &pc_offset,
2000 "common_preempt_count");
2001}
2002
2003int parse_common_flags(void *data)
2004{
2005 static int flags_offset;
2006 static int flags_size;
2007
2008 return __parse_common(data, &flags_size, &flags_offset,
2009 "common_flags");
2010}
2011
2012int parse_common_lock_depth(void *data)
2013{
2014 static int ld_offset;
2015 static int ld_size;
1845 int ret; 2016 int ret;
1846 2017
1847 if (!pid_size) { 2018 ret = __parse_common(data, &ld_size, &ld_offset,
1848 ret = get_common_info("common_pid", 2019 "common_lock_depth");
1849 &pid_offset, 2020 if (ret < 0)
1850 &pid_size); 2021 return -1;
1851 if (ret < 0)
1852 return ret;
1853 }
1854 2022
1855 return read_size(data + pid_offset, pid_size); 2023 return ret;
1856} 2024}
1857 2025
1858struct event *trace_find_event(int id) 2026struct event *trace_find_event(int id)
@@ -1866,11 +2034,20 @@ struct event *trace_find_event(int id)
1866 return event; 2034 return event;
1867} 2035}
1868 2036
2037struct event *trace_find_next_event(struct event *event)
2038{
2039 if (!event)
2040 return event_list;
2041
2042 return event->next;
2043}
2044
1869static unsigned long long eval_num_arg(void *data, int size, 2045static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg) 2046 struct event *event, struct print_arg *arg)
1871{ 2047{
1872 unsigned long long val = 0; 2048 unsigned long long val = 0;
1873 unsigned long long left, right; 2049 unsigned long long left, right;
2050 struct print_arg *larg;
1874 2051
1875 switch (arg->type) { 2052 switch (arg->type) {
1876 case PRINT_NULL: 2053 case PRINT_NULL:
@@ -1897,6 +2074,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1897 return 0; 2074 return 0;
1898 break; 2075 break;
1899 case PRINT_OP: 2076 case PRINT_OP:
2077 if (strcmp(arg->op.op, "[") == 0) {
2078 /*
2079 * Arrays are special, since we don't want
2080 * to read the arg as is.
2081 */
2082 if (arg->op.left->type != PRINT_FIELD)
2083 goto default_op; /* oops, all bets off */
2084 larg = arg->op.left;
2085 if (!larg->field.field) {
2086 larg->field.field =
2087 find_any_field(event, larg->field.name);
2088 if (!larg->field.field)
2089 die("field %s not found", larg->field.name);
2090 }
2091 right = eval_num_arg(data, size, event, arg->op.right);
2092 val = read_size(data + larg->field.field->offset +
2093 right * long_size, long_size);
2094 break;
2095 }
2096 default_op:
1900 left = eval_num_arg(data, size, event, arg->op.left); 2097 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right); 2098 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) { 2099 switch (arg->op.op[0]) {
@@ -1947,6 +2144,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1947 die("unknown op '%s'", arg->op.op); 2144 die("unknown op '%s'", arg->op.op);
1948 val = left == right; 2145 val = left == right;
1949 break; 2146 break;
2147 case '-':
2148 val = left - right;
2149 break;
2150 case '+':
2151 val = left + right;
2152 break;
1950 default: 2153 default:
1951 die("unknown op '%s'", arg->op.op); 2154 die("unknown op '%s'", arg->op.op);
1952 } 2155 }
@@ -1978,7 +2181,7 @@ static const struct flag flags[] = {
1978 { "HRTIMER_RESTART", 1 }, 2181 { "HRTIMER_RESTART", 1 },
1979}; 2182};
1980 2183
1981static unsigned long long eval_flag(const char *flag) 2184unsigned long long eval_flag(const char *flag)
1982{ 2185{
1983 int i; 2186 int i;
1984 2187
@@ -2145,8 +2348,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2145 case 'u': 2348 case 'u':
2146 case 'x': 2349 case 'x':
2147 case 'i': 2350 case 'i':
2148 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2351 /* the pointers are always 4 bytes aligned */
2149 ~(long_size - 1)); 2352 bptr = (void *)(((unsigned long)bptr + 3) &
2353 ~3);
2150 switch (ls) { 2354 switch (ls) {
2151 case 0: 2355 case 0:
2152 case 1: 2356 case 1:
@@ -2270,7 +2474,27 @@ static void pretty_print(void *data, int size, struct event *event)
2270 2474
2271 for (; *ptr; ptr++) { 2475 for (; *ptr; ptr++) {
2272 ls = 0; 2476 ls = 0;
2273 if (*ptr == '%') { 2477 if (*ptr == '\\') {
2478 ptr++;
2479 switch (*ptr) {
2480 case 'n':
2481 printf("\n");
2482 break;
2483 case 't':
2484 printf("\t");
2485 break;
2486 case 'r':
2487 printf("\r");
2488 break;
2489 case '\\':
2490 printf("\\");
2491 break;
2492 default:
2493 printf("%c", *ptr);
2494 break;
2495 }
2496
2497 } else if (*ptr == '%') {
2274 saveptr = ptr; 2498 saveptr = ptr;
2275 show_func = 0; 2499 show_func = 0;
2276 cont_process: 2500 cont_process:
@@ -2377,6 +2601,41 @@ static inline int log10_cpu(int nb)
2377 return 1; 2601 return 1;
2378} 2602}
2379 2603
2604static void print_lat_fmt(void *data, int size __unused)
2605{
2606 unsigned int lat_flags;
2607 unsigned int pc;
2608 int lock_depth;
2609 int hardirq;
2610 int softirq;
2611
2612 lat_flags = parse_common_flags(data);
2613 pc = parse_common_pc(data);
2614 lock_depth = parse_common_lock_depth(data);
2615
2616 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2617 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2618
2619 printf("%c%c%c",
2620 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2621 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2622 'X' : '.',
2623 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2624 'N' : '.',
2625 (hardirq && softirq) ? 'H' :
2626 hardirq ? 'h' : softirq ? 's' : '.');
2627
2628 if (pc)
2629 printf("%x", pc);
2630 else
2631 printf(".");
2632
2633 if (lock_depth < 0)
2634 printf(".");
2635 else
2636 printf("%d", lock_depth);
2637}
2638
2380/* taken from Linux, written by Frederic Weisbecker */ 2639/* taken from Linux, written by Frederic Weisbecker */
2381static void print_graph_cpu(int cpu) 2640static void print_graph_cpu(int cpu)
2382{ 2641{
@@ -2452,7 +2711,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2452 if (!(event->flags & EVENT_FL_ISFUNCRET)) 2711 if (!(event->flags & EVENT_FL_ISFUNCRET))
2453 return NULL; 2712 return NULL;
2454 2713
2455 pid = parse_common_pid(next->data); 2714 pid = trace_parse_common_pid(next->data);
2456 field = find_field(event, "func"); 2715 field = find_field(event, "func");
2457 if (!field) 2716 if (!field)
2458 die("function return does not have field func"); 2717 die("function return does not have field func");
@@ -2620,6 +2879,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2620 2879
2621 printf(" | "); 2880 printf(" | ");
2622 2881
2882 if (latency_format) {
2883 print_lat_fmt(data, size);
2884 printf(" | ");
2885 }
2886
2623 field = find_field(event, "func"); 2887 field = find_field(event, "func");
2624 if (!field) 2888 if (!field)
2625 die("function entry does not have func field"); 2889 die("function entry does not have func field");
@@ -2663,6 +2927,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2663 2927
2664 printf(" | "); 2928 printf(" | ");
2665 2929
2930 if (latency_format) {
2931 print_lat_fmt(data, size);
2932 printf(" | ");
2933 }
2934
2666 field = find_field(event, "rettime"); 2935 field = find_field(event, "rettime");
2667 if (!field) 2936 if (!field)
2668 die("can't find rettime in return graph"); 2937 die("can't find rettime in return graph");
@@ -2724,19 +2993,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2724 2993
2725 event = trace_find_event(type); 2994 event = trace_find_event(type);
2726 if (!event) { 2995 if (!event) {
2727 printf("ug! no event found for type %d\n", type); 2996 warning("ug! no event found for type %d", type);
2728 return; 2997 return;
2729 } 2998 }
2730 2999
2731 pid = parse_common_pid(data); 3000 pid = trace_parse_common_pid(data);
2732 3001
2733 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 3002 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2734 return pretty_print_func_graph(data, size, event, cpu, 3003 return pretty_print_func_graph(data, size, event, cpu,
2735 pid, comm, secs, usecs); 3004 pid, comm, secs, usecs);
2736 3005
2737 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 3006 if (latency_format) {
2738 comm, pid, cpu, 3007 printf("%8.8s-%-5d %3d",
2739 secs, nsecs, event->name); 3008 comm, pid, cpu);
3009 print_lat_fmt(data, size);
3010 } else
3011 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3012
3013 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3014
3015 if (event->flags & EVENT_FL_FAILED) {
3016 printf("EVENT '%s' FAILED TO PARSE\n",
3017 event->name);
3018 return;
3019 }
2740 3020
2741 pretty_print(data, size, event); 3021 pretty_print(data, size, event);
2742 printf("\n"); 3022 printf("\n");
@@ -2807,46 +3087,71 @@ static void print_args(struct print_arg *args)
2807 } 3087 }
2808} 3088}
2809 3089
2810static void parse_header_field(char *type, 3090static void parse_header_field(const char *field,
2811 int *offset, int *size) 3091 int *offset, int *size)
2812{ 3092{
2813 char *token; 3093 char *token;
3094 int type;
2814 3095
2815 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3096 if (read_expected(EVENT_ITEM, "field") < 0)
2816 return; 3097 return;
2817 if (read_expected(EVENT_OP, (char *)":") < 0) 3098 if (read_expected(EVENT_OP, ":") < 0)
2818 return; 3099 return;
3100
2819 /* type */ 3101 /* type */
2820 if (read_expect_type(EVENT_ITEM, &token) < 0) 3102 if (read_expect_type(EVENT_ITEM, &token) < 0)
2821 return; 3103 goto fail;
2822 free_token(token); 3104 free_token(token);
2823 3105
2824 if (read_expected(EVENT_ITEM, type) < 0) 3106 if (read_expected(EVENT_ITEM, field) < 0)
2825 return; 3107 return;
2826 if (read_expected(EVENT_OP, (char *)";") < 0) 3108 if (read_expected(EVENT_OP, ";") < 0)
2827 return; 3109 return;
2828 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3110 if (read_expected(EVENT_ITEM, "offset") < 0)
2829 return; 3111 return;
2830 if (read_expected(EVENT_OP, (char *)":") < 0) 3112 if (read_expected(EVENT_OP, ":") < 0)
2831 return; 3113 return;
2832 if (read_expect_type(EVENT_ITEM, &token) < 0) 3114 if (read_expect_type(EVENT_ITEM, &token) < 0)
2833 return; 3115 goto fail;
2834 *offset = atoi(token); 3116 *offset = atoi(token);
2835 free_token(token); 3117 free_token(token);
2836 if (read_expected(EVENT_OP, (char *)";") < 0) 3118 if (read_expected(EVENT_OP, ";") < 0)
2837 return; 3119 return;
2838 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3120 if (read_expected(EVENT_ITEM, "size") < 0)
2839 return; 3121 return;
2840 if (read_expected(EVENT_OP, (char *)":") < 0) 3122 if (read_expected(EVENT_OP, ":") < 0)
2841 return; 3123 return;
2842 if (read_expect_type(EVENT_ITEM, &token) < 0) 3124 if (read_expect_type(EVENT_ITEM, &token) < 0)
2843 return; 3125 goto fail;
2844 *size = atoi(token); 3126 *size = atoi(token);
2845 free_token(token); 3127 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 3128 if (read_expected(EVENT_OP, ";") < 0)
2847 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 return; 3129 return;
3130 type = read_token(&token);
3131 if (type != EVENT_NEWLINE) {
3132 /* newer versions of the kernel have a "signed" type */
3133 if (type != EVENT_ITEM)
3134 goto fail;
3135
3136 if (strcmp(token, "signed") != 0)
3137 goto fail;
3138
3139 free_token(token);
3140
3141 if (read_expected(EVENT_OP, ":") < 0)
3142 return;
3143
3144 if (read_expect_type(EVENT_ITEM, &token))
3145 goto fail;
3146
3147 free_token(token);
3148 if (read_expected(EVENT_OP, ";") < 0)
3149 return;
3150
3151 if (read_expect_type(EVENT_NEWLINE, &token))
3152 goto fail;
3153 }
3154 fail:
2850 free_token(token); 3155 free_token(token);
2851} 3156}
2852 3157
@@ -2854,11 +3159,11 @@ int parse_header_page(char *buf, unsigned long size)
2854{ 3159{
2855 init_input_buf(buf, size); 3160 init_input_buf(buf, size);
2856 3161
2857 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3162 parse_header_field("timestamp", &header_page_ts_offset,
2858 &header_page_ts_size); 3163 &header_page_ts_size);
2859 parse_header_field((char *)"commit", &header_page_size_offset, 3164 parse_header_field("commit", &header_page_size_offset,
2860 &header_page_size_size); 3165 &header_page_size_size);
2861 parse_header_field((char *)"data", &header_page_data_offset, 3166 parse_header_field("data", &header_page_data_offset,
2862 &header_page_data_size); 3167 &header_page_data_size);
2863 3168
2864 return 0; 3169 return 0;
@@ -2909,6 +3214,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2909 if (ret < 0) 3214 if (ret < 0)
2910 die("failed to read ftrace event print fmt"); 3215 die("failed to read ftrace event print fmt");
2911 3216
3217 /* New ftrace handles args */
3218 if (ret > 0)
3219 return 0;
2912 /* 3220 /*
2913 * The arguments for ftrace files are parsed by the fields. 3221 * The arguments for ftrace files are parsed by the fields.
2914 * Set up the fields as their arguments. 3222 * Set up the fields as their arguments.
@@ -2926,7 +3234,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 3234 return 0;
2927} 3235}
2928 3236
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 3237int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 3238{
2931 struct event *event; 3239 struct event *event;
2932 int ret; 3240 int ret;
@@ -2946,12 +3254,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2946 die("failed to read event id"); 3254 die("failed to read event id");
2947 3255
2948 ret = event_read_format(event); 3256 ret = event_read_format(event);
2949 if (ret < 0) 3257 if (ret < 0) {
2950 die("failed to read event format"); 3258 warning("failed to read event format for %s", event->name);
3259 goto event_failed;
3260 }
2951 3261
2952 ret = event_read_print(event); 3262 ret = event_read_print(event);
2953 if (ret < 0) 3263 if (ret < 0) {
2954 die("failed to read event print fmt"); 3264 warning("failed to read event print fmt for %s", event->name);
3265 goto event_failed;
3266 }
3267
3268 event->system = strdup(sys);
2955 3269
2956#define PRINT_ARGS 0 3270#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3271 if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3273,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2959 3273
2960 add_event(event); 3274 add_event(event);
2961 return 0; 3275 return 0;
3276
3277 event_failed:
3278 event->flags |= EVENT_FL_FAILED;
3279 /* still add it even if it failed */
3280 add_event(event);
3281 return -1;
2962} 3282}
2963 3283
2964void parse_set_info(int nr_cpus, int long_sz) 3284void parse_set_info(int nr_cpus, int long_sz)
@@ -2966,3 +3286,18 @@ void parse_set_info(int nr_cpus, int long_sz)
2966 cpus = nr_cpus; 3286 cpus = nr_cpus;
2967 long_size = long_sz; 3287 long_size = long_sz;
2968} 3288}
3289
3290int common_pc(struct scripting_context *context)
3291{
3292 return parse_common_pc(context->event_data);
3293}
3294
3295int common_flags(struct scripting_context *context)
3296{
3297 return parse_common_flags(context->event_data);
3298}
3299
3300int common_lock_depth(struct scripting_context *context)
3301{
3302 return parse_common_lock_depth(context->event_data);
3303}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..7cd1193918c7 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -83,7 +83,7 @@ static char *read_string(void)
83 char *str = NULL; 83 char *str = NULL;
84 int size = 0; 84 int size = 0;
85 int i; 85 int i;
86 int r; 86 off_t r;
87 87
88 for (;;) { 88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 89 r = read(input_fd, buf, BUFSIZ);
@@ -118,7 +118,7 @@ static char *read_string(void)
118 118
119 /* move the file descriptor to the end of the string */ 119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR); 120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0) 121 if (r == (off_t)-1)
122 die("lseek"); 122 die("lseek");
123 123
124 if (str) { 124 if (str) {
@@ -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
@@ -281,8 +282,8 @@ static void update_cpu_data_index(int cpu)
281 282
282static void get_next_page(int cpu) 283static void get_next_page(int cpu)
283{ 284{
284 off64_t save_seek; 285 off_t save_seek;
285 off64_t ret; 286 off_t ret;
286 287
287 if (!cpu_data[cpu].page) 288 if (!cpu_data[cpu].page)
288 return; 289 return;
@@ -297,17 +298,17 @@ static void get_next_page(int cpu)
297 update_cpu_data_index(cpu); 298 update_cpu_data_index(cpu);
298 299
299 /* other parts of the code may expect the pointer to not move */ 300 /* other parts of the code may expect the pointer to not move */
300 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 save_seek = lseek(input_fd, 0, SEEK_CUR);
301 302
302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
303 if (ret < 0) 304 if (ret == (off_t)-1)
304 die("failed to lseek"); 305 die("failed to lseek");
305 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 ret = read(input_fd, cpu_data[cpu].page, page_size);
306 if (ret < 0) 307 if (ret < 0)
307 die("failed to read page"); 308 die("failed to read page");
308 309
309 /* reset the file pointer back */ 310 /* reset the file pointer back */
310 lseek64(input_fd, save_seek, SEEK_SET); 311 lseek(input_fd, save_seek, SEEK_SET);
311 312
312 return; 313 return;
313 } 314 }
@@ -458,9 +459,8 @@ struct record *trace_read_data(int cpu)
458 return data; 459 return data;
459} 460}
460 461
461void trace_report(void) 462void trace_report(int fd)
462{ 463{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ]; 464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 465 char test[] = { 23, 8, 68 };
466 char *version; 466 char *version;
@@ -468,17 +468,15 @@ void trace_report(void)
468 int show_funcs = 0; 468 int show_funcs = 0;
469 int show_printk = 0; 469 int show_printk = 0;
470 470
471 input_fd = open(input_file, O_RDONLY); 471 input_fd = fd;
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474 472
475 read_or_die(buf, 3); 473 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0) 474 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file"); 475 die("no trace data in the file");
478 476
479 read_or_die(buf, 7); 477 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0) 478 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)"); 479 die("not a trace file (missing 'tracing' tag)");
482 480
483 version = read_string(); 481 version = read_string();
484 if (show_version) 482 if (show_version)
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..7ea983acfaea
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..c3269b937db4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
1#ifndef _TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include "parse-events.h" 4#include "parse-events.h"
5 5
@@ -26,6 +26,11 @@ enum {
26enum format_flags { 26enum format_flags {
27 FIELD_IS_ARRAY = 1, 27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2, 28 FIELD_IS_POINTER = 2,
29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16,
32 FIELD_IS_FLAG = 32,
33 FIELD_IS_SYMBOLIC = 64,
29}; 34};
30 35
31struct format_field { 36struct format_field {
@@ -132,15 +137,18 @@ struct event {
132 int flags; 137 int flags;
133 struct format format; 138 struct format format;
134 struct print_fmt print_fmt; 139 struct print_fmt print_fmt;
140 char *system;
135}; 141};
136 142
137enum { 143enum {
138 EVENT_FL_ISFTRACE = 1, 144 EVENT_FL_ISFTRACE = 0x01,
139 EVENT_FL_ISPRINT = 2, 145 EVENT_FL_ISPRINT = 0x02,
140 EVENT_FL_ISBPRINT = 4, 146 EVENT_FL_ISBPRINT = 0x04,
141 EVENT_FL_ISFUNC = 8, 147 EVENT_FL_ISFUNC = 0x08,
142 EVENT_FL_ISFUNCENT = 16, 148 EVENT_FL_ISFUNCENT = 0x10,
143 EVENT_FL_ISFUNCRET = 32, 149 EVENT_FL_ISFUNCRET = 0x20,
150
151 EVENT_FL_FAILED = 0x80000000
144}; 152};
145 153
146struct record { 154struct record {
@@ -154,7 +162,7 @@ struct record *trace_read_data(int cpu);
154 162
155void parse_set_info(int nr_cpus, int long_sz); 163void parse_set_info(int nr_cpus, int long_sz);
156 164
157void trace_report(void); 165void trace_report(int fd);
158 166
159void *malloc_or_die(unsigned int size); 167void *malloc_or_die(unsigned int size);
160 168
@@ -166,7 +174,7 @@ void print_funcs(void);
166void print_printk(void); 174void print_printk(void);
167 175
168int parse_ftrace_file(char *buf, unsigned long size); 176int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system); 177int parse_event_file(char *buf, unsigned long size, char *sys);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs, 178void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm); 179 char *comm);
172 180
@@ -233,13 +241,53 @@ extern int header_page_size_size;
233extern int header_page_data_offset; 241extern int header_page_data_offset;
234extern int header_page_data_size; 242extern int header_page_data_size;
235 243
244extern int latency_format;
245
236int parse_header_page(char *buf, unsigned long size); 246int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data); 247int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data);
250int parse_common_flags(void *data);
251int parse_common_lock_depth(void *data);
238struct event *trace_find_event(int id); 252struct event *trace_find_event(int id);
253struct event *trace_find_next_event(struct event *event);
254unsigned long long read_size(void *ptr, int size);
239unsigned long long 255unsigned long long
240raw_field_value(struct event *event, const char *name, void *data); 256raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data); 257void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag);
259
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
261
262/* taken from kernel/trace/trace.h */
263enum trace_flag_type {
264 TRACE_FLAG_IRQS_OFF = 0x01,
265 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
266 TRACE_FLAG_NEED_RESCHED = 0x04,
267 TRACE_FLAG_HARDIRQ = 0x08,
268 TRACE_FLAG_SOFTIRQ = 0x10,
269};
270
271struct scripting_ops {
272 const char *name;
273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm);
277 int (*generate_script) (const char *outfile);
278};
279
280int script_spec_register(const char *spec, struct scripting_ops *ops);
281
282void setup_perl_scripting(void);
283void setup_python_scripting(void);
284
285struct scripting_context {
286 void *event_data;
287};
242 288
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 289int common_pc(struct scripting_context *context);
290int common_flags(struct scripting_context *context);
291int common_lock_depth(struct scripting_context *context);
244 292
245#endif /* _TRACE_EVENTS_H */ 293#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define _PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4/* 4/*
5 * We define u64 as unsigned long long for every architecture 5 * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
14typedef unsigned char u8; 14typedef unsigned char u8;
15typedef signed char s8; 15typedef signed char s8;
16 16
17#endif /* _PERF_TYPES_H */ 17#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..f9b890fde681
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,94 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 9de2329dd44d..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -84,6 +84,9 @@
84#include <iconv.h> 84#include <iconv.h>
85#endif 85#endif
86 86
87extern const char *graph_line;
88extern const char *graph_dotted_line;
89
87/* On most systems <limits.h> would have given us this, but 90/* On most systems <limits.h> would have given us this, but
88 * not on some systems (e.g. GNU/Hurd). 91 * not on some systems (e.g. GNU/Hurd).
89 */ 92 */
@@ -134,6 +137,15 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
134extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); 137extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
135extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); 138extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
136 139
140#include "../../../include/linux/stringify.h"
141
142#define DIE_IF(cnd) \
143 do { if (cnd) \
144 die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
145 __stringify(cnd) "\n"); \
146 } while (0)
147
148
137extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 149extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
138 150
139extern int prefixcmp(const char *str, const char *prefix); 151extern int prefixcmp(const char *str, const char *prefix);
@@ -278,17 +290,15 @@ static inline char *gitstrchrnul(const char *s, int c)
278 * Wrappers: 290 * Wrappers:
279 */ 291 */
280extern char *xstrdup(const char *str); 292extern char *xstrdup(const char *str);
281extern void *xmalloc(size_t size); 293extern void *xmalloc(size_t size) __attribute__((weak));
282extern void *xmemdupz(const void *data, size_t len); 294extern void *xmemdupz(const void *data, size_t len);
283extern char *xstrndup(const char *str, size_t len); 295extern char *xstrndup(const char *str, size_t len);
284extern void *xrealloc(void *ptr, size_t size); 296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
285extern void *xcalloc(size_t nmemb, size_t size); 297
286extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 298static inline void *zalloc(size_t size)
287extern ssize_t xread(int fd, void *buf, size_t len); 299{
288extern ssize_t xwrite(int fd, const void *buf, size_t len); 300 return calloc(1, size);
289extern int xdup(int fd); 301}
290extern FILE *xfdopen(int fd, const char *mode);
291extern int xmkstemp(char *template);
292 302
293static inline size_t xsize_t(off_t len) 303static inline size_t xsize_t(off_t len)
294{ 304{
@@ -306,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
306#undef isascii 316#undef isascii
307#undef isspace 317#undef isspace
308#undef isdigit 318#undef isdigit
319#undef isxdigit
309#undef isalpha 320#undef isalpha
310#undef isprint 321#undef isprint
311#undef isalnum 322#undef isalnum
@@ -323,6 +334,8 @@ extern unsigned char sane_ctype[256];
323#define isascii(x) (((x) & ~0x7f) == 0) 334#define isascii(x) (((x) & ~0x7f) == 0)
324#define isspace(x) sane_istest(x,GIT_SPACE) 335#define isspace(x) sane_istest(x,GIT_SPACE)
325#define isdigit(x) sane_istest(x,GIT_DIGIT) 336#define isdigit(x) sane_istest(x,GIT_DIGIT)
337#define isxdigit(x) \
338 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
326#define isalpha(x) sane_istest(x,GIT_ALPHA) 339#define isalpha(x) sane_istest(x,GIT_ALPHA)
327#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 340#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
328#define isprint(x) sane_istest(x,GIT_PRINT) 341#define isprint(x) sane_istest(x,GIT_PRINT)
@@ -390,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
390#endif 403#endif
391#endif 404#endif
392 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
393#endif 409#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define _PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
24void perf_read_values_display(FILE *fp, struct perf_read_values *values, 24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw); 25 int raw);
26 26
27#endif /* _PERF_VALUES_H */ 27#endif /* __PERF_VALUES_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 4574ac28396f..bf44ca85d23b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
79 return ret; 79 return ret;
80} 80}
81 81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/* 82/*
114 * xread() is the same a read(), but it automatically restarts read() 83 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread() 84 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. 85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */ 86 */
118ssize_t xread(int fd, void *buf, size_t len) 87static ssize_t xread(int fd, void *buf, size_t len)
119{ 88{
120 ssize_t nr; 89 ssize_t nr;
121 while (1) { 90 while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT 100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful. 101 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */ 102 */
134ssize_t xwrite(int fd, const void *buf, size_t len) 103static ssize_t xwrite(int fd, const void *buf, size_t len)
135{ 104{
136 ssize_t nr; 105 ssize_t nr;
137 while (1) { 106 while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
179 148
180 return total; 149 return total;
181} 150}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}