aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-04-09 10:17:41 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-04-09 10:21:12 -0400
commit87d8a69709d971913e6cc7210450fcb8be963667 (patch)
tree4f8eb95c588f7df84554dcf97d67540664333a7b /tools
parent0b8973a81876d90f916507ac40d1381068dc986a (diff)
parent2eaa9cfdf33b8d7fb7aff27792192e0019ae8fc6 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/Makefile4
-rw-r--r--tools/perf/Documentation/perf-archive.txt22
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Documentation/perf-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-lock.txt29
-rw-r--r--tools/perf/Documentation/perf-probe.txt77
-rw-r--r--tools/perf/Documentation/perf-report.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt2
-rw-r--r--tools/perf/Documentation/perf-trace-python.txt625
-rw-r--r--tools/perf/Documentation/perf-trace.txt42
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/Makefile118
-rw-r--r--tools/perf/builtin-annotate.c300
-rw-r--r--tools/perf/builtin-buildid-cache.c133
-rw-r--r--tools/perf/builtin-buildid-list.c37
-rw-r--r--tools/perf/builtin-diff.c242
-rw-r--r--tools/perf/builtin-help.c5
-rw-r--r--tools/perf/builtin-kmem.c115
-rw-r--r--tools/perf/builtin-lock.c822
-rw-r--r--tools/perf/builtin-probe.c222
-rw-r--r--tools/perf/builtin-record.c198
-rw-r--r--tools/perf/builtin-report.c838
-rw-r--r--tools/perf/builtin-sched.c117
-rw-r--r--tools/perf/builtin-stat.c116
-rw-r--r--tools/perf/builtin-timechart.c80
-rw-r--r--tools/perf/builtin-top.c176
-rw-r--r--tools/perf/builtin-trace.c385
-rw-r--r--tools/perf/builtin.h3
-rw-r--r--tools/perf/command-list.txt4
-rw-r--r--tools/perf/design.txt16
-rw-r--r--tools/perf/perf-archive.sh33
-rw-r--r--tools/perf/perf.c28
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c5
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs3
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm2
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-record7
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report5
-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-report4
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report1
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report1
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report1
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl38
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl5
-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/cpumap.c59
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/data_map.c242
-rw-r--r--tools/perf/util/data_map.h29
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c334
-rw-r--r--tools/perf/util/event.h104
-rw-r--r--tools/perf/util/header.c286
-rw-r--r--tools/perf/util/header.h9
-rw-r--r--tools/perf/util/hist.c524
-rw-r--r--tools/perf/util/hist.h59
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h1
-rw-r--r--tools/perf/util/map.c50
-rw-r--r--tools/perf/util/map.h94
-rw-r--r--tools/perf/util/parse-events.c48
-rw-r--r--tools/perf/util/probe-event.c379
-rw-r--r--tools/perf/util/probe-event.h13
-rw-r--r--tools/perf/util/probe-finder.c967
-rw-r--r--tools/perf/util/probe-finder.h91
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c (renamed from tools/perf/util/trace-event-perl.c)151
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c573
-rw-r--r--tools/perf/util/session.c506
-rw-r--r--tools/perf/util/session.h73
-rw-r--r--tools/perf/util/sort.c26
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/string.c111
-rw-r--r--tools/perf/util/string.h3
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h41
-rw-r--r--tools/perf/util/symbol.c617
-rw-r--r--tools/perf/util/symbol.h77
-rw-r--r--tools/perf/util/thread.c124
-rw-r--r--tools/perf/util/thread.h33
-rw-r--r--tools/perf/util/trace-event-info.c64
-rw-r--r--tools/perf/util/trace-event-parse.c24
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c18
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h12
-rw-r--r--tools/perf/util/util.c94
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.c1
108 files changed, 8611 insertions, 3012 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index fe08660ce0bd..e1d60d780784 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -13,6 +13,8 @@ perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data 15perf.data
16perf.data.old
17perf-archive
16tags 18tags
17TAGS 19TAGS
18cscope* 20cscope*
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index bdd3b7ecad0a..bd498d496952 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) 24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) 25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
26 26
27# Make the path relative to DESTDIR, not prefix
28ifndef DESTDIR
27prefix?=$(HOME) 29prefix?=$(HOME)
30endif
28bindir?=$(prefix)/bin 31bindir?=$(prefix)/bin
29htmldir?=$(prefix)/share/doc/perf-doc 32htmldir?=$(prefix)/share/doc/perf-doc
30pdfdir?=$(prefix)/share/doc/perf-doc 33pdfdir?=$(prefix)/share/doc/perf-doc
@@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man
32man1dir=$(mandir)/man1 35man1dir=$(mandir)/man1
33man5dir=$(mandir)/man5 36man5dir=$(mandir)/man5
34man7dir=$(mandir)/man7 37man7dir=$(mandir)/man7
35# DESTDIR=
36 38
37ASCIIDOC=asciidoc 39ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = --unsafe 40ASCIIDOC_EXTRA = --unsafe
diff --git a/tools/perf/Documentation/perf-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-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-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-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
index 8fa6bf99fcb5..34202b1be0bb 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -15,6 +15,8 @@ or
15'perf probe' [options] --del='[GROUP:]EVENT' [...] 15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or 16or
17'perf probe' --list 17'perf probe' --list
18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
18 20
19DESCRIPTION 21DESCRIPTION
20----------- 22-----------
@@ -39,22 +41,89 @@ OPTIONS
39 41
40-d:: 42-d::
41--del=:: 43--del=::
42 Delete a probe event. 44 Delete probe events. This accepts glob wildcards('*', '?') and character
45 classes(e.g. [a-z], [!A-Z]).
43 46
44-l:: 47-l::
45--list:: 48--list::
46 List up current probe events. 49 List up current probe events.
47 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
48PROBE SYNTAX 60PROBE SYNTAX
49------------ 61------------
50Probe points are defined by following syntax. 62Probe points are defined by following syntax.
51 63
52 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 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 ...]
53 69
54'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 70 3) Define event based on source file with lazy pattern
55It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 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.
56'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 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).
57 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
58SEE ALSO 127SEE ALSO
59-------- 128--------
60linkperf:perf-trace[1], linkperf:perf-record[1] 129linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9dccb180b7af..abfabe9147a4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -39,6 +39,10 @@ OPTIONS
39 Only consider these symbols. CSV that understands 39 Only consider these symbols. CSV that understands
40 file://filename entries. 40 file://filename entries.
41 41
42-s::
43--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent.
45
42-w:: 46-w::
43--field-width=:: 47--field-width=::
44 Force each column width to the provided list, for large terminal 48 Force each column width to the provided list, for large terminal
diff --git a/tools/perf/Documentation/perf-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
index c5f55f439091..d729cee8d987 100644
--- a/tools/perf/Documentation/perf-trace-perl.txt
+++ b/tools/perf/Documentation/perf-trace-perl.txt
@@ -8,7 +8,7 @@ perf-trace-perl - Process trace data with a Perl script
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [lang]:script[.ext] ] 11'perf trace' [-s [Perl]:script[.pl] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
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 07065efa60e0..8879299cd9df 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,21 +8,56 @@ 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
23-s:: 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']::
24--script=:: 57--script=::
25 Process trace data with the given script ([lang]:script[.ext]). 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.
26 61
27-g:: 62-g::
28--gen-script=:: 63--gen-script=::
@@ -31,4 +66,5 @@ OPTIONS
31 66
32SEE ALSO 67SEE ALSO
33-------- 68--------
34linkperf:perf-record[1], linkperf:perf-trace-perl[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 406999668cab..8a8f52db7e38 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -216,7 +216,10 @@ STRIP ?= strip
216# runtime figures out where they are based on the path to the executable. 216# runtime figures out where they are based on the path to the executable.
217# This can help installing the suite in a relocatable way. 217# This can help installing the suite in a relocatable way.
218 218
219# Make the path relative to DESTDIR, not to prefix
220ifndef DESTDIR
219prefix = $(HOME) 221prefix = $(HOME)
222endif
220bindir_relative = bin 223bindir_relative = bin
221bindir = $(prefix)/$(bindir_relative) 224bindir = $(prefix)/$(bindir_relative)
222mandir = share/man 225mandir = share/man
@@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc
233ETC_PERFCONFIG = etc/perfconfig 236ETC_PERFCONFIG = etc/perfconfig
234endif 237endif
235lib = lib 238lib = lib
236# DESTDIR=
237 239
238export prefix bindir sharedir sysconfdir 240export prefix bindir sharedir sysconfdir
239 241
@@ -250,7 +252,19 @@ PTHREAD_LIBS = -lpthread
250# explicitly what architecture to check for. Fix this up for yours.. 252# explicitly what architecture to check for. Fix this up for yours..
251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 253SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
252 254
253ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null "$(QUIET_STDERR)" && echo y"), y) 255ifeq ($(V), 2)
256 QUIET_STDERR = ">/dev/null"
257else
258 QUIET_STDERR = ">/dev/null 2>&1"
259endif
260
261BITBUCKET = "/dev/null"
262
263ifneq ($(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)
264 BITBUCKET = .perf.dev.null
265endif
266
267ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
254 CFLAGS := $(CFLAGS) -fstack-protector-all 268 CFLAGS := $(CFLAGS) -fstack-protector-all
255endif 269endif
256 270
@@ -274,11 +288,7 @@ SCRIPT_PERL =
274SCRIPT_SH = 288SCRIPT_SH =
275TEST_PROGRAMS = 289TEST_PROGRAMS =
276 290
277# 291SCRIPT_SH += perf-archive.sh
278# No scripts right now:
279#
280
281# SCRIPT_SH += perf-am.sh
282 292
283# 293#
284# No Perl scripts right now: 294# No Perl scripts right now:
@@ -303,9 +313,6 @@ PROGRAMS += perf
303# List built-in command $C whose implementation cmd_$C() is not in 313# List built-in command $C whose implementation cmd_$C() is not in
304# builtin-$C.o but is linked in as part of some other command. 314# builtin-$C.o but is linked in as part of some other command.
305# 315#
306# None right now:
307#
308# BUILT_INS += perf-init $X
309 316
310# what 'all' will build and 'install' will install, in perfexecdir 317# what 'all' will build and 'install' will install, in perfexecdir
311ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 318ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -328,6 +335,7 @@ LIB_FILE=libperf.a
328LIB_H += ../../include/linux/perf_event.h 335LIB_H += ../../include/linux/perf_event.h
329LIB_H += ../../include/linux/rbtree.h 336LIB_H += ../../include/linux/rbtree.h
330LIB_H += ../../include/linux/list.h 337LIB_H += ../../include/linux/list.h
338LIB_H += ../../include/linux/hash.h
331LIB_H += ../../include/linux/stringify.h 339LIB_H += ../../include/linux/stringify.h
332LIB_H += util/include/linux/bitmap.h 340LIB_H += util/include/linux/bitmap.h
333LIB_H += util/include/linux/bitops.h 341LIB_H += util/include/linux/bitops.h
@@ -343,15 +351,22 @@ LIB_H += util/include/linux/string.h
343LIB_H += util/include/linux/types.h 351LIB_H += util/include/linux/types.h
344LIB_H += util/include/asm/asm-offsets.h 352LIB_H += util/include/asm/asm-offsets.h
345LIB_H += util/include/asm/bitops.h 353LIB_H += util/include/asm/bitops.h
354LIB_H += util/include/asm/bug.h
346LIB_H += util/include/asm/byteorder.h 355LIB_H += util/include/asm/byteorder.h
347LIB_H += util/include/asm/swab.h 356LIB_H += util/include/asm/swab.h
348LIB_H += util/include/asm/system.h 357LIB_H += util/include/asm/system.h
349LIB_H += util/include/asm/uaccess.h 358LIB_H += util/include/asm/uaccess.h
350LIB_H += perf.h 359LIB_H += perf.h
360LIB_H += util/cache.h
361LIB_H += util/callchain.h
362LIB_H += util/build-id.h
363LIB_H += util/debug.h
351LIB_H += util/debugfs.h 364LIB_H += util/debugfs.h
352LIB_H += util/event.h 365LIB_H += util/event.h
366LIB_H += util/exec_cmd.h
353LIB_H += util/types.h 367LIB_H += util/types.h
354LIB_H += util/levenshtein.h 368LIB_H += util/levenshtein.h
369LIB_H += util/map.h
355LIB_H += util/parse-options.h 370LIB_H += util/parse-options.h
356LIB_H += util/parse-events.h 371LIB_H += util/parse-events.h
357LIB_H += util/quote.h 372LIB_H += util/quote.h
@@ -362,6 +377,7 @@ LIB_H += util/session.h
362LIB_H += util/strbuf.h 377LIB_H += util/strbuf.h
363LIB_H += util/string.h 378LIB_H += util/string.h
364LIB_H += util/strlist.h 379LIB_H += util/strlist.h
380LIB_H += util/svghelper.h
365LIB_H += util/run-command.h 381LIB_H += util/run-command.h
366LIB_H += util/sigchain.h 382LIB_H += util/sigchain.h
367LIB_H += util/symbol.h 383LIB_H += util/symbol.h
@@ -370,12 +386,14 @@ LIB_H += util/values.h
370LIB_H += util/sort.h 386LIB_H += util/sort.h
371LIB_H += util/hist.h 387LIB_H += util/hist.h
372LIB_H += util/thread.h 388LIB_H += util/thread.h
373LIB_H += util/data_map.h 389LIB_H += util/trace-event.h
374LIB_H += util/probe-finder.h 390LIB_H += util/probe-finder.h
375LIB_H += util/probe-event.h 391LIB_H += util/probe-event.h
392LIB_H += util/cpumap.h
376 393
377LIB_OBJS += util/abspath.o 394LIB_OBJS += util/abspath.o
378LIB_OBJS += util/alias.o 395LIB_OBJS += util/alias.o
396LIB_OBJS += util/build-id.o
379LIB_OBJS += util/config.o 397LIB_OBJS += util/config.o
380LIB_OBJS += util/ctype.o 398LIB_OBJS += util/ctype.o
381LIB_OBJS += util/debugfs.o 399LIB_OBJS += util/debugfs.o
@@ -412,12 +430,13 @@ LIB_OBJS += util/thread.o
412LIB_OBJS += util/trace-event-parse.o 430LIB_OBJS += util/trace-event-parse.o
413LIB_OBJS += util/trace-event-read.o 431LIB_OBJS += util/trace-event-read.o
414LIB_OBJS += util/trace-event-info.o 432LIB_OBJS += util/trace-event-info.o
415LIB_OBJS += util/trace-event-perl.o 433LIB_OBJS += util/trace-event-scripting.o
416LIB_OBJS += util/svghelper.o 434LIB_OBJS += util/svghelper.o
417LIB_OBJS += util/sort.o 435LIB_OBJS += util/sort.o
418LIB_OBJS += util/hist.o 436LIB_OBJS += util/hist.o
419LIB_OBJS += util/data_map.o
420LIB_OBJS += util/probe-event.o 437LIB_OBJS += util/probe-event.o
438LIB_OBJS += util/util.o
439LIB_OBJS += util/cpumap.o
421 440
422BUILTIN_OBJS += builtin-annotate.o 441BUILTIN_OBJS += builtin-annotate.o
423 442
@@ -428,9 +447,11 @@ BUILTIN_OBJS += bench/sched-messaging.o
428BUILTIN_OBJS += bench/sched-pipe.o 447BUILTIN_OBJS += bench/sched-pipe.o
429BUILTIN_OBJS += bench/mem-memcpy.o 448BUILTIN_OBJS += bench/mem-memcpy.o
430 449
450BUILTIN_OBJS += builtin-diff.o
431BUILTIN_OBJS += builtin-help.o 451BUILTIN_OBJS += builtin-help.o
432BUILTIN_OBJS += builtin-sched.o 452BUILTIN_OBJS += builtin-sched.o
433BUILTIN_OBJS += builtin-buildid-list.o 453BUILTIN_OBJS += builtin-buildid-list.o
454BUILTIN_OBJS += builtin-buildid-cache.o
434BUILTIN_OBJS += builtin-list.o 455BUILTIN_OBJS += builtin-list.o
435BUILTIN_OBJS += builtin-record.o 456BUILTIN_OBJS += builtin-record.o
436BUILTIN_OBJS += builtin-report.o 457BUILTIN_OBJS += builtin-report.o
@@ -440,14 +461,10 @@ BUILTIN_OBJS += builtin-top.o
440BUILTIN_OBJS += builtin-trace.o 461BUILTIN_OBJS += builtin-trace.o
441BUILTIN_OBJS += builtin-probe.o 462BUILTIN_OBJS += builtin-probe.o
442BUILTIN_OBJS += builtin-kmem.o 463BUILTIN_OBJS += builtin-kmem.o
464BUILTIN_OBJS += builtin-lock.o
443 465
444PERFLIBS = $(LIB_FILE) 466PERFLIBS = $(LIB_FILE)
445 467
446ifeq ($(V), 2)
447 QUIET_STDERR = ">/dev/null"
448else
449 QUIET_STDERR = ">/dev/null 2>&1"
450endif
451# 468#
452# Platform specific tweaks 469# Platform specific tweaks
453# 470#
@@ -475,23 +492,24 @@ ifeq ($(uname_S),Darwin)
475 PTHREAD_LIBS = 492 PTHREAD_LIBS =
476endif 493endif
477 494
478ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 495ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
479ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 496ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
480 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 497 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
481endif 498endif
482 499
483 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 500 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
484 BASIC_CFLAGS += -DLIBELF_NO_MMAP 501 BASIC_CFLAGS += -DLIBELF_NO_MMAP
485 endif 502 endif
486else 503else
487 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 504 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
488endif 505endif
489 506
490ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 507ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
491 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); 508 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
492 BASIC_CFLAGS += -DNO_LIBDWARF 509 BASIC_CFLAGS += -DNO_DWARF_SUPPORT
493else 510else
494 EXTLIBS += -lelf -ldwarf 511 BASIC_CFLAGS += -I/usr/include/elfutils
512 EXTLIBS += -lelf -ldw
495 LIB_OBJS += util/probe-finder.o 513 LIB_OBJS += util/probe-finder.o
496endif 514endif
497 515
@@ -500,30 +518,44 @@ PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
500PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 518PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
501endif 519endif
502 520
503ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 521ifneq ($(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)
504 BASIC_CFLAGS += -DNO_LIBPERL 522 BASIC_CFLAGS += -DNO_LIBPERL
505else 523else
506 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 524 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
525 LIB_OBJS += util/scripting-engines/trace-event-perl.o
507 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o 526 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
508endif 527endif
509 528
529ifndef NO_LIBPYTHON
530PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
531PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
532endif
533
534ifneq ($(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)
535 BASIC_CFLAGS += -DNO_LIBPYTHON
536else
537 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
538 LIB_OBJS += util/scripting-engines/trace-event-python.o
539 LIB_OBJS += scripts/python/Perf-Trace-Util/Context.o
540endif
541
510ifdef NO_DEMANGLE 542ifdef NO_DEMANGLE
511 BASIC_CFLAGS += -DNO_DEMANGLE 543 BASIC_CFLAGS += -DNO_DEMANGLE
512else 544else
513 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") 545 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")
514 546
515 ifeq ($(has_bfd),y) 547 ifeq ($(has_bfd),y)
516 EXTLIBS += -lbfd 548 EXTLIBS += -lbfd
517 else 549 else
518 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") 550 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")
519 ifeq ($(has_bfd_iberty),y) 551 ifeq ($(has_bfd_iberty),y)
520 EXTLIBS += -lbfd -liberty 552 EXTLIBS += -lbfd -liberty
521 else 553 else
522 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") 554 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")
523 ifeq ($(has_bfd_iberty_z),y) 555 ifeq ($(has_bfd_iberty_z),y)
524 EXTLIBS += -lbfd -liberty -lz 556 EXTLIBS += -lbfd -liberty -lz
525 else 557 else
526 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") 558 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")
527 ifeq ($(has_cplus_demangle),y) 559 ifeq ($(has_cplus_demangle),y)
528 EXTLIBS += -liberty 560 EXTLIBS += -liberty
529 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 561 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -771,7 +803,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
771 803
772SHELL = $(SHELL_PATH) 804SHELL = $(SHELL_PATH)
773 805
774all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 806all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS
775ifneq (,$X) 807ifneq (,$X)
776 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 808 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
777endif 809endif
@@ -878,12 +910,18 @@ util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
878util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS 910util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
879 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 911 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
880 912
881util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS 913util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c PERF-CFLAGS
882 $(QUIET_CC)$(CC) -o util/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 914 $(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 $<
883 915
884scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS 916scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
885 $(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 $< 917 $(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 $<
886 918
919util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c PERF-CFLAGS
920 $(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 $<
921
922scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c PERF-CFLAGS
923 $(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 $<
924
887perf-%$X: %.o $(PERFLIBS) 925perf-%$X: %.o $(PERFLIBS)
888 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 926 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
889 927
@@ -993,11 +1031,16 @@ install: all
993 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1031 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
994 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1032 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
995 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1033 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1034 $(INSTALL) perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
996 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1035 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
997 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 1036 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
998 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1037 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
999 $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util' 1038 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1000 $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util' 1039 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1040 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1041 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1042 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1043
1001ifdef BUILT_INS 1044ifdef BUILT_INS
1002 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1045 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1003 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1046 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -1100,6 +1143,11 @@ clean:
1100.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1143.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1101.PHONY: .FORCE-PERF-BUILD-OPTIONS 1144.PHONY: .FORCE-PERF-BUILD-OPTIONS
1102 1145
1146.perf.dev.null:
1147 touch .perf.dev.null
1148
1149.INTERMEDIATE: .perf.dev.null
1150
1103### Make sure built-ins do not have dups and listed in perf.c 1151### Make sure built-ins do not have dups and listed in perf.c
1104# 1152#
1105check-builtins:: 1153check-builtins::
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 21a78d30d53d..6ad7148451c5 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -26,7 +26,6 @@
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/session.h" 28#include "util/session.h"
29#include "util/data_map.h"
30 29
31static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
32 31
@@ -52,39 +51,22 @@ struct sym_priv {
52 struct sym_ext *ext; 51 struct sym_ext *ext;
53}; 52};
54 53
55static struct symbol_conf symbol_conf = {
56 .priv_size = sizeof(struct sym_priv),
57 .try_vmlinux_path = true,
58};
59
60static const char *sym_hist_filter; 54static const char *sym_hist_filter;
61 55
62static int symbol_filter(struct map *map __used, struct symbol *sym) 56static int sym__alloc_hist(struct symbol *self)
63{ 57{
64 if (sym_hist_filter == NULL || 58 struct sym_priv *priv = symbol__priv(self);
65 strcmp(sym->name, sym_hist_filter) == 0) { 59 const int size = (sizeof(*priv->hist) +
66 struct sym_priv *priv = symbol__priv(sym); 60 (self->end - self->start) * sizeof(u64));
67 const int size = (sizeof(*priv->hist) +
68 (sym->end - sym->start) * sizeof(u64));
69 61
70 priv->hist = malloc(size); 62 priv->hist = zalloc(size);
71 if (priv->hist) 63 return priv->hist == NULL ? -1 : 0;
72 memset(priv->hist, 0, size);
73 return 0;
74 }
75 /*
76 * FIXME: We should really filter it out, as we don't want to go thru symbols
77 * we're not interested, and if a DSO ends up with no symbols, delete it too,
78 * but right now the kernel loading routines in symbol.c bail out if no symbols
79 * are found, fix it later.
80 */
81 return 0;
82} 64}
83 65
84/* 66/*
85 * collect histogram counts 67 * collect histogram counts
86 */ 68 */
87static void hist_hit(struct hist_entry *he, u64 ip) 69static int annotate__hist_hit(struct hist_entry *he, u64 ip)
88{ 70{
89 unsigned int sym_size, offset; 71 unsigned int sym_size, offset;
90 struct symbol *sym = he->sym; 72 struct symbol *sym = he->sym;
@@ -94,81 +76,127 @@ static void hist_hit(struct hist_entry *he, u64 ip)
94 he->count++; 76 he->count++;
95 77
96 if (!sym || !he->map) 78 if (!sym || !he->map)
97 return; 79 return 0;
98 80
99 priv = symbol__priv(sym); 81 priv = symbol__priv(sym);
100 if (!priv->hist) 82 if (priv->hist == NULL && sym__alloc_hist(sym) < 0)
101 return; 83 return -ENOMEM;
102 84
103 sym_size = sym->end - sym->start; 85 sym_size = sym->end - sym->start;
104 offset = ip - sym->start; 86 offset = ip - sym->start;
105 87
106 if (verbose) 88 pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip));
107 fprintf(stderr, "%s: ip=%Lx\n", __func__,
108 he->map->unmap_ip(he->map, ip));
109 89
110 if (offset >= sym_size) 90 if (offset >= sym_size)
111 return; 91 return 0;
112 92
113 h = priv->hist; 93 h = priv->hist;
114 h->sum++; 94 h->sum++;
115 h->ip[offset]++; 95 h->ip[offset]++;
116 96
117 if (verbose >= 3) 97 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start,
118 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 98 he->sym->name, ip, ip - he->sym->start, h->ip[offset]);
119 (void *)(unsigned long)he->sym->start, 99 return 0;
120 he->sym->name,
121 (void *)(unsigned long)ip, ip - he->sym->start,
122 h->ip[offset]);
123} 100}
124 101
125static int hist_entry__add(struct addr_location *al, u64 count) 102static int perf_session__add_hist_entry(struct perf_session *self,
103 struct addr_location *al, u64 count)
126{ 104{
127 bool hit; 105 bool hit;
128 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit); 106 struct hist_entry *he;
107
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);
115 }
116 return 0;
117 }
118
119 he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit);
129 if (he == NULL) 120 if (he == NULL)
130 return -ENOMEM; 121 return -ENOMEM;
131 hist_hit(he, al->addr); 122
132 return 0; 123 return annotate__hist_hit(he, al->addr);
133} 124}
134 125
135static int process_sample_event(event_t *event) 126static int process_sample_event(event_t *event, struct perf_session *session)
136{ 127{
137 struct addr_location al; 128 struct addr_location al;
138 129
139 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 130 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
140 event->ip.pid, (void *)(long)event->ip.ip); 131 event->ip.pid, event->ip.ip);
141 132
142 if (event__preprocess_sample(event, &al, symbol_filter) < 0) { 133 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
143 fprintf(stderr, "problem processing %d event, skipping it.\n", 134 pr_warning("problem processing %d event, skipping it.\n",
144 event->header.type); 135 event->header.type);
145 return -1; 136 return -1;
146 } 137 }
147 138
148 if (hist_entry__add(&al, 1)) { 139 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
149 fprintf(stderr, "problem incrementing symbol count, " 140 pr_warning("problem incrementing symbol count, "
150 "skipping event\n"); 141 "skipping event\n");
151 return -1; 142 return -1;
152 } 143 }
153 144
154 return 0; 145 return 0;
155} 146}
156 147
157static int parse_line(FILE *file, struct hist_entry *he, u64 len) 148struct objdump_line {
149 struct list_head node;
150 s64 offset;
151 char *line;
152};
153
154static struct objdump_line *objdump_line__new(s64 offset, char *line)
155{
156 struct objdump_line *self = malloc(sizeof(*self));
157
158 if (self != NULL) {
159 self->offset = offset;
160 self->line = line;
161 }
162
163 return self;
164}
165
166static void objdump_line__free(struct objdump_line *self)
167{
168 free(self->line);
169 free(self);
170}
171
172static void objdump__add_line(struct list_head *head, struct objdump_line *line)
173{
174 list_add_tail(&line->node, head);
175}
176
177static struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
178 struct objdump_line *pos)
179{
180 list_for_each_entry_continue(pos, head, node)
181 if (pos->offset >= 0)
182 return pos;
183
184 return NULL;
185}
186
187static int parse_line(FILE *file, struct hist_entry *he,
188 struct list_head *head)
158{ 189{
159 struct symbol *sym = he->sym; 190 struct symbol *sym = he->sym;
191 struct objdump_line *objdump_line;
160 char *line = NULL, *tmp, *tmp2; 192 char *line = NULL, *tmp, *tmp2;
161 static const char *prev_line;
162 static const char *prev_color;
163 unsigned int offset;
164 size_t line_len; 193 size_t line_len;
165 u64 start; 194 s64 line_ip, offset = -1;
166 s64 line_ip;
167 int ret;
168 char *c; 195 char *c;
169 196
170 if (getline(&line, &line_len, file) < 0) 197 if (getline(&line, &line_len, file) < 0)
171 return -1; 198 return -1;
199
172 if (!line) 200 if (!line)
173 return -1; 201 return -1;
174 202
@@ -177,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
177 *c = 0; 205 *c = 0;
178 206
179 line_ip = -1; 207 line_ip = -1;
180 offset = 0;
181 ret = -2;
182 208
183 /* 209 /*
184 * Strip leading spaces: 210 * Strip leading spaces:
@@ -199,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
199 line_ip = -1; 225 line_ip = -1;
200 } 226 }
201 227
202 start = he->map->unmap_ip(he->map, sym->start);
203
204 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) {
205 const char *path = NULL; 252 const char *path = NULL;
206 unsigned int hits = 0; 253 unsigned int hits = 0;
207 double percent = 0.0; 254 double percent = 0.0;
@@ -209,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
209 struct sym_priv *priv = symbol__priv(sym); 256 struct sym_priv *priv = symbol__priv(sym);
210 struct sym_ext *sym_ext = priv->ext; 257 struct sym_ext *sym_ext = priv->ext;
211 struct sym_hist *h = priv->hist; 258 struct sym_hist *h = priv->hist;
259 s64 offset = self->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 }
212 273
213 offset = line_ip - start; 274 if (sym_ext == NULL && h->sum)
214 if (offset < len)
215 hits = h->ip[offset];
216
217 if (offset < len && sym_ext) {
218 path = sym_ext[offset].path;
219 percent = sym_ext[offset].percent;
220 } else if (h->sum)
221 percent = 100.0 * hits / h->sum; 275 percent = 100.0 * hits / h->sum;
222 276
223 color = get_percent_color(percent); 277 color = get_percent_color(percent);
@@ -238,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
238 292
239 color_fprintf(stdout, color, " %7.2f", percent); 293 color_fprintf(stdout, color, " %7.2f", percent);
240 printf(" : "); 294 printf(" : ");
241 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 295 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
242 } else { 296 } else {
243 if (!*line) 297 if (!*self->line)
244 printf(" :\n"); 298 printf(" :\n");
245 else 299 else
246 printf(" : %s\n", line); 300 printf(" : %s\n", self->line);
247 } 301 }
248 302
249 return 0; 303 return 0;
@@ -369,6 +423,20 @@ static void print_summary(const char *filename)
369 } 423 }
370} 424}
371 425
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
372static void annotate_sym(struct hist_entry *he) 440static void annotate_sym(struct hist_entry *he)
373{ 441{
374 struct map *map = he->map; 442 struct map *map = he->map;
@@ -378,15 +446,15 @@ static void annotate_sym(struct hist_entry *he)
378 u64 len; 446 u64 len;
379 char command[PATH_MAX*2]; 447 char command[PATH_MAX*2];
380 FILE *file; 448 FILE *file;
449 LIST_HEAD(head);
450 struct objdump_line *pos, *n;
381 451
382 if (!filename) 452 if (!filename)
383 return; 453 return;
384 454
385 if (verbose) 455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
386 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", 456 filename, sym->name, map->unmap_ip(map, sym->start),
387 __func__, filename, sym->name, 457 map->unmap_ip(map, sym->end));
388 map->unmap_ip(map, sym->start),
389 map->unmap_ip(map, sym->end));
390 458
391 if (full_paths) 459 if (full_paths)
392 d_filename = filename; 460 d_filename = filename;
@@ -409,7 +477,8 @@ static void annotate_sym(struct hist_entry *he)
409 dso, dso->long_name, sym, sym->name); 477 dso, dso->long_name, sym, sym->name);
410 478
411 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",
412 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end), 480 map__rip_2objdump(map, sym->start),
481 map__rip_2objdump(map, sym->end),
413 filename, filename); 482 filename, filename);
414 483
415 if (verbose >= 3) 484 if (verbose >= 3)
@@ -420,20 +489,30 @@ static void annotate_sym(struct hist_entry *he)
420 return; 489 return;
421 490
422 while (!feof(file)) { 491 while (!feof(file)) {
423 if (parse_line(file, he, len) < 0) 492 if (parse_line(file, he, &head) < 0)
424 break; 493 break;
425 } 494 }
426 495
427 pclose(file); 496 pclose(file);
497
498 if (verbose)
499 hist_entry__print_hits(he);
500
501 list_for_each_entry_safe(pos, n, &head, node) {
502 objdump_line__print(pos, &head, he, len);
503 list_del(&pos->node);
504 objdump_line__free(pos);
505 }
506
428 if (print_line) 507 if (print_line)
429 free_source_line(he, len); 508 free_source_line(he, len);
430} 509}
431 510
432static void find_annotations(void) 511static void perf_session__find_annotations(struct perf_session *self)
433{ 512{
434 struct rb_node *nd; 513 struct rb_node *nd;
435 514
436 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 515 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
437 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 516 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
438 struct sym_priv *priv; 517 struct sym_priv *priv;
439 518
@@ -454,26 +533,23 @@ static void find_annotations(void)
454 } 533 }
455} 534}
456 535
457static struct perf_file_handler file_handler = { 536static struct perf_event_ops event_ops = {
458 .process_sample_event = process_sample_event, 537 .sample = process_sample_event,
459 .process_mmap_event = event__process_mmap, 538 .mmap = event__process_mmap,
460 .process_comm_event = event__process_comm, 539 .comm = event__process_comm,
461 .process_fork_event = event__process_task, 540 .fork = event__process_task,
462}; 541};
463 542
464static int __cmd_annotate(void) 543static int __cmd_annotate(void)
465{ 544{
466 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
467 struct thread *idle;
468 int ret; 545 int ret;
546 struct perf_session *session;
469 547
548 session = perf_session__new(input_name, O_RDONLY, force);
470 if (session == NULL) 549 if (session == NULL)
471 return -ENOMEM; 550 return -ENOMEM;
472 551
473 idle = register_idle_thread(); 552 ret = perf_session__process_events(session, &event_ops);
474 register_perf_file_handler(&file_handler);
475
476 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
477 if (ret) 553 if (ret)
478 goto out_delete; 554 goto out_delete;
479 555
@@ -483,15 +559,14 @@ static int __cmd_annotate(void)
483 } 559 }
484 560
485 if (verbose > 3) 561 if (verbose > 3)
486 threads__fprintf(stdout); 562 perf_session__fprintf(session, stdout);
487 563
488 if (verbose > 2) 564 if (verbose > 2)
489 dsos__fprintf(stdout); 565 dsos__fprintf(stdout);
490 566
491 collapse__resort(); 567 perf_session__collapse_resort(&session->hists);
492 output__resort(event__total[0]); 568 perf_session__output_resort(&session->hists, session->event_total[0]);
493 569 perf_session__find_annotations(session);
494 find_annotations();
495out_delete: 570out_delete:
496 perf_session__delete(session); 571 perf_session__delete(session);
497 572
@@ -524,29 +599,17 @@ static const struct option options[] = {
524 OPT_END() 599 OPT_END()
525}; 600};
526 601
527static void setup_sorting(void) 602int cmd_annotate(int argc, const char **argv, const char *prefix __used)
528{ 603{
529 char *tmp, *tok, *str = strdup(sort_order); 604 argc = parse_options(argc, argv, options, annotate_usage, 0);
530
531 for (tok = strtok_r(str, ", ", &tmp);
532 tok; tok = strtok_r(NULL, ", ", &tmp)) {
533 if (sort_dimension__add(tok) < 0) {
534 error("Unknown --sort key: `%s'", tok);
535 usage_with_options(annotate_usage, options);
536 }
537 }
538 605
539 free(str); 606 symbol_conf.priv_size = sizeof(struct sym_priv);
540} 607 symbol_conf.try_vmlinux_path = true;
541 608
542int cmd_annotate(int argc, const char **argv, const char *prefix __used) 609 if (symbol__init() < 0)
543{
544 if (symbol__init(&symbol_conf) < 0)
545 return -1; 610 return -1;
546 611
547 argc = parse_options(argc, argv, options, annotate_usage, 0); 612 setup_sorting(annotate_usage, options);
548
549 setup_sorting();
550 613
551 if (argc) { 614 if (argc) {
552 /* 615 /*
@@ -562,9 +625,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
562 setup_pager(); 625 setup_pager();
563 626
564 if (field_sep && *field_sep == '.') { 627 if (field_sep && *field_sep == '.') {
565 fputs("'.' is the only non valid --field-separator argument\n", 628 pr_err("'.' is the only non valid --field-separator argument\n");
566 stderr); 629 return -1;
567 exit(129);
568 } 630 }
569 631
570 return __cmd_annotate(); 632 return __cmd_annotate();
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
index bfd16a1594e4..d0675c02f81e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -8,8 +8,8 @@
8 */ 8 */
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11#include "util/build-id.h"
11#include "util/cache.h" 12#include "util/cache.h"
12#include "util/data_map.h"
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/session.h" 15#include "util/session.h"
@@ -17,13 +17,15 @@
17 17
18static char const *input_name = "perf.data"; 18static char const *input_name = "perf.data";
19static int force; 19static int force;
20static bool with_hits;
20 21
21static const char *const buildid_list_usage[] = { 22static const char * const buildid_list_usage[] = {
22 "perf buildid-list [<options>]", 23 "perf buildid-list [<options>]",
23 NULL 24 NULL
24}; 25};
25 26
26static const struct option options[] = { 27static const struct option options[] = {
28 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
27 OPT_STRING('i', "input", &input_name, "file", 29 OPT_STRING('i', "input", &input_name, "file",
28 "input file name"), 30 "input file name"),
29 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -32,38 +34,19 @@ static const struct option options[] = {
32 OPT_END() 34 OPT_END()
33}; 35};
34 36
35static int perf_file_section__process_buildids(struct perf_file_section *self,
36 int feat, int fd)
37{
38 if (feat != HEADER_BUILD_ID)
39 return 0;
40
41 if (lseek(fd, self->offset, SEEK_SET) < 0) {
42 pr_warning("Failed to lseek to %Ld offset for buildids!\n",
43 self->offset);
44 return -1;
45 }
46
47 if (perf_header__read_build_ids(fd, self->offset, self->size)) {
48 pr_warning("Failed to read buildids!\n");
49 return -1;
50 }
51
52 return 0;
53}
54
55static int __cmd_buildid_list(void) 37static int __cmd_buildid_list(void)
56{ 38{
57 int err = -1; 39 int err = -1;
58 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force); 40 struct perf_session *session;
59 41
42 session = perf_session__new(input_name, O_RDONLY, force);
60 if (session == NULL) 43 if (session == NULL)
61 return -1; 44 return -1;
62 45
63 err = perf_header__process_sections(&session->header, session->fd, 46 if (with_hits)
64 perf_file_section__process_buildids); 47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
65 if (err >= 0) 48
66 dsos__fprintf_buildid(stdout); 49 dsos__fprintf_buildid(stdout, with_hits);
67 50
68 perf_session__delete(session); 51 perf_session__delete(session);
69 return err; 52 return err;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
new file mode 100644
index 000000000000..1ea15d8aeed1
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,242 @@
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->hists,
30 al, NULL,
31 count, &hit);
32 if (he == NULL)
33 return -ENOMEM;
34
35 if (hit)
36 he->count += count;
37
38 return 0;
39}
40
41static int diff__process_sample_event(event_t *event, struct perf_session *session)
42{
43 struct addr_location al;
44 struct sample_data data = { .period = 1, };
45
46 dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
47 event->ip.pid, event->ip.ip);
48
49 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
50 pr_warning("problem processing %d event, skipping it.\n",
51 event->header.type);
52 return -1;
53 }
54
55 if (al.filtered || al.sym == NULL)
56 return 0;
57
58 event__parse_sample(event, session->sample_type, &data);
59
60 if (perf_session__add_hist_entry(session, &al, data.period)) {
61 pr_warning("problem incrementing symbol count, skipping event\n");
62 return -1;
63 }
64
65 session->events_stats.total += data.period;
66 return 0;
67}
68
69static struct perf_event_ops event_ops = {
70 .sample = diff__process_sample_event,
71 .mmap = event__process_mmap,
72 .comm = event__process_comm,
73 .exit = event__process_task,
74 .fork = event__process_task,
75 .lost = event__process_lost,
76};
77
78static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
79 struct hist_entry *he)
80{
81 struct rb_node **p = &root->rb_node;
82 struct rb_node *parent = NULL;
83 struct hist_entry *iter;
84
85 while (*p != NULL) {
86 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node);
88 if (hist_entry__cmp(he, iter) < 0)
89 p = &(*p)->rb_left;
90 else
91 p = &(*p)->rb_right;
92 }
93
94 rb_link_node(&he->rb_node, parent, p);
95 rb_insert_color(&he->rb_node, root);
96}
97
98static void perf_session__resort_hist_entries(struct perf_session *self)
99{
100 unsigned long position = 1;
101 struct rb_root tmp = RB_ROOT;
102 struct rb_node *next = rb_first(&self->hists);
103
104 while (next != NULL) {
105 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
106
107 next = rb_next(&n->rb_node);
108 rb_erase(&n->rb_node, &self->hists);
109 n->position = position++;
110 perf_session__insert_hist_entry_by_name(&tmp, n);
111 }
112
113 self->hists = tmp;
114}
115
116static void perf_session__set_hist_entries_positions(struct perf_session *self)
117{
118 perf_session__output_resort(&self->hists, self->events_stats.total);
119 perf_session__resort_hist_entries(self);
120}
121
122static struct hist_entry *
123perf_session__find_hist_entry(struct perf_session *self,
124 struct hist_entry *he)
125{
126 struct rb_node *n = self->hists.rb_node;
127
128 while (n) {
129 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
130 int64_t cmp = hist_entry__cmp(he, iter);
131
132 if (cmp < 0)
133 n = n->rb_left;
134 else if (cmp > 0)
135 n = n->rb_right;
136 else
137 return iter;
138 }
139
140 return NULL;
141}
142
143static void perf_session__match_hists(struct perf_session *old_session,
144 struct perf_session *new_session)
145{
146 struct rb_node *nd;
147
148 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
149 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
150 pos->pair = perf_session__find_hist_entry(old_session, pos);
151 }
152}
153
154static int __cmd_diff(void)
155{
156 int ret, i;
157 struct perf_session *session[2];
158
159 session[0] = perf_session__new(input_old, O_RDONLY, force);
160 session[1] = perf_session__new(input_new, O_RDONLY, force);
161 if (session[0] == NULL || session[1] == NULL)
162 return -ENOMEM;
163
164 for (i = 0; i < 2; ++i) {
165 ret = perf_session__process_events(session[i], &event_ops);
166 if (ret)
167 goto out_delete;
168 }
169
170 perf_session__output_resort(&session[1]->hists,
171 session[1]->events_stats.total);
172 if (show_displacement)
173 perf_session__set_hist_entries_positions(session[0]);
174
175 perf_session__match_hists(session[0], session[1]);
176 perf_session__fprintf_hists(&session[1]->hists, session[0],
177 show_displacement, stdout,
178 session[1]->events_stats.total);
179out_delete:
180 for (i = 0; i < 2; ++i)
181 perf_session__delete(session[i]);
182 return ret;
183}
184
185static const char * const diff_usage[] = {
186 "perf diff [<options>] [old_file] [new_file]",
187 NULL,
188};
189
190static const struct option options[] = {
191 OPT_BOOLEAN('v', "verbose", &verbose,
192 "be more verbose (show symbol address, etc)"),
193 OPT_BOOLEAN('m', "displacement", &show_displacement,
194 "Show position displacement relative to baseline"),
195 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
196 "dump raw trace in ASCII"),
197 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
198 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
199 "load module symbols - WARNING: use only with -k and LIVE kernel"),
200 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
201 "Don't shorten the pathnames taking into account the cwd"),
202 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
203 "only consider symbols in these dsos"),
204 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
205 "only consider symbols in these comms"),
206 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
207 "only consider these symbols"),
208 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
209 "sort by key(s): pid, comm, dso, symbol, parent"),
210 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
211 "separator for columns, no spaces will be added between "
212 "columns '.' is reserved."),
213 OPT_END()
214};
215
216int cmd_diff(int argc, const char **argv, const char *prefix __used)
217{
218 sort_order = diff__default_sort_order;
219 argc = parse_options(argc, argv, options, diff_usage, 0);
220 if (argc) {
221 if (argc > 2)
222 usage_with_options(diff_usage, options);
223 if (argc == 2) {
224 input_old = argv[0];
225 input_new = argv[1];
226 } else
227 input_new = argv[0];
228 }
229
230 symbol_conf.exclude_other = false;
231 if (symbol__init() < 0)
232 return -1;
233
234 setup_sorting(diff_usage, options);
235 setup_pager();
236
237 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
238 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
239 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
240
241 return __cmd_diff();
242}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 9f810b17c25c..215b584007b1 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -286,8 +286,7 @@ void list_common_cmds_help(void)
286 286
287 puts(" The most commonly used perf commands are:"); 287 puts(" The most commonly used perf commands are:");
288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289 printf(" %s ", common_cmds[i].name); 289 printf(" %-*s ", longest, common_cmds[i].name);
290 mput_char(' ', longest - strlen(common_cmds[i].name));
291 puts(common_cmds[i].help); 290 puts(common_cmds[i].help);
292 } 291 }
293} 292}
@@ -314,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd)
314 return "perf"; 313 return "perf";
315 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
316 return perf_cmd; 315 return perf_cmd;
317 else if (is_perf_command(perf_cmd))
318 return prepend("perf-", perf_cmd);
319 else 316 else
320 return prepend("perf-", perf_cmd); 317 return prepend("perf-", perf_cmd);
321} 318}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 2071d2485913..924a9518931a 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -12,7 +12,6 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13 13
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/data_map.h"
16 15
17#include <linux/rbtree.h> 16#include <linux/rbtree.h>
18 17
@@ -21,8 +20,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
21 20
22static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
23 22
24static u64 sample_type;
25
26static int alloc_flag; 23static int alloc_flag;
27static int caller_flag; 24static int caller_flag;
28 25
@@ -95,23 +92,18 @@ static void setup_cpunode_map(void)
95 if (!dir1) 92 if (!dir1)
96 return; 93 return;
97 94
98 while (true) { 95 while ((dent1 = readdir(dir1)) != NULL) {
99 dent1 = readdir(dir1); 96 if (dent1->d_type != DT_DIR ||
100 if (!dent1) 97 sscanf(dent1->d_name, "node%u", &mem) < 1)
101 break;
102
103 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
104 continue; 98 continue;
105 99
106 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); 100 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
107 dir2 = opendir(buf); 101 dir2 = opendir(buf);
108 if (!dir2) 102 if (!dir2)
109 continue; 103 continue;
110 while (true) { 104 while ((dent2 = readdir(dir2)) != NULL) {
111 dent2 = readdir(dir2); 105 if (dent2->d_type != DT_LNK ||
112 if (!dent2) 106 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
113 break;
114 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
115 continue; 107 continue;
116 cpunode_map[cpu] = mem; 108 cpunode_map[cpu] = mem;
117 } 109 }
@@ -140,7 +132,7 @@ static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
140 if (data && data->ptr == ptr) { 132 if (data && data->ptr == ptr) {
141 data->hit++; 133 data->hit++;
142 data->bytes_req += bytes_req; 134 data->bytes_req += bytes_req;
143 data->bytes_alloc += bytes_req; 135 data->bytes_alloc += bytes_alloc;
144 } else { 136 } else {
145 data = malloc(sizeof(*data)); 137 data = malloc(sizeof(*data));
146 if (!data) 138 if (!data)
@@ -180,7 +172,7 @@ static void insert_caller_stat(unsigned long call_site,
180 if (data && data->call_site == call_site) { 172 if (data && data->call_site == call_site) {
181 data->hit++; 173 data->hit++;
182 data->bytes_req += bytes_req; 174 data->bytes_req += bytes_req;
183 data->bytes_alloc += bytes_req; 175 data->bytes_alloc += bytes_alloc;
184 } else { 176 } else {
185 data = malloc(sizeof(*data)); 177 data = malloc(sizeof(*data));
186 if (!data) 178 if (!data)
@@ -312,7 +304,7 @@ process_raw_event(event_t *raw_event __used, void *data,
312 } 304 }
313} 305}
314 306
315static int process_sample_event(event_t *event) 307static int process_sample_event(event_t *event, struct perf_session *session)
316{ 308{
317 struct sample_data data; 309 struct sample_data data;
318 struct thread *thread; 310 struct thread *thread;
@@ -322,15 +314,12 @@ static int process_sample_event(event_t *event)
322 data.cpu = -1; 314 data.cpu = -1;
323 data.period = 1; 315 data.period = 1;
324 316
325 event__parse_sample(event, sample_type, &data); 317 event__parse_sample(event, session->sample_type, &data);
326 318
327 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
328 event->header.misc, 320 data.pid, data.tid, data.ip, data.period);
329 data.pid, data.tid,
330 (void *)(long)data.ip,
331 (long long)data.period);
332 321
333 thread = threads__findnew(event->ip.pid); 322 thread = perf_session__findnew(session, event->ip.pid);
334 if (thread == NULL) { 323 if (thread == NULL) {
335 pr_debug("problem processing %d event, skipping it.\n", 324 pr_debug("problem processing %d event, skipping it.\n",
336 event->header.type); 325 event->header.type);
@@ -345,42 +334,11 @@ static int process_sample_event(event_t *event)
345 return 0; 334 return 0;
346} 335}
347 336
348static int sample_type_check(u64 type) 337static struct perf_event_ops event_ops = {
349{ 338 .sample = process_sample_event,
350 sample_type = type; 339 .comm = event__process_comm,
351
352 if (!(sample_type & PERF_SAMPLE_RAW)) {
353 fprintf(stderr,
354 "No trace sample to read. Did you call perf record "
355 "without -R?");
356 return -1;
357 }
358
359 return 0;
360}
361
362static struct perf_file_handler file_handler = {
363 .process_sample_event = process_sample_event,
364 .process_comm_event = event__process_comm,
365 .sample_type_check = sample_type_check,
366}; 340};
367 341
368static int read_events(void)
369{
370 int err;
371 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
372
373 if (session == NULL)
374 return -ENOMEM;
375
376 register_idle_thread();
377 register_perf_file_handler(&file_handler);
378
379 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
380 perf_session__delete(session);
381 return err;
382}
383
384static double fragmentation(unsigned long n_req, unsigned long n_alloc) 342static double fragmentation(unsigned long n_req, unsigned long n_alloc)
385{ 343{
386 if (n_alloc == 0) 344 if (n_alloc == 0)
@@ -389,13 +347,14 @@ static double fragmentation(unsigned long n_req, unsigned long n_alloc)
389 return 100.0 - (100.0 * n_req / n_alloc); 347 return 100.0 - (100.0 * n_req / n_alloc);
390} 348}
391 349
392static void __print_result(struct rb_root *root, int n_lines, int is_caller) 350static void __print_result(struct rb_root *root, struct perf_session *session,
351 int n_lines, int is_caller)
393{ 352{
394 struct rb_node *next; 353 struct rb_node *next;
395 354
396 printf("%.102s\n", graph_dotted_line); 355 printf("%.102s\n", graph_dotted_line);
397 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 356 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
398 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n"); 357 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
399 printf("%.102s\n", graph_dotted_line); 358 printf("%.102s\n", graph_dotted_line);
400 359
401 next = rb_first(root); 360 next = rb_first(root);
@@ -410,7 +369,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
410 if (is_caller) { 369 if (is_caller) {
411 addr = data->call_site; 370 addr = data->call_site;
412 if (!raw_ip) 371 if (!raw_ip)
413 sym = map_groups__find_function(kmaps, addr, NULL); 372 sym = map_groups__find_function(&session->kmaps, addr, NULL);
414 } else 373 } else
415 addr = data->ptr; 374 addr = data->ptr;
416 375
@@ -421,7 +380,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
421 snprintf(buf, sizeof(buf), "%#Lx", addr); 380 snprintf(buf, sizeof(buf), "%#Lx", addr);
422 printf(" %-34s |", buf); 381 printf(" %-34s |", buf);
423 382
424 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n", 383 printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
425 (unsigned long long)data->bytes_alloc, 384 (unsigned long long)data->bytes_alloc,
426 (unsigned long)data->bytes_alloc / data->hit, 385 (unsigned long)data->bytes_alloc / data->hit,
427 (unsigned long long)data->bytes_req, 386 (unsigned long long)data->bytes_req,
@@ -451,12 +410,12 @@ static void print_summary(void)
451 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); 410 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
452} 411}
453 412
454static void print_result(void) 413static void print_result(struct perf_session *session)
455{ 414{
456 if (caller_flag) 415 if (caller_flag)
457 __print_result(&root_caller_sorted, caller_lines, 1); 416 __print_result(&root_caller_sorted, session, caller_lines, 1);
458 if (alloc_flag) 417 if (alloc_flag)
459 __print_result(&root_alloc_sorted, alloc_lines, 0); 418 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
460 print_summary(); 419 print_summary();
461} 420}
462 421
@@ -524,12 +483,23 @@ static void sort_result(void)
524 483
525static int __cmd_kmem(void) 484static int __cmd_kmem(void)
526{ 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
527 setup_pager(); 494 setup_pager();
528 read_events(); 495 err = perf_session__process_events(session, &event_ops);
496 if (err != 0)
497 goto out_delete;
529 sort_result(); 498 sort_result();
530 print_result(); 499 print_result(session);
531 500out_delete:
532 return 0; 501 perf_session__delete(session);
502 return err;
533} 503}
534 504
535static const char * const kmem_usage[] = { 505static const char * const kmem_usage[] = {
@@ -778,13 +748,13 @@ static int __cmd_record(int argc, const char **argv)
778 748
779int cmd_kmem(int argc, const char **argv, const char *prefix __used) 749int cmd_kmem(int argc, const char **argv, const char *prefix __used)
780{ 750{
781 symbol__init(0);
782
783 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 751 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
784 752
785 if (!argc) 753 if (!argc)
786 usage_with_options(kmem_usage, kmem_options); 754 usage_with_options(kmem_usage, kmem_options);
787 755
756 symbol__init();
757
788 if (!strncmp(argv[0], "rec", 3)) { 758 if (!strncmp(argv[0], "rec", 3)) {
789 return __cmd_record(argc, argv); 759 return __cmd_record(argc, argv);
790 } else if (!strcmp(argv[0], "stat")) { 760 } else if (!strcmp(argv[0], "stat")) {
@@ -796,7 +766,8 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __used)
796 setup_sorting(&alloc_sort, default_sort_order); 766 setup_sorting(&alloc_sort, default_sort_order);
797 767
798 return __cmd_kmem(); 768 return __cmd_kmem();
799 } 769 } else
770 usage_with_options(kmem_usage, kmem_options);
800 771
801 return 0; 772 return 0;
802} 773}
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
index 5a47c1e11f77..152d6c9b1fa4 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -38,34 +38,30 @@
38#include "util/strlist.h" 38#include "util/strlist.h"
39#include "util/event.h" 39#include "util/event.h"
40#include "util/debug.h" 40#include "util/debug.h"
41#include "util/debugfs.h"
42#include "util/symbol.h"
43#include "util/thread.h"
41#include "util/parse-options.h" 44#include "util/parse-options.h"
42#include "util/parse-events.h" /* For debugfs_path */ 45#include "util/parse-events.h" /* For debugfs_path */
43#include "util/probe-finder.h" 46#include "util/probe-finder.h"
44#include "util/probe-event.h" 47#include "util/probe-event.h"
45 48
46/* Default vmlinux search paths */
47#define NR_SEARCH_PATH 4
48const char *default_search_path[NR_SEARCH_PATH] = {
49"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
50"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
51"/boot/vmlinux-debug-%s", /* Ubuntu */
52"./vmlinux", /* CWD */
53};
54
55#define MAX_PATH_LEN 256 49#define MAX_PATH_LEN 256
56#define MAX_PROBES 128
57 50
58/* Session management structure */ 51/* Session management structure */
59static struct { 52static struct {
60 char *vmlinux; 53 bool need_dwarf;
61 char *release; 54 bool list_events;
62 int need_dwarf; 55 bool force_add;
56 bool show_lines;
63 int nr_probe; 57 int nr_probe;
64 struct probe_point probes[MAX_PROBES]; 58 struct probe_point probes[MAX_PROBES];
65 struct strlist *dellist; 59 struct strlist *dellist;
60 struct map_groups kmap_groups;
61 struct map *kmaps[MAP__NR_TYPES];
62 struct line_range line_range;
66} session; 63} session;
67 64
68static bool listing;
69 65
70/* Parse an event definition. Note that any error must die. */ 66/* Parse an event definition. Note that any error must die. */
71static void parse_probe_event(const char *str) 67static void parse_probe_event(const char *str)
@@ -77,7 +73,7 @@ static void parse_probe_event(const char *str)
77 die("Too many probes (> %d) are specified.", MAX_PROBES); 73 die("Too many probes (> %d) are specified.", MAX_PROBES);
78 74
79 /* Parse perf-probe event into probe_point */ 75 /* Parse perf-probe event into probe_point */
80 session.need_dwarf = parse_perf_probe_event(str, pp); 76 parse_perf_probe_event(str, pp, &session.need_dwarf);
81 77
82 pr_debug("%d arguments\n", pp->nr_args); 78 pr_debug("%d arguments\n", pp->nr_args);
83} 79}
@@ -120,34 +116,37 @@ static int opt_del_probe_event(const struct option *opt __used,
120 return 0; 116 return 0;
121} 117}
122 118
123#ifndef NO_LIBDWARF 119/* Currently just checking function name from symbol map */
124static int open_default_vmlinux(void) 120static void evaluate_probe_point(struct probe_point *pp)
125{ 121{
126 struct utsname uts; 122 struct symbol *sym;
127 char fname[MAX_PATH_LEN]; 123 sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION],
128 int fd, ret, i; 124 pp->function, NULL);
129 125 if (!sym)
130 ret = uname(&uts); 126 die("Kernel symbol \'%s\' not found - probe not added.",
131 if (ret) { 127 pp->function);
132 pr_debug("uname() failed.\n"); 128}
133 return -errno; 129
134 } 130#ifndef NO_DWARF_SUPPORT
135 session.release = uts.release; 131static int open_vmlinux(void)
136 for (i = 0; i < NR_SEARCH_PATH; i++) { 132{
137 ret = snprintf(fname, MAX_PATH_LEN, 133 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
138 default_search_path[i], session.release); 134 pr_debug("Failed to load kernel map.\n");
139 if (ret >= MAX_PATH_LEN || ret < 0) { 135 return -EINVAL;
140 pr_debug("Filename(%d,%s) is too long.\n", i,
141 uts.release);
142 errno = E2BIG;
143 return -E2BIG;
144 }
145 pr_debug("try to open %s\n", fname);
146 fd = open(fname, O_RDONLY);
147 if (fd >= 0)
148 break;
149 } 136 }
150 return fd; 137 pr_debug("Try to open %s\n",
138 session.kmaps[MAP__FUNCTION]->dso->long_name);
139 return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
140}
141
142static int opt_show_lines(const struct option *opt __used,
143 const char *str, int unset __used)
144{
145 if (str)
146 parse_line_range_desc(str, &session.line_range);
147 INIT_LIST_HEAD(&session.line_range.line_list);
148 session.show_lines = true;
149 return 0;
151} 150}
152#endif 151#endif
153 152
@@ -156,70 +155,133 @@ static const char * const probe_usage[] = {
156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 155 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
157 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 156 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
158 "perf probe --list", 157 "perf probe --list",
158#ifndef NO_DWARF_SUPPORT
159 "perf probe --line 'LINEDESC'",
160#endif
159 NULL 161 NULL
160}; 162};
161 163
162static const struct option options[] = { 164static const struct option options[] = {
163 OPT_BOOLEAN('v', "verbose", &verbose, 165 OPT_BOOLEAN('v', "verbose", &verbose,
164 "be more verbose (show parsed arguments, etc)"), 166 "be more verbose (show parsed arguments, etc)"),
165#ifndef NO_LIBDWARF 167#ifndef NO_DWARF_SUPPORT
166 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 168 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
167 "vmlinux/module pathname"), 169 "file", "vmlinux pathname"),
168#endif 170#endif
169 OPT_BOOLEAN('l', "list", &listing, "list up current probe events"), 171 OPT_BOOLEAN('l', "list", &session.list_events,
172 "list up current probe events"),
170 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 173 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
171 opt_del_probe_event), 174 opt_del_probe_event),
172 OPT_CALLBACK('a', "add", NULL, 175 OPT_CALLBACK('a', "add", NULL,
173#ifdef NO_LIBDWARF 176#ifdef NO_DWARF_SUPPORT
174 "FUNC[+OFFS|%return] [ARG ...]", 177 "[EVENT=]FUNC[+OFF|%return] [ARG ...]",
175#else 178#else
176 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 179 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
180 " [ARG ...]",
177#endif 181#endif
178 "probe point definition, where\n" 182 "probe point definition, where\n"
179 "\t\tGRP:\tGroup name (optional)\n" 183 "\t\tGROUP:\tGroup name (optional)\n"
180 "\t\tNAME:\tEvent name\n" 184 "\t\tEVENT:\tEvent name\n"
181 "\t\tFUNC:\tFunction name\n" 185 "\t\tFUNC:\tFunction name\n"
182 "\t\tOFFS:\tOffset from function entry (in byte)\n" 186 "\t\tOFF:\tOffset from function entry (in byte)\n"
183 "\t\t%return:\tPut the probe at function return\n" 187 "\t\t%return:\tPut the probe at function return\n"
184#ifdef NO_LIBDWARF 188#ifdef NO_DWARF_SUPPORT
185 "\t\tARG:\tProbe argument (only \n" 189 "\t\tARG:\tProbe argument (only \n"
186#else 190#else
187 "\t\tSRC:\tSource code path\n" 191 "\t\tSRC:\tSource code path\n"
188 "\t\tRLN:\tRelative line number from function entry.\n" 192 "\t\tRL:\tRelative line number from function entry.\n"
189 "\t\tALN:\tAbsolute line number in file.\n" 193 "\t\tAL:\tAbsolute line number in file.\n"
194 "\t\tPT:\tLazy expression of line code.\n"
190 "\t\tARG:\tProbe argument (local variable name or\n" 195 "\t\tARG:\tProbe argument (local variable name or\n"
191#endif 196#endif
192 "\t\t\tkprobe-tracer argument format.)\n", 197 "\t\t\tkprobe-tracer argument format.)\n",
193 opt_add_probe_event), 198 opt_add_probe_event),
199 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
200 " with existing name"),
201#ifndef NO_DWARF_SUPPORT
202 OPT_CALLBACK('L', "line", NULL,
203 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
204 "Show source code lines.", opt_show_lines),
205#endif
194 OPT_END() 206 OPT_END()
195}; 207};
196 208
209/* Initialize symbol maps for vmlinux */
210static void init_vmlinux(void)
211{
212 symbol_conf.sort_by_name = true;
213 if (symbol_conf.vmlinux_name == NULL)
214 symbol_conf.try_vmlinux_path = true;
215 else
216 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
217 if (symbol__init() < 0)
218 die("Failed to init symbol map.");
219
220 map_groups__init(&session.kmap_groups);
221 if (map_groups__create_kernel_maps(&session.kmap_groups,
222 session.kmaps) < 0)
223 die("Failed to create kernel maps.");
224}
225
197int cmd_probe(int argc, const char **argv, const char *prefix __used) 226int cmd_probe(int argc, const char **argv, const char *prefix __used)
198{ 227{
199 int i, ret; 228 int i, ret;
200#ifndef NO_LIBDWARF 229#ifndef NO_DWARF_SUPPORT
201 int fd; 230 int fd;
202#endif 231#endif
203 struct probe_point *pp; 232 struct probe_point *pp;
204 233
205 argc = parse_options(argc, argv, options, probe_usage, 234 argc = parse_options(argc, argv, options, probe_usage,
206 PARSE_OPT_STOP_AT_NON_OPTION); 235 PARSE_OPT_STOP_AT_NON_OPTION);
207 if (argc > 0) 236 if (argc > 0) {
237 if (strcmp(argv[0], "-") == 0) {
238 pr_warning(" Error: '-' is not supported.\n");
239 usage_with_options(probe_usage, options);
240 }
208 parse_probe_event_argv(argc, argv); 241 parse_probe_event_argv(argc, argv);
242 }
209 243
210 if ((session.nr_probe == 0 && !session.dellist && !listing)) 244 if ((!session.nr_probe && !session.dellist && !session.list_events &&
245 !session.show_lines))
211 usage_with_options(probe_usage, options); 246 usage_with_options(probe_usage, options);
212 247
213 if (listing) { 248 if (debugfs_valid_mountpoint(debugfs_path) < 0)
249 die("Failed to find debugfs path.");
250
251 if (session.list_events) {
214 if (session.nr_probe != 0 || session.dellist) { 252 if (session.nr_probe != 0 || session.dellist) {
215 pr_warning(" Error: Don't use --list with" 253 pr_warning(" Error: Don't use --list with"
216 " --add/--del.\n"); 254 " --add/--del.\n");
217 usage_with_options(probe_usage, options); 255 usage_with_options(probe_usage, options);
218 } 256 }
257 if (session.show_lines) {
258 pr_warning(" Error: Don't use --list with --line.\n");
259 usage_with_options(probe_usage, options);
260 }
219 show_perf_probe_events(); 261 show_perf_probe_events();
220 return 0; 262 return 0;
221 } 263 }
222 264
265#ifndef NO_DWARF_SUPPORT
266 if (session.show_lines) {
267 if (session.nr_probe != 0 || session.dellist) {
268 pr_warning(" Error: Don't use --line with"
269 " --add/--del.\n");
270 usage_with_options(probe_usage, options);
271 }
272 init_vmlinux();
273 fd = open_vmlinux();
274 if (fd < 0)
275 die("Could not open debuginfo file.");
276 ret = find_line_range(fd, &session.line_range);
277 if (ret <= 0)
278 die("Source line is not found.\n");
279 close(fd);
280 show_line_range(&session.line_range);
281 return 0;
282 }
283#endif
284
223 if (session.dellist) { 285 if (session.dellist) {
224 del_trace_kprobe_events(session.dellist); 286 del_trace_kprobe_events(session.dellist);
225 strlist__delete(session.dellist); 287 strlist__delete(session.dellist);
@@ -227,17 +289,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
227 return 0; 289 return 0;
228 } 290 }
229 291
292 /* Add probes */
293 init_vmlinux();
294
230 if (session.need_dwarf) 295 if (session.need_dwarf)
231#ifdef NO_LIBDWARF 296#ifdef NO_DWARF_SUPPORT
232 die("Debuginfo-analysis is not supported"); 297 die("Debuginfo-analysis is not supported");
233#else /* !NO_LIBDWARF */ 298#else /* !NO_DWARF_SUPPORT */
234 pr_debug("Some probes require debuginfo.\n"); 299 pr_debug("Some probes require debuginfo.\n");
235 300
236 if (session.vmlinux) { 301 fd = open_vmlinux();
237 pr_debug("Try to open %s.", session.vmlinux);
238 fd = open(session.vmlinux, O_RDONLY);
239 } else
240 fd = open_default_vmlinux();
241 if (fd < 0) { 302 if (fd < 0) {
242 if (session.need_dwarf) 303 if (session.need_dwarf)
243 die("Could not open debuginfo file."); 304 die("Could not open debuginfo file.");
@@ -254,21 +315,28 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
254 continue; 315 continue;
255 316
256 lseek(fd, SEEK_SET, 0); 317 lseek(fd, SEEK_SET, 0);
257 ret = find_probepoint(fd, pp); 318 ret = find_probe_point(fd, pp);
258 if (ret < 0) { 319 if (ret > 0)
259 if (session.need_dwarf) 320 continue;
260 die("Could not analyze debuginfo."); 321 if (ret == 0) { /* No error but failed to find probe point. */
261 322 synthesize_perf_probe_point(pp);
262 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n"); 323 die("Probe point '%s' not found. - probe not added.",
263 break; 324 pp->probes[0]);
264 } 325 }
265 if (ret == 0) /* No error but failed to find probe point. */ 326 /* Error path */
266 die("No probe point found."); 327 if (session.need_dwarf) {
328 if (ret == -ENOENT)
329 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
330 die("Could not analyze debuginfo.");
331 }
332 pr_debug("An error occurred in debuginfo analysis."
333 " Try to use symbols.\n");
334 break;
267 } 335 }
268 close(fd); 336 close(fd);
269 337
270end_dwarf: 338end_dwarf:
271#endif /* !NO_LIBDWARF */ 339#endif /* !NO_DWARF_SUPPORT */
272 340
273 /* Synthesize probes without dwarf */ 341 /* Synthesize probes without dwarf */
274 for (i = 0; i < session.nr_probe; i++) { 342 for (i = 0; i < session.nr_probe; i++) {
@@ -276,6 +344,7 @@ end_dwarf:
276 if (pp->found) /* This probe is already found. */ 344 if (pp->found) /* This probe is already found. */
277 continue; 345 continue;
278 346
347 evaluate_probe_point(pp);
279 ret = synthesize_trace_kprobe_event(pp); 348 ret = synthesize_trace_kprobe_event(pp);
280 if (ret == -E2BIG) 349 if (ret == -E2BIG)
281 die("probe point definition becomes too long."); 350 die("probe point definition becomes too long.");
@@ -284,7 +353,8 @@ end_dwarf:
284 } 353 }
285 354
286 /* Settng up probe points */ 355 /* Settng up probe points */
287 add_trace_kprobe_events(session.probes, session.nr_probe); 356 add_trace_kprobe_events(session.probes, session.nr_probe,
357 session.force_add);
288 return 0; 358 return 0;
289} 359}
290 360
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4decbd14eaed..3b8b6387c47c 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"
@@ -19,6 +22,7 @@
19#include "util/debug.h" 22#include "util/debug.h"
20#include "util/session.h" 23#include "util/session.h"
21#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/cpumap.h"
22 26
23#include <unistd.h> 27#include <unistd.h>
24#include <sched.h> 28#include <sched.h>
@@ -62,6 +66,7 @@ static int nr_poll = 0;
62static int nr_cpu = 0; 66static int nr_cpu = 0;
63 67
64static int file_new = 1; 68static int file_new = 1;
69static off_t post_processing_offset;
65 70
66static struct perf_session *session; 71static struct perf_session *session;
67 72
@@ -111,21 +116,10 @@ static void write_output(void *buf, size_t size)
111 } 116 }
112} 117}
113 118
114static void write_event(event_t *buf, size_t size) 119static int process_synthesized_event(event_t *event,
120 struct perf_session *self __used)
115{ 121{
116 /* 122 write_output(event, event->header.size);
117 * Add it to the list of DSOs, so that when we finish this
118 * record session we can pick the available build-ids.
119 */
120 if (buf->header.type == PERF_RECORD_MMAP)
121 dsos__findnew(buf->mmap.filename);
122
123 write_output(buf, size);
124}
125
126static int process_synthesized_event(event_t *event)
127{
128 write_event(event, event->header.size);
129 return 0; 123 return 0;
130} 124}
131 125
@@ -177,14 +171,14 @@ static void mmap_read(struct mmap_data *md)
177 size = md->mask + 1 - (old & md->mask); 171 size = md->mask + 1 - (old & md->mask);
178 old += size; 172 old += size;
179 173
180 write_event(buf, size); 174 write_output(buf, size);
181 } 175 }
182 176
183 buf = &data[old & md->mask]; 177 buf = &data[old & md->mask];
184 size = head - old; 178 size = head - old;
185 old += size; 179 old += size;
186 180
187 write_event(buf, size); 181 write_output(buf, size);
188 182
189 md->prev = old; 183 md->prev = old;
190 mmap_write_tail(md, old); 184 mmap_write_tail(md, old);
@@ -251,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid)
251 245
252 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 246 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
253 247
248 if (nr_counters > 1)
249 attr->sample_type |= PERF_SAMPLE_ID;
250
254 if (freq) { 251 if (freq) {
255 attr->sample_type |= PERF_SAMPLE_PERIOD; 252 attr->sample_type |= PERF_SAMPLE_PERIOD;
256 attr->freq = 1; 253 attr->freq = 1;
@@ -277,7 +274,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
277 274
278 attr->mmap = track; 275 attr->mmap = track;
279 attr->comm = track; 276 attr->comm = track;
280 attr->inherit = (cpu < 0) && inherit; 277 attr->inherit = inherit;
281 attr->disabled = 1; 278 attr->disabled = 1;
282 279
283try_again: 280try_again:
@@ -394,10 +391,24 @@ static void open_counters(int cpu, pid_t pid)
394 nr_cpu++; 391 nr_cpu++;
395} 392}
396 393
394static int process_buildids(void)
395{
396 u64 size = lseek(output, 0, SEEK_CUR);
397
398 if (size == 0)
399 return 0;
400
401 session->fd = output;
402 return __perf_session__process_events(session, post_processing_offset,
403 size - post_processing_offset,
404 size, &build_id__mark_dso_hit_ops);
405}
406
397static void atexit_header(void) 407static void atexit_header(void)
398{ 408{
399 session->header.data_size += bytes_written; 409 session->header.data_size += bytes_written;
400 410
411 process_buildids();
401 perf_header__write(&session->header, output, true); 412 perf_header__write(&session->header, output, true);
402} 413}
403 414
@@ -409,21 +420,35 @@ static int __cmd_record(int argc, const char **argv)
409 int flags; 420 int flags;
410 int err; 421 int err;
411 unsigned long waking = 0; 422 unsigned long waking = 0;
423 int child_ready_pipe[2], go_pipe[2];
424 const bool forks = target_pid == -1 && argc > 0;
425 char buf;
412 426
413 page_size = sysconf(_SC_PAGE_SIZE); 427 page_size = sysconf(_SC_PAGE_SIZE);
414 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
415 assert(nr_cpus <= MAX_NR_CPUS);
416 assert(nr_cpus >= 0);
417 428
418 atexit(sig_atexit); 429 atexit(sig_atexit);
419 signal(SIGCHLD, sig_handler); 430 signal(SIGCHLD, sig_handler);
420 signal(SIGINT, sig_handler); 431 signal(SIGINT, sig_handler);
421 432
433 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
434 perror("failed to create pipes");
435 exit(-1);
436 }
437
422 if (!stat(output_name, &st) && st.st_size) { 438 if (!stat(output_name, &st) && st.st_size) {
423 if (!force && !append_file) { 439 if (!force) {
424 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 440 if (!append_file) {
425 output_name); 441 pr_err("Error, output file %s exists, use -A "
426 exit(-1); 442 "to append or -f to overwrite.\n",
443 output_name);
444 exit(-1);
445 }
446 } else {
447 char oldname[PATH_MAX];
448 snprintf(oldname, sizeof(oldname), "%s.old",
449 output_name);
450 unlink(oldname);
451 rename(output_name, oldname);
427 } 452 }
428 } else { 453 } else {
429 append_file = 0; 454 append_file = 0;
@@ -466,19 +491,66 @@ static int __cmd_record(int argc, const char **argv)
466 491
467 atexit(atexit_header); 492 atexit(atexit_header);
468 493
469 if (!system_wide) { 494 if (forks) {
470 pid = target_pid; 495 pid = fork();
471 if (pid == -1) 496 if (pid < 0) {
472 pid = getpid(); 497 perror("failed to fork");
498 exit(-1);
499 }
473 500
474 open_counters(profile_cpu, pid); 501 if (!pid) {
475 } else { 502 close(child_ready_pipe[0]);
476 if (profile_cpu != -1) { 503 close(go_pipe[1]);
477 open_counters(profile_cpu, target_pid); 504 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
478 } else { 505
479 for (i = 0; i < nr_cpus; i++) 506 /*
480 open_counters(i, target_pid); 507 * Do a dummy execvp to get the PLT entry resolved,
508 * so we avoid the resolver overhead on the real
509 * execvp call.
510 */
511 execvp("", (char **)argv);
512
513 /*
514 * Tell the parent we're ready to go
515 */
516 close(child_ready_pipe[1]);
517
518 /*
519 * Wait until the parent tells us to go.
520 */
521 if (read(go_pipe[0], &buf, 1) == -1)
522 perror("unable to read pipe");
523
524 execvp(argv[0], (char **)argv);
525
526 perror(argv[0]);
527 exit(-1);
528 }
529
530 child_pid = pid;
531
532 if (!system_wide)
533 target_pid = pid;
534
535 close(child_ready_pipe[1]);
536 close(go_pipe[0]);
537 /*
538 * wait for child to settle
539 */
540 if (read(child_ready_pipe[0], &buf, 1) == -1) {
541 perror("unable to read pipe");
542 exit(-1);
481 } 543 }
544 close(child_ready_pipe[0]);
545 }
546
547
548 if ((!system_wide && !inherit) || profile_cpu != -1) {
549 open_counters(profile_cpu, target_pid);
550 } else {
551 nr_cpus = read_cpu_map();
552 for (i = 0; i < nr_cpus; i++)
553 open_counters(cpumap[i], target_pid);
482 } 554 }
483 555
484 if (file_new) { 556 if (file_new) {
@@ -487,35 +559,27 @@ static int __cmd_record(int argc, const char **argv)
487 return err; 559 return err;
488 } 560 }
489 561
490 if (!system_wide) 562 post_processing_offset = lseek(output, 0, SEEK_CUR);
491 event__synthesize_thread(pid, process_synthesized_event);
492 else
493 event__synthesize_threads(process_synthesized_event);
494 563
495 if (target_pid == -1 && argc) { 564 err = event__synthesize_kernel_mmap(process_synthesized_event,
496 pid = fork(); 565 session, "_text");
497 if (pid < 0) 566 if (err < 0) {
498 die("failed to fork"); 567 pr_err("Couldn't record kernel reference relocation symbol.\n");
499 568 return err;
500 if (!pid) { 569 }
501 if (execvp(argv[0], (char **)argv)) {
502 perror(argv[0]);
503 exit(-1);
504 }
505 } else {
506 /*
507 * Wait a bit for the execv'ed child to appear
508 * and be updated in /proc
509 * FIXME: Do you know a less heuristical solution?
510 */
511 usleep(1000);
512 event__synthesize_thread(pid,
513 process_synthesized_event);
514 }
515 570
516 child_pid = pid; 571 err = event__synthesize_modules(process_synthesized_event, session);
572 if (err < 0) {
573 pr_err("Couldn't record kernel reference relocation symbol.\n");
574 return err;
517 } 575 }
518 576
577 if (!system_wide && profile_cpu == -1)
578 event__synthesize_thread(target_pid, process_synthesized_event,
579 session);
580 else
581 event__synthesize_threads(process_synthesized_event, session);
582
519 if (realtime_prio) { 583 if (realtime_prio) {
520 struct sched_param param; 584 struct sched_param param;
521 585
@@ -526,6 +590,12 @@ static int __cmd_record(int argc, const char **argv)
526 } 590 }
527 } 591 }
528 592
593 /*
594 * Let the child rip
595 */
596 if (forks)
597 close(go_pipe[1]);
598
529 for (;;) { 599 for (;;) {
530 int hits = samples; 600 int hits = samples;
531 601
@@ -620,13 +690,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
620{ 690{
621 int counter; 691 int counter;
622 692
623 symbol__init(0);
624
625 argc = parse_options(argc, argv, options, record_usage, 693 argc = parse_options(argc, argv, options, record_usage,
626 PARSE_OPT_STOP_AT_NON_OPTION); 694 PARSE_OPT_STOP_AT_NON_OPTION);
627 if (!argc && target_pid == -1 && !system_wide) 695 if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1)
628 usage_with_options(record_usage, options); 696 usage_with_options(record_usage, options);
629 697
698 symbol__init();
699
630 if (!nr_counters) { 700 if (!nr_counters) {
631 nr_counters = 1; 701 nr_counters = 1;
632 attrs[0].type = PERF_TYPE_HARDWARE; 702 attrs[0].type = PERF_TYPE_HARDWARE;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index e2ec49a9b731..f815de25d0fc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,21 +27,15 @@
27#include "util/parse-options.h" 27#include "util/parse-options.h"
28#include "util/parse-events.h" 28#include "util/parse-events.h"
29 29
30#include "util/data_map.h"
31#include "util/thread.h" 30#include "util/thread.h"
32#include "util/sort.h" 31#include "util/sort.h"
33#include "util/hist.h" 32#include "util/hist.h"
34 33
35static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
36 35
37static char *dso_list_str, *comm_list_str, *sym_list_str,
38 *col_width_list_str;
39static struct strlist *dso_list, *comm_list, *sym_list;
40
41static int force; 36static int force;
42 37static bool hide_unresolved;
43static int full_paths; 38static bool dont_use_callchains;
44static int show_nr_samples;
45 39
46static int show_threads; 40static int show_threads;
47static struct perf_read_values show_threads_values; 41static struct perf_read_values show_threads_values;
@@ -49,548 +43,79 @@ static struct perf_read_values show_threads_values;
49static char default_pretty_printing_style[] = "normal"; 43static char default_pretty_printing_style[] = "normal";
50static char *pretty_printing_style = default_pretty_printing_style; 44static char *pretty_printing_style = default_pretty_printing_style;
51 45
52static int exclude_other = 1;
53
54static char callchain_default_opt[] = "fractal,0.5"; 46static char callchain_default_opt[] = "fractal,0.5";
55 47
56static struct perf_session *session; 48static struct event_stat_id *get_stats(struct perf_session *self,
57 49 u64 event_stream, u32 type, u64 config)
58static u64 sample_type;
59
60struct symbol_conf symbol_conf;
61
62
63static size_t
64callchain__fprintf_left_margin(FILE *fp, int left_margin)
65{
66 int i;
67 int ret;
68
69 ret = fprintf(fp, " ");
70
71 for (i = 0; i < left_margin; i++)
72 ret += fprintf(fp, " ");
73
74 return ret;
75}
76
77static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
78 int left_margin)
79{
80 int i;
81 size_t ret = 0;
82
83 ret += callchain__fprintf_left_margin(fp, left_margin);
84
85 for (i = 0; i < depth; i++)
86 if (depth_mask & (1 << i))
87 ret += fprintf(fp, "| ");
88 else
89 ret += fprintf(fp, " ");
90
91 ret += fprintf(fp, "\n");
92
93 return ret;
94}
95static size_t
96ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
97 int depth_mask, int count, u64 total_samples,
98 int hits, int left_margin)
99{
100 int i;
101 size_t ret = 0;
102
103 ret += callchain__fprintf_left_margin(fp, left_margin);
104 for (i = 0; i < depth; i++) {
105 if (depth_mask & (1 << i))
106 ret += fprintf(fp, "|");
107 else
108 ret += fprintf(fp, " ");
109 if (!count && i == depth - 1) {
110 double percent;
111
112 percent = hits * 100.0 / total_samples;
113 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
114 } else
115 ret += fprintf(fp, "%s", " ");
116 }
117 if (chain->sym)
118 ret += fprintf(fp, "%s\n", chain->sym->name);
119 else
120 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
121
122 return ret;
123}
124
125static struct symbol *rem_sq_bracket;
126static struct callchain_list rem_hits;
127
128static void init_rem_hits(void)
129{
130 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
131 if (!rem_sq_bracket) {
132 fprintf(stderr, "Not enough memory to display remaining hits\n");
133 return;
134 }
135
136 strcpy(rem_sq_bracket->name, "[...]");
137 rem_hits.sym = rem_sq_bracket;
138}
139
140static size_t
141__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
142 u64 total_samples, int depth, int depth_mask,
143 int left_margin)
144{ 50{
145 struct rb_node *node, *next; 51 struct rb_node **p = &self->stats_by_id.rb_node;
146 struct callchain_node *child; 52 struct rb_node *parent = NULL;
147 struct callchain_list *chain; 53 struct event_stat_id *iter, *new;
148 int new_depth_mask = depth_mask;
149 u64 new_total;
150 u64 remaining;
151 size_t ret = 0;
152 int i;
153
154 if (callchain_param.mode == CHAIN_GRAPH_REL)
155 new_total = self->children_hit;
156 else
157 new_total = total_samples;
158
159 remaining = new_total;
160
161 node = rb_first(&self->rb_root);
162 while (node) {
163 u64 cumul;
164
165 child = rb_entry(node, struct callchain_node, rb_node);
166 cumul = cumul_hits(child);
167 remaining -= cumul;
168
169 /*
170 * The depth mask manages the output of pipes that show
171 * the depth. We don't want to keep the pipes of the current
172 * level for the last child of this depth.
173 * Except if we have remaining filtered hits. They will
174 * supersede the last child
175 */
176 next = rb_next(node);
177 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
178 new_depth_mask &= ~(1 << (depth - 1));
179
180 /*
181 * But we keep the older depth mask for the line seperator
182 * to keep the level link until we reach the last child
183 */
184 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
185 left_margin);
186 i = 0;
187 list_for_each_entry(chain, &child->val, list) {
188 if (chain->ip >= PERF_CONTEXT_MAX)
189 continue;
190 ret += ipchain__fprintf_graph(fp, chain, depth,
191 new_depth_mask, i++,
192 new_total,
193 cumul,
194 left_margin);
195 }
196 ret += __callchain__fprintf_graph(fp, child, new_total,
197 depth + 1,
198 new_depth_mask | (1 << depth),
199 left_margin);
200 node = next;
201 }
202
203 if (callchain_param.mode == CHAIN_GRAPH_REL &&
204 remaining && remaining != new_total) {
205
206 if (!rem_sq_bracket)
207 return ret;
208
209 new_depth_mask &= ~(1 << (depth - 1));
210
211 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
212 new_depth_mask, 0, new_total,
213 remaining, left_margin);
214 }
215 54
216 return ret; 55 while (*p != NULL) {
217} 56 parent = *p;
57 iter = rb_entry(parent, struct event_stat_id, rb_node);
58 if (iter->config == config)
59 return iter;
218 60
219 61
220static size_t 62 if (config > iter->config)
221callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 63 p = &(*p)->rb_right;
222 u64 total_samples, int left_margin)
223{
224 struct callchain_list *chain;
225 bool printed = false;
226 int i = 0;
227 int ret = 0;
228
229 list_for_each_entry(chain, &self->val, list) {
230 if (chain->ip >= PERF_CONTEXT_MAX)
231 continue;
232
233 if (!i++ && sort__first_dimension == SORT_SYM)
234 continue;
235
236 if (!printed) {
237 ret += callchain__fprintf_left_margin(fp, left_margin);
238 ret += fprintf(fp, "|\n");
239 ret += callchain__fprintf_left_margin(fp, left_margin);
240 ret += fprintf(fp, "---");
241
242 left_margin += 3;
243 printed = true;
244 } else
245 ret += callchain__fprintf_left_margin(fp, left_margin);
246
247 if (chain->sym)
248 ret += fprintf(fp, " %s\n", chain->sym->name);
249 else 64 else
250 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 65 p = &(*p)->rb_left;
251 } 66 }
252 67
253 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 68 new = malloc(sizeof(struct event_stat_id));
254 69 if (new == NULL)
255 return ret; 70 return NULL;
71 memset(new, 0, sizeof(struct event_stat_id));
72 new->event_stream = event_stream;
73 new->config = config;
74 new->type = type;
75 rb_link_node(&new->rb_node, parent, p);
76 rb_insert_color(&new->rb_node, &self->stats_by_id);
77 return new;
256} 78}
257 79
258static size_t 80static int perf_session__add_hist_entry(struct perf_session *self,
259callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 81 struct addr_location *al,
260 u64 total_samples) 82 struct sample_data *data)
261{
262 struct callchain_list *chain;
263 size_t ret = 0;
264
265 if (!self)
266 return 0;
267
268 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
269
270
271 list_for_each_entry(chain, &self->val, list) {
272 if (chain->ip >= PERF_CONTEXT_MAX)
273 continue;
274 if (chain->sym)
275 ret += fprintf(fp, " %s\n", chain->sym->name);
276 else
277 ret += fprintf(fp, " %p\n",
278 (void *)(long)chain->ip);
279 }
280
281 return ret;
282}
283
284static size_t
285hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
286 u64 total_samples, int left_margin)
287{
288 struct rb_node *rb_node;
289 struct callchain_node *chain;
290 size_t ret = 0;
291
292 rb_node = rb_first(&self->sorted_chain);
293 while (rb_node) {
294 double percent;
295
296 chain = rb_entry(rb_node, struct callchain_node, rb_node);
297 percent = chain->hit * 100.0 / total_samples;
298 switch (callchain_param.mode) {
299 case CHAIN_FLAT:
300 ret += percent_color_fprintf(fp, " %6.2f%%\n",
301 percent);
302 ret += callchain__fprintf_flat(fp, chain, total_samples);
303 break;
304 case CHAIN_GRAPH_ABS: /* Falldown */
305 case CHAIN_GRAPH_REL:
306 ret += callchain__fprintf_graph(fp, chain, total_samples,
307 left_margin);
308 case CHAIN_NONE:
309 default:
310 break;
311 }
312 ret += fprintf(fp, "\n");
313 rb_node = rb_next(rb_node);
314 }
315
316 return ret;
317}
318
319static size_t
320hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
321{
322 struct sort_entry *se;
323 size_t ret;
324
325 if (exclude_other && !self->parent)
326 return 0;
327
328 if (total_samples)
329 ret = percent_color_fprintf(fp,
330 field_sep ? "%.2f" : " %6.2f%%",
331 (self->count * 100.0) / total_samples);
332 else
333 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
334
335 if (show_nr_samples) {
336 if (field_sep)
337 fprintf(fp, "%c%lld", *field_sep, self->count);
338 else
339 fprintf(fp, "%11lld", self->count);
340 }
341
342 list_for_each_entry(se, &hist_entry__sort_list, list) {
343 if (se->elide)
344 continue;
345
346 fprintf(fp, "%s", field_sep ?: " ");
347 ret += se->print(fp, self, se->width ? *se->width : 0);
348 }
349
350 ret += fprintf(fp, "\n");
351
352 if (callchain) {
353 int left_margin = 0;
354
355 if (sort__first_dimension == SORT_COMM) {
356 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
357 list);
358 left_margin = se->width ? *se->width : 0;
359 left_margin -= thread__comm_len(self->thread);
360 }
361
362 hist_entry_callchain__fprintf(fp, self, total_samples,
363 left_margin);
364 }
365
366 return ret;
367}
368
369/*
370 *
371 */
372
373static void dso__calc_col_width(struct dso *self)
374{
375 if (!col_width_list_str && !field_sep &&
376 (!dso_list || strlist__has_entry(dso_list, self->name))) {
377 unsigned int slen = strlen(self->name);
378 if (slen > dsos__col_width)
379 dsos__col_width = slen;
380 }
381
382 self->slen_calculated = 1;
383}
384
385static void thread__comm_adjust(struct thread *self)
386{
387 char *comm = self->comm;
388
389 if (!col_width_list_str && !field_sep &&
390 (!comm_list || strlist__has_entry(comm_list, comm))) {
391 unsigned int slen = strlen(comm);
392
393 if (slen > comms__col_width) {
394 comms__col_width = slen;
395 threads__col_width = slen + 6;
396 }
397 }
398}
399
400static int thread__set_comm_adjust(struct thread *self, const char *comm)
401{
402 int ret = thread__set_comm(self, comm);
403
404 if (ret)
405 return ret;
406
407 thread__comm_adjust(self);
408
409 return 0;
410}
411
412static int call__match(struct symbol *sym)
413{
414 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
415 return 1;
416
417 return 0;
418}
419
420static struct symbol **resolve_callchain(struct thread *thread,
421 struct ip_callchain *chain,
422 struct symbol **parent)
423{
424 u8 cpumode = PERF_RECORD_MISC_USER;
425 struct symbol **syms = NULL;
426 unsigned int i;
427
428 if (callchain) {
429 syms = calloc(chain->nr, sizeof(*syms));
430 if (!syms) {
431 fprintf(stderr, "Can't allocate memory for symbols\n");
432 exit(-1);
433 }
434 }
435
436 for (i = 0; i < chain->nr; i++) {
437 u64 ip = chain->ips[i];
438 struct addr_location al;
439
440 if (ip >= PERF_CONTEXT_MAX) {
441 switch (ip) {
442 case PERF_CONTEXT_HV:
443 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
444 case PERF_CONTEXT_KERNEL:
445 cpumode = PERF_RECORD_MISC_KERNEL; break;
446 case PERF_CONTEXT_USER:
447 cpumode = PERF_RECORD_MISC_USER; break;
448 default:
449 break;
450 }
451 continue;
452 }
453
454 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
455 ip, &al, NULL);
456 if (al.sym != NULL) {
457 if (sort__has_parent && !*parent &&
458 call__match(al.sym))
459 *parent = al.sym;
460 if (!callchain)
461 break;
462 syms[i] = al.sym;
463 }
464 }
465
466 return syms;
467}
468
469/*
470 * collect histogram counts
471 */
472
473static int hist_entry__add(struct addr_location *al,
474 struct ip_callchain *chain, u64 count)
475{ 83{
476 struct symbol **syms = NULL, *parent = NULL; 84 struct symbol **syms = NULL, *parent = NULL;
477 bool hit; 85 bool hit;
478 struct hist_entry *he; 86 struct hist_entry *he;
87 struct event_stat_id *stats;
88 struct perf_event_attr *attr;
479 89
480 if ((sort__has_parent || callchain) && chain) 90 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain)
481 syms = resolve_callchain(al->thread, chain, &parent); 91 syms = perf_session__resolve_callchain(self, al->thread,
92 data->callchain, &parent);
482 93
483 he = __hist_entry__add(al, parent, count, &hit); 94 attr = perf_header__find_attr(data->id, &self->header);
95 if (attr)
96 stats = get_stats(self, data->id, attr->type, attr->config);
97 else
98 stats = get_stats(self, data->id, 0, 0);
99 if (stats == NULL)
100 return -ENOMEM;
101 he = __perf_session__add_hist_entry(&stats->hists, al, parent,
102 data->period, &hit);
484 if (he == NULL) 103 if (he == NULL)
485 return -ENOMEM; 104 return -ENOMEM;
486 105
487 if (hit) 106 if (hit)
488 he->count += count; 107 he->count += data->period;
489 108
490 if (callchain) { 109 if (symbol_conf.use_callchain) {
491 if (!hit) 110 if (!hit)
492 callchain_init(&he->callchain); 111 callchain_init(&he->callchain);
493 append_chain(&he->callchain, chain, syms); 112 append_chain(&he->callchain, data->callchain, syms);
494 free(syms); 113 free(syms);
495 } 114 }
496 115
497 return 0; 116 return 0;
498} 117}
499 118
500static size_t output__fprintf(FILE *fp, u64 total_samples)
501{
502 struct hist_entry *pos;
503 struct sort_entry *se;
504 struct rb_node *nd;
505 size_t ret = 0;
506 unsigned int width;
507 char *col_width = col_width_list_str;
508 int raw_printing_style;
509
510 raw_printing_style = !strcmp(pretty_printing_style, "raw");
511
512 init_rem_hits();
513
514 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
515 fprintf(fp, "#\n");
516
517 fprintf(fp, "# Overhead");
518 if (show_nr_samples) {
519 if (field_sep)
520 fprintf(fp, "%cSamples", *field_sep);
521 else
522 fputs(" Samples ", fp);
523 }
524 list_for_each_entry(se, &hist_entry__sort_list, list) {
525 if (se->elide)
526 continue;
527 if (field_sep) {
528 fprintf(fp, "%c%s", *field_sep, se->header);
529 continue;
530 }
531 width = strlen(se->header);
532 if (se->width) {
533 if (col_width_list_str) {
534 if (col_width) {
535 *se->width = atoi(col_width);
536 col_width = strchr(col_width, ',');
537 if (col_width)
538 ++col_width;
539 }
540 }
541 width = *se->width = max(*se->width, width);
542 }
543 fprintf(fp, " %*s", width, se->header);
544 }
545 fprintf(fp, "\n");
546
547 if (field_sep)
548 goto print_entries;
549
550 fprintf(fp, "# ........");
551 if (show_nr_samples)
552 fprintf(fp, " ..........");
553 list_for_each_entry(se, &hist_entry__sort_list, list) {
554 unsigned int i;
555
556 if (se->elide)
557 continue;
558
559 fprintf(fp, " ");
560 if (se->width)
561 width = *se->width;
562 else
563 width = strlen(se->header);
564 for (i = 0; i < width; i++)
565 fprintf(fp, ".");
566 }
567 fprintf(fp, "\n");
568
569 fprintf(fp, "#\n");
570
571print_entries:
572 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
573 pos = rb_entry(nd, struct hist_entry, rb_node);
574 ret += hist_entry__fprintf(fp, pos, total_samples);
575 }
576
577 if (sort_order == default_sort_order &&
578 parent_pattern == default_parent_pattern) {
579 fprintf(fp, "#\n");
580 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
581 fprintf(fp, "#\n");
582 }
583 fprintf(fp, "\n");
584
585 free(rem_sq_bracket);
586
587 if (show_threads)
588 perf_read_values_display(fp, &show_threads_values,
589 raw_printing_style);
590
591 return ret;
592}
593
594static int validate_chain(struct ip_callchain *chain, event_t *event) 119static int validate_chain(struct ip_callchain *chain, event_t *event)
595{ 120{
596 unsigned int chain_size; 121 unsigned int chain_size;
@@ -604,25 +129,37 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
604 return 0; 129 return 0;
605} 130}
606 131
607static int process_sample_event(event_t *event) 132static int add_event_total(struct perf_session *session,
133 struct sample_data *data,
134 struct perf_event_attr *attr)
608{ 135{
609 struct sample_data data; 136 struct event_stat_id *stats;
610 int cpumode; 137
611 struct addr_location al; 138 if (attr)
612 struct thread *thread; 139 stats = get_stats(session, data->id, attr->type, attr->config);
140 else
141 stats = get_stats(session, data->id, 0, 0);
142
143 if (!stats)
144 return -ENOMEM;
145
146 stats->stats.total += data->period;
147 session->events_stats.total += data->period;
148 return 0;
149}
613 150
614 memset(&data, 0, sizeof(data)); 151static int process_sample_event(event_t *event, struct perf_session *session)
615 data.period = 1; 152{
153 struct sample_data data = { .period = 1, };
154 struct addr_location al;
155 struct perf_event_attr *attr;
616 156
617 event__parse_sample(event, sample_type, &data); 157 event__parse_sample(event, session->sample_type, &data);
618 158
619 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 159 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
620 event->header.misc, 160 data.pid, data.tid, data.ip, data.period);
621 data.pid, data.tid,
622 (void *)(long)data.ip,
623 (long long)data.period);
624 161
625 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 162 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
626 unsigned int i; 163 unsigned int i;
627 164
628 dump_printf("... chain: nr:%Lu\n", data.callchain->nr); 165 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
@@ -640,65 +177,31 @@ static int process_sample_event(event_t *event)
640 } 177 }
641 } 178 }
642 179
643 thread = threads__findnew(data.pid); 180 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
644 if (thread == NULL) { 181 fprintf(stderr, "problem processing %d event, skipping it.\n",
645 pr_debug("problem processing %d event, skipping it.\n",
646 event->header.type); 182 event->header.type);
647 return -1; 183 return -1;
648 } 184 }
649 185
650 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 186 if (al.filtered || (hide_unresolved && al.sym == NULL))
651
652 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
653 return 0; 187 return 0;
654 188
655 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 189 if (perf_session__add_hist_entry(session, &al, &data)) {
656
657 thread__find_addr_location(thread, cpumode,
658 MAP__FUNCTION, data.ip, &al, NULL);
659 /*
660 * We have to do this here as we may have a dso with no symbol hit that
661 * has a name longer than the ones with symbols sampled.
662 */
663 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
664 dso__calc_col_width(al.map->dso);
665
666 if (dso_list &&
667 (!al.map || !al.map->dso ||
668 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
669 (al.map->dso->short_name != al.map->dso->long_name &&
670 strlist__has_entry(dso_list, al.map->dso->long_name)))))
671 return 0;
672
673 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
674 return 0;
675
676 if (hist_entry__add(&al, data.callchain, data.period)) {
677 pr_debug("problem incrementing symbol count, skipping event\n"); 190 pr_debug("problem incrementing symbol count, skipping event\n");
678 return -1; 191 return -1;
679 } 192 }
680 193
681 event__stats.total += data.period; 194 attr = perf_header__find_attr(data.id, &session->header);
682
683 return 0;
684}
685
686static int process_comm_event(event_t *event)
687{
688 struct thread *thread = threads__findnew(event->comm.pid);
689
690 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
691 195
692 if (thread == NULL || 196 if (add_event_total(session, &data, attr)) {
693 thread__set_comm_adjust(thread, event->comm.comm)) { 197 pr_debug("problem adding event count\n");
694 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
695 return -1; 198 return -1;
696 } 199 }
697 200
698 return 0; 201 return 0;
699} 202}
700 203
701static int process_read_event(event_t *event) 204static int process_read_event(event_t *event, struct perf_session *session __used)
702{ 205{
703 struct perf_event_attr *attr; 206 struct perf_event_attr *attr;
704 207
@@ -721,66 +224,62 @@ static int process_read_event(event_t *event)
721 return 0; 224 return 0;
722} 225}
723 226
724static int sample_type_check(u64 type) 227static int perf_session__setup_sample_type(struct perf_session *self)
725{ 228{
726 sample_type = type; 229 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
727
728 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
729 if (sort__has_parent) { 230 if (sort__has_parent) {
730 fprintf(stderr, "selected --sort parent, but no" 231 fprintf(stderr, "selected --sort parent, but no"
731 " callchain data. Did you call" 232 " callchain data. Did you call"
732 " perf record without -g?\n"); 233 " perf record without -g?\n");
733 return -1; 234 return -EINVAL;
734 } 235 }
735 if (callchain) { 236 if (symbol_conf.use_callchain) {
736 fprintf(stderr, "selected -g but no callchain data." 237 fprintf(stderr, "selected -g but no callchain data."
737 " Did you call perf record without" 238 " Did you call perf record without"
738 " -g?\n"); 239 " -g?\n");
739 return -1; 240 return -1;
740 } 241 }
741 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 242 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
742 callchain = 1; 243 !symbol_conf.use_callchain) {
244 symbol_conf.use_callchain = true;
743 if (register_callchain_param(&callchain_param) < 0) { 245 if (register_callchain_param(&callchain_param) < 0) {
744 fprintf(stderr, "Can't register callchain" 246 fprintf(stderr, "Can't register callchain"
745 " params\n"); 247 " params\n");
746 return -1; 248 return -EINVAL;
747 } 249 }
748 } 250 }
749 251
750 return 0; 252 return 0;
751} 253}
752 254
753static struct perf_file_handler file_handler = { 255static struct perf_event_ops event_ops = {
754 .process_sample_event = process_sample_event, 256 .sample = process_sample_event,
755 .process_mmap_event = event__process_mmap, 257 .mmap = event__process_mmap,
756 .process_comm_event = process_comm_event, 258 .comm = event__process_comm,
757 .process_exit_event = event__process_task, 259 .exit = event__process_task,
758 .process_fork_event = event__process_task, 260 .fork = event__process_task,
759 .process_lost_event = event__process_lost, 261 .lost = event__process_lost,
760 .process_read_event = process_read_event, 262 .read = process_read_event,
761 .sample_type_check = sample_type_check,
762}; 263};
763 264
764
765static int __cmd_report(void) 265static int __cmd_report(void)
766{ 266{
767 struct thread *idle; 267 int ret = -EINVAL;
768 int ret; 268 struct perf_session *session;
269 struct rb_node *next;
769 270
770 session = perf_session__new(input_name, O_RDONLY, force); 271 session = perf_session__new(input_name, O_RDONLY, force);
771 if (session == NULL) 272 if (session == NULL)
772 return -ENOMEM; 273 return -ENOMEM;
773 274
774 idle = register_idle_thread();
775 thread__comm_adjust(idle);
776
777 if (show_threads) 275 if (show_threads)
778 perf_read_values_init(&show_threads_values); 276 perf_read_values_init(&show_threads_values);
779 277
780 register_perf_file_handler(&file_handler); 278 ret = perf_session__setup_sample_type(session);
279 if (ret)
280 goto out_delete;
781 281
782 ret = perf_session__process_events(session, full_paths, 282 ret = perf_session__process_events(session, &event_ops);
783 &event__cwdlen, &event__cwd);
784 if (ret) 283 if (ret)
785 goto out_delete; 284 goto out_delete;
786 285
@@ -790,17 +289,43 @@ static int __cmd_report(void)
790 } 289 }
791 290
792 if (verbose > 3) 291 if (verbose > 3)
793 threads__fprintf(stdout); 292 perf_session__fprintf(session, stdout);
794 293
795 if (verbose > 2) 294 if (verbose > 2)
796 dsos__fprintf(stdout); 295 dsos__fprintf(stdout);
797 296
798 collapse__resort(); 297 next = rb_first(&session->stats_by_id);
799 output__resort(event__stats.total); 298 while (next) {
800 output__fprintf(stdout, event__stats.total); 299 struct event_stat_id *stats;
300
301 stats = rb_entry(next, struct event_stat_id, rb_node);
302 perf_session__collapse_resort(&stats->hists);
303 perf_session__output_resort(&stats->hists, stats->stats.total);
304 if (rb_first(&session->stats_by_id) ==
305 rb_last(&session->stats_by_id))
306 fprintf(stdout, "# Samples: %Ld\n#\n",
307 stats->stats.total);
308 else
309 fprintf(stdout, "# Samples: %Ld %s\n#\n",
310 stats->stats.total,
311 __event_name(stats->type, stats->config));
801 312
802 if (show_threads) 313 perf_session__fprintf_hists(&stats->hists, NULL, false, stdout,
314 stats->stats.total);
315 fprintf(stdout, "\n\n");
316 next = rb_next(&stats->rb_node);
317 }
318
319 if (sort_order == default_sort_order &&
320 parent_pattern == default_parent_pattern)
321 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
322
323 if (show_threads) {
324 bool raw_printing_style = !strcmp(pretty_printing_style, "raw");
325 perf_read_values_display(stdout, &show_threads_values,
326 raw_printing_style);
803 perf_read_values_destroy(&show_threads_values); 327 perf_read_values_destroy(&show_threads_values);
328 }
804out_delete: 329out_delete:
805 perf_session__delete(session); 330 perf_session__delete(session);
806 return ret; 331 return ret;
@@ -808,12 +333,20 @@ out_delete:
808 333
809static int 334static int
810parse_callchain_opt(const struct option *opt __used, const char *arg, 335parse_callchain_opt(const struct option *opt __used, const char *arg,
811 int unset __used) 336 int unset)
812{ 337{
813 char *tok; 338 char *tok;
814 char *endptr; 339 char *endptr;
815 340
816 callchain = 1; 341 /*
342 * --no-call-graph
343 */
344 if (unset) {
345 dont_use_callchains = true;
346 return 0;
347 }
348
349 symbol_conf.use_callchain = true;
817 350
818 if (!arg) 351 if (!arg)
819 return 0; 352 return 0;
@@ -834,7 +367,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
834 367
835 else if (!strncmp(tok, "none", strlen(arg))) { 368 else if (!strncmp(tok, "none", strlen(arg))) {
836 callchain_param.mode = CHAIN_NONE; 369 callchain_param.mode = CHAIN_NONE;
837 callchain = 0; 370 symbol_conf.use_callchain = false;
838 371
839 return 0; 372 return 0;
840 } 373 }
@@ -859,8 +392,7 @@ setup:
859 return 0; 392 return 0;
860} 393}
861 394
862//static const char * const report_usage[] = { 395static const char * const report_usage[] = {
863const char * const report_usage[] = {
864 "perf report [<options>] <command>", 396 "perf report [<options>] <command>",
865 NULL 397 NULL
866}; 398};
@@ -877,7 +409,7 @@ static const struct option options[] = {
877 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 409 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
878 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 410 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
879 "load module symbols - WARNING: use only with -k and LIVE kernel"), 411 "load module symbols - WARNING: use only with -k and LIVE kernel"),
880 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 412 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
881 "Show a column with the number of samples"), 413 "Show a column with the number of samples"),
882 OPT_BOOLEAN('T', "threads", &show_threads, 414 OPT_BOOLEAN('T', "threads", &show_threads,
883 "Show per-thread event counters"), 415 "Show per-thread event counters"),
@@ -885,78 +417,48 @@ static const struct option options[] = {
885 "pretty printing style key: normal raw"), 417 "pretty printing style key: normal raw"),
886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 418 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
887 "sort by key(s): pid, comm, dso, symbol, parent"), 419 "sort by key(s): pid, comm, dso, symbol, parent"),
888 OPT_BOOLEAN('P', "full-paths", &full_paths, 420 OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
889 "Don't shorten the pathnames taking into account the cwd"), 421 "Don't shorten the pathnames taking into account the cwd"),
890 OPT_STRING('p', "parent", &parent_pattern, "regex", 422 OPT_STRING('p', "parent", &parent_pattern, "regex",
891 "regex filter to identify parent, see: '--sort parent'"), 423 "regex filter to identify parent, see: '--sort parent'"),
892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 424 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
893 "Only display entries with parent-match"), 425 "Only display entries with parent-match"),
894 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 426 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
895 "Display callchains using output_type and min percent threshold. " 427 "Display callchains using output_type and min percent threshold. "
896 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 428 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 429 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
898 "only consider symbols in these dsos"), 430 "only consider symbols in these dsos"),
899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 431 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
900 "only consider symbols in these comms"), 432 "only consider symbols in these comms"),
901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 433 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
902 "only consider these symbols"), 434 "only consider these symbols"),
903 OPT_STRING('w', "column-widths", &col_width_list_str, 435 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
904 "width[,width...]", 436 "width[,width...]",
905 "don't try to adjust column width, use these fixed values"), 437 "don't try to adjust column width, use these fixed values"),
906 OPT_STRING('t', "field-separator", &field_sep, "separator", 438 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
907 "separator for columns, no spaces will be added between " 439 "separator for columns, no spaces will be added between "
908 "columns '.' is reserved."), 440 "columns '.' is reserved."),
441 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
442 "Only display entries resolved to a symbol"),
909 OPT_END() 443 OPT_END()
910}; 444};
911 445
912static void setup_sorting(void) 446int cmd_report(int argc, const char **argv, const char *prefix __used)
913{ 447{
914 char *tmp, *tok, *str = strdup(sort_order); 448 argc = parse_options(argc, argv, options, report_usage, 0);
915
916 for (tok = strtok_r(str, ", ", &tmp);
917 tok; tok = strtok_r(NULL, ", ", &tmp)) {
918 if (sort_dimension__add(tok) < 0) {
919 error("Unknown --sort key: `%s'", tok);
920 usage_with_options(report_usage, options);
921 }
922 }
923
924 free(str);
925}
926 449
927static void setup_list(struct strlist **list, const char *list_str, 450 setup_pager();
928 struct sort_entry *se, const char *list_name,
929 FILE *fp)
930{
931 if (list_str) {
932 *list = strlist__new(true, list_str);
933 if (!*list) {
934 fprintf(stderr, "problems parsing %s list\n",
935 list_name);
936 exit(129);
937 }
938 if (strlist__nr_entries(*list) == 1) {
939 fprintf(fp, "# %s: %s\n", list_name,
940 strlist__entry(*list, 0)->s);
941 se->elide = true;
942 }
943 }
944}
945 451
946int cmd_report(int argc, const char **argv, const char *prefix __used) 452 if (symbol__init() < 0)
947{
948 if (symbol__init(&symbol_conf) < 0)
949 return -1; 453 return -1;
950 454
951 argc = parse_options(argc, argv, options, report_usage, 0); 455 setup_sorting(report_usage, options);
952
953 setup_sorting();
954 456
955 if (parent_pattern != default_parent_pattern) { 457 if (parent_pattern != default_parent_pattern) {
956 sort_dimension__add("parent"); 458 sort_dimension__add("parent");
957 sort_parent.elide = 1; 459 sort_parent.elide = 1;
958 } else 460 } else
959 exclude_other = 0; 461 symbol_conf.exclude_other = false;
960 462
961 /* 463 /*
962 * Any (unrecognized) arguments left? 464 * Any (unrecognized) arguments left?
@@ -964,17 +466,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
964 if (argc) 466 if (argc)
965 usage_with_options(report_usage, options); 467 usage_with_options(report_usage, options);
966 468
967 setup_pager(); 469 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
968 470 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
969 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 471 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
970 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
971 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
972
973 if (field_sep && *field_sep == '.') {
974 fputs("'.' is the only non valid --field-separator argument\n",
975 stderr);
976 exit(129);
977 }
978 472
979 return __cmd_report(); 473 return __cmd_report();
980} 474}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 65021fe1361e..4f5a03e43444 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -12,7 +12,6 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13 13
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/data_map.h"
16 15
17#include <sys/prctl.h> 16#include <sys/prctl.h>
18 17
@@ -22,8 +21,6 @@
22 21
23static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
24 23
25static u64 sample_type;
26
27static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
28static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
29 26
@@ -731,18 +728,21 @@ struct trace_migrate_task_event {
731 728
732struct trace_sched_handler { 729struct trace_sched_handler {
733 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
734 struct event *, 732 struct event *,
735 int cpu, 733 int cpu,
736 u64 timestamp, 734 u64 timestamp,
737 struct thread *thread); 735 struct thread *thread);
738 736
739 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
740 struct event *, 739 struct event *,
741 int cpu, 740 int cpu,
742 u64 timestamp, 741 u64 timestamp,
743 struct thread *thread); 742 struct thread *thread);
744 743
745 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
746 struct event *, 746 struct event *,
747 int cpu, 747 int cpu,
748 u64 timestamp, 748 u64 timestamp,
@@ -755,6 +755,7 @@ struct trace_sched_handler {
755 struct thread *thread); 755 struct thread *thread);
756 756
757 void (*migrate_task_event)(struct trace_migrate_task_event *, 757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
758 struct event *, 759 struct event *,
759 int cpu, 760 int cpu,
760 u64 timestamp, 761 u64 timestamp,
@@ -764,6 +765,7 @@ struct trace_sched_handler {
764 765
765static void 766static void
766replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
767 struct event *event, 769 struct event *event,
768 int cpu __used, 770 int cpu __used,
769 u64 timestamp __used, 771 u64 timestamp __used,
@@ -790,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
790 792
791static void 793static void
792replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
793 struct event *event, 796 struct event *event,
794 int cpu, 797 int cpu,
795 u64 timestamp, 798 u64 timestamp,
@@ -1023,6 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1023 1026
1024static void 1027static void
1025latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1026 struct event *event __used, 1030 struct event *event __used,
1027 int cpu, 1031 int cpu,
1028 u64 timestamp, 1032 u64 timestamp,
@@ -1046,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1046 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1047 1051
1048 1052
1049 sched_out = threads__findnew(switch_event->prev_pid); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1050 sched_in = threads__findnew(switch_event->next_pid); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1051 1055
1052 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1053 if (!out_events) { 1057 if (!out_events) {
@@ -1075,12 +1079,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1075 1079
1076static void 1080static void
1077latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1078 struct event *event __used, 1083 struct event *event __used,
1079 int cpu, 1084 int cpu,
1080 u64 timestamp, 1085 u64 timestamp,
1081 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1082{ 1087{
1083 struct thread *thread = threads__findnew(runtime_event->pid); 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1089 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1085 1090
1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1097 1102
1098static void 1103static void
1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1100 struct event *__event __used, 1106 struct event *__event __used,
1101 int cpu __used, 1107 int cpu __used,
1102 u64 timestamp, 1108 u64 timestamp,
@@ -1110,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1110 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1111 return; 1117 return;
1112 1118
1113 wakee = threads__findnew(wakeup_event->pid); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1114 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1115 if (!atoms) { 1121 if (!atoms) {
1116 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1144,6 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1144 1150
1145static void 1151static void
1146latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1152latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1153 struct perf_session *session,
1147 struct event *__event __used, 1154 struct event *__event __used,
1148 int cpu __used, 1155 int cpu __used,
1149 u64 timestamp, 1156 u64 timestamp,
@@ -1159,7 +1166,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1159 if (profile_cpu == -1) 1166 if (profile_cpu == -1)
1160 return; 1167 return;
1161 1168
1162 migrant = threads__findnew(migrate_task_event->pid); 1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1163 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1164 if (!atoms) { 1171 if (!atoms) {
1165 thread_atoms_insert(migrant); 1172 thread_atoms_insert(migrant);
@@ -1354,7 +1361,7 @@ static void sort_lat(void)
1354static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1355 1362
1356static void 1363static void
1357process_sched_wakeup_event(void *data, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1358 struct event *event, 1365 struct event *event,
1359 int cpu __used, 1366 int cpu __used,
1360 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1371,7 +1378,8 @@ process_sched_wakeup_event(void *data,
1371 FILL_FIELD(wakeup_event, cpu, event, data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1372 1379
1373 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1374 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1375} 1383}
1376 1384
1377/* 1385/*
@@ -1389,6 +1397,7 @@ static char next_shortname2 = '0';
1389 1397
1390static void 1398static void
1391map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1392 struct event *event __used, 1401 struct event *event __used,
1393 int this_cpu, 1402 int this_cpu,
1394 u64 timestamp, 1403 u64 timestamp,
@@ -1416,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1416 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1417 1426
1418 1427
1419 sched_out = threads__findnew(switch_event->prev_pid); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1420 sched_in = threads__findnew(switch_event->next_pid); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1421 1430
1422 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1423 1432
@@ -1467,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1467 1476
1468 1477
1469static void 1478static void
1470process_sched_switch_event(void *data, 1479process_sched_switch_event(void *data, struct perf_session *session,
1471 struct event *event, 1480 struct event *event,
1472 int this_cpu, 1481 int this_cpu,
1473 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1494,13 +1503,14 @@ process_sched_switch_event(void *data,
1494 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1495 } 1504 }
1496 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1497 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread); 1506 trace_handler->switch_event(&switch_event, session, event,
1507 this_cpu, timestamp, thread);
1498 1508
1499 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1500} 1510}
1501 1511
1502static void 1512static void
1503process_sched_runtime_event(void *data, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1504 struct event *event, 1514 struct event *event,
1505 int cpu __used, 1515 int cpu __used,
1506 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1514,7 +1524,7 @@ process_sched_runtime_event(void *data,
1514 FILL_FIELD(runtime_event, vruntime, event, data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1515 1525
1516 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1517 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1518} 1528}
1519 1529
1520static void 1530static void
@@ -1534,7 +1544,8 @@ process_sched_fork_event(void *data,
1534 FILL_FIELD(fork_event, child_pid, event, data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1535 1545
1536 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1537 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1538} 1549}
1539 1550
1540static void 1551static void
@@ -1548,7 +1559,7 @@ process_sched_exit_event(struct event *event,
1548} 1559}
1549 1560
1550static void 1561static void
1551process_sched_migrate_task_event(void *data, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1552 struct event *event, 1563 struct event *event,
1553 int cpu __used, 1564 int cpu __used,
1554 u64 timestamp __used, 1565 u64 timestamp __used,
@@ -1564,12 +1575,13 @@ process_sched_migrate_task_event(void *data,
1564 FILL_FIELD(migrate_task_event, cpu, event, data); 1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1565 1576
1566 if (trace_handler->migrate_task_event) 1577 if (trace_handler->migrate_task_event)
1567 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); 1578 trace_handler->migrate_task_event(&migrate_task_event, session,
1579 event, cpu, timestamp, thread);
1568} 1580}
1569 1581
1570static void 1582static void
1571process_raw_event(event_t *raw_event __used, void *data, 1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1572 int cpu, u64 timestamp, struct thread *thread) 1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1573{ 1585{
1574 struct event *event; 1586 struct event *event;
1575 int type; 1587 int type;
@@ -1579,27 +1591,27 @@ process_raw_event(event_t *raw_event __used, void *data,
1579 event = trace_find_event(type); 1591 event = trace_find_event(type);
1580 1592
1581 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1582 process_sched_switch_event(data, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1583 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1584 process_sched_runtime_event(data, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1585 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1586 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1587 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1588 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1589 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1590 process_sched_fork_event(data, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1591 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1592 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_migrate_task")) 1605 if (!strcmp(event->name, "sched_migrate_task"))
1594 process_sched_migrate_task_event(data, event, cpu, timestamp, thread); 1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1595} 1607}
1596 1608
1597static int process_sample_event(event_t *event) 1609static int process_sample_event(event_t *event, struct perf_session *session)
1598{ 1610{
1599 struct sample_data data; 1611 struct sample_data data;
1600 struct thread *thread; 1612 struct thread *thread;
1601 1613
1602 if (!(sample_type & PERF_SAMPLE_RAW)) 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1603 return 0; 1615 return 0;
1604 1616
1605 memset(&data, 0, sizeof(data)); 1617 memset(&data, 0, sizeof(data));
@@ -1607,15 +1619,12 @@ static int process_sample_event(event_t *event)
1607 data.cpu = -1; 1619 data.cpu = -1;
1608 data.period = -1; 1620 data.period = -1;
1609 1621
1610 event__parse_sample(event, sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1611 1623
1612 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1613 event->header.misc, 1625 data.pid, data.tid, data.ip, data.period);
1614 data.pid, data.tid,
1615 (void *)(long)data.ip,
1616 (long long)data.period);
1617 1626
1618 thread = threads__findnew(data.pid); 1627 thread = perf_session__findnew(session, data.pid);
1619 if (thread == NULL) { 1628 if (thread == NULL) {
1620 pr_debug("problem processing %d event, skipping it.\n", 1629 pr_debug("problem processing %d event, skipping it.\n",
1621 event->header.type); 1630 event->header.type);
@@ -1627,12 +1636,13 @@ static int process_sample_event(event_t *event)
1627 if (profile_cpu != -1 && profile_cpu != (int)data.cpu) 1636 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1628 return 0; 1637 return 0;
1629 1638
1630 process_raw_event(event, data.raw_data, data.cpu, data.time, thread); 1639 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1631 1640
1632 return 0; 1641 return 0;
1633} 1642}
1634 1643
1635static int process_lost_event(event_t *event __used) 1644static int process_lost_event(event_t *event __used,
1645 struct perf_session *session __used)
1636{ 1646{
1637 nr_lost_chunks++; 1647 nr_lost_chunks++;
1638 nr_lost_events += event->lost.lost; 1648 nr_lost_events += event->lost.lost;
@@ -1640,39 +1650,22 @@ static int process_lost_event(event_t *event __used)
1640 return 0; 1650 return 0;
1641} 1651}
1642 1652
1643static int sample_type_check(u64 type) 1653static struct perf_event_ops event_ops = {
1644{ 1654 .sample = process_sample_event,
1645 sample_type = type; 1655 .comm = event__process_comm,
1646 1656 .lost = process_lost_event,
1647 if (!(sample_type & PERF_SAMPLE_RAW)) {
1648 fprintf(stderr,
1649 "No trace sample to read. Did you call perf record "
1650 "without -R?");
1651 return -1;
1652 }
1653
1654 return 0;
1655}
1656
1657static struct perf_file_handler file_handler = {
1658 .process_sample_event = process_sample_event,
1659 .process_comm_event = event__process_comm,
1660 .process_lost_event = process_lost_event,
1661 .sample_type_check = sample_type_check,
1662}; 1657};
1663 1658
1664static int read_events(void) 1659static int read_events(void)
1665{ 1660{
1666 int err; 1661 int err = -EINVAL;
1667 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1662 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1668
1669 if (session == NULL) 1663 if (session == NULL)
1670 return -ENOMEM; 1664 return -ENOMEM;
1671 1665
1672 register_idle_thread(); 1666 if (perf_session__has_traces(session, "record -R"))
1673 register_perf_file_handler(&file_handler); 1667 err = perf_session__process_events(session, &event_ops);
1674 1668
1675 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1676 perf_session__delete(session); 1669 perf_session__delete(session);
1677 return err; 1670 return err;
1678} 1671}
@@ -1904,7 +1897,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1904 if (!strcmp(argv[0], "trace")) 1897 if (!strcmp(argv[0], "trace"))
1905 return cmd_trace(argc, argv, prefix); 1898 return cmd_trace(argc, argv, prefix);
1906 1899
1907 symbol__init(0); 1900 symbol__init();
1908 if (!strncmp(argv[0], "rec", 3)) { 1901 if (!strncmp(argv[0], "rec", 3)) {
1909 return __cmd_record(argc, argv); 1902 return __cmd_record(argc, argv);
1910 } else if (!strncmp(argv[0], "lat", 3)) { 1903 } else if (!strncmp(argv[0], "lat", 3)) {
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c70d72003557..95db31cff6fd 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -44,6 +44,8 @@
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"
48#include "util/cpumap.h"
47 49
48#include <sys/prctl.h> 50#include <sys/prctl.h>
49#include <math.h> 51#include <math.h>
@@ -79,6 +81,8 @@ static int fd[MAX_NR_CPUS][MAX_COUNTERS];
79 81
80static int event_scaled[MAX_COUNTERS]; 82static int event_scaled[MAX_COUNTERS];
81 83
84static volatile int done = 0;
85
82struct stats 86struct stats
83{ 87{
84 double n, mean, M2; 88 double n, mean, M2;
@@ -148,7 +152,7 @@ static void create_perf_stat_counter(int counter, int pid)
148 unsigned int cpu; 152 unsigned int cpu;
149 153
150 for (cpu = 0; cpu < nr_cpus; cpu++) { 154 for (cpu = 0; cpu < nr_cpus; cpu++) {
151 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); 155 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0);
152 if (fd[cpu][counter] < 0 && verbose) 156 if (fd[cpu][counter] < 0 && verbose)
153 fprintf(stderr, ERR_PERF_OPEN, counter, 157 fprintf(stderr, ERR_PERF_OPEN, counter,
154 fd[cpu][counter], strerror(errno)); 158 fd[cpu][counter], strerror(errno));
@@ -247,61 +251,64 @@ static int run_perf_stat(int argc __used, const char **argv)
247 unsigned long long t0, t1; 251 unsigned long long t0, t1;
248 int status = 0; 252 int status = 0;
249 int counter; 253 int counter;
250 int pid; 254 int pid = target_pid;
251 int child_ready_pipe[2], go_pipe[2]; 255 int child_ready_pipe[2], go_pipe[2];
256 const bool forks = (target_pid == -1 && argc > 0);
252 char buf; 257 char buf;
253 258
254 if (!system_wide) 259 if (!system_wide)
255 nr_cpus = 1; 260 nr_cpus = 1;
256 261
257 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { 262 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
258 perror("failed to create pipes"); 263 perror("failed to create pipes");
259 exit(1); 264 exit(1);
260 } 265 }
261 266
262 if ((pid = fork()) < 0) 267 if (forks) {
263 perror("failed to fork"); 268 if ((pid = fork()) < 0)
264 269 perror("failed to fork");
265 if (!pid) { 270
266 close(child_ready_pipe[0]); 271 if (!pid) {
267 close(go_pipe[1]); 272 close(child_ready_pipe[0]);
268 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 273 close(go_pipe[1]);
274 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
275
276 /*
277 * Do a dummy execvp to get the PLT entry resolved,
278 * so we avoid the resolver overhead on the real
279 * execvp call.
280 */
281 execvp("", (char **)argv);
282
283 /*
284 * Tell the parent we're ready to go
285 */
286 close(child_ready_pipe[1]);
287
288 /*
289 * Wait until the parent tells us to go.
290 */
291 if (read(go_pipe[0], &buf, 1) == -1)
292 perror("unable to read pipe");
293
294 execvp(argv[0], (char **)argv);
295
296 perror(argv[0]);
297 exit(-1);
298 }
269 299
270 /* 300 child_pid = pid;
271 * Do a dummy execvp to get the PLT entry resolved,
272 * so we avoid the resolver overhead on the real
273 * execvp call.
274 */
275 execvp("", (char **)argv);
276 301
277 /* 302 /*
278 * Tell the parent we're ready to go 303 * Wait for the child to be ready to exec.
279 */ 304 */
280 close(child_ready_pipe[1]); 305 close(child_ready_pipe[1]);
281 306 close(go_pipe[0]);
282 /* 307 if (read(child_ready_pipe[0], &buf, 1) == -1)
283 * Wait until the parent tells us to go.
284 */
285 if (read(go_pipe[0], &buf, 1) == -1)
286 perror("unable to read pipe"); 308 perror("unable to read pipe");
287 309 close(child_ready_pipe[0]);
288 execvp(argv[0], (char **)argv);
289
290 perror(argv[0]);
291 exit(-1);
292 } 310 }
293 311
294 child_pid = pid;
295
296 /*
297 * Wait for the child to be ready to exec.
298 */
299 close(child_ready_pipe[1]);
300 close(go_pipe[0]);
301 if (read(child_ready_pipe[0], &buf, 1) == -1)
302 perror("unable to read pipe");
303 close(child_ready_pipe[0]);
304
305 for (counter = 0; counter < nr_counters; counter++) 312 for (counter = 0; counter < nr_counters; counter++)
306 create_perf_stat_counter(counter, pid); 313 create_perf_stat_counter(counter, pid);
307 314
@@ -310,8 +317,12 @@ static int run_perf_stat(int argc __used, const char **argv)
310 */ 317 */
311 t0 = rdclock(); 318 t0 = rdclock();
312 319
313 close(go_pipe[1]); 320 if (forks) {
314 wait(&status); 321 close(go_pipe[1]);
322 wait(&status);
323 } else {
324 while(!done);
325 }
315 326
316 t1 = rdclock(); 327 t1 = rdclock();
317 328
@@ -417,10 +428,13 @@ static void print_stat(int argc, const char **argv)
417 fflush(stdout); 428 fflush(stdout);
418 429
419 fprintf(stderr, "\n"); 430 fprintf(stderr, "\n");
420 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 431 fprintf(stderr, " Performance counter stats for ");
421 432 if(target_pid == -1) {
422 for (i = 1; i < argc; i++) 433 fprintf(stderr, "\'%s", argv[0]);
423 fprintf(stderr, " %s", argv[i]); 434 for (i = 1; i < argc; i++)
435 fprintf(stderr, " %s", argv[i]);
436 }else
437 fprintf(stderr, "task pid \'%d", target_pid);
424 438
425 fprintf(stderr, "\'"); 439 fprintf(stderr, "\'");
426 if (run_count > 1) 440 if (run_count > 1)
@@ -445,6 +459,9 @@ static volatile int signr = -1;
445 459
446static void skip_signal(int signo) 460static void skip_signal(int signo)
447{ 461{
462 if(target_pid != -1)
463 done = 1;
464
448 signr = signo; 465 signr = signo;
449} 466}
450 467
@@ -461,7 +478,7 @@ static void sig_atexit(void)
461} 478}
462 479
463static const char * const stat_usage[] = { 480static const char * const stat_usage[] = {
464 "perf stat [<options>] <command>", 481 "perf stat [<options>] [<command>]",
465 NULL 482 NULL
466}; 483};
467 484
@@ -492,7 +509,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
492 509
493 argc = parse_options(argc, argv, options, stat_usage, 510 argc = parse_options(argc, argv, options, stat_usage,
494 PARSE_OPT_STOP_AT_NON_OPTION); 511 PARSE_OPT_STOP_AT_NON_OPTION);
495 if (!argc) 512 if (!argc && target_pid == -1)
496 usage_with_options(stat_usage, options); 513 usage_with_options(stat_usage, options);
497 if (run_count <= 0) 514 if (run_count <= 0)
498 usage_with_options(stat_usage, options); 515 usage_with_options(stat_usage, options);
@@ -503,9 +520,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
503 nr_counters = ARRAY_SIZE(default_attrs); 520 nr_counters = ARRAY_SIZE(default_attrs);
504 } 521 }
505 522
506 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 523 if (system_wide)
507 assert(nr_cpus <= MAX_NR_CPUS); 524 nr_cpus = read_cpu_map();
508 assert((int)nr_cpus >= 0); 525 else
526 nr_cpus = 1;
509 527
510 /* 528 /*
511 * We dont want to block the signals - that would cause 529 * We dont want to block the signals - that would cause
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 759dd2b35fdb..0d4d8ff7914b 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,15 +30,12 @@
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h" 32#include "util/event.h"
33#include "util/data_map.h" 33#include "util/session.h"
34#include "util/svghelper.h" 34#include "util/svghelper.h"
35 35
36static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
37static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
38 38
39
40static u64 sample_type;
41
42static unsigned int numcpus; 39static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */ 40static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */ 41static u64 max_freq; /* Highest CPU frequency seen */
@@ -281,21 +278,19 @@ static int cpus_cstate_state[MAX_CPUS];
281static u64 cpus_pstate_start_times[MAX_CPUS]; 278static u64 cpus_pstate_start_times[MAX_CPUS];
282static u64 cpus_pstate_state[MAX_CPUS]; 279static u64 cpus_pstate_state[MAX_CPUS];
283 280
284static int 281static int process_comm_event(event_t *event, struct perf_session *session __used)
285process_comm_event(event_t *event)
286{ 282{
287 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.tid, event->comm.comm);
288 return 0; 284 return 0;
289} 285}
290static int 286
291process_fork_event(event_t *event) 287static int process_fork_event(event_t *event, struct perf_session *session __used)
292{ 288{
293 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
294 return 0; 290 return 0;
295} 291}
296 292
297static int 293static int process_exit_event(event_t *event, struct perf_session *session __used)
298process_exit_event(event_t *event)
299{ 294{
300 pid_exit(event->fork.pid, event->fork.time); 295 pid_exit(event->fork.pid, event->fork.time);
301 return 0; 296 return 0;
@@ -480,17 +475,16 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
480} 475}
481 476
482 477
483static int 478static int process_sample_event(event_t *event, struct perf_session *session)
484process_sample_event(event_t *event)
485{ 479{
486 struct sample_data data; 480 struct sample_data data;
487 struct trace_entry *te; 481 struct trace_entry *te;
488 482
489 memset(&data, 0, sizeof(data)); 483 memset(&data, 0, sizeof(data));
490 484
491 event__parse_sample(event, sample_type, &data); 485 event__parse_sample(event, session->sample_type, &data);
492 486
493 if (sample_type & PERF_SAMPLE_TIME) { 487 if (session->sample_type & PERF_SAMPLE_TIME) {
494 if (!first_time || first_time > data.time) 488 if (!first_time || first_time > data.time)
495 first_time = data.time; 489 first_time = data.time;
496 if (last_time < data.time) 490 if (last_time < data.time)
@@ -498,7 +492,7 @@ process_sample_event(event_t *event)
498 } 492 }
499 493
500 te = (void *)data.raw_data; 494 te = (void *)data.raw_data;
501 if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
502 char *event_str; 496 char *event_str;
503 struct power_entry *pe; 497 struct power_entry *pe;
504 498
@@ -575,16 +569,16 @@ static void end_sample_processing(void)
575 } 569 }
576} 570}
577 571
578static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
579{ 573{
580 int cursor; 574 int cursor;
581 575
582 cursor = 0; 576 cursor = 0;
583 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
584 cursor++; 578 cursor++;
585 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
586 cursor++; 580 cursor++;
587 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
588 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
589 return 0; 583 return 0;
590} 584}
@@ -594,8 +588,7 @@ static u64 sample_time(event_t *event)
594 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
595 * The order will get flipped later. 589 * The order will get flipped later.
596 */ 590 */
597static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
598queue_sample_event(event_t *event)
599{ 592{
600 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
601 int size; 594 int size;
@@ -609,7 +602,7 @@ queue_sample_event(event_t *event)
609 memset(copy, 0, size); 602 memset(copy, 0, size);
610 603
611 copy->next = NULL; 604 copy->next = NULL;
612 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
613 606
614 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
615 608
@@ -1021,7 +1014,7 @@ static void write_svg_file(const char *filename)
1021 svg_close(); 1014 svg_close();
1022} 1015}
1023 1016
1024static void process_samples(void) 1017static void process_samples(struct perf_session *session)
1025{ 1018{
1026 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
1027 event_t *event; 1020 event_t *event;
@@ -1032,46 +1025,33 @@ static void process_samples(void)
1032 while (cursor) { 1025 while (cursor) {
1033 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1034 cursor = cursor->next; 1027 cursor = cursor->next;
1035 process_sample_event(event); 1028 process_sample_event(event, session);
1036 }
1037}
1038
1039static int sample_type_check(u64 type)
1040{
1041 sample_type = type;
1042
1043 if (!(sample_type & PERF_SAMPLE_RAW)) {
1044 fprintf(stderr, "No trace samples found in the file.\n"
1045 "Have you used 'perf timechart record' to record it?\n");
1046 return -1;
1047 } 1029 }
1048
1049 return 0;
1050} 1030}
1051 1031
1052static struct perf_file_handler file_handler = { 1032static struct perf_event_ops event_ops = {
1053 .process_comm_event = process_comm_event, 1033 .comm = process_comm_event,
1054 .process_fork_event = process_fork_event, 1034 .fork = process_fork_event,
1055 .process_exit_event = process_exit_event, 1035 .exit = process_exit_event,
1056 .process_sample_event = queue_sample_event, 1036 .sample = queue_sample_event,
1057 .sample_type_check = sample_type_check,
1058}; 1037};
1059 1038
1060static int __cmd_timechart(void) 1039static int __cmd_timechart(void)
1061{ 1040{
1062 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1041 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1063 int ret; 1042 int ret = -EINVAL;
1064 1043
1065 if (session == NULL) 1044 if (session == NULL)
1066 return -ENOMEM; 1045 return -ENOMEM;
1067 1046
1068 register_perf_file_handler(&file_handler); 1047 if (!perf_session__has_traces(session, "timechart record"))
1048 goto out_delete;
1069 1049
1070 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd); 1050 ret = perf_session__process_events(session, &event_ops);
1071 if (ret) 1051 if (ret)
1072 goto out_delete; 1052 goto out_delete;
1073 1053
1074 process_samples(); 1054 process_samples(session);
1075 1055
1076 end_sample_processing(); 1056 end_sample_processing();
1077 1057
@@ -1148,11 +1128,11 @@ static const struct option options[] = {
1148 1128
1149int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1129int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1150{ 1130{
1151 symbol__init(0);
1152
1153 argc = parse_options(argc, argv, options, timechart_usage, 1131 argc = parse_options(argc, argv, options, timechart_usage,
1154 PARSE_OPT_STOP_AT_NON_OPTION); 1132 PARSE_OPT_STOP_AT_NON_OPTION);
1155 1133
1134 symbol__init();
1135
1156 if (argc && !strncmp(argv[0], "rec", 3)) 1136 if (argc && !strncmp(argv[0], "rec", 3))
1157 return __cmd_record(argc, argv); 1137 return __cmd_record(argc, argv);
1158 else if (argc) 1138 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e0a374d0e43a..1f529321607e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,13 +20,15 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/symbol.h"
24#include "util/color.h" 23#include "util/color.h"
24#include "util/session.h"
25#include "util/symbol.h"
25#include "util/thread.h" 26#include "util/thread.h"
26#include "util/util.h" 27#include "util/util.h"
27#include <linux/rbtree.h> 28#include <linux/rbtree.h>
28#include "util/parse-options.h" 29#include "util/parse-options.h"
29#include "util/parse-events.h" 30#include "util/parse-events.h"
31#include "util/cpumap.h"
30 32
31#include "util/debug.h" 33#include "util/debug.h"
32 34
@@ -79,7 +81,6 @@ static int dump_symtab = 0;
79static bool hide_kernel_symbols = false; 81static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false; 82static bool hide_user_symbols = false;
81static struct winsize winsize; 83static struct winsize winsize;
82struct symbol_conf symbol_conf;
83 84
84/* 85/*
85 * Source 86 * Source
@@ -94,6 +95,7 @@ struct source_line {
94 95
95static char *sym_filter = NULL; 96static char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry = NULL; 97struct sym_entry *sym_filter_entry = NULL;
98struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 99static int sym_pcnt_filter = 5;
98static int sym_counter = 0; 100static int sym_counter = 0;
99static int display_weighted = -1; 101static int display_weighted = -1;
@@ -201,10 +203,9 @@ static void parse_source(struct sym_entry *syme)
201 len = sym->end - sym->start; 203 len = sym->end - sym->start;
202 204
203 sprintf(command, 205 sprintf(command,
204 "objdump --start-address=0x%016Lx " 206 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
205 "--stop-address=0x%016Lx -dS %s", 207 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
206 map->unmap_ip(map, sym->start), 208 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
207 map->unmap_ip(map, sym->end), path);
208 209
209 file = popen(command, "r"); 210 file = popen(command, "r");
210 if (!file) 211 if (!file)
@@ -215,7 +216,7 @@ static void parse_source(struct sym_entry *syme)
215 while (!feof(file)) { 216 while (!feof(file)) {
216 struct source_line *src; 217 struct source_line *src;
217 size_t dummy = 0; 218 size_t dummy = 0;
218 char *c; 219 char *c, *sep;
219 220
220 src = malloc(sizeof(struct source_line)); 221 src = malloc(sizeof(struct source_line));
221 assert(src != NULL); 222 assert(src != NULL);
@@ -234,14 +235,11 @@ static void parse_source(struct sym_entry *syme)
234 *source->lines_tail = src; 235 *source->lines_tail = src;
235 source->lines_tail = &src->next; 236 source->lines_tail = &src->next;
236 237
237 if (strlen(src->line)>8 && src->line[8] == ':') { 238 src->eip = strtoull(src->line, &sep, 16);
238 src->eip = strtoull(src->line, NULL, 16); 239 if (*sep == ':')
239 src->eip = map->unmap_ip(map, src->eip); 240 src->eip = map__objdump_2ip(map, src->eip);
240 } 241 else /* this line has no ip info (e.g. source line) */
241 if (strlen(src->line)>8 && src->line[16] == ':') { 242 src->eip = 0;
242 src->eip = strtoull(src->line, NULL, 16);
243 src->eip = map->unmap_ip(map, src->eip);
244 }
245 } 243 }
246 pclose(file); 244 pclose(file);
247out_assign: 245out_assign:
@@ -276,6 +274,9 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
276 goto out_unlock; 274 goto out_unlock;
277 275
278 for (line = syme->src->lines; line; line = line->next) { 276 for (line = syme->src->lines; line; line = line->next) {
277 /* skip lines without IP info */
278 if (line->eip == 0)
279 continue;
279 if (line->eip == ip) { 280 if (line->eip == ip) {
280 line->count[counter]++; 281 line->count[counter]++;
281 break; 282 break;
@@ -287,17 +288,20 @@ out_unlock:
287 pthread_mutex_unlock(&syme->src->lock); 288 pthread_mutex_unlock(&syme->src->lock);
288} 289}
289 290
291#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
292
290static void lookup_sym_source(struct sym_entry *syme) 293static void lookup_sym_source(struct sym_entry *syme)
291{ 294{
292 struct symbol *symbol = sym_entry__symbol(syme); 295 struct symbol *symbol = sym_entry__symbol(syme);
293 struct source_line *line; 296 struct source_line *line;
294 char pattern[PATH_MAX]; 297 char pattern[PATTERN_LEN + 1];
295 298
296 sprintf(pattern, "<%s>:", symbol->name); 299 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
300 map__rip_2objdump(syme->map, symbol->start));
297 301
298 pthread_mutex_lock(&syme->src->lock); 302 pthread_mutex_lock(&syme->src->lock);
299 for (line = syme->src->lines; line; line = line->next) { 303 for (line = syme->src->lines; line; line = line->next) {
300 if (strstr(line->line, pattern)) { 304 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
301 syme->src->source = line; 305 syme->src->source = line;
302 break; 306 break;
303 } 307 }
@@ -451,7 +455,7 @@ static void print_sym_table(void)
451 struct sym_entry *syme, *n; 455 struct sym_entry *syme, *n;
452 struct rb_root tmp = RB_ROOT; 456 struct rb_root tmp = RB_ROOT;
453 struct rb_node *nd; 457 struct rb_node *nd;
454 int sym_width = 0, dso_width = 0, max_dso_width; 458 int sym_width = 0, dso_width = 0, dso_short_width = 0;
455 const int win_width = winsize.ws_col - 1; 459 const int win_width = winsize.ws_col - 1;
456 460
457 samples = userspace_samples = 0; 461 samples = userspace_samples = 0;
@@ -541,15 +545,20 @@ static void print_sym_table(void)
541 if (syme->map->dso->long_name_len > dso_width) 545 if (syme->map->dso->long_name_len > dso_width)
542 dso_width = syme->map->dso->long_name_len; 546 dso_width = syme->map->dso->long_name_len;
543 547
548 if (syme->map->dso->short_name_len > dso_short_width)
549 dso_short_width = syme->map->dso->short_name_len;
550
544 if (syme->name_len > sym_width) 551 if (syme->name_len > sym_width)
545 sym_width = syme->name_len; 552 sym_width = syme->name_len;
546 } 553 }
547 554
548 printed = 0; 555 printed = 0;
549 556
550 max_dso_width = winsize.ws_col - sym_width - 29; 557 if (sym_width + dso_width > winsize.ws_col - 29) {
551 if (dso_width > max_dso_width) 558 dso_width = dso_short_width;
552 dso_width = max_dso_width; 559 if (sym_width + dso_width > winsize.ws_col - 29)
560 sym_width = winsize.ws_col - dso_width - 29;
561 }
553 putchar('\n'); 562 putchar('\n');
554 if (nr_counters == 1) 563 if (nr_counters == 1)
555 printf(" samples pcnt"); 564 printf(" samples pcnt");
@@ -667,7 +676,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
667 } 676 }
668 677
669 if (!found) { 678 if (!found) {
670 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 679 fprintf(stderr, "Sorry, %s is not active.\n", buf);
671 sleep(1); 680 sleep(1);
672 return; 681 return;
673 } else 682 } else
@@ -695,17 +704,15 @@ static void print_mapped_keys(void)
695 704
696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 705 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
697 706
698 if (symbol_conf.vmlinux_name) { 707 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
699 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 708 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 709 fprintf(stdout, "\t[S] stop annotation.\n");
701 fprintf(stdout, "\t[S] stop annotation.\n");
702 }
703 710
704 if (nr_counters > 1) 711 if (nr_counters > 1)
705 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 712 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
706 713
707 fprintf(stdout, 714 fprintf(stdout,
708 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 715 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
709 hide_kernel_symbols ? "yes" : "no"); 716 hide_kernel_symbols ? "yes" : "no");
710 fprintf(stdout, 717 fprintf(stdout,
711 "\t[U] hide user symbols. \t(%s)\n", 718 "\t[U] hide user symbols. \t(%s)\n",
@@ -725,14 +732,13 @@ static int key_mapped(int c)
725 case 'Q': 732 case 'Q':
726 case 'K': 733 case 'K':
727 case 'U': 734 case 'U':
735 case 'F':
736 case 's':
737 case 'S':
728 return 1; 738 return 1;
729 case 'E': 739 case 'E':
730 case 'w': 740 case 'w':
731 return nr_counters > 1 ? 1 : 0; 741 return nr_counters > 1 ? 1 : 0;
732 case 'F':
733 case 's':
734 case 'S':
735 return symbol_conf.vmlinux_name ? 1 : 0;
736 default: 742 default:
737 break; 743 break;
738 } 744 }
@@ -910,8 +916,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
910 syme = symbol__priv(sym); 916 syme = symbol__priv(sym);
911 syme->map = map; 917 syme->map = map;
912 syme->src = NULL; 918 syme->src = NULL;
913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 919
914 sym_filter_entry = syme; 920 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
921 /* schedule initial sym_filter_entry setup */
922 sym_filter_entry_sched = syme;
923 sym_filter = NULL;
924 }
915 925
916 for (i = 0; skip_symbols[i]; i++) { 926 for (i = 0; skip_symbols[i]; i++) {
917 if (!strcmp(skip_symbols[i], name)) { 927 if (!strcmp(skip_symbols[i], name)) {
@@ -926,15 +936,19 @@ static int symbol_filter(struct map *map, struct symbol *sym)
926 return 0; 936 return 0;
927} 937}
928 938
929static void event__process_sample(const event_t *self, int counter) 939static void event__process_sample(const event_t *self,
940 struct perf_session *session, int counter)
930{ 941{
931 u64 ip = self->ip.ip; 942 u64 ip = self->ip.ip;
932 struct sym_entry *syme; 943 struct sym_entry *syme;
933 struct addr_location al; 944 struct addr_location al;
934 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 945 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
935 946
947 ++samples;
948
936 switch (origin) { 949 switch (origin) {
937 case PERF_RECORD_MISC_USER: 950 case PERF_RECORD_MISC_USER:
951 ++userspace_samples;
938 if (hide_user_symbols) 952 if (hide_user_symbols)
939 return; 953 return;
940 break; 954 break;
@@ -946,10 +960,39 @@ static void event__process_sample(const event_t *self, int counter)
946 return; 960 return;
947 } 961 }
948 962
949 if (event__preprocess_sample(self, &al, symbol_filter) < 0 || 963 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
950 al.sym == NULL) 964 al.filtered)
951 return; 965 return;
952 966
967 if (al.sym == NULL) {
968 /*
969 * As we do lazy loading of symtabs we only will know if the
970 * specified vmlinux file is invalid when we actually have a
971 * hit in kernel space and then try to load it. So if we get
972 * here and there are _no_ symbols in the DSO backing the
973 * kernel map, bail out.
974 *
975 * We may never get here, for instance, if we use -K/
976 * --hide-kernel-symbols, even if the user specifies an
977 * invalid --vmlinux ;-)
978 */
979 if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
980 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
981 pr_err("The %s file can't be used\n",
982 symbol_conf.vmlinux_name);
983 exit(1);
984 }
985
986 return;
987 }
988
989 /* let's see, whether we need to install initial sym_filter_entry */
990 if (sym_filter_entry_sched) {
991 sym_filter_entry = sym_filter_entry_sched;
992 sym_filter_entry_sched = NULL;
993 parse_source(sym_filter_entry);
994 }
995
953 syme = symbol__priv(al.sym); 996 syme = symbol__priv(al.sym);
954 if (!syme->skip) { 997 if (!syme->skip) {
955 syme->count[counter]++; 998 syme->count[counter]++;
@@ -959,20 +1002,21 @@ static void event__process_sample(const event_t *self, int counter)
959 if (list_empty(&syme->node) || !syme->node.next) 1002 if (list_empty(&syme->node) || !syme->node.next)
960 __list_insert_active_sym(syme); 1003 __list_insert_active_sym(syme);
961 pthread_mutex_unlock(&active_symbols_lock); 1004 pthread_mutex_unlock(&active_symbols_lock);
962 if (origin == PERF_RECORD_MISC_USER)
963 ++userspace_samples;
964 ++samples;
965 } 1005 }
966} 1006}
967 1007
968static int event__process(event_t *event) 1008static int event__process(event_t *event, struct perf_session *session)
969{ 1009{
970 switch (event->header.type) { 1010 switch (event->header.type) {
971 case PERF_RECORD_COMM: 1011 case PERF_RECORD_COMM:
972 event__process_comm(event); 1012 event__process_comm(event, session);
973 break; 1013 break;
974 case PERF_RECORD_MMAP: 1014 case PERF_RECORD_MMAP:
975 event__process_mmap(event); 1015 event__process_mmap(event, session);
1016 break;
1017 case PERF_RECORD_FORK:
1018 case PERF_RECORD_EXIT:
1019 event__process_task(event, session);
976 break; 1020 break;
977 default: 1021 default:
978 break; 1022 break;
@@ -999,7 +1043,8 @@ static unsigned int mmap_read_head(struct mmap_data *md)
999 return head; 1043 return head;
1000} 1044}
1001 1045
1002static void mmap_read_counter(struct mmap_data *md) 1046static void perf_session__mmap_read_counter(struct perf_session *self,
1047 struct mmap_data *md)
1003{ 1048{
1004 unsigned int head = mmap_read_head(md); 1049 unsigned int head = mmap_read_head(md);
1005 unsigned int old = md->prev; 1050 unsigned int old = md->prev;
@@ -1052,9 +1097,9 @@ static void mmap_read_counter(struct mmap_data *md)
1052 } 1097 }
1053 1098
1054 if (event->header.type == PERF_RECORD_SAMPLE) 1099 if (event->header.type == PERF_RECORD_SAMPLE)
1055 event__process_sample(event, md->counter); 1100 event__process_sample(event, self, md->counter);
1056 else 1101 else
1057 event__process(event); 1102 event__process(event, self);
1058 old += size; 1103 old += size;
1059 } 1104 }
1060 1105
@@ -1064,13 +1109,13 @@ static void mmap_read_counter(struct mmap_data *md)
1064static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1109static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
1065static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1110static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1066 1111
1067static void mmap_read(void) 1112static void perf_session__mmap_read(struct perf_session *self)
1068{ 1113{
1069 int i, counter; 1114 int i, counter;
1070 1115
1071 for (i = 0; i < nr_cpus; i++) { 1116 for (i = 0; i < nr_cpus; i++) {
1072 for (counter = 0; counter < nr_counters; counter++) 1117 for (counter = 0; counter < nr_counters; counter++)
1073 mmap_read_counter(&mmap_array[i][counter]); 1118 perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
1074 } 1119 }
1075} 1120}
1076 1121
@@ -1084,7 +1129,7 @@ static void start_counter(int i, int counter)
1084 1129
1085 cpu = profile_cpu; 1130 cpu = profile_cpu;
1086 if (target_pid == -1 && profile_cpu == -1) 1131 if (target_pid == -1 && profile_cpu == -1)
1087 cpu = i; 1132 cpu = cpumap[i];
1088 1133
1089 attr = attrs + counter; 1134 attr = attrs + counter;
1090 1135
@@ -1155,11 +1200,18 @@ static int __cmd_top(void)
1155 pthread_t thread; 1200 pthread_t thread;
1156 int i, counter; 1201 int i, counter;
1157 int ret; 1202 int ret;
1203 /*
1204 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1205 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1206 */
1207 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
1208 if (session == NULL)
1209 return -ENOMEM;
1158 1210
1159 if (target_pid != -1) 1211 if (target_pid != -1)
1160 event__synthesize_thread(target_pid, event__process); 1212 event__synthesize_thread(target_pid, event__process, session);
1161 else 1213 else
1162 event__synthesize_threads(event__process); 1214 event__synthesize_threads(event__process, session);
1163 1215
1164 for (i = 0; i < nr_cpus; i++) { 1216 for (i = 0; i < nr_cpus; i++) {
1165 group_fd = -1; 1217 group_fd = -1;
@@ -1170,7 +1222,7 @@ static int __cmd_top(void)
1170 /* Wait for a minimal set of events before starting the snapshot */ 1222 /* Wait for a minimal set of events before starting the snapshot */
1171 poll(event_array, nr_poll, 100); 1223 poll(event_array, nr_poll, 100);
1172 1224
1173 mmap_read(); 1225 perf_session__mmap_read(session);
1174 1226
1175 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1227 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1176 printf("Could not create display thread.\n"); 1228 printf("Could not create display thread.\n");
@@ -1190,7 +1242,7 @@ static int __cmd_top(void)
1190 while (1) { 1242 while (1) {
1191 int hits = samples; 1243 int hits = samples;
1192 1244
1193 mmap_read(); 1245 perf_session__mmap_read(session);
1194 1246
1195 if (hits == samples) 1247 if (hits == samples)
1196 ret = poll(event_array, nr_poll, 100); 1248 ret = poll(event_array, nr_poll, 100);
@@ -1235,7 +1287,7 @@ static const struct option options[] = {
1235 OPT_BOOLEAN('i', "inherit", &inherit, 1287 OPT_BOOLEAN('i', "inherit", &inherit,
1236 "child tasks inherit counters"), 1288 "child tasks inherit counters"),
1237 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1289 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1238 "symbol to annotate - requires -k option"), 1290 "symbol to annotate"),
1239 OPT_BOOLEAN('z', "zero", &zero, 1291 OPT_BOOLEAN('z', "zero", &zero,
1240 "zero history across updates"), 1292 "zero history across updates"),
1241 OPT_INTEGER('F', "freq", &freq, 1293 OPT_INTEGER('F', "freq", &freq,
@@ -1271,16 +1323,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1271 1323
1272 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1324 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1273 (nr_counters + 1) * sizeof(unsigned long)); 1325 (nr_counters + 1) * sizeof(unsigned long));
1274 if (symbol_conf.vmlinux_name == NULL) 1326
1275 symbol_conf.try_vmlinux_path = true; 1327 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1276 if (symbol__init(&symbol_conf) < 0) 1328 if (symbol__init() < 0)
1277 return -1; 1329 return -1;
1278 1330
1279 if (delay_secs < 1) 1331 if (delay_secs < 1)
1280 delay_secs = 1; 1332 delay_secs = 1;
1281 1333
1282 parse_source(sym_filter_entry);
1283
1284 /* 1334 /*
1285 * User specified count overrides default frequency. 1335 * User specified count overrides default frequency.
1286 */ 1336 */
@@ -1303,12 +1353,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1303 attrs[counter].sample_period = default_interval; 1353 attrs[counter].sample_period = default_interval;
1304 } 1354 }
1305 1355
1306 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
1307 assert(nr_cpus <= MAX_NR_CPUS);
1308 assert(nr_cpus >= 0);
1309
1310 if (target_pid != -1 || profile_cpu != -1) 1356 if (target_pid != -1 || profile_cpu != -1)
1311 nr_cpus = 1; 1357 nr_cpus = 1;
1358 else
1359 nr_cpus = read_cpu_map();
1312 1360
1313 get_term_dimensions(&winsize); 1361 get_term_dimensions(&winsize);
1314 if (print_entries == 0) { 1362 if (print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0756664666f1..407041d20de0 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -12,7 +12,9 @@
12static char const *script_name; 12static char const *script_name;
13static char const *generate_script_lang; 13static char const *generate_script_lang;
14 14
15static int default_start_script(const char *script __attribute((unused))) 15static int default_start_script(const char *script __unused,
16 int argc __unused,
17 const char **argv __unused)
16{ 18{
17 return 0; 19 return 0;
18} 20}
@@ -22,7 +24,7 @@ static int default_stop_script(void)
22 return 0; 24 return 0;
23} 25}
24 26
25static int default_generate_script(const char *outfile __attribute ((unused))) 27static int default_generate_script(const char *outfile __unused)
26{ 28{
27 return 0; 29 return 0;
28} 30}
@@ -42,6 +44,7 @@ static void setup_scripting(void)
42 perf_set_argv_exec_path(perf_exec_path()); 44 perf_set_argv_exec_path(perf_exec_path());
43 45
44 setup_perl_scripting(); 46 setup_perl_scripting();
47 setup_python_scripting();
45 48
46 scripting_ops = &default_scripting_ops; 49 scripting_ops = &default_scripting_ops;
47} 50}
@@ -57,15 +60,11 @@ static int cleanup_scripting(void)
57#include "util/debug.h" 60#include "util/debug.h"
58 61
59#include "util/trace-event.h" 62#include "util/trace-event.h"
60#include "util/data_map.h"
61#include "util/exec_cmd.h" 63#include "util/exec_cmd.h"
62 64
63static char const *input_name = "perf.data"; 65static char const *input_name = "perf.data";
64 66
65static struct perf_session *session; 67static int process_sample_event(event_t *event, struct perf_session *session)
66static u64 sample_type;
67
68static int process_sample_event(event_t *event)
69{ 68{
70 struct sample_data data; 69 struct sample_data data;
71 struct thread *thread; 70 struct thread *thread;
@@ -75,22 +74,19 @@ static int process_sample_event(event_t *event)
75 data.cpu = -1; 74 data.cpu = -1;
76 data.period = 1; 75 data.period = 1;
77 76
78 event__parse_sample(event, sample_type, &data); 77 event__parse_sample(event, session->sample_type, &data);
79 78
80 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 79 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
81 event->header.misc, 80 data.pid, data.tid, data.ip, data.period);
82 data.pid, data.tid,
83 (void *)(long)data.ip,
84 (long long)data.period);
85 81
86 thread = threads__findnew(event->ip.pid); 82 thread = perf_session__findnew(session, event->ip.pid);
87 if (thread == NULL) { 83 if (thread == NULL) {
88 pr_debug("problem processing %d event, skipping it.\n", 84 pr_debug("problem processing %d event, skipping it.\n",
89 event->header.type); 85 event->header.type);
90 return -1; 86 return -1;
91 } 87 }
92 88
93 if (sample_type & PERF_SAMPLE_RAW) { 89 if (session->sample_type & PERF_SAMPLE_RAW) {
94 /* 90 /*
95 * FIXME: better resolve from pid from the struct trace_entry 91 * FIXME: better resolve from pid from the struct trace_entry
96 * field, although it should be the same than this perf 92 * field, although it should be the same than this perf
@@ -100,45 +96,19 @@ static int process_sample_event(event_t *event)
100 data.raw_size, 96 data.raw_size,
101 data.time, thread->comm); 97 data.time, thread->comm);
102 } 98 }
103 event__stats.total += data.period;
104
105 return 0;
106}
107
108static int sample_type_check(u64 type)
109{
110 sample_type = type;
111
112 if (!(sample_type & PERF_SAMPLE_RAW)) {
113 fprintf(stderr,
114 "No trace sample to read. Did you call perf record "
115 "without -R?");
116 return -1;
117 }
118 99
100 session->events_stats.total += data.period;
119 return 0; 101 return 0;
120} 102}
121 103
122static struct perf_file_handler file_handler = { 104static struct perf_event_ops event_ops = {
123 .process_sample_event = process_sample_event, 105 .sample = process_sample_event,
124 .process_comm_event = event__process_comm, 106 .comm = event__process_comm,
125 .sample_type_check = sample_type_check,
126}; 107};
127 108
128static int __cmd_trace(void) 109static int __cmd_trace(struct perf_session *session)
129{ 110{
130 int err; 111 return perf_session__process_events(session, &event_ops);
131
132 session = perf_session__new(input_name, O_RDONLY, 0);
133 if (session == NULL)
134 return -ENOMEM;
135
136 register_idle_thread();
137 register_perf_file_handler(&file_handler);
138
139 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
140 perf_session__delete(session);
141 return err;
142} 112}
143 113
144struct script_spec { 114struct script_spec {
@@ -250,9 +220,9 @@ static int parse_scriptname(const struct option *opt __used,
250 const char *script, *ext; 220 const char *script, *ext;
251 int len; 221 int len;
252 222
253 if (strcmp(str, "list") == 0) { 223 if (strcmp(str, "lang") == 0) {
254 list_available_languages(); 224 list_available_languages();
255 return 0; 225 exit(0);
256 } 226 }
257 227
258 script = strchr(str, ':'); 228 script = strchr(str, ':');
@@ -289,7 +259,245 @@ static int parse_scriptname(const struct option *opt __used,
289 return 0; 259 return 0;
290} 260}
291 261
292static const char * const annotate_usage[] = { 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)
288{
289 struct script_desc *s = zalloc(sizeof(*s));
290
291 if (s != NULL)
292 s->name = strdup(name);
293
294 return s;
295}
296
297static void script_desc__delete(struct script_desc *s)
298{
299 free(s->name);
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;
332
333out_delete_desc:
334 script_desc__delete(s);
335
336 return NULL;
337}
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;
348 }
349
350 return NULL;
351}
352
353static char *ltrim(char *str)
354{
355 int len = strlen(str);
356
357 while (len && isspace(*str)) {
358 len--;
359 str++;
360 }
361
362 return str;
363}
364
365static int read_script_info(struct script_desc *desc, const char *filename)
366{
367 char line[BUFSIZ], *p;
368 FILE *fp;
369
370 fp = fopen(filename, "r");
371 if (!fp)
372 return -1;
373
374 while (fgets(line, sizeof(line), fp)) {
375 p = ltrim(line);
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 }
399 }
400
401 fclose(fp);
402
403 return 0;
404}
405
406static int list_available_scripts(const struct option *opt __used,
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;
424
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 }
444 }
445
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 }
453
454 exit(0);
455}
456
457static char *get_script_path(const char *script_root, const char *suffix)
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 }
496
497 return path;
498}
499
500static const char * const trace_usage[] = {
293 "perf trace [<options>] <command>", 501 "perf trace [<options>] <command>",
294 NULL 502 NULL
295}; 503};
@@ -299,36 +507,81 @@ static const struct option options[] = {
299 "dump raw trace in ASCII"), 507 "dump raw trace in ASCII"),
300 OPT_BOOLEAN('v', "verbose", &verbose, 508 OPT_BOOLEAN('v', "verbose", &verbose,
301 "be more verbose (show symbol address, etc)"), 509 "be more verbose (show symbol address, etc)"),
302 OPT_BOOLEAN('l', "latency", &latency_format, 510 OPT_BOOLEAN('L', "Latency", &latency_format,
303 "show latency attributes (irqs/preemption disabled, etc)"), 511 "show latency attributes (irqs/preemption disabled, etc)"),
512 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
513 list_available_scripts),
304 OPT_CALLBACK('s', "script", NULL, "name", 514 OPT_CALLBACK('s', "script", NULL, "name",
305 "script file name (lang:script name, script name, or *)", 515 "script file name (lang:script name, script name, or *)",
306 parse_scriptname), 516 parse_scriptname),
307 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 517 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
308 "generate perf-trace.xx script in specified language"), 518 "generate perf-trace.xx script in specified language"),
519 OPT_STRING('i', "input", &input_name, "file",
520 "input file name"),
309 521
310 OPT_END() 522 OPT_END()
311}; 523};
312 524
313int cmd_trace(int argc, const char **argv, const char *prefix __used) 525int cmd_trace(int argc, const char **argv, const char *prefix __used)
314{ 526{
315 int err; 527 struct perf_session *session;
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 }
316 541
317 symbol__init(0); 542 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
543 if (argc < 3) {
544 fprintf(stderr,
545 "Please specify a report script\n");
546 return -1;
547 }
548 suffix = REPORT_SUFFIX;
549 }
318 550
319 setup_scripting(); 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 }
320 557
321 argc = parse_options(argc, argv, options, annotate_usage, 0); 558 __argv = malloc((argc + 1) * sizeof(const char *));
322 if (argc) { 559 __argv[0] = "/bin/sh";
323 /* 560 __argv[1] = script_path;
324 * Special case: if there's an argument left then assume tha 561 for (i = 3; i < argc; i++)
325 * it's a symbol filter: 562 __argv[i - 1] = argv[i];
326 */ 563 __argv[argc - 1] = NULL;
327 if (argc > 1) 564
328 usage_with_options(annotate_usage, options); 565 execvp("/bin/sh", (char **)__argv);
566 exit(-1);
329 } 567 }
330 568
331 setup_pager(); 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;
332 585
333 if (generate_script_lang) { 586 if (generate_script_lang) {
334 struct stat perf_stat; 587 struct stat perf_stat;
@@ -356,19 +609,19 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
356 return -1; 609 return -1;
357 } 610 }
358 611
359 perf_header__read(&session->header, input);
360 err = scripting_ops->generate_script("perf-trace"); 612 err = scripting_ops->generate_script("perf-trace");
361 goto out; 613 goto out;
362 } 614 }
363 615
364 if (script_name) { 616 if (script_name) {
365 err = scripting_ops->start_script(script_name); 617 err = scripting_ops->start_script(script_name, argc, argv);
366 if (err) 618 if (err)
367 goto out; 619 goto out;
368 } 620 }
369 621
370 err = __cmd_trace(); 622 err = __cmd_trace(session);
371 623
624 perf_session__delete(session);
372 cleanup_scripting(); 625 cleanup_scripting();
373out: 626out:
374 return err; 627 return err;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index a3d8bf65f26c..10fe49e7048a 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,7 +16,9 @@ extern 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); 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);
19extern int cmd_buildid_list(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);
20extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern int cmd_help(int argc, const char **argv, const char *prefix);
21extern int cmd_sched(int argc, const char **argv, const char *prefix); 23extern int cmd_sched(int argc, const char **argv, const char *prefix);
22extern int cmd_list(int argc, const char **argv, const char *prefix); 24extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -29,5 +31,6 @@ extern int cmd_trace(int argc, const char **argv, const char *prefix);
29extern int cmd_version(int argc, const char **argv, const char *prefix); 31extern int cmd_version(int argc, const char **argv, const char *prefix);
30extern int cmd_probe(int argc, const char **argv, const char *prefix); 32extern int cmd_probe(int argc, const char **argv, const char *prefix);
31extern int cmd_kmem(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);
32 35
33#endif 36#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 02b09ea17a3e..db6ee94d4a8e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,8 +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
6perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
7perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-diff mainporcelain common
8perf-list mainporcelain common 11perf-list mainporcelain common
9perf-sched mainporcelain common 12perf-sched mainporcelain common
10perf-record mainporcelain common 13perf-record mainporcelain common
@@ -15,3 +18,4 @@ perf-top mainporcelain common
15perf-trace mainporcelain common 18perf-trace mainporcelain common
16perf-probe mainporcelain common 19perf-probe mainporcelain common
17perf-kmem mainporcelain common 20perf-kmem mainporcelain common
21perf-lock mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index f000c30877ac..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,8 +131,8 @@ 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,
@@ -399,7 +399,7 @@ Notification of new events is possible through poll()/select()/epoll() and
399fcntl() managing signals. 399fcntl() managing signals.
400 400
401Normally a notification is generated for every page filled, however one can 401Normally a notification is generated for every page filled, however one can
402additionally set perf_event_hw_event.wakeup_events to generate one every 402additionally set perf_event_attr.wakeup_events to generate one every
403so many counter overflow events. 403so many counter overflow events.
404 404
405Future work will include a splice() interface to the ring-buffer. 405Future work will include a splice() interface to the ring-buffer.
diff --git a/tools/perf/perf-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 cf64049bc9bd..cd32c200cdb3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -48,7 +48,8 @@ int check_pager_config(const char *cmd)
48 return c.val; 48 return c.val;
49} 49}
50 50
51static void commit_pager_choice(void) { 51static void commit_pager_choice(void)
52{
52 switch (use_pager) { 53 switch (use_pager) {
53 case 0: 54 case 0:
54 setenv("PERF_PAGER", "cat", 1); 55 setenv("PERF_PAGER", "cat", 1);
@@ -70,7 +71,7 @@ static void set_debugfs_path(void)
70 "tracing/events"); 71 "tracing/events");
71} 72}
72 73
73static int handle_options(const char*** argv, int* argc, int* envchanged) 74static int handle_options(const char ***argv, int *argc, int *envchanged)
74{ 75{
75 int handled = 0; 76 int handled = 0;
76 77
@@ -109,7 +110,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
109 *envchanged = 1; 110 *envchanged = 1;
110 } else if (!strcmp(cmd, "--perf-dir")) { 111 } else if (!strcmp(cmd, "--perf-dir")) {
111 if (*argc < 2) { 112 if (*argc < 2) {
112 fprintf(stderr, "No directory given for --perf-dir.\n" ); 113 fprintf(stderr, "No directory given for --perf-dir.\n");
113 usage(perf_usage_string); 114 usage(perf_usage_string);
114 } 115 }
115 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); 116 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
@@ -124,7 +125,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
124 *envchanged = 1; 125 *envchanged = 1;
125 } else if (!strcmp(cmd, "--work-tree")) { 126 } else if (!strcmp(cmd, "--work-tree")) {
126 if (*argc < 2) { 127 if (*argc < 2) {
127 fprintf(stderr, "No directory given for --work-tree.\n" ); 128 fprintf(stderr, "No directory given for --work-tree.\n");
128 usage(perf_usage_string); 129 usage(perf_usage_string);
129 } 130 }
130 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); 131 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
@@ -168,7 +169,7 @@ static int handle_alias(int *argcp, const char ***argv)
168{ 169{
169 int envchanged = 0, ret = 0, saved_errno = errno; 170 int envchanged = 0, ret = 0, saved_errno = errno;
170 int count, option_count; 171 int count, option_count;
171 const char** new_argv; 172 const char **new_argv;
172 const char *alias_command; 173 const char *alias_command;
173 char *alias_string; 174 char *alias_string;
174 175
@@ -210,11 +211,11 @@ static int handle_alias(int *argcp, const char ***argv)
210 if (!strcmp(alias_command, new_argv[0])) 211 if (!strcmp(alias_command, new_argv[0]))
211 die("recursive alias: %s", alias_command); 212 die("recursive alias: %s", alias_command);
212 213
213 new_argv = realloc(new_argv, sizeof(char*) * 214 new_argv = realloc(new_argv, sizeof(char *) *
214 (count + *argcp + 1)); 215 (count + *argcp + 1));
215 /* insert after command name */ 216 /* insert after command name */
216 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); 217 memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
217 new_argv[count+*argcp] = NULL; 218 new_argv[count + *argcp] = NULL;
218 219
219 *argv = new_argv; 220 *argv = new_argv;
220 *argcp += count - 1; 221 *argcp += count - 1;
@@ -285,7 +286,9 @@ static void handle_internal_command(int argc, const char **argv)
285{ 286{
286 const char *cmd = argv[0]; 287 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 288 static struct cmd_struct commands[] = {
289 { "buildid-cache", cmd_buildid_cache, 0 },
288 { "buildid-list", cmd_buildid_list, 0 }, 290 { "buildid-list", cmd_buildid_list, 0 },
291 { "diff", cmd_diff, 0 },
289 { "help", cmd_help, 0 }, 292 { "help", cmd_help, 0 },
290 { "list", cmd_list, 0 }, 293 { "list", cmd_list, 0 },
291 { "record", cmd_record, 0 }, 294 { "record", cmd_record, 0 },
@@ -300,6 +303,7 @@ static void handle_internal_command(int argc, const char **argv)
300 { "sched", cmd_sched, 0 }, 303 { "sched", cmd_sched, 0 },
301 { "probe", cmd_probe, 0 }, 304 { "probe", cmd_probe, 0 },
302 { "kmem", cmd_kmem, 0 }, 305 { "kmem", cmd_kmem, 0 },
306 { "lock", cmd_lock, 0 },
303 }; 307 };
304 unsigned int i; 308 unsigned int i;
305 static const char ext[] = STRIP_EXTENSION; 309 static const char ext[] = STRIP_EXTENSION;
@@ -387,7 +391,7 @@ static int run_argv(int *argcp, const char ***argv)
387/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 391/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
388static void get_debugfs_mntpt(void) 392static void get_debugfs_mntpt(void)
389{ 393{
390 const char *path = debugfs_find_mountpoint(); 394 const char *path = debugfs_mount(NULL);
391 395
392 if (path) 396 if (path)
393 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); 397 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
@@ -441,15 +445,15 @@ int main(int argc, const char **argv)
441 445
442 /* 446 /*
443 * 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
444 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 448 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
445 * environment, and the $(perfexecdir) from the Makefile at build 449 * environment, and the $(perfexecdir) from the Makefile at build
446 * time. 450 * time.
447 */ 451 */
448 setup_path(); 452 setup_path();
449 453
450 while (1) { 454 while (1) {
451 static int done_help = 0; 455 static int done_help;
452 static int was_alias = 0; 456 static int was_alias;
453 457
454 was_alias = run_argv(&argc, &argv); 458 was_alias = run_argv(&argc, &argv);
455 if (errno != ENOENT) 459 if (errno != ENOENT)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 75f941bfba9e..6fb379bc1d1f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -65,9 +65,7 @@
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See 65 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details. 66 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */ 67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \ 68#define rmb() ((void(*)(void))0xffff0fa0)()
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory") 69#define cpu_relax() asm volatile("":::"memory")
72#endif 70#endif
73 71
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
index af78d9a52a7d..01a64ad693f2 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -31,13 +31,14 @@
31#include "EXTERN.h" 31#include "EXTERN.h"
32#include "perl.h" 32#include "perl.h"
33#include "XSUB.h" 33#include "XSUB.h"
34#include "../../../util/trace-event-perl.h" 34#include "../../../perf.h"
35#include "../../../util/trace-event.h"
35 36
36#ifndef PERL_UNUSED_VAR 37#ifndef PERL_UNUSED_VAR
37# define PERL_UNUSED_VAR(var) if (0) var = var 38# define PERL_UNUSED_VAR(var) if (0) var = var
38#endif 39#endif
39 40
40#line 41 "Context.c" 41#line 42 "Context.c"
41 42
42XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */ 43XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
43XS(XS_Perf__Trace__Context_common_pc) 44XS(XS_Perf__Trace__Context_common_pc)
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
index fb78006c165e..549cf0467d30 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -22,7 +22,8 @@
22#include "EXTERN.h" 22#include "EXTERN.h"
23#include "perl.h" 23#include "perl.h"
24#include "XSUB.h" 24#include "XSUB.h"
25#include "../../../util/trace-event-perl.h" 25#include "../../../perf.h"
26#include "../../../util/trace-event.h"
26 27
27MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context 28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
28PROTOTYPES: ENABLE 29PROTOTYPES: ENABLE
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
index 052f132ced24..f869c48dc9b0 100644
--- 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
@@ -44,7 +44,7 @@ sub nsecs_secs {
44sub nsecs_nsecs { 44sub nsecs_nsecs {
45 my ($nsecs) = @_; 45 my ($nsecs) = @_;
46 46
47 return $nsecs - nsecs_secs($nsecs); 47 return $nsecs % $NSECS_PER_SEC;
48} 48}
49 49
50sub nsecs_str { 50sub nsecs_str {
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
index c7ec5de2f535..e6cb1474f8e8 100644
--- a/tools/perf/scripts/perl/bin/check-perf-trace-record
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-record
@@ -1,7 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry 2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree
3
4
5
6
7
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
deleted file mode 100644
index 89948b015020..000000000000
--- a/tools/perf/scripts/perl/bin/check-perf-trace-report
+++ /dev/null
@@ -1,5 +0,0 @@
1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
3
4
5
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-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index f5dcf9cb5bd2..eddb9ccce6a5 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -1,5 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl 2# description: r/w activity for a program, by file
3# args: <comm>
4perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1
3 5
4 6
5 7
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index cea16f78a3a2..7f44c25cc857 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index 85769dc456eb..fce3adcb3249 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency
2perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index aa68435be926..71cfbd182fb9 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
2perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/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
index 61f91561d848..2a39097687b9 100644
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -18,8 +18,9 @@ use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20 20
21# change this to the comm of the program you're interested in 21my $usage = "perf trace -s rw-by-file.pl <comm>\n";
22my $for_comm = "perf"; 22
23my $for_comm = shift or die $usage;
23 24
24my %reads; 25my %reads;
25my %writes; 26my %writes;
diff --git a/tools/perf/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/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644
index 000000000000..4e01490e51e5
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,59 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7int cpumap[MAX_NR_CPUS];
8
9static int default_cpu_map(void)
10{
11 int nr_cpus, i;
12
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS);
15 assert((int)nr_cpus >= 0);
16
17 for (i = 0; i < nr_cpus; ++i)
18 cpumap[i] = i;
19
20 return nr_cpus;
21}
22
23int read_cpu_map(void)
24{
25 FILE *onlnf;
26 int nr_cpus = 0;
27 int n, cpu, prev;
28 char sep;
29
30 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf)
32 return default_cpu_map();
33
34 sep = 0;
35 prev = -1;
36 for (;;) {
37 n = fscanf(onlnf, "%u%c", &cpu, &sep);
38 if (n <= 0)
39 break;
40 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
42 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev;
44 }
45 assert (nr_cpus < MAX_NR_CPUS);
46 cpumap[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-')
48 prev = cpu;
49 else
50 prev = -1;
51 if (n == 1 || sep == '\n')
52 break;
53 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57
58 return default_cpu_map();
59}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..86c78bb33098
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4extern int read_cpu_map(void);
5extern int cpumap[];
6
7#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index 6d46dda53a29..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,242 +0,0 @@
1#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{
13 dump_printf(": unhandled!\n");
14 return 0;
15}
16
17void register_perf_file_handler(struct perf_file_handler *handler)
18{
19 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub;
21 if (!handler->process_mmap_event)
22 handler->process_mmap_event = process_event_stub;
23 if (!handler->process_comm_event)
24 handler->process_comm_event = process_event_stub;
25 if (!handler->process_fork_event)
26 handler->process_fork_event = process_event_stub;
27 if (!handler->process_exit_event)
28 handler->process_exit_event = process_event_stub;
29 if (!handler->process_lost_event)
30 handler->process_lost_event = process_event_stub;
31 if (!handler->process_read_event)
32 handler->process_read_event = process_event_stub;
33 if (!handler->process_throttle_event)
34 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39}
40
41static const char *event__name[] = {
42 [0] = "TOTAL",
43 [PERF_RECORD_MMAP] = "MMAP",
44 [PERF_RECORD_LOST] = "LOST",
45 [PERF_RECORD_COMM] = "COMM",
46 [PERF_RECORD_EXIT] = "EXIT",
47 [PERF_RECORD_THROTTLE] = "THROTTLE",
48 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
49 [PERF_RECORD_FORK] = "FORK",
50 [PERF_RECORD_READ] = "READ",
51 [PERF_RECORD_SAMPLE] = "SAMPLE",
52};
53
54unsigned long event__total[PERF_RECORD_MAX];
55
56void event__print_totals(void)
57{
58 int i;
59 for (i = 0; i < PERF_RECORD_MAX; ++i)
60 pr_info("%10s events: %10ld\n",
61 event__name[i], event__total[i]);
62}
63
64static int
65process_event(event_t *event, unsigned long offset, unsigned long head)
66{
67 trace_event(event);
68
69 if (event->header.type < PERF_RECORD_MAX) {
70 dump_printf("%p [%p]: PERF_RECORD_%s",
71 (void *)(offset + head),
72 (void *)(long)(event->header.size),
73 event__name[event->header.type]);
74 ++event__total[0];
75 ++event__total[event->header.type];
76 }
77
78 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event);
81 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event);
83 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event);
85 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event);
87 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event);
89 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event);
91 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event);
93 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event);
95 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event);
97 default:
98 curr_handler->total_unknown++;
99 return -1;
100 }
101}
102
103int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{
105 struct build_id_event bev;
106 char filename[PATH_MAX];
107 u64 limit = offset + size;
108 int err = -1;
109
110 while (offset < limit) {
111 struct dso *dso;
112 ssize_t len;
113
114 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
115 goto out;
116
117 len = bev.header.size - sizeof(bev);
118 if (read(input, filename, len) != len)
119 goto out;
120
121 dso = dsos__findnew(filename);
122 if (dso != NULL)
123 dso__set_build_id(dso, &bev.build_id);
124
125 offset += bev.header.size;
126 }
127 err = 0;
128out:
129 return err;
130}
131
132int perf_session__process_events(struct perf_session *self,
133 int full_paths, int *cwdlen, char **cwd)
134{
135 int err;
136 unsigned long head, shift;
137 unsigned long offset = 0;
138 size_t page_size;
139 u64 sample_type;
140 event_t *event;
141 uint32_t size;
142 char *buf;
143
144 if (curr_handler == NULL) {
145 pr_debug("Forgot to register perf file handler\n");
146 return -EINVAL;
147 }
148
149 page_size = getpagesize();
150
151 head = self->header.data_offset;
152 sample_type = perf_header__sample_type(&self->header);
153
154 err = -EINVAL;
155 if (curr_handler->sample_type_check &&
156 curr_handler->sample_type_check(sample_type) < 0)
157 goto out_err;
158
159 if (!full_paths) {
160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
161 pr_err("failed to get the current directory\n");
162 err = -errno;
163 goto out_err;
164 }
165 *cwd = __cwd;
166 *cwdlen = strlen(*cwd);
167 } else {
168 *cwd = NULL;
169 *cwdlen = 0;
170 }
171
172 shift = page_size * (head / page_size);
173 offset += shift;
174 head -= shift;
175
176remap:
177 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
178 MAP_SHARED, self->fd, offset);
179 if (buf == MAP_FAILED) {
180 pr_err("failed to mmap file\n");
181 err = -errno;
182 goto out_err;
183 }
184
185more:
186 event = (event_t *)(buf + head);
187
188 size = event->header.size;
189 if (!size)
190 size = 8;
191
192 if (head + event->header.size >= page_size * mmap_window) {
193 int munmap_ret;
194
195 shift = page_size * (head / page_size);
196
197 munmap_ret = munmap(buf, page_size * mmap_window);
198 assert(munmap_ret == 0);
199
200 offset += shift;
201 head -= shift;
202 goto remap;
203 }
204
205 size = event->header.size;
206
207 dump_printf("\n%p [%p]: event: %d\n",
208 (void *)(offset + head),
209 (void *)(long)event->header.size,
210 event->header.type);
211
212 if (!size || process_event(event, offset, head) < 0) {
213
214 dump_printf("%p [%p]: skipping unknown header type: %d\n",
215 (void *)(offset + head),
216 (void *)(long)(event->header.size),
217 event->header.type);
218
219 /*
220 * assume we lost track of the stream, check alignment, and
221 * increment a single u64 in the hope to catch on again 'soon'.
222 */
223
224 if (unlikely(head & 7))
225 head &= ~7ULL;
226
227 size = 8;
228 }
229
230 head += size;
231
232 if (offset + head >= self->header.data_offset + self->header.data_size)
233 goto done;
234
235 if (offset + head < self->size)
236 goto more;
237
238done:
239 err = 0;
240out_err:
241 return err;
242}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
deleted file mode 100644
index 98c5b823388c..000000000000
--- a/tools/perf/util/data_map.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6#include "session.h"
7
8typedef int (*event_type_handler_t)(event_t *);
9
10struct perf_file_handler {
11 event_type_handler_t process_sample_event;
12 event_type_handler_t process_mmap_event;
13 event_type_handler_t process_comm_event;
14 event_type_handler_t process_fork_event;
15 event_type_handler_t process_exit_event;
16 event_type_handler_t process_lost_event;
17 event_type_handler_t process_read_event;
18 event_type_handler_t process_throttle_event;
19 event_type_handler_t process_unthrottle_event;
20 int (*sample_type_check)(u64 sample_type);
21 unsigned long total_unknown;
22};
23
24void register_perf_file_handler(struct perf_file_handler *handler);
25int perf_session__process_events(struct perf_session *self,
26 int full_paths, int *cwdlen, char **cwd);
27int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
28
29#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..0905600c3851 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -9,6 +9,7 @@
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;
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ba0de90cd3d4..705ec63548b4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,11 +1,15 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h"
4#include "string.h" 6#include "string.h"
7#include "strlist.h"
5#include "thread.h" 8#include "thread.h"
6 9
7static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event)) 11 event__handler_t process,
12 struct perf_session *session)
9{ 13{
10 event_t ev; 14 event_t ev;
11 char filename[PATH_MAX]; 15 char filename[PATH_MAX];
@@ -54,7 +58,7 @@ out_race:
54 if (!full) { 58 if (!full) {
55 ev.comm.tid = pid; 59 ev.comm.tid = pid;
56 60
57 process(&ev); 61 process(&ev, session);
58 goto out_fclose; 62 goto out_fclose;
59 } 63 }
60 64
@@ -72,7 +76,7 @@ out_race:
72 76
73 ev.comm.tid = pid; 77 ev.comm.tid = pid;
74 78
75 process(&ev); 79 process(&ev, session);
76 } 80 }
77 closedir(tasks); 81 closedir(tasks);
78 82
@@ -86,7 +90,8 @@ out_failure:
86} 90}
87 91
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 92static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event)) 93 event__handler_t process,
94 struct perf_session *session)
90{ 95{
91 char filename[PATH_MAX]; 96 char filename[PATH_MAX];
92 FILE *fp; 97 FILE *fp;
@@ -105,7 +110,10 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
105 while (1) { 110 while (1) {
106 char bf[BUFSIZ], *pbf = bf; 111 char bf[BUFSIZ], *pbf = bf;
107 event_t ev = { 112 event_t ev = {
108 .header = { .type = PERF_RECORD_MMAP }, 113 .header = {
114 .type = PERF_RECORD_MMAP,
115 .misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
116 },
109 }; 117 };
110 int n; 118 int n;
111 size_t size; 119 size_t size;
@@ -141,7 +149,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
141 ev.mmap.pid = tgid; 149 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid; 150 ev.mmap.tid = pid;
143 151
144 process(&ev); 152 process(&ev, session);
145 } 153 }
146 } 154 }
147 155
@@ -149,15 +157,48 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
149 return 0; 157 return 0;
150} 158}
151 159
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) 160int event__synthesize_modules(event__handler_t process,
161 struct perf_session *session)
153{ 162{
154 pid_t tgid = event__synthesize_comm(pid, 1, process); 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);
155 if (tgid == -1) 195 if (tgid == -1)
156 return -1; 196 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process); 197 return event__synthesize_mmap_events(pid, tgid, process, session);
158} 198}
159 199
160void event__synthesize_threads(int (*process)(event_t *event)) 200void event__synthesize_threads(event__handler_t process,
201 struct perf_session *session)
161{ 202{
162 DIR *proc; 203 DIR *proc;
163 struct dirent dirent, *next; 204 struct dirent dirent, *next;
@@ -171,24 +212,100 @@ void event__synthesize_threads(int (*process)(event_t *event))
171 if (*end) /* only interested in proper numerical dirents */ 212 if (*end) /* only interested in proper numerical dirents */
172 continue; 213 continue;
173 214
174 event__synthesize_thread(pid, process); 215 event__synthesize_thread(pid, process, session);
175 } 216 }
176 217
177 closedir(proc); 218 closedir(proc);
178} 219}
179 220
180char *event__cwd; 221struct process_symbol_args {
181int event__cwdlen; 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);
182 298
183struct events_stats event__stats; 299 return 0;
300}
184 301
185int event__process_comm(event_t *self) 302int event__process_comm(event_t *self, struct perf_session *session)
186{ 303{
187 struct thread *thread = threads__findnew(self->comm.pid); 304 struct thread *thread = perf_session__findnew(session, self->comm.pid);
188 305
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 306 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 307
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 308 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 309 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1; 310 return -1;
194 } 311 }
@@ -196,38 +313,104 @@ int event__process_comm(event_t *self)
196 return 0; 313 return 0;
197} 314}
198 315
199int event__process_lost(event_t *self) 316int event__process_lost(event_t *self, struct perf_session *session)
200{ 317{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 318 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost; 319 session->events_stats.lost += self->lost.lost;
203 return 0; 320 return 0;
204} 321}
205 322
206int event__process_mmap(event_t *self) 323int event__process_mmap(event_t *self, struct perf_session *session)
207{ 324{
208 struct thread *thread = threads__findnew(self->mmap.pid); 325 struct thread *thread;
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 326 struct map *map;
210 event__cwd, event__cwdlen); 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 }
211 394
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 395 thread = perf_session__findnew(session, self->mmap.pid);
213 self->mmap.pid, self->mmap.tid, 396 map = map__new(&self->mmap, MAP__FUNCTION,
214 (void *)(long)self->mmap.start, 397 session->cwd, session->cwdlen);
215 (void *)(long)self->mmap.len,
216 (void *)(long)self->mmap.pgoff,
217 self->mmap.filename);
218 398
219 if (thread == NULL || map == NULL) 399 if (thread == NULL || map == NULL)
220 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 400 goto out_problem;
221 else
222 thread__insert_map(thread, map);
223 401
402 thread__insert_map(thread, map);
403 return 0;
404
405out_problem:
406 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
224 return 0; 407 return 0;
225} 408}
226 409
227int event__process_task(event_t *self) 410int event__process_task(event_t *self, struct perf_session *session)
228{ 411{
229 struct thread *thread = threads__findnew(self->fork.pid); 412 struct thread *thread = perf_session__findnew(session, self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid); 413 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
231 414
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 415 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid); 416 self->fork.ppid, self->fork.ptid);
@@ -249,25 +432,24 @@ int event__process_task(event_t *self)
249 return 0; 432 return 0;
250} 433}
251 434
252void thread__find_addr_location(struct thread *self, u8 cpumode, 435void thread__find_addr_map(struct thread *self,
253 enum map_type type, u64 addr, 436 struct perf_session *session, u8 cpumode,
254 struct addr_location *al, 437 enum map_type type, u64 addr,
255 symbol_filter_t filter) 438 struct addr_location *al)
256{ 439{
257 struct map_groups *mg = &self->mg; 440 struct map_groups *mg = &self->mg;
258 441
259 al->thread = self; 442 al->thread = self;
260 al->addr = addr; 443 al->addr = addr;
261 444
262 if (cpumode & PERF_RECORD_MISC_KERNEL) { 445 if (cpumode == PERF_RECORD_MISC_KERNEL) {
263 al->level = 'k'; 446 al->level = 'k';
264 mg = kmaps; 447 mg = &session->kmaps;
265 } else if (cpumode & PERF_RECORD_MISC_USER) 448 } else if (cpumode == PERF_RECORD_MISC_USER)
266 al->level = '.'; 449 al->level = '.';
267 else { 450 else {
268 al->level = 'H'; 451 al->level = 'H';
269 al->map = NULL; 452 al->map = NULL;
270 al->sym = NULL;
271 return; 453 return;
272 } 454 }
273try_again: 455try_again:
@@ -282,33 +464,83 @@ try_again:
282 * "[vdso]" dso, but for now lets use the old trick of looking 464 * "[vdso]" dso, but for now lets use the old trick of looking
283 * in the whole kernel symbol list. 465 * in the whole kernel symbol list.
284 */ 466 */
285 if ((long long)al->addr < 0 && mg != kmaps) { 467 if ((long long)al->addr < 0 && mg != &session->kmaps) {
286 mg = kmaps; 468 mg = &session->kmaps;
287 goto try_again; 469 goto try_again;
288 } 470 }
289 al->sym = NULL; 471 } else
290 } else {
291 al->addr = al->map->map_ip(al->map, al->addr); 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)
292 al->sym = map__find_symbol(al->map, al->addr, filter); 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;
293 } 496 }
497
498 self->slen_calculated = 1;
294} 499}
295 500
296int event__preprocess_sample(const event_t *self, struct addr_location *al, 501int event__preprocess_sample(const event_t *self, struct perf_session *session,
297 symbol_filter_t filter) 502 struct addr_location *al, symbol_filter_t filter)
298{ 503{
299 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 504 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
300 struct thread *thread = threads__findnew(self->ip.pid); 505 struct thread *thread = perf_session__findnew(session, self->ip.pid);
301 506
302 if (thread == NULL) 507 if (thread == NULL)
303 return -1; 508 return -1;
304 509
510 if (symbol_conf.comm_list &&
511 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
512 goto out_filtered;
513
305 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 514 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
306 515
307 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 516 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
308 self->ip.ip, al, filter); 517 self->ip.ip, al, filter);
309 dump_printf(" ...... dso: %s\n", 518 dump_printf(" ...... dso: %s\n",
310 al->map ? al->map->dso->long_name : 519 al->map ? al->map->dso->long_name :
311 al->level == 'H' ? "[hypervisor]" : "<not found>"); 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;
312 return 0; 544 return 0;
313} 545}
314 546
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 51a96c2effde..a33b94952e34 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -95,83 +95,43 @@ typedef union event_union {
95} event_t; 95} event_t;
96 96
97struct events_stats { 97struct events_stats {
98 unsigned long total; 98 u64 total;
99 unsigned long lost; 99 u64 lost;
100};
101
102struct event_stat_id {
103 struct rb_node rb_node;
104 struct rb_root hists;
105 struct events_stats stats;
106 u64 config;
107 u64 event_stream;
108 u32 type;
100}; 109};
101 110
102void event__print_totals(void); 111void event__print_totals(void);
103 112
104enum map_type { 113struct perf_session;
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108 114
109#define MAP__NR_TYPES (MAP__VARIABLE + 1) 115typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
110 116
111struct map { 117int event__synthesize_thread(pid_t pid, event__handler_t process,
112 union { 118 struct perf_session *session);
113 struct rb_node rb_node; 119void event__synthesize_threads(event__handler_t process,
114 struct list_head node; 120 struct perf_session *session);
115 }; 121int event__synthesize_kernel_mmap(event__handler_t process,
116 u64 start; 122 struct perf_session *session,
117 u64 end; 123 const char *symbol_name);
118 enum map_type type; 124int event__synthesize_modules(event__handler_t process,
119 u64 pgoff; 125 struct perf_session *session);
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123};
124 126
125static inline u64 map__map_ip(struct map *map, u64 ip) 127int event__process_comm(event_t *self, struct perf_session *session);
126{ 128int event__process_lost(event_t *self, struct perf_session *session);
127 return ip - map->start + map->pgoff; 129int event__process_mmap(event_t *self, struct perf_session *session);
128} 130int event__process_task(event_t *self, struct perf_session *session);
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152struct symbol *map__find_symbol(struct map *self, u64 addr,
153 symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
155 symbol_filter_t filter);
156void map__fixup_start(struct map *self);
157void map__fixup_end(struct map *self);
158
159int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
160void event__synthesize_threads(int (*process)(event_t *event));
161
162extern char *event__cwd;
163extern int event__cwdlen;
164extern struct events_stats event__stats;
165extern unsigned long event__total[PERF_RECORD_MAX];
166
167int event__process_comm(event_t *self);
168int event__process_lost(event_t *self);
169int event__process_mmap(event_t *self);
170int event__process_task(event_t *self);
171 131
172struct addr_location; 132struct addr_location;
173int event__preprocess_sample(const event_t *self, struct addr_location *al, 133int event__preprocess_sample(const event_t *self, struct perf_session *session,
174 symbol_filter_t filter); 134 struct addr_location *al, symbol_filter_t filter);
175int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 135int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
176 136
177#endif /* __PERF_RECORD_H */ 137#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f2e8d8715111..6c9aa16ee51f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,15 +1,19 @@
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>
5#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h>
6 10
7#include "util.h" 11#include "util.h"
8#include "header.h" 12#include "header.h"
9#include "../perf.h" 13#include "../perf.h"
10#include "trace-event.h" 14#include "trace-event.h"
15#include "session.h"
11#include "symbol.h" 16#include "symbol.h"
12#include "data_map.h"
13#include "debug.h" 17#include "debug.h"
14 18
15/* 19/*
@@ -105,24 +109,28 @@ struct perf_trace_event_type {
105static int event_count; 109static int event_count;
106static struct perf_trace_event_type *events; 110static struct perf_trace_event_type *events;
107 111
108void perf_header__push_event(u64 id, const char *name) 112int perf_header__push_event(u64 id, const char *name)
109{ 113{
110 if (strlen(name) > MAX_EVENT_NAME) 114 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 115 pr_warning("Event %s will be truncated\n", name);
112 116
113 if (!events) { 117 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 118 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 119 if (events == NULL)
116 die("nomem"); 120 return -ENOMEM;
117 } else { 121 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 122 struct perf_trace_event_type *nevents;
119 if (!events) 123
120 die("nomem"); 124 nevents = realloc(events, (event_count + 1) * sizeof(*events));
125 if (nevents == NULL)
126 return -ENOMEM;
127 events = nevents;
121 } 128 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 129 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 130 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 131 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 132 event_count++;
133 return 0;
126} 134}
127 135
128char *perf_header__find_event(u64 id) 136char *perf_header__find_event(u64 id)
@@ -169,31 +177,48 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 177 return 0;
170} 178}
171 179
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
173{ 184{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 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}
177 193
178 list_for_each_entry(pos, head, node) { 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) {
179 int err; 205 int err;
180 struct build_id_event b; 206 struct build_id_event b;
181 size_t len; 207 size_t len;
182 208
183 if (!pos->has_build_id) 209 if (!pos->hit)
184 continue; 210 continue;
185 len = pos->long_name_len + 1; 211 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 212 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 213 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 214 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
215 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 216 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 217 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 218 if (err < 0)
192 return err; 219 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 220 err = write_padded(fd, pos->long_name,
194 if (err < 0) 221 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 222 if (err < 0)
198 return err; 223 return err;
199 } 224 }
@@ -203,12 +228,143 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
203 228
204static int dsos__write_buildid_table(int fd) 229static int dsos__write_buildid_table(int fd)
205{ 230{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 231 int err = __dsos__write_buildid_table(&dsos__kernel,
232 PERF_RECORD_MISC_KERNEL, fd);
207 if (err == 0) 233 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 234 err = __dsos__write_buildid_table(&dsos__user,
235 PERF_RECORD_MISC_USER, fd);
209 return err; 236 return err;
210} 237}
211 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
212static int perf_header__adds_write(struct perf_header *self, int fd) 368static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 369{
214 int nr_sections; 370 int nr_sections;
@@ -217,7 +373,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
217 u64 sec_start; 373 u64 sec_start;
218 int idx = 0, err; 374 int idx = 0, err;
219 375
220 if (dsos__read_build_ids()) 376 if (dsos__read_build_ids(true))
221 perf_header__set_feat(self, HEADER_BUILD_ID); 377 perf_header__set_feat(self, HEADER_BUILD_ID);
222 378
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 379 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -257,7 +413,9 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
257 pr_debug("failed to write buildid table\n"); 413 pr_debug("failed to write buildid table\n");
258 goto out_free; 414 goto out_free;
259 } 415 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 416 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
417 buildid_sec->offset;
418 dsos__cache_build_ids();
261 } 419 }
262 420
263 lseek(fd, sec_start, SEEK_SET); 421 lseek(fd, sec_start, SEEK_SET);
@@ -360,30 +518,43 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 518 return 0;
361} 519}
362 520
363static void do_read(int fd, void *buf, size_t size) 521static int do_read(int fd, void *buf, size_t size)
364{ 522{
365 while (size) { 523 while (size) {
366 int ret = read(fd, buf, size); 524 int ret = read(fd, buf, size);
367 525
368 if (ret < 0) 526 if (ret <= 0)
369 die("failed to read"); 527 return -1;
370 if (ret == 0)
371 die("failed to read: missing data");
372 528
373 size -= ret; 529 size -= ret;
374 buf += ret; 530 buf += ret;
375 } 531 }
532
533 return 0;
534}
535
536static int perf_header__getbuffer64(struct perf_header *self,
537 int fd, void *buf, size_t size)
538{
539 if (do_read(fd, buf, size))
540 return -1;
541
542 if (self->needs_swap)
543 mem_bswap_64(buf, size);
544
545 return 0;
376} 546}
377 547
378int perf_header__process_sections(struct perf_header *self, int fd, 548int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 549 int (*process)(struct perf_file_section *self,
550 struct perf_header *ph,
380 int feat, int fd)) 551 int feat, int fd))
381{ 552{
382 struct perf_file_section *feat_sec; 553 struct perf_file_section *feat_sec;
383 int nr_sections; 554 int nr_sections;
384 int sec_size; 555 int sec_size;
385 int idx = 0; 556 int idx = 0;
386 int err = 0, feat = 1; 557 int err = -1, feat = 1;
387 558
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 559 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 560 if (!nr_sections)
@@ -397,33 +568,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 568
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 569 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 570
400 do_read(fd, feat_sec, sec_size); 571 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
572 goto out_free;
401 573
574 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 575 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 576 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 577 struct perf_file_section *sec = &feat_sec[idx++];
405 578
406 err = process(sec, feat, fd); 579 err = process(sec, self, feat, fd);
407 if (err < 0) 580 if (err < 0)
408 break; 581 break;
409 } 582 }
410 ++feat; 583 ++feat;
411 } 584 }
412 585out_free:
413 free(feat_sec); 586 free(feat_sec);
414 return err; 587 return err;
415}; 588}
416 589
417int perf_file_header__read(struct perf_file_header *self, 590int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 591 struct perf_header *ph, int fd)
419{ 592{
420 lseek(fd, 0, SEEK_SET); 593 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 594
423 if (self->magic != PERF_MAGIC || 595 if (do_read(fd, self, sizeof(*self)) ||
424 self->attr_size != sizeof(struct perf_file_attr)) 596 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 597 return -1;
426 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
427 if (self->size != sizeof(*self)) { 610 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 611 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 612 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +616,31 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 616 }
434 617
435 memcpy(&ph->adds_features, &self->adds_features, 618 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(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 }
437 631
438 ph->event_offset = self->event_types.offset; 632 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 633 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 634 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 635 ph->data_size = self->data.size;
442 return 0; 636 return 0;
443} 637}
444 638
445static int perf_file_section__process(struct perf_file_section *self, 639static int perf_file_section__process(struct perf_file_section *self,
640 struct perf_header *ph,
446 int feat, int fd) 641 int feat, int fd)
447{ 642{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 643 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 644 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 645 "continuing...\n", self->offset, feat);
451 return 0; 646 return 0;
@@ -457,7 +652,7 @@ static int perf_file_section__process(struct perf_file_section *self,
457 break; 652 break;
458 653
459 case HEADER_BUILD_ID: 654 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 655 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 656 pr_debug("Failed to read buildids, continuing...\n");
462 break; 657 break;
463 default: 658 default:
@@ -469,7 +664,7 @@ static int perf_file_section__process(struct perf_file_section *self,
469 664
470int perf_header__read(struct perf_header *self, int fd) 665int perf_header__read(struct perf_header *self, int fd)
471{ 666{
472 struct perf_file_header f_header; 667 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 668 struct perf_file_attr f_attr;
474 u64 f_id; 669 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 670 int nr_attrs, nr_ids, i, j;
@@ -486,7 +681,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 681 struct perf_header_attr *attr;
487 off_t tmp; 682 off_t tmp;
488 683
489 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
490 tmp = lseek(fd, 0, SEEK_CUR); 687 tmp = lseek(fd, 0, SEEK_CUR);
491 688
492 attr = perf_header_attr__new(&f_attr.attr); 689 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +694,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 694 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 695
499 for (j = 0; j < nr_ids; j++) { 696 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 697 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
698 goto out_errno;
501 699
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 700 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 701 perf_header_attr__delete(attr);
@@ -517,7 +715,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 715 events = malloc(f_header.event_types.size);
518 if (events == NULL) 716 if (events == NULL)
519 return -ENOMEM; 717 return -ENOMEM;
520 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;
521 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);
522 } 722 }
523 723
@@ -527,6 +727,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 727
528 self->frozen = 1; 728 self->frozen = 1;
529 return 0; 729 return 0;
730out_errno:
731 return -errno;
530} 732}
531 733
532u64 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 d118d05d3abe..82a6af72d4cc 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -52,6 +53,7 @@ struct perf_header {
52 u64 data_size; 53 u64 data_size;
53 u64 event_offset; 54 u64 event_offset;
54 u64 event_size; 55 u64 event_size;
56 bool needs_swap;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 57 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
56}; 58};
57 59
@@ -64,7 +66,7 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit);
64int perf_header__add_attr(struct perf_header *self, 66int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 67 struct perf_header_attr *attr);
66 68
67void perf_header__push_event(u64 id, const char *name); 69int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 70char *perf_header__find_event(u64 id);
69 71
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 72struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -80,6 +82,11 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 82
81int perf_header__process_sections(struct perf_header *self, int fd, 83int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 84 int (*process)(struct perf_file_section *self,
85 struct perf_header *ph,
83 int feat, int fd)); 86 int feat, int fd));
84 87
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);
91
85#endif /* __PERF_HEADER_H */ 92#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0ebf6ee16caa..2be33c7dbf03 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,9 +1,7 @@
1#include "hist.h" 1#include "hist.h"
2 2#include "session.h"
3struct rb_root hist; 3#include "sort.h"
4struct rb_root collapse_hists; 4#include <math.h>
5struct rb_root output_hists;
6int callchain;
7 5
8struct callchain_param callchain_param = { 6struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 7 .mode = CHAIN_GRAPH_REL,
@@ -14,11 +12,12 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
15 */ 13 */
16 14
17struct hist_entry *__hist_entry__add(struct addr_location *al, 15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
18 struct symbol *sym_parent, 16 struct addr_location *al,
19 u64 count, bool *hit) 17 struct symbol *sym_parent,
18 u64 count, bool *hit)
20{ 19{
21 struct rb_node **p = &hist.rb_node; 20 struct rb_node **p = &hists->rb_node;
22 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
23 struct hist_entry *he; 22 struct hist_entry *he;
24 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -54,7 +53,7 @@ struct hist_entry *__hist_entry__add(struct addr_location *al,
54 return NULL; 53 return NULL;
55 *he = entry; 54 *he = entry;
56 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist); 56 rb_insert_color(&he->rb_node, hists);
58 *hit = false; 57 *hit = false;
59 return he; 58 return he;
60} 59}
@@ -102,9 +101,9 @@ void hist_entry__free(struct hist_entry *he)
102 * collapse the histogram 101 * collapse the histogram
103 */ 102 */
104 103
105void collapse__insert_entry(struct hist_entry *he) 104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
106{ 105{
107 struct rb_node **p = &collapse_hists.rb_node; 106 struct rb_node **p = &root->rb_node;
108 struct rb_node *parent = NULL; 107 struct rb_node *parent = NULL;
109 struct hist_entry *iter; 108 struct hist_entry *iter;
110 int64_t cmp; 109 int64_t cmp;
@@ -128,38 +127,45 @@ void collapse__insert_entry(struct hist_entry *he)
128 } 127 }
129 128
130 rb_link_node(&he->rb_node, parent, p); 129 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists); 130 rb_insert_color(&he->rb_node, root);
132} 131}
133 132
134void collapse__resort(void) 133void perf_session__collapse_resort(struct rb_root *hists)
135{ 134{
135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
137 struct hist_entry *n; 137 struct hist_entry *n;
138 138
139 if (!sort__need_collapse) 139 if (!sort__need_collapse)
140 return; 140 return;
141 141
142 next = rb_first(&hist); 142 tmp = RB_ROOT;
143 next = rb_first(hists);
144
143 while (next) { 145 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
146 148
147 rb_erase(&n->rb_node, &hist); 149 rb_erase(&n->rb_node, hists);
148 collapse__insert_entry(n); 150 collapse__insert_entry(&tmp, n);
149 } 151 }
152
153 *hists = tmp;
150} 154}
151 155
152/* 156/*
153 * reverse the map, sort on count. 157 * reverse the map, sort on count.
154 */ 158 */
155 159
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) 160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
157{ 163{
158 struct rb_node **p = &output_hists.rb_node; 164 struct rb_node **p = &root->rb_node;
159 struct rb_node *parent = NULL; 165 struct rb_node *parent = NULL;
160 struct hist_entry *iter; 166 struct hist_entry *iter;
161 167
162 if (callchain) 168 if (symbol_conf.use_callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain, 169 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param); 170 min_callchain_hits, &callchain_param);
165 171
@@ -174,29 +180,489 @@ void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
174 } 180 }
175 181
176 rb_link_node(&he->rb_node, parent, p); 182 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists); 183 rb_insert_color(&he->rb_node, root);
178} 184}
179 185
180void output__resort(u64 total_samples) 186void perf_session__output_resort(struct rb_root *hists, u64 total_samples)
181{ 187{
188 struct rb_root tmp;
182 struct rb_node *next; 189 struct rb_node *next;
183 struct hist_entry *n; 190 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits; 191 u64 min_callchain_hits;
186 192
187 min_callchain_hits = 193 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
189 195
190 if (sort__need_collapse) 196 tmp = RB_ROOT;
191 tree = &collapse_hists; 197 next = rb_first(hists);
192
193 next = rb_first(tree);
194 198
195 while (next) { 199 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
198 202
199 rb_erase(&n->rb_node, tree); 203 rb_erase(&n->rb_node, hists);
200 output__insert_entry(n, min_callchain_hits); 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
201 } 206 }
207
208 *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 *pair_session,
460 bool show_displacement,
461 long displacement, FILE *fp,
462 u64 session_total)
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_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_total > 0)
500 new_percent = (self->count * 100.0) / session_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_total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct rb_root *hists,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp,
557 u64 session_total)
558{
559 struct sort_entry *se;
560 struct rb_node *nd;
561 size_t ret = 0;
562 unsigned long position = 1;
563 long displacement = 0;
564 unsigned int width;
565 const char *sep = symbol_conf.field_sep;
566 char *col_width = symbol_conf.col_width_list_str;
567
568 init_rem_hits();
569
570 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
571
572 if (symbol_conf.show_nr_samples) {
573 if (sep)
574 fprintf(fp, "%cSamples", *sep);
575 else
576 fputs(" Samples ", fp);
577 }
578
579 if (pair) {
580 if (sep)
581 ret += fprintf(fp, "%cDelta", *sep);
582 else
583 ret += fprintf(fp, " Delta ");
584
585 if (show_displacement) {
586 if (sep)
587 ret += fprintf(fp, "%cDisplacement", *sep);
588 else
589 ret += fprintf(fp, " Displ");
590 }
591 }
592
593 list_for_each_entry(se, &hist_entry__sort_list, list) {
594 if (se->elide)
595 continue;
596 if (sep) {
597 fprintf(fp, "%c%s", *sep, se->header);
598 continue;
599 }
600 width = strlen(se->header);
601 if (se->width) {
602 if (symbol_conf.col_width_list_str) {
603 if (col_width) {
604 *se->width = atoi(col_width);
605 col_width = strchr(col_width, ',');
606 if (col_width)
607 ++col_width;
608 }
609 }
610 width = *se->width = max(*se->width, width);
611 }
612 fprintf(fp, " %*s", width, se->header);
613 }
614 fprintf(fp, "\n");
615
616 if (sep)
617 goto print_entries;
618
619 fprintf(fp, "# ........");
620 if (symbol_conf.show_nr_samples)
621 fprintf(fp, " ..........");
622 if (pair) {
623 fprintf(fp, " ..........");
624 if (show_displacement)
625 fprintf(fp, " .....");
626 }
627 list_for_each_entry(se, &hist_entry__sort_list, list) {
628 unsigned int i;
629
630 if (se->elide)
631 continue;
632
633 fprintf(fp, " ");
634 if (se->width)
635 width = *se->width;
636 else
637 width = strlen(se->header);
638 for (i = 0; i < width; i++)
639 fprintf(fp, ".");
640 }
641
642 fprintf(fp, "\n#\n");
643
644print_entries:
645 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
646 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
647
648 if (show_displacement) {
649 if (h->pair != NULL)
650 displacement = ((long)h->pair->position -
651 (long)position);
652 else
653 displacement = 0;
654 ++position;
655 }
656 ret += hist_entry__fprintf(h, pair, show_displacement,
657 displacement, fp, session_total);
658 if (h->map == NULL && verbose > 1) {
659 __map_groups__fprintf_maps(&h->thread->mg,
660 MAP__FUNCTION, fp);
661 fprintf(fp, "%.10s end\n", graph_dotted_line);
662 }
663 }
664
665 free(rem_sq_bracket);
666
667 return ret;
202} 668}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3020db0c9292..16f360cce5bf 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -1,50 +1,29 @@
1#ifndef __PERF_HIST_H 1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3#include "../builtin.h"
4 3
5#include "util.h" 4#include <linux/types.h>
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h" 5#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23 6
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38 8
39struct hist_entry *__hist_entry__add(struct addr_location *al, 9struct perf_session;
40 struct symbol *parent, 10struct hist_entry;
41 u64 count, bool *hit); 11struct addr_location;
12struct symbol;
13struct rb_root;
14
15struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
16 struct addr_location *al,
17 struct symbol *parent,
18 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 21void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *); 22
46extern void collapse__resort(void); 23void perf_session__output_resort(struct rb_root *hists, u64 total_samples);
47extern void output__insert_entry(struct hist_entry *, u64); 24void perf_session__collapse_resort(struct rb_root *hists);
48extern void output__resort(u64); 25size_t perf_session__fprintf_hists(struct rb_root *hists,
49 26 struct perf_session *pair,
27 bool show_displacement, FILE *fp,
28 u64 session_total);
50#endif /* __PERF_HIST_H */ 29#endif /* __PERF_HIST_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 21c0274c02fa..f2611655ab51 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -101,5 +101,6 @@ simple_strtoul(const char *nptr, char **endptr, int base)
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, 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__) 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__)
104 105
105#endif 106#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 76bdca640a9b..e509cd59c67d 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -5,6 +5,11 @@
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h" 6#include "debug.h"
7 7
8const char *map_type__name[MAP__NR_TYPES] = {
9 [MAP__FUNCTION] = "Functions",
10 [MAP__VARIABLE] = "Variables",
11};
12
8static inline int is_anon_memory(const char *filename) 13static inline int is_anon_memory(const char *filename)
9{ 14{
10 return strcmp(filename, "//anon") == 0; 15 return strcmp(filename, "//anon") == 0;
@@ -68,8 +73,13 @@ struct map *map__new(struct mmap_event *event, enum map_type type,
68 map__init(self, type, event->start, event->start + event->len, 73 map__init(self, type, event->start, event->start + event->len,
69 event->pgoff, dso); 74 event->pgoff, dso);
70 75
71 if (self->dso == vdso || anon) 76 if (anon) {
77set_identity:
72 self->map_ip = self->unmap_ip = identity__map_ip; 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 }
73 } 83 }
74 return self; 84 return self;
75out_delete: 85out_delete:
@@ -104,11 +114,15 @@ void map__fixup_end(struct map *self)
104 114
105#define DSO__DELETED "(deleted)" 115#define DSO__DELETED "(deleted)"
106 116
107static int map__load(struct map *self, symbol_filter_t filter) 117int map__load(struct map *self, symbol_filter_t filter)
108{ 118{
109 const char *name = self->dso->long_name; 119 const char *name = self->dso->long_name;
110 int nr = dso__load(self->dso, self, filter); 120 int nr;
111 121
122 if (dso__loaded(self->dso, self->type))
123 return 0;
124
125 nr = dso__load(self->dso, self, filter);
112 if (nr < 0) { 126 if (nr < 0) {
113 if (self->dso->has_build_id) { 127 if (self->dso->has_build_id) {
114 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 128 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -139,6 +153,12 @@ static int map__load(struct map *self, symbol_filter_t filter)
139 153
140 return -1; 154 return -1;
141 } 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);
142 162
143 return 0; 163 return 0;
144} 164}
@@ -146,7 +166,7 @@ static int map__load(struct map *self, symbol_filter_t filter)
146struct symbol *map__find_symbol(struct map *self, u64 addr, 166struct symbol *map__find_symbol(struct map *self, u64 addr,
147 symbol_filter_t filter) 167 symbol_filter_t filter)
148{ 168{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 169 if (map__load(self, filter) < 0)
150 return NULL; 170 return NULL;
151 171
152 return dso__find_symbol(self->dso, self->type, addr); 172 return dso__find_symbol(self->dso, self->type, addr);
@@ -155,7 +175,7 @@ struct symbol *map__find_symbol(struct map *self, u64 addr,
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 175struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
156 symbol_filter_t filter) 176 symbol_filter_t filter)
157{ 177{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 178 if (map__load(self, filter) < 0)
159 return NULL; 179 return NULL;
160 180
161 if (!dso__sorted_by_name(self->dso, self->type)) 181 if (!dso__sorted_by_name(self->dso, self->type))
@@ -195,3 +215,23 @@ size_t map__fprintf(struct map *self, FILE *fp)
195 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 215 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
196 self->start, self->end, self->pgoff, self->dso->name); 216 self->start, self->end, self->pgoff, self->dso->name);
197} 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/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..05d0c5c2030c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -450,7 +450,8 @@ parse_single_tracepoint_event(char *sys_name,
450/* sys + ':' + event + ':' + flags*/ 450/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 452static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 453parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
454 char *flags)
454{ 455{
455 char evt_path[MAXPATHLEN]; 456 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 457 struct dirent *evt_ent;
@@ -474,6 +475,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 475 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 476 continue;
476 477
478 if (!strglobmatch(evt_ent->d_name, evt_exp))
479 continue;
480
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 481 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 482 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 483 flags ?: "");
@@ -522,9 +526,10 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 526 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 527 return EVT_FAILED;
524 528
525 if (!strcmp(evt_name, "*")) { 529 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 530 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 531 return parse_multiple_tracepoint_event(sys_name, evt_name,
532 flags);
528 } else 533 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 534 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 535 evt_length, flags,
@@ -753,11 +758,11 @@ modifier:
753 return ret; 758 return ret;
754} 759}
755 760
756static void store_event_type(const char *orgname) 761static int store_event_type(const char *orgname)
757{ 762{
758 char filename[PATH_MAX], *c; 763 char filename[PATH_MAX], *c;
759 FILE *file; 764 FILE *file;
760 int id; 765 int id, n;
761 766
762 sprintf(filename, "%s/", debugfs_path); 767 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 768 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +774,14 @@ static void store_event_type(const char *orgname)
769 774
770 file = fopen(filename, "r"); 775 file = fopen(filename, "r");
771 if (!file) 776 if (!file)
772 return; 777 return 0;
773 if (fscanf(file, "%i", &id) < 1) 778 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 779 fclose(file);
776 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);
777} 785}
778 786
779int 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)
@@ -782,7 +790,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 790 enum event_result ret;
783 791
784 if (strchr(str, ':')) 792 if (strchr(str, ':'))
785 store_event_type(str); 793 if (store_event_type(str) < 0)
794 return -1;
786 795
787 for (;;) { 796 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 797 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +844,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 844}
836 845
837static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 847 "Hardware event",
840 "Software event", 848 "Software event",
841 "Tracepoint event", 849 "Tracepoint event",
842 "Hardware cache event", 850 "Hardware cache event",
851 "Raw hardware event descriptor",
852 "Hardware breakpoint",
843}; 853};
844 854
845/* 855/*
@@ -872,7 +882,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 882 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 883 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 884 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 885 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 886 }
877 closedir(evt_dir); 887 closedir(evt_dir);
878 } 888 }
@@ -892,9 +902,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 902 printf("List of pre-defined events (to be used in -e):\n");
893 903
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 904 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 905 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 906
899 if (type != prev_type) 907 if (type != prev_type)
900 printf("\n"); 908 printf("\n");
@@ -919,17 +927,19 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 927 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 928 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 929 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 930 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 931 }
924 } 932 }
925 } 933 }
926 934
927 printf("\n"); 935 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 936 printf(" %-42s [%s]\n",
929 "rNNN"); 937 "rNNN", event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 938 printf("\n");
931 939
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 940 printf(" %-42s [%s]\n",
941 "mem:<addr>[:access]",
942 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 943 printf("\n");
934 944
935 print_tracepoint_events(); 945 print_tracepoint_events();
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d14a4585bcaf..7c004b6ef24f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -37,6 +37,8 @@
37#include "string.h" 37#include "string.h"
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h"
41#include "color.h"
40#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h" 43#include "probe-event.h"
42 44
@@ -62,6 +64,54 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 64 return ret;
63} 65}
64 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
65/* Parse probepoint definition. */ 115/* Parse probepoint definition. */
66static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 116static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
67{ 117{
@@ -69,11 +119,27 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
69 char c, nc = 0; 119 char c, nc = 0;
70 /* 120 /*
71 * <Syntax> 121 * <Syntax>
72 * perf probe SRC:LN 122 * perf probe [EVENT=]SRC[:LN|;PTN]
73 * perf probe FUNC[+OFFS|%return][@SRC] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 *
125 * TODO:Group name support
74 */ 126 */
75 127
76 ptr = strpbrk(arg, ":+@%"); 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, ";:+@%");
77 if (ptr) { 143 if (ptr) {
78 nc = *ptr; 144 nc = *ptr;
79 *ptr++ = '\0'; 145 *ptr++ = '\0';
@@ -90,7 +156,11 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
90 while (ptr) { 156 while (ptr) {
91 arg = ptr; 157 arg = ptr;
92 c = nc; 158 c = nc;
93 ptr = strpbrk(arg, ":+@%"); 159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
94 if (ptr) { 164 if (ptr) {
95 nc = *ptr; 165 nc = *ptr;
96 *ptr++ = '\0'; 166 *ptr++ = '\0';
@@ -99,13 +169,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
99 case ':': /* Line number */ 169 case ':': /* Line number */
100 pp->line = strtoul(arg, &tmp, 0); 170 pp->line = strtoul(arg, &tmp, 0);
101 if (*tmp != '\0') 171 if (*tmp != '\0')
102 semantic_error("There is non-digit charactor" 172 semantic_error("There is non-digit char"
103 " in line number."); 173 " in line number.");
104 break; 174 break;
105 case '+': /* Byte offset from a symbol */ 175 case '+': /* Byte offset from a symbol */
106 pp->offset = strtoul(arg, &tmp, 0); 176 pp->offset = strtoul(arg, &tmp, 0);
107 if (*tmp != '\0') 177 if (*tmp != '\0')
108 semantic_error("There is non-digit charactor" 178 semantic_error("There is non-digit character"
109 " in offset."); 179 " in offset.");
110 break; 180 break;
111 case '@': /* File name */ 181 case '@': /* File name */
@@ -113,9 +183,6 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
113 semantic_error("SRC@SRC is not allowed."); 183 semantic_error("SRC@SRC is not allowed.");
114 pp->file = strdup(arg); 184 pp->file = strdup(arg);
115 DIE_IF(pp->file == NULL); 185 DIE_IF(pp->file == NULL);
116 if (ptr)
117 semantic_error("@SRC must be the last "
118 "option.");
119 break; 186 break;
120 case '%': /* Probe places */ 187 case '%': /* Probe places */
121 if (strcmp(arg, "return") == 0) { 188 if (strcmp(arg, "return") == 0) {
@@ -130,11 +197,18 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
130 } 197 }
131 198
132 /* Exclusion check */ 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
133 if (pp->line && pp->offset) 206 if (pp->line && pp->offset)
134 semantic_error("Offset can't be used with line number."); 207 semantic_error("Offset can't be used with line number.");
135 208
136 if (!pp->line && pp->file && !pp->function) 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
137 semantic_error("File always requires line number."); 210 semantic_error("File always requires line number or "
211 "lazy pattern.");
138 212
139 if (pp->offset && !pp->function) 213 if (pp->offset && !pp->function)
140 semantic_error("Offset requires an entry function."); 214 semantic_error("Offset requires an entry function.");
@@ -142,18 +216,23 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
142 if (pp->retprobe && !pp->function) 216 if (pp->retprobe && !pp->function)
143 semantic_error("Return probe requires an entry function."); 217 semantic_error("Return probe requires an entry function.");
144 218
145 if ((pp->offset || pp->line) && pp->retprobe) 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
146 semantic_error("Offset/Line can't be used with return probe."); 220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
147 222
148 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
149 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
150} 226}
151 227
152/* Parse perf-probe event definition */ 228/* Parse perf-probe event definition */
153int parse_perf_probe_event(const char *str, struct probe_point *pp) 229void parse_perf_probe_event(const char *str, struct probe_point *pp,
230 bool *need_dwarf)
154{ 231{
155 char **argv; 232 char **argv;
156 int argc, i, need_dwarf = 0; 233 int argc, i;
234
235 *need_dwarf = false;
157 236
158 argv = argv_split(str, &argc); 237 argv = argv_split(str, &argc);
159 if (!argv) 238 if (!argv)
@@ -163,8 +242,8 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
163 242
164 /* Parse probe point */ 243 /* Parse probe point */
165 parse_perf_probe_probepoint(argv[0], pp); 244 parse_perf_probe_probepoint(argv[0], pp);
166 if (pp->file || pp->line) 245 if (pp->file || pp->line || pp->lazy_line)
167 need_dwarf = 1; 246 *need_dwarf = true;
168 247
169 /* Copy arguments and ensure return probe has no C argument */ 248 /* Copy arguments and ensure return probe has no C argument */
170 pp->nr_args = argc - 1; 249 pp->nr_args = argc - 1;
@@ -177,17 +256,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
177 if (pp->retprobe) 256 if (pp->retprobe)
178 semantic_error("You can't specify local" 257 semantic_error("You can't specify local"
179 " variable for kretprobe"); 258 " variable for kretprobe");
180 need_dwarf = 1; 259 *need_dwarf = true;
181 } 260 }
182 } 261 }
183 262
184 argv_free(argv); 263 argv_free(argv);
185 return need_dwarf;
186} 264}
187 265
188/* Parse kprobe_events event into struct probe_point */ 266/* Parse kprobe_events event into struct probe_point */
189void parse_trace_kprobe_event(const char *str, char **group, char **event, 267void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
190 struct probe_point *pp)
191{ 268{
192 char pr; 269 char pr;
193 char *p; 270 char *p;
@@ -203,18 +280,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
203 280
204 /* Scan event and group name. */ 281 /* Scan event and group name. */
205 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 282 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
206 &pr, (float *)(void *)group, (float *)(void *)event); 283 &pr, (float *)(void *)&pp->group,
284 (float *)(void *)&pp->event);
207 if (ret != 3) 285 if (ret != 3)
208 semantic_error("Failed to parse event name: %s", argv[0]); 286 semantic_error("Failed to parse event name: %s", argv[0]);
209 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr); 287 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
210
211 if (!pp)
212 goto end;
213 288
214 pp->retprobe = (pr == 'r'); 289 pp->retprobe = (pr == 'r');
215 290
216 /* Scan function name and offset */ 291 /* Scan function name and offset */
217 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); 292 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
293 &pp->offset);
218 if (ret == 1) 294 if (ret == 1)
219 pp->offset = 0; 295 pp->offset = 0;
220 296
@@ -233,17 +309,18 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
233 die("Failed to copy argument."); 309 die("Failed to copy argument.");
234 } 310 }
235 311
236end:
237 argv_free(argv); 312 argv_free(argv);
238} 313}
239 314
240int synthesize_perf_probe_event(struct probe_point *pp) 315/* Synthesize only probe point (not argument) */
316int synthesize_perf_probe_point(struct probe_point *pp)
241{ 317{
242 char *buf; 318 char *buf;
243 char offs[64] = "", line[64] = ""; 319 char offs[64] = "", line[64] = "";
244 int i, len, ret; 320 int ret;
245 321
246 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 322 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
323 pp->found = 1;
247 if (!buf) 324 if (!buf)
248 die("Failed to allocate memory by zalloc."); 325 die("Failed to allocate memory by zalloc.");
249 if (pp->offset) { 326 if (pp->offset) {
@@ -262,10 +339,25 @@ int synthesize_perf_probe_event(struct probe_point *pp)
262 offs, pp->retprobe ? "%return" : "", line); 339 offs, pp->retprobe ? "%return" : "", line);
263 else 340 else
264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 341 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
265 if (ret <= 0) 342 if (ret <= 0) {
266 goto error; 343error:
267 len = ret; 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;
268 359
360 buf = pp->probes[0];
269 for (i = 0; i < pp->nr_args; i++) { 361 for (i = 0; i < pp->nr_args; i++) {
270 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 362 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
271 pp->args[i]); 363 pp->args[i]);
@@ -278,6 +370,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
278 return pp->found; 370 return pp->found;
279error: 371error:
280 free(pp->probes[0]); 372 free(pp->probes[0]);
373 pp->probes[0] = NULL;
281 374
282 return ret; 375 return ret;
283} 376}
@@ -307,6 +400,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
307 return pp->found; 400 return pp->found;
308error: 401error:
309 free(pp->probes[0]); 402 free(pp->probes[0]);
403 pp->probes[0] = NULL;
310 404
311 return ret; 405 return ret;
312} 406}
@@ -324,7 +418,7 @@ static int open_kprobe_events(int flags, int mode)
324 if (ret < 0) { 418 if (ret < 0) {
325 if (errno == ENOENT) 419 if (errno == ENOENT)
326 die("kprobe_events file does not exist -" 420 die("kprobe_events file does not exist -"
327 " please rebuild with CONFIG_KPROBE_TRACER."); 421 " please rebuild with CONFIG_KPROBE_EVENT.");
328 else 422 else
329 die("Could not open kprobe_events file: %s", 423 die("Could not open kprobe_events file: %s",
330 strerror(errno)); 424 strerror(errno));
@@ -366,10 +460,16 @@ static void clear_probe_point(struct probe_point *pp)
366{ 460{
367 int i; 461 int i;
368 462
463 if (pp->event)
464 free(pp->event);
465 if (pp->group)
466 free(pp->group);
369 if (pp->function) 467 if (pp->function)
370 free(pp->function); 468 free(pp->function);
371 if (pp->file) 469 if (pp->file)
372 free(pp->file); 470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
373 for (i = 0; i < pp->nr_args; i++) 473 for (i = 0; i < pp->nr_args; i++)
374 free(pp->args[i]); 474 free(pp->args[i]);
375 if (pp->args) 475 if (pp->args)
@@ -380,13 +480,15 @@ static void clear_probe_point(struct probe_point *pp)
380} 480}
381 481
382/* Show an event */ 482/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event, 483static void show_perf_probe_event(const char *event, const char *place,
384 const char *place, struct probe_point *pp) 484 struct probe_point *pp)
385{ 485{
386 int i; 486 int i, ret;
387 char buf[128]; 487 char buf[128];
388 488
389 e_snprintf(buf, 128, "%s:%s", group, event); 489 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
490 if (ret < 0)
491 die("Failed to copy event: %s", strerror(-ret));
390 printf(" %-40s (on %s", buf, place); 492 printf(" %-40s (on %s", buf, place);
391 493
392 if (pp->nr_args > 0) { 494 if (pp->nr_args > 0) {
@@ -400,29 +502,24 @@ static void show_perf_probe_event(const char *group, const char *event,
400/* List up current perf-probe events */ 502/* List up current perf-probe events */
401void show_perf_probe_events(void) 503void show_perf_probe_events(void)
402{ 504{
403 unsigned int i; 505 int fd;
404 int fd, nr;
405 char *group, *event;
406 struct probe_point pp; 506 struct probe_point pp;
407 struct strlist *rawlist; 507 struct strlist *rawlist;
408 struct str_node *ent; 508 struct str_node *ent;
409 509
510 setup_pager();
511 memset(&pp, 0, sizeof(pp));
512
410 fd = open_kprobe_events(O_RDONLY, 0); 513 fd = open_kprobe_events(O_RDONLY, 0);
411 rawlist = get_trace_kprobe_event_rawlist(fd); 514 rawlist = get_trace_kprobe_event_rawlist(fd);
412 close(fd); 515 close(fd);
413 516
414 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 517 strlist__for_each(ent, rawlist) {
415 ent = strlist__entry(rawlist, i); 518 parse_trace_kprobe_event(ent->s, &pp);
416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */ 519 /* Synthesize only event probe point */
418 nr = pp.nr_args; 520 synthesize_perf_probe_point(&pp);
419 pp.nr_args = 0;
420 synthesize_perf_probe_event(&pp);
421 pp.nr_args = nr;
422 /* Show an event */ 521 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp); 522 show_perf_probe_event(pp.event, pp.probes[0], &pp);
424 free(group);
425 free(event);
426 clear_probe_point(&pp); 523 clear_probe_point(&pp);
427 } 524 }
428 525
@@ -432,26 +529,25 @@ void show_perf_probe_events(void)
432/* Get current perf-probe event names */ 529/* Get current perf-probe event names */
433static struct strlist *get_perf_event_names(int fd, bool include_group) 530static struct strlist *get_perf_event_names(int fd, bool include_group)
434{ 531{
435 unsigned int i;
436 char *group, *event;
437 char buf[128]; 532 char buf[128];
438 struct strlist *sl, *rawlist; 533 struct strlist *sl, *rawlist;
439 struct str_node *ent; 534 struct str_node *ent;
535 struct probe_point pp;
440 536
537 memset(&pp, 0, sizeof(pp));
441 rawlist = get_trace_kprobe_event_rawlist(fd); 538 rawlist = get_trace_kprobe_event_rawlist(fd);
442 539
443 sl = strlist__new(true, NULL); 540 sl = strlist__new(true, NULL);
444 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 541 strlist__for_each(ent, rawlist) {
445 ent = strlist__entry(rawlist, i); 542 parse_trace_kprobe_event(ent->s, &pp);
446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
447 if (include_group) { 543 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 544 if (e_snprintf(buf, 128, "%s:%s", pp.group,
545 pp.event) < 0)
449 die("Failed to copy group:event name."); 546 die("Failed to copy group:event name.");
450 strlist__add(sl, buf); 547 strlist__add(sl, buf);
451 } else 548 } else
452 strlist__add(sl, event); 549 strlist__add(sl, pp.event);
453 free(group); 550 clear_probe_point(&pp);
454 free(event);
455 } 551 }
456 552
457 strlist__delete(rawlist); 553 strlist__delete(rawlist);
@@ -470,7 +566,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
470} 566}
471 567
472static void get_new_event_name(char *buf, size_t len, const char *base, 568static void get_new_event_name(char *buf, size_t len, const char *base,
473 struct strlist *namelist) 569 struct strlist *namelist, bool allow_suffix)
474{ 570{
475 int i, ret; 571 int i, ret;
476 572
@@ -481,6 +577,12 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
481 if (!strlist__has_entry(namelist, buf)) 577 if (!strlist__has_entry(namelist, buf))
482 return; 578 return;
483 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
484 /* Try to add suffix */ 586 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) { 587 for (i = 1; i < MAX_EVENT_INDEX; i++) {
486 ret = e_snprintf(buf, len, "%s_%d", base, i); 588 ret = e_snprintf(buf, len, "%s_%d", base, i);
@@ -493,13 +595,15 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
493 die("Too many events are on the same function."); 595 die("Too many events are on the same function.");
494} 596}
495 597
496void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) 598void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
599 bool force_add)
497{ 600{
498 int i, j, fd; 601 int i, j, fd;
499 struct probe_point *pp; 602 struct probe_point *pp;
500 char buf[MAX_CMDLEN]; 603 char buf[MAX_CMDLEN];
501 char event[64]; 604 char event[64];
502 struct strlist *namelist; 605 struct strlist *namelist;
606 bool allow_suffix;
503 607
504 fd = open_kprobe_events(O_RDWR, O_APPEND); 608 fd = open_kprobe_events(O_RDWR, O_APPEND);
505 /* Get current event names */ 609 /* Get current event names */
@@ -507,21 +611,35 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
507 611
508 for (j = 0; j < nr_probes; j++) { 612 for (j = 0; j < nr_probes; j++) {
509 pp = 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;
510 for (i = 0; i < pp->found; i++) { 621 for (i = 0; i < pp->found; i++) {
511 /* Get an unused new event name */ 622 /* Get an unused new event name */
512 get_new_event_name(event, 64, pp->function, namelist); 623 get_new_event_name(event, 64, pp->event, namelist,
624 allow_suffix);
513 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 625 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
514 pp->retprobe ? 'r' : 'p', 626 pp->retprobe ? 'r' : 'p',
515 PERFPROBE_GROUP, event, 627 pp->group, event,
516 pp->probes[i]); 628 pp->probes[i]);
517 write_trace_kprobe_event(fd, buf); 629 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n"); 630 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */ 631 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf); 632 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event, 633 show_perf_probe_event(event, buf, pp);
522 buf, pp);
523 /* Add added event name to namelist */ 634 /* Add added event name to namelist */
524 strlist__add(namelist, event); 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;
525 } 643 }
526 } 644 }
527 /* Show how to use the event. */ 645 /* Show how to use the event. */
@@ -532,29 +650,55 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
532 close(fd); 650 close(fd);
533} 651}
534 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
535static void del_trace_kprobe_event(int fd, const char *group, 670static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist) 671 const char *event, struct strlist *namelist)
537{ 672{
538 char buf[128]; 673 char buf[128];
674 struct str_node *ent, *n;
675 int found = 0;
539 676
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 677 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event."); 678 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549 679
550 write_trace_kprobe_event(fd, buf); 680 if (strpbrk(buf, "*?")) { /* Glob-exp */
551 printf("Remove event: %s:%s\n", group, event); 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);
552} 697}
553 698
554void del_trace_kprobe_events(struct strlist *dellist) 699void del_trace_kprobe_events(struct strlist *dellist)
555{ 700{
556 int fd; 701 int fd;
557 unsigned int i;
558 const char *group, *event; 702 const char *group, *event;
559 char *p, *str; 703 char *p, *str;
560 struct str_node *ent; 704 struct str_node *ent;
@@ -564,20 +708,21 @@ void del_trace_kprobe_events(struct strlist *dellist)
564 /* Get current event names */ 708 /* Get current event names */
565 namelist = get_perf_event_names(fd, true); 709 namelist = get_perf_event_names(fd, true);
566 710
567 for (i = 0; i < strlist__nr_entries(dellist); i++) { 711 strlist__for_each(ent, dellist) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s); 712 str = strdup(ent->s);
570 if (!str) 713 if (!str)
571 die("Failed to copy event."); 714 die("Failed to copy event.");
715 pr_debug("Parsing: %s\n", str);
572 p = strchr(str, ':'); 716 p = strchr(str, ':');
573 if (p) { 717 if (p) {
574 group = str; 718 group = str;
575 *p = '\0'; 719 *p = '\0';
576 event = p + 1; 720 event = p + 1;
577 } else { 721 } else {
578 group = PERFPROBE_GROUP; 722 group = "*";
579 event = str; 723 event = str;
580 } 724 }
725 pr_debug("Group: %s, Event: %s\n", group, event);
581 del_trace_kprobe_event(fd, group, event, namelist); 726 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str); 727 free(str);
583 } 728 }
@@ -585,3 +730,73 @@ void del_trace_kprobe_events(struct strlist *dellist)
585 close(fd); 730 close(fd);
586} 731}
587 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
index f752159124ae..711287d4baea 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,17 +1,22 @@
1#ifndef _PROBE_EVENT_H 1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h>
4#include "probe-finder.h" 5#include "probe-finder.h"
5#include "strlist.h" 6#include "strlist.h"
6 7
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 8extern void parse_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);
8extern int synthesize_perf_probe_event(struct probe_point *pp); 12extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group, 13extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 14extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 15extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
16 bool force_add);
13extern void del_trace_kprobe_events(struct strlist *dellist); 17extern void del_trace_kprobe_events(struct strlist *dellist);
14extern void show_perf_probe_events(void); 18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
15 20
16/* Maximum index number of event-name postfix */ 21/* Maximum index number of event-name postfix */
17#define MAX_EVENT_INDEX 1024 22#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4585f1d86792..c171a243d05b 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -32,21 +32,13 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34 34
35#include "string.h"
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
38#include "probe-finder.h" 39#include "probe-finder.h"
39 40
40 41
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/* 42/*
51 * Generic dwarf analysis helpers 43 * Generic dwarf analysis helpers
52 */ 44 */
@@ -113,256 +105,190 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 105 return 0;
114} 106}
115 107
116/* Find the fileno of the target file. */ 108/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118{
119 Dwarf_Signed cnt, i;
120 Dwarf_Unsigned found = 0;
121 char **srcs;
122 int ret;
123
124 if (!fname)
125 return 0;
126 109
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 110/* Add a line to line number list */
128 if (ret == DW_DLV_OK) { 111static void line_list__add_line(struct list_head *head, unsigned int line)
129 for (i = 0; i < cnt && !found; i++) { 112{
130 if (strtailcmp(srcs[i], fname) == 0) 113 struct line_node *ln;
131 found = i + 1; 114 struct list_head *p;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 115
133 } 116 /* Reverse search, because new line will be the last one */
134 for (; i < cnt; i++) 117 list_for_each_entry_reverse(ln, head, list) {
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 118 if (ln->line < line) {
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST); 119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
137 } 123 }
138 if (found) 124 /* List is empty, or the smallest entry */
139 pr_debug("found fno: %d\n", (int)found); 125 p = head;
140 return found; 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);
141} 133}
142 134
143/* Compare diename and tname */ 135/* Check if the line in line number list */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 136static int line_list__has_line(struct list_head *head, unsigned int line)
145{ 137{
146 char *name; 138 struct line_node *ln;
147 int ret;
148 ret = dwarf_diename(dw_die, &name, &__dw_error);
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156}
157 139
158/* Check the address is in the subprogram(function). */ 140 /* Reverse search, because new line will be the last one */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 141 list_for_each_entry(ln, head, list)
160 Dwarf_Signed *offs) 142 if (ln->line == line)
161{ 143 return 1;
162 Dwarf_Addr lopc, hipc;
163 int ret;
164 144
165 /* TODO: check ranges */ 145 return 0;
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error);
167 DIE_IF(ret == DW_DLV_ERROR);
168 if (ret == DW_DLV_NO_ENTRY)
169 return 0;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
171 DIE_IF(ret != DW_DLV_OK);
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177} 146}
178 147
179/* Check the die is inlined function */ 148/* Init line number list */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 149static void line_list__init(struct list_head *head)
181{ 150{
182 /* TODO: check strictly */ 151 INIT_LIST_HEAD(head);
183 Dwarf_Bool inl; 152}
184 int ret;
185 153
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 154/* Free line number list */
187 DIE_IF(ret == DW_DLV_ERROR); 155static void line_list__free(struct list_head *head)
188 return inl; 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 }
189} 163}
190 164
191/* Get the offset of abstruct_origin */ 165/* Dwarf wrappers */
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
193{ 169{
194 Dwarf_Attribute attr; 170 Dwarf_Files *files;
195 Dwarf_Off cu_offs; 171 size_t nfiles, i;
172 const char *src = NULL;
196 int ret; 173 int ret;
197 174
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 175 if (!fname)
199 DIE_IF(ret != DW_DLV_OK); 176 return NULL;
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 177
201 DIE_IF(ret != DW_DLV_OK); 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 179 if (ret != 0)
203 return cu_offs; 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;
204} 188}
205 189
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 190struct __addr_die_search_param {
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
208{ 196{
209 Dwarf_Attribute attr; 197 struct __addr_die_search_param *ad = data;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215 198
216 /* Try to get entry pc */ 199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 200 dwarf_haspc(fn_die, ad->addr)) {
218 DIE_IF(ret == DW_DLV_ERROR); 201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
219 if (ret == DW_DLV_OK) { 202 return DWARF_CB_ABORT;
220 ret = dwarf_formaddr(attr, &addr, &__dw_error);
221 DIE_IF(ret != DW_DLV_OK);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 } 203 }
204 return DWARF_CB_OK;
205}
225 206
226 /* Try to get low pc */ 207/* Search a real subprogram including this line, */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
228 DIE_IF(ret == DW_DLV_ERROR); 209 Dwarf_Die *die_mem)
229 if (ret == DW_DLV_OK) 210{
230 return addr; 211 struct __addr_die_search_param ad;
231 212 ad.addr = addr;
232 /* Try to get ranges */ 213 ad.die_mem = die_mem;
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); 214 /* dwarf_getscopes can't find subprogram. */
234 DIE_IF(ret != DW_DLV_OK); 215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
235 ret = dwarf_formref(attr, &offs, &__dw_error); 216 return NULL;
236 DIE_IF(ret != DW_DLV_OK); 217 else
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, 218 return die_mem;
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243} 219}
244 220
245/* 221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
246 * Search a Die from Die tree. 222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
247 * Note: cur_link->die should be deallocated in this function. 223 Dwarf_Die *die_mem)
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{ 224{
253 Dwarf_Die new_die; 225 Dwarf_Die child_die;
254 struct die_link new_link;
255 int ret; 226 int ret;
256 227
257 if (!die_cb) 228 ret = dwarf_child(sp_die, die_mem);
258 return 0; 229 if (ret != 0)
230 return NULL;
259 231
260 /* Check current die */ 232 do {
261 while (!(ret = die_cb(cur_link, data))) { 233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
262 /* Check child die */ 234 dwarf_haspc(die_mem, addr))
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 235 return die_mem;
264 DIE_IF(ret == DW_DLV_ERROR);
265 if (ret == DW_DLV_OK) {
266 new_link.parent = cur_link;
267 new_link.die = new_die;
268 ret = __search_die_tree(&new_link, die_cb, data);
269 if (ret)
270 break;
271 }
272 236
273 /* Move to next sibling */ 237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
275 &__dw_error); 239 return die_mem;
276 DIE_IF(ret == DW_DLV_ERROR); 240 }
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); 241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284}
285
286/* Search a die in its children's die tree */
287static int search_die_from_children(Dwarf_Die parent_die,
288 int (*die_cb)(struct die_link *, void *),
289 void *data)
290{
291 struct die_link new_link;
292 int ret;
293 242
294 new_link.parent = NULL; 243 return NULL;
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
296 DIE_IF(ret == DW_DLV_ERROR);
297 if (ret == DW_DLV_OK)
298 return __search_die_tree(&new_link, die_cb, data);
299 else
300 return 0;
301} 244}
302 245
303/* Find a locdesc corresponding to the address */ 246/* Compare diename and tname */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
305 Dwarf_Addr addr)
306{ 248{
307 Dwarf_Signed lcnt; 249 const char *name;
308 Dwarf_Locdesc **llbuf; 250 name = dwarf_diename(dw_die);
309 int ret, i; 251 DIE_IF(name == NULL);
310 252 return strcmp(tname, name);
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
312 DIE_IF(ret != DW_DLV_OK);
313 ret = DW_DLV_NO_ENTRY;
314 for (i = 0; i < lcnt; ++i) {
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 }
329 /* Releasing loop */
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336} 253}
337 254
338/* Get decl_file attribute value (file number) */ 255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
340{ 257{
341 Dwarf_Attribute attr; 258 Dwarf_Addr epc;
342 Dwarf_Unsigned fno;
343 int ret; 259 int ret;
344 260
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 261 ret = dwarf_entrypc(dw_die, &epc);
346 DIE_IF(ret != DW_DLV_OK); 262 DIE_IF(ret == -1);
347 dwarf_formudata(attr, &fno, &__dw_error); 263 return epc;
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351} 264}
352 265
353/* Get decl_line attribute value (line number) */ 266/* Get a variable die */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
355{ 269{
356 Dwarf_Attribute attr; 270 Dwarf_Die child_die;
357 Dwarf_Unsigned lno; 271 int tag;
358 int ret; 272 int ret;
359 273
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 274 ret = dwarf_child(sp_die, die_mem);
361 DIE_IF(ret != DW_DLV_OK); 275 if (ret != 0)
362 dwarf_formudata(attr, &lno, &__dw_error); 276 return NULL;
363 DIE_IF(ret != DW_DLV_OK); 277
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 278 do {
365 return lno; 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;
366} 292}
367 293
368/* 294/*
@@ -370,47 +296,45 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
370 */ 296 */
371 297
372/* Show a location */ 298/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
374{ 300{
375 Dwarf_Small op; 301 unsigned int regn;
376 Dwarf_Unsigned regn; 302 Dwarf_Word offs = 0;
377 Dwarf_Signed offs;
378 int deref = 0, ret; 303 int deref = 0, ret;
379 const char *regs; 304 const char *regs;
380 305
381 op = loc->lr_atom; 306 /* TODO: support CFA */
382
383 /* If this is based on frame buffer, set the offset */ 307 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
385 deref = 1; 311 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number; 312 offs = op->number;
387 op = pf->fbloc.ld_s[0].lr_atom; 313 op = &pf->fb_ops[0];
388 loc = &pf->fbloc.ld_s[0]; 314 }
389 } else
390 offs = 0;
391 315
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0; 317 regn = op->atom - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number; 318 offs += op->number;
395 deref = 1; 319 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0; 321 regn = op->atom - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) { 322 } else if (op->atom == DW_OP_bregx) {
399 regn = loc->lr_number; 323 regn = op->number;
400 offs += (Dwarf_Signed)loc->lr_number2; 324 offs += op->number2;
401 deref = 1; 325 deref = 1;
402 } else if (op == DW_OP_regx) { 326 } else if (op->atom == DW_OP_regx) {
403 regn = loc->lr_number; 327 regn = op->number;
404 } else 328 } else
405 die("Dwarf_OP %d is not supported.\n", op); 329 die("DW_OP %d is not supported.", op->atom);
406 330
407 regs = get_arch_regstr(regn); 331 regs = get_arch_regstr(regn);
408 if (!regs) 332 if (!regs)
409 die("%lld exceeds max register number.\n", regn); 333 die("%u exceeds max register number.", regn);
410 334
411 if (deref) 335 if (deref)
412 ret = snprintf(pf->buf, pf->len, 336 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
413 " %s=%+lld(%s)", pf->var, offs, regs); 337 pf->var, (intmax_t)offs, regs);
414 else 338 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
416 DIE_IF(ret < 0); 340 DIE_IF(ret < 0);
@@ -418,52 +342,36 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
418} 342}
419 343
420/* Show a variables in kprobe event format */ 344/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
422{ 346{
423 Dwarf_Attribute attr; 347 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld; 348 Dwarf_Op *expr;
349 size_t nexpr;
425 int ret; 350 int ret;
426 351
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
428 if (ret != DW_DLV_OK)
429 goto error; 353 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 354 /* TODO: handle more than 1 exprs */
431 if (ret != DW_DLV_OK) 355 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
356 if (ret <= 0 || nexpr == 0)
432 goto error; 357 goto error;
433 /* TODO? */ 358
434 DIE_IF(ld.ld_cents != 1); 359 show_location(expr, pf);
435 show_location(&ld.ld_s[0], pf); 360 /* *expr will be cached in libdw. Don't free it. */
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ; 361 return ;
439error: 362error:
363 /* TODO: Support const_value */
440 die("Failed to find the location of %s at this address.\n" 364 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var); 365 " Perhaps, it has been optimized out.", pf->var);
442}
443
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
451 DIE_IF(ret == DW_DLV_ERROR);
452 if ((tag == DW_TAG_formal_parameter ||
453 tag == DW_TAG_variable) &&
454 (die_compare_name(dlink->die, pf->var) == 0)) {
455 show_variable(dlink->die, pf);
456 return 1;
457 }
458 /* TODO: Support struct members and arrays */
459 return 0;
460} 366}
461 367
462/* Find a variable in a subprogram die */ 368/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 369static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
464{ 370{
465 int ret; 371 int ret;
372 Dwarf_Die vr_die;
466 373
374 /* TODO: Support struct members and arrays */
467 if (!is_c_varname(pf->var)) { 375 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */ 376 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 377 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -474,58 +382,51 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
474 382
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 383 pr_debug("Searching '%s' variable in context.\n", pf->var);
476 /* Search child die for local variables and parameters. */ 384 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf); 385 if (!die_find_variable(sp_die, pf->var, &vr_die))
478 if (!ret) 386 die("Failed to find '%s' in this function.", pf->var);
479 die("Failed to find '%s' in this function.\n", pf->var);
480}
481 387
482/* Get a frame base on the address */ 388 show_variable(&vr_die, pf);
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
484{
485 Dwarf_Attribute attr;
486 int ret;
487
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error);
489 DIE_IF(ret != DW_DLV_OK);
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
491 DIE_IF(ret != DW_DLV_OK);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
493}
494
495static void free_current_frame_base(struct probe_finder *pf)
496{
497 free(pf->fbloc.ld_s);
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
499} 389}
500 390
501/* Show a probe point to output buffer */ 391/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 392static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
503 struct probe_finder *pf)
504{ 393{
505 struct probe_point *pp = pf->pp; 394 struct probe_point *pp = pf->pp;
506 char *name; 395 Dwarf_Addr eaddr;
396 Dwarf_Die die_mem;
397 const char *name;
507 char tmp[MAX_PROBE_BUFFER]; 398 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len; 399 int ret, i, len;
400 Dwarf_Attribute fb_attr;
401 size_t nops;
402
403 /* If no real subprogram, find a real one */
404 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
405 sp_die = die_get_real_subprogram(&pf->cu_die,
406 pf->addr, &die_mem);
407 if (!sp_die)
408 die("Probe point is not found in subprograms.");
409 }
509 410
510 /* Output name of probe point */ 411 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 412 name = dwarf_diename(sp_die);
512 DIE_IF(ret == DW_DLV_ERROR); 413 if (name) {
513 if (ret == DW_DLV_OK) { 414 dwarf_entrypc(sp_die, &eaddr);
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 415 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
515 (unsigned int)offs); 416 (unsigned long)(pf->addr - eaddr));
516 /* Copy the function name if possible */ 417 /* Copy the function name if possible */
517 if (!pp->function) { 418 if (!pp->function) {
518 pp->function = strdup(name); 419 pp->function = strdup(name);
519 pp->offset = offs; 420 pp->offset = (size_t)(pf->addr - eaddr);
520 } 421 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else { 422 } else {
523 /* This function has no name. */ 423 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 424 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
425 (uintmax_t)pf->addr);
525 if (!pp->function) { 426 if (!pp->function) {
526 /* TODO: Use _stext */ 427 /* TODO: Use _stext */
527 pp->function = strdup(""); 428 pp->function = strdup("");
528 pp->offset = (int)pf->addr; 429 pp->offset = (size_t)pf->addr;
529 } 430 }
530 } 431 }
531 DIE_IF(ret < 0); 432 DIE_IF(ret < 0);
@@ -533,8 +434,14 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
533 len = ret; 434 len = ret;
534 pr_debug("Probe point found: %s\n", tmp); 435 pr_debug("Probe point found: %s\n", tmp);
535 436
437 /* Get the frame base attribute/ops */
438 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
439 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
440 if (ret <= 0 || nops == 0)
441 pf->fb_ops = NULL;
442
536 /* Find each argument */ 443 /* Find each argument */
537 get_current_frame_base(sp_die, pf); 444 /* TODO: use dwarf_cfi_addrframe */
538 for (i = 0; i < pp->nr_args; i++) { 445 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i]; 446 pf->var = pp->args[i];
540 pf->buf = &tmp[len]; 447 pf->buf = &tmp[len];
@@ -542,191 +449,381 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
542 find_variable(sp_die, pf); 449 find_variable(sp_die, pf);
543 len += strlen(pf->buf); 450 len += strlen(pf->buf);
544 } 451 }
545 free_current_frame_base(pf); 452
453 /* *pf->fb_ops will be cached in libdw. Don't free it. */
454 pf->fb_ops = NULL;
455
456 if (pp->found == MAX_PROBES)
457 die("Too many( > %d) probe point found.\n", MAX_PROBES);
546 458
547 pp->probes[pp->found] = strdup(tmp); 459 pp->probes[pp->found] = strdup(tmp);
548 pp->found++; 460 pp->found++;
549} 461}
550 462
551static int probeaddr_callback(struct die_link *dlink, void *data) 463/* Find probe point from its line number */
464static void find_probe_point_by_line(struct probe_finder *pf)
552{ 465{
553 struct probe_finder *pf = (struct probe_finder *)data; 466 Dwarf_Lines *lines;
554 Dwarf_Half tag; 467 Dwarf_Line *line;
555 Dwarf_Signed offs; 468 size_t nlines, i;
469 Dwarf_Addr addr;
470 int lineno;
556 int ret; 471 int ret;
557 472
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 473 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
559 DIE_IF(ret == DW_DLV_ERROR); 474 DIE_IF(ret != 0);
560 /* Check the address is in this subprogram */ 475
561 if (tag == DW_TAG_subprogram && 476 for (i = 0; i < nlines; i++) {
562 die_within_subprogram(dlink->die, pf->addr, &offs)) { 477 line = dwarf_onesrcline(lines, i);
563 show_probepoint(dlink->die, offs, pf); 478 dwarf_lineno(line, &lineno);
564 return 1; 479 if (lineno != pf->lno)
480 continue;
481
482 /* TODO: Get fileno from line, but how? */
483 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
484 continue;
485
486 ret = dwarf_lineaddr(line, &addr);
487 DIE_IF(ret != 0);
488 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
489 (int)i, lineno, (uintmax_t)addr);
490 pf->addr = addr;
491
492 show_probe_point(NULL, pf);
493 /* Continuing, because target line might be inlined. */
565 } 494 }
566 return 0;
567} 495}
568 496
569/* Find probe point from its line number */ 497/* Find lines which match lazy pattern */
570static void find_by_line(struct probe_finder *pf) 498static int find_lazy_match_lines(struct list_head *head,
499 const char *fname, const char *pat)
500{
501 char *fbuf, *p1, *p2;
502 int fd, line, nlines = 0;
503 struct stat st;
504
505 fd = open(fname, O_RDONLY);
506 if (fd < 0)
507 die("failed to open %s", fname);
508 DIE_IF(fstat(fd, &st) < 0);
509 fbuf = malloc(st.st_size + 2);
510 DIE_IF(fbuf == NULL);
511 DIE_IF(read(fd, fbuf, st.st_size) < 0);
512 close(fd);
513 fbuf[st.st_size] = '\n'; /* Dummy line */
514 fbuf[st.st_size + 1] = '\0';
515 p1 = fbuf;
516 line = 1;
517 while ((p2 = strchr(p1, '\n')) != NULL) {
518 *p2 = '\0';
519 if (strlazymatch(p1, pat)) {
520 line_list__add_line(head, line);
521 nlines++;
522 }
523 line++;
524 p1 = p2 + 1;
525 }
526 free(fbuf);
527 return nlines;
528}
529
530/* Find probe points from lazy pattern */
531static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
571{ 532{
572 Dwarf_Signed cnt, i, clm; 533 Dwarf_Lines *lines;
573 Dwarf_Line *lines; 534 Dwarf_Line *line;
574 Dwarf_Unsigned lineno = 0; 535 size_t nlines, i;
575 Dwarf_Addr addr; 536 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 537 Dwarf_Die die_mem;
538 int lineno;
577 int ret; 539 int ret;
578 540
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 541 if (list_empty(&pf->lcache)) {
580 DIE_IF(ret != DW_DLV_OK); 542 /* Matching lazy line pattern */
543 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
544 pf->pp->lazy_line);
545 if (ret <= 0)
546 die("No matched lines found in %s.", pf->fname);
547 }
548
549 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
550 DIE_IF(ret != 0);
551 for (i = 0; i < nlines; i++) {
552 line = dwarf_onesrcline(lines, i);
581 553
582 for (i = 0; i < cnt; i++) { 554 dwarf_lineno(line, &lineno);
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 555 if (!line_list__has_line(&pf->lcache, lineno))
584 DIE_IF(ret != DW_DLV_OK);
585 if (fno != pf->fno)
586 continue; 556 continue;
587 557
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 558 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 559 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 560 continue;
592 561
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 562 ret = dwarf_lineaddr(line, &addr);
594 DIE_IF(ret != DW_DLV_OK); 563 DIE_IF(ret != 0);
564 if (sp_die) {
565 /* Address filtering 1: does sp_die include addr? */
566 if (!dwarf_haspc(sp_die, addr))
567 continue;
568 /* Address filtering 2: No child include addr? */
569 if (die_get_inlinefunc(sp_die, addr, &die_mem))
570 continue;
571 }
595 572
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 573 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
597 DIE_IF(ret != DW_DLV_OK); 574 (int)i, lineno, (unsigned long long)addr);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr; 575 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 576
602 ret = search_die_from_children(pf->cu_die, 577 show_probe_point(sp_die, pf);
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */ 578 /* Continuing, because target line might be inlined. */
607 } 579 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 580 /* TODO: deallocate lines, but how? */
581}
582
583static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
584{
585 struct probe_finder *pf = (struct probe_finder *)data;
586 struct probe_point *pp = pf->pp;
587
588 if (pp->lazy_line)
589 find_probe_point_lazy(in_die, pf);
590 else {
591 /* Get probe address */
592 pf->addr = die_get_entrypc(in_die);
593 pf->addr += pp->offset;
594 pr_debug("found inline addr: 0x%jx\n",
595 (uintmax_t)pf->addr);
596
597 show_probe_point(in_die, pf);
598 }
599
600 return DWARF_CB_OK;
609} 601}
610 602
611/* Search function from function name */ 603/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data) 604static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
613{ 605{
614 struct probe_finder *pf = (struct probe_finder *)data; 606 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp; 607 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620 608
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 609 /* Check tag and diename */
622 DIE_IF(ret == DW_DLV_ERROR); 610 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
623 if (tag == DW_TAG_subprogram) { 611 die_compare_name(sp_die, pp->function) != 0)
624 if (die_compare_name(dlink->die, pp->function) == 0) { 612 return 0;
625 if (pp->line) { /* Function relative line */ 613
626 pf->fno = die_get_decl_file(dlink->die); 614 pf->fname = dwarf_decl_file(sp_die);
627 pf->lno = die_get_decl_line(dlink->die) 615 if (pp->line) { /* Function relative line */
628 + pp->line; 616 dwarf_decl_line(sp_die, &pf->lno);
629 find_by_line(pf); 617 pf->lno += pp->line;
630 return 1; 618 find_probe_point_by_line(pf);
631 } 619 } else if (!dwarf_func_inline(sp_die)) {
632 if (die_inlined_subprogram(dlink->die)) { 620 /* Real function */
633 /* Inlined function, save it. */ 621 if (pp->lazy_line)
634 ret = dwarf_die_CU_offset(dlink->die, 622 find_probe_point_lazy(sp_die, pf);
635 &pf->inl_offs, 623 else {
636 &__dw_error); 624 pf->addr = die_get_entrypc(sp_die);
637 DIE_IF(ret != DW_DLV_OK);
638 pr_debug("inline definition offset %lld\n",
639 pf->inl_offs);
640 return 0; /* Continue to search */
641 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 625 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 626 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 627 show_probe_point(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
651 /* Get probe address */
652 pf->addr = die_get_entrypc(dlink->die);
653 pf->addr += pp->offset;
654 pr_debug("found inline addr: 0x%llx\n", pf->addr);
655 /* Inlined function. Get a real subprogram */
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
657 tag = 0;
658 dwarf_tag(lk->die, &tag, &__dw_error);
659 DIE_IF(ret == DW_DLV_ERROR);
660 if (tag == DW_TAG_subprogram &&
661 !die_inlined_subprogram(lk->die))
662 goto found;
663 }
664 die("Failed to find real subprogram.\n");
665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
668 DIE_IF(!ret);
669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 } 628 }
672 } 629 } else
673 return 0; 630 /* Inlined function: search instances */
631 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
632
633 return 1; /* Exit; no same symbol in this CU. */
674} 634}
675 635
676static void find_by_func(struct probe_finder *pf) 636static void find_probe_point_by_func(struct probe_finder *pf)
677{ 637{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 638 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
679} 639}
680 640
681/* Find a probe point */ 641/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp) 642int find_probe_point(int fd, struct probe_point *pp)
683{ 643{
684 Dwarf_Half addr_size = 0;
685 Dwarf_Unsigned next_cuh = 0;
686 int cu_number = 0, ret;
687 struct probe_finder pf = {.pp = pp}; 644 struct probe_finder pf = {.pp = pp};
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
688 649
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 650 dbg = dwarf_begin(fd, DWARF_C_READ);
690 if (ret != DW_DLV_OK) { 651 if (!dbg)
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT; 652 return -ENOENT;
693 }
694 653
695 pp->found = 0; 654 pp->found = 0;
696 while (++cu_number) { 655 off = 0;
697 /* Search CU (Compilation Unit) */ 656 line_list__init(&pf.lcache);
698 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 657 /* Loop on CUs (Compilation Unit) */
699 &addr_size, &next_cuh, &__dw_error); 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
700 DIE_IF(ret == DW_DLV_ERROR);
701 if (ret == DW_DLV_NO_ENTRY)
702 break;
703
704 /* Get the DIE(Debugging Information Entry) of this CU */ 659 /* Get the DIE(Debugging Information Entry) of this CU */
705 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
706 DIE_IF(ret != DW_DLV_OK); 661 if (!diep)
662 continue;
707 663
708 /* Check if target file is included. */ 664 /* Check if target file is included. */
709 if (pp->file) 665 if (pp->file)
710 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
711 667 else
712 if (!pp->file || pf.fno) { 668 pf.fname = NULL;
713 /* Save CU base address (for frame_base) */ 669
714 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 670 if (!pp->file || pf.fname) {
715 DIE_IF(ret == DW_DLV_ERROR);
716 if (ret == DW_DLV_NO_ENTRY)
717 pf.cu_base = 0;
718 if (pp->function) 671 if (pp->function)
719 find_by_func(&pf); 672 find_probe_point_by_func(&pf);
673 else if (pp->lazy_line)
674 find_probe_point_lazy(NULL, &pf);
720 else { 675 else {
721 pf.lno = pp->line; 676 pf.lno = pp->line;
722 find_by_line(&pf); 677 find_probe_point_by_line(&pf);
723 } 678 }
724 } 679 }
725 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 680 off = noff;
726 } 681 }
727 ret = dwarf_finish(__dw_debug, &__dw_error); 682 line_list__free(&pf.lcache);
728 DIE_IF(ret != DW_DLV_OK); 683 dwarf_end(dbg);
729 684
730 return pp->found; 685 return pp->found;
731} 686}
732 687
688/* Find line range from its line number */
689static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
690{
691 Dwarf_Lines *lines;
692 Dwarf_Line *line;
693 size_t nlines, i;
694 Dwarf_Addr addr;
695 int lineno;
696 int ret;
697 const char *src;
698 Dwarf_Die die_mem;
699
700 line_list__init(&lf->lr->line_list);
701 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
702 DIE_IF(ret != 0);
703
704 for (i = 0; i < nlines; i++) {
705 line = dwarf_onesrcline(lines, i);
706 ret = dwarf_lineno(line, &lineno);
707 DIE_IF(ret != 0);
708 if (lf->lno_s > lineno || lf->lno_e < lineno)
709 continue;
710
711 if (sp_die) {
712 /* Address filtering 1: does sp_die include addr? */
713 ret = dwarf_lineaddr(line, &addr);
714 DIE_IF(ret != 0);
715 if (!dwarf_haspc(sp_die, addr))
716 continue;
717
718 /* Address filtering 2: No child include addr? */
719 if (die_get_inlinefunc(sp_die, addr, &die_mem))
720 continue;
721 }
722
723 /* TODO: Get fileno from line, but how? */
724 src = dwarf_linesrc(line, NULL, NULL);
725 if (strtailcmp(src, lf->fname) != 0)
726 continue;
727
728 /* Copy real path */
729 if (!lf->lr->path)
730 lf->lr->path = strdup(src);
731 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
732 }
733 /* Update status */
734 if (!list_empty(&lf->lr->line_list))
735 lf->found = 1;
736 else {
737 free(lf->lr->path);
738 lf->lr->path = NULL;
739 }
740}
741
742static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
743{
744 find_line_range_by_line(in_die, (struct line_finder *)data);
745 return DWARF_CB_ABORT; /* No need to find other instances */
746}
747
748/* Search function from function name */
749static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
750{
751 struct line_finder *lf = (struct line_finder *)data;
752 struct line_range *lr = lf->lr;
753
754 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
755 die_compare_name(sp_die, lr->function) == 0) {
756 lf->fname = dwarf_decl_file(sp_die);
757 dwarf_decl_line(sp_die, &lr->offset);
758 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
759 lf->lno_s = lr->offset + lr->start;
760 if (!lr->end)
761 lf->lno_e = INT_MAX;
762 else
763 lf->lno_e = lr->offset + lr->end;
764 lr->start = lf->lno_s;
765 lr->end = lf->lno_e;
766 if (dwarf_func_inline(sp_die))
767 dwarf_func_inline_instances(sp_die,
768 line_range_inline_cb, lf);
769 else
770 find_line_range_by_line(sp_die, lf);
771 return 1;
772 }
773 return 0;
774}
775
776static void find_line_range_by_func(struct line_finder *lf)
777{
778 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
779}
780
781int find_line_range(int fd, struct line_range *lr)
782{
783 struct line_finder lf = {.lr = lr, .found = 0};
784 int ret;
785 Dwarf_Off off = 0, noff;
786 size_t cuhl;
787 Dwarf_Die *diep;
788 Dwarf *dbg;
789
790 dbg = dwarf_begin(fd, DWARF_C_READ);
791 if (!dbg)
792 return -ENOENT;
793
794 /* Loop on CUs (Compilation Unit) */
795 while (!lf.found) {
796 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
797 if (ret != 0)
798 break;
799
800 /* Get the DIE(Debugging Information Entry) of this CU */
801 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
802 if (!diep)
803 continue;
804
805 /* Check if target file is included. */
806 if (lr->file)
807 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
808 else
809 lf.fname = 0;
810
811 if (!lr->file || lf.fname) {
812 if (lr->function)
813 find_line_range_by_func(&lf);
814 else {
815 lf.lno_s = lr->start;
816 if (!lr->end)
817 lf.lno_e = INT_MAX;
818 else
819 lf.lno_e = lr->end;
820 find_line_range_by_line(NULL, &lf);
821 }
822 }
823 off = noff;
824 }
825 pr_debug("path: %lx\n", (unsigned long)lr->path);
826 dwarf_end(dbg);
827 return lf.found;
828}
829
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bdebca6697d2..21f7354397b4 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,9 +1,12 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#define MAX_PATH_LEN 256 4#include <stdbool.h>
5#define MAX_PROBE_BUFFER 1024 5#include "util.h"
6#define MAX_PROBES 128 6
7#define MAX_PATH_LEN 256
8#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128
7 10
8static inline int is_c_varname(const char *name) 11static inline int is_c_varname(const char *name)
9{ 12{
@@ -12,46 +15,78 @@ static inline int is_c_varname(const char *name)
12} 15}
13 16
14struct probe_point { 17struct probe_point {
18 char *event; /* Event name */
19 char *group; /* Event group */
20
15 /* Inputs */ 21 /* Inputs */
16 char *file; /* File name */ 22 char *file; /* File name */
17 int line; /* Line number */ 23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
18 25
19 char *function; /* Function name */ 26 char *function; /* Function name */
20 int offset; /* Offset bytes */ 27 int offset; /* Offset bytes */
21 28
22 int nr_args; /* Number of arguments */ 29 int nr_args; /* Number of arguments */
23 char **args; /* Arguments */ 30 char **args; /* Arguments */
24 31
25 int retprobe; /* Return probe */ 32 int retprobe; /* Return probe */
26 33
27 /* Output */ 34 /* Output */
28 int found; /* Number of found probe points */ 35 int found; /* Number of found probe points */
29 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 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 */
30}; 54};
31 55
32#ifndef NO_LIBDWARF 56#ifndef NO_DWARF_SUPPORT
33extern int find_probepoint(int fd, struct probe_point *pp); 57extern int find_probe_point(int fd, struct probe_point *pp);
58extern int find_line_range(int fd, struct line_range *lr);
34 59
35#include <libdwarf/dwarf.h> 60#include <dwarf.h>
36#include <libdwarf/libdwarf.h> 61#include <libdw.h>
37 62
38struct probe_finder { 63struct probe_finder {
39 struct probe_point *pp; /* Target probe point */ 64 struct probe_point *pp; /* Target probe point */
40 65
41 /* For function searching */ 66 /* For function searching */
42 Dwarf_Addr addr; /* Address */ 67 Dwarf_Addr addr; /* Address */
43 Dwarf_Unsigned fno; /* File number */ 68 const char *fname; /* File name */
44 Dwarf_Unsigned lno; /* Line number */ 69 int lno; /* Line number */
45 Dwarf_Off inl_offs; /* Inline offset */ 70 Dwarf_Die cu_die; /* Current CU */
46 Dwarf_Die cu_die; /* Current CU */
47 71
48 /* For variable searching */ 72 /* For variable searching */
49 Dwarf_Addr cu_base; /* Current CU base address */ 73 Dwarf_Op *fb_ops; /* Frame base attribute */
50 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 74 const char *var; /* Current variable name */
51 const char *var; /* Current variable name */ 75 char *buf; /* Current output buffer */
52 char *buf; /* Current output buffer */ 76 int len; /* Length of output buffer */
53 int len; /* Length of output buffer */ 77 struct list_head lcache; /* Line cache for lazy match */
54}; 78};
55#endif /* NO_LIBDWARF */ 79
80struct line_finder {
81 struct line_range *lr; /* Target line range */
82
83 const char *fname; /* File name */
84 int lno_s; /* Start line number */
85 int lno_e; /* End line number */
86 Dwarf_Die cu_die; /* Current CU */
87 int found;
88};
89
90#endif /* NO_DWARF_SUPPORT */
56 91
57#endif /*_PROBE_FINDER_H */ 92#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index a5ffe60db5d6..5376378e0cfc 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -25,10 +25,16 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../perf.h" 28#include "../../perf.h"
29#include "util.h" 29#include "../util.h"
30#include "trace-event.h" 30#include "../trace-event.h"
31#include "trace-event-perl.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;
32 38
33void xs_init(pTHX); 39void xs_init(pTHX);
34 40
@@ -49,7 +55,7 @@ INTERP my_perl;
49 55
50struct event *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
51 57
52static struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
53 59
54static char *cur_field_name; 60static char *cur_field_name;
55static int zero_flag_atom; 61static int zero_flag_atom;
@@ -239,35 +245,8 @@ static inline struct event *find_cache_event(int type)
239 return event; 245 return event;
240} 246}
241 247
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data, 248static void perl_process_event(int cpu, void *data,
270 int size __attribute((unused)), 249 int size __unused,
271 unsigned long long nsecs, char *comm) 250 unsigned long long nsecs, char *comm)
272{ 251{
273 struct format_field *field; 252 struct format_field *field;
@@ -359,28 +338,46 @@ static void run_start_sub(void)
359/* 338/*
360 * Start trace script 339 * Start trace script
361 */ 340 */
362static int perl_start_script(const char *script) 341static int perl_start_script(const char *script, int argc, const char **argv)
363{ 342{
364 const char *command_line[2] = { "", NULL }; 343 const char **command_line;
344 int i, err = 0;
365 345
346 command_line = malloc((argc + 2) * sizeof(const char *));
347 command_line[0] = "";
366 command_line[1] = script; 348 command_line[1] = script;
349 for (i = 2; i < argc + 2; i++)
350 command_line[i] = argv[i - 2];
367 351
368 my_perl = perl_alloc(); 352 my_perl = perl_alloc();
369 perl_construct(my_perl); 353 perl_construct(my_perl);
370 354
371 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 355 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
372 (char **)NULL)) 356 (char **)NULL)) {
373 return -1; 357 err = -1;
358 goto error;
359 }
374 360
375 perl_run(my_perl); 361 if (perl_run(my_perl)) {
376 if (SvTRUE(ERRSV)) 362 err = -1;
377 return -1; 363 goto error;
364 }
365
366 if (SvTRUE(ERRSV)) {
367 err = -1;
368 goto error;
369 }
378 370
379 run_start_sub(); 371 run_start_sub();
380 372
373 free(command_line);
381 fprintf(stderr, "perf trace started with Perl script %s\n\n", script); 374 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
382
383 return 0; 375 return 0;
376error:
377 perl_free(my_perl);
378 free(command_line);
379
380 return err;
384} 381}
385 382
386/* 383/*
@@ -569,73 +566,3 @@ struct scripting_ops perl_scripting_ops = {
569 .process_event = perl_process_event, 566 .process_event = perl_process_event,
570 .generate_script = perl_generate_script, 567 .generate_script = perl_generate_script,
571}; 568};
572
573static void print_unsupported_msg(void)
574{
575 fprintf(stderr, "Perl scripting not supported."
576 " Install libperl and rebuild perf to enable it.\n"
577 "For example:\n # apt-get install libperl-dev (ubuntu)"
578 "\n # yum install perl-ExtUtils-Embed (Fedora)"
579 "\n etc.\n");
580}
581
582static int perl_start_script_unsupported(const char *script __unused)
583{
584 print_unsupported_msg();
585
586 return -1;
587}
588
589static int perl_stop_script_unsupported(void)
590{
591 return 0;
592}
593
594static void perl_process_event_unsupported(int cpu __unused,
595 void *data __unused,
596 int size __unused,
597 unsigned long long nsecs __unused,
598 char *comm __unused)
599{
600}
601
602static int perl_generate_script_unsupported(const char *outfile __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609struct scripting_ops perl_scripting_unsupported_ops = {
610 .name = "Perl",
611 .start_script = perl_start_script_unsupported,
612 .stop_script = perl_stop_script_unsupported,
613 .process_event = perl_process_event_unsupported,
614 .generate_script = perl_generate_script_unsupported,
615};
616
617static void register_perl_scripting(struct scripting_ops *scripting_ops)
618{
619 int err;
620 err = script_spec_register("Perl", scripting_ops);
621 if (err)
622 die("error registering Perl script extension");
623
624 err = script_spec_register("pl", scripting_ops);
625 if (err)
626 die("error registering pl script extension");
627
628 scripting_context = malloc(sizeof(struct scripting_context));
629}
630
631#ifdef NO_LIBPERL
632void setup_perl_scripting(void)
633{
634 register_perl_scripting(&perl_scripting_unsupported_ops);
635}
636#else
637void setup_perl_scripting(void)
638{
639 register_perl_scripting(&perl_scripting_ops);
640}
641#endif
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
index 707ce1cb1621..eed1cb889008 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,9 +1,13 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2 4
5#include <byteswap.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <sys/types.h> 7#include <sys/types.h>
5 8
6#include "session.h" 9#include "session.h"
10#include "sort.h"
7#include "util.h" 11#include "util.h"
8 12
9static int perf_session__open(struct perf_session *self, bool force) 13static int perf_session__open(struct perf_session *self, bool force)
@@ -48,33 +52,523 @@ out_close:
48 return -1; 52 return -1;
49} 53}
50 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
51struct perf_session *perf_session__new(const char *filename, int mode, bool force) 60struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{ 61{
53 size_t len = strlen(filename) + 1; 62 size_t len = filename ? strlen(filename) + 1 : 0;
54 struct perf_session *self = zalloc(sizeof(*self) + len); 63 struct perf_session *self = zalloc(sizeof(*self) + len);
55 64
56 if (self == NULL) 65 if (self == NULL)
57 goto out; 66 goto out;
58 67
59 if (perf_header__init(&self->header) < 0) 68 if (perf_header__init(&self->header) < 0)
60 goto out_delete; 69 goto out_free;
61 70
62 memcpy(self->filename, filename, len); 71 memcpy(self->filename, filename, len);
72 self->threads = RB_ROOT;
73 self->stats_by_id = RB_ROOT;
74 self->last_match = NULL;
75 self->mmap_window = 32;
76 self->cwd = NULL;
77 self->cwdlen = 0;
78 self->unknown_events = 0;
79 map_groups__init(&self->kmaps);
63 80
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) { 81 if (mode == O_RDONLY) {
65 perf_session__delete(self); 82 if (perf_session__open(self, force) < 0)
66 self = NULL; 83 goto out_delete;
84 } else if (mode == O_WRONLY) {
85 /*
86 * In O_RDONLY mode this will be performed when reading the
87 * kernel MMAP event, in event__process_mmap().
88 */
89 if (perf_session__create_kernel_maps(self) < 0)
90 goto out_delete;
67 } 91 }
92
93 self->sample_type = perf_header__sample_type(&self->header);
68out: 94out:
69 return self; 95 return self;
70out_delete: 96out_free:
71 free(self); 97 free(self);
72 return NULL; 98 return NULL;
99out_delete:
100 perf_session__delete(self);
101 return NULL;
73} 102}
74 103
75void perf_session__delete(struct perf_session *self) 104void perf_session__delete(struct perf_session *self)
76{ 105{
77 perf_header__exit(&self->header); 106 perf_header__exit(&self->header);
78 close(self->fd); 107 close(self->fd);
108 free(self->cwd);
79 free(self); 109 free(self);
80} 110}
111
112static bool symbol__match_parent_regex(struct symbol *sym)
113{
114 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
115 return 1;
116
117 return 0;
118}
119
120struct symbol **perf_session__resolve_callchain(struct perf_session *self,
121 struct thread *thread,
122 struct ip_callchain *chain,
123 struct symbol **parent)
124{
125 u8 cpumode = PERF_RECORD_MISC_USER;
126 struct symbol **syms = NULL;
127 unsigned int i;
128
129 if (symbol_conf.use_callchain) {
130 syms = calloc(chain->nr, sizeof(*syms));
131 if (!syms) {
132 fprintf(stderr, "Can't allocate memory for symbols\n");
133 exit(-1);
134 }
135 }
136
137 for (i = 0; i < chain->nr; i++) {
138 u64 ip = chain->ips[i];
139 struct addr_location al;
140
141 if (ip >= PERF_CONTEXT_MAX) {
142 switch (ip) {
143 case PERF_CONTEXT_HV:
144 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
145 case PERF_CONTEXT_KERNEL:
146 cpumode = PERF_RECORD_MISC_KERNEL; break;
147 case PERF_CONTEXT_USER:
148 cpumode = PERF_RECORD_MISC_USER; break;
149 default:
150 break;
151 }
152 continue;
153 }
154
155 thread__find_addr_location(thread, self, cpumode,
156 MAP__FUNCTION, ip, &al, NULL);
157 if (al.sym != NULL) {
158 if (sort__has_parent && !*parent &&
159 symbol__match_parent_regex(al.sym))
160 *parent = al.sym;
161 if (!symbol_conf.use_callchain)
162 break;
163 syms[i] = al.sym;
164 }
165 }
166
167 return syms;
168}
169
170static int process_event_stub(event_t *event __used,
171 struct perf_session *session __used)
172{
173 dump_printf(": unhandled!\n");
174 return 0;
175}
176
177static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
178{
179 if (handler->sample == NULL)
180 handler->sample = process_event_stub;
181 if (handler->mmap == NULL)
182 handler->mmap = process_event_stub;
183 if (handler->comm == NULL)
184 handler->comm = process_event_stub;
185 if (handler->fork == NULL)
186 handler->fork = process_event_stub;
187 if (handler->exit == NULL)
188 handler->exit = process_event_stub;
189 if (handler->lost == NULL)
190 handler->lost = process_event_stub;
191 if (handler->read == NULL)
192 handler->read = process_event_stub;
193 if (handler->throttle == NULL)
194 handler->throttle = process_event_stub;
195 if (handler->unthrottle == NULL)
196 handler->unthrottle = process_event_stub;
197}
198
199static const char *event__name[] = {
200 [0] = "TOTAL",
201 [PERF_RECORD_MMAP] = "MMAP",
202 [PERF_RECORD_LOST] = "LOST",
203 [PERF_RECORD_COMM] = "COMM",
204 [PERF_RECORD_EXIT] = "EXIT",
205 [PERF_RECORD_THROTTLE] = "THROTTLE",
206 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
207 [PERF_RECORD_FORK] = "FORK",
208 [PERF_RECORD_READ] = "READ",
209 [PERF_RECORD_SAMPLE] = "SAMPLE",
210};
211
212unsigned long event__total[PERF_RECORD_MAX];
213
214void event__print_totals(void)
215{
216 int i;
217 for (i = 0; i < PERF_RECORD_MAX; ++i)
218 pr_info("%10s events: %10ld\n",
219 event__name[i], event__total[i]);
220}
221
222void mem_bswap_64(void *src, int byte_size)
223{
224 u64 *m = src;
225
226 while (byte_size > 0) {
227 *m = bswap_64(*m);
228 byte_size -= sizeof(u64);
229 ++m;
230 }
231}
232
233static void event__all64_swap(event_t *self)
234{
235 struct perf_event_header *hdr = &self->header;
236 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
237}
238
239static void event__comm_swap(event_t *self)
240{
241 self->comm.pid = bswap_32(self->comm.pid);
242 self->comm.tid = bswap_32(self->comm.tid);
243}
244
245static void event__mmap_swap(event_t *self)
246{
247 self->mmap.pid = bswap_32(self->mmap.pid);
248 self->mmap.tid = bswap_32(self->mmap.tid);
249 self->mmap.start = bswap_64(self->mmap.start);
250 self->mmap.len = bswap_64(self->mmap.len);
251 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
252}
253
254static void event__task_swap(event_t *self)
255{
256 self->fork.pid = bswap_32(self->fork.pid);
257 self->fork.tid = bswap_32(self->fork.tid);
258 self->fork.ppid = bswap_32(self->fork.ppid);
259 self->fork.ptid = bswap_32(self->fork.ptid);
260 self->fork.time = bswap_64(self->fork.time);
261}
262
263static void event__read_swap(event_t *self)
264{
265 self->read.pid = bswap_32(self->read.pid);
266 self->read.tid = bswap_32(self->read.tid);
267 self->read.value = bswap_64(self->read.value);
268 self->read.time_enabled = bswap_64(self->read.time_enabled);
269 self->read.time_running = bswap_64(self->read.time_running);
270 self->read.id = bswap_64(self->read.id);
271}
272
273typedef void (*event__swap_op)(event_t *self);
274
275static event__swap_op event__swap_ops[] = {
276 [PERF_RECORD_MMAP] = event__mmap_swap,
277 [PERF_RECORD_COMM] = event__comm_swap,
278 [PERF_RECORD_FORK] = event__task_swap,
279 [PERF_RECORD_EXIT] = event__task_swap,
280 [PERF_RECORD_LOST] = event__all64_swap,
281 [PERF_RECORD_READ] = event__read_swap,
282 [PERF_RECORD_SAMPLE] = event__all64_swap,
283 [PERF_RECORD_MAX] = NULL,
284};
285
286static int perf_session__process_event(struct perf_session *self,
287 event_t *event,
288 struct perf_event_ops *ops,
289 u64 offset, u64 head)
290{
291 trace_event(event);
292
293 if (event->header.type < PERF_RECORD_MAX) {
294 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
295 offset + head, event->header.size,
296 event__name[event->header.type]);
297 ++event__total[0];
298 ++event__total[event->header.type];
299 }
300
301 if (self->header.needs_swap && event__swap_ops[event->header.type])
302 event__swap_ops[event->header.type](event);
303
304 switch (event->header.type) {
305 case PERF_RECORD_SAMPLE:
306 return ops->sample(event, self);
307 case PERF_RECORD_MMAP:
308 return ops->mmap(event, self);
309 case PERF_RECORD_COMM:
310 return ops->comm(event, self);
311 case PERF_RECORD_FORK:
312 return ops->fork(event, self);
313 case PERF_RECORD_EXIT:
314 return ops->exit(event, self);
315 case PERF_RECORD_LOST:
316 return ops->lost(event, self);
317 case PERF_RECORD_READ:
318 return ops->read(event, self);
319 case PERF_RECORD_THROTTLE:
320 return ops->throttle(event, self);
321 case PERF_RECORD_UNTHROTTLE:
322 return ops->unthrottle(event, self);
323 default:
324 self->unknown_events++;
325 return -1;
326 }
327}
328
329void perf_event_header__bswap(struct perf_event_header *self)
330{
331 self->type = bswap_32(self->type);
332 self->misc = bswap_16(self->misc);
333 self->size = bswap_16(self->size);
334}
335
336int perf_header__read_build_ids(struct perf_header *self,
337 int input, u64 offset, u64 size)
338{
339 struct build_id_event bev;
340 char filename[PATH_MAX];
341 u64 limit = offset + size;
342 int err = -1;
343
344 while (offset < limit) {
345 struct dso *dso;
346 ssize_t len;
347 struct list_head *head = &dsos__user;
348
349 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
350 goto out;
351
352 if (self->needs_swap)
353 perf_event_header__bswap(&bev.header);
354
355 len = bev.header.size - sizeof(bev);
356 if (read(input, filename, len) != len)
357 goto out;
358
359 if (bev.header.misc & PERF_RECORD_MISC_KERNEL)
360 head = &dsos__kernel;
361
362 dso = __dsos__findnew(head, filename);
363 if (dso != NULL) {
364 dso__set_build_id(dso, &bev.build_id);
365 if (head == &dsos__kernel && filename[0] == '[')
366 dso->kernel = 1;
367 }
368
369 offset += bev.header.size;
370 }
371 err = 0;
372out:
373 return err;
374}
375
376static struct thread *perf_session__register_idle_thread(struct perf_session *self)
377{
378 struct thread *thread = perf_session__findnew(self, 0);
379
380 if (thread == NULL || thread__set_comm(thread, "swapper")) {
381 pr_err("problem inserting idle task.\n");
382 thread = NULL;
383 }
384
385 return thread;
386}
387
388int __perf_session__process_events(struct perf_session *self,
389 u64 data_offset, u64 data_size,
390 u64 file_size, struct perf_event_ops *ops)
391{
392 int err, mmap_prot, mmap_flags;
393 u64 head, shift;
394 u64 offset = 0;
395 size_t page_size;
396 event_t *event;
397 uint32_t size;
398 char *buf;
399
400 perf_event_ops__fill_defaults(ops);
401
402 page_size = sysconf(_SC_PAGESIZE);
403
404 head = data_offset;
405 shift = page_size * (head / page_size);
406 offset += shift;
407 head -= shift;
408
409 mmap_prot = PROT_READ;
410 mmap_flags = MAP_SHARED;
411
412 if (self->header.needs_swap) {
413 mmap_prot |= PROT_WRITE;
414 mmap_flags = MAP_PRIVATE;
415 }
416remap:
417 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
418 mmap_flags, self->fd, offset);
419 if (buf == MAP_FAILED) {
420 pr_err("failed to mmap file\n");
421 err = -errno;
422 goto out_err;
423 }
424
425more:
426 event = (event_t *)(buf + head);
427
428 if (self->header.needs_swap)
429 perf_event_header__bswap(&event->header);
430 size = event->header.size;
431 if (size == 0)
432 size = 8;
433
434 if (head + event->header.size >= page_size * self->mmap_window) {
435 int munmap_ret;
436
437 shift = page_size * (head / page_size);
438
439 munmap_ret = munmap(buf, page_size * self->mmap_window);
440 assert(munmap_ret == 0);
441
442 offset += shift;
443 head -= shift;
444 goto remap;
445 }
446
447 size = event->header.size;
448
449 dump_printf("\n%#Lx [%#x]: event: %d\n",
450 offset + head, event->header.size, event->header.type);
451
452 if (size == 0 ||
453 perf_session__process_event(self, event, ops, offset, head) < 0) {
454 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
455 offset + head, event->header.size,
456 event->header.type);
457 /*
458 * assume we lost track of the stream, check alignment, and
459 * increment a single u64 in the hope to catch on again 'soon'.
460 */
461 if (unlikely(head & 7))
462 head &= ~7ULL;
463
464 size = 8;
465 }
466
467 head += size;
468
469 if (offset + head >= data_offset + data_size)
470 goto done;
471
472 if (offset + head < file_size)
473 goto more;
474done:
475 err = 0;
476out_err:
477 return err;
478}
479
480int perf_session__process_events(struct perf_session *self,
481 struct perf_event_ops *ops)
482{
483 int err;
484
485 if (perf_session__register_idle_thread(self) == NULL)
486 return -ENOMEM;
487
488 if (!symbol_conf.full_paths) {
489 char bf[PATH_MAX];
490
491 if (getcwd(bf, sizeof(bf)) == NULL) {
492 err = -errno;
493out_getcwd_err:
494 pr_err("failed to get the current directory\n");
495 goto out_err;
496 }
497 self->cwd = strdup(bf);
498 if (self->cwd == NULL) {
499 err = -ENOMEM;
500 goto out_getcwd_err;
501 }
502 self->cwdlen = strlen(self->cwd);
503 }
504
505 err = __perf_session__process_events(self, self->header.data_offset,
506 self->header.data_size,
507 self->size, ops);
508out_err:
509 return err;
510}
511
512bool perf_session__has_traces(struct perf_session *self, const char *msg)
513{
514 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
515 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
516 return false;
517 }
518
519 return true;
520}
521
522int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
523 const char *symbol_name,
524 u64 addr)
525{
526 char *bracket;
527 enum map_type i;
528
529 self->ref_reloc_sym.name = strdup(symbol_name);
530 if (self->ref_reloc_sym.name == NULL)
531 return -ENOMEM;
532
533 bracket = strchr(self->ref_reloc_sym.name, ']');
534 if (bracket)
535 *bracket = '\0';
536
537 self->ref_reloc_sym.addr = addr;
538
539 for (i = 0; i < MAP__NR_TYPES; ++i) {
540 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]);
541 kmap->ref_reloc_sym = &self->ref_reloc_sym;
542 }
543
544 return 0;
545}
546
547static u64 map__reloc_map_ip(struct map *map, u64 ip)
548{
549 return ip + (s64)map->pgoff;
550}
551
552static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
553{
554 return ip - (s64)map->pgoff;
555}
556
557void map__reloc_vmlinux(struct map *self)
558{
559 struct kmap *kmap = map__kmap(self);
560 s64 reloc;
561
562 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
563 return;
564
565 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
566 kmap->ref_reloc_sym->addr);
567
568 if (!reloc)
569 return;
570
571 self->map_ip = map__reloc_map_ip;
572 self->unmap_ip = map__reloc_unmap_ip;
573 self->pgoff = reloc;
574}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f3699c8c8ed4..5c33417eebb3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,16 +1,89 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "event.h"
4#include "header.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;
5 13
6struct perf_session { 14struct perf_session {
7 struct perf_header header; 15 struct perf_header header;
8 unsigned long size; 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 struct rb_root stats_by_id;
24 unsigned long event_total[PERF_RECORD_MAX];
25 unsigned long unknown_events;
26 struct rb_root hists;
27 u64 sample_type;
28 struct ref_reloc_sym ref_reloc_sym;
9 int fd; 29 int fd;
30 int cwdlen;
31 char *cwd;
10 char filename[0]; 32 char filename[0];
11}; 33};
12 34
35typedef int (*event_op)(event_t *self, struct perf_session *session);
36
37struct perf_event_ops {
38 event_op sample,
39 mmap,
40 comm,
41 fork,
42 exit,
43 lost,
44 read,
45 throttle,
46 unthrottle;
47};
48
13struct perf_session *perf_session__new(const char *filename, int mode, bool force); 49struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self); 50void perf_session__delete(struct perf_session *self);
15 51
52void perf_event_header__bswap(struct perf_event_header *self);
53
54int __perf_session__process_events(struct perf_session *self,
55 u64 data_offset, u64 data_size, u64 size,
56 struct perf_event_ops *ops);
57int perf_session__process_events(struct perf_session *self,
58 struct perf_event_ops *event_ops);
59
60struct symbol **perf_session__resolve_callchain(struct perf_session *self,
61 struct thread *thread,
62 struct ip_callchain *chain,
63 struct symbol **parent);
64
65bool perf_session__has_traces(struct perf_session *self, const char *msg);
66
67int perf_header__read_build_ids(struct perf_header *self, int input,
68 u64 offset, u64 file_size);
69
70int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
71 const char *symbol_name,
72 u64 addr);
73
74void mem_bswap_64(void *src, int byte_size);
75
76static inline int __perf_session__create_kernel_maps(struct perf_session *self,
77 struct dso *kernel)
78{
79 return __map_groups__create_kernel_maps(&self->kmaps,
80 self->vmlinux_maps, kernel);
81}
82
83static inline struct map *
84 perf_session__new_module_map(struct perf_session *self,
85 u64 start, const char *filename)
86{
87 return map_groups__new_module(&self->kmaps, start, filename);
88}
16#endif /* __PERF_SESSION_H */ 89#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b490354d1b23..cb0f327de9e8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -288,3 +288,29 @@ int sort_dimension__add(const char *tok)
288 288
289 return -ESRCH; 289 return -ESRCH;
290} 290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 333e664ff45f..753f9ea99fb0 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,9 +49,13 @@ struct hist_entry {
49 struct symbol *sym; 49 struct symbol *sym;
50 u64 ip; 50 u64 ip;
51 char level; 51 char level;
52 struct symbol *parent; 52 struct symbol *parent;
53 struct callchain_node callchain; 53 struct callchain_node callchain;
54 struct rb_root sorted_chain; 54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
55}; 59};
56 60
57enum sort_type { 61enum sort_type {
@@ -81,6 +85,8 @@ struct sort_entry {
81extern struct sort_entry sort_thread; 85extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list; 86extern struct list_head hist_entry__sort_list;
83 87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...); 90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
@@ -95,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *); 103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
98 106
99#endif /* __PERF_SORT_H */ 107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f24a8cc933d5..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -226,3 +226,114 @@ fail:
226 argv_free(argv); 226 argv_free(argv);
227 return NULL; 227 return NULL;
228} 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 bfecec265a1a..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
@@ -8,6 +9,8 @@ char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 9s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
11 14
12#define _STR(x) #x 15#define _STR(x) #x
13#define STR(x) _STR(x) 16#define STR(x) _STR(x)
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index cb4659306d7b..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* __PERF_STRLIST_H */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d3d9fed74f1d..c458c4a371d1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,6 @@
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"
5#include "thread.h" 6#include "thread.h"
@@ -20,6 +21,7 @@
20enum dso_origin { 21enum dso_origin {
21 DSO__ORIG_KERNEL = 0, 22 DSO__ORIG_KERNEL = 0,
22 DSO__ORIG_JAVA_JIT, 23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
23 DSO__ORIG_FEDORA, 25 DSO__ORIG_FEDORA,
24 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
25 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
@@ -31,19 +33,16 @@ enum dso_origin {
31static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
34 struct map_groups *mg, symbol_filter_t filter); 36 symbol_filter_t filter);
35unsigned int symbol__priv_size;
36static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
37static char **vmlinux_path; 38static char **vmlinux_path;
38 39
39static struct symbol_conf symbol_conf__defaults = { 40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
40 .use_modules = true, 42 .use_modules = true,
41 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
42}; 44};
43 45
44static struct map_groups kmaps_mem;
45struct map_groups *kmaps = &kmaps_mem;
46
47bool dso__loaded(const struct dso *self, enum map_type type) 46bool dso__loaded(const struct dso *self, enum map_type type)
48{ 47{
49 return self->loaded & (1 << type); 48 return self->loaded & (1 << type);
@@ -54,17 +53,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
54 return self->sorted_by_name & (1 << type); 53 return self->sorted_by_name & (1 << type);
55} 54}
56 55
57static void dso__set_loaded(struct dso *self, enum map_type type)
58{
59 self->loaded |= (1 << type);
60}
61
62static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 56static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
63{ 57{
64 self->sorted_by_name |= (1 << type); 58 self->sorted_by_name |= (1 << type);
65} 59}
66 60
67static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 61bool symbol_type__is_a(char symbol_type, enum map_type map_type)
68{ 62{
69 switch (map_type) { 63 switch (map_type) {
70 case MAP__FUNCTION: 64 case MAP__FUNCTION:
@@ -132,27 +126,27 @@ static void map_groups__fixup_end(struct map_groups *self)
132static struct symbol *symbol__new(u64 start, u64 len, const char *name) 126static struct symbol *symbol__new(u64 start, u64 len, const char *name)
133{ 127{
134 size_t namelen = strlen(name) + 1; 128 size_t namelen = strlen(name) + 1;
135 struct symbol *self = zalloc(symbol__priv_size + 129 struct symbol *self = zalloc(symbol_conf.priv_size +
136 sizeof(*self) + namelen); 130 sizeof(*self) + namelen);
137 if (self == NULL) 131 if (self == NULL)
138 return NULL; 132 return NULL;
139 133
140 if (symbol__priv_size) 134 if (symbol_conf.priv_size)
141 self = ((void *)self) + symbol__priv_size; 135 self = ((void *)self) + symbol_conf.priv_size;
142 136
143 self->start = start; 137 self->start = start;
144 self->end = len ? start + len - 1 : start; 138 self->end = len ? start + len - 1 : start;
145 139
146 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 140 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
147 141
148 memcpy(self->name, name, namelen); 142 memcpy(self->name, name, namelen);
149 143
150 return self; 144 return self;
151} 145}
152 146
153static void symbol__delete(struct symbol *self) 147void symbol__delete(struct symbol *self)
154{ 148{
155 free(((void *)self) - symbol__priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
156} 150}
157 151
158static size_t symbol__fprintf(struct symbol *self, FILE *fp) 152static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -161,7 +155,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
161 self->start, self->end, self->name); 155 self->start, self->end, self->name);
162} 156}
163 157
164static void dso__set_long_name(struct dso *self, char *name) 158void dso__set_long_name(struct dso *self, char *name)
165{ 159{
166 if (name == NULL) 160 if (name == NULL)
167 return; 161 return;
@@ -169,20 +163,28 @@ static void dso__set_long_name(struct dso *self, char *name)
169 self->long_name_len = strlen(name); 163 self->long_name_len = strlen(name);
170} 164}
171 165
166static void dso__set_short_name(struct dso *self, const char *name)
167{
168 if (name == NULL)
169 return;
170 self->short_name = name;
171 self->short_name_len = strlen(name);
172}
173
172static void dso__set_basename(struct dso *self) 174static void dso__set_basename(struct dso *self)
173{ 175{
174 self->short_name = basename(self->long_name); 176 dso__set_short_name(self, basename(self->long_name));
175} 177}
176 178
177struct dso *dso__new(const char *name) 179struct dso *dso__new(const char *name)
178{ 180{
179 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 181 struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
180 182
181 if (self != NULL) { 183 if (self != NULL) {
182 int i; 184 int i;
183 strcpy(self->name, name); 185 strcpy(self->name, name);
184 dso__set_long_name(self, self->name); 186 dso__set_long_name(self, self->name);
185 self->short_name = self->name; 187 dso__set_short_name(self, self->name);
186 for (i = 0; i < MAP__NR_TYPES; ++i) 188 for (i = 0; i < MAP__NR_TYPES; ++i)
187 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 189 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
188 self->slen_calculated = 0; 190 self->slen_calculated = 0;
@@ -345,10 +347,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
345 &self->symbols[type]); 347 &self->symbols[type]);
346} 348}
347 349
348int build_id__sprintf(u8 *self, int len, char *bf) 350int build_id__sprintf(const u8 *self, int len, char *bf)
349{ 351{
350 char *bid = bf; 352 char *bid = bf;
351 u8 *raw = self; 353 const u8 *raw = self;
352 int i; 354 int i;
353 355
354 for (i = 0; i < len; ++i) { 356 for (i = 0; i < len; ++i) {
@@ -373,6 +375,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
373 struct rb_node *nd; 375 struct rb_node *nd;
374 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 376 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
375 377
378 if (self->short_name != self->long_name)
379 ret += fprintf(fp, "%s, ", self->long_name);
380 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
381 self->loaded ? "" : "NOT ");
376 ret += dso__fprintf_buildid(self, fp); 382 ret += dso__fprintf_buildid(self, fp);
377 ret += fprintf(fp, ")\n"); 383 ret += fprintf(fp, ")\n");
378 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 384 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -383,24 +389,20 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
383 return ret; 389 return ret;
384} 390}
385 391
386/* 392int kallsyms__parse(const char *filename, void *arg,
387 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 393 int (*process_symbol)(void *arg, const char *name,
388 * so that we can in the next step set the symbol ->end address and then 394 char type, u64 start))
389 * call kernel_maps__split_kallsyms.
390 */
391static int dso__load_all_kallsyms(struct dso *self, struct map *map)
392{ 395{
393 char *line = NULL; 396 char *line = NULL;
394 size_t n; 397 size_t n;
395 struct rb_root *root = &self->symbols[map->type]; 398 int err = 0;
396 FILE *file = fopen("/proc/kallsyms", "r"); 399 FILE *file = fopen(filename, "r");
397 400
398 if (file == NULL) 401 if (file == NULL)
399 goto out_failure; 402 goto out_failure;
400 403
401 while (!feof(file)) { 404 while (!feof(file)) {
402 u64 start; 405 u64 start;
403 struct symbol *sym;
404 int line_len, len; 406 int line_len, len;
405 char symbol_type; 407 char symbol_type;
406 char *symbol_name; 408 char *symbol_name;
@@ -421,43 +423,72 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
421 continue; 423 continue;
422 424
423 symbol_type = toupper(line[len]); 425 symbol_type = toupper(line[len]);
424 if (!symbol_type__is_a(symbol_type, map->type))
425 continue;
426
427 symbol_name = line + len + 2; 426 symbol_name = line + len + 2;
428 /*
429 * Will fix up the end later, when we have all symbols sorted.
430 */
431 sym = symbol__new(start, 0, symbol_name);
432 427
433 if (sym == NULL) 428 err = process_symbol(arg, symbol_name, symbol_type, start);
434 goto out_delete_line; 429 if (err)
435 /* 430 break;
436 * We will pass the symbols to the filter later, in
437 * map__split_kallsyms, when we have split the maps per module
438 */
439 symbols__insert(root, sym);
440 } 431 }
441 432
442 free(line); 433 free(line);
443 fclose(file); 434 fclose(file);
435 return err;
444 436
445 return 0;
446
447out_delete_line:
448 free(line);
449out_failure: 437out_failure:
450 return -1; 438 return -1;
451} 439}
452 440
441struct process_kallsyms_args {
442 struct map *map;
443 struct dso *dso;
444};
445
446static int map__process_kallsym_symbol(void *arg, const char *name,
447 char type, u64 start)
448{
449 struct symbol *sym;
450 struct process_kallsyms_args *a = arg;
451 struct rb_root *root = &a->dso->symbols[a->map->type];
452
453 if (!symbol_type__is_a(type, a->map->type))
454 return 0;
455
456 /*
457 * Will fix up the end later, when we have all symbols sorted.
458 */
459 sym = symbol__new(start, 0, name);
460
461 if (sym == NULL)
462 return -ENOMEM;
463 /*
464 * We will pass the symbols to the filter later, in
465 * map__split_kallsyms, when we have split the maps per module
466 */
467 symbols__insert(root, sym);
468 return 0;
469}
470
471/*
472 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
473 * so that we can in the next step set the symbol ->end address and then
474 * call kernel_maps__split_kallsyms.
475 */
476static int dso__load_all_kallsyms(struct dso *self, const char *filename,
477 struct map *map)
478{
479 struct process_kallsyms_args args = { .map = map, .dso = self, };
480 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
481}
482
453/* 483/*
454 * Split the symbols into maps, making sure there are no overlaps, i.e. the 484 * Split the symbols into maps, making sure there are no overlaps, i.e. the
455 * kernel range is broken in several maps, named [kernel].N, as we don't have 485 * kernel range is broken in several maps, named [kernel].N, as we don't have
456 * the original ELF section names vmlinux have. 486 * the original ELF section names vmlinux have.
457 */ 487 */
458static int dso__split_kallsyms(struct dso *self, struct map *map, 488static int dso__split_kallsyms(struct dso *self, struct map *map,
459 struct map_groups *mg, symbol_filter_t filter) 489 symbol_filter_t filter)
460{ 490{
491 struct map_groups *kmaps = map__kmap(map)->kmaps;
461 struct map *curr_map = map; 492 struct map *curr_map = map;
462 struct symbol *pos; 493 struct symbol *pos;
463 int count = 0; 494 int count = 0;
@@ -473,18 +504,22 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
473 504
474 module = strchr(pos->name, '\t'); 505 module = strchr(pos->name, '\t');
475 if (module) { 506 if (module) {
476 if (!mg->use_modules) 507 if (!symbol_conf.use_modules)
477 goto discard_symbol; 508 goto discard_symbol;
478 509
479 *module++ = '\0'; 510 *module++ = '\0';
480 511
481 if (strcmp(self->name, module)) { 512 if (strcmp(curr_map->dso->short_name, module)) {
482 curr_map = map_groups__find_by_name(mg, map->type, module); 513 curr_map = map_groups__find_by_name(kmaps, map->type, module);
483 if (curr_map == NULL) { 514 if (curr_map == NULL) {
484 pr_debug("/proc/{kallsyms,modules} " 515 pr_debug("/proc/{kallsyms,modules} "
485 "inconsistency!\n"); 516 "inconsistency while looking "
517 "for \"%s\" module!\n", module);
486 return -1; 518 return -1;
487 } 519 }
520
521 if (curr_map->dso->loaded)
522 goto discard_symbol;
488 } 523 }
489 /* 524 /*
490 * So that we look just like we get from .ko files, 525 * So that we look just like we get from .ko files,
@@ -504,13 +539,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
504 return -1; 539 return -1;
505 540
506 curr_map = map__new2(pos->start, dso, map->type); 541 curr_map = map__new2(pos->start, dso, map->type);
507 if (map == NULL) { 542 if (curr_map == NULL) {
508 dso__delete(dso); 543 dso__delete(dso);
509 return -1; 544 return -1;
510 } 545 }
511 546
512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 547 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
513 map_groups__insert(mg, curr_map); 548 map_groups__insert(kmaps, curr_map);
514 ++kernel_range; 549 ++kernel_range;
515 } 550 }
516 551
@@ -529,24 +564,16 @@ discard_symbol: rb_erase(&pos->rb_node, root);
529 return count; 564 return count;
530} 565}
531 566
532 567int dso__load_kallsyms(struct dso *self, const char *filename,
533static int dso__load_kallsyms(struct dso *self, struct map *map, 568 struct map *map, symbol_filter_t filter)
534 struct map_groups *mg, symbol_filter_t filter)
535{ 569{
536 if (dso__load_all_kallsyms(self, map) < 0) 570 if (dso__load_all_kallsyms(self, filename, map) < 0)
537 return -1; 571 return -1;
538 572
539 symbols__fixup_end(&self->symbols[map->type]); 573 symbols__fixup_end(&self->symbols[map->type]);
540 self->origin = DSO__ORIG_KERNEL; 574 self->origin = DSO__ORIG_KERNEL;
541 575
542 return dso__split_kallsyms(self, map, mg, filter); 576 return dso__split_kallsyms(self, map, filter);
543}
544
545size_t kernel_maps__fprintf(FILE *fp)
546{
547 size_t printed = fprintf(fp, "Kernel maps:\n");
548 printed += map_groups__fprintf_maps(kmaps, fp);
549 return printed + fprintf(fp, "END kernel maps\n");
550} 577}
551 578
552static int dso__load_perf_map(struct dso *self, struct map *map, 579static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -872,13 +899,12 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
872 } 899 }
873} 900}
874 901
875static int dso__load_sym(struct dso *self, struct map *map, 902static int dso__load_sym(struct dso *self, struct map *map, const char *name,
876 struct map_groups *mg, const char *name, int fd, 903 int fd, symbol_filter_t filter, int kmodule)
877 symbol_filter_t filter, int kernel, int kmodule)
878{ 904{
905 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
879 struct map *curr_map = map; 906 struct map *curr_map = map;
880 struct dso *curr_dso = self; 907 struct dso *curr_dso = self;
881 size_t dso_name_len = strlen(self->short_name);
882 Elf_Data *symstrs, *secstrs; 908 Elf_Data *symstrs, *secstrs;
883 uint32_t nr_syms; 909 uint32_t nr_syms;
884 int err = -1; 910 int err = -1;
@@ -932,7 +958,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
932 nr_syms = shdr.sh_size / shdr.sh_entsize; 958 nr_syms = shdr.sh_size / shdr.sh_entsize;
933 959
934 memset(&sym, 0, sizeof(sym)); 960 memset(&sym, 0, sizeof(sym));
935 if (!kernel) { 961 if (!self->kernel) {
936 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 962 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
937 elf_section_by_name(elf, &ehdr, &shdr, 963 elf_section_by_name(elf, &ehdr, &shdr,
938 ".gnu.prelink_undo", 964 ".gnu.prelink_undo",
@@ -941,11 +967,15 @@ static int dso__load_sym(struct dso *self, struct map *map,
941 967
942 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 968 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
943 struct symbol *f; 969 struct symbol *f;
944 const char *elf_name; 970 const char *elf_name = elf_sym__name(&sym, symstrs);
945 char *demangled = NULL; 971 char *demangled = NULL;
946 int is_label = elf_sym__is_label(&sym); 972 int is_label = elf_sym__is_label(&sym);
947 const char *section_name; 973 const char *section_name;
948 974
975 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
976 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
977 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
978
949 if (!is_label && !elf_sym__is_a(&sym, map->type)) 979 if (!is_label && !elf_sym__is_a(&sym, map->type))
950 continue; 980 continue;
951 981
@@ -958,14 +988,14 @@ static int dso__load_sym(struct dso *self, struct map *map,
958 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 988 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
959 continue; 989 continue;
960 990
961 elf_name = elf_sym__name(&sym, symstrs);
962 section_name = elf_sec__name(&shdr, secstrs); 991 section_name = elf_sec__name(&shdr, secstrs);
963 992
964 if (kernel || kmodule) { 993 if (self->kernel || kmodule) {
965 char dso_name[PATH_MAX]; 994 char dso_name[PATH_MAX];
966 995
967 if (strcmp(section_name, 996 if (strcmp(section_name,
968 curr_dso->short_name + dso_name_len) == 0) 997 (curr_dso->short_name +
998 self->short_name_len)) == 0)
969 goto new_symbol; 999 goto new_symbol;
970 1000
971 if (strcmp(section_name, ".text") == 0) { 1001 if (strcmp(section_name, ".text") == 0) {
@@ -977,7 +1007,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
977 snprintf(dso_name, sizeof(dso_name), 1007 snprintf(dso_name, sizeof(dso_name),
978 "%s%s", self->short_name, section_name); 1008 "%s%s", self->short_name, section_name);
979 1009
980 curr_map = map_groups__find_by_name(mg, map->type, dso_name); 1010 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
981 if (curr_map == NULL) { 1011 if (curr_map == NULL) {
982 u64 start = sym.st_value; 1012 u64 start = sym.st_value;
983 1013
@@ -988,7 +1018,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
988 if (curr_dso == NULL) 1018 if (curr_dso == NULL)
989 goto out_elf_end; 1019 goto out_elf_end;
990 curr_map = map__new2(start, curr_dso, 1020 curr_map = map__new2(start, curr_dso,
991 MAP__FUNCTION); 1021 map->type);
992 if (curr_map == NULL) { 1022 if (curr_map == NULL) {
993 dso__delete(curr_dso); 1023 dso__delete(curr_dso);
994 goto out_elf_end; 1024 goto out_elf_end;
@@ -996,8 +1026,9 @@ static int dso__load_sym(struct dso *self, struct map *map,
996 curr_map->map_ip = identity__map_ip; 1026 curr_map->map_ip = identity__map_ip;
997 curr_map->unmap_ip = identity__map_ip; 1027 curr_map->unmap_ip = identity__map_ip;
998 curr_dso->origin = DSO__ORIG_KERNEL; 1028 curr_dso->origin = DSO__ORIG_KERNEL;
999 map_groups__insert(kmaps, curr_map); 1029 map_groups__insert(kmap->kmaps, curr_map);
1000 dsos__add(&dsos__kernel, curr_dso); 1030 dsos__add(&dsos__kernel, curr_dso);
1031 dso__set_loaded(curr_dso, map->type);
1001 } else 1032 } else
1002 curr_dso = curr_map->dso; 1033 curr_dso = curr_map->dso;
1003 1034
@@ -1005,9 +1036,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
1005 } 1036 }
1006 1037
1007 if (curr_dso->adjust_symbols) { 1038 if (curr_dso->adjust_symbols) {
1008 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1039 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1009 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1040 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1010 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1041 (u64)sym.st_value, (u64)shdr.sh_addr,
1042 (u64)shdr.sh_offset);
1011 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1043 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1012 } 1044 }
1013 /* 1045 /*
@@ -1035,8 +1067,16 @@ new_symbol:
1035 /* 1067 /*
1036 * For misannotated, zeroed, ASM function sizes. 1068 * For misannotated, zeroed, ASM function sizes.
1037 */ 1069 */
1038 if (nr > 0) 1070 if (nr > 0) {
1039 symbols__fixup_end(&self->symbols[map->type]); 1071 symbols__fixup_end(&self->symbols[map->type]);
1072 if (kmap) {
1073 /*
1074 * We need to fixup this here too because we create new
1075 * maps here, for things like vsyscall sections.
1076 */
1077 __map_groups__fixup_end(kmap->kmaps, map->type);
1078 }
1079 }
1040 err = nr; 1080 err = nr;
1041out_elf_end: 1081out_elf_end:
1042 elf_end(elf); 1082 elf_end(elf);
@@ -1049,25 +1089,28 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1049 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1089 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1050} 1090}
1051 1091
1052static bool __dsos__read_build_ids(struct list_head *head) 1092static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1053{ 1093{
1054 bool have_build_id = false; 1094 bool have_build_id = false;
1055 struct dso *pos; 1095 struct dso *pos;
1056 1096
1057 list_for_each_entry(pos, head, node) 1097 list_for_each_entry(pos, head, node) {
1098 if (with_hits && !pos->hit)
1099 continue;
1058 if (filename__read_build_id(pos->long_name, pos->build_id, 1100 if (filename__read_build_id(pos->long_name, pos->build_id,
1059 sizeof(pos->build_id)) > 0) { 1101 sizeof(pos->build_id)) > 0) {
1060 have_build_id = true; 1102 have_build_id = true;
1061 pos->has_build_id = true; 1103 pos->has_build_id = true;
1062 } 1104 }
1105 }
1063 1106
1064 return have_build_id; 1107 return have_build_id;
1065} 1108}
1066 1109
1067bool dsos__read_build_ids(void) 1110bool dsos__read_build_ids(bool with_hits)
1068{ 1111{
1069 bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 1112 bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
1070 ubuildids = __dsos__read_build_ids(&dsos__user); 1113 ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
1071 return kbuildids || ubuildids; 1114 return kbuildids || ubuildids;
1072} 1115}
1073 1116
@@ -1199,6 +1242,7 @@ char dso__symtab_origin(const struct dso *self)
1199 static const char origin[] = { 1242 static const char origin[] = {
1200 [DSO__ORIG_KERNEL] = 'k', 1243 [DSO__ORIG_KERNEL] = 'k',
1201 [DSO__ORIG_JAVA_JIT] = 'j', 1244 [DSO__ORIG_JAVA_JIT] = 'j',
1245 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1202 [DSO__ORIG_FEDORA] = 'f', 1246 [DSO__ORIG_FEDORA] = 'f',
1203 [DSO__ORIG_UBUNTU] = 'u', 1247 [DSO__ORIG_UBUNTU] = 'u',
1204 [DSO__ORIG_BUILDID] = 'b', 1248 [DSO__ORIG_BUILDID] = 'b',
@@ -1216,13 +1260,14 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1216 int size = PATH_MAX; 1260 int size = PATH_MAX;
1217 char *name; 1261 char *name;
1218 u8 build_id[BUILD_ID_SIZE]; 1262 u8 build_id[BUILD_ID_SIZE];
1263 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1219 int ret = -1; 1264 int ret = -1;
1220 int fd; 1265 int fd;
1221 1266
1222 dso__set_loaded(self, map->type); 1267 dso__set_loaded(self, map->type);
1223 1268
1224 if (self->kernel) 1269 if (self->kernel)
1225 return dso__load_kernel_sym(self, map, kmaps, filter); 1270 return dso__load_kernel_sym(self, map, filter);
1226 1271
1227 name = malloc(size); 1272 name = malloc(size);
1228 if (!name) 1273 if (!name)
@@ -1237,8 +1282,16 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1237 return ret; 1282 return ret;
1238 } 1283 }
1239 1284
1240 self->origin = DSO__ORIG_FEDORA - 1; 1285 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1241 1286
1287 if (self->has_build_id) {
1288 build_id__sprintf(self->build_id, sizeof(self->build_id),
1289 build_id_hex);
1290 snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
1291 getenv("HOME"), DEBUG_CACHE_DIR,
1292 build_id_hex, build_id_hex + 2);
1293 goto open_file;
1294 }
1242more: 1295more:
1243 do { 1296 do {
1244 self->origin++; 1297 self->origin++;
@@ -1254,8 +1307,6 @@ more:
1254 case DSO__ORIG_BUILDID: 1307 case DSO__ORIG_BUILDID:
1255 if (filename__read_build_id(self->long_name, build_id, 1308 if (filename__read_build_id(self->long_name, build_id,
1256 sizeof(build_id))) { 1309 sizeof(build_id))) {
1257 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1258
1259 build_id__sprintf(build_id, sizeof(build_id), 1310 build_id__sprintf(build_id, sizeof(build_id),
1260 build_id_hex); 1311 build_id_hex);
1261 snprintf(name, size, 1312 snprintf(name, size,
@@ -1283,11 +1334,11 @@ compare_build_id:
1283 if (!dso__build_id_equal(self, build_id)) 1334 if (!dso__build_id_equal(self, build_id))
1284 goto more; 1335 goto more;
1285 } 1336 }
1286 1337open_file:
1287 fd = open(name, O_RDONLY); 1338 fd = open(name, O_RDONLY);
1288 } while (fd < 0); 1339 } while (fd < 0);
1289 1340
1290 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1341 ret = dso__load_sym(self, map, name, fd, filter, 0);
1291 close(fd); 1342 close(fd);
1292 1343
1293 /* 1344 /*
@@ -1316,14 +1367,34 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1316 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1367 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1317 struct map *map = rb_entry(nd, struct map, rb_node); 1368 struct map *map = rb_entry(nd, struct map, rb_node);
1318 1369
1319 if (map->dso && strcmp(map->dso->name, name) == 0) 1370 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1320 return map; 1371 return map;
1321 } 1372 }
1322 1373
1323 return NULL; 1374 return NULL;
1324} 1375}
1325 1376
1326static int dsos__set_modules_path_dir(char *dirname) 1377static int dso__kernel_module_get_build_id(struct dso *self)
1378{
1379 char filename[PATH_MAX];
1380 /*
1381 * kernel module short names are of the form "[module]" and
1382 * we need just "module" here.
1383 */
1384 const char *name = self->short_name + 1;
1385
1386 snprintf(filename, sizeof(filename),
1387 "/sys/module/%.*s/notes/.note.gnu.build-id",
1388 (int)strlen(name - 1), name);
1389
1390 if (sysfs__read_build_id(filename, self->build_id,
1391 sizeof(self->build_id)) == 0)
1392 self->has_build_id = true;
1393
1394 return 0;
1395}
1396
1397static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
1327{ 1398{
1328 struct dirent *dent; 1399 struct dirent *dent;
1329 DIR *dir = opendir(dirname); 1400 DIR *dir = opendir(dirname);
@@ -1343,7 +1414,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1343 1414
1344 snprintf(path, sizeof(path), "%s/%s", 1415 snprintf(path, sizeof(path), "%s/%s",
1345 dirname, dent->d_name); 1416 dirname, dent->d_name);
1346 if (dsos__set_modules_path_dir(path) < 0) 1417 if (map_groups__set_modules_path_dir(self, path) < 0)
1347 goto failure; 1418 goto failure;
1348 } else { 1419 } else {
1349 char *dot = strrchr(dent->d_name, '.'), 1420 char *dot = strrchr(dent->d_name, '.'),
@@ -1357,7 +1428,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1357 (int)(dot - dent->d_name), dent->d_name); 1428 (int)(dot - dent->d_name), dent->d_name);
1358 1429
1359 strxfrchar(dso_name, '-', '_'); 1430 strxfrchar(dso_name, '-', '_');
1360 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); 1431 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1361 if (map == NULL) 1432 if (map == NULL)
1362 continue; 1433 continue;
1363 1434
@@ -1368,6 +1439,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1368 if (long_name == NULL) 1439 if (long_name == NULL)
1369 goto failure; 1440 goto failure;
1370 dso__set_long_name(map->dso, long_name); 1441 dso__set_long_name(map->dso, long_name);
1442 dso__kernel_module_get_build_id(map->dso);
1371 } 1443 }
1372 } 1444 }
1373 1445
@@ -1377,7 +1449,7 @@ failure:
1377 return -1; 1449 return -1;
1378} 1450}
1379 1451
1380static int dsos__set_modules_path(void) 1452static int map_groups__set_modules_path(struct map_groups *self)
1381{ 1453{
1382 struct utsname uts; 1454 struct utsname uts;
1383 char modules_path[PATH_MAX]; 1455 char modules_path[PATH_MAX];
@@ -1388,7 +1460,7 @@ static int dsos__set_modules_path(void)
1388 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1460 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1389 uts.release); 1461 uts.release);
1390 1462
1391 return dsos__set_modules_path_dir(modules_path); 1463 return map_groups__set_modules_path_dir(self, modules_path);
1392} 1464}
1393 1465
1394/* 1466/*
@@ -1398,8 +1470,8 @@ static int dsos__set_modules_path(void)
1398 */ 1470 */
1399static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1471static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1400{ 1472{
1401 struct map *self = malloc(sizeof(*self)); 1473 struct map *self = zalloc(sizeof(*self) +
1402 1474 (dso->kernel ? sizeof(struct kmap) : 0));
1403 if (self != NULL) { 1475 if (self != NULL) {
1404 /* 1476 /*
1405 * ->end will be filled after we load all the symbols 1477 * ->end will be filled after we load all the symbols
@@ -1410,7 +1482,25 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1410 return self; 1482 return self;
1411} 1483}
1412 1484
1413static int map_groups__create_module_maps(struct map_groups *self) 1485struct map *map_groups__new_module(struct map_groups *self, u64 start,
1486 const char *filename)
1487{
1488 struct map *map;
1489 struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1490
1491 if (dso == NULL)
1492 return NULL;
1493
1494 map = map__new2(start, dso, MAP__FUNCTION);
1495 if (map == NULL)
1496 return NULL;
1497
1498 dso->origin = DSO__ORIG_KMODULE;
1499 map_groups__insert(self, map);
1500 return map;
1501}
1502
1503static int map_groups__create_modules(struct map_groups *self)
1414{ 1504{
1415 char *line = NULL; 1505 char *line = NULL;
1416 size_t n; 1506 size_t n;
@@ -1423,7 +1513,6 @@ static int map_groups__create_module_maps(struct map_groups *self)
1423 while (!feof(file)) { 1513 while (!feof(file)) {
1424 char name[PATH_MAX]; 1514 char name[PATH_MAX];
1425 u64 start; 1515 u64 start;
1426 struct dso *dso;
1427 char *sep; 1516 char *sep;
1428 int line_len; 1517 int line_len;
1429 1518
@@ -1449,32 +1538,16 @@ static int map_groups__create_module_maps(struct map_groups *self)
1449 *sep = '\0'; 1538 *sep = '\0';
1450 1539
1451 snprintf(name, sizeof(name), "[%s]", line); 1540 snprintf(name, sizeof(name), "[%s]", line);
1452 dso = dso__new(name); 1541 map = map_groups__new_module(self, start, name);
1453 1542 if (map == NULL)
1454 if (dso == NULL)
1455 goto out_delete_line; 1543 goto out_delete_line;
1456 1544 dso__kernel_module_get_build_id(map->dso);
1457 map = map__new2(start, dso, MAP__FUNCTION);
1458 if (map == NULL) {
1459 dso__delete(dso);
1460 goto out_delete_line;
1461 }
1462
1463 snprintf(name, sizeof(name),
1464 "/sys/module/%s/notes/.note.gnu.build-id", line);
1465 if (sysfs__read_build_id(name, dso->build_id,
1466 sizeof(dso->build_id)) == 0)
1467 dso->has_build_id = true;
1468
1469 dso->origin = DSO__ORIG_KMODULE;
1470 map_groups__insert(self, map);
1471 dsos__add(&dsos__kernel, dso);
1472 } 1545 }
1473 1546
1474 free(line); 1547 free(line);
1475 fclose(file); 1548 fclose(file);
1476 1549
1477 return dsos__set_modules_path(); 1550 return map_groups__set_modules_path(self);
1478 1551
1479out_delete_line: 1552out_delete_line:
1480 free(line); 1553 free(line);
@@ -1483,7 +1556,6 @@ out_failure:
1483} 1556}
1484 1557
1485static int dso__load_vmlinux(struct dso *self, struct map *map, 1558static int dso__load_vmlinux(struct dso *self, struct map *map,
1486 struct map_groups *mg,
1487 const char *vmlinux, symbol_filter_t filter) 1559 const char *vmlinux, symbol_filter_t filter)
1488{ 1560{
1489 int err = -1, fd; 1561 int err = -1, fd;
@@ -1517,51 +1589,124 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1517 return -1; 1589 return -1;
1518 1590
1519 dso__set_loaded(self, map->type); 1591 dso__set_loaded(self, map->type);
1520 err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 1592 err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
1521 close(fd); 1593 close(fd);
1522 1594
1595 if (err > 0)
1596 pr_debug("Using %s for symbols\n", vmlinux);
1597
1598 return err;
1599}
1600
1601int dso__load_vmlinux_path(struct dso *self, struct map *map,
1602 symbol_filter_t filter)
1603{
1604 int i, err = 0;
1605
1606 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1607 vmlinux_path__nr_entries);
1608
1609 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1610 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1611 if (err > 0) {
1612 dso__set_long_name(self, strdup(vmlinux_path[i]));
1613 break;
1614 }
1615 }
1616
1523 return err; 1617 return err;
1524} 1618}
1525 1619
1526static int dso__load_kernel_sym(struct dso *self, struct map *map, 1620static int dso__load_kernel_sym(struct dso *self, struct map *map,
1527 struct map_groups *mg, symbol_filter_t filter) 1621 symbol_filter_t filter)
1528{ 1622{
1529 int err; 1623 int err;
1530 bool is_kallsyms; 1624 const char *kallsyms_filename = NULL;
1625 char *kallsyms_allocated_filename = NULL;
1626 /*
1627 * Step 1: if the user specified a vmlinux filename, use it and only
1628 * it, reporting errors to the user if it cannot be used.
1629 *
1630 * For instance, try to analyse an ARM perf.data file _without_ a
1631 * build-id, or if the user specifies the wrong path to the right
1632 * vmlinux file, obviously we can't fallback to another vmlinux (a
1633 * x86_86 one, on the machine where analysis is being performed, say),
1634 * or worse, /proc/kallsyms.
1635 *
1636 * If the specified file _has_ a build-id and there is a build-id
1637 * section in the perf.data file, we will still do the expected
1638 * validation in dso__load_vmlinux and will bail out if they don't
1639 * match.
1640 */
1641 if (symbol_conf.vmlinux_name != NULL) {
1642 err = dso__load_vmlinux(self, map,
1643 symbol_conf.vmlinux_name, filter);
1644 goto out_try_fixup;
1645 }
1531 1646
1532 if (vmlinux_path != NULL) { 1647 if (vmlinux_path != NULL) {
1533 int i; 1648 err = dso__load_vmlinux_path(self, map, filter);
1534 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1649 if (err > 0)
1535 vmlinux_path__nr_entries); 1650 goto out_fixup;
1536 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1651 }
1537 err = dso__load_vmlinux(self, map, mg, 1652
1538 vmlinux_path[i], filter); 1653 /*
1539 if (err > 0) { 1654 * Say the kernel DSO was created when processing the build-id header table,
1540 pr_debug("Using %s for symbols\n", 1655 * we have a build-id, so check if it is the same as the running kernel,
1541 vmlinux_path[i]); 1656 * using it if it is.
1542 dso__set_long_name(self, 1657 */
1543 strdup(vmlinux_path[i])); 1658 if (self->has_build_id) {
1544 goto out_fixup; 1659 u8 kallsyms_build_id[BUILD_ID_SIZE];
1660 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1661
1662 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1663 sizeof(kallsyms_build_id)) == 0) {
1664 if (dso__build_id_equal(self, kallsyms_build_id)) {
1665 kallsyms_filename = "/proc/kallsyms";
1666 goto do_kallsyms;
1545 } 1667 }
1546 } 1668 }
1547 } 1669 /*
1670 * Now look if we have it on the build-id cache in
1671 * $HOME/.debug/[kernel.kallsyms].
1672 */
1673 build_id__sprintf(self->build_id, sizeof(self->build_id),
1674 sbuild_id);
1675
1676 if (asprintf(&kallsyms_allocated_filename,
1677 "%s/.debug/[kernel.kallsyms]/%s",
1678 getenv("HOME"), sbuild_id) == -1) {
1679 pr_err("Not enough memory for kallsyms file lookup\n");
1680 return -1;
1681 }
1548 1682
1549 is_kallsyms = self->long_name[0] == '['; 1683 kallsyms_filename = kallsyms_allocated_filename;
1550 if (is_kallsyms)
1551 goto do_kallsyms;
1552 1684
1553 err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1685 if (access(kallsyms_filename, F_OK)) {
1554 if (err <= 0) { 1686 pr_err("No kallsyms or vmlinux with build-id %s "
1555 pr_info("The file %s cannot be used, " 1687 "was found\n", sbuild_id);
1556 "trying to use /proc/kallsyms...", self->long_name); 1688 free(kallsyms_allocated_filename);
1557do_kallsyms: 1689 return -1;
1558 err = dso__load_kallsyms(self, map, mg, filter); 1690 }
1559 if (err > 0 && !is_kallsyms) 1691 } else {
1560 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1692 /*
1693 * Last resort, if we don't have a build-id and couldn't find
1694 * any vmlinux file, try the running kernel kallsyms table.
1695 */
1696 kallsyms_filename = "/proc/kallsyms";
1561 } 1697 }
1562 1698
1699do_kallsyms:
1700 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1701 if (err > 0)
1702 pr_debug("Using %s for symbols\n", kallsyms_filename);
1703 free(kallsyms_allocated_filename);
1704
1705out_try_fixup:
1563 if (err > 0) { 1706 if (err > 0) {
1564out_fixup: 1707out_fixup:
1708 if (kallsyms_filename != NULL)
1709 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1565 map__fixup_start(map); 1710 map__fixup_start(map);
1566 map__fixup_end(map); 1711 map__fixup_end(map);
1567 } 1712 }
@@ -1571,7 +1716,6 @@ out_fixup:
1571 1716
1572LIST_HEAD(dsos__user); 1717LIST_HEAD(dsos__user);
1573LIST_HEAD(dsos__kernel); 1718LIST_HEAD(dsos__kernel);
1574struct dso *vdso;
1575 1719
1576static void dsos__add(struct list_head *head, struct dso *dso) 1720static void dsos__add(struct list_head *head, struct dso *dso)
1577{ 1721{
@@ -1583,19 +1727,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1583 struct dso *pos; 1727 struct dso *pos;
1584 1728
1585 list_for_each_entry(pos, head, node) 1729 list_for_each_entry(pos, head, node)
1586 if (strcmp(pos->name, name) == 0) 1730 if (strcmp(pos->long_name, name) == 0)
1587 return pos; 1731 return pos;
1588 return NULL; 1732 return NULL;
1589} 1733}
1590 1734
1591struct dso *dsos__findnew(const char *name) 1735struct dso *__dsos__findnew(struct list_head *head, const char *name)
1592{ 1736{
1593 struct dso *dso = dsos__find(&dsos__user, name); 1737 struct dso *dso = dsos__find(head, name);
1594 1738
1595 if (!dso) { 1739 if (!dso) {
1596 dso = dso__new(name); 1740 dso = dso__new(name);
1597 if (dso != NULL) { 1741 if (dso != NULL) {
1598 dsos__add(&dsos__user, dso); 1742 dsos__add(head, dso);
1599 dso__set_basename(dso); 1743 dso__set_basename(dso);
1600 } 1744 }
1601 } 1745 }
@@ -1620,75 +1764,78 @@ void dsos__fprintf(FILE *fp)
1620 __dsos__fprintf(&dsos__user, fp); 1764 __dsos__fprintf(&dsos__user, fp);
1621} 1765}
1622 1766
1623static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 1767static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1768 bool with_hits)
1624{ 1769{
1625 struct dso *pos; 1770 struct dso *pos;
1626 size_t ret = 0; 1771 size_t ret = 0;
1627 1772
1628 list_for_each_entry(pos, head, node) { 1773 list_for_each_entry(pos, head, node) {
1774 if (with_hits && !pos->hit)
1775 continue;
1629 ret += dso__fprintf_buildid(pos, fp); 1776 ret += dso__fprintf_buildid(pos, fp);
1630 ret += fprintf(fp, " %s\n", pos->long_name); 1777 ret += fprintf(fp, " %s\n", pos->long_name);
1631 } 1778 }
1632 return ret; 1779 return ret;
1633} 1780}
1634 1781
1635size_t dsos__fprintf_buildid(FILE *fp) 1782size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
1636{ 1783{
1637 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1784 return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
1638 __dsos__fprintf_buildid(&dsos__user, fp)); 1785 __dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1639} 1786}
1640 1787
1641static struct dso *dsos__create_kernel( const char *vmlinux) 1788struct dso *dso__new_kernel(const char *name)
1642{ 1789{
1643 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1790 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1644 1791
1645 if (kernel == NULL) 1792 if (self != NULL) {
1646 return NULL; 1793 dso__set_short_name(self, "[kernel]");
1794 self->kernel = 1;
1795 }
1647 1796
1648 kernel->short_name = "[kernel]"; 1797 return self;
1649 kernel->kernel = 1; 1798}
1650 1799
1651 vdso = dso__new("[vdso]"); 1800void dso__read_running_kernel_build_id(struct dso *self)
1652 if (vdso == NULL) 1801{
1653 goto out_delete_kernel_dso; 1802 if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1654 dso__set_loaded(vdso, MAP__FUNCTION); 1803 sizeof(self->build_id)) == 0)
1804 self->has_build_id = true;
1805}
1655 1806
1656 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 1807static struct dso *dsos__create_kernel(const char *vmlinux)
1657 sizeof(kernel->build_id)) == 0) 1808{
1658 kernel->has_build_id = true; 1809 struct dso *kernel = dso__new_kernel(vmlinux);
1659 1810
1660 dsos__add(&dsos__kernel, kernel); 1811 if (kernel != NULL) {
1661 dsos__add(&dsos__user, vdso); 1812 dso__read_running_kernel_build_id(kernel);
1813 dsos__add(&dsos__kernel, kernel);
1814 }
1662 1815
1663 return kernel; 1816 return kernel;
1664
1665out_delete_kernel_dso:
1666 dso__delete(kernel);
1667 return NULL;
1668} 1817}
1669 1818
1670static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1819int __map_groups__create_kernel_maps(struct map_groups *self,
1820 struct map *vmlinux_maps[MAP__NR_TYPES],
1821 struct dso *kernel)
1671{ 1822{
1672 struct map *functions, *variables; 1823 enum map_type type;
1673 struct dso *kernel = dsos__create_kernel(vmlinux);
1674 1824
1675 if (kernel == NULL) 1825 for (type = 0; type < MAP__NR_TYPES; ++type) {
1676 return -1; 1826 struct kmap *kmap;
1677 1827
1678 functions = map__new2(0, kernel, MAP__FUNCTION); 1828 vmlinux_maps[type] = map__new2(0, kernel, type);
1679 if (functions == NULL) 1829 if (vmlinux_maps[type] == NULL)
1680 return -1; 1830 return -1;
1681 1831
1682 variables = map__new2(0, kernel, MAP__VARIABLE); 1832 vmlinux_maps[type]->map_ip =
1683 if (variables == NULL) { 1833 vmlinux_maps[type]->unmap_ip = identity__map_ip;
1684 map__delete(functions);
1685 return -1;
1686 }
1687 1834
1688 functions->map_ip = functions->unmap_ip = 1835 kmap = map__kmap(vmlinux_maps[type]);
1689 variables->map_ip = variables->unmap_ip = identity__map_ip; 1836 kmap->kmaps = self;
1690 map_groups__insert(self, functions); 1837 map_groups__insert(self, vmlinux_maps[type]);
1691 map_groups__insert(self, variables); 1838 }
1692 1839
1693 return 0; 1840 return 0;
1694} 1841}
@@ -1748,32 +1895,72 @@ out_fail:
1748 return -1; 1895 return -1;
1749} 1896}
1750 1897
1751int symbol__init(struct symbol_conf *conf) 1898static int setup_list(struct strlist **list, const char *list_str,
1899 const char *list_name)
1752{ 1900{
1753 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1901 if (list_str == NULL)
1902 return 0;
1754 1903
1904 *list = strlist__new(true, list_str);
1905 if (!*list) {
1906 pr_err("problems parsing %s list\n", list_name);
1907 return -1;
1908 }
1909 return 0;
1910}
1911
1912int symbol__init(void)
1913{
1755 elf_version(EV_CURRENT); 1914 elf_version(EV_CURRENT);
1756 symbol__priv_size = pconf->priv_size; 1915 if (symbol_conf.sort_by_name)
1757 if (pconf->sort_by_name) 1916 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1758 symbol__priv_size += (sizeof(struct symbol_name_rb_node) - 1917 sizeof(struct symbol));
1759 sizeof(struct symbol));
1760 map_groups__init(kmaps);
1761 1918
1762 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1919 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1763 return -1; 1920 return -1;
1764 1921
1765 if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { 1922 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1766 vmlinux_path__exit(); 1923 pr_err("'.' is the only non valid --field-separator argument\n");
1767 return -1; 1924 return -1;
1768 } 1925 }
1769 1926
1770 kmaps->use_modules = pconf->use_modules; 1927 if (setup_list(&symbol_conf.dso_list,
1771 if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 1928 symbol_conf.dso_list_str, "dso") < 0)
1772 pr_debug("Failed to load list of modules in use, " 1929 return -1;
1773 "continuing...\n"); 1930
1931 if (setup_list(&symbol_conf.comm_list,
1932 symbol_conf.comm_list_str, "comm") < 0)
1933 goto out_free_dso_list;
1934
1935 if (setup_list(&symbol_conf.sym_list,
1936 symbol_conf.sym_list_str, "symbol") < 0)
1937 goto out_free_comm_list;
1938
1939 return 0;
1940
1941out_free_dso_list:
1942 strlist__delete(symbol_conf.dso_list);
1943out_free_comm_list:
1944 strlist__delete(symbol_conf.comm_list);
1945 return -1;
1946}
1947
1948int map_groups__create_kernel_maps(struct map_groups *self,
1949 struct map *vmlinux_maps[MAP__NR_TYPES])
1950{
1951 struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
1952
1953 if (kernel == NULL)
1954 return -1;
1955
1956 if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
1957 return -1;
1958
1959 if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
1960 pr_debug("Problems creating module maps, continuing anyway...\n");
1774 /* 1961 /*
1775 * Now that we have all the maps created, just set the ->end of them: 1962 * Now that we have all the maps created, just set the ->end of them:
1776 */ 1963 */
1777 map_groups__fixup_end(kmaps); 1964 map_groups__fixup_end(self);
1778 return 0; 1965 return 0;
1779} 1966}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index cf99f88adf39..f30a37428919 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -8,6 +8,8 @@
8#include <linux/rbtree.h> 8#include <linux/rbtree.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
@@ -49,27 +51,50 @@ struct symbol {
49 char name[0]; 51 char name[0];
50}; 52};
51 53
54void symbol__delete(struct symbol *self);
55
56struct strlist;
57
52struct symbol_conf { 58struct symbol_conf {
53 unsigned short priv_size; 59 unsigned short priv_size;
54 bool try_vmlinux_path, 60 bool try_vmlinux_path,
55 use_modules, 61 use_modules,
56 sort_by_name; 62 sort_by_name,
57 const char *vmlinux_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;
58}; 76};
59 77
60extern unsigned int symbol__priv_size; 78extern struct symbol_conf symbol_conf;
61 79
62static inline void *symbol__priv(struct symbol *self) 80static inline void *symbol__priv(struct symbol *self)
63{ 81{
64 return ((void *)self) - symbol__priv_size; 82 return ((void *)self) - symbol_conf.priv_size;
65} 83}
66 84
85struct ref_reloc_sym {
86 const char *name;
87 u64 addr;
88 u64 unrelocated_addr;
89};
90
67struct addr_location { 91struct addr_location {
68 struct thread *thread; 92 struct thread *thread;
69 struct map *map; 93 struct map *map;
70 struct symbol *sym; 94 struct symbol *sym;
71 u64 addr; 95 u64 addr;
72 char level; 96 char level;
97 bool filtered;
73}; 98};
74 99
75struct dso { 100struct dso {
@@ -80,48 +105,68 @@ struct dso {
80 u8 slen_calculated:1; 105 u8 slen_calculated:1;
81 u8 has_build_id:1; 106 u8 has_build_id:1;
82 u8 kernel:1; 107 u8 kernel:1;
108 u8 hit:1;
83 unsigned char origin; 109 unsigned char origin;
84 u8 sorted_by_name; 110 u8 sorted_by_name;
85 u8 loaded; 111 u8 loaded;
86 u8 build_id[BUILD_ID_SIZE]; 112 u8 build_id[BUILD_ID_SIZE];
87 u16 long_name_len;
88 const char *short_name; 113 const char *short_name;
89 char *long_name; 114 char *long_name;
115 u16 long_name_len;
116 u16 short_name_len;
90 char name[0]; 117 char name[0];
91}; 118};
92 119
93struct dso *dso__new(const char *name); 120struct dso *dso__new(const char *name);
121struct dso *dso__new_kernel(const char *name);
94void dso__delete(struct dso *self); 122void dso__delete(struct dso *self);
95 123
96bool dso__loaded(const struct dso *self, enum map_type type); 124bool dso__loaded(const struct dso *self, enum map_type type);
97bool dso__sorted_by_name(const struct dso *self, enum map_type type); 125bool dso__sorted_by_name(const struct dso *self, enum map_type type);
98 126
127static inline void dso__set_loaded(struct dso *self, enum map_type type)
128{
129 self->loaded |= (1 << type);
130}
131
99void dso__sort_by_name(struct dso *self, enum map_type type); 132void dso__sort_by_name(struct dso *self, enum map_type type);
100 133
101struct dso *dsos__findnew(const char *name); 134extern struct list_head dsos__user, dsos__kernel;
135
136struct dso *__dsos__findnew(struct list_head *head, const char *name);
137
138static inline struct dso *dsos__findnew(const char *name)
139{
140 return __dsos__findnew(&dsos__user, name);
141}
142
102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 143int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
144int dso__load_vmlinux_path(struct dso *self, struct map *map,
145 symbol_filter_t filter);
146int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
147 symbol_filter_t filter);
103void dsos__fprintf(FILE *fp); 148void dsos__fprintf(FILE *fp);
104size_t dsos__fprintf_buildid(FILE *fp); 149size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
105 150
106size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 151size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
107size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 152size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
108char dso__symtab_origin(const struct dso *self); 153char dso__symtab_origin(const struct dso *self);
154void dso__set_long_name(struct dso *self, char *name);
109void dso__set_build_id(struct dso *self, void *build_id); 155void dso__set_build_id(struct dso *self, void *build_id);
156void dso__read_running_kernel_build_id(struct dso *self);
110struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 157struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
111struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 158struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
112 const char *name); 159 const char *name);
113 160
114int filename__read_build_id(const char *filename, void *bf, size_t size); 161int filename__read_build_id(const char *filename, void *bf, size_t size);
115int sysfs__read_build_id(const char *filename, void *bf, size_t size); 162int sysfs__read_build_id(const char *filename, void *bf, size_t size);
116bool dsos__read_build_ids(void); 163bool dsos__read_build_ids(bool with_hits);
117int build_id__sprintf(u8 *self, int len, char *bf); 164int build_id__sprintf(const u8 *self, int len, char *bf);
165int kallsyms__parse(const char *filename, void *arg,
166 int (*process_symbol)(void *arg, const char *name,
167 char type, u64 start));
118 168
119size_t kernel_maps__fprintf(FILE *fp); 169int symbol__init(void);
170bool symbol_type__is_a(char symbol_type, enum map_type map_type);
120 171
121int symbol__init(struct symbol_conf *conf);
122
123struct map_groups;
124struct map_groups *kmaps;
125extern struct list_head dsos__user, dsos__kernel;
126extern struct dso *vdso;
127#endif /* __PERF_SYMBOL */ 172#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index b68a00ea4121..fa968312ee7d 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,13 +2,11 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
9static struct rb_root threads;
10static struct thread *last_match;
11
12void map_groups__init(struct map_groups *self) 10void map_groups__init(struct map_groups *self)
13{ 11{
14 int i; 12 int i;
@@ -33,12 +31,41 @@ static struct thread *thread__new(pid_t pid)
33 return self; 31 return self;
34} 32}
35 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
36int thread__set_comm(struct thread *self, const char *comm) 56int thread__set_comm(struct thread *self, const char *comm)
37{ 57{
58 int err;
59
38 if (self->comm) 60 if (self->comm)
39 free(self->comm); 61 free(self->comm);
40 self->comm = strdup(comm); 62 self->comm = strdup(comm);
41 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;
42} 69}
43 70
44int thread__comm_len(struct thread *self) 71int thread__comm_len(struct thread *self)
@@ -52,13 +79,8 @@ int thread__comm_len(struct thread *self)
52 return self->comm_len; 79 return self->comm_len;
53} 80}
54 81
55static const char *map_type__name[MAP__NR_TYPES] = { 82size_t __map_groups__fprintf_maps(struct map_groups *self,
56 [MAP__FUNCTION] = "Functions", 83 enum map_type type, FILE *fp)
57 [MAP__VARIABLE] = "Variables",
58};
59
60static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp)
62{ 84{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 85 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
64 struct rb_node *nd; 86 struct rb_node *nd;
@@ -67,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self,
67 struct map *pos = rb_entry(nd, struct map, rb_node); 89 struct map *pos = rb_entry(nd, struct map, rb_node);
68 printed += fprintf(fp, "Map:"); 90 printed += fprintf(fp, "Map:");
69 printed += map__fprintf(pos, fp); 91 printed += map__fprintf(pos, fp);
70 if (verbose > 1) { 92 if (verbose > 2) {
71 printed += dso__fprintf(pos->dso, type, fp); 93 printed += dso__fprintf(pos->dso, type, fp);
72 printed += fprintf(fp, "--\n"); 94 printed += fprintf(fp, "--\n");
73 } 95 }
@@ -122,9 +144,9 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
122 map_groups__fprintf(&self->mg, fp); 144 map_groups__fprintf(&self->mg, fp);
123} 145}
124 146
125struct thread *threads__findnew(pid_t pid) 147struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
126{ 148{
127 struct rb_node **p = &threads.rb_node; 149 struct rb_node **p = &self->threads.rb_node;
128 struct rb_node *parent = NULL; 150 struct rb_node *parent = NULL;
129 struct thread *th; 151 struct thread *th;
130 152
@@ -133,15 +155,15 @@ struct thread *threads__findnew(pid_t pid)
133 * so most of the time we dont have to look up 155 * so most of the time we dont have to look up
134 * the full rbtree: 156 * the full rbtree:
135 */ 157 */
136 if (last_match && last_match->pid == pid) 158 if (self->last_match && self->last_match->pid == pid)
137 return last_match; 159 return self->last_match;
138 160
139 while (*p != NULL) { 161 while (*p != NULL) {
140 parent = *p; 162 parent = *p;
141 th = rb_entry(parent, struct thread, rb_node); 163 th = rb_entry(parent, struct thread, rb_node);
142 164
143 if (th->pid == pid) { 165 if (th->pid == pid) {
144 last_match = th; 166 self->last_match = th;
145 return th; 167 return th;
146 } 168 }
147 169
@@ -154,27 +176,15 @@ struct thread *threads__findnew(pid_t pid)
154 th = thread__new(pid); 176 th = thread__new(pid);
155 if (th != NULL) { 177 if (th != NULL) {
156 rb_link_node(&th->rb_node, parent, p); 178 rb_link_node(&th->rb_node, parent, p);
157 rb_insert_color(&th->rb_node, &threads); 179 rb_insert_color(&th->rb_node, &self->threads);
158 last_match = th; 180 self->last_match = th;
159 } 181 }
160 182
161 return th; 183 return th;
162} 184}
163 185
164struct thread *register_idle_thread(void) 186static int map_groups__fixup_overlappings(struct map_groups *self,
165{ 187 struct map *map)
166 struct thread *thread = threads__findnew(0);
167
168 if (!thread || thread__set_comm(thread, "swapper")) {
169 fprintf(stderr, "problem inserting idle task.\n");
170 exit(-1);
171 }
172
173 return thread;
174}
175
176static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map)
178{ 188{
179 struct rb_root *root = &self->maps[map->type]; 189 struct rb_root *root = &self->maps[map->type];
180 struct rb_node *next = rb_first(root); 190 struct rb_node *next = rb_first(root);
@@ -199,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self,
199 * list. 209 * list.
200 */ 210 */
201 list_add_tail(&pos->node, &self->removed_maps[map->type]); 211 list_add_tail(&pos->node, &self->removed_maps[map->type]);
212 /*
213 * Now check if we need to create new maps for areas not
214 * overlapped by the new map:
215 */
216 if (map->start > pos->start) {
217 struct map *before = map__clone(pos);
218
219 if (before == NULL)
220 return -ENOMEM;
221
222 before->end = map->start - 1;
223 map_groups__insert(self, before);
224 if (verbose >= 2)
225 map__fprintf(before, stderr);
226 }
227
228 if (map->end < pos->end) {
229 struct map *after = map__clone(pos);
230
231 if (after == NULL)
232 return -ENOMEM;
233
234 after->start = map->end + 1;
235 map_groups__insert(self, after);
236 if (verbose >= 2)
237 map__fprintf(after, stderr);
238 }
202 } 239 }
240
241 return 0;
203} 242}
204 243
205void maps__insert(struct rb_root *maps, struct map *map) 244void maps__insert(struct rb_root *maps, struct map *map)
@@ -244,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
244 283
245void thread__insert_map(struct thread *self, struct map *map) 284void thread__insert_map(struct thread *self, struct map *map)
246{ 285{
247 map_groups__remove_overlappings(&self->mg, map); 286 map_groups__fixup_overlappings(&self->mg, map);
248 map_groups__insert(&self->mg, map); 287 map_groups__insert(&self->mg, map);
249} 288}
250 289
@@ -269,11 +308,14 @@ int thread__fork(struct thread *self, struct thread *parent)
269{ 308{
270 int i; 309 int i;
271 310
272 if (self->comm) 311 if (parent->comm_set) {
273 free(self->comm); 312 if (self->comm)
274 self->comm = strdup(parent->comm); 313 free(self->comm);
275 if (!self->comm) 314 self->comm = strdup(parent->comm);
276 return -ENOMEM; 315 if (!self->comm)
316 return -ENOMEM;
317 self->comm_set = true;
318 }
277 319
278 for (i = 0; i < MAP__NR_TYPES; ++i) 320 for (i = 0; i < MAP__NR_TYPES; ++i)
279 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 321 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -281,12 +323,12 @@ int thread__fork(struct thread *self, struct thread *parent)
281 return 0; 323 return 0;
282} 324}
283 325
284size_t threads__fprintf(FILE *fp) 326size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
285{ 327{
286 size_t ret = 0; 328 size_t ret = 0;
287 struct rb_node *nd; 329 struct rb_node *nd;
288 330
289 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 331 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
290 struct thread *pos = rb_entry(nd, struct thread, rb_node); 332 struct thread *pos = rb_entry(nd, struct thread, rb_node);
291 333
292 ret += thread__fprintf(pos, fp); 334 ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 1751802a09ba..dcf70303e58e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,14 +8,17 @@
8struct map_groups { 8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11 bool use_modules;
12}; 11};
13 12
13size_t __map_groups__fprintf_maps(struct map_groups *self,
14 enum map_type type, FILE *fp);
15
14struct thread { 16struct thread {
15 struct rb_node rb_node; 17 struct rb_node rb_node;
16 struct map_groups mg; 18 struct map_groups mg;
17 pid_t pid; 19 pid_t pid;
18 char shortname[3]; 20 char shortname[3];
21 bool comm_set;
19 char *comm; 22 char *comm;
20 int comm_len; 23 int comm_len;
21}; 24};
@@ -23,12 +26,11 @@ struct thread {
23void map_groups__init(struct map_groups *self); 26void map_groups__init(struct map_groups *self);
24int thread__set_comm(struct thread *self, const char *comm); 27int thread__set_comm(struct thread *self, const char *comm);
25int thread__comm_len(struct thread *self); 28int thread__comm_len(struct thread *self);
26struct thread *threads__findnew(pid_t pid); 29struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
27struct thread *register_idle_thread(void);
28void thread__insert_map(struct thread *self, struct map *map); 30void thread__insert_map(struct thread *self, struct map *map);
29int thread__fork(struct thread *self, struct thread *parent); 31int thread__fork(struct thread *self, struct thread *parent);
30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); 32size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
31size_t threads__fprintf(FILE *fp); 33size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
32 34
33void maps__insert(struct rb_root *maps, struct map *map); 35void maps__insert(struct rb_root *maps, struct map *map);
34struct map *maps__find(struct rb_root *maps, u64 addr); 36struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -50,7 +52,13 @@ static inline struct map *thread__find_map(struct thread *self,
50 return self ? map_groups__find(&self->mg, type, addr) : NULL; 52 return self ? map_groups__find(&self->mg, type, addr) : NULL;
51} 53}
52 54
53void thread__find_addr_location(struct thread *self, u8 cpumode, 55void thread__find_addr_map(struct thread *self,
56 struct perf_session *session, u8 cpumode,
57 enum map_type type, u64 addr,
58 struct addr_location *al);
59
60void thread__find_addr_location(struct thread *self,
61 struct perf_session *session, u8 cpumode,
54 enum map_type type, u64 addr, 62 enum map_type type, u64 addr,
55 struct addr_location *al, 63 struct addr_location *al,
56 symbol_filter_t filter); 64 symbol_filter_t filter);
@@ -58,13 +66,22 @@ struct symbol *map_groups__find_symbol(struct map_groups *self,
58 enum map_type type, u64 addr, 66 enum map_type type, u64 addr,
59 symbol_filter_t filter); 67 symbol_filter_t filter);
60 68
61static inline struct symbol * 69static inline struct symbol *map_groups__find_function(struct map_groups *self,
62map_groups__find_function(struct map_groups *self, u64 addr, 70 u64 addr,
63 symbol_filter_t filter) 71 symbol_filter_t filter)
64{ 72{
65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); 73 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
66} 74}
67 75
68struct map *map_groups__find_by_name(struct map_groups *self, 76struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name); 77 enum map_type type, const char *name);
78
79int __map_groups__create_kernel_maps(struct map_groups *self,
80 struct map *vmlinux_maps[MAP__NR_TYPES],
81 struct dso *kernel);
82int map_groups__create_kernel_maps(struct map_groups *self,
83 struct map *vmlinux_maps[MAP__NR_TYPES]);
84
85struct map *map_groups__new_module(struct map_groups *self, u64 start,
86 const char *filename);
70#endif /* __PERF_THREAD_H */ 87#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..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>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
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
@@ -533,7 +515,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 515 write_or_die(buf, 1);
534 516
535 /* save page_size */ 517 /* save page_size */
536 page_size = getpagesize(); 518 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 519 write_or_die(&page_size, 4);
538 520
539 read_header_files(); 521 read_header_files();
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index c5c32be040bf..9b3c20f42f98 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1925,6 +1925,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1925 if (!field) 1925 if (!field)
1926 return NULL; 1926 return NULL;
1927 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
1928 return data + field->offset; 1937 return data + field->offset;
1929} 1938}
1930 1939
@@ -3277,3 +3286,18 @@ void parse_set_info(int nr_cpus, int long_sz)
3277 cpus = nr_cpus; 3286 cpus = nr_cpus;
3278 long_size = long_sz; 3287 long_size = long_sz;
3279} 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-perl.h b/tools/perf/util/trace-event-perl.h
deleted file mode 100644
index e88fb26137bb..000000000000
--- a/tools/perf/util/trace-event-perl.h
+++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1744422cafcb..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) {
@@ -282,8 +282,8 @@ static void update_cpu_data_index(int cpu)
282 282
283static void get_next_page(int cpu) 283static void get_next_page(int cpu)
284{ 284{
285 off64_t save_seek; 285 off_t save_seek;
286 off64_t ret; 286 off_t ret;
287 287
288 if (!cpu_data[cpu].page) 288 if (!cpu_data[cpu].page)
289 return; 289 return;
@@ -298,17 +298,17 @@ static void get_next_page(int cpu)
298 update_cpu_data_index(cpu); 298 update_cpu_data_index(cpu);
299 299
300 /* 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 */
301 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 save_seek = lseek(input_fd, 0, SEEK_CUR);
302 302
303 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
304 if (ret < 0) 304 if (ret == (off_t)-1)
305 die("failed to lseek"); 305 die("failed to lseek");
306 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 ret = read(input_fd, cpu_data[cpu].page, page_size);
307 if (ret < 0) 307 if (ret < 0)
308 die("failed to read page"); 308 die("failed to read page");
309 309
310 /* reset the file pointer back */ 310 /* reset the file pointer back */
311 lseek64(input_fd, save_seek, SEEK_SET); 311 lseek(input_fd, save_seek, SEEK_SET);
312 312
313 return; 313 return;
314 } 314 }
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 81698d5e6503..c3269b937db4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -270,7 +270,7 @@ enum trace_flag_type {
270 270
271struct scripting_ops { 271struct scripting_ops {
272 const char *name; 272 const char *name;
273 int (*start_script) (const char *); 273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void); 274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size, 275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm); 276 unsigned long long nsecs, char *comm);
@@ -279,7 +279,15 @@ struct scripting_ops {
279 279
280int script_spec_register(const char *spec, struct scripting_ops *ops); 280int script_spec_register(const char *spec, struct scripting_ops *ops);
281 281
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 282void setup_perl_scripting(void);
283void setup_python_scripting(void);
284
285struct scripting_context {
286 void *event_data;
287};
288
289int common_pc(struct scripting_context *context);
290int common_flags(struct scripting_context *context);
291int common_lock_depth(struct scripting_context *context);
284 292
285#endif /* __PERF_TRACE_EVENTS_H */ 293#endif /* __PERF_TRACE_EVENTS_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 c673d8825883..0f5b2a6f1080 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 403#endif
404#endif 404#endif
405 405
406int mkdir_p(char *path, mode_t mode);
407int copyfile(const char *from, const char *to);
408
406#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,