aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/perf-bench.txt120
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt34
-rw-r--r--tools/perf/Documentation/perf-kmem.txt44
-rw-r--r--tools/perf/Documentation/perf-probe.txt49
-rw-r--r--tools/perf/Documentation/perf-record.txt16
-rw-r--r--tools/perf/Documentation/perf-report.txt8
-rw-r--r--tools/perf/Documentation/perf-timechart.txt5
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt219
-rw-r--r--tools/perf/Documentation/perf-trace.txt11
-rw-r--r--tools/perf/Makefile146
-rw-r--r--tools/perf/bench/bench.h17
-rw-r--r--tools/perf/bench/mem-memcpy.c193
-rw-r--r--tools/perf/bench/sched-messaging.c336
-rw-r--r--tools/perf/bench/sched-pipe.c124
-rw-r--r--tools/perf/builtin-annotate.c476
-rw-r--r--tools/perf/builtin-bench.c196
-rw-r--r--tools/perf/builtin-buildid-list.c116
-rw-r--r--tools/perf/builtin-help.c16
-rw-r--r--tools/perf/builtin-kmem.c807
-rw-r--r--tools/perf/builtin-probe.c242
-rw-r--r--tools/perf/builtin-record.c280
-rw-r--r--tools/perf/builtin-report.c417
-rw-r--r--tools/perf/builtin-sched.c97
-rw-r--r--tools/perf/builtin-stat.c34
-rw-r--r--tools/perf/builtin-timechart.c295
-rw-r--r--tools/perf/builtin-top.c384
-rw-r--r--tools/perf/builtin-trace.c313
-rw-r--r--tools/perf/builtin.h4
-rw-r--r--tools/perf/command-list.txt4
-rw-r--r--tools/perf/design.txt2
-rw-r--r--tools/perf/perf.c86
-rw-r--r--tools/perf/perf.h12
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c134
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs41
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL17
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/README59
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm55
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm192
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm88
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/typemap1
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-record7
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report5
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report5
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report5
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record6
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report5
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report6
-rw-r--r--tools/perf/scripts/perl/check-perf-trace.pl106
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl105
-rw-r--r--tools/perf/scripts/perl/rw-by-pid.pl170
-rw-r--r--tools/perf/scripts/perl/wakeup-latency.pl103
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN2
-rw-r--r--tools/perf/util/cache.h5
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/ctype.c8
-rw-r--r--tools/perf/util/data_map.c167
-rw-r--r--tools/perf/util/data_map.h3
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h5
-rw-r--r--tools/perf/util/debugfs.c241
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c312
-rw-r--r--tools/perf/util/event.h60
-rw-r--r--tools/perf/util/header.c433
-rw-r--r--tools/perf/util/header.h72
-rw-r--r--tools/perf/util/hist.c22
-rw-r--r--tools/perf/util/hist.h6
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/bug.h22
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/bitops.h29
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/kernel.h76
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/include/linux/types.h9
-rw-r--r--tools/perf/util/map.c99
-rw-r--r--tools/perf/util/parse-events.c155
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/probe-event.c484
-rw-r--r--tools/perf/util/probe-event.h18
-rw-r--r--tools/perf/util/probe-finder.c732
-rw-r--r--tools/perf/util/probe-finder.h57
-rw-r--r--tools/perf/util/sort.c20
-rw-r--r--tools/perf/util/sort.h9
-rw-r--r--tools/perf/util/string.c185
-rw-r--r--tools/perf/util/string.h3
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/symbol.c980
-rw-r--r--tools/perf/util/symbol.h90
-rw-r--r--tools/perf/util/thread.c173
-rw-r--r--tools/perf/util/thread.h43
-rw-r--r--tools/perf/util/trace-event-info.c22
-rw-r--r--tools/perf/util/trace-event-parse.c561
-rw-r--r--tools/perf/util/trace-event-perl.c598
-rw-r--r--tools/perf/util/trace-event-perl.h51
-rw-r--r--tools/perf/util/trace-event-read.c4
-rw-r--r--tools/perf/util/trace-event.h50
-rw-r--r--tools/perf/util/util.h31
-rw-r--r--tools/perf/util/wrapper.c61
109 files changed, 10121 insertions, 2212 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 0854f110bf7f..fe08660ce0bd 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -12,6 +12,7 @@ perf*.1
12perf*.xml 12perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data
15tags 16tags
16TAGS 17TAGS
17cscope* 18cscope*
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
new file mode 100644
index 000000000000..ae525ac5a2ce
--- /dev/null
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -0,0 +1,120 @@
1perf-bench(1)
2============
3
4NAME
5----
6perf-bench - General framework for benchmark suites
7
8SYNOPSIS
9--------
10[verse]
11'perf bench' [<common options>] <subsystem> <suite> [<options>]
12
13DESCRIPTION
14-----------
15This 'perf bench' command is general framework for benchmark suites.
16
17COMMON OPTIONS
18--------------
19-f::
20--format=::
21Specify format style.
22Current available format styles are,
23
24'default'::
25Default style. This is mainly for human reading.
26---------------------
27% perf bench sched pipe # with no style specify
28(executing 1000000 pipe operations between two tasks)
29 Total time:5.855 sec
30 5.855061 usecs/op
31 170792 ops/sec
32---------------------
33
34'simple'::
35This simple style is friendly for automated
36processing by scripts.
37---------------------
38% perf bench --format=simple sched pipe # specified simple
395.988
40---------------------
41
42SUBSYSTEM
43---------
44
45'sched'::
46 Scheduler and IPC mechanisms.
47
48SUITES FOR 'sched'
49~~~~~~~~~~~~~~~~~~
50*messaging*::
51Suite for evaluating performance of scheduler and IPC mechanisms.
52Based on hackbench by Rusty Russell.
53
54Options of *pipe*
55^^^^^^^^^^^^^^^^^
56-p::
57--pipe::
58Use pipe() instead of socketpair()
59
60-t::
61--thread::
62Be multi thread instead of multi process
63
64-g::
65--group=::
66Specify number of groups
67
68-l::
69--loop=::
70Specify number of loops
71
72Example of *messaging*
73^^^^^^^^^^^^^^^^^^^^^^
74
75---------------------
76% perf bench sched messaging # run with default
77options (20 sender and receiver processes per group)
78(10 groups == 400 processes run)
79
80 Total time:0.308 sec
81
82% perf bench sched messaging -t -g 20 # be multi-thread,with 20 groups
83(20 sender and receiver threads per group)
84(20 groups == 800 threads run)
85
86 Total time:0.582 sec
87---------------------
88
89*pipe*::
90Suite for pipe() system call.
91Based on pipe-test-1m.c by Ingo Molnar.
92
93Options of *pipe*
94^^^^^^^^^^^^^^^^^
95-l::
96--loop=::
97Specify number of loops.
98
99Example of *pipe*
100^^^^^^^^^^^^^^^^^
101
102---------------------
103% perf bench sched pipe
104(executing 1000000 pipe operations between two tasks)
105
106 Total time:8.091 sec
107 8.091833 usecs/op
108 123581 ops/sec
109
110% perf bench sched pipe -l 1000 # loop 1000
111(executing 1000 pipe operations between two tasks)
112
113 Total time:0.016 sec
114 16.948000 usecs/op
115 59004 ops/sec
116---------------------
117
118SEE ALSO
119--------
120linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
new file mode 100644
index 000000000000..01b642c0bf8f
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -0,0 +1,34 @@
1perf-buildid-list(1)
2====================
3
4NAME
5----
6perf-buildid-list - List the buildids in a perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-list <options>'
12
13DESCRIPTION
14-----------
15This command displays the buildids found in a perf.data file, so that other
16tools can be used to fetch packages with matching symbol tables for use by
17perf report.
18
19OPTIONS
20-------
21-i::
22--input=::
23 Input file name. (default: perf.data)
24-f::
25--force::
26 Don't do ownership validation.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-top[1],
34linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
new file mode 100644
index 000000000000..44b0ce35c28a
--- /dev/null
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -0,0 +1,44 @@
1perf-kmem(1)
2==============
3
4NAME
5----
6perf-kmem - Tool to trace/measure kernel memory(slab) properties
7
8SYNOPSIS
9--------
10[verse]
11'perf kmem' {record} [<options>]
12
13DESCRIPTION
14-----------
15There's two variants of perf kmem:
16
17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload.
19
20 'perf kmem' to report kernel memory statistics.
21
22OPTIONS
23-------
24-i <file>::
25--input=<file>::
26 Select the input file (default: perf.data)
27
28--stat=<caller|alloc>::
29 Select per callsite or per allocation statistics
30
31-s <key[,key2...]>::
32--sort=<key[,key2...]>::
33 Sort the output (default: frag,hit,bytes)
34
35-l <num>::
36--line=<num>::
37 Print n lines only
38
39--raw-ip::
40 Print raw ip instead of symbol
41
42SEE ALSO
43--------
44linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644
index 000000000000..9270594e6dfd
--- /dev/null
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -0,0 +1,49 @@
1perf-probe(1)
2=============
3
4NAME
5----
6perf-probe - Define new dynamic tracepoints
7
8SYNOPSIS
9--------
10[verse]
11'perf probe' [options] --add 'PROBE' [--add 'PROBE' ...]
12or
13'perf probe' [options] 'PROBE' ['PROBE' ...]
14
15
16DESCRIPTION
17-----------
18This command defines dynamic tracepoint events, by symbol and registers
19without debuginfo, or by C expressions (C line numbers, C function names,
20and C local variables) with debuginfo.
21
22
23OPTIONS
24-------
25-k::
26--vmlinux=PATH::
27 Specify vmlinux path which has debuginfo (Dwarf binary).
28
29-v::
30--verbose::
31 Be more verbose (show parsed arguments, etc).
32
33-a::
34--add::
35 Define a probe point (see PROBE SYNTAX for detail)
36
37PROBE SYNTAX
38------------
39Probe points are defined by following syntax.
40
41 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
42
43'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function.
44It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
45'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
46
47SEE ALSO
48--------
49linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 0ff23de9e453..fc46c0b40f6e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -26,11 +26,19 @@ OPTIONS
26 26
27-e:: 27-e::
28--event=:: 28--event=::
29 Select the PMU event. Selection can be a symbolic event name 29 Select the PMU event. Selection can be:
30 (use 'perf list' to list all events) or a raw PMU
31 event (eventsel+umask) in the form of rNNN where NNN is a
32 hexadecimal event descriptor.
33 30
31 - a symbolic event name (use 'perf list' to list all events)
32
33 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
34 hexadecimal event descriptor.
35
36 - a hardware breakpoint event in the form of '\mem:addr[:access]'
37 where addr is the address in memory you want to break in.
38 Access is the memory access type (read, write, execute) it can
39 be passed as follows: '\mem:addr[:[r][w][x]]'.
40 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'.
34-a:: 42-a::
35 System-wide collection. 43 System-wide collection.
36 44
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 59f0b846cd71..9dccb180b7af 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -24,11 +24,11 @@ OPTIONS
24--dsos=:: 24--dsos=::
25 Only consider symbols in these dsos. CSV that understands 25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries. 26 file://filename entries.
27-n 27-n::
28--show-nr-samples 28--show-nr-samples::
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T 30-T::
31--threads 31--threads::
32 Show per-thread event counters 32 Show per-thread event counters
33-C:: 33-C::
34--comms=:: 34--comms=::
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index a7910099d6fd..4b1788355eca 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -31,9 +31,12 @@ OPTIONS
31-w:: 31-w::
32--width=:: 32--width=::
33 Select the width of the SVG file (default: 1000) 33 Select the width of the SVG file (default: 1000)
34-p:: 34-P::
35--power-only:: 35--power-only::
36 Only output the CPU power section of the diagram 36 Only output the CPU power section of the diagram
37-p::
38--process::
39 Select the processes to display, by name or PID
37 40
38 41
39SEE ALSO 42SEE ALSO
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
new file mode 100644
index 000000000000..c5f55f439091
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace-perl.txt
@@ -0,0 +1,219 @@
1perf-trace-perl(1)
2==================
3
4NAME
5----
6perf-trace-perl - Process trace data with a Perl script
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-s [lang]:script[.ext] ]
12
13DESCRIPTION
14-----------
15
16This perf trace option is used to process perf trace data using perf's
17built-in Perl interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given
19Perl script, if any.
20
21STARTER SCRIPTS
22---------------
23
24You can avoid reading the rest of this document by running 'perf trace
25-g perl' in the same directory as an existing perf.data trace file.
26That will generate a starter script containing a handler for each of
27the event types in the trace file; it simply prints every available
28field for each event in the trace file.
29
30You can also look at the existing scripts in
31~/libexec/perf-core/scripts/perl for typical examples showing how to
32do basic things like aggregate event data, print results, etc. Also,
33the check-perf-trace.pl script, while not interesting for its results,
34attempts to exercise all of the main scripting features.
35
36EVENT HANDLERS
37--------------
38
39When perf trace is invoked using a trace script, a user-defined
40'handler function' is called for each event in the trace. If there's
41no handler function defined for a given event type, the event is
42ignored (or passed to a 'trace_handled' function, see below) and the
43next event is processed.
44
45Most of the event's field values are passed as arguments to the
46handler function; some of the less common ones aren't - those are
47available as calls back into the perf executable (see below).
48
49As an example, the following perf record command can be used to record
50all sched_wakeup events in the system:
51
52 # perf record -c 1 -f -a -M -R -e sched:sched_wakeup
53
54Traces meant to be processed using a script should be recorded with
55the above options: -c 1 says to sample every event, -a to enable
56system-wide collection, -M to multiplex the output, and -R to collect
57raw samples.
58
59The format file for the sched_wakep event defines the following fields
60(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
61
62----
63 format:
64 field:unsigned short common_type;
65 field:unsigned char common_flags;
66 field:unsigned char common_preempt_count;
67 field:int common_pid;
68 field:int common_lock_depth;
69
70 field:char comm[TASK_COMM_LEN];
71 field:pid_t pid;
72 field:int prio;
73 field:int success;
74 field:int target_cpu;
75----
76
77The handler function for this event would be defined as:
78
79----
80sub sched::sched_wakeup
81{
82 my ($event_name, $context, $common_cpu, $common_secs,
83 $common_nsecs, $common_pid, $common_comm,
84 $comm, $pid, $prio, $success, $target_cpu) = @_;
85}
86----
87
88The handler function takes the form subsystem::event_name.
89
90The $common_* arguments in the handler's argument list are the set of
91arguments passed to all event handlers; some of the fields correspond
92to the common_* fields in the format file, but some are synthesized,
93and some of the common_* fields aren't common enough to to be passed
94to every event as arguments but are available as library functions.
95
96Here's a brief description of each of the invariant event args:
97
98 $event_name the name of the event as text
99 $context an opaque 'cookie' used in calls back into perf
100 $common_cpu the cpu the event occurred on
101 $common_secs the secs portion of the event timestamp
102 $common_nsecs the nsecs portion of the event timestamp
103 $common_pid the pid of the current task
104 $common_comm the name of the current process
105
106All of the remaining fields in the event's format file have
107counterparts as handler function arguments of the same name, as can be
108seen in the example above.
109
110The above provides the basics needed to directly access every field of
111every event in a trace, which covers 90% of what you need to know to
112write a useful trace script. The sections below cover the rest.
113
114SCRIPT LAYOUT
115-------------
116
117Every perf trace Perl script should start by setting up a Perl module
118search path and 'use'ing a few support modules (see module
119descriptions below):
120
121----
122 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
123 use lib "./Perf-Trace-Util/lib";
124 use Perf::Trace::Core;
125 use Perf::Trace::Context;
126 use Perf::Trace::Util;
127----
128
129The rest of the script can contain handler functions and support
130functions in any order.
131
132Aside from the event handler functions discussed above, every script
133can implement a set of optional functions:
134
135*trace_begin*, if defined, is called before any event is processed and
136gives scripts a chance to do setup tasks:
137
138----
139 sub trace_begin
140 {
141 }
142----
143
144*trace_end*, if defined, is called after all events have been
145 processed and gives scripts a chance to do end-of-script tasks, such
146 as display results:
147
148----
149sub trace_end
150{
151}
152----
153
154*trace_unhandled*, if defined, is called after for any event that
155 doesn't have a handler explicitly defined for it. The standard set
156 of common arguments are passed into it:
157
158----
159sub trace_unhandled
160{
161 my ($event_name, $context, $common_cpu, $common_secs,
162 $common_nsecs, $common_pid, $common_comm) = @_;
163}
164----
165
166The remaining sections provide descriptions of each of the available
167built-in perf trace Perl modules and their associated functions.
168
169AVAILABLE MODULES AND FUNCTIONS
170-------------------------------
171
172The following sections describe the functions and variables available
173via the various Perf::Trace::* Perl modules. To use the functions and
174variables from the given module, add the corresponding 'use
175Perf::Trace::XXX' line to your perf trace script.
176
177Perf::Trace::Core Module
178~~~~~~~~~~~~~~~~~~~~~~~~
179
180These functions provide some essential functions to user scripts.
181
182The *flag_str* and *symbol_str* functions provide human-readable
183strings for flag and symbolic fields. These correspond to the strings
184and values parsed from the 'print fmt' fields of the event format
185files:
186
187 flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name
188 symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name
189
190Perf::Trace::Context Module
191~~~~~~~~~~~~~~~~~~~~~~~~~~~
192
193Some of the 'common' fields in the event format file aren't all that
194common, but need to be made accessible to user scripts nonetheless.
195
196Perf::Trace::Context defines a set of functions that can be used to
197access this data in the context of the current event. Each of these
198functions expects a $context variable, which is the same as the
199$context variable passed into every event handler as the second
200argument.
201
202 common_pc($context) - returns common_preempt count for the current event
203 common_flags($context) - returns common_flags for the current event
204 common_lock_depth($context) - returns common_lock_depth for the current event
205
206Perf::Trace::Util Module
207~~~~~~~~~~~~~~~~~~~~~~~~
208
209Various utility functions for use with perf trace:
210
211 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
212 nsecs_secs($nsecs) - returns whole secs portion given nsecs
213 nsecs_nsecs($nsecs) - returns nsecs remainder given nsecs
214 nsecs_str($nsecs) - returns printable string in the form secs.nsecs
215 avg($total, $n) - returns average given a sum and a total number of values
216
217SEE ALSO
218--------
219linkperf:perf-trace[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 41ed75398ca9..07065efa60e0 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -20,6 +20,15 @@ OPTIONS
20--dump-raw-trace=:: 20--dump-raw-trace=::
21 Display verbose dump of the trace data. 21 Display verbose dump of the trace data.
22 22
23-s::
24--script=::
25 Process trace data with the given script ([lang]:script[.ext]).
26
27-g::
28--gen-script=::
29 Generate perf-trace.[ext] starter script for given language,
30 using current perf.data.
31
23SEE ALSO 32SEE ALSO
24-------- 33--------
25linkperf:perf-record[1] 34linkperf:perf-record[1], linkperf:perf-trace-perl[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 106c15055b50..23ec66098bdc 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -2,6 +2,7 @@
2all:: 2all::
3 3
4# Define V=1 to have a more verbose compile. 4# Define V=1 to have a more verbose compile.
5# Define V=2 to have an even more verbose compile.
5# 6#
6# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() 7# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
7# or vsnprintf() return -1 instead of number of characters which would 8# or vsnprintf() return -1 instead of number of characters which would
@@ -145,6 +146,10 @@ all::
145# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call 146# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
146# your external grep (e.g., if your system lacks grep, if its grep is 147# your external grep (e.g., if your system lacks grep, if its grep is
147# broken, or spawning external process is slower than built-in grep perf has). 148# broken, or spawning external process is slower than built-in grep perf has).
149#
150# Define LDFLAGS=-static to build a static binary.
151#
152# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
148 153
149PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 154PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
150 @$(SHELL_PATH) util/PERF-VERSION-GEN 155 @$(SHELL_PATH) util/PERF-VERSION-GEN
@@ -157,28 +162,13 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 162uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 163uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 164
160#
161# Add -m32 for cross-builds:
162#
163ifdef NO_64BIT
164 MBITS := -m32
165else
166 #
167 # If we're on a 64-bit kernel, use -m64:
168 #
169 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
170 MBITS := -m64
171 endif
172endif
173
174# CFLAGS and LDFLAGS are for the users to override from the command line. 165# CFLAGS and LDFLAGS are for the users to override from the command line.
175 166
176# 167#
177# Include saner warnings here, which can catch bugs: 168# Include saner warnings here, which can catch bugs:
178# 169#
179 170
180EXTRA_WARNINGS := -Wcast-align 171EXTRA_WARNINGS := -Wformat
181EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat
182EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security 172EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
183EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k 173EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
184EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow 174EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
@@ -201,8 +191,15 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes 191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
202EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement 192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
203 193
204CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) 194ifeq ("$(origin DEBUG)", "command line")
205LDFLAGS = -lpthread -lrt -lelf -lm 195 PERF_DEBUG = $(DEBUG)
196endif
197ifndef PERF_DEBUG
198 CFLAGS_OPTIMIZE = -O6
199endif
200
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm
206ALL_CFLAGS = $(CFLAGS) 203ALL_CFLAGS = $(CFLAGS)
207ALL_LDFLAGS = $(LDFLAGS) 204ALL_LDFLAGS = $(LDFLAGS)
208STRIP ?= strip 205STRIP ?= strip
@@ -253,6 +250,9 @@ PTHREAD_LIBS = -lpthread
253# explicitly what architecture to check for. Fix this up for yours.. 250# explicitly what architecture to check for. Fix this up for yours..
254SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
255 252
253ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o /dev/null "$(QUIET_STDERR)" && echo y"), y)
254 CFLAGS := $(CFLAGS) -fstack-protector-all
255endif
256 256
257 257
258### --- END CONFIGURATION SECTION --- 258### --- END CONFIGURATION SECTION ---
@@ -328,8 +328,27 @@ LIB_FILE=libperf.a
328LIB_H += ../../include/linux/perf_event.h 328LIB_H += ../../include/linux/perf_event.h
329LIB_H += ../../include/linux/rbtree.h 329LIB_H += ../../include/linux/rbtree.h
330LIB_H += ../../include/linux/list.h 330LIB_H += ../../include/linux/list.h
331LIB_H += ../../include/linux/stringify.h
332LIB_H += util/include/linux/bitmap.h
333LIB_H += util/include/linux/bitops.h
334LIB_H += util/include/linux/compiler.h
335LIB_H += util/include/linux/ctype.h
336LIB_H += util/include/linux/kernel.h
331LIB_H += util/include/linux/list.h 337LIB_H += util/include/linux/list.h
338LIB_H += util/include/linux/module.h
339LIB_H += util/include/linux/poison.h
340LIB_H += util/include/linux/prefetch.h
341LIB_H += util/include/linux/rbtree.h
342LIB_H += util/include/linux/string.h
343LIB_H += util/include/linux/types.h
344LIB_H += util/include/asm/asm-offsets.h
345LIB_H += util/include/asm/bitops.h
346LIB_H += util/include/asm/byteorder.h
347LIB_H += util/include/asm/swab.h
348LIB_H += util/include/asm/system.h
349LIB_H += util/include/asm/uaccess.h
332LIB_H += perf.h 350LIB_H += perf.h
351LIB_H += util/debugfs.h
333LIB_H += util/event.h 352LIB_H += util/event.h
334LIB_H += util/types.h 353LIB_H += util/types.h
335LIB_H += util/levenshtein.h 354LIB_H += util/levenshtein.h
@@ -350,12 +369,16 @@ LIB_H += util/sort.h
350LIB_H += util/hist.h 369LIB_H += util/hist.h
351LIB_H += util/thread.h 370LIB_H += util/thread.h
352LIB_H += util/data_map.h 371LIB_H += util/data_map.h
372LIB_H += util/probe-finder.h
373LIB_H += util/probe-event.h
353 374
354LIB_OBJS += util/abspath.o 375LIB_OBJS += util/abspath.o
355LIB_OBJS += util/alias.o 376LIB_OBJS += util/alias.o
356LIB_OBJS += util/config.o 377LIB_OBJS += util/config.o
357LIB_OBJS += util/ctype.o 378LIB_OBJS += util/ctype.o
379LIB_OBJS += util/debugfs.o
358LIB_OBJS += util/environment.o 380LIB_OBJS += util/environment.o
381LIB_OBJS += util/event.o
359LIB_OBJS += util/exec_cmd.o 382LIB_OBJS += util/exec_cmd.o
360LIB_OBJS += util/help.o 383LIB_OBJS += util/help.o
361LIB_OBJS += util/levenshtein.o 384LIB_OBJS += util/levenshtein.o
@@ -363,6 +386,9 @@ LIB_OBJS += util/parse-options.o
363LIB_OBJS += util/parse-events.o 386LIB_OBJS += util/parse-events.o
364LIB_OBJS += util/path.o 387LIB_OBJS += util/path.o
365LIB_OBJS += util/rbtree.o 388LIB_OBJS += util/rbtree.o
389LIB_OBJS += util/bitmap.o
390LIB_OBJS += util/hweight.o
391LIB_OBJS += util/find_next_bit.o
366LIB_OBJS += util/run-command.o 392LIB_OBJS += util/run-command.o
367LIB_OBJS += util/quote.o 393LIB_OBJS += util/quote.o
368LIB_OBJS += util/strbuf.o 394LIB_OBJS += util/strbuf.o
@@ -383,14 +409,25 @@ LIB_OBJS += util/thread.o
383LIB_OBJS += util/trace-event-parse.o 409LIB_OBJS += util/trace-event-parse.o
384LIB_OBJS += util/trace-event-read.o 410LIB_OBJS += util/trace-event-read.o
385LIB_OBJS += util/trace-event-info.o 411LIB_OBJS += util/trace-event-info.o
412LIB_OBJS += util/trace-event-perl.o
386LIB_OBJS += util/svghelper.o 413LIB_OBJS += util/svghelper.o
387LIB_OBJS += util/sort.o 414LIB_OBJS += util/sort.o
388LIB_OBJS += util/hist.o 415LIB_OBJS += util/hist.o
389LIB_OBJS += util/data_map.o 416LIB_OBJS += util/data_map.o
417LIB_OBJS += util/probe-event.o
390 418
391BUILTIN_OBJS += builtin-annotate.o 419BUILTIN_OBJS += builtin-annotate.o
420
421BUILTIN_OBJS += builtin-bench.o
422
423# Benchmark modules
424BUILTIN_OBJS += bench/sched-messaging.o
425BUILTIN_OBJS += bench/sched-pipe.o
426BUILTIN_OBJS += bench/mem-memcpy.o
427
392BUILTIN_OBJS += builtin-help.o 428BUILTIN_OBJS += builtin-help.o
393BUILTIN_OBJS += builtin-sched.o 429BUILTIN_OBJS += builtin-sched.o
430BUILTIN_OBJS += builtin-buildid-list.o
394BUILTIN_OBJS += builtin-list.o 431BUILTIN_OBJS += builtin-list.o
395BUILTIN_OBJS += builtin-record.o 432BUILTIN_OBJS += builtin-record.o
396BUILTIN_OBJS += builtin-report.o 433BUILTIN_OBJS += builtin-report.o
@@ -398,9 +435,16 @@ BUILTIN_OBJS += builtin-stat.o
398BUILTIN_OBJS += builtin-timechart.o 435BUILTIN_OBJS += builtin-timechart.o
399BUILTIN_OBJS += builtin-top.o 436BUILTIN_OBJS += builtin-top.o
400BUILTIN_OBJS += builtin-trace.o 437BUILTIN_OBJS += builtin-trace.o
438BUILTIN_OBJS += builtin-probe.o
439BUILTIN_OBJS += builtin-kmem.o
401 440
402PERFLIBS = $(LIB_FILE) 441PERFLIBS = $(LIB_FILE)
403 442
443ifeq ($(V), 2)
444 QUIET_STDERR = ">/dev/null"
445else
446 QUIET_STDERR = ">/dev/null 2>&1"
447endif
404# 448#
405# Platform specific tweaks 449# Platform specific tweaks
406# 450#
@@ -428,32 +472,58 @@ ifeq ($(uname_S),Darwin)
428 PTHREAD_LIBS = 472 PTHREAD_LIBS =
429endif 473endif
430 474
431ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) 475ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
476ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
477 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
478endif
479
480 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
481 BASIC_CFLAGS += -DLIBELF_NO_MMAP
482 endif
483else
432 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 484 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
433endif 485endif
434 486
487ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
488 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
489 BASIC_CFLAGS += -DNO_LIBDWARF
490else
491 EXTLIBS += -lelf -ldwarf
492 LIB_OBJS += util/probe-finder.o
493endif
494
495PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
496PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
497
498ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
499 BASIC_CFLAGS += -DNO_LIBPERL
500else
501 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
502 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
503endif
504
435ifdef NO_DEMANGLE 505ifdef NO_DEMANGLE
436 BASIC_CFLAGS += -DNO_DEMANGLE 506 BASIC_CFLAGS += -DNO_DEMANGLE
437else 507else
438 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y") 508 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
439 509
440 ifeq ($(has_bfd),y) 510 ifeq ($(has_bfd),y)
441 EXTLIBS += -lbfd 511 EXTLIBS += -lbfd
442 else 512 else
443 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") 513 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
444 ifeq ($(has_bfd_iberty),y) 514 ifeq ($(has_bfd_iberty),y)
445 EXTLIBS += -lbfd -liberty 515 EXTLIBS += -lbfd -liberty
446 else 516 else
447 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") 517 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
448 ifeq ($(has_bfd_iberty_z),y) 518 ifeq ($(has_bfd_iberty_z),y)
449 EXTLIBS += -lbfd -liberty -lz 519 EXTLIBS += -lbfd -liberty -lz
450 else 520 else
451 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y") 521 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
452 ifeq ($(has_cplus_demangle),y) 522 ifeq ($(has_cplus_demangle),y)
453 EXTLIBS += -liberty 523 EXTLIBS += -liberty
454 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 524 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
455 else 525 else
456 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) 526 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
457 BASIC_CFLAGS += -DNO_DEMANGLE 527 BASIC_CFLAGS += -DNO_DEMANGLE
458 endif 528 endif
459 endif 529 endif
@@ -790,6 +860,25 @@ util/config.o: util/config.c PERF-CFLAGS
790util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 860util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
791 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 861 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
792 862
863# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
864# from <string.h> that comes from kernel headers wrapping.
865KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
866
867util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
868 $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
869
870util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
871 $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
872
873util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
874 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
875
876util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS
877 $(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 $<
878
879scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
880 $(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 $<
881
793perf-%$X: %.o $(PERFLIBS) 882perf-%$X: %.o $(PERFLIBS)
794 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 883 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
795 884
@@ -897,6 +986,13 @@ export perfexec_instdir
897install: all 986install: all
898 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 987 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
899 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 988 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
989 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
990 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
991 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
992 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
993 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
994 $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
995 $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
900ifdef BUILT_INS 996ifdef BUILT_INS
901 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 997 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
902 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 998 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -982,7 +1078,7 @@ distclean: clean
982# $(RM) configure 1078# $(RM) configure
983 1079
984clean: 1080clean:
985 $(RM) *.o */*.o $(LIB_FILE) 1081 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
986 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1082 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
987 $(RM) $(TEST_PROGRAMS) 1083 $(RM) $(TEST_PROGRAMS)
988 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1084 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
new file mode 100644
index 000000000000..f7781c6267c0
--- /dev/null
+++ b/tools/perf/bench/bench.h
@@ -0,0 +1,17 @@
1#ifndef BENCH_H
2#define BENCH_H
3
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
7
8#define BENCH_FORMAT_DEFAULT_STR "default"
9#define BENCH_FORMAT_DEFAULT 0
10#define BENCH_FORMAT_SIMPLE_STR "simple"
11#define BENCH_FORMAT_SIMPLE 1
12
13#define BENCH_FORMAT_UNKNOWN -1
14
15extern int bench_format;
16
17#endif
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
new file mode 100644
index 000000000000..89773178e894
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy.c
@@ -0,0 +1,193 @@
1/*
2 * mem-memcpy.c
3 *
4 * memcpy: Simple memory copy in various ways
5 *
6 * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
7 */
8#include <ctype.h>
9
10#include "../perf.h"
11#include "../util/util.h"
12#include "../util/parse-options.h"
13#include "../util/string.h"
14#include "../util/header.h"
15#include "bench.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/time.h>
21#include <errno.h>
22
23#define K 1024
24
25static const char *length_str = "1MB";
26static const char *routine = "default";
27static int use_clock = 0;
28static int clock_fd;
29
30static const struct option options[] = {
31 OPT_STRING('l', "length", &length_str, "1MB",
32 "Specify length of memory to copy. "
33 "available unit: B, MB, GB (upper and lower)"),
34 OPT_STRING('r', "routine", &routine, "default",
35 "Specify routine to copy"),
36 OPT_BOOLEAN('c', "clock", &use_clock,
37 "Use CPU clock for measuring"),
38 OPT_END()
39};
40
41struct routine {
42 const char *name;
43 const char *desc;
44 void * (*fn)(void *dst, const void *src, size_t len);
45};
46
47struct routine routines[] = {
48 { "default",
49 "Default memcpy() provided by glibc",
50 memcpy },
51 { NULL,
52 NULL,
53 NULL }
54};
55
56static const char * const bench_mem_memcpy_usage[] = {
57 "perf bench mem memcpy <options>",
58 NULL
59};
60
61static struct perf_event_attr clock_attr = {
62 .type = PERF_TYPE_HARDWARE,
63 .config = PERF_COUNT_HW_CPU_CYCLES
64};
65
66static void init_clock(void)
67{
68 clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
69
70 if (clock_fd < 0 && errno == ENOSYS)
71 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
72 else
73 BUG_ON(clock_fd < 0);
74}
75
76static u64 get_clock(void)
77{
78 int ret;
79 u64 clk;
80
81 ret = read(clock_fd, &clk, sizeof(u64));
82 BUG_ON(ret != sizeof(u64));
83
84 return clk;
85}
86
87static double timeval2double(struct timeval *ts)
88{
89 return (double)ts->tv_sec +
90 (double)ts->tv_usec / (double)1000000;
91}
92
93int bench_mem_memcpy(int argc, const char **argv,
94 const char *prefix __used)
95{
96 int i;
97 void *dst, *src;
98 size_t length;
99 double bps = 0.0;
100 struct timeval tv_start, tv_end, tv_diff;
101 u64 clock_start, clock_end, clock_diff;
102
103 clock_start = clock_end = clock_diff = 0ULL;
104 argc = parse_options(argc, argv, options,
105 bench_mem_memcpy_usage, 0);
106
107 tv_diff.tv_sec = 0;
108 tv_diff.tv_usec = 0;
109 length = (size_t)perf_atoll((char *)length_str);
110
111 if ((s64)length <= 0) {
112 fprintf(stderr, "Invalid length:%s\n", length_str);
113 return 1;
114 }
115
116 for (i = 0; routines[i].name; i++) {
117 if (!strcmp(routines[i].name, routine))
118 break;
119 }
120 if (!routines[i].name) {
121 printf("Unknown routine:%s\n", routine);
122 printf("Available routines...\n");
123 for (i = 0; routines[i].name; i++) {
124 printf("\t%s ... %s\n",
125 routines[i].name, routines[i].desc);
126 }
127 return 1;
128 }
129
130 dst = zalloc(length);
131 if (!dst)
132 die("memory allocation failed - maybe length is too large?\n");
133
134 src = zalloc(length);
135 if (!src)
136 die("memory allocation failed - maybe length is too large?\n");
137
138 if (bench_format == BENCH_FORMAT_DEFAULT) {
139 printf("# Copying %s Bytes from %p to %p ...\n\n",
140 length_str, src, dst);
141 }
142
143 if (use_clock) {
144 init_clock();
145 clock_start = get_clock();
146 } else {
147 BUG_ON(gettimeofday(&tv_start, NULL));
148 }
149
150 routines[i].fn(dst, src, length);
151
152 if (use_clock) {
153 clock_end = get_clock();
154 clock_diff = clock_end - clock_start;
155 } else {
156 BUG_ON(gettimeofday(&tv_end, NULL));
157 timersub(&tv_end, &tv_start, &tv_diff);
158 bps = (double)((double)length / timeval2double(&tv_diff));
159 }
160
161 switch (bench_format) {
162 case BENCH_FORMAT_DEFAULT:
163 if (use_clock) {
164 printf(" %14lf Clock/Byte\n",
165 (double)clock_diff / (double)length);
166 } else {
167 if (bps < K)
168 printf(" %14lf B/Sec\n", bps);
169 else if (bps < K * K)
170 printf(" %14lfd KB/Sec\n", bps / 1024);
171 else if (bps < K * K * K)
172 printf(" %14lf MB/Sec\n", bps / 1024 / 1024);
173 else {
174 printf(" %14lf GB/Sec\n",
175 bps / 1024 / 1024 / 1024);
176 }
177 }
178 break;
179 case BENCH_FORMAT_SIMPLE:
180 if (use_clock) {
181 printf("%14lf\n",
182 (double)clock_diff / (double)length);
183 } else
184 printf("%lf\n", bps);
185 break;
186 default:
187 /* reaching this means there's some disaster: */
188 die("unknown format: %d\n", bench_format);
189 break;
190 }
191
192 return 0;
193}
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
new file mode 100644
index 000000000000..605a2a959aa8
--- /dev/null
+++ b/tools/perf/bench/sched-messaging.c
@@ -0,0 +1,336 @@
1/*
2 *
3 * builtin-bench-messaging.c
4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms
6 *
7 * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au>
8 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
9 *
10 */
11
12#include "../perf.h"
13#include "../util/util.h"
14#include "../util/parse-options.h"
15#include "../builtin.h"
16#include "bench.h"
17
18/* Test groups of 20 processes spraying to 20 receivers */
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <sys/poll.h>
30#include <limits.h>
31
32#define DATASIZE 100
33
34static int use_pipes = 0;
35static unsigned int loops = 100;
36static unsigned int thread_mode = 0;
37static unsigned int num_groups = 10;
38
39struct sender_context {
40 unsigned int num_fds;
41 int ready_out;
42 int wakefd;
43 int out_fds[0];
44};
45
46struct receiver_context {
47 unsigned int num_packets;
48 int in_fds[2];
49 int ready_out;
50 int wakefd;
51};
52
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2])
60{
61 if (use_pipes) {
62 if (pipe(fds) == 0)
63 return;
64 } else {
65 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
66 return;
67 }
68
69 barf(use_pipes ? "pipe()" : "socketpair()");
70}
71
72/* Block until we're ready to go */
73static void ready(int ready_out, int wakefd)
74{
75 char dummy;
76 struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
77
78 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write");
81
82 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll");
85}
86
87/* Sender sprays loops messages down each file descriptor */
88static void *sender(struct sender_context *ctx)
89{
90 char data[DATASIZE];
91 unsigned int i, j;
92
93 ready(ctx->ready_out, ctx->wakefd);
94
95 /* Now pump to every receiver. */
96 for (i = 0; i < loops; i++) {
97 for (j = 0; j < ctx->num_fds; j++) {
98 int ret, done = 0;
99
100again:
101 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done);
103 if (ret < 0)
104 barf("SENDER: write");
105 done += ret;
106 if (done < DATASIZE)
107 goto again;
108 }
109 }
110
111 return NULL;
112}
113
114
115/* One receiver per fd */
116static void *receiver(struct receiver_context* ctx)
117{
118 unsigned int i;
119
120 if (!thread_mode)
121 close(ctx->in_fds[1]);
122
123 /* Wait for start... */
124 ready(ctx->ready_out, ctx->wakefd);
125
126 /* Receive them all */
127 for (i = 0; i < ctx->num_packets; i++) {
128 char data[DATASIZE];
129 int ret, done = 0;
130
131again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0)
134 barf("SERVER: read");
135 done += ret;
136 if (done < DATASIZE)
137 goto again;
138 }
139
140 return NULL;
141}
142
143static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{
145 pthread_attr_t attr;
146 pthread_t childid;
147 int err;
148
149 if (!thread_mode) {
150 /* process mode */
151 /* Fork the receiver. */
152 switch (fork()) {
153 case -1:
154 barf("fork()");
155 break;
156 case 0:
157 (*func) (ctx);
158 exit(0);
159 break;
160 default:
161 break;
162 }
163
164 return (pthread_t)0;
165 }
166
167 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:");
169
170#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize");
173#endif
174
175 err = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) {
177 fprintf(stderr, "pthread_create failed: %s (%d)\n",
178 strerror(err), err);
179 exit(-1);
180 }
181 return childid;
182}
183
184static void reap_worker(pthread_t id)
185{
186 int proc_status;
187 void *thread_status;
188
189 if (!thread_mode) {
190 /* process mode */
191 wait(&proc_status);
192 if (!WIFEXITED(proc_status))
193 exit(1);
194 } else {
195 pthread_join(id, &thread_status);
196 }
197}
198
199/* One group of senders and receivers */
200static unsigned int group(pthread_t *pth,
201 unsigned int num_fds,
202 int ready_out,
203 int wakefd)
204{
205 unsigned int i;
206 struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)
207 + num_fds * sizeof(int));
208
209 if (!snd_ctx)
210 barf("malloc()");
211
212 for (i = 0; i < num_fds; i++) {
213 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx));
215
216 if (!ctx)
217 barf("malloc()");
218
219
220 /* Create the pipe between client and server */
221 fdpair(fds);
222
223 ctx->num_packets = num_fds * loops;
224 ctx->in_fds[0] = fds[0];
225 ctx->in_fds[1] = fds[1];
226 ctx->ready_out = ready_out;
227 ctx->wakefd = wakefd;
228
229 pth[i] = create_worker(ctx, (void *)receiver);
230
231 snd_ctx->out_fds[i] = fds[1];
232 if (!thread_mode)
233 close(fds[0]);
234 }
235
236 /* Now we have all the fds, fork the senders */
237 for (i = 0; i < num_fds; i++) {
238 snd_ctx->ready_out = ready_out;
239 snd_ctx->wakefd = wakefd;
240 snd_ctx->num_fds = num_fds;
241
242 pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);
243 }
244
245 /* Close the fds we have left */
246 if (!thread_mode)
247 for (i = 0; i < num_fds; i++)
248 close(snd_ctx->out_fds[i]);
249
250 /* Return number of children to reap */
251 return num_fds * 2;
252}
253
254static const struct option options[] = {
255 OPT_BOOLEAN('p', "pipe", &use_pipes,
256 "Use pipe() instead of socketpair()"),
257 OPT_BOOLEAN('t', "thread", &thread_mode,
258 "Be multi thread instead of multi process"),
259 OPT_INTEGER('g', "group", &num_groups,
260 "Specify number of groups"),
261 OPT_INTEGER('l', "loop", &loops,
262 "Specify number of loops"),
263 OPT_END()
264};
265
266static const char * const bench_sched_message_usage[] = {
267 "perf bench sched messaging <options>",
268 NULL
269};
270
271int bench_sched_messaging(int argc, const char **argv,
272 const char *prefix __used)
273{
274 unsigned int i, total_children;
275 struct timeval start, stop, diff;
276 unsigned int num_fds = 20;
277 int readyfds[2], wakefds[2];
278 char dummy;
279 pthread_t *pth_tab;
280
281 argc = parse_options(argc, argv, options,
282 bench_sched_message_usage, 0);
283
284 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
285 if (!pth_tab)
286 barf("main:malloc()");
287
288 fdpair(readyfds);
289 fdpair(wakefds);
290
291 total_children = 0;
292 for (i = 0; i < num_groups; i++)
293 total_children += group(pth_tab+total_children, num_fds,
294 readyfds[1], wakefds[0]);
295
296 /* Wait for everyone to be ready */
297 for (i = 0; i < total_children; i++)
298 if (read(readyfds[0], &dummy, 1) != 1)
299 barf("Reading for readyfds");
300
301 gettimeofday(&start, NULL);
302
303 /* Kick them off */
304 if (write(wakefds[1], &dummy, 1) != 1)
305 barf("Writing to start them");
306
307 /* Reap them all */
308 for (i = 0; i < total_children; i++)
309 reap_worker(pth_tab[i]);
310
311 gettimeofday(&stop, NULL);
312
313 timersub(&stop, &start, &diff);
314
315 switch (bench_format) {
316 case BENCH_FORMAT_DEFAULT:
317 printf("# %d sender and receiver %s per group\n",
318 num_fds, thread_mode ? "threads" : "processes");
319 printf("# %d groups == %d %s run\n\n",
320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec, diff.tv_usec/1000);
324 break;
325 case BENCH_FORMAT_SIMPLE:
326 printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000);
327 break;
328 default:
329 /* reaching here is something disaster */
330 fprintf(stderr, "Unknown format:%d\n", bench_format);
331 exit(1);
332 break;
333 }
334
335 return 0;
336}
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
new file mode 100644
index 000000000000..238185f97977
--- /dev/null
+++ b/tools/perf/bench/sched-pipe.c
@@ -0,0 +1,124 @@
1/*
2 *
3 * builtin-bench-pipe.c
4 *
5 * pipe: Benchmark for pipe()
6 *
7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
10 *
11 */
12
13#include "../perf.h"
14#include "../util/util.h"
15#include "../util/parse-options.h"
16#include "../builtin.h"
17#include "bench.h"
18
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <signal.h>
23#include <sys/wait.h>
24#include <linux/unistd.h>
25#include <string.h>
26#include <errno.h>
27#include <assert.h>
28#include <sys/time.h>
29#include <sys/types.h>
30
31#define LOOPS_DEFAULT 1000000
32static int loops = LOOPS_DEFAULT;
33
34static const struct option options[] = {
35 OPT_INTEGER('l', "loop", &loops,
36 "Specify number of loops"),
37 OPT_END()
38};
39
40static const char * const bench_sched_pipe_usage[] = {
41 "perf bench sched pipe <options>",
42 NULL
43};
44
45int bench_sched_pipe(int argc, const char **argv,
46 const char *prefix __used)
47{
48 int pipe_1[2], pipe_2[2];
49 int m = 0, i;
50 struct timeval start, stop, diff;
51 unsigned long long result_usec = 0;
52
53 /*
54 * why does "ret" exist?
55 * discarding returned value of read(), write()
56 * causes error in building environment for perf
57 */
58 int ret, wait_stat;
59 pid_t pid, retpid;
60
61 argc = parse_options(argc, argv, options,
62 bench_sched_pipe_usage, 0);
63
64 assert(!pipe(pipe_1));
65 assert(!pipe(pipe_2));
66
67 pid = fork();
68 assert(pid >= 0);
69
70 gettimeofday(&start, NULL);
71
72 if (!pid) {
73 for (i = 0; i < loops; i++) {
74 ret = read(pipe_1[0], &m, sizeof(int));
75 ret = write(pipe_2[1], &m, sizeof(int));
76 }
77 } else {
78 for (i = 0; i < loops; i++) {
79 ret = write(pipe_1[1], &m, sizeof(int));
80 ret = read(pipe_2[0], &m, sizeof(int));
81 }
82 }
83
84 gettimeofday(&stop, NULL);
85 timersub(&stop, &start, &diff);
86
87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 return 0;
91 }
92
93 switch (bench_format) {
94 case BENCH_FORMAT_DEFAULT:
95 printf("# Extecuted %d pipe operations between two tasks\n\n",
96 loops);
97
98 result_usec = diff.tv_sec * 1000000;
99 result_usec += diff.tv_usec;
100
101 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
102 diff.tv_sec, diff.tv_usec/1000);
103
104 printf(" %14lf usecs/op\n",
105 (double)result_usec / (double)loops);
106 printf(" %14d ops/sec\n",
107 (int)((double)loops /
108 ((double)result_usec / (double)1000000)));
109 break;
110
111 case BENCH_FORMAT_SIMPLE:
112 printf("%lu.%03lu\n",
113 diff.tv_sec, diff.tv_usec / 1000);
114 break;
115
116 default:
117 /* reaching here is something disaster */
118 fprintf(stderr, "Unknown format:%d\n", bench_format);
119 exit(1);
120 break;
121 }
122
123 return 0;
124}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 8c84320ecb06..0bf2e8f9af57 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,27 +19,26 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/event.h"
22#include "util/parse-options.h" 23#include "util/parse-options.h"
23#include "util/parse-events.h" 24#include "util/parse-events.h"
24#include "util/thread.h" 25#include "util/thread.h"
25#include "util/sort.h" 26#include "util/sort.h"
26#include "util/hist.h" 27#include "util/hist.h"
28#include "util/data_map.h"
27 29
28static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
29 31
30static int force; 32static int force;
31static int input;
32 33
33static int full_paths; 34static int full_paths;
34 35
35static int print_line; 36static int print_line;
36 37
37static unsigned long page_size; 38struct sym_hist {
38static unsigned long mmap_window = 32; 39 u64 sum;
39 40 u64 ip[0];
40static struct rb_root threads; 41};
41static struct thread *last_match;
42
43 42
44struct sym_ext { 43struct sym_ext {
45 struct rb_node node; 44 struct rb_node node;
@@ -47,6 +46,39 @@ struct sym_ext {
47 char *path; 46 char *path;
48}; 47};
49 48
49struct sym_priv {
50 struct sym_hist *hist;
51 struct sym_ext *ext;
52};
53
54static struct symbol_conf symbol_conf = {
55 .priv_size = sizeof(struct sym_priv),
56 .try_vmlinux_path = true,
57};
58
59static const char *sym_hist_filter;
60
61static int symbol_filter(struct map *map __used, struct symbol *sym)
62{
63 if (sym_hist_filter == NULL ||
64 strcmp(sym->name, sym_hist_filter) == 0) {
65 struct sym_priv *priv = symbol__priv(sym);
66 const int size = (sizeof(*priv->hist) +
67 (sym->end - sym->start) * sizeof(u64));
68
69 priv->hist = malloc(size);
70 if (priv->hist)
71 memset(priv->hist, 0, size);
72 return 0;
73 }
74 /*
75 * FIXME: We should really filter it out, as we don't want to go thru symbols
76 * we're not interested, and if a DSO ends up with no symbols, delete it too,
77 * but right now the kernel loading routines in symbol.c bail out if no symbols
78 * are found, fix it later.
79 */
80 return 0;
81}
50 82
51/* 83/*
52 * collect histogram counts 84 * collect histogram counts
@@ -55,230 +87,81 @@ static void hist_hit(struct hist_entry *he, u64 ip)
55{ 87{
56 unsigned int sym_size, offset; 88 unsigned int sym_size, offset;
57 struct symbol *sym = he->sym; 89 struct symbol *sym = he->sym;
90 struct sym_priv *priv;
91 struct sym_hist *h;
58 92
59 he->count++; 93 he->count++;
60 94
61 if (!sym || !sym->hist) 95 if (!sym || !he->map)
96 return;
97
98 priv = symbol__priv(sym);
99 if (!priv->hist)
62 return; 100 return;
63 101
64 sym_size = sym->end - sym->start; 102 sym_size = sym->end - sym->start;
65 ip = he->map->map_ip(he->map, ip);
66 offset = ip - sym->start; 103 offset = ip - sym->start;
67 104
105 if (verbose)
106 fprintf(stderr, "%s: ip=%Lx\n", __func__,
107 he->map->unmap_ip(he->map, ip));
108
68 if (offset >= sym_size) 109 if (offset >= sym_size)
69 return; 110 return;
70 111
71 sym->hist_sum++; 112 h = priv->hist;
72 sym->hist[offset]++; 113 h->sum++;
114 h->ip[offset]++;
73 115
74 if (verbose >= 3) 116 if (verbose >= 3)
75 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 117 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
76 (void *)(unsigned long)he->sym->start, 118 (void *)(unsigned long)he->sym->start,
77 he->sym->name, 119 he->sym->name,
78 (void *)(unsigned long)ip, ip - he->sym->start, 120 (void *)(unsigned long)ip, ip - he->sym->start,
79 sym->hist[offset]); 121 h->ip[offset]);
80} 122}
81 123
82static int hist_entry__add(struct thread *thread, struct map *map, 124static int hist_entry__add(struct addr_location *al, u64 count)
83 struct symbol *sym, u64 ip, u64 count, char level)
84{ 125{
85 bool hit; 126 bool hit;
86 struct hist_entry *he = __hist_entry__add(thread, map, sym, NULL, ip, 127 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
87 count, level, &hit);
88 if (he == NULL) 128 if (he == NULL)
89 return -ENOMEM; 129 return -ENOMEM;
90 if (hit) 130 hist_hit(he, al->addr);
91 hist_hit(he, ip);
92 return 0; 131 return 0;
93} 132}
94 133
95static int 134static int process_sample_event(event_t *event)
96process_sample_event(event_t *event, unsigned long offset, unsigned long head)
97{ 135{
98 char level; 136 struct addr_location al;
99 struct thread *thread;
100 u64 ip = event->ip.ip;
101 struct map *map = NULL;
102 struct symbol *sym = NULL;
103
104 thread = threads__findnew(event->ip.pid, &threads, &last_match);
105 137
106 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 138 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
107 (void *)(offset + head), 139 event->ip.pid, (void *)(long)event->ip.ip);
108 (void *)(long)(event->header.size),
109 event->header.misc,
110 event->ip.pid,
111 (void *)(long)ip);
112 140
113 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 141 if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
114
115 if (thread == NULL) {
116 fprintf(stderr, "problem processing %d event, skipping it.\n", 142 fprintf(stderr, "problem processing %d event, skipping it.\n",
117 event->header.type); 143 event->header.type);
118 return -1; 144 return -1;
119 } 145 }
120 146
121 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 147 if (hist_entry__add(&al, 1)) {
122 level = 'k';
123 sym = kernel_maps__find_symbol(ip, &map);
124 dump_printf(" ...... dso: %s\n",
125 map ? map->dso->long_name : "<not found>");
126 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
127 level = '.';
128 map = thread__find_map(thread, ip);
129 if (map != NULL) {
130got_map:
131 ip = map->map_ip(map, ip);
132 sym = map->dso->find_symbol(map->dso, ip);
133 } else {
134 /*
135 * If this is outside of all known maps,
136 * and is a negative address, try to look it
137 * up in the kernel dso, as it might be a
138 * vsyscall or vdso (which executes in user-mode).
139 *
140 * XXX This is nasty, we should have a symbol list in
141 * the "[vdso]" dso, but for now lets use the old
142 * trick of looking in the whole kernel symbol list.
143 */
144 if ((long long)ip < 0) {
145 map = kernel_map;
146 goto got_map;
147 }
148 }
149 dump_printf(" ...... dso: %s\n",
150 map ? map->dso->long_name : "<not found>");
151 } else {
152 level = 'H';
153 dump_printf(" ...... dso: [hypervisor]\n");
154 }
155
156 if (hist_entry__add(thread, map, sym, ip, 1, level)) {
157 fprintf(stderr, "problem incrementing symbol count, " 148 fprintf(stderr, "problem incrementing symbol count, "
158 "skipping event\n"); 149 "skipping event\n");
159 return -1; 150 return -1;
160 } 151 }
161 total++;
162
163 return 0;
164}
165
166static int
167process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
168{
169 struct thread *thread;
170 struct map *map = map__new(&event->mmap, NULL, 0);
171
172 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
173
174 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
175 (void *)(offset + head),
176 (void *)(long)(event->header.size),
177 event->mmap.pid,
178 (void *)(long)event->mmap.start,
179 (void *)(long)event->mmap.len,
180 (void *)(long)event->mmap.pgoff,
181 event->mmap.filename);
182
183 if (thread == NULL || map == NULL) {
184 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
185 return 0;
186 }
187
188 thread__insert_map(thread, map);
189 total_mmap++;
190
191 return 0;
192}
193
194static int
195process_comm_event(event_t *event, unsigned long offset, unsigned long head)
196{
197 struct thread *thread;
198
199 thread = threads__findnew(event->comm.pid, &threads, &last_match);
200 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
201 (void *)(offset + head),
202 (void *)(long)(event->header.size),
203 event->comm.comm, event->comm.pid);
204
205 if (thread == NULL ||
206 thread__set_comm(thread, event->comm.comm)) {
207 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
208 return -1;
209 }
210 total_comm++;
211
212 return 0;
213}
214
215static int
216process_fork_event(event_t *event, unsigned long offset, unsigned long head)
217{
218 struct thread *thread;
219 struct thread *parent;
220
221 thread = threads__findnew(event->fork.pid, &threads, &last_match);
222 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
223 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
224 (void *)(offset + head),
225 (void *)(long)(event->header.size),
226 event->fork.pid, event->fork.ppid);
227
228 /*
229 * A thread clone will have the same PID for both
230 * parent and child.
231 */
232 if (thread == parent)
233 return 0;
234
235 if (!thread || !parent || thread__fork(thread, parent)) {
236 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
237 return -1;
238 }
239 total_fork++;
240
241 return 0;
242}
243
244static int
245process_event(event_t *event, unsigned long offset, unsigned long head)
246{
247 switch (event->header.type) {
248 case PERF_RECORD_SAMPLE:
249 return process_sample_event(event, offset, head);
250
251 case PERF_RECORD_MMAP:
252 return process_mmap_event(event, offset, head);
253
254 case PERF_RECORD_COMM:
255 return process_comm_event(event, offset, head);
256
257 case PERF_RECORD_FORK:
258 return process_fork_event(event, offset, head);
259 /*
260 * We dont process them right now but they are fine:
261 */
262
263 case PERF_RECORD_THROTTLE:
264 case PERF_RECORD_UNTHROTTLE:
265 return 0;
266
267 default:
268 return -1;
269 }
270 152
271 return 0; 153 return 0;
272} 154}
273 155
274static int 156static int parse_line(FILE *file, struct hist_entry *he, u64 len)
275parse_line(FILE *file, struct symbol *sym, u64 len)
276{ 157{
158 struct symbol *sym = he->sym;
277 char *line = NULL, *tmp, *tmp2; 159 char *line = NULL, *tmp, *tmp2;
278 static const char *prev_line; 160 static const char *prev_line;
279 static const char *prev_color; 161 static const char *prev_color;
280 unsigned int offset; 162 unsigned int offset;
281 size_t line_len; 163 size_t line_len;
164 u64 start;
282 s64 line_ip; 165 s64 line_ip;
283 int ret; 166 int ret;
284 char *c; 167 char *c;
@@ -315,22 +198,26 @@ parse_line(FILE *file, struct symbol *sym, u64 len)
315 line_ip = -1; 198 line_ip = -1;
316 } 199 }
317 200
201 start = he->map->unmap_ip(he->map, sym->start);
202
318 if (line_ip != -1) { 203 if (line_ip != -1) {
319 const char *path = NULL; 204 const char *path = NULL;
320 unsigned int hits = 0; 205 unsigned int hits = 0;
321 double percent = 0.0; 206 double percent = 0.0;
322 const char *color; 207 const char *color;
323 struct sym_ext *sym_ext = sym->priv; 208 struct sym_priv *priv = symbol__priv(sym);
209 struct sym_ext *sym_ext = priv->ext;
210 struct sym_hist *h = priv->hist;
324 211
325 offset = line_ip - sym->start; 212 offset = line_ip - start;
326 if (offset < len) 213 if (offset < len)
327 hits = sym->hist[offset]; 214 hits = h->ip[offset];
328 215
329 if (offset < len && sym_ext) { 216 if (offset < len && sym_ext) {
330 path = sym_ext[offset].path; 217 path = sym_ext[offset].path;
331 percent = sym_ext[offset].percent; 218 percent = sym_ext[offset].percent;
332 } else if (sym->hist_sum) 219 } else if (h->sum)
333 percent = 100.0 * hits / sym->hist_sum; 220 percent = 100.0 * hits / h->sum;
334 221
335 color = get_percent_color(percent); 222 color = get_percent_color(percent);
336 223
@@ -383,9 +270,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
383 rb_insert_color(&sym_ext->node, &root_sym_ext); 270 rb_insert_color(&sym_ext->node, &root_sym_ext);
384} 271}
385 272
386static void free_source_line(struct symbol *sym, int len) 273static void free_source_line(struct hist_entry *he, int len)
387{ 274{
388 struct sym_ext *sym_ext = sym->priv; 275 struct sym_priv *priv = symbol__priv(he->sym);
276 struct sym_ext *sym_ext = priv->ext;
389 int i; 277 int i;
390 278
391 if (!sym_ext) 279 if (!sym_ext)
@@ -395,26 +283,30 @@ static void free_source_line(struct symbol *sym, int len)
395 free(sym_ext[i].path); 283 free(sym_ext[i].path);
396 free(sym_ext); 284 free(sym_ext);
397 285
398 sym->priv = NULL; 286 priv->ext = NULL;
399 root_sym_ext = RB_ROOT; 287 root_sym_ext = RB_ROOT;
400} 288}
401 289
402/* Get the filename:line for the colored entries */ 290/* Get the filename:line for the colored entries */
403static void 291static void
404get_source_line(struct symbol *sym, int len, const char *filename) 292get_source_line(struct hist_entry *he, int len, const char *filename)
405{ 293{
294 struct symbol *sym = he->sym;
295 u64 start;
406 int i; 296 int i;
407 char cmd[PATH_MAX * 2]; 297 char cmd[PATH_MAX * 2];
408 struct sym_ext *sym_ext; 298 struct sym_ext *sym_ext;
299 struct sym_priv *priv = symbol__priv(sym);
300 struct sym_hist *h = priv->hist;
409 301
410 if (!sym->hist_sum) 302 if (!h->sum)
411 return; 303 return;
412 304
413 sym->priv = calloc(len, sizeof(struct sym_ext)); 305 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
414 if (!sym->priv) 306 if (!priv->ext)
415 return; 307 return;
416 308
417 sym_ext = sym->priv; 309 start = he->map->unmap_ip(he->map, sym->start);
418 310
419 for (i = 0; i < len; i++) { 311 for (i = 0; i < len; i++) {
420 char *path = NULL; 312 char *path = NULL;
@@ -422,11 +314,11 @@ get_source_line(struct symbol *sym, int len, const char *filename)
422 u64 offset; 314 u64 offset;
423 FILE *fp; 315 FILE *fp;
424 316
425 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 317 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
426 if (sym_ext[i].percent <= 0.5) 318 if (sym_ext[i].percent <= 0.5)
427 continue; 319 continue;
428 320
429 offset = sym->start + i; 321 offset = start + i;
430 sprintf(cmd, "addr2line -e %s %016llx", filename, offset); 322 sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
431 fp = popen(cmd, "r"); 323 fp = popen(cmd, "r");
432 if (!fp) 324 if (!fp)
@@ -476,8 +368,11 @@ static void print_summary(const char *filename)
476 } 368 }
477} 369}
478 370
479static void annotate_sym(struct dso *dso, struct symbol *sym) 371static void annotate_sym(struct hist_entry *he)
480{ 372{
373 struct map *map = he->map;
374 struct dso *dso = map->dso;
375 struct symbol *sym = he->sym;
481 const char *filename = dso->long_name, *d_filename; 376 const char *filename = dso->long_name, *d_filename;
482 u64 len; 377 u64 len;
483 char command[PATH_MAX*2]; 378 char command[PATH_MAX*2];
@@ -486,6 +381,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
486 if (!filename) 381 if (!filename)
487 return; 382 return;
488 383
384 if (verbose)
385 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
386 __func__, filename, sym->name,
387 map->unmap_ip(map, sym->start),
388 map->unmap_ip(map, sym->end));
389
489 if (full_paths) 390 if (full_paths)
490 d_filename = filename; 391 d_filename = filename;
491 else 392 else
@@ -494,7 +395,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
494 len = sym->end - sym->start; 395 len = sym->end - sym->start;
495 396
496 if (print_line) { 397 if (print_line) {
497 get_source_line(sym, len, filename); 398 get_source_line(he, len, filename);
498 print_summary(filename); 399 print_summary(filename);
499 } 400 }
500 401
@@ -507,7 +408,8 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
507 dso, dso->long_name, sym, sym->name); 408 dso, dso->long_name, sym, sym->name);
508 409
509 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 410 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
510 sym->start, sym->end, filename, filename); 411 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
412 filename, filename);
511 413
512 if (verbose >= 3) 414 if (verbose >= 3)
513 printf("doing: %s\n", command); 415 printf("doing: %s\n", command);
@@ -517,159 +419,78 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
517 return; 419 return;
518 420
519 while (!feof(file)) { 421 while (!feof(file)) {
520 if (parse_line(file, sym, len) < 0) 422 if (parse_line(file, he, len) < 0)
521 break; 423 break;
522 } 424 }
523 425
524 pclose(file); 426 pclose(file);
525 if (print_line) 427 if (print_line)
526 free_source_line(sym, len); 428 free_source_line(he, len);
527} 429}
528 430
529static void find_annotations(void) 431static void find_annotations(void)
530{ 432{
531 struct rb_node *nd; 433 struct rb_node *nd;
532 struct dso *dso;
533 int count = 0;
534
535 list_for_each_entry(dso, &dsos, node) {
536
537 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
538 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
539
540 if (sym->hist) {
541 annotate_sym(dso, sym);
542 count++;
543 }
544 }
545 }
546
547 if (!count)
548 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
549}
550
551static int __cmd_annotate(void)
552{
553 int ret, rc = EXIT_FAILURE;
554 unsigned long offset = 0;
555 unsigned long head = 0;
556 struct stat input_stat;
557 event_t *event;
558 uint32_t size;
559 char *buf;
560
561 register_idle_thread(&threads, &last_match);
562
563 input = open(input_name, O_RDONLY);
564 if (input < 0) {
565 perror("failed to open file");
566 exit(-1);
567 }
568
569 ret = fstat(input, &input_stat);
570 if (ret < 0) {
571 perror("failed to stat file");
572 exit(-1);
573 }
574
575 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
576 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
577 exit(-1);
578 }
579
580 if (!input_stat.st_size) {
581 fprintf(stderr, "zero-sized file, nothing to do!\n");
582 exit(0);
583 }
584
585 if (load_kernel() < 0) {
586 perror("failed to load kernel symbols");
587 return EXIT_FAILURE;
588 }
589
590remap:
591 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
592 MAP_SHARED, input, offset);
593 if (buf == MAP_FAILED) {
594 perror("failed to mmap file");
595 exit(-1);
596 }
597
598more:
599 event = (event_t *)(buf + head);
600
601 size = event->header.size;
602 if (!size)
603 size = 8;
604
605 if (head + event->header.size >= page_size * mmap_window) {
606 unsigned long shift = page_size * (head / page_size);
607 int munmap_ret;
608
609 munmap_ret = munmap(buf, page_size * mmap_window);
610 assert(munmap_ret == 0);
611
612 offset += shift;
613 head -= shift;
614 goto remap;
615 }
616
617 size = event->header.size;
618
619 dump_printf("%p [%p]: event: %d\n",
620 (void *)(offset + head),
621 (void *)(long)event->header.size,
622 event->header.type);
623 434
624 if (!size || process_event(event, offset, head) < 0) { 435 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
436 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
437 struct sym_priv *priv;
625 438
626 dump_printf("%p [%p]: skipping unknown header type: %d\n", 439 if (he->sym == NULL)
627 (void *)(offset + head), 440 continue;
628 (void *)(long)(event->header.size),
629 event->header.type);
630 441
631 total_unknown++; 442 priv = symbol__priv(he->sym);
443 if (priv->hist == NULL)
444 continue;
632 445
446 annotate_sym(he);
633 /* 447 /*
634 * assume we lost track of the stream, check alignment, and 448 * Since we have a hist_entry per IP for the same symbol, free
635 * increment a single u64 in the hope to catch on again 'soon'. 449 * he->sym->hist to signal we already processed this symbol.
636 */ 450 */
637 451 free(priv->hist);
638 if (unlikely(head & 7)) 452 priv->hist = NULL;
639 head &= ~7ULL;
640
641 size = 8;
642 } 453 }
454}
643 455
644 head += size; 456static struct perf_file_handler file_handler = {
457 .process_sample_event = process_sample_event,
458 .process_mmap_event = event__process_mmap,
459 .process_comm_event = event__process_comm,
460 .process_fork_event = event__process_task,
461};
645 462
646 if (offset + head < (unsigned long)input_stat.st_size) 463static int __cmd_annotate(void)
647 goto more; 464{
465 struct perf_header *header;
466 struct thread *idle;
467 int ret;
648 468
649 rc = EXIT_SUCCESS; 469 idle = register_idle_thread();
650 close(input); 470 register_perf_file_handler(&file_handler);
651 471
652 dump_printf(" IP events: %10ld\n", total); 472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
653 dump_printf(" mmap events: %10ld\n", total_mmap); 473 &event__cwdlen, &event__cwd);
654 dump_printf(" comm events: %10ld\n", total_comm); 474 if (ret)
655 dump_printf(" fork events: %10ld\n", total_fork); 475 return ret;
656 dump_printf(" unknown events: %10ld\n", total_unknown);
657 476
658 if (dump_trace) 477 if (dump_trace) {
478 event__print_totals();
659 return 0; 479 return 0;
480 }
660 481
661 if (verbose > 3) 482 if (verbose > 3)
662 threads__fprintf(stdout, &threads); 483 threads__fprintf(stdout);
663 484
664 if (verbose > 2) 485 if (verbose > 2)
665 dsos__fprintf(stdout); 486 dsos__fprintf(stdout);
666 487
667 collapse__resort(); 488 collapse__resort();
668 output__resort(total); 489 output__resort(event__total[0]);
669 490
670 find_annotations(); 491 find_annotations();
671 492
672 return rc; 493 return ret;
673} 494}
674 495
675static const char * const annotate_usage[] = { 496static const char * const annotate_usage[] = {
@@ -687,8 +508,9 @@ static const struct option options[] = {
687 "be more verbose (show symbol address, etc)"), 508 "be more verbose (show symbol address, etc)"),
688 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 509 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
689 "dump raw trace in ASCII"), 510 "dump raw trace in ASCII"),
690 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 511 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
691 OPT_BOOLEAN('m', "modules", &modules, 512 "file", "vmlinux pathname"),
513 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
692 "load module symbols - WARNING: use only with -k and LIVE kernel"), 514 "load module symbols - WARNING: use only with -k and LIVE kernel"),
693 OPT_BOOLEAN('l', "print-line", &print_line, 515 OPT_BOOLEAN('l', "print-line", &print_line,
694 "print matching source lines (may be slow)"), 516 "print matching source lines (may be slow)"),
@@ -714,9 +536,8 @@ static void setup_sorting(void)
714 536
715int cmd_annotate(int argc, const char **argv, const char *prefix __used) 537int cmd_annotate(int argc, const char **argv, const char *prefix __used)
716{ 538{
717 symbol__init(); 539 if (symbol__init(&symbol_conf) < 0)
718 540 return -1;
719 page_size = getpagesize();
720 541
721 argc = parse_options(argc, argv, options, annotate_usage, 0); 542 argc = parse_options(argc, argv, options, annotate_usage, 0);
722 543
@@ -733,9 +554,6 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
733 sym_hist_filter = argv[0]; 554 sym_hist_filter = argv[0];
734 } 555 }
735 556
736 if (!sym_hist_filter)
737 usage_with_options(annotate_usage, options);
738
739 setup_pager(); 557 setup_pager();
740 558
741 if (field_sep && *field_sep == '.') { 559 if (field_sep && *field_sep == '.') {
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
new file mode 100644
index 000000000000..e043eb83092a
--- /dev/null
+++ b/tools/perf/builtin-bench.c
@@ -0,0 +1,196 @@
1/*
2 *
3 * builtin-bench.c
4 *
5 * General benchmarking subsystem provided by perf
6 *
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8 *
9 */
10
11/*
12 *
13 * Available subsystem list:
14 * sched ... scheduler and IPC mechanism
15 * mem ... memory access performance
16 *
17 */
18
19#include "perf.h"
20#include "util/util.h"
21#include "util/parse-options.h"
22#include "builtin.h"
23#include "bench/bench.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29struct bench_suite {
30 const char *name;
31 const char *summary;
32 int (*fn)(int, const char **, const char *);
33};
34
35static struct bench_suite sched_suites[] = {
36 { "messaging",
37 "Benchmark for scheduler and IPC mechanisms",
38 bench_sched_messaging },
39 { "pipe",
40 "Flood of communication over pipe() between two processes",
41 bench_sched_pipe },
42 { NULL,
43 NULL,
44 NULL }
45};
46
47static struct bench_suite mem_suites[] = {
48 { "memcpy",
49 "Simple memory copy in various ways",
50 bench_mem_memcpy },
51 { NULL,
52 NULL,
53 NULL }
54};
55
56struct bench_subsys {
57 const char *name;
58 const char *summary;
59 struct bench_suite *suites;
60};
61
62static struct bench_subsys subsystems[] = {
63 { "sched",
64 "scheduler and IPC mechanism",
65 sched_suites },
66 { "mem",
67 "memory access performance",
68 mem_suites },
69 { NULL,
70 NULL,
71 NULL }
72};
73
74static void dump_suites(int subsys_index)
75{
76 int i;
77
78 printf("List of available suites for %s...\n\n",
79 subsystems[subsys_index].name);
80
81 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
82 printf("\t%s: %s\n",
83 subsystems[subsys_index].suites[i].name,
84 subsystems[subsys_index].suites[i].summary);
85
86 printf("\n");
87 return;
88}
89
90static char *bench_format_str;
91int bench_format = BENCH_FORMAT_DEFAULT;
92
93static const struct option bench_options[] = {
94 OPT_STRING('f', "format", &bench_format_str, "default",
95 "Specify format style"),
96 OPT_END()
97};
98
99static const char * const bench_usage[] = {
100 "perf bench [<common options>] <subsystem> <suite> [<options>]",
101 NULL
102};
103
104static void print_usage(void)
105{
106 int i;
107
108 printf("Usage: \n");
109 for (i = 0; bench_usage[i]; i++)
110 printf("\t%s\n", bench_usage[i]);
111 printf("\n");
112
113 printf("List of available subsystems...\n\n");
114
115 for (i = 0; subsystems[i].name; i++)
116 printf("\t%s: %s\n",
117 subsystems[i].name, subsystems[i].summary);
118 printf("\n");
119}
120
121static int bench_str2int(char *str)
122{
123 if (!str)
124 return BENCH_FORMAT_DEFAULT;
125
126 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
127 return BENCH_FORMAT_DEFAULT;
128 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
129 return BENCH_FORMAT_SIMPLE;
130
131 return BENCH_FORMAT_UNKNOWN;
132}
133
134int cmd_bench(int argc, const char **argv, const char *prefix __used)
135{
136 int i, j, status = 0;
137
138 if (argc < 2) {
139 /* No subsystem specified. */
140 print_usage();
141 goto end;
142 }
143
144 argc = parse_options(argc, argv, bench_options, bench_usage,
145 PARSE_OPT_STOP_AT_NON_OPTION);
146
147 bench_format = bench_str2int(bench_format_str);
148 if (bench_format == BENCH_FORMAT_UNKNOWN) {
149 printf("Unknown format descriptor:%s\n", bench_format_str);
150 goto end;
151 }
152
153 if (argc < 1) {
154 print_usage();
155 goto end;
156 }
157
158 for (i = 0; subsystems[i].name; i++) {
159 if (strcmp(subsystems[i].name, argv[0]))
160 continue;
161
162 if (argc < 2) {
163 /* No suite specified. */
164 dump_suites(i);
165 goto end;
166 }
167
168 for (j = 0; subsystems[i].suites[j].name; j++) {
169 if (strcmp(subsystems[i].suites[j].name, argv[1]))
170 continue;
171
172 if (bench_format == BENCH_FORMAT_DEFAULT)
173 printf("# Running %s/%s benchmark...\n",
174 subsystems[i].name,
175 subsystems[i].suites[j].name);
176 status = subsystems[i].suites[j].fn(argc - 1,
177 argv + 1, prefix);
178 goto end;
179 }
180
181 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
182 dump_suites(i);
183 goto end;
184 }
185
186 printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
187 status = 1;
188 goto end;
189 }
190
191 printf("Unknown subsystem:%s\n", argv[0]);
192 status = 1;
193
194end:
195 return status;
196}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
new file mode 100644
index 000000000000..7dee9d19ab7a
--- /dev/null
+++ b/tools/perf/builtin-buildid-list.c
@@ -0,0 +1,116 @@
1/*
2 * builtin-buildid-list.c
3 *
4 * Builtin buildid-list command: list buildids in perf.data
5 *
6 * Copyright (C) 2009, Red Hat Inc.
7 * Copyright (C) 2009, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/data_map.h"
13#include "util/debug.h"
14#include "util/header.h"
15#include "util/parse-options.h"
16#include "util/symbol.h"
17
18static char const *input_name = "perf.data";
19static int force;
20
21static const char *const buildid_list_usage[] = {
22 "perf report [<options>]",
23 NULL
24};
25
26static const struct option options[] = {
27 OPT_STRING('i', "input", &input_name, "file",
28 "input file name"),
29 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
30 OPT_BOOLEAN('v', "verbose", &verbose,
31 "be more verbose"),
32 OPT_END()
33};
34
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)
56{
57 int err = -1;
58 struct perf_header *header;
59 struct perf_file_header f_header;
60 struct stat input_stat;
61 int input = open(input_name, O_RDONLY);
62
63 if (input < 0) {
64 pr_err("failed to open file: %s", input_name);
65 if (!strcmp(input_name, "perf.data"))
66 pr_err(" (try 'perf record' first)");
67 pr_err("\n");
68 goto out;
69 }
70
71 err = fstat(input, &input_stat);
72 if (err < 0) {
73 perror("failed to stat file");
74 goto out_close;
75 }
76
77 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
78 pr_err("file %s not owned by current user or root\n",
79 input_name);
80 goto out_close;
81 }
82
83 if (!input_stat.st_size) {
84 pr_info("zero-sized file, nothing to do!\n");
85 goto out_close;
86 }
87
88 err = -1;
89 header = perf_header__new();
90 if (header == NULL)
91 goto out_close;
92
93 if (perf_file_header__read(&f_header, header, input) < 0) {
94 pr_warning("incompatible file format");
95 goto out_close;
96 }
97
98 err = perf_header__process_sections(header, input,
99 perf_file_section__process_buildids);
100
101 if (err < 0)
102 goto out_close;
103
104 dsos__fprintf_buildid(stdout);
105out_close:
106 close(input);
107out:
108 return err;
109}
110
111int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
112{
113 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
114 setup_pager();
115 return __cmd_buildid_list();
116}
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 4fb8734a796e..9f810b17c25c 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -61,8 +61,7 @@ static const char *get_man_viewer_info(const char *name)
61{ 61{
62 struct man_viewer_info_list *viewer; 62 struct man_viewer_info_list *viewer;
63 63
64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) 64 for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) {
65 {
66 if (!strcasecmp(name, viewer->name)) 65 if (!strcasecmp(name, viewer->name))
67 return viewer->info; 66 return viewer->info;
68 } 67 }
@@ -115,7 +114,7 @@ static int check_emacsclient_version(void)
115 return 0; 114 return 0;
116} 115}
117 116
118static void exec_woman_emacs(const char* path, const char *page) 117static void exec_woman_emacs(const char *path, const char *page)
119{ 118{
120 if (!check_emacsclient_version()) { 119 if (!check_emacsclient_version()) {
121 /* This works only with emacsclient version >= 22. */ 120 /* This works only with emacsclient version >= 22. */
@@ -129,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page)
129 } 128 }
130} 129}
131 130
132static void exec_man_konqueror(const char* path, const char *page) 131static void exec_man_konqueror(const char *path, const char *page)
133{ 132{
134 const char *display = getenv("DISPLAY"); 133 const char *display = getenv("DISPLAY");
135 if (display && *display) { 134 if (display && *display) {
@@ -157,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page)
157 } 156 }
158} 157}
159 158
160static void exec_man_man(const char* path, const char *page) 159static void exec_man_man(const char *path, const char *page)
161{ 160{
162 if (!path) 161 if (!path)
163 path = "man"; 162 path = "man";
@@ -180,7 +179,7 @@ static void add_man_viewer(const char *name)
180 179
181 while (*p) 180 while (*p)
182 p = &((*p)->next); 181 p = &((*p)->next);
183 *p = calloc(1, (sizeof(**p) + len + 1)); 182 *p = zalloc(sizeof(**p) + len + 1);
184 strncpy((*p)->name, name, len); 183 strncpy((*p)->name, name, len);
185} 184}
186 185
@@ -195,7 +194,7 @@ static void do_add_man_viewer_info(const char *name,
195 size_t len, 194 size_t len,
196 const char *value) 195 const char *value)
197{ 196{
198 struct man_viewer_info_list *new = calloc(1, sizeof(*new) + len + 1); 197 struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1);
199 198
200 strncpy(new->name, name, len); 199 strncpy(new->name, name, len);
201 new->info = strdup(value); 200 new->info = strdup(value);
@@ -364,9 +363,8 @@ static void show_man_page(const char *perf_cmd)
364 363
365 setup_man_path(); 364 setup_man_path();
366 for (viewer = man_viewer_list; viewer; viewer = viewer->next) 365 for (viewer = man_viewer_list; viewer; viewer = viewer->next)
367 {
368 exec_viewer(viewer->name, page); /* will return when unable */ 366 exec_viewer(viewer->name, page); /* will return when unable */
369 } 367
370 if (fallback) 368 if (fallback)
371 exec_viewer(fallback, page); 369 exec_viewer(fallback, page);
372 exec_viewer("man", page); 370 exec_viewer("man", page);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
new file mode 100644
index 000000000000..047fef74bd52
--- /dev/null
+++ b/tools/perf/builtin-kmem.c
@@ -0,0 +1,807 @@
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/data_map.h"
15
16#include <linux/rbtree.h>
17
18struct alloc_stat;
19typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20
21static char const *input_name = "perf.data";
22
23static struct perf_header *header;
24static u64 sample_type;
25
26static int alloc_flag;
27static int caller_flag;
28
29static int alloc_lines = -1;
30static int caller_lines = -1;
31
32static bool raw_ip;
33
34static char default_sort_order[] = "frag,hit,bytes";
35
36static int *cpunode_map;
37static int max_cpu_num;
38
39struct alloc_stat {
40 u64 call_site;
41 u64 ptr;
42 u64 bytes_req;
43 u64 bytes_alloc;
44 u32 hit;
45 u32 pingpong;
46
47 short alloc_cpu;
48
49 struct rb_node node;
50};
51
52static struct rb_root root_alloc_stat;
53static struct rb_root root_alloc_sorted;
54static struct rb_root root_caller_stat;
55static struct rb_root root_caller_sorted;
56
57static unsigned long total_requested, total_allocated;
58static unsigned long nr_allocs, nr_cross_allocs;
59
60struct raw_event_sample {
61 u32 size;
62 char data[0];
63};
64
65#define PATH_SYS_NODE "/sys/devices/system/node"
66
67static void init_cpunode_map(void)
68{
69 FILE *fp;
70 int i;
71
72 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
73 if (!fp) {
74 max_cpu_num = 4096;
75 return;
76 }
77
78 if (fscanf(fp, "%d", &max_cpu_num) < 1)
79 die("Failed to read 'kernel_max' from sysfs");
80 max_cpu_num++;
81
82 cpunode_map = calloc(max_cpu_num, sizeof(int));
83 if (!cpunode_map)
84 die("calloc");
85 for (i = 0; i < max_cpu_num; i++)
86 cpunode_map[i] = -1;
87 fclose(fp);
88}
89
90static void setup_cpunode_map(void)
91{
92 struct dirent *dent1, *dent2;
93 DIR *dir1, *dir2;
94 unsigned int cpu, mem;
95 char buf[PATH_MAX];
96
97 init_cpunode_map();
98
99 dir1 = opendir(PATH_SYS_NODE);
100 if (!dir1)
101 return;
102
103 while (true) {
104 dent1 = readdir(dir1);
105 if (!dent1)
106 break;
107
108 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
109 continue;
110
111 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
112 dir2 = opendir(buf);
113 if (!dir2)
114 continue;
115 while (true) {
116 dent2 = readdir(dir2);
117 if (!dent2)
118 break;
119 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
120 continue;
121 cpunode_map[cpu] = mem;
122 }
123 }
124}
125
126static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
127 int bytes_req, int bytes_alloc, int cpu)
128{
129 struct rb_node **node = &root_alloc_stat.rb_node;
130 struct rb_node *parent = NULL;
131 struct alloc_stat *data = NULL;
132
133 while (*node) {
134 parent = *node;
135 data = rb_entry(*node, struct alloc_stat, node);
136
137 if (ptr > data->ptr)
138 node = &(*node)->rb_right;
139 else if (ptr < data->ptr)
140 node = &(*node)->rb_left;
141 else
142 break;
143 }
144
145 if (data && data->ptr == ptr) {
146 data->hit++;
147 data->bytes_req += bytes_req;
148 data->bytes_alloc += bytes_req;
149 } else {
150 data = malloc(sizeof(*data));
151 if (!data)
152 die("malloc");
153 data->ptr = ptr;
154 data->pingpong = 0;
155 data->hit = 1;
156 data->bytes_req = bytes_req;
157 data->bytes_alloc = bytes_alloc;
158
159 rb_link_node(&data->node, parent, node);
160 rb_insert_color(&data->node, &root_alloc_stat);
161 }
162 data->call_site = call_site;
163 data->alloc_cpu = cpu;
164}
165
166static void insert_caller_stat(unsigned long call_site,
167 int bytes_req, int bytes_alloc)
168{
169 struct rb_node **node = &root_caller_stat.rb_node;
170 struct rb_node *parent = NULL;
171 struct alloc_stat *data = NULL;
172
173 while (*node) {
174 parent = *node;
175 data = rb_entry(*node, struct alloc_stat, node);
176
177 if (call_site > data->call_site)
178 node = &(*node)->rb_right;
179 else if (call_site < data->call_site)
180 node = &(*node)->rb_left;
181 else
182 break;
183 }
184
185 if (data && data->call_site == call_site) {
186 data->hit++;
187 data->bytes_req += bytes_req;
188 data->bytes_alloc += bytes_req;
189 } else {
190 data = malloc(sizeof(*data));
191 if (!data)
192 die("malloc");
193 data->call_site = call_site;
194 data->pingpong = 0;
195 data->hit = 1;
196 data->bytes_req = bytes_req;
197 data->bytes_alloc = bytes_alloc;
198
199 rb_link_node(&data->node, parent, node);
200 rb_insert_color(&data->node, &root_caller_stat);
201 }
202}
203
204static void process_alloc_event(struct raw_event_sample *raw,
205 struct event *event,
206 int cpu,
207 u64 timestamp __used,
208 struct thread *thread __used,
209 int node)
210{
211 unsigned long call_site;
212 unsigned long ptr;
213 int bytes_req;
214 int bytes_alloc;
215 int node1, node2;
216
217 ptr = raw_field_value(event, "ptr", raw->data);
218 call_site = raw_field_value(event, "call_site", raw->data);
219 bytes_req = raw_field_value(event, "bytes_req", raw->data);
220 bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data);
221
222 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
223 insert_caller_stat(call_site, bytes_req, bytes_alloc);
224
225 total_requested += bytes_req;
226 total_allocated += bytes_alloc;
227
228 if (node) {
229 node1 = cpunode_map[cpu];
230 node2 = raw_field_value(event, "node", raw->data);
231 if (node1 != node2)
232 nr_cross_allocs++;
233 }
234 nr_allocs++;
235}
236
237static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
238static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
239
240static struct alloc_stat *search_alloc_stat(unsigned long ptr,
241 unsigned long call_site,
242 struct rb_root *root,
243 sort_fn_t sort_fn)
244{
245 struct rb_node *node = root->rb_node;
246 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
247
248 while (node) {
249 struct alloc_stat *data;
250 int cmp;
251
252 data = rb_entry(node, struct alloc_stat, node);
253
254 cmp = sort_fn(&key, data);
255 if (cmp < 0)
256 node = node->rb_left;
257 else if (cmp > 0)
258 node = node->rb_right;
259 else
260 return data;
261 }
262 return NULL;
263}
264
265static void process_free_event(struct raw_event_sample *raw,
266 struct event *event,
267 int cpu,
268 u64 timestamp __used,
269 struct thread *thread __used)
270{
271 unsigned long ptr;
272 struct alloc_stat *s_alloc, *s_caller;
273
274 ptr = raw_field_value(event, "ptr", raw->data);
275
276 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
277 if (!s_alloc)
278 return;
279
280 if (cpu != s_alloc->alloc_cpu) {
281 s_alloc->pingpong++;
282
283 s_caller = search_alloc_stat(0, s_alloc->call_site,
284 &root_caller_stat, callsite_cmp);
285 assert(s_caller);
286 s_caller->pingpong++;
287 }
288 s_alloc->alloc_cpu = -1;
289}
290
291static void
292process_raw_event(event_t *raw_event __used, void *more_data,
293 int cpu, u64 timestamp, struct thread *thread)
294{
295 struct raw_event_sample *raw = more_data;
296 struct event *event;
297 int type;
298
299 type = trace_parse_common_type(raw->data);
300 event = trace_find_event(type);
301
302 if (!strcmp(event->name, "kmalloc") ||
303 !strcmp(event->name, "kmem_cache_alloc")) {
304 process_alloc_event(raw, event, cpu, timestamp, thread, 0);
305 return;
306 }
307
308 if (!strcmp(event->name, "kmalloc_node") ||
309 !strcmp(event->name, "kmem_cache_alloc_node")) {
310 process_alloc_event(raw, event, cpu, timestamp, thread, 1);
311 return;
312 }
313
314 if (!strcmp(event->name, "kfree") ||
315 !strcmp(event->name, "kmem_cache_free")) {
316 process_free_event(raw, event, cpu, timestamp, thread);
317 return;
318 }
319}
320
321static int process_sample_event(event_t *event)
322{
323 u64 ip = event->ip.ip;
324 u64 timestamp = -1;
325 u32 cpu = -1;
326 u64 period = 1;
327 void *more_data = event->ip.__more_data;
328 struct thread *thread = threads__findnew(event->ip.pid);
329
330 if (sample_type & PERF_SAMPLE_TIME) {
331 timestamp = *(u64 *)more_data;
332 more_data += sizeof(u64);
333 }
334
335 if (sample_type & PERF_SAMPLE_CPU) {
336 cpu = *(u32 *)more_data;
337 more_data += sizeof(u32);
338 more_data += sizeof(u32); /* reserved */
339 }
340
341 if (sample_type & PERF_SAMPLE_PERIOD) {
342 period = *(u64 *)more_data;
343 more_data += sizeof(u64);
344 }
345
346 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
347 event->header.misc,
348 event->ip.pid, event->ip.tid,
349 (void *)(long)ip,
350 (long long)period);
351
352 if (thread == NULL) {
353 pr_debug("problem processing %d event, skipping it.\n",
354 event->header.type);
355 return -1;
356 }
357
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
359
360 process_raw_event(event, more_data, cpu, timestamp, thread);
361
362 return 0;
363}
364
365static int sample_type_check(u64 type)
366{
367 sample_type = type;
368
369 if (!(sample_type & PERF_SAMPLE_RAW)) {
370 fprintf(stderr,
371 "No trace sample to read. Did you call perf record "
372 "without -R?");
373 return -1;
374 }
375
376 return 0;
377}
378
379static struct perf_file_handler file_handler = {
380 .process_sample_event = process_sample_event,
381 .process_comm_event = event__process_comm,
382 .sample_type_check = sample_type_check,
383};
384
385static int read_events(void)
386{
387 register_idle_thread();
388 register_perf_file_handler(&file_handler);
389
390 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
391 &event__cwdlen, &event__cwd);
392}
393
394static double fragmentation(unsigned long n_req, unsigned long n_alloc)
395{
396 if (n_alloc == 0)
397 return 0.0;
398 else
399 return 100.0 - (100.0 * n_req / n_alloc);
400}
401
402static void __print_result(struct rb_root *root, int n_lines, int is_caller)
403{
404 struct rb_node *next;
405
406 printf("%.102s\n", graph_dotted_line);
407 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
408 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
409 printf("%.102s\n", graph_dotted_line);
410
411 next = rb_first(root);
412
413 while (next && n_lines--) {
414 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
415 node);
416 struct symbol *sym = NULL;
417 char buf[BUFSIZ];
418 u64 addr;
419
420 if (is_caller) {
421 addr = data->call_site;
422 if (!raw_ip)
423 sym = thread__find_function(kthread, addr, NULL);
424 } else
425 addr = data->ptr;
426
427 if (sym != NULL)
428 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
429 addr - sym->start);
430 else
431 snprintf(buf, sizeof(buf), "%#Lx", addr);
432 printf(" %-34s |", buf);
433
434 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
435 (unsigned long long)data->bytes_alloc,
436 (unsigned long)data->bytes_alloc / data->hit,
437 (unsigned long long)data->bytes_req,
438 (unsigned long)data->bytes_req / data->hit,
439 (unsigned long)data->hit,
440 (unsigned long)data->pingpong,
441 fragmentation(data->bytes_req, data->bytes_alloc));
442
443 next = rb_next(next);
444 }
445
446 if (n_lines == -1)
447 printf(" ... | ... | ... | ... | ... | ... \n");
448
449 printf("%.102s\n", graph_dotted_line);
450}
451
452static void print_summary(void)
453{
454 printf("\nSUMMARY\n=======\n");
455 printf("Total bytes requested: %lu\n", total_requested);
456 printf("Total bytes allocated: %lu\n", total_allocated);
457 printf("Total bytes wasted on internal fragmentation: %lu\n",
458 total_allocated - total_requested);
459 printf("Internal fragmentation: %f%%\n",
460 fragmentation(total_requested, total_allocated));
461 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
462}
463
464static void print_result(void)
465{
466 if (caller_flag)
467 __print_result(&root_caller_sorted, caller_lines, 1);
468 if (alloc_flag)
469 __print_result(&root_alloc_sorted, alloc_lines, 0);
470 print_summary();
471}
472
473struct sort_dimension {
474 const char name[20];
475 sort_fn_t cmp;
476 struct list_head list;
477};
478
479static LIST_HEAD(caller_sort);
480static LIST_HEAD(alloc_sort);
481
482static void sort_insert(struct rb_root *root, struct alloc_stat *data,
483 struct list_head *sort_list)
484{
485 struct rb_node **new = &(root->rb_node);
486 struct rb_node *parent = NULL;
487 struct sort_dimension *sort;
488
489 while (*new) {
490 struct alloc_stat *this;
491 int cmp = 0;
492
493 this = rb_entry(*new, struct alloc_stat, node);
494 parent = *new;
495
496 list_for_each_entry(sort, sort_list, list) {
497 cmp = sort->cmp(data, this);
498 if (cmp)
499 break;
500 }
501
502 if (cmp > 0)
503 new = &((*new)->rb_left);
504 else
505 new = &((*new)->rb_right);
506 }
507
508 rb_link_node(&data->node, parent, new);
509 rb_insert_color(&data->node, root);
510}
511
512static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
513 struct list_head *sort_list)
514{
515 struct rb_node *node;
516 struct alloc_stat *data;
517
518 for (;;) {
519 node = rb_first(root);
520 if (!node)
521 break;
522
523 rb_erase(node, root);
524 data = rb_entry(node, struct alloc_stat, node);
525 sort_insert(root_sorted, data, sort_list);
526 }
527}
528
529static void sort_result(void)
530{
531 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
532 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
533}
534
535static int __cmd_kmem(void)
536{
537 setup_pager();
538 read_events();
539 sort_result();
540 print_result();
541
542 return 0;
543}
544
545static const char * const kmem_usage[] = {
546 "perf kmem [<options>] {record}",
547 NULL
548};
549
550static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
551{
552 if (l->ptr < r->ptr)
553 return -1;
554 else if (l->ptr > r->ptr)
555 return 1;
556 return 0;
557}
558
559static struct sort_dimension ptr_sort_dimension = {
560 .name = "ptr",
561 .cmp = ptr_cmp,
562};
563
564static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
565{
566 if (l->call_site < r->call_site)
567 return -1;
568 else if (l->call_site > r->call_site)
569 return 1;
570 return 0;
571}
572
573static struct sort_dimension callsite_sort_dimension = {
574 .name = "callsite",
575 .cmp = callsite_cmp,
576};
577
578static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
579{
580 if (l->hit < r->hit)
581 return -1;
582 else if (l->hit > r->hit)
583 return 1;
584 return 0;
585}
586
587static struct sort_dimension hit_sort_dimension = {
588 .name = "hit",
589 .cmp = hit_cmp,
590};
591
592static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
593{
594 if (l->bytes_alloc < r->bytes_alloc)
595 return -1;
596 else if (l->bytes_alloc > r->bytes_alloc)
597 return 1;
598 return 0;
599}
600
601static struct sort_dimension bytes_sort_dimension = {
602 .name = "bytes",
603 .cmp = bytes_cmp,
604};
605
606static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
607{
608 double x, y;
609
610 x = fragmentation(l->bytes_req, l->bytes_alloc);
611 y = fragmentation(r->bytes_req, r->bytes_alloc);
612
613 if (x < y)
614 return -1;
615 else if (x > y)
616 return 1;
617 return 0;
618}
619
620static struct sort_dimension frag_sort_dimension = {
621 .name = "frag",
622 .cmp = frag_cmp,
623};
624
625static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
626{
627 if (l->pingpong < r->pingpong)
628 return -1;
629 else if (l->pingpong > r->pingpong)
630 return 1;
631 return 0;
632}
633
634static struct sort_dimension pingpong_sort_dimension = {
635 .name = "pingpong",
636 .cmp = pingpong_cmp,
637};
638
639static struct sort_dimension *avail_sorts[] = {
640 &ptr_sort_dimension,
641 &callsite_sort_dimension,
642 &hit_sort_dimension,
643 &bytes_sort_dimension,
644 &frag_sort_dimension,
645 &pingpong_sort_dimension,
646};
647
648#define NUM_AVAIL_SORTS \
649 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
650
651static int sort_dimension__add(const char *tok, struct list_head *list)
652{
653 struct sort_dimension *sort;
654 int i;
655
656 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
657 if (!strcmp(avail_sorts[i]->name, tok)) {
658 sort = malloc(sizeof(*sort));
659 if (!sort)
660 die("malloc");
661 memcpy(sort, avail_sorts[i], sizeof(*sort));
662 list_add_tail(&sort->list, list);
663 return 0;
664 }
665 }
666
667 return -1;
668}
669
670static int setup_sorting(struct list_head *sort_list, const char *arg)
671{
672 char *tok;
673 char *str = strdup(arg);
674
675 if (!str)
676 die("strdup");
677
678 while (true) {
679 tok = strsep(&str, ",");
680 if (!tok)
681 break;
682 if (sort_dimension__add(tok, sort_list) < 0) {
683 error("Unknown --sort key: '%s'", tok);
684 return -1;
685 }
686 }
687
688 free(str);
689 return 0;
690}
691
692static int parse_sort_opt(const struct option *opt __used,
693 const char *arg, int unset __used)
694{
695 if (!arg)
696 return -1;
697
698 if (caller_flag > alloc_flag)
699 return setup_sorting(&caller_sort, arg);
700 else
701 return setup_sorting(&alloc_sort, arg);
702
703 return 0;
704}
705
706static int parse_stat_opt(const struct option *opt __used,
707 const char *arg, int unset __used)
708{
709 if (!arg)
710 return -1;
711
712 if (strcmp(arg, "alloc") == 0)
713 alloc_flag = (caller_flag + 1);
714 else if (strcmp(arg, "caller") == 0)
715 caller_flag = (alloc_flag + 1);
716 else
717 return -1;
718 return 0;
719}
720
721static int parse_line_opt(const struct option *opt __used,
722 const char *arg, int unset __used)
723{
724 int lines;
725
726 if (!arg)
727 return -1;
728
729 lines = strtoul(arg, NULL, 10);
730
731 if (caller_flag > alloc_flag)
732 caller_lines = lines;
733 else
734 alloc_lines = lines;
735
736 return 0;
737}
738
739static const struct option kmem_options[] = {
740 OPT_STRING('i', "input", &input_name, "file",
741 "input file name"),
742 OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>",
743 "stat selector, Pass 'alloc' or 'caller'.",
744 parse_stat_opt),
745 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
746 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
747 parse_sort_opt),
748 OPT_CALLBACK('l', "line", NULL, "num",
749 "show n lins",
750 parse_line_opt),
751 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
752 OPT_END()
753};
754
755static const char *record_args[] = {
756 "record",
757 "-a",
758 "-R",
759 "-M",
760 "-f",
761 "-c", "1",
762 "-e", "kmem:kmalloc",
763 "-e", "kmem:kmalloc_node",
764 "-e", "kmem:kfree",
765 "-e", "kmem:kmem_cache_alloc",
766 "-e", "kmem:kmem_cache_alloc_node",
767 "-e", "kmem:kmem_cache_free",
768};
769
770static int __cmd_record(int argc, const char **argv)
771{
772 unsigned int rec_argc, i, j;
773 const char **rec_argv;
774
775 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
776 rec_argv = calloc(rec_argc + 1, sizeof(char *));
777
778 for (i = 0; i < ARRAY_SIZE(record_args); i++)
779 rec_argv[i] = strdup(record_args[i]);
780
781 for (j = 1; j < (unsigned int)argc; j++, i++)
782 rec_argv[i] = argv[j];
783
784 return cmd_record(i, rec_argv, NULL);
785}
786
787int cmd_kmem(int argc, const char **argv, const char *prefix __used)
788{
789 symbol__init(0);
790
791 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
792
793 if (argc && !strncmp(argv[0], "rec", 3))
794 return __cmd_record(argc, argv);
795 else if (argc)
796 usage_with_options(kmem_usage, kmem_options);
797
798 if (list_empty(&caller_sort))
799 setup_sorting(&caller_sort, default_sort_order);
800 if (list_empty(&alloc_sort))
801 setup_sorting(&alloc_sort, default_sort_order);
802
803 setup_cpunode_map();
804
805 return __cmd_kmem();
806}
807
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644
index 000000000000..a58e11b7ea80
--- /dev/null
+++ b/tools/perf/builtin-probe.c
@@ -0,0 +1,242 @@
1/*
2 * builtin-probe.c
3 *
4 * Builtin probe command: Set up probe events by C expression
5 *
6 * Written by Masami Hiramatsu <mhiramat@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 */
23#define _GNU_SOURCE
24#include <sys/utsname.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#undef _GNU_SOURCE
35#include "perf.h"
36#include "builtin.h"
37#include "util/util.h"
38#include "util/event.h"
39#include "util/debug.h"
40#include "util/parse-options.h"
41#include "util/parse-events.h" /* For debugfs_path */
42#include "util/probe-finder.h"
43#include "util/probe-event.h"
44
45/* Default vmlinux search paths */
46#define NR_SEARCH_PATH 3
47const char *default_search_path[NR_SEARCH_PATH] = {
48"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
49"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
50"/boot/vmlinux-debug-%s", /* Ubuntu */
51};
52
53#define MAX_PATH_LEN 256
54#define MAX_PROBES 128
55
56/* Session management structure */
57static struct {
58 char *vmlinux;
59 char *release;
60 int need_dwarf;
61 int nr_probe;
62 struct probe_point probes[MAX_PROBES];
63} session;
64
65static bool listing;
66
67/* Parse an event definition. Note that any error must die. */
68static void parse_probe_event(const char *str)
69{
70 struct probe_point *pp = &session.probes[session.nr_probe];
71
72 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
73 if (++session.nr_probe == MAX_PROBES)
74 die("Too many probes (> %d) are specified.", MAX_PROBES);
75
76 /* Parse perf-probe event into probe_point */
77 session.need_dwarf = parse_perf_probe_event(str, pp);
78
79 pr_debug("%d arguments\n", pp->nr_args);
80}
81
82static int opt_add_probe_event(const struct option *opt __used,
83 const char *str, int unset __used)
84{
85 if (str)
86 parse_probe_event(str);
87 return 0;
88}
89
90#ifndef NO_LIBDWARF
91static int open_default_vmlinux(void)
92{
93 struct utsname uts;
94 char fname[MAX_PATH_LEN];
95 int fd, ret, i;
96
97 ret = uname(&uts);
98 if (ret) {
99 pr_debug("uname() failed.\n");
100 return -errno;
101 }
102 session.release = uts.release;
103 for (i = 0; i < NR_SEARCH_PATH; i++) {
104 ret = snprintf(fname, MAX_PATH_LEN,
105 default_search_path[i], session.release);
106 if (ret >= MAX_PATH_LEN || ret < 0) {
107 pr_debug("Filename(%d,%s) is too long.\n", i,
108 uts.release);
109 errno = E2BIG;
110 return -E2BIG;
111 }
112 pr_debug("try to open %s\n", fname);
113 fd = open(fname, O_RDONLY);
114 if (fd >= 0)
115 break;
116 }
117 return fd;
118}
119#endif
120
121static const char * const probe_usage[] = {
122 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
123 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
124 "perf probe --list",
125 NULL
126};
127
128static const struct option options[] = {
129 OPT_BOOLEAN('v', "verbose", &verbose,
130 "be more verbose (show parsed arguments, etc)"),
131#ifndef NO_LIBDWARF
132 OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
133 "vmlinux/module pathname"),
134#endif
135 OPT_BOOLEAN('l', "list", &listing, "list up current probes"),
136 OPT_CALLBACK('a', "add", NULL,
137#ifdef NO_LIBDWARF
138 "FUNC[+OFFS|%return] [ARG ...]",
139#else
140 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
141#endif
142 "probe point definition, where\n"
143 "\t\tGRP:\tGroup name (optional)\n"
144 "\t\tNAME:\tEvent name\n"
145 "\t\tFUNC:\tFunction name\n"
146 "\t\tOFFS:\tOffset from function entry (in byte)\n"
147 "\t\t%return:\tPut the probe at function return\n"
148#ifdef NO_LIBDWARF
149 "\t\tARG:\tProbe argument (only \n"
150#else
151 "\t\tSRC:\tSource code path\n"
152 "\t\tRLN:\tRelative line number from function entry.\n"
153 "\t\tALN:\tAbsolute line number in file.\n"
154 "\t\tARG:\tProbe argument (local variable name or\n"
155#endif
156 "\t\t\tkprobe-tracer argument format.)\n",
157 opt_add_probe_event),
158 OPT_END()
159};
160
161int cmd_probe(int argc, const char **argv, const char *prefix __used)
162{
163 int i, j, ret;
164#ifndef NO_LIBDWARF
165 int fd;
166#endif
167 struct probe_point *pp;
168
169 argc = parse_options(argc, argv, options, probe_usage,
170 PARSE_OPT_STOP_AT_NON_OPTION);
171 for (i = 0; i < argc; i++)
172 parse_probe_event(argv[i]);
173
174 if ((session.nr_probe == 0 && !listing) ||
175 (session.nr_probe != 0 && listing))
176 usage_with_options(probe_usage, options);
177
178 if (listing) {
179 show_perf_probe_events();
180 return 0;
181 }
182
183 if (session.need_dwarf)
184#ifdef NO_LIBDWARF
185 die("Debuginfo-analysis is not supported");
186#else /* !NO_LIBDWARF */
187 pr_debug("Some probes require debuginfo.\n");
188
189 if (session.vmlinux)
190 fd = open(session.vmlinux, O_RDONLY);
191 else
192 fd = open_default_vmlinux();
193 if (fd < 0) {
194 if (session.need_dwarf)
195 die("Could not open vmlinux/module file.");
196
197 pr_warning("Could not open vmlinux/module file."
198 " Try to use symbols.\n");
199 goto end_dwarf;
200 }
201
202 /* Searching probe points */
203 for (j = 0; j < session.nr_probe; j++) {
204 pp = &session.probes[j];
205 if (pp->found)
206 continue;
207
208 lseek(fd, SEEK_SET, 0);
209 ret = find_probepoint(fd, pp);
210 if (ret < 0) {
211 if (session.need_dwarf)
212 die("Could not analyze debuginfo.");
213
214 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n");
215 break;
216 }
217 if (ret == 0) /* No error but failed to find probe point. */
218 die("No probe point found.");
219 }
220 close(fd);
221
222end_dwarf:
223#endif /* !NO_LIBDWARF */
224
225 /* Synthesize probes without dwarf */
226 for (j = 0; j < session.nr_probe; j++) {
227 pp = &session.probes[j];
228 if (pp->found) /* This probe is already found. */
229 continue;
230
231 ret = synthesize_trace_kprobe_event(pp);
232 if (ret == -E2BIG)
233 die("probe point definition becomes too long.");
234 else if (ret < 0)
235 die("Failed to synthesize a probe point.");
236 }
237
238 /* Settng up probe points */
239 add_trace_kprobe_events(session.probes, session.nr_probe);
240 return 0;
241}
242
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4e3a374e7aa7..0e519c667e3a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,13 +17,11 @@
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h" 18#include "util/event.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/symbol.h"
20 21
21#include <unistd.h> 22#include <unistd.h>
22#include <sched.h> 23#include <sched.h>
23 24
24#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
25#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
26
27static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 25static int fd[MAX_NR_CPUS][MAX_COUNTERS];
28 26
29static long default_interval = 0; 27static long default_interval = 0;
@@ -112,6 +110,24 @@ static void write_output(void *buf, size_t size)
112 } 110 }
113} 111}
114 112
113static void write_event(event_t *buf, size_t size)
114{
115 /*
116 * Add it to the list of DSOs, so that when we finish this
117 * record session we can pick the available build-ids.
118 */
119 if (buf->header.type == PERF_RECORD_MMAP)
120 dsos__findnew(buf->mmap.filename);
121
122 write_output(buf, size);
123}
124
125static int process_synthesized_event(event_t *event)
126{
127 write_event(event, event->header.size);
128 return 0;
129}
130
115static void mmap_read(struct mmap_data *md) 131static void mmap_read(struct mmap_data *md)
116{ 132{
117 unsigned int head = mmap_read_head(md); 133 unsigned int head = mmap_read_head(md);
@@ -160,14 +176,14 @@ static void mmap_read(struct mmap_data *md)
160 size = md->mask + 1 - (old & md->mask); 176 size = md->mask + 1 - (old & md->mask);
161 old += size; 177 old += size;
162 178
163 write_output(buf, size); 179 write_event(buf, size);
164 } 180 }
165 181
166 buf = &data[old & md->mask]; 182 buf = &data[old & md->mask];
167 size = head - old; 183 size = head - old;
168 old += size; 184 old += size;
169 185
170 write_output(buf, size); 186 write_event(buf, size);
171 187
172 md->prev = old; 188 md->prev = old;
173 mmap_write_tail(md, old); 189 mmap_write_tail(md, old);
@@ -194,168 +210,6 @@ static void sig_atexit(void)
194 kill(getpid(), signr); 210 kill(getpid(), signr);
195} 211}
196 212
197static pid_t pid_synthesize_comm_event(pid_t pid, int full)
198{
199 struct comm_event comm_ev;
200 char filename[PATH_MAX];
201 char bf[BUFSIZ];
202 FILE *fp;
203 size_t size = 0;
204 DIR *tasks;
205 struct dirent dirent, *next;
206 pid_t tgid = 0;
207
208 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
209
210 fp = fopen(filename, "r");
211 if (fp == NULL) {
212 /*
213 * We raced with a task exiting - just return:
214 */
215 if (verbose)
216 fprintf(stderr, "couldn't open %s\n", filename);
217 return 0;
218 }
219
220 memset(&comm_ev, 0, sizeof(comm_ev));
221 while (!comm_ev.comm[0] || !comm_ev.pid) {
222 if (fgets(bf, sizeof(bf), fp) == NULL)
223 goto out_failure;
224
225 if (memcmp(bf, "Name:", 5) == 0) {
226 char *name = bf + 5;
227 while (*name && isspace(*name))
228 ++name;
229 size = strlen(name) - 1;
230 memcpy(comm_ev.comm, name, size++);
231 } else if (memcmp(bf, "Tgid:", 5) == 0) {
232 char *tgids = bf + 5;
233 while (*tgids && isspace(*tgids))
234 ++tgids;
235 tgid = comm_ev.pid = atoi(tgids);
236 }
237 }
238
239 comm_ev.header.type = PERF_RECORD_COMM;
240 size = ALIGN(size, sizeof(u64));
241 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
242
243 if (!full) {
244 comm_ev.tid = pid;
245
246 write_output(&comm_ev, comm_ev.header.size);
247 goto out_fclose;
248 }
249
250 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
251
252 tasks = opendir(filename);
253 while (!readdir_r(tasks, &dirent, &next) && next) {
254 char *end;
255 pid = strtol(dirent.d_name, &end, 10);
256 if (*end)
257 continue;
258
259 comm_ev.tid = pid;
260
261 write_output(&comm_ev, comm_ev.header.size);
262 }
263 closedir(tasks);
264
265out_fclose:
266 fclose(fp);
267 return tgid;
268
269out_failure:
270 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
271 filename);
272 exit(EXIT_FAILURE);
273}
274
275static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
276{
277 char filename[PATH_MAX];
278 FILE *fp;
279
280 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
281
282 fp = fopen(filename, "r");
283 if (fp == NULL) {
284 /*
285 * We raced with a task exiting - just return:
286 */
287 if (verbose)
288 fprintf(stderr, "couldn't open %s\n", filename);
289 return;
290 }
291 while (1) {
292 char bf[BUFSIZ], *pbf = bf;
293 struct mmap_event mmap_ev = {
294 .header = { .type = PERF_RECORD_MMAP },
295 };
296 int n;
297 size_t size;
298 if (fgets(bf, sizeof(bf), fp) == NULL)
299 break;
300
301 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
302 n = hex2u64(pbf, &mmap_ev.start);
303 if (n < 0)
304 continue;
305 pbf += n + 1;
306 n = hex2u64(pbf, &mmap_ev.len);
307 if (n < 0)
308 continue;
309 pbf += n + 3;
310 if (*pbf == 'x') { /* vm_exec */
311 char *execname = strchr(bf, '/');
312
313 /* Catch VDSO */
314 if (execname == NULL)
315 execname = strstr(bf, "[vdso]");
316
317 if (execname == NULL)
318 continue;
319
320 size = strlen(execname);
321 execname[size - 1] = '\0'; /* Remove \n */
322 memcpy(mmap_ev.filename, execname, size);
323 size = ALIGN(size, sizeof(u64));
324 mmap_ev.len -= mmap_ev.start;
325 mmap_ev.header.size = (sizeof(mmap_ev) -
326 (sizeof(mmap_ev.filename) - size));
327 mmap_ev.pid = tgid;
328 mmap_ev.tid = pid;
329
330 write_output(&mmap_ev, mmap_ev.header.size);
331 }
332 }
333
334 fclose(fp);
335}
336
337static void synthesize_all(void)
338{
339 DIR *proc;
340 struct dirent dirent, *next;
341
342 proc = opendir("/proc");
343
344 while (!readdir_r(proc, &dirent, &next) && next) {
345 char *end;
346 pid_t pid, tgid;
347
348 pid = strtol(dirent.d_name, &end, 10);
349 if (*end) /* only interested in proper numerical dirents */
350 continue;
351
352 tgid = pid_synthesize_comm_event(pid, 1);
353 pid_synthesize_mmap_samples(pid, tgid);
354 }
355
356 closedir(proc);
357}
358
359static int group_fd; 213static int group_fd;
360 214
361static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 215static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -366,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
366 h_attr = header->attr[nr]; 220 h_attr = header->attr[nr];
367 } else { 221 } else {
368 h_attr = perf_header_attr__new(a); 222 h_attr = perf_header_attr__new(a);
369 perf_header__add_attr(header, h_attr); 223 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr);
226 h_attr = NULL;
227 }
370 } 228 }
371 229
372 return h_attr; 230 return h_attr;
@@ -374,9 +232,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
374 232
375static void create_counter(int counter, int cpu, pid_t pid) 233static void create_counter(int counter, int cpu, pid_t pid)
376{ 234{
235 char *filter = filters[counter];
377 struct perf_event_attr *attr = attrs + counter; 236 struct perf_event_attr *attr = attrs + counter;
378 struct perf_header_attr *h_attr; 237 struct perf_header_attr *h_attr;
379 int track = !counter; /* only the first counter needs these */ 238 int track = !counter; /* only the first counter needs these */
239 int ret;
380 struct { 240 struct {
381 u64 count; 241 u64 count;
382 u64 time_enabled; 242 u64 time_enabled;
@@ -425,7 +285,7 @@ try_again:
425 if (fd[nr_cpu][counter] < 0) { 285 if (fd[nr_cpu][counter] < 0) {
426 int err = errno; 286 int err = errno;
427 287
428 if (err == EPERM) 288 if (err == EPERM || err == EACCES)
429 die("Permission error - are you root?\n"); 289 die("Permission error - are you root?\n");
430 else if (err == ENODEV && profile_cpu != -1) 290 else if (err == ENODEV && profile_cpu != -1)
431 die("No such device - did you specify an out-of-range profile CPU?\n"); 291 die("No such device - did you specify an out-of-range profile CPU?\n");
@@ -447,11 +307,19 @@ try_again:
447 printf("\n"); 307 printf("\n");
448 error("perfcounter syscall returned with %d (%s)\n", 308 error("perfcounter syscall returned with %d (%s)\n",
449 fd[nr_cpu][counter], strerror(err)); 309 fd[nr_cpu][counter], strerror(err));
310
311#if defined(__i386__) || defined(__x86_64__)
312 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
313 die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n");
314#endif
315
450 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 316 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
451 exit(-1); 317 exit(-1);
452 } 318 }
453 319
454 h_attr = get_header_attr(attr, counter); 320 h_attr = get_header_attr(attr, counter);
321 if (h_attr == NULL)
322 die("nomem\n");
455 323
456 if (!file_new) { 324 if (!file_new) {
457 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 325 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -465,7 +333,10 @@ try_again:
465 exit(-1); 333 exit(-1);
466 } 334 }
467 335
468 perf_header_attr__add_id(h_attr, read_data.id); 336 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
337 pr_warning("Not enough memory to add id\n");
338 exit(-1);
339 }
469 340
470 assert(fd[nr_cpu][counter] >= 0); 341 assert(fd[nr_cpu][counter] >= 0);
471 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 342 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -479,7 +350,6 @@ try_again:
479 multiplex_fd = fd[nr_cpu][counter]; 350 multiplex_fd = fd[nr_cpu][counter];
480 351
481 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 352 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
482 int ret;
483 353
484 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 354 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
485 assert(ret != -1); 355 assert(ret != -1);
@@ -499,6 +369,16 @@ try_again:
499 } 369 }
500 } 370 }
501 371
372 if (filter != NULL) {
373 ret = ioctl(fd[nr_cpu][counter],
374 PERF_EVENT_IOC_SET_FILTER, filter);
375 if (ret) {
376 error("failed to set filter with %d (%s)\n", errno,
377 strerror(errno));
378 exit(-1);
379 }
380 }
381
502 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 382 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
503} 383}
504 384
@@ -517,7 +397,7 @@ static void atexit_header(void)
517{ 397{
518 header->data_size += bytes_written; 398 header->data_size += bytes_written;
519 399
520 perf_header__write(header, output); 400 perf_header__write(header, output, true);
521} 401}
522 402
523static int __cmd_record(int argc, const char **argv) 403static int __cmd_record(int argc, const char **argv)
@@ -526,7 +406,7 @@ static int __cmd_record(int argc, const char **argv)
526 struct stat st; 406 struct stat st;
527 pid_t pid = 0; 407 pid_t pid = 0;
528 int flags; 408 int flags;
529 int ret; 409 int err;
530 unsigned long waking = 0; 410 unsigned long waking = 0;
531 411
532 page_size = sysconf(_SC_PAGE_SIZE); 412 page_size = sysconf(_SC_PAGE_SIZE);
@@ -560,17 +440,24 @@ static int __cmd_record(int argc, const char **argv)
560 exit(-1); 440 exit(-1);
561 } 441 }
562 442
563 if (!file_new) 443 header = perf_header__new();
564 header = perf_header__read(output); 444 if (header == NULL) {
565 else 445 pr_err("Not enough memory for reading perf file header\n");
566 header = perf_header__new(); 446 return -1;
447 }
448
449 if (!file_new) {
450 err = perf_header__read(header, output);
451 if (err < 0)
452 return err;
453 }
567 454
568 if (raw_samples) { 455 if (raw_samples) {
569 perf_header__set_trace_info(); 456 perf_header__set_feat(header, HEADER_TRACE_INFO);
570 } else { 457 } else {
571 for (i = 0; i < nr_counters; i++) { 458 for (i = 0; i < nr_counters; i++) {
572 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
573 perf_header__set_trace_info(); 460 perf_header__set_feat(header, HEADER_TRACE_INFO);
574 break; 461 break;
575 } 462 }
576 } 463 }
@@ -593,25 +480,36 @@ static int __cmd_record(int argc, const char **argv)
593 } 480 }
594 } 481 }
595 482
596 if (file_new) 483 if (file_new) {
597 perf_header__write(header, output); 484 err = perf_header__write(header, output, false);
485 if (err < 0)
486 return err;
487 }
598 488
599 if (!system_wide) { 489 if (!system_wide)
600 pid_t tgid = pid_synthesize_comm_event(pid, 0); 490 event__synthesize_thread(pid, process_synthesized_event);
601 pid_synthesize_mmap_samples(pid, tgid); 491 else
602 } else 492 event__synthesize_threads(process_synthesized_event);
603 synthesize_all();
604 493
605 if (target_pid == -1 && argc) { 494 if (target_pid == -1 && argc) {
606 pid = fork(); 495 pid = fork();
607 if (pid < 0) 496 if (pid < 0)
608 perror("failed to fork"); 497 die("failed to fork");
609 498
610 if (!pid) { 499 if (!pid) {
611 if (execvp(argv[0], (char **)argv)) { 500 if (execvp(argv[0], (char **)argv)) {
612 perror(argv[0]); 501 perror(argv[0]);
613 exit(-1); 502 exit(-1);
614 } 503 }
504 } else {
505 /*
506 * Wait a bit for the execv'ed child to appear
507 * and be updated in /proc
508 * FIXME: Do you know a less heuristical solution?
509 */
510 usleep(1000);
511 event__synthesize_thread(pid,
512 process_synthesized_event);
615 } 513 }
616 514
617 child_pid = pid; 515 child_pid = pid;
@@ -622,7 +520,7 @@ static int __cmd_record(int argc, const char **argv)
622 520
623 param.sched_priority = realtime_prio; 521 param.sched_priority = realtime_prio;
624 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 522 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
625 printf("Could not set realtime priority.\n"); 523 pr_err("Could not set realtime priority.\n");
626 exit(-1); 524 exit(-1);
627 } 525 }
628 } 526 }
@@ -640,7 +538,7 @@ static int __cmd_record(int argc, const char **argv)
640 if (hits == samples) { 538 if (hits == samples) {
641 if (done) 539 if (done)
642 break; 540 break;
643 ret = poll(event_array, nr_poll, -1); 541 err = poll(event_array, nr_poll, -1);
644 waking++; 542 waking++;
645 } 543 }
646 544
@@ -676,6 +574,8 @@ static const struct option options[] = {
676 OPT_CALLBACK('e', "event", NULL, "event", 574 OPT_CALLBACK('e', "event", NULL, "event",
677 "event selector. use 'perf list' to list available events", 575 "event selector. use 'perf list' to list available events",
678 parse_events), 576 parse_events),
577 OPT_CALLBACK(0, "filter", NULL, "filter",
578 "event filter", parse_filter),
679 OPT_INTEGER('p', "pid", &target_pid, 579 OPT_INTEGER('p', "pid", &target_pid,
680 "record events on existing pid"), 580 "record events on existing pid"),
681 OPT_INTEGER('r', "realtime", &realtime_prio, 581 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -719,6 +619,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
719{ 619{
720 int counter; 620 int counter;
721 621
622 symbol__init(0);
623
722 argc = parse_options(argc, argv, options, record_usage, 624 argc = parse_options(argc, argv, options, record_usage,
723 PARSE_OPT_STOP_AT_NON_OPTION); 625 PARSE_OPT_STOP_AT_NON_OPTION);
724 if (!argc && target_pid == -1 && !system_wide) 626 if (!argc && target_pid == -1 && !system_wide)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f57a23b19f3c..383c4ab4f9af 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -52,22 +52,34 @@ static int exclude_other = 1;
52 52
53static char callchain_default_opt[] = "fractal,0.5"; 53static char callchain_default_opt[] = "fractal,0.5";
54 54
55static char *cwd;
56static int cwdlen;
57
58static struct rb_root threads;
59static struct thread *last_match;
60
61static struct perf_header *header; 55static struct perf_header *header;
62 56
63static u64 sample_type; 57static u64 sample_type;
64 58
65static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask) 59struct symbol_conf symbol_conf;
60
61
62static size_t
63callchain__fprintf_left_margin(FILE *fp, int left_margin)
64{
65 int i;
66 int ret;
67
68 ret = fprintf(fp, " ");
69
70 for (i = 0; i < left_margin; i++)
71 ret += fprintf(fp, " ");
72
73 return ret;
74}
75
76static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
77 int left_margin)
66{ 78{
67 int i; 79 int i;
68 size_t ret = 0; 80 size_t ret = 0;
69 81
70 ret += fprintf(fp, "%s", " "); 82 ret += callchain__fprintf_left_margin(fp, left_margin);
71 83
72 for (i = 0; i < depth; i++) 84 for (i = 0; i < depth; i++)
73 if (depth_mask & (1 << i)) 85 if (depth_mask & (1 << i))
@@ -82,12 +94,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
82static size_t 94static size_t
83ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, 95ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
84 int depth_mask, int count, u64 total_samples, 96 int depth_mask, int count, u64 total_samples,
85 int hits) 97 int hits, int left_margin)
86{ 98{
87 int i; 99 int i;
88 size_t ret = 0; 100 size_t ret = 0;
89 101
90 ret += fprintf(fp, "%s", " "); 102 ret += callchain__fprintf_left_margin(fp, left_margin);
91 for (i = 0; i < depth; i++) { 103 for (i = 0; i < depth; i++) {
92 if (depth_mask & (1 << i)) 104 if (depth_mask & (1 << i))
93 ret += fprintf(fp, "|"); 105 ret += fprintf(fp, "|");
@@ -125,8 +137,9 @@ static void init_rem_hits(void)
125} 137}
126 138
127static size_t 139static size_t
128callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 140__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
129 u64 total_samples, int depth, int depth_mask) 141 u64 total_samples, int depth, int depth_mask,
142 int left_margin)
130{ 143{
131 struct rb_node *node, *next; 144 struct rb_node *node, *next;
132 struct callchain_node *child; 145 struct callchain_node *child;
@@ -167,7 +180,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
167 * But we keep the older depth mask for the line seperator 180 * But we keep the older depth mask for the line seperator
168 * to keep the level link until we reach the last child 181 * to keep the level link until we reach the last child
169 */ 182 */
170 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask); 183 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
184 left_margin);
171 i = 0; 185 i = 0;
172 list_for_each_entry(chain, &child->val, list) { 186 list_for_each_entry(chain, &child->val, list) {
173 if (chain->ip >= PERF_CONTEXT_MAX) 187 if (chain->ip >= PERF_CONTEXT_MAX)
@@ -175,11 +189,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
175 ret += ipchain__fprintf_graph(fp, chain, depth, 189 ret += ipchain__fprintf_graph(fp, chain, depth,
176 new_depth_mask, i++, 190 new_depth_mask, i++,
177 new_total, 191 new_total,
178 cumul); 192 cumul,
193 left_margin);
179 } 194 }
180 ret += callchain__fprintf_graph(fp, child, new_total, 195 ret += __callchain__fprintf_graph(fp, child, new_total,
181 depth + 1, 196 depth + 1,
182 new_depth_mask | (1 << depth)); 197 new_depth_mask | (1 << depth),
198 left_margin);
183 node = next; 199 node = next;
184 } 200 }
185 201
@@ -193,12 +209,51 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
193 209
194 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 210 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
195 new_depth_mask, 0, new_total, 211 new_depth_mask, 0, new_total,
196 remaining); 212 remaining, left_margin);
197 } 213 }
198 214
199 return ret; 215 return ret;
200} 216}
201 217
218
219static size_t
220callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
221 u64 total_samples, int left_margin)
222{
223 struct callchain_list *chain;
224 bool printed = false;
225 int i = 0;
226 int ret = 0;
227
228 list_for_each_entry(chain, &self->val, list) {
229 if (chain->ip >= PERF_CONTEXT_MAX)
230 continue;
231
232 if (!i++ && sort__first_dimension == SORT_SYM)
233 continue;
234
235 if (!printed) {
236 ret += callchain__fprintf_left_margin(fp, left_margin);
237 ret += fprintf(fp, "|\n");
238 ret += callchain__fprintf_left_margin(fp, left_margin);
239 ret += fprintf(fp, "---");
240
241 left_margin += 3;
242 printed = true;
243 } else
244 ret += callchain__fprintf_left_margin(fp, left_margin);
245
246 if (chain->sym)
247 ret += fprintf(fp, " %s\n", chain->sym->name);
248 else
249 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
250 }
251
252 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
253
254 return ret;
255}
256
202static size_t 257static size_t
203callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 258callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
204 u64 total_samples) 259 u64 total_samples)
@@ -227,7 +282,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
227 282
228static size_t 283static size_t
229hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, 284hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
230 u64 total_samples) 285 u64 total_samples, int left_margin)
231{ 286{
232 struct rb_node *rb_node; 287 struct rb_node *rb_node;
233 struct callchain_node *chain; 288 struct callchain_node *chain;
@@ -247,8 +302,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
247 break; 302 break;
248 case CHAIN_GRAPH_ABS: /* Falldown */ 303 case CHAIN_GRAPH_ABS: /* Falldown */
249 case CHAIN_GRAPH_REL: 304 case CHAIN_GRAPH_REL:
250 ret += callchain__fprintf_graph(fp, chain, 305 ret += callchain__fprintf_graph(fp, chain, total_samples,
251 total_samples, 1, 1); 306 left_margin);
252 case CHAIN_NONE: 307 case CHAIN_NONE:
253 default: 308 default:
254 break; 309 break;
@@ -293,8 +348,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
293 348
294 ret += fprintf(fp, "\n"); 349 ret += fprintf(fp, "\n");
295 350
296 if (callchain) 351 if (callchain) {
297 hist_entry_callchain__fprintf(fp, self, total_samples); 352 int left_margin = 0;
353
354 if (sort__first_dimension == SORT_COMM) {
355 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
356 list);
357 left_margin = se->width ? *se->width : 0;
358 left_margin -= thread__comm_len(self->thread);
359 }
360
361 hist_entry_callchain__fprintf(fp, self, total_samples,
362 left_margin);
363 }
298 364
299 return ret; 365 return ret;
300} 366}
@@ -342,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
342 return 0; 408 return 0;
343} 409}
344 410
345
346static struct symbol *
347resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
348{
349 struct map *map = mapp ? *mapp : NULL;
350 u64 ip = *ipp;
351
352 if (map)
353 goto got_map;
354
355 if (!thread)
356 return NULL;
357
358 map = thread__find_map(thread, ip);
359 if (map != NULL) {
360 /*
361 * We have to do this here as we may have a dso
362 * with no symbol hit that has a name longer than
363 * the ones with symbols sampled.
364 */
365 if (!sort_dso.elide && !map->dso->slen_calculated)
366 dso__calc_col_width(map->dso);
367
368 if (mapp)
369 *mapp = map;
370got_map:
371 ip = map->map_ip(map, ip);
372 } else {
373 /*
374 * If this is outside of all known maps,
375 * and is a negative address, try to look it
376 * up in the kernel dso, as it might be a
377 * vsyscall or vdso (which executes in user-mode).
378 *
379 * XXX This is nasty, we should have a symbol list in
380 * the "[vdso]" dso, but for now lets use the old
381 * trick of looking in the whole kernel symbol list.
382 */
383 if ((long long)ip < 0)
384 return kernel_maps__find_symbol(ip, mapp);
385 }
386 dump_printf(" ...... dso: %s\n",
387 map ? map->dso->long_name : "<not found>");
388 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
389 *ipp = ip;
390
391 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
392}
393
394static int call__match(struct symbol *sym) 411static int call__match(struct symbol *sym)
395{ 412{
396 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 413 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -399,11 +416,11 @@ static int call__match(struct symbol *sym)
399 return 0; 416 return 0;
400} 417}
401 418
402static struct symbol **resolve_callchain(struct thread *thread, struct map *map, 419static struct symbol **resolve_callchain(struct thread *thread,
403 struct ip_callchain *chain, 420 struct ip_callchain *chain,
404 struct symbol **parent) 421 struct symbol **parent)
405{ 422{
406 u64 context = PERF_CONTEXT_MAX; 423 u8 cpumode = PERF_RECORD_MISC_USER;
407 struct symbol **syms = NULL; 424 struct symbol **syms = NULL;
408 unsigned int i; 425 unsigned int i;
409 426
@@ -417,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
417 434
418 for (i = 0; i < chain->nr; i++) { 435 for (i = 0; i < chain->nr; i++) {
419 u64 ip = chain->ips[i]; 436 u64 ip = chain->ips[i];
420 struct symbol *sym = NULL; 437 struct addr_location al;
421 438
422 if (ip >= PERF_CONTEXT_MAX) { 439 if (ip >= PERF_CONTEXT_MAX) {
423 context = ip; 440 switch (ip) {
441 case PERF_CONTEXT_HV:
442 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
443 case PERF_CONTEXT_KERNEL:
444 cpumode = PERF_RECORD_MISC_KERNEL; break;
445 case PERF_CONTEXT_USER:
446 cpumode = PERF_RECORD_MISC_USER; break;
447 default:
448 break;
449 }
424 continue; 450 continue;
425 } 451 }
426 452
427 switch (context) { 453 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
428 case PERF_CONTEXT_HV: 454 ip, &al, NULL);
429 break; 455 if (al.sym != NULL) {
430 case PERF_CONTEXT_KERNEL: 456 if (sort__has_parent && !*parent &&
431 sym = kernel_maps__find_symbol(ip, &map); 457 call__match(al.sym))
432 break; 458 *parent = al.sym;
433 default:
434 sym = resolve_symbol(thread, &map, &ip);
435 break;
436 }
437
438 if (sym) {
439 if (sort__has_parent && !*parent && call__match(sym))
440 *parent = sym;
441 if (!callchain) 459 if (!callchain)
442 break; 460 break;
443 syms[i] = sym; 461 syms[i] = al.sym;
444 } 462 }
445 } 463 }
446 464
@@ -451,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
451 * collect histogram counts 469 * collect histogram counts
452 */ 470 */
453 471
454static int 472static int hist_entry__add(struct addr_location *al,
455hist_entry__add(struct thread *thread, struct map *map, 473 struct ip_callchain *chain, u64 count)
456 struct symbol *sym, u64 ip, struct ip_callchain *chain,
457 char level, u64 count)
458{ 474{
459 struct symbol **syms = NULL, *parent = NULL; 475 struct symbol **syms = NULL, *parent = NULL;
460 bool hit; 476 bool hit;
461 struct hist_entry *he; 477 struct hist_entry *he;
462 478
463 if ((sort__has_parent || callchain) && chain) 479 if ((sort__has_parent || callchain) && chain)
464 syms = resolve_callchain(thread, map, chain, &parent); 480 syms = resolve_callchain(al->thread, chain, &parent);
465 481
466 he = __hist_entry__add(thread, map, sym, parent, 482 he = __hist_entry__add(al, parent, count, &hit);
467 ip, count, level, &hit);
468 if (he == NULL) 483 if (he == NULL)
469 return -ENOMEM; 484 return -ENOMEM;
470 485
@@ -588,29 +603,22 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
588 return 0; 603 return 0;
589} 604}
590 605
591static int 606static int process_sample_event(event_t *event)
592process_sample_event(event_t *event, unsigned long offset, unsigned long head)
593{ 607{
594 char level;
595 struct symbol *sym = NULL;
596 struct thread *thread;
597 u64 ip = event->ip.ip; 608 u64 ip = event->ip.ip;
598 u64 period = 1; 609 u64 period = 1;
599 struct map *map = NULL;
600 void *more_data = event->ip.__more_data; 610 void *more_data = event->ip.__more_data;
601 struct ip_callchain *chain = NULL; 611 struct ip_callchain *chain = NULL;
602 int cpumode; 612 int cpumode;
603 613 struct addr_location al;
604 thread = threads__findnew(event->ip.pid, &threads, &last_match); 614 struct thread *thread = threads__findnew(event->ip.pid);
605 615
606 if (sample_type & PERF_SAMPLE_PERIOD) { 616 if (sample_type & PERF_SAMPLE_PERIOD) {
607 period = *(u64 *)more_data; 617 period = *(u64 *)more_data;
608 more_data += sizeof(u64); 618 more_data += sizeof(u64);
609 } 619 }
610 620
611 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 621 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
612 (void *)(offset + head),
613 (void *)(long)(event->header.size),
614 event->header.misc, 622 event->header.misc,
615 event->ip.pid, event->ip.tid, 623 event->ip.pid, event->ip.tid,
616 (void *)(long)ip, 624 (void *)(long)ip,
@@ -624,7 +632,8 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
624 dump_printf("... chain: nr:%Lu\n", chain->nr); 632 dump_printf("... chain: nr:%Lu\n", chain->nr);
625 633
626 if (validate_chain(chain, event) < 0) { 634 if (validate_chain(chain, event) < 0) {
627 eprintf("call-chain problem with event, skipping it.\n"); 635 pr_debug("call-chain problem with event, "
636 "skipping it.\n");
628 return 0; 637 return 0;
629 } 638 }
630 639
@@ -634,156 +643,64 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
634 } 643 }
635 } 644 }
636 645
637 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
638
639 if (thread == NULL) { 646 if (thread == NULL) {
640 eprintf("problem processing %d event, skipping it.\n", 647 pr_debug("problem processing %d event, skipping it.\n",
641 event->header.type); 648 event->header.type);
642 return -1; 649 return -1;
643 } 650 }
644 651
652 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
653
645 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 654 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
646 return 0; 655 return 0;
647 656
648 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 657 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
649 658
650 if (cpumode == PERF_RECORD_MISC_KERNEL) { 659 thread__find_addr_location(thread, cpumode,
651 level = 'k'; 660 MAP__FUNCTION, ip, &al, NULL);
652 sym = kernel_maps__find_symbol(ip, &map); 661 /*
653 dump_printf(" ...... dso: %s\n", 662 * We have to do this here as we may have a dso with no symbol hit that
654 map ? map->dso->long_name : "<not found>"); 663 * has a name longer than the ones with symbols sampled.
655 } else if (cpumode == PERF_RECORD_MISC_USER) { 664 */
656 level = '.'; 665 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
657 sym = resolve_symbol(thread, &map, &ip); 666 dso__calc_col_width(al.map->dso);
658
659 } else {
660 level = 'H';
661 dump_printf(" ...... dso: [hypervisor]\n");
662 }
663 667
664 if (dso_list && 668 if (dso_list &&
665 (!map || !map->dso || 669 (!al.map || !al.map->dso ||
666 !(strlist__has_entry(dso_list, map->dso->short_name) || 670 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
667 (map->dso->short_name != map->dso->long_name && 671 (al.map->dso->short_name != al.map->dso->long_name &&
668 strlist__has_entry(dso_list, map->dso->long_name))))) 672 strlist__has_entry(dso_list, al.map->dso->long_name)))))
669 return 0; 673 return 0;
670 674
671 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) 675 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
672 return 0; 676 return 0;
673 677
674 if (hist_entry__add(thread, map, sym, ip, 678 if (hist_entry__add(&al, chain, period)) {
675 chain, level, period)) { 679 pr_debug("problem incrementing symbol count, skipping event\n");
676 eprintf("problem incrementing symbol count, skipping event\n");
677 return -1; 680 return -1;
678 } 681 }
679 682
680 total += period; 683 event__stats.total += period;
681
682 return 0;
683}
684
685static int
686process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
687{
688 struct thread *thread;
689 struct map *map = map__new(&event->mmap, cwd, cwdlen);
690
691 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
692
693 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
694 (void *)(offset + head),
695 (void *)(long)(event->header.size),
696 event->mmap.pid,
697 event->mmap.tid,
698 (void *)(long)event->mmap.start,
699 (void *)(long)event->mmap.len,
700 (void *)(long)event->mmap.pgoff,
701 event->mmap.filename);
702
703 if (thread == NULL || map == NULL) {
704 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
705 return 0;
706 }
707
708 thread__insert_map(thread, map);
709 total_mmap++;
710 684
711 return 0; 685 return 0;
712} 686}
713 687
714static int 688static int process_comm_event(event_t *event)
715process_comm_event(event_t *event, unsigned long offset, unsigned long head)
716{ 689{
717 struct thread *thread; 690 struct thread *thread = threads__findnew(event->comm.pid);
718
719 thread = threads__findnew(event->comm.pid, &threads, &last_match);
720 691
721 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 692 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
722 (void *)(offset + head),
723 (void *)(long)(event->header.size),
724 event->comm.comm, event->comm.pid);
725 693
726 if (thread == NULL || 694 if (thread == NULL ||
727 thread__set_comm_adjust(thread, event->comm.comm)) { 695 thread__set_comm_adjust(thread, event->comm.comm)) {
728 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 696 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
729 return -1; 697 return -1;
730 } 698 }
731 total_comm++;
732 699
733 return 0; 700 return 0;
734} 701}
735 702
736static int 703static int process_read_event(event_t *event)
737process_task_event(event_t *event, unsigned long offset, unsigned long head)
738{
739 struct thread *thread;
740 struct thread *parent;
741
742 thread = threads__findnew(event->fork.pid, &threads, &last_match);
743 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
744
745 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
746 (void *)(offset + head),
747 (void *)(long)(event->header.size),
748 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
749 event->fork.pid, event->fork.tid,
750 event->fork.ppid, event->fork.ptid);
751
752 /*
753 * A thread clone will have the same PID for both
754 * parent and child.
755 */
756 if (thread == parent)
757 return 0;
758
759 if (event->header.type == PERF_RECORD_EXIT)
760 return 0;
761
762 if (!thread || !parent || thread__fork(thread, parent)) {
763 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
764 return -1;
765 }
766 total_fork++;
767
768 return 0;
769}
770
771static int
772process_lost_event(event_t *event, unsigned long offset, unsigned long head)
773{
774 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
775 (void *)(offset + head),
776 (void *)(long)(event->header.size),
777 event->lost.id,
778 event->lost.lost);
779
780 total_lost += event->lost.lost;
781
782 return 0;
783}
784
785static int
786process_read_event(event_t *event, unsigned long offset, unsigned long head)
787{ 704{
788 struct perf_event_attr *attr; 705 struct perf_event_attr *attr;
789 706
@@ -799,14 +716,9 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
799 event->read.value); 716 event->read.value);
800 } 717 }
801 718
802 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", 719 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
803 (void *)(offset + head), 720 attr ? __event_name(attr->type, attr->config) : "FAIL",
804 (void *)(long)(event->header.size), 721 event->read.value);
805 event->read.pid,
806 event->read.tid,
807 attr ? __event_name(attr->type, attr->config)
808 : "FAIL",
809 event->read.value);
810 722
811 return 0; 723 return 0;
812} 724}
@@ -842,11 +754,11 @@ static int sample_type_check(u64 type)
842 754
843static struct perf_file_handler file_handler = { 755static struct perf_file_handler file_handler = {
844 .process_sample_event = process_sample_event, 756 .process_sample_event = process_sample_event,
845 .process_mmap_event = process_mmap_event, 757 .process_mmap_event = event__process_mmap,
846 .process_comm_event = process_comm_event, 758 .process_comm_event = process_comm_event,
847 .process_exit_event = process_task_event, 759 .process_exit_event = event__process_task,
848 .process_fork_event = process_task_event, 760 .process_fork_event = event__process_task,
849 .process_lost_event = process_lost_event, 761 .process_lost_event = event__process_lost,
850 .process_read_event = process_read_event, 762 .process_read_event = process_read_event,
851 .sample_type_check = sample_type_check, 763 .sample_type_check = sample_type_check,
852}; 764};
@@ -857,7 +769,7 @@ static int __cmd_report(void)
857 struct thread *idle; 769 struct thread *idle;
858 int ret; 770 int ret;
859 771
860 idle = register_idle_thread(&threads, &last_match); 772 idle = register_idle_thread();
861 thread__comm_adjust(idle); 773 thread__comm_adjust(idle);
862 774
863 if (show_threads) 775 if (show_threads)
@@ -865,30 +777,25 @@ static int __cmd_report(void)
865 777
866 register_perf_file_handler(&file_handler); 778 register_perf_file_handler(&file_handler);
867 779
868 ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths, 780 ret = mmap_dispatch_perf_file(&header, input_name, force,
869 &cwdlen, &cwd); 781 full_paths, &event__cwdlen, &event__cwd);
870 if (ret) 782 if (ret)
871 return ret; 783 return ret;
872 784
873 dump_printf(" IP events: %10ld\n", total); 785 if (dump_trace) {
874 dump_printf(" mmap events: %10ld\n", total_mmap); 786 event__print_totals();
875 dump_printf(" comm events: %10ld\n", total_comm);
876 dump_printf(" fork events: %10ld\n", total_fork);
877 dump_printf(" lost events: %10ld\n", total_lost);
878 dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
879
880 if (dump_trace)
881 return 0; 787 return 0;
788 }
882 789
883 if (verbose > 3) 790 if (verbose > 3)
884 threads__fprintf(stdout, &threads); 791 threads__fprintf(stdout);
885 792
886 if (verbose > 2) 793 if (verbose > 2)
887 dsos__fprintf(stdout); 794 dsos__fprintf(stdout);
888 795
889 collapse__resort(); 796 collapse__resort();
890 output__resort(total); 797 output__resort(event__stats.total);
891 output__fprintf(stdout, total); 798 output__fprintf(stdout, event__stats.total);
892 799
893 if (show_threads) 800 if (show_threads)
894 perf_read_values_destroy(&show_threads_values); 801 perf_read_values_destroy(&show_threads_values);
@@ -962,9 +869,10 @@ static const struct option options[] = {
962 "be more verbose (show symbol address, etc)"), 869 "be more verbose (show symbol address, etc)"),
963 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 870 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
964 "dump raw trace in ASCII"), 871 "dump raw trace in ASCII"),
965 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 872 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
873 "file", "vmlinux pathname"),
966 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 874 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
967 OPT_BOOLEAN('m', "modules", &modules, 875 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
968 "load module symbols - WARNING: use only with -k and LIVE kernel"), 876 "load module symbols - WARNING: use only with -k and LIVE kernel"),
969 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 877 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
970 "Show a column with the number of samples"), 878 "Show a column with the number of samples"),
@@ -1034,7 +942,8 @@ static void setup_list(struct strlist **list, const char *list_str,
1034 942
1035int cmd_report(int argc, const char **argv, const char *prefix __used) 943int cmd_report(int argc, const char **argv, const char *prefix __used)
1036{ 944{
1037 symbol__init(); 945 if (symbol__init(&symbol_conf) < 0)
946 return -1;
1038 947
1039 argc = parse_options(argc, argv, options, report_usage, 0); 948 argc = parse_options(argc, argv, options, report_usage, 0);
1040 949
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 62585b20dd0c..26b782f26ee1 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -22,11 +22,6 @@
22 22
23static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
24 24
25static unsigned long total_comm = 0;
26
27static struct rb_root threads;
28static struct thread *last_match;
29
30static struct perf_header *header; 25static struct perf_header *header;
31static u64 sample_type; 26static u64 sample_type;
32 27
@@ -35,14 +30,9 @@ static char *sort_order = default_sort_order;
35 30
36static int profile_cpu = -1; 31static int profile_cpu = -1;
37 32
38static char *cwd;
39static int cwdlen;
40
41#define PR_SET_NAME 15 /* Set process name */ 33#define PR_SET_NAME 15 /* Set process name */
42#define MAX_CPUS 4096 34#define MAX_CPUS 4096
43 35
44#define BUG_ON(x) assert(!(x))
45
46static u64 run_measurement_overhead; 36static u64 run_measurement_overhead;
47static u64 sleep_measurement_overhead; 37static u64 sleep_measurement_overhead;
48 38
@@ -230,7 +220,7 @@ static void calibrate_sleep_measurement_overhead(void)
230static struct sched_atom * 220static struct sched_atom *
231get_new_event(struct task_desc *task, u64 timestamp) 221get_new_event(struct task_desc *task, u64 timestamp)
232{ 222{
233 struct sched_atom *event = calloc(1, sizeof(*event)); 223 struct sched_atom *event = zalloc(sizeof(*event));
234 unsigned long idx = task->nr_events; 224 unsigned long idx = task->nr_events;
235 size_t size; 225 size_t size;
236 226
@@ -298,7 +288,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
298 return; 288 return;
299 } 289 }
300 290
301 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); 291 wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
302 sem_init(wakee_event->wait_sem, 0, 0); 292 sem_init(wakee_event->wait_sem, 0, 0);
303 wakee_event->specific_wait = 1; 293 wakee_event->specific_wait = 1;
304 event->wait_sem = wakee_event->wait_sem; 294 event->wait_sem = wakee_event->wait_sem;
@@ -328,7 +318,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
328 if (task) 318 if (task)
329 return task; 319 return task;
330 320
331 task = calloc(1, sizeof(*task)); 321 task = zalloc(sizeof(*task));
332 task->pid = pid; 322 task->pid = pid;
333 task->nr = nr_tasks; 323 task->nr = nr_tasks;
334 strcpy(task->comm, comm); 324 strcpy(task->comm, comm);
@@ -638,29 +628,6 @@ static void test_calibrations(void)
638 printf("the sleep test took %Ld nsecs\n", T1-T0); 628 printf("the sleep test took %Ld nsecs\n", T1-T0);
639} 629}
640 630
641static int
642process_comm_event(event_t *event, unsigned long offset, unsigned long head)
643{
644 struct thread *thread;
645
646 thread = threads__findnew(event->comm.tid, &threads, &last_match);
647
648 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
649 (void *)(offset + head),
650 (void *)(long)(event->header.size),
651 event->comm.comm, event->comm.pid);
652
653 if (thread == NULL ||
654 thread__set_comm(thread, event->comm.comm)) {
655 dump_printf("problem processing perf_event_comm, skipping event.\n");
656 return -1;
657 }
658 total_comm++;
659
660 return 0;
661}
662
663
664struct raw_event_sample { 631struct raw_event_sample {
665 u32 size; 632 u32 size;
666 char data[0]; 633 char data[0];
@@ -969,9 +936,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
969 936
970static void thread_atoms_insert(struct thread *thread) 937static void thread_atoms_insert(struct thread *thread)
971{ 938{
972 struct work_atoms *atoms; 939 struct work_atoms *atoms = zalloc(sizeof(*atoms));
973
974 atoms = calloc(sizeof(*atoms), 1);
975 if (!atoms) 940 if (!atoms)
976 die("No memory"); 941 die("No memory");
977 942
@@ -1003,9 +968,7 @@ add_sched_out_event(struct work_atoms *atoms,
1003 char run_state, 968 char run_state,
1004 u64 timestamp) 969 u64 timestamp)
1005{ 970{
1006 struct work_atom *atom; 971 struct work_atom *atom = zalloc(sizeof(*atom));
1007
1008 atom = calloc(sizeof(*atom), 1);
1009 if (!atom) 972 if (!atom)
1010 die("Non memory"); 973 die("Non memory");
1011 974
@@ -1086,8 +1049,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1086 die("hm, delta: %Ld < 0 ?\n", delta); 1049 die("hm, delta: %Ld < 0 ?\n", delta);
1087 1050
1088 1051
1089 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1052 sched_out = threads__findnew(switch_event->prev_pid);
1090 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1053 sched_in = threads__findnew(switch_event->next_pid);
1091 1054
1092 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1055 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1093 if (!out_events) { 1056 if (!out_events) {
@@ -1120,13 +1083,10 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1120 u64 timestamp, 1083 u64 timestamp,
1121 struct thread *this_thread __used) 1084 struct thread *this_thread __used)
1122{ 1085{
1123 struct work_atoms *atoms; 1086 struct thread *thread = threads__findnew(runtime_event->pid);
1124 struct thread *thread; 1087 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1125 1088
1126 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1089 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1127
1128 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1129 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1130 if (!atoms) { 1090 if (!atoms) {
1131 thread_atoms_insert(thread); 1091 thread_atoms_insert(thread);
1132 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1092 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1153,7 +1113,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1153 if (!wakeup_event->success) 1113 if (!wakeup_event->success)
1154 return; 1114 return;
1155 1115
1156 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); 1116 wakee = threads__findnew(wakeup_event->pid);
1157 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1117 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1158 if (!atoms) { 1118 if (!atoms) {
1159 thread_atoms_insert(wakee); 1119 thread_atoms_insert(wakee);
@@ -1202,7 +1162,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1202 if (profile_cpu == -1) 1162 if (profile_cpu == -1)
1203 return; 1163 return;
1204 1164
1205 migrant = threads__findnew(migrate_task_event->pid, &threads, &last_match); 1165 migrant = threads__findnew(migrate_task_event->pid);
1206 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1166 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1207 if (!atoms) { 1167 if (!atoms) {
1208 thread_atoms_insert(migrant); 1168 thread_atoms_insert(migrant);
@@ -1458,8 +1418,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1458 die("hm, delta: %Ld < 0 ?\n", delta); 1418 die("hm, delta: %Ld < 0 ?\n", delta);
1459 1419
1460 1420
1461 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1421 sched_out = threads__findnew(switch_event->prev_pid);
1462 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1422 sched_in = threads__findnew(switch_event->next_pid);
1463 1423
1464 curr_thread[this_cpu] = sched_in; 1424 curr_thread[this_cpu] = sched_in;
1465 1425
@@ -1636,8 +1596,7 @@ process_raw_event(event_t *raw_event __used, void *more_data,
1636 process_sched_migrate_task_event(raw, event, cpu, timestamp, thread); 1596 process_sched_migrate_task_event(raw, event, cpu, timestamp, thread);
1637} 1597}
1638 1598
1639static int 1599static int process_sample_event(event_t *event)
1640process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1641{ 1600{
1642 struct thread *thread; 1601 struct thread *thread;
1643 u64 ip = event->ip.ip; 1602 u64 ip = event->ip.ip;
@@ -1649,7 +1608,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1649 if (!(sample_type & PERF_SAMPLE_RAW)) 1608 if (!(sample_type & PERF_SAMPLE_RAW))
1650 return 0; 1609 return 0;
1651 1610
1652 thread = threads__findnew(event->ip.pid, &threads, &last_match); 1611 thread = threads__findnew(event->ip.pid);
1653 1612
1654 if (sample_type & PERF_SAMPLE_TIME) { 1613 if (sample_type & PERF_SAMPLE_TIME) {
1655 timestamp = *(u64 *)more_data; 1614 timestamp = *(u64 *)more_data;
@@ -1667,22 +1626,20 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1667 more_data += sizeof(u64); 1626 more_data += sizeof(u64);
1668 } 1627 }
1669 1628
1670 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 1629 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1671 (void *)(offset + head),
1672 (void *)(long)(event->header.size),
1673 event->header.misc, 1630 event->header.misc,
1674 event->ip.pid, event->ip.tid, 1631 event->ip.pid, event->ip.tid,
1675 (void *)(long)ip, 1632 (void *)(long)ip,
1676 (long long)period); 1633 (long long)period);
1677 1634
1678 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1679
1680 if (thread == NULL) { 1635 if (thread == NULL) {
1681 eprintf("problem processing %d event, skipping it.\n", 1636 pr_debug("problem processing %d event, skipping it.\n",
1682 event->header.type); 1637 event->header.type);
1683 return -1; 1638 return -1;
1684 } 1639 }
1685 1640
1641 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1642
1686 if (profile_cpu != -1 && profile_cpu != (int) cpu) 1643 if (profile_cpu != -1 && profile_cpu != (int) cpu)
1687 return 0; 1644 return 0;
1688 1645
@@ -1691,10 +1648,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1691 return 0; 1648 return 0;
1692} 1649}
1693 1650
1694static int 1651static int process_lost_event(event_t *event __used)
1695process_lost_event(event_t *event __used,
1696 unsigned long offset __used,
1697 unsigned long head __used)
1698{ 1652{
1699 nr_lost_chunks++; 1653 nr_lost_chunks++;
1700 nr_lost_events += event->lost.lost; 1654 nr_lost_events += event->lost.lost;
@@ -1718,17 +1672,18 @@ static int sample_type_check(u64 type)
1718 1672
1719static struct perf_file_handler file_handler = { 1673static struct perf_file_handler file_handler = {
1720 .process_sample_event = process_sample_event, 1674 .process_sample_event = process_sample_event,
1721 .process_comm_event = process_comm_event, 1675 .process_comm_event = event__process_comm,
1722 .process_lost_event = process_lost_event, 1676 .process_lost_event = process_lost_event,
1723 .sample_type_check = sample_type_check, 1677 .sample_type_check = sample_type_check,
1724}; 1678};
1725 1679
1726static int read_events(void) 1680static int read_events(void)
1727{ 1681{
1728 register_idle_thread(&threads, &last_match); 1682 register_idle_thread();
1729 register_perf_file_handler(&file_handler); 1683 register_perf_file_handler(&file_handler);
1730 1684
1731 return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); 1685 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
1686 &event__cwdlen, &event__cwd);
1732} 1687}
1733 1688
1734static void print_bad_events(void) 1689static void print_bad_events(void)
@@ -1947,7 +1902,7 @@ static int __cmd_record(int argc, const char **argv)
1947 1902
1948int cmd_sched(int argc, const char **argv, const char *prefix __used) 1903int cmd_sched(int argc, const char **argv, const char *prefix __used)
1949{ 1904{
1950 symbol__init(); 1905 symbol__init(0);
1951 1906
1952 argc = parse_options(argc, argv, sched_options, sched_usage, 1907 argc = parse_options(argc, argv, sched_options, sched_usage,
1953 PARSE_OPT_STOP_AT_NON_OPTION); 1908 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3db31e7bf173..c70d72003557 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -50,15 +50,17 @@
50 50
51static struct perf_event_attr default_attrs[] = { 51static struct perf_event_attr default_attrs[] = {
52 52
53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, 54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
55 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, 55 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
56 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 56 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
57 57
58 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 58 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
59 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 59 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
60 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES}, 60 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
61 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES }, 61 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
62 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_REFERENCES },
63 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CACHE_MISSES },
62 64
63}; 65};
64 66
@@ -125,6 +127,7 @@ struct stats event_res_stats[MAX_COUNTERS][3];
125struct stats runtime_nsecs_stats; 127struct stats runtime_nsecs_stats;
126struct stats walltime_nsecs_stats; 128struct stats walltime_nsecs_stats;
127struct stats runtime_cycles_stats; 129struct stats runtime_cycles_stats;
130struct stats runtime_branches_stats;
128 131
129#define MATCH_EVENT(t, c, counter) \ 132#define MATCH_EVENT(t, c, counter) \
130 (attrs[counter].type == PERF_TYPE_##t && \ 133 (attrs[counter].type == PERF_TYPE_##t && \
@@ -235,6 +238,8 @@ static void read_counter(int counter)
235 update_stats(&runtime_nsecs_stats, count[0]); 238 update_stats(&runtime_nsecs_stats, count[0]);
236 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 239 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
237 update_stats(&runtime_cycles_stats, count[0]); 240 update_stats(&runtime_cycles_stats, count[0]);
241 if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter))
242 update_stats(&runtime_branches_stats, count[0]);
238} 243}
239 244
240static int run_perf_stat(int argc __used, const char **argv) 245static int run_perf_stat(int argc __used, const char **argv)
@@ -352,7 +357,16 @@ static void abs_printout(int counter, double avg)
352 ratio = avg / total; 357 ratio = avg / total;
353 358
354 fprintf(stderr, " # %10.3f IPC ", ratio); 359 fprintf(stderr, " # %10.3f IPC ", ratio);
355 } else { 360 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) &&
361 runtime_branches_stats.n != 0) {
362 total = avg_stats(&runtime_branches_stats);
363
364 if (total)
365 ratio = avg * 100 / total;
366
367 fprintf(stderr, " # %10.3f %% ", ratio);
368
369 } else if (runtime_nsecs_stats.n != 0) {
356 total = avg_stats(&runtime_nsecs_stats); 370 total = avg_stats(&runtime_nsecs_stats);
357 371
358 if (total) 372 if (total)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 702d8fe58fbc..cb58b6605fcc 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -29,14 +29,14 @@
29#include "util/header.h" 29#include "util/header.h"
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h"
33#include "util/data_map.h"
32#include "util/svghelper.h" 34#include "util/svghelper.h"
33 35
34static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
35static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
36 38
37 39
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type; 40static u64 sample_type;
41 41
42static unsigned int numcpus; 42static unsigned int numcpus;
@@ -49,8 +49,6 @@ static u64 first_time, last_time;
49static int power_only; 49static int power_only;
50 50
51 51
52static struct perf_header *header;
53
54struct per_pid; 52struct per_pid;
55struct per_pidcomm; 53struct per_pidcomm;
56 54
@@ -153,6 +151,17 @@ static struct wake_event *wake_events;
153 151
154struct sample_wrapper *all_samples; 152struct sample_wrapper *all_samples;
155 153
154
155struct process_filter;
156struct process_filter {
157 char *name;
158 int pid;
159 struct process_filter *next;
160};
161
162static struct process_filter *process_filter;
163
164
156static struct per_pid *find_create_pid(int pid) 165static struct per_pid *find_create_pid(int pid)
157{ 166{
158 struct per_pid *cursor = all_data; 167 struct per_pid *cursor = all_data;
@@ -763,21 +772,42 @@ static void draw_wakeups(void)
763 c = p->all; 772 c = p->all;
764 while (c) { 773 while (c) {
765 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { 774 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
766 if (p->pid == we->waker) { 775 if (p->pid == we->waker && !from) {
767 from = c->Y; 776 from = c->Y;
768 task_from = c->comm; 777 task_from = strdup(c->comm);
769 } 778 }
770 if (p->pid == we->wakee) { 779 if (p->pid == we->wakee && !to) {
771 to = c->Y; 780 to = c->Y;
772 task_to = c->comm; 781 task_to = strdup(c->comm);
773 } 782 }
774 } 783 }
775 c = c->next; 784 c = c->next;
776 } 785 }
786 c = p->all;
787 while (c) {
788 if (p->pid == we->waker && !from) {
789 from = c->Y;
790 task_from = strdup(c->comm);
791 }
792 if (p->pid == we->wakee && !to) {
793 to = c->Y;
794 task_to = strdup(c->comm);
795 }
796 c = c->next;
797 }
777 } 798 }
778 p = p->next; 799 p = p->next;
779 } 800 }
780 801
802 if (!task_from) {
803 task_from = malloc(40);
804 sprintf(task_from, "[%i]", we->waker);
805 }
806 if (!task_to) {
807 task_to = malloc(40);
808 sprintf(task_to, "[%i]", we->wakee);
809 }
810
781 if (we->waker == -1) 811 if (we->waker == -1)
782 svg_interrupt(we->time, to); 812 svg_interrupt(we->time, to);
783 else if (from && to && abs(from - to) == 1) 813 else if (from && to && abs(from - to) == 1)
@@ -785,6 +815,9 @@ static void draw_wakeups(void)
785 else 815 else
786 svg_partial_wakeline(we->time, from, task_from, to, task_to); 816 svg_partial_wakeline(we->time, from, task_from, to, task_to);
787 we = we->next; 817 we = we->next;
818
819 free(task_from);
820 free(task_to);
788 } 821 }
789} 822}
790 823
@@ -858,12 +891,89 @@ static void draw_process_bars(void)
858 } 891 }
859} 892}
860 893
894static void add_process_filter(const char *string)
895{
896 struct process_filter *filt;
897 int pid;
898
899 pid = strtoull(string, NULL, 10);
900 filt = malloc(sizeof(struct process_filter));
901 if (!filt)
902 return;
903
904 filt->name = strdup(string);
905 filt->pid = pid;
906 filt->next = process_filter;
907
908 process_filter = filt;
909}
910
911static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
912{
913 struct process_filter *filt;
914 if (!process_filter)
915 return 1;
916
917 filt = process_filter;
918 while (filt) {
919 if (filt->pid && p->pid == filt->pid)
920 return 1;
921 if (strcmp(filt->name, c->comm) == 0)
922 return 1;
923 filt = filt->next;
924 }
925 return 0;
926}
927
928static int determine_display_tasks_filtered(void)
929{
930 struct per_pid *p;
931 struct per_pidcomm *c;
932 int count = 0;
933
934 p = all_data;
935 while (p) {
936 p->display = 0;
937 if (p->start_time == 1)
938 p->start_time = first_time;
939
940 /* no exit marker, task kept running to the end */
941 if (p->end_time == 0)
942 p->end_time = last_time;
943
944 c = p->all;
945
946 while (c) {
947 c->display = 0;
948
949 if (c->start_time == 1)
950 c->start_time = first_time;
951
952 if (passes_filter(p, c)) {
953 c->display = 1;
954 p->display = 1;
955 count++;
956 }
957
958 if (c->end_time == 0)
959 c->end_time = last_time;
960
961 c = c->next;
962 }
963 p = p->next;
964 }
965 return count;
966}
967
861static int determine_display_tasks(u64 threshold) 968static int determine_display_tasks(u64 threshold)
862{ 969{
863 struct per_pid *p; 970 struct per_pid *p;
864 struct per_pidcomm *c; 971 struct per_pidcomm *c;
865 int count = 0; 972 int count = 0;
866 973
974 if (process_filter)
975 return determine_display_tasks_filtered();
976
867 p = all_data; 977 p = all_data;
868 while (p) { 978 while (p) {
869 p->display = 0; 979 p->display = 0;
@@ -933,36 +1043,6 @@ static void write_svg_file(const char *filename)
933 svg_close(); 1043 svg_close();
934} 1044}
935 1045
936static int
937process_event(event_t *event)
938{
939
940 switch (event->header.type) {
941
942 case PERF_RECORD_COMM:
943 return process_comm_event(event);
944 case PERF_RECORD_FORK:
945 return process_fork_event(event);
946 case PERF_RECORD_EXIT:
947 return process_exit_event(event);
948 case PERF_RECORD_SAMPLE:
949 return queue_sample_event(event);
950
951 /*
952 * We dont process them right now but they are fine:
953 */
954 case PERF_RECORD_MMAP:
955 case PERF_RECORD_THROTTLE:
956 case PERF_RECORD_UNTHROTTLE:
957 return 0;
958
959 default:
960 return -1;
961 }
962
963 return 0;
964}
965
966static void process_samples(void) 1046static void process_samples(void)
967{ 1047{
968 struct sample_wrapper *cursor; 1048 struct sample_wrapper *cursor;
@@ -978,107 +1058,38 @@ static void process_samples(void)
978 } 1058 }
979} 1059}
980 1060
981 1061static int sample_type_check(u64 type)
982static int __cmd_timechart(void)
983{ 1062{
984 int ret, rc = EXIT_FAILURE; 1063 sample_type = type;
985 unsigned long offset = 0;
986 unsigned long head, shift;
987 struct stat statbuf;
988 event_t *event;
989 uint32_t size;
990 char *buf;
991 int input;
992
993 input = open(input_name, O_RDONLY);
994 if (input < 0) {
995 fprintf(stderr, " failed to open file: %s", input_name);
996 if (!strcmp(input_name, "perf.data"))
997 fprintf(stderr, " (try 'perf record' first)");
998 fprintf(stderr, "\n");
999 exit(-1);
1000 }
1001
1002 ret = fstat(input, &statbuf);
1003 if (ret < 0) {
1004 perror("failed to stat file");
1005 exit(-1);
1006 }
1007
1008 if (!statbuf.st_size) {
1009 fprintf(stderr, "zero-sized file, nothing to do!\n");
1010 exit(0);
1011 }
1012
1013 header = perf_header__read(input);
1014 head = header->data_offset;
1015
1016 sample_type = perf_header__sample_type(header);
1017
1018 shift = page_size * (head / page_size);
1019 offset += shift;
1020 head -= shift;
1021
1022remap:
1023 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1024 MAP_SHARED, input, offset);
1025 if (buf == MAP_FAILED) {
1026 perror("failed to mmap file");
1027 exit(-1);
1028 }
1029
1030more:
1031 event = (event_t *)(buf + head);
1032
1033 size = event->header.size;
1034 if (!size)
1035 size = 8;
1036
1037 if (head + event->header.size >= page_size * mmap_window) {
1038 int ret2;
1039
1040 shift = page_size * (head / page_size);
1041
1042 ret2 = munmap(buf, page_size * mmap_window);
1043 assert(ret2 == 0);
1044
1045 offset += shift;
1046 head -= shift;
1047 goto remap;
1048 }
1049
1050 size = event->header.size;
1051
1052 if (!size || process_event(event) < 0) {
1053 1064
1054 printf("%p [%p]: skipping unknown header type: %d\n", 1065 if (!(sample_type & PERF_SAMPLE_RAW)) {
1055 (void *)(offset + head), 1066 fprintf(stderr, "No trace samples found in the file.\n"
1056 (void *)(long)(event->header.size), 1067 "Have you used 'perf timechart record' to record it?\n");
1057 event->header.type); 1068 return -1;
1058
1059 /*
1060 * assume we lost track of the stream, check alignment, and
1061 * increment a single u64 in the hope to catch on again 'soon'.
1062 */
1063
1064 if (unlikely(head & 7))
1065 head &= ~7ULL;
1066
1067 size = 8;
1068 } 1069 }
1069 1070
1070 head += size; 1071 return 0;
1072}
1071 1073
1072 if (offset + head >= header->data_offset + header->data_size) 1074static struct perf_file_handler file_handler = {
1073 goto done; 1075 .process_comm_event = process_comm_event,
1076 .process_fork_event = process_fork_event,
1077 .process_exit_event = process_exit_event,
1078 .process_sample_event = queue_sample_event,
1079 .sample_type_check = sample_type_check,
1080};
1074 1081
1075 if (offset + head < (unsigned long)statbuf.st_size) 1082static int __cmd_timechart(void)
1076 goto more; 1083{
1084 struct perf_header *header;
1085 int ret;
1077 1086
1078done: 1087 register_perf_file_handler(&file_handler);
1079 rc = EXIT_SUCCESS;
1080 close(input);
1081 1088
1089 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
1090 &event__cwdlen, &event__cwd);
1091 if (ret)
1092 return EXIT_FAILURE;
1082 1093
1083 process_samples(); 1094 process_samples();
1084 1095
@@ -1088,9 +1099,10 @@ done:
1088 1099
1089 write_svg_file(output_name); 1100 write_svg_file(output_name);
1090 1101
1091 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1102 pr_info("Written %2.1f seconds of trace to %s.\n",
1103 (last_time - first_time) / 1000000000.0, output_name);
1092 1104
1093 return rc; 1105 return EXIT_SUCCESS;
1094} 1106}
1095 1107
1096static const char * const timechart_usage[] = { 1108static const char * const timechart_usage[] = {
@@ -1129,6 +1141,14 @@ static int __cmd_record(int argc, const char **argv)
1129 return cmd_record(i, rec_argv, NULL); 1141 return cmd_record(i, rec_argv, NULL);
1130} 1142}
1131 1143
1144static int
1145parse_process(const struct option *opt __used, const char *arg, int __used unset)
1146{
1147 if (arg)
1148 add_process_filter(arg);
1149 return 0;
1150}
1151
1132static const struct option options[] = { 1152static const struct option options[] = {
1133 OPT_STRING('i', "input", &input_name, "file", 1153 OPT_STRING('i', "input", &input_name, "file",
1134 "input file name"), 1154 "input file name"),
@@ -1136,17 +1156,18 @@ static const struct option options[] = {
1136 "output file name"), 1156 "output file name"),
1137 OPT_INTEGER('w', "width", &svg_page_width, 1157 OPT_INTEGER('w', "width", &svg_page_width,
1138 "page width"), 1158 "page width"),
1139 OPT_BOOLEAN('p', "power-only", &power_only, 1159 OPT_BOOLEAN('P', "power-only", &power_only,
1140 "output power data only"), 1160 "output power data only"),
1161 OPT_CALLBACK('p', "process", NULL, "process",
1162 "process selector. Pass a pid or process name.",
1163 parse_process),
1141 OPT_END() 1164 OPT_END()
1142}; 1165};
1143 1166
1144 1167
1145int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1168int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1146{ 1169{
1147 symbol__init(); 1170 symbol__init(0);
1148
1149 page_size = getpagesize();
1150 1171
1151 argc = parse_options(argc, argv, options, timechart_usage, 1172 argc = parse_options(argc, argv, options, timechart_usage,
1152 PARSE_OPT_STOP_AT_NON_OPTION); 1173 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c0f69e80b2cc..e0a374d0e43a 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -60,7 +60,7 @@ static int system_wide = 0;
60static int default_interval = 0; 60static int default_interval = 0;
61 61
62static int count_filter = 5; 62static int count_filter = 5;
63static int print_entries = 15; 63static int print_entries;
64 64
65static int target_pid = -1; 65static int target_pid = -1;
66static int inherit = 0; 66static int inherit = 0;
@@ -76,6 +76,11 @@ static int delay_secs = 2;
76static int zero = 0; 76static int zero = 0;
77static int dump_symtab = 0; 77static int dump_symtab = 0;
78 78
79static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false;
81static struct winsize winsize;
82struct symbol_conf symbol_conf;
83
79/* 84/*
80 * Source 85 * Source
81 */ 86 */
@@ -97,27 +102,75 @@ static int display_weighted = -1;
97 * Symbols 102 * Symbols
98 */ 103 */
99 104
105struct sym_entry_source {
106 struct source_line *source;
107 struct source_line *lines;
108 struct source_line **lines_tail;
109 pthread_mutex_t lock;
110};
111
100struct sym_entry { 112struct sym_entry {
101 struct rb_node rb_node; 113 struct rb_node rb_node;
102 struct list_head node; 114 struct list_head node;
103 unsigned long count[MAX_COUNTERS];
104 unsigned long snap_count; 115 unsigned long snap_count;
105 double weight; 116 double weight;
106 int skip; 117 int skip;
118 u16 name_len;
119 u8 origin;
107 struct map *map; 120 struct map *map;
108 struct source_line *source; 121 struct sym_entry_source *src;
109 struct source_line *lines; 122 unsigned long count[0];
110 struct source_line **lines_tail;
111 pthread_mutex_t source_lock;
112}; 123};
113 124
114/* 125/*
115 * Source functions 126 * Source functions
116 */ 127 */
117 128
129static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
130{
131 return ((void *)self) + symbol_conf.priv_size;
132}
133
134static void get_term_dimensions(struct winsize *ws)
135{
136 char *s = getenv("LINES");
137
138 if (s != NULL) {
139 ws->ws_row = atoi(s);
140 s = getenv("COLUMNS");
141 if (s != NULL) {
142 ws->ws_col = atoi(s);
143 if (ws->ws_row && ws->ws_col)
144 return;
145 }
146 }
147#ifdef TIOCGWINSZ
148 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
149 ws->ws_row && ws->ws_col)
150 return;
151#endif
152 ws->ws_row = 25;
153 ws->ws_col = 80;
154}
155
156static void update_print_entries(struct winsize *ws)
157{
158 print_entries = ws->ws_row;
159
160 if (print_entries > 9)
161 print_entries -= 9;
162}
163
164static void sig_winch_handler(int sig __used)
165{
166 get_term_dimensions(&winsize);
167 update_print_entries(&winsize);
168}
169
118static void parse_source(struct sym_entry *syme) 170static void parse_source(struct sym_entry *syme)
119{ 171{
120 struct symbol *sym; 172 struct symbol *sym;
173 struct sym_entry_source *source;
121 struct map *map; 174 struct map *map;
122 FILE *file; 175 FILE *file;
123 char command[PATH_MAX*2]; 176 char command[PATH_MAX*2];
@@ -127,12 +180,21 @@ static void parse_source(struct sym_entry *syme)
127 if (!syme) 180 if (!syme)
128 return; 181 return;
129 182
130 if (syme->lines) { 183 if (syme->src == NULL) {
131 pthread_mutex_lock(&syme->source_lock); 184 syme->src = zalloc(sizeof(*source));
185 if (syme->src == NULL)
186 return;
187 pthread_mutex_init(&syme->src->lock, NULL);
188 }
189
190 source = syme->src;
191
192 if (source->lines) {
193 pthread_mutex_lock(&source->lock);
132 goto out_assign; 194 goto out_assign;
133 } 195 }
134 196
135 sym = (struct symbol *)(syme + 1); 197 sym = sym_entry__symbol(syme);
136 map = syme->map; 198 map = syme->map;
137 path = map->dso->long_name; 199 path = map->dso->long_name;
138 200
@@ -141,14 +203,15 @@ static void parse_source(struct sym_entry *syme)
141 sprintf(command, 203 sprintf(command,
142 "objdump --start-address=0x%016Lx " 204 "objdump --start-address=0x%016Lx "
143 "--stop-address=0x%016Lx -dS %s", 205 "--stop-address=0x%016Lx -dS %s",
144 sym->start, sym->end, path); 206 map->unmap_ip(map, sym->start),
207 map->unmap_ip(map, sym->end), path);
145 208
146 file = popen(command, "r"); 209 file = popen(command, "r");
147 if (!file) 210 if (!file)
148 return; 211 return;
149 212
150 pthread_mutex_lock(&syme->source_lock); 213 pthread_mutex_lock(&source->lock);
151 syme->lines_tail = &syme->lines; 214 source->lines_tail = &source->lines;
152 while (!feof(file)) { 215 while (!feof(file)) {
153 struct source_line *src; 216 struct source_line *src;
154 size_t dummy = 0; 217 size_t dummy = 0;
@@ -168,22 +231,22 @@ static void parse_source(struct sym_entry *syme)
168 *c = 0; 231 *c = 0;
169 232
170 src->next = NULL; 233 src->next = NULL;
171 *syme->lines_tail = src; 234 *source->lines_tail = src;
172 syme->lines_tail = &src->next; 235 source->lines_tail = &src->next;
173 236
174 if (strlen(src->line)>8 && src->line[8] == ':') { 237 if (strlen(src->line)>8 && src->line[8] == ':') {
175 src->eip = strtoull(src->line, NULL, 16); 238 src->eip = strtoull(src->line, NULL, 16);
176 src->eip += map->start; 239 src->eip = map->unmap_ip(map, src->eip);
177 } 240 }
178 if (strlen(src->line)>8 && src->line[16] == ':') { 241 if (strlen(src->line)>8 && src->line[16] == ':') {
179 src->eip = strtoull(src->line, NULL, 16); 242 src->eip = strtoull(src->line, NULL, 16);
180 src->eip += map->start; 243 src->eip = map->unmap_ip(map, src->eip);
181 } 244 }
182 } 245 }
183 pclose(file); 246 pclose(file);
184out_assign: 247out_assign:
185 sym_filter_entry = syme; 248 sym_filter_entry = syme;
186 pthread_mutex_unlock(&syme->source_lock); 249 pthread_mutex_unlock(&source->lock);
187} 250}
188 251
189static void __zero_source_counters(struct sym_entry *syme) 252static void __zero_source_counters(struct sym_entry *syme)
@@ -191,7 +254,7 @@ static void __zero_source_counters(struct sym_entry *syme)
191 int i; 254 int i;
192 struct source_line *line; 255 struct source_line *line;
193 256
194 line = syme->lines; 257 line = syme->src->lines;
195 while (line) { 258 while (line) {
196 for (i = 0; i < nr_counters; i++) 259 for (i = 0; i < nr_counters; i++)
197 line->count[i] = 0; 260 line->count[i] = 0;
@@ -206,13 +269,13 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
206 if (syme != sym_filter_entry) 269 if (syme != sym_filter_entry)
207 return; 270 return;
208 271
209 if (pthread_mutex_trylock(&syme->source_lock)) 272 if (pthread_mutex_trylock(&syme->src->lock))
210 return; 273 return;
211 274
212 if (!syme->source) 275 if (syme->src == NULL || syme->src->source == NULL)
213 goto out_unlock; 276 goto out_unlock;
214 277
215 for (line = syme->lines; line; line = line->next) { 278 for (line = syme->src->lines; line; line = line->next) {
216 if (line->eip == ip) { 279 if (line->eip == ip) {
217 line->count[counter]++; 280 line->count[counter]++;
218 break; 281 break;
@@ -221,25 +284,25 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
221 break; 284 break;
222 } 285 }
223out_unlock: 286out_unlock:
224 pthread_mutex_unlock(&syme->source_lock); 287 pthread_mutex_unlock(&syme->src->lock);
225} 288}
226 289
227static void lookup_sym_source(struct sym_entry *syme) 290static void lookup_sym_source(struct sym_entry *syme)
228{ 291{
229 struct symbol *symbol = (struct symbol *)(syme + 1); 292 struct symbol *symbol = sym_entry__symbol(syme);
230 struct source_line *line; 293 struct source_line *line;
231 char pattern[PATH_MAX]; 294 char pattern[PATH_MAX];
232 295
233 sprintf(pattern, "<%s>:", symbol->name); 296 sprintf(pattern, "<%s>:", symbol->name);
234 297
235 pthread_mutex_lock(&syme->source_lock); 298 pthread_mutex_lock(&syme->src->lock);
236 for (line = syme->lines; line; line = line->next) { 299 for (line = syme->src->lines; line; line = line->next) {
237 if (strstr(line->line, pattern)) { 300 if (strstr(line->line, pattern)) {
238 syme->source = line; 301 syme->src->source = line;
239 break; 302 break;
240 } 303 }
241 } 304 }
242 pthread_mutex_unlock(&syme->source_lock); 305 pthread_mutex_unlock(&syme->src->lock);
243} 306}
244 307
245static void show_lines(struct source_line *queue, int count, int total) 308static void show_lines(struct source_line *queue, int count, int total)
@@ -269,24 +332,24 @@ static void show_details(struct sym_entry *syme)
269 if (!syme) 332 if (!syme)
270 return; 333 return;
271 334
272 if (!syme->source) 335 if (!syme->src->source)
273 lookup_sym_source(syme); 336 lookup_sym_source(syme);
274 337
275 if (!syme->source) 338 if (!syme->src->source)
276 return; 339 return;
277 340
278 symbol = (struct symbol *)(syme + 1); 341 symbol = sym_entry__symbol(syme);
279 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 342 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
280 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 343 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
281 344
282 pthread_mutex_lock(&syme->source_lock); 345 pthread_mutex_lock(&syme->src->lock);
283 line = syme->source; 346 line = syme->src->source;
284 while (line) { 347 while (line) {
285 total += line->count[sym_counter]; 348 total += line->count[sym_counter];
286 line = line->next; 349 line = line->next;
287 } 350 }
288 351
289 line = syme->source; 352 line = syme->src->source;
290 while (line) { 353 while (line) {
291 float pcnt = 0.0; 354 float pcnt = 0.0;
292 355
@@ -311,13 +374,13 @@ static void show_details(struct sym_entry *syme)
311 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; 374 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
312 line = line->next; 375 line = line->next;
313 } 376 }
314 pthread_mutex_unlock(&syme->source_lock); 377 pthread_mutex_unlock(&syme->src->lock);
315 if (more) 378 if (more)
316 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 379 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
317} 380}
318 381
319/* 382/*
320 * Symbols will be added here in record_ip and will get out 383 * Symbols will be added here in event__process_sample and will get out
321 * after decayed. 384 * after decayed.
322 */ 385 */
323static LIST_HEAD(active_symbols); 386static LIST_HEAD(active_symbols);
@@ -388,6 +451,8 @@ static void print_sym_table(void)
388 struct sym_entry *syme, *n; 451 struct sym_entry *syme, *n;
389 struct rb_root tmp = RB_ROOT; 452 struct rb_root tmp = RB_ROOT;
390 struct rb_node *nd; 453 struct rb_node *nd;
454 int sym_width = 0, dso_width = 0, max_dso_width;
455 const int win_width = winsize.ws_col - 1;
391 456
392 samples = userspace_samples = 0; 457 samples = userspace_samples = 0;
393 458
@@ -399,6 +464,14 @@ static void print_sym_table(void)
399 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 464 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
400 syme->snap_count = syme->count[snap]; 465 syme->snap_count = syme->count[snap];
401 if (syme->snap_count != 0) { 466 if (syme->snap_count != 0) {
467
468 if ((hide_user_symbols &&
469 syme->origin == PERF_RECORD_MISC_USER) ||
470 (hide_kernel_symbols &&
471 syme->origin == PERF_RECORD_MISC_KERNEL)) {
472 list_remove_active_sym(syme);
473 continue;
474 }
402 syme->weight = sym_weight(syme); 475 syme->weight = sym_weight(syme);
403 rb_insert_active_sym(&tmp, syme); 476 rb_insert_active_sym(&tmp, syme);
404 sum_ksamples += syme->snap_count; 477 sum_ksamples += syme->snap_count;
@@ -411,8 +484,7 @@ static void print_sym_table(void)
411 484
412 puts(CONSOLE_CLEAR); 485 puts(CONSOLE_CLEAR);
413 486
414 printf( 487 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
415"------------------------------------------------------------------------------\n");
416 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 488 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
417 samples_per_sec, 489 samples_per_sec,
418 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 490 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
@@ -450,33 +522,57 @@ static void print_sym_table(void)
450 printf(", %d CPUs)\n", nr_cpus); 522 printf(", %d CPUs)\n", nr_cpus);
451 } 523 }
452 524
453 printf("------------------------------------------------------------------------------\n\n"); 525 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
454 526
455 if (sym_filter_entry) { 527 if (sym_filter_entry) {
456 show_details(sym_filter_entry); 528 show_details(sym_filter_entry);
457 return; 529 return;
458 } 530 }
459 531
532 /*
533 * Find the longest symbol name that will be displayed
534 */
535 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
536 syme = rb_entry(nd, struct sym_entry, rb_node);
537 if (++printed > print_entries ||
538 (int)syme->snap_count < count_filter)
539 continue;
540
541 if (syme->map->dso->long_name_len > dso_width)
542 dso_width = syme->map->dso->long_name_len;
543
544 if (syme->name_len > sym_width)
545 sym_width = syme->name_len;
546 }
547
548 printed = 0;
549
550 max_dso_width = winsize.ws_col - sym_width - 29;
551 if (dso_width > max_dso_width)
552 dso_width = max_dso_width;
553 putchar('\n');
460 if (nr_counters == 1) 554 if (nr_counters == 1)
461 printf(" samples pcnt"); 555 printf(" samples pcnt");
462 else 556 else
463 printf(" weight samples pcnt"); 557 printf(" weight samples pcnt");
464 558
465 if (verbose) 559 if (verbose)
466 printf(" RIP "); 560 printf(" RIP ");
467 printf(" kernel function\n"); 561 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
468 printf(" %s _______ _____", 562 printf(" %s _______ _____",
469 nr_counters == 1 ? " " : "______"); 563 nr_counters == 1 ? " " : "______");
470 if (verbose) 564 if (verbose)
471 printf(" ________________"); 565 printf(" ________________");
472 printf(" _______________\n\n"); 566 printf(" %-*.*s", sym_width, sym_width, graph_line);
567 printf(" %-*.*s", dso_width, dso_width, graph_line);
568 puts("\n");
473 569
474 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 570 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
475 struct symbol *sym; 571 struct symbol *sym;
476 double pcnt; 572 double pcnt;
477 573
478 syme = rb_entry(nd, struct sym_entry, rb_node); 574 syme = rb_entry(nd, struct sym_entry, rb_node);
479 sym = (struct symbol *)(syme + 1); 575 sym = sym_entry__symbol(syme);
480 576
481 if (++printed > print_entries || (int)syme->snap_count < count_filter) 577 if (++printed > print_entries || (int)syme->snap_count < count_filter)
482 continue; 578 continue;
@@ -485,17 +581,18 @@ static void print_sym_table(void)
485 sum_ksamples)); 581 sum_ksamples));
486 582
487 if (nr_counters == 1 || !display_weighted) 583 if (nr_counters == 1 || !display_weighted)
488 printf("%20.2f - ", syme->weight); 584 printf("%20.2f ", syme->weight);
489 else 585 else
490 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 586 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
491 587
492 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 588 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
493 if (verbose) 589 if (verbose)
494 printf(" - %016llx", sym->start); 590 printf(" %016llx", sym->start);
495 printf(" : %s", sym->name); 591 printf(" %-*.*s", sym_width, sym_width, sym->name);
496 if (syme->map->dso->name[0] == '[') 592 printf(" %-*.*s\n", dso_width, dso_width,
497 printf(" \t%s", syme->map->dso->name); 593 dso_width >= syme->map->dso->long_name_len ?
498 printf("\n"); 594 syme->map->dso->long_name :
595 syme->map->dso->short_name);
499 } 596 }
500} 597}
501 598
@@ -542,10 +639,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
542 639
543 /* zero counters of active symbol */ 640 /* zero counters of active symbol */
544 if (syme) { 641 if (syme) {
545 pthread_mutex_lock(&syme->source_lock); 642 pthread_mutex_lock(&syme->src->lock);
546 __zero_source_counters(syme); 643 __zero_source_counters(syme);
547 *target = NULL; 644 *target = NULL;
548 pthread_mutex_unlock(&syme->source_lock); 645 pthread_mutex_unlock(&syme->src->lock);
549 } 646 }
550 647
551 fprintf(stdout, "\n%s: ", msg); 648 fprintf(stdout, "\n%s: ", msg);
@@ -561,7 +658,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
561 pthread_mutex_unlock(&active_symbols_lock); 658 pthread_mutex_unlock(&active_symbols_lock);
562 659
563 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 660 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
564 struct symbol *sym = (struct symbol *)(syme + 1); 661 struct symbol *sym = sym_entry__symbol(syme);
565 662
566 if (!strcmp(buf, sym->name)) { 663 if (!strcmp(buf, sym->name)) {
567 found = syme; 664 found = syme;
@@ -585,7 +682,7 @@ static void print_mapped_keys(void)
585 char *name = NULL; 682 char *name = NULL;
586 683
587 if (sym_filter_entry) { 684 if (sym_filter_entry) {
588 struct symbol *sym = (struct symbol *)(sym_filter_entry+1); 685 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
589 name = sym->name; 686 name = sym->name;
590 } 687 }
591 688
@@ -598,7 +695,7 @@ static void print_mapped_keys(void)
598 695
599 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
600 697
601 if (vmlinux_name) { 698 if (symbol_conf.vmlinux_name) {
602 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);
603 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
604 fprintf(stdout, "\t[S] stop annotation.\n"); 701 fprintf(stdout, "\t[S] stop annotation.\n");
@@ -607,6 +704,12 @@ static void print_mapped_keys(void)
607 if (nr_counters > 1) 704 if (nr_counters > 1)
608 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 705 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
609 706
707 fprintf(stdout,
708 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
709 hide_kernel_symbols ? "yes" : "no");
710 fprintf(stdout,
711 "\t[U] hide user symbols. \t(%s)\n",
712 hide_user_symbols ? "yes" : "no");
610 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 713 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
611 fprintf(stdout, "\t[qQ] quit.\n"); 714 fprintf(stdout, "\t[qQ] quit.\n");
612} 715}
@@ -620,6 +723,8 @@ static int key_mapped(int c)
620 case 'z': 723 case 'z':
621 case 'q': 724 case 'q':
622 case 'Q': 725 case 'Q':
726 case 'K':
727 case 'U':
623 return 1; 728 return 1;
624 case 'E': 729 case 'E':
625 case 'w': 730 case 'w':
@@ -627,7 +732,7 @@ static int key_mapped(int c)
627 case 'F': 732 case 'F':
628 case 's': 733 case 's':
629 case 'S': 734 case 'S':
630 return vmlinux_name ? 1 : 0; 735 return symbol_conf.vmlinux_name ? 1 : 0;
631 default: 736 default:
632 break; 737 break;
633 } 738 }
@@ -663,9 +768,16 @@ static void handle_keypress(int c)
663 switch (c) { 768 switch (c) {
664 case 'd': 769 case 'd':
665 prompt_integer(&delay_secs, "Enter display delay"); 770 prompt_integer(&delay_secs, "Enter display delay");
771 if (delay_secs < 1)
772 delay_secs = 1;
666 break; 773 break;
667 case 'e': 774 case 'e':
668 prompt_integer(&print_entries, "Enter display entries (lines)"); 775 prompt_integer(&print_entries, "Enter display entries (lines)");
776 if (print_entries == 0) {
777 sig_winch_handler(SIGWINCH);
778 signal(SIGWINCH, sig_winch_handler);
779 } else
780 signal(SIGWINCH, SIG_DFL);
669 break; 781 break;
670 case 'E': 782 case 'E':
671 if (nr_counters > 1) { 783 if (nr_counters > 1) {
@@ -690,9 +802,14 @@ static void handle_keypress(int c)
690 case 'F': 802 case 'F':
691 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 803 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
692 break; 804 break;
805 case 'K':
806 hide_kernel_symbols = !hide_kernel_symbols;
807 break;
693 case 'q': 808 case 'q':
694 case 'Q': 809 case 'Q':
695 printf("exiting.\n"); 810 printf("exiting.\n");
811 if (dump_symtab)
812 dsos__fprintf(stderr);
696 exit(0); 813 exit(0);
697 case 's': 814 case 's':
698 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 815 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -703,12 +820,15 @@ static void handle_keypress(int c)
703 else { 820 else {
704 struct sym_entry *syme = sym_filter_entry; 821 struct sym_entry *syme = sym_filter_entry;
705 822
706 pthread_mutex_lock(&syme->source_lock); 823 pthread_mutex_lock(&syme->src->lock);
707 sym_filter_entry = NULL; 824 sym_filter_entry = NULL;
708 __zero_source_counters(syme); 825 __zero_source_counters(syme);
709 pthread_mutex_unlock(&syme->source_lock); 826 pthread_mutex_unlock(&syme->src->lock);
710 } 827 }
711 break; 828 break;
829 case 'U':
830 hide_user_symbols = !hide_user_symbols;
831 break;
712 case 'w': 832 case 'w':
713 display_weighted = ~display_weighted; 833 display_weighted = ~display_weighted;
714 break; 834 break;
@@ -787,9 +907,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
787 strstr(name, "_text_end")) 907 strstr(name, "_text_end"))
788 return 1; 908 return 1;
789 909
790 syme = dso__sym_priv(map->dso, sym); 910 syme = symbol__priv(sym);
791 syme->map = map; 911 syme->map = map;
792 pthread_mutex_init(&syme->source_lock, NULL); 912 syme->src = NULL;
793 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
794 sym_filter_entry = syme; 914 sym_filter_entry = syme;
795 915
@@ -800,56 +920,65 @@ static int symbol_filter(struct map *map, struct symbol *sym)
800 } 920 }
801 } 921 }
802 922
803 return 0; 923 if (!syme->skip)
804} 924 syme->name_len = strlen(sym->name);
805
806static int parse_symbols(void)
807{
808 if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
809 symbol_filter, verbose, 1) <= 0)
810 return -1;
811
812 if (dump_symtab)
813 dsos__fprintf(stderr);
814 925
815 return 0; 926 return 0;
816} 927}
817 928
818/* 929static void event__process_sample(const event_t *self, int counter)
819 * Binary search in the histogram table and record the hit:
820 */
821static void record_ip(u64 ip, int counter)
822{ 930{
823 struct map *map; 931 u64 ip = self->ip.ip;
824 struct symbol *sym = kernel_maps__find_symbol(ip, &map); 932 struct sym_entry *syme;
825 933 struct addr_location al;
826 if (sym != NULL) { 934 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
827 struct sym_entry *syme = dso__sym_priv(map->dso, sym); 935
828 936 switch (origin) {
829 if (!syme->skip) { 937 case PERF_RECORD_MISC_USER:
830 syme->count[counter]++; 938 if (hide_user_symbols)
831 record_precise_ip(syme, counter, ip);
832 pthread_mutex_lock(&active_symbols_lock);
833 if (list_empty(&syme->node) || !syme->node.next)
834 __list_insert_active_sym(syme);
835 pthread_mutex_unlock(&active_symbols_lock);
836 return; 939 return;
837 } 940 break;
941 case PERF_RECORD_MISC_KERNEL:
942 if (hide_kernel_symbols)
943 return;
944 break;
945 default:
946 return;
838 } 947 }
839 948
840 samples--; 949 if (event__preprocess_sample(self, &al, symbol_filter) < 0 ||
950 al.sym == NULL)
951 return;
952
953 syme = symbol__priv(al.sym);
954 if (!syme->skip) {
955 syme->count[counter]++;
956 syme->origin = origin;
957 record_precise_ip(syme, counter, ip);
958 pthread_mutex_lock(&active_symbols_lock);
959 if (list_empty(&syme->node) || !syme->node.next)
960 __list_insert_active_sym(syme);
961 pthread_mutex_unlock(&active_symbols_lock);
962 if (origin == PERF_RECORD_MISC_USER)
963 ++userspace_samples;
964 ++samples;
965 }
841} 966}
842 967
843static void process_event(u64 ip, int counter, int user) 968static int event__process(event_t *event)
844{ 969{
845 samples++; 970 switch (event->header.type) {
846 971 case PERF_RECORD_COMM:
847 if (user) { 972 event__process_comm(event);
848 userspace_samples++; 973 break;
849 return; 974 case PERF_RECORD_MMAP:
975 event__process_mmap(event);
976 break;
977 default:
978 break;
850 } 979 }
851 980
852 record_ip(ip, counter); 981 return 0;
853} 982}
854 983
855struct mmap_data { 984struct mmap_data {
@@ -870,8 +999,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
870 return head; 999 return head;
871} 1000}
872 1001
873struct timeval last_read, this_read;
874
875static void mmap_read_counter(struct mmap_data *md) 1002static void mmap_read_counter(struct mmap_data *md)
876{ 1003{
877 unsigned int head = mmap_read_head(md); 1004 unsigned int head = mmap_read_head(md);
@@ -879,8 +1006,6 @@ static void mmap_read_counter(struct mmap_data *md)
879 unsigned char *data = md->base + page_size; 1006 unsigned char *data = md->base + page_size;
880 int diff; 1007 int diff;
881 1008
882 gettimeofday(&this_read, NULL);
883
884 /* 1009 /*
885 * If we're further behind than half the buffer, there's a chance 1010 * If we're further behind than half the buffer, there's a chance
886 * the writer will bite our tail and mess up the samples under us. 1011 * the writer will bite our tail and mess up the samples under us.
@@ -891,14 +1016,7 @@ static void mmap_read_counter(struct mmap_data *md)
891 */ 1016 */
892 diff = head - old; 1017 diff = head - old;
893 if (diff > md->mask / 2 || diff < 0) { 1018 if (diff > md->mask / 2 || diff < 0) {
894 struct timeval iv; 1019 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
895 unsigned long msecs;
896
897 timersub(&this_read, &last_read, &iv);
898 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
899
900 fprintf(stderr, "WARNING: failed to keep up with mmap data."
901 " Last read %lu msecs ago.\n", msecs);
902 1020
903 /* 1021 /*
904 * head points to a known good entry, start there. 1022 * head points to a known good entry, start there.
@@ -906,8 +1024,6 @@ static void mmap_read_counter(struct mmap_data *md)
906 old = head; 1024 old = head;
907 } 1025 }
908 1026
909 last_read = this_read;
910
911 for (; old != head;) { 1027 for (; old != head;) {
912 event_t *event = (event_t *)&data[old & md->mask]; 1028 event_t *event = (event_t *)&data[old & md->mask];
913 1029
@@ -935,13 +1051,11 @@ static void mmap_read_counter(struct mmap_data *md)
935 event = &event_copy; 1051 event = &event_copy;
936 } 1052 }
937 1053
1054 if (event->header.type == PERF_RECORD_SAMPLE)
1055 event__process_sample(event, md->counter);
1056 else
1057 event__process(event);
938 old += size; 1058 old += size;
939
940 if (event->header.type == PERF_RECORD_SAMPLE) {
941 int user =
942 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
943 process_event(event->ip.ip, md->counter, user);
944 }
945 } 1059 }
946 1060
947 md->prev = old; 1061 md->prev = old;
@@ -983,6 +1097,7 @@ static void start_counter(int i, int counter)
983 } 1097 }
984 1098
985 attr->inherit = (cpu < 0) && inherit; 1099 attr->inherit = (cpu < 0) && inherit;
1100 attr->mmap = 1;
986 1101
987try_again: 1102try_again:
988 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1103 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -990,7 +1105,7 @@ try_again:
990 if (fd[i][counter] < 0) { 1105 if (fd[i][counter] < 0) {
991 int err = errno; 1106 int err = errno;
992 1107
993 if (err == EPERM) 1108 if (err == EPERM || err == EACCES)
994 die("No permission - are you root?\n"); 1109 die("No permission - are you root?\n");
995 /* 1110 /*
996 * If it's cycles then fall back to hrtimer 1111 * If it's cycles then fall back to hrtimer
@@ -1041,6 +1156,11 @@ static int __cmd_top(void)
1041 int i, counter; 1156 int i, counter;
1042 int ret; 1157 int ret;
1043 1158
1159 if (target_pid != -1)
1160 event__synthesize_thread(target_pid, event__process);
1161 else
1162 event__synthesize_threads(event__process);
1163
1044 for (i = 0; i < nr_cpus; i++) { 1164 for (i = 0; i < nr_cpus; i++) {
1045 group_fd = -1; 1165 group_fd = -1;
1046 for (counter = 0; counter < nr_counters; counter++) 1166 for (counter = 0; counter < nr_counters; counter++)
@@ -1096,7 +1216,10 @@ static const struct option options[] = {
1096 "system-wide collection from all CPUs"), 1216 "system-wide collection from all CPUs"),
1097 OPT_INTEGER('C', "CPU", &profile_cpu, 1217 OPT_INTEGER('C', "CPU", &profile_cpu,
1098 "CPU to profile on"), 1218 "CPU to profile on"),
1099 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1219 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1220 "file", "vmlinux pathname"),
1221 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1222 "hide kernel symbols"),
1100 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1223 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1101 "number of mmap data pages"), 1224 "number of mmap data pages"),
1102 OPT_INTEGER('r', "realtime", &realtime_prio, 1225 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1119,6 +1242,8 @@ static const struct option options[] = {
1119 "profile at this frequency"), 1242 "profile at this frequency"),
1120 OPT_INTEGER('E', "entries", &print_entries, 1243 OPT_INTEGER('E', "entries", &print_entries,
1121 "display this many functions"), 1244 "display this many functions"),
1245 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1246 "hide user symbols"),
1122 OPT_BOOLEAN('v', "verbose", &verbose, 1247 OPT_BOOLEAN('v', "verbose", &verbose,
1123 "be more verbose (show counter open errors, etc)"), 1248 "be more verbose (show counter open errors, etc)"),
1124 OPT_END() 1249 OPT_END()
@@ -1128,8 +1253,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1128{ 1253{
1129 int counter; 1254 int counter;
1130 1255
1131 symbol__init();
1132
1133 page_size = sysconf(_SC_PAGE_SIZE); 1256 page_size = sysconf(_SC_PAGE_SIZE);
1134 1257
1135 argc = parse_options(argc, argv, options, top_usage, 0); 1258 argc = parse_options(argc, argv, options, top_usage, 0);
@@ -1146,13 +1269,18 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1146 if (!nr_counters) 1269 if (!nr_counters)
1147 nr_counters = 1; 1270 nr_counters = 1;
1148 1271
1272 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1273 (nr_counters + 1) * sizeof(unsigned long));
1274 if (symbol_conf.vmlinux_name == NULL)
1275 symbol_conf.try_vmlinux_path = true;
1276 if (symbol__init(&symbol_conf) < 0)
1277 return -1;
1278
1149 if (delay_secs < 1) 1279 if (delay_secs < 1)
1150 delay_secs = 1; 1280 delay_secs = 1;
1151 1281
1152 parse_symbols();
1153 parse_source(sym_filter_entry); 1282 parse_source(sym_filter_entry);
1154 1283
1155
1156 /* 1284 /*
1157 * User specified count overrides default frequency. 1285 * User specified count overrides default frequency.
1158 */ 1286 */
@@ -1182,5 +1310,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1182 if (target_pid != -1 || profile_cpu != -1) 1310 if (target_pid != -1 || profile_cpu != -1)
1183 nr_cpus = 1; 1311 nr_cpus = 1;
1184 1312
1313 get_term_dimensions(&winsize);
1314 if (print_entries == 0) {
1315 update_print_entries(&winsize);
1316 signal(SIGWINCH, sig_winch_handler);
1317 }
1318
1185 return __cmd_top(); 1319 return __cmd_top();
1186} 1320}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index fb3f3c220211..abb914aa7be6 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -5,63 +5,73 @@
5#include "util/symbol.h" 5#include "util/symbol.h"
6#include "util/thread.h" 6#include "util/thread.h"
7#include "util/header.h" 7#include "util/header.h"
8#include "util/exec_cmd.h"
9#include "util/trace-event.h"
8 10
9#include "util/parse-options.h" 11static char const *script_name;
12static char const *generate_script_lang;
10 13
11#include "perf.h" 14static int default_start_script(const char *script __attribute((unused)))
12#include "util/debug.h" 15{
16 return 0;
17}
13 18
14#include "util/trace-event.h" 19static int default_stop_script(void)
15#include "util/data_map.h" 20{
21 return 0;
22}
16 23
17static char const *input_name = "perf.data"; 24static int default_generate_script(const char *outfile __attribute ((unused)))
25{
26 return 0;
27}
18 28
19static unsigned long total = 0; 29static struct scripting_ops default_scripting_ops = {
20static unsigned long total_comm = 0; 30 .start_script = default_start_script,
31 .stop_script = default_stop_script,
32 .process_event = print_event,
33 .generate_script = default_generate_script,
34};
21 35
22static struct rb_root threads; 36static struct scripting_ops *scripting_ops;
23static struct thread *last_match;
24 37
25static struct perf_header *header; 38static void setup_scripting(void)
26static u64 sample_type; 39{
40 /* make sure PERF_EXEC_PATH is set for scripts */
41 perf_set_argv_exec_path(perf_exec_path());
27 42
28static char *cwd; 43 setup_perl_scripting();
29static int cwdlen;
30 44
45 scripting_ops = &default_scripting_ops;
46}
31 47
32static int 48static int cleanup_scripting(void)
33process_comm_event(event_t *event, unsigned long offset, unsigned long head)
34{ 49{
35 struct thread *thread; 50 return scripting_ops->stop_script();
51}
36 52
37 thread = threads__findnew(event->comm.pid, &threads, &last_match); 53#include "util/parse-options.h"
38 54
39 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 55#include "perf.h"
40 (void *)(offset + head), 56#include "util/debug.h"
41 (void *)(long)(event->header.size),
42 event->comm.comm, event->comm.pid);
43 57
44 if (thread == NULL || 58#include "util/trace-event.h"
45 thread__set_comm(thread, event->comm.comm)) { 59#include "util/data_map.h"
46 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 60#include "util/exec_cmd.h"
47 return -1;
48 }
49 total_comm++;
50 61
51 return 0; 62static char const *input_name = "perf.data";
52} 63
64static struct perf_header *header;
65static u64 sample_type;
53 66
54static int 67static int process_sample_event(event_t *event)
55process_sample_event(event_t *event, unsigned long offset, unsigned long head)
56{ 68{
57 struct thread *thread;
58 u64 ip = event->ip.ip; 69 u64 ip = event->ip.ip;
59 u64 timestamp = -1; 70 u64 timestamp = -1;
60 u32 cpu = -1; 71 u32 cpu = -1;
61 u64 period = 1; 72 u64 period = 1;
62 void *more_data = event->ip.__more_data; 73 void *more_data = event->ip.__more_data;
63 74 struct thread *thread = threads__findnew(event->ip.pid);
64 thread = threads__findnew(event->ip.pid, &threads, &last_match);
65 75
66 if (sample_type & PERF_SAMPLE_TIME) { 76 if (sample_type & PERF_SAMPLE_TIME) {
67 timestamp = *(u64 *)more_data; 77 timestamp = *(u64 *)more_data;
@@ -79,22 +89,20 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
79 more_data += sizeof(u64); 89 more_data += sizeof(u64);
80 } 90 }
81 91
82 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 92 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
83 (void *)(offset + head),
84 (void *)(long)(event->header.size),
85 event->header.misc, 93 event->header.misc,
86 event->ip.pid, event->ip.tid, 94 event->ip.pid, event->ip.tid,
87 (void *)(long)ip, 95 (void *)(long)ip,
88 (long long)period); 96 (long long)period);
89 97
90 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
91
92 if (thread == NULL) { 98 if (thread == NULL) {
93 eprintf("problem processing %d event, skipping it.\n", 99 pr_debug("problem processing %d event, skipping it.\n",
94 event->header.type); 100 event->header.type);
95 return -1; 101 return -1;
96 } 102 }
97 103
104 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
105
98 if (sample_type & PERF_SAMPLE_RAW) { 106 if (sample_type & PERF_SAMPLE_RAW) {
99 struct { 107 struct {
100 u32 size; 108 u32 size;
@@ -106,9 +114,10 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
106 * field, although it should be the same than this perf 114 * field, although it should be the same than this perf
107 * event pid 115 * event pid
108 */ 116 */
109 print_event(cpu, raw->data, raw->size, timestamp, thread->comm); 117 scripting_ops->process_event(cpu, raw->data, raw->size,
118 timestamp, thread->comm);
110 } 119 }
111 total += period; 120 event__stats.total += period;
112 121
113 return 0; 122 return 0;
114} 123}
@@ -129,16 +138,165 @@ static int sample_type_check(u64 type)
129 138
130static struct perf_file_handler file_handler = { 139static struct perf_file_handler file_handler = {
131 .process_sample_event = process_sample_event, 140 .process_sample_event = process_sample_event,
132 .process_comm_event = process_comm_event, 141 .process_comm_event = event__process_comm,
133 .sample_type_check = sample_type_check, 142 .sample_type_check = sample_type_check,
134}; 143};
135 144
136static int __cmd_trace(void) 145static int __cmd_trace(void)
137{ 146{
138 register_idle_thread(&threads, &last_match); 147 register_idle_thread();
139 register_perf_file_handler(&file_handler); 148 register_perf_file_handler(&file_handler);
140 149
141 return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); 150 return mmap_dispatch_perf_file(&header, input_name,
151 0, 0, &event__cwdlen, &event__cwd);
152}
153
154struct script_spec {
155 struct list_head node;
156 struct scripting_ops *ops;
157 char spec[0];
158};
159
160LIST_HEAD(script_specs);
161
162static struct script_spec *script_spec__new(const char *spec,
163 struct scripting_ops *ops)
164{
165 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
166
167 if (s != NULL) {
168 strcpy(s->spec, spec);
169 s->ops = ops;
170 }
171
172 return s;
173}
174
175static void script_spec__delete(struct script_spec *s)
176{
177 free(s->spec);
178 free(s);
179}
180
181static void script_spec__add(struct script_spec *s)
182{
183 list_add_tail(&s->node, &script_specs);
184}
185
186static struct script_spec *script_spec__find(const char *spec)
187{
188 struct script_spec *s;
189
190 list_for_each_entry(s, &script_specs, node)
191 if (strcasecmp(s->spec, spec) == 0)
192 return s;
193 return NULL;
194}
195
196static struct script_spec *script_spec__findnew(const char *spec,
197 struct scripting_ops *ops)
198{
199 struct script_spec *s = script_spec__find(spec);
200
201 if (s)
202 return s;
203
204 s = script_spec__new(spec, ops);
205 if (!s)
206 goto out_delete_spec;
207
208 script_spec__add(s);
209
210 return s;
211
212out_delete_spec:
213 script_spec__delete(s);
214
215 return NULL;
216}
217
218int script_spec_register(const char *spec, struct scripting_ops *ops)
219{
220 struct script_spec *s;
221
222 s = script_spec__find(spec);
223 if (s)
224 return -1;
225
226 s = script_spec__findnew(spec, ops);
227 if (!s)
228 return -1;
229
230 return 0;
231}
232
233static struct scripting_ops *script_spec__lookup(const char *spec)
234{
235 struct script_spec *s = script_spec__find(spec);
236 if (!s)
237 return NULL;
238
239 return s->ops;
240}
241
242static void list_available_languages(void)
243{
244 struct script_spec *s;
245
246 fprintf(stderr, "\n");
247 fprintf(stderr, "Scripting language extensions (used in "
248 "perf trace -s [spec:]script.[spec]):\n\n");
249
250 list_for_each_entry(s, &script_specs, node)
251 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
252
253 fprintf(stderr, "\n");
254}
255
256static int parse_scriptname(const struct option *opt __used,
257 const char *str, int unset __used)
258{
259 char spec[PATH_MAX];
260 const char *script, *ext;
261 int len;
262
263 if (strcmp(str, "list") == 0) {
264 list_available_languages();
265 return 0;
266 }
267
268 script = strchr(str, ':');
269 if (script) {
270 len = script - str;
271 if (len >= PATH_MAX) {
272 fprintf(stderr, "invalid language specifier");
273 return -1;
274 }
275 strncpy(spec, str, len);
276 spec[len] = '\0';
277 scripting_ops = script_spec__lookup(spec);
278 if (!scripting_ops) {
279 fprintf(stderr, "invalid language specifier");
280 return -1;
281 }
282 script++;
283 } else {
284 script = str;
285 ext = strchr(script, '.');
286 if (!ext) {
287 fprintf(stderr, "invalid script extension");
288 return -1;
289 }
290 scripting_ops = script_spec__lookup(++ext);
291 if (!scripting_ops) {
292 fprintf(stderr, "invalid script extension");
293 return -1;
294 }
295 }
296
297 script_name = strdup(script);
298
299 return 0;
142} 300}
143 301
144static const char * const annotate_usage[] = { 302static const char * const annotate_usage[] = {
@@ -151,12 +309,24 @@ static const struct option options[] = {
151 "dump raw trace in ASCII"), 309 "dump raw trace in ASCII"),
152 OPT_BOOLEAN('v', "verbose", &verbose, 310 OPT_BOOLEAN('v', "verbose", &verbose,
153 "be more verbose (show symbol address, etc)"), 311 "be more verbose (show symbol address, etc)"),
312 OPT_BOOLEAN('l', "latency", &latency_format,
313 "show latency attributes (irqs/preemption disabled, etc)"),
314 OPT_CALLBACK('s', "script", NULL, "name",
315 "script file name (lang:script name, script name, or *)",
316 parse_scriptname),
317 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
318 "generate perf-trace.xx script in specified language"),
319
154 OPT_END() 320 OPT_END()
155}; 321};
156 322
157int cmd_trace(int argc, const char **argv, const char *prefix __used) 323int cmd_trace(int argc, const char **argv, const char *prefix __used)
158{ 324{
159 symbol__init(); 325 int err;
326
327 symbol__init(0);
328
329 setup_scripting();
160 330
161 argc = parse_options(argc, argv, options, annotate_usage, 0); 331 argc = parse_options(argc, argv, options, annotate_usage, 0);
162 if (argc) { 332 if (argc) {
@@ -170,5 +340,50 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
170 340
171 setup_pager(); 341 setup_pager();
172 342
173 return __cmd_trace(); 343 if (generate_script_lang) {
344 struct stat perf_stat;
345
346 int input = open(input_name, O_RDONLY);
347 if (input < 0) {
348 perror("failed to open file");
349 exit(-1);
350 }
351
352 err = fstat(input, &perf_stat);
353 if (err < 0) {
354 perror("failed to stat file");
355 exit(-1);
356 }
357
358 if (!perf_stat.st_size) {
359 fprintf(stderr, "zero-sized file, nothing to do!\n");
360 exit(0);
361 }
362
363 scripting_ops = script_spec__lookup(generate_script_lang);
364 if (!scripting_ops) {
365 fprintf(stderr, "invalid language specifier");
366 return -1;
367 }
368
369 header = perf_header__new();
370 if (header == NULL)
371 return -1;
372
373 perf_header__read(header, input);
374 err = scripting_ops->generate_script("perf-trace");
375 goto out;
376 }
377
378 if (script_name) {
379 err = scripting_ops->start_script(script_name);
380 if (err)
381 goto out;
382 }
383
384 err = __cmd_trace();
385
386 cleanup_scripting();
387out:
388 return err;
174} 389}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index e11d8d231c3b..a3d8bf65f26c 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -15,6 +15,8 @@ extern int read_line_with_nul(char *buf, int size, FILE *file);
15extern int check_pager_config(const char *cmd); 15extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 20extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix); 21extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix); 22extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -25,5 +27,7 @@ extern int cmd_timechart(int argc, const char **argv, const char *prefix);
25extern int cmd_top(int argc, const char **argv, const char *prefix); 27extern int cmd_top(int argc, const char **argv, const char *prefix);
26extern int cmd_trace(int argc, const char **argv, const char *prefix); 28extern int cmd_trace(int argc, const char **argv, const char *prefix);
27extern int cmd_version(int argc, const char **argv, const char *prefix); 29extern int cmd_version(int argc, const char **argv, const char *prefix);
30extern int cmd_probe(int argc, const char **argv, const char *prefix);
31extern int cmd_kmem(int argc, const char **argv, const char *prefix);
28 32
29#endif 33#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00326e230d87..02b09ea17a3e 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,6 +3,8 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-bench mainporcelain common
7perf-buildid-list mainporcelain common
6perf-list mainporcelain common 8perf-list mainporcelain common
7perf-sched mainporcelain common 9perf-sched mainporcelain common
8perf-record mainporcelain common 10perf-record mainporcelain common
@@ -11,3 +13,5 @@ perf-stat mainporcelain common
11perf-timechart mainporcelain common 13perf-timechart mainporcelain common
12perf-top mainporcelain common 14perf-top mainporcelain common
13perf-trace mainporcelain common 15perf-trace mainporcelain common
16perf-probe mainporcelain common
17perf-kmem mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index fdd42a824c98..f000c30877ac 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -137,6 +137,8 @@ enum sw_event_ids {
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, 139 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
140 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
141 PERF_COUNT_SW_EMULATION_FAULTS = 8,
140}; 142};
141 143
142Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event 144Counters of the type PERF_TYPE_TRACEPOINT are available when the ftrace event
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 19fc7feb9d59..cf64049bc9bd 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -14,6 +14,7 @@
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/string.h" 16#include "util/string.h"
17#include "util/debugfs.h"
17 18
18const char perf_usage_string[] = 19const char perf_usage_string[] =
19 "perf [--version] [--help] COMMAND [ARGS]"; 20 "perf [--version] [--help] COMMAND [ARGS]";
@@ -89,8 +90,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
89 /* 90 /*
90 * Check remaining flags. 91 * Check remaining flags.
91 */ 92 */
92 if (!prefixcmp(cmd, "--exec-path")) { 93 if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
93 cmd += 11; 94 cmd += strlen(CMD_EXEC_PATH);
94 if (*cmd == '=') 95 if (*cmd == '=')
95 perf_set_argv_exec_path(cmd + 1); 96 perf_set_argv_exec_path(cmd + 1);
96 else { 97 else {
@@ -117,8 +118,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
117 (*argv)++; 118 (*argv)++;
118 (*argc)--; 119 (*argc)--;
119 handled++; 120 handled++;
120 } else if (!prefixcmp(cmd, "--perf-dir=")) { 121 } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
121 setenv(PERF_DIR_ENVIRONMENT, cmd + 10, 1); 122 setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
122 if (envchanged) 123 if (envchanged)
123 *envchanged = 1; 124 *envchanged = 1;
124 } else if (!strcmp(cmd, "--work-tree")) { 125 } else if (!strcmp(cmd, "--work-tree")) {
@@ -131,8 +132,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
131 *envchanged = 1; 132 *envchanged = 1;
132 (*argv)++; 133 (*argv)++;
133 (*argc)--; 134 (*argc)--;
134 } else if (!prefixcmp(cmd, "--work-tree=")) { 135 } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
135 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + 12, 1); 136 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
136 if (envchanged) 137 if (envchanged)
137 *envchanged = 1; 138 *envchanged = 1;
138 } else if (!strcmp(cmd, "--debugfs-dir")) { 139 } else if (!strcmp(cmd, "--debugfs-dir")) {
@@ -146,8 +147,8 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
146 *envchanged = 1; 147 *envchanged = 1;
147 (*argv)++; 148 (*argv)++;
148 (*argc)--; 149 (*argc)--;
149 } else if (!prefixcmp(cmd, "--debugfs-dir=")) { 150 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
150 strncpy(debugfs_mntpt, cmd + 14, MAXPATHLEN); 151 strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN);
151 debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 152 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
152 if (envchanged) 153 if (envchanged)
153 *envchanged = 1; 154 *envchanged = 1;
@@ -284,17 +285,21 @@ static void handle_internal_command(int argc, const char **argv)
284{ 285{
285 const char *cmd = argv[0]; 286 const char *cmd = argv[0];
286 static struct cmd_struct commands[] = { 287 static struct cmd_struct commands[] = {
287 { "help", cmd_help, 0 }, 288 { "buildid-list", cmd_buildid_list, 0 },
288 { "list", cmd_list, 0 }, 289 { "help", cmd_help, 0 },
289 { "record", cmd_record, 0 }, 290 { "list", cmd_list, 0 },
290 { "report", cmd_report, 0 }, 291 { "record", cmd_record, 0 },
291 { "stat", cmd_stat, 0 }, 292 { "report", cmd_report, 0 },
292 { "timechart", cmd_timechart, 0 }, 293 { "bench", cmd_bench, 0 },
293 { "top", cmd_top, 0 }, 294 { "stat", cmd_stat, 0 },
294 { "annotate", cmd_annotate, 0 }, 295 { "timechart", cmd_timechart, 0 },
295 { "version", cmd_version, 0 }, 296 { "top", cmd_top, 0 },
296 { "trace", cmd_trace, 0 }, 297 { "annotate", cmd_annotate, 0 },
297 { "sched", cmd_sched, 0 }, 298 { "version", cmd_version, 0 },
299 { "trace", cmd_trace, 0 },
300 { "sched", cmd_sched, 0 },
301 { "probe", cmd_probe, 0 },
302 { "kmem", cmd_kmem, 0 },
298 }; 303 };
299 unsigned int i; 304 unsigned int i;
300 static const char ext[] = STRIP_EXTENSION; 305 static const char ext[] = STRIP_EXTENSION;
@@ -382,45 +387,12 @@ static int run_argv(int *argcp, const char ***argv)
382/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 387/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
383static void get_debugfs_mntpt(void) 388static void get_debugfs_mntpt(void)
384{ 389{
385 FILE *file; 390 const char *path = debugfs_find_mountpoint();
386 char fs_type[100];
387 char debugfs[MAXPATHLEN];
388 391
389 /* 392 if (path)
390 * try the standard location 393 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
391 */ 394 else
392 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) { 395 debugfs_mntpt[0] = '\0';
393 strcpy(debugfs_mntpt, "/sys/kernel/debug/");
394 return;
395 }
396
397 /*
398 * try the sane location
399 */
400 if (valid_debugfs_mount("/debug/") == 0) {
401 strcpy(debugfs_mntpt, "/debug/");
402 return;
403 }
404
405 /*
406 * give up and parse /proc/mounts
407 */
408 file = fopen("/proc/mounts", "r");
409 if (file == NULL)
410 return;
411
412 while (fscanf(file, "%*s %"
413 STR(MAXPATHLEN)
414 "s %99s %*s %*d %*d\n",
415 debugfs, fs_type) == 2) {
416 if (strcmp(fs_type, "debugfs") == 0)
417 break;
418 }
419 fclose(file);
420 if (strcmp(fs_type, "debugfs") == 0) {
421 strncpy(debugfs_mntpt, debugfs, MAXPATHLEN);
422 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
423 }
424} 396}
425 397
426int main(int argc, const char **argv) 398int main(int argc, const char **argv)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 8cc4623afd6f..454d5d55f32d 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -47,6 +47,18 @@
47#define cpu_relax() asm volatile("":::"memory") 47#define cpu_relax() asm volatile("":::"memory")
48#endif 48#endif
49 49
50#ifdef __alpha__
51#include "../../arch/alpha/include/asm/unistd.h"
52#define rmb() asm volatile("mb" ::: "memory")
53#define cpu_relax() asm volatile("" ::: "memory")
54#endif
55
56#ifdef __ia64__
57#include "../../arch/ia64/include/asm/unistd.h"
58#define rmb() asm volatile ("mf" ::: "memory")
59#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
60#endif
61
50#include <time.h> 62#include <time.h>
51#include <unistd.h> 63#include <unistd.h>
52#include <sys/types.h> 64#include <sys/types.h>
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
new file mode 100644
index 000000000000..af78d9a52a7d
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -0,0 +1,134 @@
1/*
2 * This file was generated automatically by ExtUtils::ParseXS version 2.18_02 from the
3 * contents of Context.xs. Do not edit this file, edit Context.xs instead.
4 *
5 * ANY CHANGES MADE HERE WILL BE LOST!
6 *
7 */
8
9#line 1 "Context.xs"
10/*
11 * Context.xs. XS interfaces for perf trace.
12 *
13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 */
30
31#include "EXTERN.h"
32#include "perl.h"
33#include "XSUB.h"
34#include "../../../util/trace-event-perl.h"
35
36#ifndef PERL_UNUSED_VAR
37# define PERL_UNUSED_VAR(var) if (0) var = var
38#endif
39
40#line 41 "Context.c"
41
42XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
43XS(XS_Perf__Trace__Context_common_pc)
44{
45#ifdef dVAR
46 dVAR; dXSARGS;
47#else
48 dXSARGS;
49#endif
50 if (items != 1)
51 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_pc", "context");
52 PERL_UNUSED_VAR(cv); /* -W */
53 {
54 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
55 int RETVAL;
56 dXSTARG;
57
58 RETVAL = common_pc(context);
59 XSprePUSH; PUSHi((IV)RETVAL);
60 }
61 XSRETURN(1);
62}
63
64
65XS(XS_Perf__Trace__Context_common_flags); /* prototype to pass -Wmissing-prototypes */
66XS(XS_Perf__Trace__Context_common_flags)
67{
68#ifdef dVAR
69 dVAR; dXSARGS;
70#else
71 dXSARGS;
72#endif
73 if (items != 1)
74 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_flags", "context");
75 PERL_UNUSED_VAR(cv); /* -W */
76 {
77 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
78 int RETVAL;
79 dXSTARG;
80
81 RETVAL = common_flags(context);
82 XSprePUSH; PUSHi((IV)RETVAL);
83 }
84 XSRETURN(1);
85}
86
87
88XS(XS_Perf__Trace__Context_common_lock_depth); /* prototype to pass -Wmissing-prototypes */
89XS(XS_Perf__Trace__Context_common_lock_depth)
90{
91#ifdef dVAR
92 dVAR; dXSARGS;
93#else
94 dXSARGS;
95#endif
96 if (items != 1)
97 Perl_croak(aTHX_ "Usage: %s(%s)", "Perf::Trace::Context::common_lock_depth", "context");
98 PERL_UNUSED_VAR(cv); /* -W */
99 {
100 struct scripting_context * context = INT2PTR(struct scripting_context *,SvIV(ST(0)));
101 int RETVAL;
102 dXSTARG;
103
104 RETVAL = common_lock_depth(context);
105 XSprePUSH; PUSHi((IV)RETVAL);
106 }
107 XSRETURN(1);
108}
109
110#ifdef __cplusplus
111extern "C"
112#endif
113XS(boot_Perf__Trace__Context); /* prototype to pass -Wmissing-prototypes */
114XS(boot_Perf__Trace__Context)
115{
116#ifdef dVAR
117 dVAR; dXSARGS;
118#else
119 dXSARGS;
120#endif
121 const char* file = __FILE__;
122
123 PERL_UNUSED_VAR(cv); /* -W */
124 PERL_UNUSED_VAR(items); /* -W */
125 XS_VERSION_BOOTCHECK ;
126
127 newXSproto("Perf::Trace::Context::common_pc", XS_Perf__Trace__Context_common_pc, file, "$");
128 newXSproto("Perf::Trace::Context::common_flags", XS_Perf__Trace__Context_common_flags, file, "$");
129 newXSproto("Perf::Trace::Context::common_lock_depth", XS_Perf__Trace__Context_common_lock_depth, file, "$");
130 if (PL_unitcheckav)
131 call_list(PL_scopestack_ix, PL_unitcheckav);
132 XSRETURN_YES;
133}
134
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
new file mode 100644
index 000000000000..fb78006c165e
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -0,0 +1,41 @@
1/*
2 * Context.xs. XS interfaces for perf trace.
3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "EXTERN.h"
23#include "perl.h"
24#include "XSUB.h"
25#include "../../../util/trace-event-perl.h"
26
27MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
28PROTOTYPES: ENABLE
29
30int
31common_pc(context)
32 struct scripting_context * context
33
34int
35common_flags(context)
36 struct scripting_context * context
37
38int
39common_lock_depth(context)
40 struct scripting_context * context
41
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
new file mode 100644
index 000000000000..decdeb0f6789
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Makefile.PL
@@ -0,0 +1,17 @@
1use 5.010000;
2use ExtUtils::MakeMaker;
3# See lib/ExtUtils/MakeMaker.pm for details of how to influence
4# the contents of the Makefile that is written.
5WriteMakefile(
6 NAME => 'Perf::Trace::Context',
7 VERSION_FROM => 'lib/Perf/Trace/Context.pm', # finds $VERSION
8 PREREQ_PM => {}, # e.g., Module::Name => 1.1
9 ($] >= 5.005 ? ## Add these new keywords supported since 5.005
10 (ABSTRACT_FROM => 'lib/Perf/Trace/Context.pm', # retrieve abstract from module
11 AUTHOR => 'Tom Zanussi <tzanussi@gmail.com>') : ()),
12 LIBS => [''], # e.g., '-lm'
13 DEFINE => '-I ../..', # e.g., '-DHAVE_SOMETHING'
14 INC => '-I.', # e.g., '-I. -I/usr/include/other'
15 # Un-comment this if you add C files to link with later:
16 OBJECT => 'Context.o', # link all the C files too
17);
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
new file mode 100644
index 000000000000..9a9707630791
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/README
@@ -0,0 +1,59 @@
1Perf-Trace-Util version 0.01
2============================
3
4This module contains utility functions for use with perf trace.
5
6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
7that the core perf support for Perl calls on and should always be
8'used', while Util.pm contains useful but optional utility functions
9that scripts may want to use. Context.pm contains the Perl->C
10interface that allows scripts to access data in the embedding perf
11executable; scripts wishing to do that should 'use Context.pm'.
12
13The Perl->C perf interface is completely driven by Context.xs. If you
14want to add new Perl functions that end up accessing C data in the
15perf executable, you add desciptions of the new functions here.
16scripting_context is a pointer to the perf data in the perf executable
17that you want to access - it's passed as the second parameter,
18$context, to all handler functions.
19
20After you do that:
21
22 perl Makefile.PL # to create a Makefile for the next step
23 make # to create Context.c
24
25 edit Context.c to add const to the char* file = __FILE__ line in
26 XS(boot_Perf__Trace__Context) to silence a warning/error.
27
28 You can delete the Makefile, object files and anything else that was
29 generated e.g. blib and shared library, etc, except for of course
30 Context.c
31
32 You should then be able to run the normal perf make as usual.
33
34INSTALLATION
35
36Building perf with perf trace Perl scripting should install this
37module in the right place.
38
39You should make sure libperl and ExtUtils/Embed.pm are installed first
40e.g. apt-get install libperl-dev or yum install perl-ExtUtils-Embed.
41
42DEPENDENCIES
43
44This module requires these other modules and libraries:
45
46 None
47
48COPYRIGHT AND LICENCE
49
50Copyright (C) 2009 by Tom Zanussi <tzanussi@gmail.com>
51
52This library is free software; you can redistribute it and/or modify
53it under the same terms as Perl itself, either Perl version 5.10.0 or,
54at your option, any later version of Perl 5 you may have available.
55
56Alternatively, this software may be distributed under the terms of the
57GNU General Public License ("GPL") version 2 as published by the Free
58Software Foundation.
59
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
new file mode 100644
index 000000000000..6c7f3659cb17
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
@@ -0,0 +1,55 @@
1package Perf::Trace::Context;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17 common_pc common_flags common_lock_depth
18);
19
20our $VERSION = '0.01';
21
22require XSLoader;
23XSLoader::load('Perf::Trace::Context', $VERSION);
24
251;
26__END__
27=head1 NAME
28
29Perf::Trace::Context - Perl extension for accessing functions in perf.
30
31=head1 SYNOPSIS
32
33 use Perf::Trace::Context;
34
35=head1 SEE ALSO
36
37Perf (trace) documentation
38
39=head1 AUTHOR
40
41Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
42
43=head1 COPYRIGHT AND LICENSE
44
45Copyright (C) 2009 by Tom Zanussi
46
47This library is free software; you can redistribute it and/or modify
48it under the same terms as Perl itself, either Perl version 5.10.0 or,
49at your option, any later version of Perl 5 you may have available.
50
51Alternatively, this software may be distributed under the terms of the
52GNU General Public License ("GPL") version 2 as published by the Free
53Software Foundation.
54
55=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
new file mode 100644
index 000000000000..9df376a9f629
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
@@ -0,0 +1,192 @@
1package Perf::Trace::Core;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17define_flag_field define_flag_value flag_str dump_flag_fields
18define_symbolic_field define_symbolic_value symbol_str dump_symbolic_fields
19trace_flag_str
20);
21
22our $VERSION = '0.01';
23
24my %trace_flags = (0x00 => "NONE",
25 0x01 => "IRQS_OFF",
26 0x02 => "IRQS_NOSUPPORT",
27 0x04 => "NEED_RESCHED",
28 0x08 => "HARDIRQ",
29 0x10 => "SOFTIRQ");
30
31sub trace_flag_str
32{
33 my ($value) = @_;
34
35 my $string;
36
37 my $print_delim = 0;
38
39 foreach my $idx (sort {$a <=> $b} keys %trace_flags) {
40 if (!$value && !$idx) {
41 $string .= "NONE";
42 last;
43 }
44
45 if ($idx && ($value & $idx) == $idx) {
46 if ($print_delim) {
47 $string .= " | ";
48 }
49 $string .= "$trace_flags{$idx}";
50 $print_delim = 1;
51 $value &= ~$idx;
52 }
53 }
54
55 return $string;
56}
57
58my %flag_fields;
59my %symbolic_fields;
60
61sub flag_str
62{
63 my ($event_name, $field_name, $value) = @_;
64
65 my $string;
66
67 if ($flag_fields{$event_name}{$field_name}) {
68 my $print_delim = 0;
69 foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event_name}{$field_name}{"values"}}) {
70 if (!$value && !$idx) {
71 $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
72 last;
73 }
74 if ($idx && ($value & $idx) == $idx) {
75 if ($print_delim && $flag_fields{$event_name}{$field_name}{'delim'}) {
76 $string .= " $flag_fields{$event_name}{$field_name}{'delim'} ";
77 }
78 $string .= "$flag_fields{$event_name}{$field_name}{'values'}{$idx}";
79 $print_delim = 1;
80 $value &= ~$idx;
81 }
82 }
83 }
84
85 return $string;
86}
87
88sub define_flag_field
89{
90 my ($event_name, $field_name, $delim) = @_;
91
92 $flag_fields{$event_name}{$field_name}{"delim"} = $delim;
93}
94
95sub define_flag_value
96{
97 my ($event_name, $field_name, $value, $field_str) = @_;
98
99 $flag_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
100}
101
102sub dump_flag_fields
103{
104 for my $event (keys %flag_fields) {
105 print "event $event:\n";
106 for my $field (keys %{$flag_fields{$event}}) {
107 print " field: $field:\n";
108 print " delim: $flag_fields{$event}{$field}{'delim'}\n";
109 foreach my $idx (sort {$a <=> $b} keys %{$flag_fields{$event}{$field}{"values"}}) {
110 print " value $idx: $flag_fields{$event}{$field}{'values'}{$idx}\n";
111 }
112 }
113 }
114}
115
116sub symbol_str
117{
118 my ($event_name, $field_name, $value) = @_;
119
120 if ($symbolic_fields{$event_name}{$field_name}) {
121 foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event_name}{$field_name}{"values"}}) {
122 if (!$value && !$idx) {
123 return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
124 last;
125 }
126 if ($value == $idx) {
127 return "$symbolic_fields{$event_name}{$field_name}{'values'}{$idx}";
128 }
129 }
130 }
131
132 return undef;
133}
134
135sub define_symbolic_field
136{
137 my ($event_name, $field_name) = @_;
138
139 # nothing to do, really
140}
141
142sub define_symbolic_value
143{
144 my ($event_name, $field_name, $value, $field_str) = @_;
145
146 $symbolic_fields{$event_name}{$field_name}{"values"}{$value} = $field_str;
147}
148
149sub dump_symbolic_fields
150{
151 for my $event (keys %symbolic_fields) {
152 print "event $event:\n";
153 for my $field (keys %{$symbolic_fields{$event}}) {
154 print " field: $field:\n";
155 foreach my $idx (sort {$a <=> $b} keys %{$symbolic_fields{$event}{$field}{"values"}}) {
156 print " value $idx: $symbolic_fields{$event}{$field}{'values'}{$idx}\n";
157 }
158 }
159 }
160}
161
1621;
163__END__
164=head1 NAME
165
166Perf::Trace::Core - Perl extension for perf trace
167
168=head1 SYNOPSIS
169
170 use Perf::Trace::Core
171
172=head1 SEE ALSO
173
174Perf (trace) documentation
175
176=head1 AUTHOR
177
178Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
179
180=head1 COPYRIGHT AND LICENSE
181
182Copyright (C) 2009 by Tom Zanussi
183
184This library is free software; you can redistribute it and/or modify
185it under the same terms as Perl itself, either Perl version 5.10.0 or,
186at your option, any later version of Perl 5 you may have available.
187
188Alternatively, this software may be distributed under the terms of the
189GNU General Public License ("GPL") version 2 as published by the Free
190Software Foundation.
191
192=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
new file mode 100644
index 000000000000..052f132ced24
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
@@ -0,0 +1,88 @@
1package Perf::Trace::Util;
2
3use 5.010000;
4use strict;
5use warnings;
6
7require Exporter;
8
9our @ISA = qw(Exporter);
10
11our %EXPORT_TAGS = ( 'all' => [ qw(
12) ] );
13
14our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15
16our @EXPORT = qw(
17avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
18);
19
20our $VERSION = '0.01';
21
22sub avg
23{
24 my ($total, $n) = @_;
25
26 return $total / $n;
27}
28
29my $NSECS_PER_SEC = 1000000000;
30
31sub nsecs
32{
33 my ($secs, $nsecs) = @_;
34
35 return $secs * $NSECS_PER_SEC + $nsecs;
36}
37
38sub nsecs_secs {
39 my ($nsecs) = @_;
40
41 return $nsecs / $NSECS_PER_SEC;
42}
43
44sub nsecs_nsecs {
45 my ($nsecs) = @_;
46
47 return $nsecs - nsecs_secs($nsecs);
48}
49
50sub nsecs_str {
51 my ($nsecs) = @_;
52
53 my $str = sprintf("%5u.%09u", nsecs_secs($nsecs), nsecs_nsecs($nsecs));
54
55 return $str;
56}
57
581;
59__END__
60=head1 NAME
61
62Perf::Trace::Util - Perl extension for perf trace
63
64=head1 SYNOPSIS
65
66 use Perf::Trace::Util;
67
68=head1 SEE ALSO
69
70Perf (trace) documentation
71
72=head1 AUTHOR
73
74Tom Zanussi, E<lt>tzanussi@gmail.com<gt>
75
76=head1 COPYRIGHT AND LICENSE
77
78Copyright (C) 2009 by Tom Zanussi
79
80This library is free software; you can redistribute it and/or modify
81it under the same terms as Perl itself, either Perl version 5.10.0 or,
82at your option, any later version of Perl 5 you may have available.
83
84Alternatively, this software may be distributed under the terms of the
85GNU General Public License ("GPL") version 2 as published by the Free
86Software Foundation.
87
88=cut
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/typemap b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
new file mode 100644
index 000000000000..840836804aa7
--- /dev/null
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/typemap
@@ -0,0 +1 @@
struct scripting_context * T_PTR
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
new file mode 100644
index 000000000000..c7ec5de2f535
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-record
@@ -0,0 +1,7 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry
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
new file mode 100644
index 000000000000..89948b015020
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-report
@@ -0,0 +1,5 @@
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/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
new file mode 100644
index 000000000000..b25056ebf963
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
new file mode 100644
index 000000000000..f5dcf9cb5bd2
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -0,0 +1,5 @@
1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl
3
4
5
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
new file mode 100644
index 000000000000..8903979c5b6c
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
new file mode 100644
index 000000000000..cea16f78a3a2
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -0,0 +1,5 @@
1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
3
4
5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
new file mode 100644
index 000000000000..6abedda911a4
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -0,0 +1,6 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup
3
4
5
6
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
new file mode 100644
index 000000000000..85769dc456eb
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -0,0 +1,5 @@
1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
3
4
5
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
new file mode 100644
index 000000000000..fce6637b19ba
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
new file mode 100644
index 000000000000..aa68435be926
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
3
4
5
6
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
new file mode 100644
index 000000000000..4e7dc0a407a5
--- /dev/null
+++ b/tools/perf/scripts/perl/check-perf-trace.pl
@@ -0,0 +1,106 @@
1# perf trace event handlers, generated by perf trace -g perl
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, perl scripting support should be ok.
9
10use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
11use lib "./Perf-Trace-Util/lib";
12use Perf::Trace::Core;
13use Perf::Trace::Context;
14use Perf::Trace::Util;
15
16sub trace_begin
17{
18 print "trace_begin\n";
19}
20
21sub trace_end
22{
23 print "trace_end\n";
24
25 print_unhandled();
26}
27
28sub irq::softirq_entry
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $vec) = @_;
33
34 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
35 $common_pid, $common_comm);
36
37 print_uncommon($context);
38
39 printf("vec=%s\n",
40 symbol_str("irq::softirq_entry", "vec", $vec));
41}
42
43sub kmem::kmalloc
44{
45 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
46 $common_pid, $common_comm,
47 $call_site, $ptr, $bytes_req, $bytes_alloc,
48 $gfp_flags) = @_;
49
50 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
51 $common_pid, $common_comm);
52
53 print_uncommon($context);
54
55 printf("call_site=%p, ptr=%p, bytes_req=%u, bytes_alloc=%u, ".
56 "gfp_flags=%s\n",
57 $call_site, $ptr, $bytes_req, $bytes_alloc,
58
59 flag_str("kmem::kmalloc", "gfp_flags", $gfp_flags));
60}
61
62# print trace fields not included in handler args
63sub print_uncommon
64{
65 my ($context) = @_;
66
67 printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
68 common_pc($context), trace_flag_str(common_flags($context)),
69 common_lock_depth($context));
70
71}
72
73my %unhandled;
74
75sub print_unhandled
76{
77 if ((scalar keys %unhandled) == 0) {
78 return;
79 }
80
81 print "\nunhandled events:\n\n";
82
83 printf("%-40s %10s\n", "event", "count");
84 printf("%-40s %10s\n", "----------------------------------------",
85 "-----------");
86
87 foreach my $event_name (keys %unhandled) {
88 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
89 }
90}
91
92sub trace_unhandled
93{
94 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
95 $common_pid, $common_comm) = @_;
96
97 $unhandled{$event_name}++;
98}
99
100sub print_header
101{
102 my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
103
104 printf("%-20s %5u %05u.%09u %8u %-20s ",
105 $event_name, $cpu, $secs, $nsecs, $pid, $comm);
106}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
new file mode 100644
index 000000000000..61f91561d848
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -0,0 +1,105 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for files read/written to for a given program
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21# change this to the comm of the program you're interested in
22my $for_comm = "perf";
23
24my %reads;
25my %writes;
26
27sub syscalls::sys_enter_read
28{
29 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
30 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
31
32 if ($common_comm eq $for_comm) {
33 $reads{$fd}{bytes_requested} += $count;
34 $reads{$fd}{total_reads}++;
35 }
36}
37
38sub syscalls::sys_enter_write
39{
40 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
41 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
42
43 if ($common_comm eq $for_comm) {
44 $writes{$fd}{bytes_written} += $count;
45 $writes{$fd}{total_writes}++;
46 }
47}
48
49sub trace_end
50{
51 printf("file read counts for $for_comm:\n\n");
52
53 printf("%6s %10s %10s\n", "fd", "# reads", "bytes_requested");
54 printf("%6s %10s %10s\n", "------", "----------", "-----------");
55
56 foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
57 $reads{$a}{bytes_requested}} keys %reads) {
58 my $total_reads = $reads{$fd}{total_reads};
59 my $bytes_requested = $reads{$fd}{bytes_requested};
60 printf("%6u %10u %10u\n", $fd, $total_reads, $bytes_requested);
61 }
62
63 printf("\nfile write counts for $for_comm:\n\n");
64
65 printf("%6s %10s %10s\n", "fd", "# writes", "bytes_written");
66 printf("%6s %10s %10s\n", "------", "----------", "-----------");
67
68 foreach my $fd (sort {$writes{$b}{bytes_written} <=>
69 $writes{$a}{bytes_written}} keys %writes) {
70 my $total_writes = $writes{$fd}{total_writes};
71 my $bytes_written = $writes{$fd}{bytes_written};
72 printf("%6u %10u %10u\n", $fd, $total_writes, $bytes_written);
73 }
74
75 print_unhandled();
76}
77
78my %unhandled;
79
80sub print_unhandled
81{
82 if ((scalar keys %unhandled) == 0) {
83 return;
84 }
85
86 print "\nunhandled events:\n\n";
87
88 printf("%-40s %10s\n", "event", "count");
89 printf("%-40s %10s\n", "----------------------------------------",
90 "-----------");
91
92 foreach my $event_name (keys %unhandled) {
93 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
94 }
95}
96
97sub trace_unhandled
98{
99 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
100 $common_pid, $common_comm) = @_;
101
102 $unhandled{$event_name}++;
103}
104
105
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
new file mode 100644
index 000000000000..da601fae1a00
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-pid.pl
@@ -0,0 +1,170 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for all processes
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %reads;
22my %writes;
23
24sub syscalls::sys_exit_read
25{
26 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
27 $common_pid, $common_comm,
28 $nr, $ret) = @_;
29
30 if ($ret > 0) {
31 $reads{$common_pid}{bytes_read} += $ret;
32 } else {
33 if (!defined ($reads{$common_pid}{bytes_read})) {
34 $reads{$common_pid}{bytes_read} = 0;
35 }
36 $reads{$common_pid}{errors}{$ret}++;
37 }
38}
39
40sub syscalls::sys_enter_read
41{
42 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
43 $common_pid, $common_comm,
44 $nr, $fd, $buf, $count) = @_;
45
46 $reads{$common_pid}{bytes_requested} += $count;
47 $reads{$common_pid}{total_reads}++;
48 $reads{$common_pid}{comm} = $common_comm;
49}
50
51sub syscalls::sys_exit_write
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $nr, $ret) = @_;
56
57 if ($ret <= 0) {
58 $writes{$common_pid}{errors}{$ret}++;
59 }
60}
61
62sub syscalls::sys_enter_write
63{
64 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
65 $common_pid, $common_comm,
66 $nr, $fd, $buf, $count) = @_;
67
68 $writes{$common_pid}{bytes_written} += $count;
69 $writes{$common_pid}{total_writes}++;
70 $writes{$common_pid}{comm} = $common_comm;
71}
72
73sub trace_end
74{
75 printf("read counts by pid:\n\n");
76
77 printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
78 "# reads", "bytes_requested", "bytes_read");
79 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
80 "-----------", "----------", "----------");
81
82 foreach my $pid (sort {$reads{$b}{bytes_read} <=>
83 $reads{$a}{bytes_read}} keys %reads) {
84 my $comm = $reads{$pid}{comm};
85 my $total_reads = $reads{$pid}{total_reads};
86 my $bytes_requested = $reads{$pid}{bytes_requested};
87 my $bytes_read = $reads{$pid}{bytes_read};
88
89 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
90 $total_reads, $bytes_requested, $bytes_read);
91 }
92
93 printf("\nfailed reads by pid:\n\n");
94
95 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
96 printf("%6s %20s %6s %10s\n", "------", "--------------------",
97 "------", "----------");
98
99 foreach my $pid (keys %reads) {
100 my $comm = $reads{$pid}{comm};
101 foreach my $err (sort {$reads{$b}{comm} cmp $reads{$a}{comm}}
102 keys %{$reads{$pid}{errors}}) {
103 my $errors = $reads{$pid}{errors}{$err};
104
105 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
106 }
107 }
108
109 printf("\nwrite counts by pid:\n\n");
110
111 printf("%6s %20s %10s %10s\n", "pid", "comm",
112 "# writes", "bytes_written");
113 printf("%6s %-20s %10s %10s\n", "------", "--------------------",
114 "-----------", "----------");
115
116 foreach my $pid (sort {$writes{$b}{bytes_written} <=>
117 $writes{$a}{bytes_written}} keys %writes) {
118 my $comm = $writes{$pid}{comm};
119 my $total_writes = $writes{$pid}{total_writes};
120 my $bytes_written = $writes{$pid}{bytes_written};
121
122 printf("%6s %-20s %10s %10s\n", $pid, $comm,
123 $total_writes, $bytes_written);
124 }
125
126 printf("\nfailed writes by pid:\n\n");
127
128 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
129 printf("%6s %20s %6s %10s\n", "------", "--------------------",
130 "------", "----------");
131
132 foreach my $pid (keys %writes) {
133 my $comm = $writes{$pid}{comm};
134 foreach my $err (sort {$writes{$b}{comm} cmp $writes{$a}{comm}}
135 keys %{$writes{$pid}{errors}}) {
136 my $errors = $writes{$pid}{errors}{$err};
137
138 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
139 }
140 }
141
142 print_unhandled();
143}
144
145my %unhandled;
146
147sub print_unhandled
148{
149 if ((scalar keys %unhandled) == 0) {
150 return;
151 }
152
153 print "\nunhandled events:\n\n";
154
155 printf("%-40s %10s\n", "event", "count");
156 printf("%-40s %10s\n", "----------------------------------------",
157 "-----------");
158
159 foreach my $event_name (keys %unhandled) {
160 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
161 }
162}
163
164sub trace_unhandled
165{
166 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
167 $common_pid, $common_comm) = @_;
168
169 $unhandled{$event_name}++;
170}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
new file mode 100644
index 000000000000..ed58ef284e23
--- /dev/null
+++ b/tools/perf/scripts/perl/wakeup-latency.pl
@@ -0,0 +1,103 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display avg/min/max wakeup latency
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %last_wakeup;
22
23my $max_wakeup_latency;
24my $min_wakeup_latency;
25my $total_wakeup_latency;
26my $total_wakeups;
27
28sub sched::sched_switch
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
33 $next_prio) = @_;
34
35 my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
36 if ($wakeup_ts) {
37 my $switch_ts = nsecs($common_secs, $common_nsecs);
38 my $wakeup_latency = $switch_ts - $wakeup_ts;
39 if ($wakeup_latency > $max_wakeup_latency) {
40 $max_wakeup_latency = $wakeup_latency;
41 }
42 if ($wakeup_latency < $min_wakeup_latency) {
43 $min_wakeup_latency = $wakeup_latency;
44 }
45 $total_wakeup_latency += $wakeup_latency;
46 $total_wakeups++;
47 }
48 $last_wakeup{$common_cpu}{ts} = 0;
49}
50
51sub sched::sched_wakeup
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $comm, $pid, $prio, $success, $target_cpu) = @_;
56
57 $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
58}
59
60sub trace_begin
61{
62 $min_wakeup_latency = 1000000000;
63 $max_wakeup_latency = 0;
64}
65
66sub trace_end
67{
68 printf("wakeup_latency stats:\n\n");
69 print "total_wakeups: $total_wakeups\n";
70 printf("avg_wakeup_latency (ns): %u\n",
71 avg($total_wakeup_latency, $total_wakeups));
72 printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
73 printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
74
75 print_unhandled();
76}
77
78my %unhandled;
79
80sub print_unhandled
81{
82 if ((scalar keys %unhandled) == 0) {
83 return;
84 }
85
86 print "\nunhandled events:\n\n";
87
88 printf("%-40s %10s\n", "event", "count");
89 printf("%-40s %10s\n", "----------------------------------------",
90 "-----------");
91
92 foreach my $event_name (keys %unhandled) {
93 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
94 }
95}
96
97sub trace_unhandled
98{
99 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
100 $common_pid, $common_comm) = @_;
101
102 $unhandled{$event_name}++;
103}
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
new file mode 100644
index 000000000000..511302c8a494
--- /dev/null
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -0,0 +1,129 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'};
75 my $exe = $$wqhash{'executed'};
76 my $comm = $$wqhash{'comm'};
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'};
91 my $destroyed = $$wqhash{'destroyed'};
92 my $comm = $$wqhash{'comm'};
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index c561d1538c03..54552a00a117 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -1,7 +1,7 @@
1#!/bin/sh 1#!/bin/sh
2 2
3GVF=PERF-VERSION-FILE 3GVF=PERF-VERSION-FILE
4DEF_VER=v0.0.1.PERF 4DEF_VER=v0.0.2.PERF
5 5
6LF=' 6LF='
7' 7'
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index f26172c0c919..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -5,6 +5,11 @@
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h" 6#include "../perf.h"
7 7
8#define CMD_EXEC_PATH "--exec-path"
9#define CMD_PERF_DIR "--perf-dir="
10#define CMD_WORK_TREE "--work-tree="
11#define CMD_DEBUGFS_DIR "--debugfs-dir="
12
8#define PERF_DIR_ENVIRONMENT "PERF_DIR" 13#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
206 } 206 }
207 node->val_nr = chain->nr - start; 207 node->val_nr = chain->nr - start;
208 if (!node->val_nr) 208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n"); 209 pr_warning("Warning: empty node in callchain tree\n");
210} 210}
211 211
212static void 212static void
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 0b791bd346bc..35073621e5de 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -29,3 +29,11 @@ unsigned char sane_ctype[256] = {
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ 29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */ 30 /* Nothing in the 128.. range */
31}; 31};
32
33const char *graph_line =
34 "_____________________________________________________________________"
35 "_____________________________________________________________________";
36const char *graph_dotted_line =
37 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------";
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 242b0555ab91..ca0bedf637c2 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -8,11 +8,9 @@ static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32; 8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX]; 9static char __cwd[PATH_MAX];
10 10
11static int 11static int process_event_stub(event_t *event __used)
12process_event_stub(event_t *event __used,
13 unsigned long offset __used,
14 unsigned long head __used)
15{ 12{
13 dump_printf(": unhandled!\n");
16 return 0; 14 return 0;
17} 15}
18 16
@@ -40,36 +38,97 @@ void register_perf_file_handler(struct perf_file_handler *handler)
40 curr_handler = handler; 38 curr_handler = handler;
41} 39}
42 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
43static int 64static int
44process_event(event_t *event, unsigned long offset, unsigned long head) 65process_event(event_t *event, unsigned long offset, unsigned long head)
45{ 66{
46 trace_event(event); 67 trace_event(event);
47 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
48 switch (event->header.type) { 78 switch (event->header.type) {
49 case PERF_RECORD_SAMPLE: 79 case PERF_RECORD_SAMPLE:
50 return curr_handler->process_sample_event(event, offset, head); 80 return curr_handler->process_sample_event(event);
51 case PERF_RECORD_MMAP: 81 case PERF_RECORD_MMAP:
52 return curr_handler->process_mmap_event(event, offset, head); 82 return curr_handler->process_mmap_event(event);
53 case PERF_RECORD_COMM: 83 case PERF_RECORD_COMM:
54 return curr_handler->process_comm_event(event, offset, head); 84 return curr_handler->process_comm_event(event);
55 case PERF_RECORD_FORK: 85 case PERF_RECORD_FORK:
56 return curr_handler->process_fork_event(event, offset, head); 86 return curr_handler->process_fork_event(event);
57 case PERF_RECORD_EXIT: 87 case PERF_RECORD_EXIT:
58 return curr_handler->process_exit_event(event, offset, head); 88 return curr_handler->process_exit_event(event);
59 case PERF_RECORD_LOST: 89 case PERF_RECORD_LOST:
60 return curr_handler->process_lost_event(event, offset, head); 90 return curr_handler->process_lost_event(event);
61 case PERF_RECORD_READ: 91 case PERF_RECORD_READ:
62 return curr_handler->process_read_event(event, offset, head); 92 return curr_handler->process_read_event(event);
63 case PERF_RECORD_THROTTLE: 93 case PERF_RECORD_THROTTLE:
64 return curr_handler->process_throttle_event(event, offset, head); 94 return curr_handler->process_throttle_event(event);
65 case PERF_RECORD_UNTHROTTLE: 95 case PERF_RECORD_UNTHROTTLE:
66 return curr_handler->process_unthrottle_event(event, offset, head); 96 return curr_handler->process_unthrottle_event(event);
67 default: 97 default:
68 curr_handler->total_unknown++; 98 curr_handler->total_unknown++;
69 return -1; 99 return -1;
70 } 100 }
71} 101}
72 102
103int perf_header__read_build_ids(int input, off_t offset, off_t size)
104{
105 struct build_id_event bev;
106 char filename[PATH_MAX];
107 off_t 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
73int mmap_dispatch_perf_file(struct perf_header **pheader, 132int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name, 133 const char *input_name,
75 int force, 134 int force,
@@ -77,7 +136,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
77 int *cwdlen, 136 int *cwdlen,
78 char **cwd) 137 char **cwd)
79{ 138{
80 int ret, rc = EXIT_FAILURE; 139 int err;
81 struct perf_header *header; 140 struct perf_header *header;
82 unsigned long head, shift; 141 unsigned long head, shift;
83 unsigned long offset = 0; 142 unsigned long offset = 0;
@@ -89,56 +148,63 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
89 int input; 148 int input;
90 char *buf; 149 char *buf;
91 150
92 if (!curr_handler) 151 if (curr_handler == NULL) {
93 die("Forgot to register perf file handler"); 152 pr_debug("Forgot to register perf file handler\n");
153 return -EINVAL;
154 }
94 155
95 page_size = getpagesize(); 156 page_size = getpagesize();
96 157
97 input = open(input_name, O_RDONLY); 158 input = open(input_name, O_RDONLY);
98 if (input < 0) { 159 if (input < 0) {
99 fprintf(stderr, " failed to open file: %s", input_name); 160 pr_err("Failed to open file: %s", input_name);
100 if (!strcmp(input_name, "perf.data")) 161 if (!strcmp(input_name, "perf.data"))
101 fprintf(stderr, " (try 'perf record' first)"); 162 pr_err(" (try 'perf record' first)");
102 fprintf(stderr, "\n"); 163 pr_err("\n");
103 exit(-1); 164 return -errno;
104 } 165 }
105 166
106 ret = fstat(input, &input_stat); 167 if (fstat(input, &input_stat) < 0) {
107 if (ret < 0) { 168 pr_err("failed to stat file");
108 perror("failed to stat file"); 169 err = -errno;
109 exit(-1); 170 goto out_close;
110 } 171 }
111 172
173 err = -EACCES;
112 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { 174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
113 fprintf(stderr, "file: %s not owned by current user or root\n", 175 pr_err("file: %s not owned by current user or root\n",
114 input_name); 176 input_name);
115 exit(-1); 177 goto out_close;
116 } 178 }
117 179
118 if (!input_stat.st_size) { 180 if (input_stat.st_size == 0) {
119 fprintf(stderr, "zero-sized file, nothing to do!\n"); 181 pr_info("zero-sized file, nothing to do!\n");
120 exit(0); 182 goto done;
121 } 183 }
122 184
123 *pheader = perf_header__read(input); 185 err = -ENOMEM;
124 header = *pheader; 186 header = perf_header__new();
187 if (header == NULL)
188 goto out_close;
189
190 err = perf_header__read(header, input);
191 if (err < 0)
192 goto out_delete;
193 *pheader = header;
125 head = header->data_offset; 194 head = header->data_offset;
126 195
127 sample_type = perf_header__sample_type(header); 196 sample_type = perf_header__sample_type(header);
128 197
129 if (curr_handler->sample_type_check) 198 err = -EINVAL;
130 if (curr_handler->sample_type_check(sample_type) < 0) 199 if (curr_handler->sample_type_check &&
131 exit(-1); 200 curr_handler->sample_type_check(sample_type) < 0)
132 201 goto out_delete;
133 if (load_kernel() < 0) {
134 perror("failed to load kernel symbols");
135 return EXIT_FAILURE;
136 }
137 202
138 if (!full_paths) { 203 if (!full_paths) {
139 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
140 perror("failed to get the current directory"); 205 pr_err("failed to get the current directory\n");
141 return EXIT_FAILURE; 206 err = -errno;
207 goto out_delete;
142 } 208 }
143 *cwd = __cwd; 209 *cwd = __cwd;
144 *cwdlen = strlen(*cwd); 210 *cwdlen = strlen(*cwd);
@@ -152,11 +218,12 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
152 head -= shift; 218 head -= shift;
153 219
154remap: 220remap:
155 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 221 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
156 MAP_SHARED, input, offset); 222 MAP_SHARED, input, offset);
157 if (buf == MAP_FAILED) { 223 if (buf == MAP_FAILED) {
158 perror("failed to mmap file"); 224 pr_err("failed to mmap file\n");
159 exit(-1); 225 err = -errno;
226 goto out_delete;
160 } 227 }
161 228
162more: 229more:
@@ -213,10 +280,12 @@ more:
213 goto more; 280 goto more;
214 281
215done: 282done:
216 rc = EXIT_SUCCESS; 283 err = 0;
284out_close:
217 close(input); 285 close(input);
218 286
219 return rc; 287 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
220} 291}
221
222
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 716d1053b074..3180ff7e3633 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -4,7 +4,7 @@
4#include "event.h" 4#include "event.h"
5#include "header.h" 5#include "header.h"
6 6
7typedef int (*event_type_handler_t)(event_t *, unsigned long, unsigned long); 7typedef int (*event_type_handler_t)(event_t *);
8 8
9struct perf_file_handler { 9struct perf_file_handler {
10 event_type_handler_t process_sample_event; 10 event_type_handler_t process_sample_event;
@@ -27,5 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
27 int full_paths, 27 int full_paths,
28 int *cwdlen, 28 int *cwdlen,
29 char **cwd); 29 char **cwd);
30int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
30 31
31#endif 32#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index e8ca98fe0bd4..28d520d5a1fb 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -13,12 +13,12 @@
13int verbose = 0; 13int verbose = 0;
14int dump_trace = 0; 14int dump_trace = 0;
15 15
16int eprintf(const char *fmt, ...) 16int eprintf(int level, const char *fmt, ...)
17{ 17{
18 va_list args; 18 va_list args;
19 int ret = 0; 19 int ret = 0;
20 20
21 if (verbose) { 21 if (verbose >= level) {
22 va_start(args, fmt); 22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 23 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 24 va_end(args);
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 02d1fa1c2465..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,10 +2,13 @@
2#ifndef __PERF_DEBUG_H 2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include "event.h"
6
5extern int verbose; 7extern int verbose;
6extern int dump_trace; 8extern int dump_trace;
7 9
8int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
9int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
10void trace_event(event_t *event); 13void trace_event(event_t *event);
11 14
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..06b73ee02c49
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,241 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1];
7
8static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/",
10 "/debug/",
11 0,
12};
13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
40static int debugfs_found;
41
42/* find the path to the mounted debugfs */
43const char *debugfs_find_mountpoint(void)
44{
45 const char **ptr;
46 char type[100];
47 FILE *fp;
48
49 if (debugfs_found)
50 return (const char *) debugfs_mountpoint;
51
52 ptr = debugfs_known_mountpoints;
53 while (*ptr) {
54 if (debugfs_valid_mountpoint(*ptr) == 0) {
55 debugfs_found = 1;
56 strcpy(debugfs_mountpoint, *ptr);
57 return debugfs_mountpoint;
58 }
59 ptr++;
60 }
61
62 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL)
65 die("Can't open /proc/mounts for read");
66
67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0)
72 break;
73 }
74 fclose(fp);
75
76 if (strcmp(type, "debugfs") != 0)
77 return NULL;
78
79 debugfs_found = 1;
80
81 return debugfs_mountpoint;
82}
83
84/* verify that a mountpoint is actually a debugfs instance */
85
86int debugfs_valid_mountpoint(const char *debugfs)
87{
88 struct statfs st_fs;
89
90 if (statfs(debugfs, &st_fs) < 0)
91 return -ENOENT;
92 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
93 return -ENOENT;
94
95 return 0;
96}
97
98
99int debugfs_valid_entry(const char *path)
100{
101 struct stat st;
102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
107}
108
109/* mount the debugfs somewhere */
110
111int debugfs_mount(const char *mountpoint)
112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1;
118 return 0;
119 }
120
121 /* if not mounted and no argument */
122 if (mountpoint == NULL) {
123 /* see if environment variable set */
124 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
125 /* if no environment variable, use default */
126 if (mountpoint == NULL)
127 mountpoint = "/sys/kernel/debug";
128 }
129
130 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
132
133 /* mount it */
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137}
138
139/* umount the debugfs */
140
141int debugfs_umount(void)
142{
143 char umountcmd[128];
144 int ret;
145
146 /* if it was already mounted, leave it */
147 if (debugfs_premounted)
148 return 0;
149
150 /* make sure it's a valid mount point */
151 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
152 if (ret)
153 return ret;
154
155 snprintf(umountcmd, sizeof(umountcmd),
156 "/bin/umount %s", debugfs_mountpoint);
157 return system(umountcmd);
158}
159
160int debugfs_write(const char *entry, const char *value)
161{
162 char path[MAX_PATH+1];
163 int ret, count;
164 int fd;
165
166 /* construct the path */
167 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
168
169 /* verify that it exists */
170 ret = debugfs_valid_entry(path);
171 if (ret)
172 return ret;
173
174 /* get how many chars we're going to write */
175 count = strlen(value);
176
177 /* open the debugfs entry */
178 fd = open(path, O_RDWR);
179 if (fd < 0)
180 return -errno;
181
182 while (count > 0) {
183 /* write it */
184 ret = write(fd, value, count);
185 if (ret <= 0) {
186 if (ret == EAGAIN)
187 continue;
188 close(fd);
189 return -errno;
190 }
191 count -= ret;
192 }
193
194 /* close it */
195 close(fd);
196
197 /* return success */
198 return 0;
199}
200
201/*
202 * read a debugfs entry
203 * returns the number of chars read or a negative errno
204 */
205int debugfs_read(const char *entry, char *buffer, size_t size)
206{
207 char path[MAX_PATH+1];
208 int ret;
209 int fd;
210
211 /* construct the path */
212 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
213
214 /* verify that it exists */
215 ret = debugfs_valid_entry(path);
216 if (ret)
217 return ret;
218
219 /* open the debugfs entry */
220 fd = open(path, O_RDONLY);
221 if (fd < 0)
222 return -errno;
223
224 do {
225 /* read it */
226 ret = read(fd, buffer, size);
227 if (ret == 0) {
228 close(fd);
229 return EOF;
230 }
231 } while (ret < 0 && errno == EAGAIN);
232
233 /* close it */
234 close(fd);
235
236 /* make *sure* there's a null character at the end */
237 buffer[ret] = '\0';
238
239 /* return the number of chars read */
240 return ret;
241}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..3cd14f9ae784
--- /dev/null
+++ b/tools/perf/util/debugfs.h
@@ -0,0 +1,25 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4#include <sys/mount.h>
5
6#ifndef MAX_PATH
7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24
25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..414b89d1bde9
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,312 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "string.h"
5#include "thread.h"
6
7static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event))
9{
10 event_t ev;
11 char filename[PATH_MAX];
12 char bf[BUFSIZ];
13 FILE *fp;
14 size_t size = 0;
15 DIR *tasks;
16 struct dirent dirent, *next;
17 pid_t tgid = 0;
18
19 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
20
21 fp = fopen(filename, "r");
22 if (fp == NULL) {
23out_race:
24 /*
25 * We raced with a task exiting - just return:
26 */
27 pr_debug("couldn't open %s\n", filename);
28 return 0;
29 }
30
31 memset(&ev.comm, 0, sizeof(ev.comm));
32 while (!ev.comm.comm[0] || !ev.comm.pid) {
33 if (fgets(bf, sizeof(bf), fp) == NULL)
34 goto out_failure;
35
36 if (memcmp(bf, "Name:", 5) == 0) {
37 char *name = bf + 5;
38 while (*name && isspace(*name))
39 ++name;
40 size = strlen(name) - 1;
41 memcpy(ev.comm.comm, name, size++);
42 } else if (memcmp(bf, "Tgid:", 5) == 0) {
43 char *tgids = bf + 5;
44 while (*tgids && isspace(*tgids))
45 ++tgids;
46 tgid = ev.comm.pid = atoi(tgids);
47 }
48 }
49
50 ev.comm.header.type = PERF_RECORD_COMM;
51 size = ALIGN(size, sizeof(u64));
52 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
53
54 if (!full) {
55 ev.comm.tid = pid;
56
57 process(&ev);
58 goto out_fclose;
59 }
60
61 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
62
63 tasks = opendir(filename);
64 if (tasks == NULL)
65 goto out_race;
66
67 while (!readdir_r(tasks, &dirent, &next) && next) {
68 char *end;
69 pid = strtol(dirent.d_name, &end, 10);
70 if (*end)
71 continue;
72
73 ev.comm.tid = pid;
74
75 process(&ev);
76 }
77 closedir(tasks);
78
79out_fclose:
80 fclose(fp);
81 return tgid;
82
83out_failure:
84 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
85 return -1;
86}
87
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event))
90{
91 char filename[PATH_MAX];
92 FILE *fp;
93
94 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
95
96 fp = fopen(filename, "r");
97 if (fp == NULL) {
98 /*
99 * We raced with a task exiting - just return:
100 */
101 pr_debug("couldn't open %s\n", filename);
102 return -1;
103 }
104
105 while (1) {
106 char bf[BUFSIZ], *pbf = bf;
107 event_t ev = {
108 .header = { .type = PERF_RECORD_MMAP },
109 };
110 int n;
111 size_t size;
112 if (fgets(bf, sizeof(bf), fp) == NULL)
113 break;
114
115 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
116 n = hex2u64(pbf, &ev.mmap.start);
117 if (n < 0)
118 continue;
119 pbf += n + 1;
120 n = hex2u64(pbf, &ev.mmap.len);
121 if (n < 0)
122 continue;
123 pbf += n + 3;
124 if (*pbf == 'x') { /* vm_exec */
125 char *execname = strchr(bf, '/');
126
127 /* Catch VDSO */
128 if (execname == NULL)
129 execname = strstr(bf, "[vdso]");
130
131 if (execname == NULL)
132 continue;
133
134 size = strlen(execname);
135 execname[size - 1] = '\0'; /* Remove \n */
136 memcpy(ev.mmap.filename, execname, size);
137 size = ALIGN(size, sizeof(u64));
138 ev.mmap.len -= ev.mmap.start;
139 ev.mmap.header.size = (sizeof(ev.mmap) -
140 (sizeof(ev.mmap.filename) - size));
141 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid;
143
144 process(&ev);
145 }
146 }
147
148 fclose(fp);
149 return 0;
150}
151
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
153{
154 pid_t tgid = event__synthesize_comm(pid, 1, process);
155 if (tgid == -1)
156 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process);
158}
159
160void event__synthesize_threads(int (*process)(event_t *event))
161{
162 DIR *proc;
163 struct dirent dirent, *next;
164
165 proc = opendir("/proc");
166
167 while (!readdir_r(proc, &dirent, &next) && next) {
168 char *end;
169 pid_t pid = strtol(dirent.d_name, &end, 10);
170
171 if (*end) /* only interested in proper numerical dirents */
172 continue;
173
174 event__synthesize_thread(pid, process);
175 }
176
177 closedir(proc);
178}
179
180char *event__cwd;
181int event__cwdlen;
182
183struct events_stats event__stats;
184
185int event__process_comm(event_t *self)
186{
187 struct thread *thread = threads__findnew(self->comm.pid);
188
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1;
194 }
195
196 return 0;
197}
198
199int event__process_lost(event_t *self)
200{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost;
203 return 0;
204}
205
206int event__process_mmap(event_t *self)
207{
208 struct thread *thread = threads__findnew(self->mmap.pid);
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 event__cwd, event__cwdlen);
211
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 self->mmap.pid, self->mmap.tid,
214 (void *)(long)self->mmap.start,
215 (void *)(long)self->mmap.len,
216 (void *)(long)self->mmap.pgoff,
217 self->mmap.filename);
218
219 if (thread == NULL || map == NULL)
220 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
221 else
222 thread__insert_map(thread, map);
223
224 return 0;
225}
226
227int event__process_task(event_t *self)
228{
229 struct thread *thread = threads__findnew(self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid);
231
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid);
234 /*
235 * A thread clone will have the same PID for both parent and child.
236 */
237 if (thread == parent)
238 return 0;
239
240 if (self->header.type == PERF_RECORD_EXIT)
241 return 0;
242
243 if (thread == NULL || parent == NULL ||
244 thread__fork(thread, parent) < 0) {
245 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
246 return -1;
247 }
248
249 return 0;
250}
251
252void thread__find_addr_location(struct thread *self, u8 cpumode,
253 enum map_type type, u64 addr,
254 struct addr_location *al,
255 symbol_filter_t filter)
256{
257 struct thread *thread = al->thread = self;
258
259 al->addr = addr;
260
261 if (cpumode & PERF_RECORD_MISC_KERNEL) {
262 al->level = 'k';
263 thread = kthread;
264 } else if (cpumode & PERF_RECORD_MISC_USER)
265 al->level = '.';
266 else {
267 al->level = 'H';
268 al->map = NULL;
269 al->sym = NULL;
270 return;
271 }
272try_again:
273 al->map = thread__find_map(thread, type, al->addr);
274 if (al->map == NULL) {
275 /*
276 * If this is outside of all known maps, and is a negative
277 * address, try to look it up in the kernel dso, as it might be
278 * a vsyscall or vdso (which executes in user-mode).
279 *
280 * XXX This is nasty, we should have a symbol list in the
281 * "[vdso]" dso, but for now lets use the old trick of looking
282 * in the whole kernel symbol list.
283 */
284 if ((long long)al->addr < 0 && thread != kthread) {
285 thread = kthread;
286 goto try_again;
287 }
288 al->sym = NULL;
289 } else {
290 al->addr = al->map->map_ip(al->map, al->addr);
291 al->sym = map__find_symbol(al->map, al->addr, filter);
292 }
293}
294
295int event__preprocess_sample(const event_t *self, struct addr_location *al,
296 symbol_filter_t filter)
297{
298 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
299 struct thread *thread = threads__findnew(self->ip.pid);
300
301 if (thread == NULL)
302 return -1;
303
304 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
305
306 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
307 self->ip.ip, al, filter);
308 dump_printf(" ...... dso: %s\n",
309 al->map ? al->map->dso->long_name :
310 al->level == 'H' ? "[hypervisor]" : "<not found>");
311 return 0;
312}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c2e62be62798..a4cc8105cf67 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,13 @@ struct sample_event{
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64#define BUILD_ID_SIZE 20
65
66struct build_id_event {
67 struct perf_event_header header;
68 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
69 char filename[];
70};
64 71
65typedef union event_union { 72typedef union event_union {
66 struct perf_event_header header; 73 struct perf_event_header header;
@@ -73,6 +80,19 @@ typedef union event_union {
73 struct sample_event sample; 80 struct sample_event sample;
74} event_t; 81} event_t;
75 82
83struct events_stats {
84 unsigned long total;
85 unsigned long lost;
86};
87
88void event__print_totals(void);
89
90enum map_type {
91 MAP__FUNCTION = 0,
92
93 MAP__NR_TYPES,
94};
95
76struct map { 96struct map {
77 union { 97 union {
78 struct rb_node rb_node; 98 struct rb_node rb_node;
@@ -80,8 +100,10 @@ struct map {
80 }; 100 };
81 u64 start; 101 u64 start;
82 u64 end; 102 u64 end;
103 enum map_type type;
83 u64 pgoff; 104 u64 pgoff;
84 u64 (*map_ip)(struct map *, u64); 105 u64 (*map_ip)(struct map *, u64);
106 u64 (*unmap_ip)(struct map *, u64);
85 struct dso *dso; 107 struct dso *dso;
86}; 108};
87 109
@@ -90,14 +112,48 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
90 return ip - map->start + map->pgoff; 112 return ip - map->start + map->pgoff;
91} 113}
92 114
93static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 115static inline u64 map__unmap_ip(struct map *map, u64 ip)
116{
117 return ip + map->start - map->pgoff;
118}
119
120static inline u64 identity__map_ip(struct map *map __used, u64 ip)
94{ 121{
95 return ip; 122 return ip;
96} 123}
97 124
98struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 125struct symbol;
126
127typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
128
129void map__init(struct map *self, enum map_type type,
130 u64 start, u64 end, u64 pgoff, struct dso *dso);
131struct map *map__new(struct mmap_event *event, enum map_type,
132 char *cwd, int cwdlen);
133void map__delete(struct map *self);
99struct map *map__clone(struct map *self); 134struct map *map__clone(struct map *self);
100int map__overlap(struct map *l, struct map *r); 135int map__overlap(struct map *l, struct map *r);
101size_t map__fprintf(struct map *self, FILE *fp); 136size_t map__fprintf(struct map *self, FILE *fp);
137struct symbol *map__find_symbol(struct map *self, u64 addr,
138 symbol_filter_t filter);
139void map__fixup_start(struct map *self);
140void map__fixup_end(struct map *self);
141
142int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
143void event__synthesize_threads(int (*process)(event_t *event));
144
145extern char *event__cwd;
146extern int event__cwdlen;
147extern struct events_stats event__stats;
148extern unsigned long event__total[PERF_RECORD_MAX];
149
150int event__process_comm(event_t *self);
151int event__process_lost(event_t *self);
152int event__process_mmap(event_t *self);
153int event__process_task(event_t *self);
154
155struct addr_location;
156int event__preprocess_sample(const event_t *self, struct addr_location *al,
157 symbol_filter_t filter);
102 158
103#endif /* __PERF_RECORD_H */ 159#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 9aae360c0f28..4805e6dfd23c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,11 +2,15 @@
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <linux/list.h>
5 6
6#include "util.h" 7#include "util.h"
7#include "header.h" 8#include "header.h"
8#include "../perf.h" 9#include "../perf.h"
9#include "trace-event.h" 10#include "trace-event.h"
11#include "symbol.h"
12#include "data_map.h"
13#include "debug.h"
10 14
11/* 15/*
12 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -15,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
15{ 19{
16 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
17 21
18 if (!self) 22 if (self != NULL) {
19 die("nomem"); 23 self->attr = *attr;
20 24 self->ids = 0;
21 self->attr = *attr; 25 self->size = 1;
22 self->ids = 0; 26 self->id = malloc(sizeof(u64));
23 self->size = 1; 27 if (self->id == NULL) {
24 self->id = malloc(sizeof(u64)); 28 free(self);
25 29 self = NULL;
26 if (!self->id) 30 }
27 die("nomem"); 31 }
28 32
29 return self; 33 return self;
30} 34}
31 35
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 36void perf_header_attr__delete(struct perf_header_attr *self)
37{
38 free(self->id);
39 free(self);
40}
41
42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
33{ 43{
34 int pos = self->ids; 44 int pos = self->ids;
35 45
36 self->ids++; 46 self->ids++;
37 if (self->ids > self->size) { 47 if (self->ids > self->size) {
38 self->size *= 2; 48 int nsize = self->size * 2;
39 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
40 if (!self->id) 50
41 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
42 } 56 }
43 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
44} 59}
45 60
46/* 61/*
@@ -48,44 +63,52 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
48 */ 63 */
49struct perf_header *perf_header__new(void) 64struct perf_header *perf_header__new(void)
50{ 65{
51 struct perf_header *self = malloc(sizeof(*self)); 66 struct perf_header *self = zalloc(sizeof(*self));
52 67
53 if (!self) 68 if (self != NULL) {
54 die("nomem"); 69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
55 71
56 self->frozen = 0; 72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
57 77
58 self->attrs = 0; 78 return self;
59 self->size = 1; 79}
60 self->attr = malloc(sizeof(void *));
61 80
62 if (!self->attr) 81void perf_header__delete(struct perf_header *self)
63 die("nomem"); 82{
83 int i;
64 84
65 self->data_offset = 0; 85 for (i = 0; i < self->attrs; ++i)
66 self->data_size = 0; 86 perf_header_attr__delete(self->attr[i]);
67 self->trace_info_offset = 0;
68 self->trace_info_size = 0;
69 87
70 return self; 88 free(self->attr);
89 free(self);
71} 90}
72 91
73void perf_header__add_attr(struct perf_header *self, 92int perf_header__add_attr(struct perf_header *self,
74 struct perf_header_attr *attr) 93 struct perf_header_attr *attr)
75{ 94{
76 int pos = self->attrs;
77
78 if (self->frozen) 95 if (self->frozen)
79 die("frozen"); 96 return -1;
80 97
81 self->attrs++; 98 if (self->attrs == self->size) {
82 if (self->attrs > self->size) { 99 int nsize = self->size * 2;
83 self->size *= 2; 100 struct perf_header_attr **nattr;
84 self->attr = realloc(self->attr, self->size * sizeof(void *)); 101
85 if (!self->attr) 102 nattr = realloc(self->attr, nsize * sizeof(void *));
86 die("nomem"); 103 if (nattr == NULL)
104 return -1;
105
106 self->size = nsize;
107 self->attr = nattr;
87 } 108 }
88 self->attr[pos] = attr; 109
110 self->attr[self->attrs++] = attr;
111 return 0;
89} 112}
90 113
91#define MAX_EVENT_NAME 64 114#define MAX_EVENT_NAME 64
@@ -101,7 +124,7 @@ static struct perf_trace_event_type *events;
101void perf_header__push_event(u64 id, const char *name) 124void perf_header__push_event(u64 id, const char *name)
102{ 125{
103 if (strlen(name) > MAX_EVENT_NAME) 126 if (strlen(name) > MAX_EVENT_NAME)
104 printf("Event %s will be truncated\n", name); 127 pr_warning("Event %s will be truncated\n", name);
105 128
106 if (!events) { 129 if (!events) {
107 events = malloc(sizeof(struct perf_trace_event_type)); 130 events = malloc(sizeof(struct perf_trace_event_type));
@@ -132,52 +155,137 @@ static const char *__perf_magic = "PERFFILE";
132 155
133#define PERF_MAGIC (*(u64 *)__perf_magic) 156#define PERF_MAGIC (*(u64 *)__perf_magic)
134 157
135struct perf_file_section {
136 u64 offset;
137 u64 size;
138};
139
140struct perf_file_attr { 158struct perf_file_attr {
141 struct perf_event_attr attr; 159 struct perf_event_attr attr;
142 struct perf_file_section ids; 160 struct perf_file_section ids;
143}; 161};
144 162
145struct perf_file_header { 163void perf_header__set_feat(struct perf_header *self, int feat)
146 u64 magic; 164{
147 u64 size; 165 set_bit(feat, self->adds_features);
148 u64 attr_size; 166}
149 struct perf_file_section attrs;
150 struct perf_file_section data;
151 struct perf_file_section event_types;
152 struct perf_file_section trace_info;
153};
154
155static int trace_info;
156 167
157void perf_header__set_trace_info(void) 168bool perf_header__has_feat(const struct perf_header *self, int feat)
158{ 169{
159 trace_info = 1; 170 return test_bit(feat, self->adds_features);
160} 171}
161 172
162static void do_write(int fd, void *buf, size_t size) 173static int do_write(int fd, const void *buf, size_t size)
163{ 174{
164 while (size) { 175 while (size) {
165 int ret = write(fd, buf, size); 176 int ret = write(fd, buf, size);
166 177
167 if (ret < 0) 178 if (ret < 0)
168 die("failed to write"); 179 return -errno;
169 180
170 size -= ret; 181 size -= ret;
171 buf += ret; 182 buf += ret;
172 } 183 }
184
185 return 0;
186}
187
188static int __dsos__write_buildid_table(struct list_head *head, int fd)
189{
190 struct dso *pos;
191
192 list_for_each_entry(pos, head, node) {
193 int err;
194 struct build_id_event b;
195 size_t len;
196
197 if (!pos->has_build_id)
198 continue;
199 len = pos->long_name_len + 1;
200 len = ALIGN(len, 64);
201 memset(&b, 0, sizeof(b));
202 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
203 b.header.size = sizeof(b) + len;
204 err = do_write(fd, &b, sizeof(b));
205 if (err < 0)
206 return err;
207 err = do_write(fd, pos->long_name, len);
208 if (err < 0)
209 return err;
210 }
211
212 return 0;
213}
214
215static int dsos__write_buildid_table(int fd)
216{
217 int err = __dsos__write_buildid_table(&dsos__kernel, fd);
218 if (err == 0)
219 err = __dsos__write_buildid_table(&dsos__user, fd);
220 return err;
221}
222
223static int perf_header__adds_write(struct perf_header *self, int fd)
224{
225 int nr_sections;
226 struct perf_file_section *feat_sec;
227 int sec_size;
228 u64 sec_start;
229 int idx = 0, err;
230
231 if (dsos__read_build_ids())
232 perf_header__set_feat(self, HEADER_BUILD_ID);
233
234 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
235 if (!nr_sections)
236 return 0;
237
238 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
239 if (feat_sec == NULL)
240 return -ENOMEM;
241
242 sec_size = sizeof(*feat_sec) * nr_sections;
243
244 sec_start = self->data_offset + self->data_size;
245 lseek(fd, sec_start + sec_size, SEEK_SET);
246
247 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
248 struct perf_file_section *trace_sec;
249
250 trace_sec = &feat_sec[idx++];
251
252 /* Write trace info */
253 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
254 read_tracing_data(fd, attrs, nr_counters);
255 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
256 }
257
258
259 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
260 struct perf_file_section *buildid_sec;
261
262 buildid_sec = &feat_sec[idx++];
263
264 /* Write build-ids */
265 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
266 err = dsos__write_buildid_table(fd);
267 if (err < 0) {
268 pr_debug("failed to write buildid table\n");
269 goto out_free;
270 }
271 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
272 }
273
274 lseek(fd, sec_start, SEEK_SET);
275 err = do_write(fd, feat_sec, sec_size);
276 if (err < 0)
277 pr_debug("failed to write feature section\n");
278out_free:
279 free(feat_sec);
280 return err;
173} 281}
174 282
175void perf_header__write(struct perf_header *self, int fd) 283int perf_header__write(struct perf_header *self, int fd, bool at_exit)
176{ 284{
177 struct perf_file_header f_header; 285 struct perf_file_header f_header;
178 struct perf_file_attr f_attr; 286 struct perf_file_attr f_attr;
179 struct perf_header_attr *attr; 287 struct perf_header_attr *attr;
180 int i; 288 int i, err;
181 289
182 lseek(fd, sizeof(f_header), SEEK_SET); 290 lseek(fd, sizeof(f_header), SEEK_SET);
183 291
@@ -186,7 +294,11 @@ void perf_header__write(struct perf_header *self, int fd)
186 attr = self->attr[i]; 294 attr = self->attr[i];
187 295
188 attr->id_offset = lseek(fd, 0, SEEK_CUR); 296 attr->id_offset = lseek(fd, 0, SEEK_CUR);
189 do_write(fd, attr->id, attr->ids * sizeof(u64)); 297 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
298 if (err < 0) {
299 pr_debug("failed to write perf header\n");
300 return err;
301 }
190 } 302 }
191 303
192 304
@@ -202,34 +314,31 @@ void perf_header__write(struct perf_header *self, int fd)
202 .size = attr->ids * sizeof(u64), 314 .size = attr->ids * sizeof(u64),
203 } 315 }
204 }; 316 };
205 do_write(fd, &f_attr, sizeof(f_attr)); 317 err = do_write(fd, &f_attr, sizeof(f_attr));
318 if (err < 0) {
319 pr_debug("failed to write perf header attribute\n");
320 return err;
321 }
206 } 322 }
207 323
208 self->event_offset = lseek(fd, 0, SEEK_CUR); 324 self->event_offset = lseek(fd, 0, SEEK_CUR);
209 self->event_size = event_count * sizeof(struct perf_trace_event_type); 325 self->event_size = event_count * sizeof(struct perf_trace_event_type);
210 if (events) 326 if (events) {
211 do_write(fd, events, self->event_size); 327 err = do_write(fd, events, self->event_size);
212 328 if (err < 0) {
213 if (trace_info) { 329 pr_debug("failed to write perf header events\n");
214 static int trace_info_written; 330 return err;
215
216 /*
217 * Write it only once
218 */
219 if (!trace_info_written) {
220 self->trace_info_offset = lseek(fd, 0, SEEK_CUR);
221 read_tracing_data(fd, attrs, nr_counters);
222 self->trace_info_size = lseek(fd, 0, SEEK_CUR) -
223 self->trace_info_offset;
224 trace_info_written = 1;
225 } else {
226 lseek(fd, self->trace_info_offset +
227 self->trace_info_size, SEEK_SET);
228 } 331 }
229 } 332 }
230 333
231 self->data_offset = lseek(fd, 0, SEEK_CUR); 334 self->data_offset = lseek(fd, 0, SEEK_CUR);
232 335
336 if (at_exit) {
337 err = perf_header__adds_write(self, fd);
338 if (err < 0)
339 return err;
340 }
341
233 f_header = (struct perf_file_header){ 342 f_header = (struct perf_file_header){
234 .magic = PERF_MAGIC, 343 .magic = PERF_MAGIC,
235 .size = sizeof(f_header), 344 .size = sizeof(f_header),
@@ -246,17 +355,20 @@ void perf_header__write(struct perf_header *self, int fd)
246 .offset = self->event_offset, 355 .offset = self->event_offset,
247 .size = self->event_size, 356 .size = self->event_size,
248 }, 357 },
249 .trace_info = {
250 .offset = self->trace_info_offset,
251 .size = self->trace_info_size,
252 },
253 }; 358 };
254 359
360 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
361
255 lseek(fd, 0, SEEK_SET); 362 lseek(fd, 0, SEEK_SET);
256 do_write(fd, &f_header, sizeof(f_header)); 363 err = do_write(fd, &f_header, sizeof(f_header));
364 if (err < 0) {
365 pr_debug("failed to write perf header\n");
366 return err;
367 }
257 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 368 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
258 369
259 self->frozen = 1; 370 self->frozen = 1;
371 return 0;
260} 372}
261 373
262static void do_read(int fd, void *buf, size_t size) 374static void do_read(int fd, void *buf, size_t size)
@@ -274,29 +386,110 @@ static void do_read(int fd, void *buf, size_t size)
274 } 386 }
275} 387}
276 388
277struct perf_header *perf_header__read(int fd) 389int perf_header__process_sections(struct perf_header *self, int fd,
390 int (*process)(struct perf_file_section *self,
391 int feat, int fd))
278{ 392{
279 struct perf_header *self = perf_header__new(); 393 struct perf_file_section *feat_sec;
280 struct perf_file_header f_header; 394 int nr_sections;
281 struct perf_file_attr f_attr; 395 int sec_size;
282 u64 f_id; 396 int idx = 0;
397 int err = 0, feat = 1;
283 398
284 int nr_attrs, nr_ids, i, j; 399 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
400 if (!nr_sections)
401 return 0;
402
403 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
404 if (!feat_sec)
405 return -1;
406
407 sec_size = sizeof(*feat_sec) * nr_sections;
285 408
409 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
410
411 do_read(fd, feat_sec, sec_size);
412
413 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
414 if (perf_header__has_feat(self, feat)) {
415 struct perf_file_section *sec = &feat_sec[idx++];
416
417 err = process(sec, feat, fd);
418 if (err < 0)
419 break;
420 }
421 ++feat;
422 }
423
424 free(feat_sec);
425 return err;
426};
427
428int perf_file_header__read(struct perf_file_header *self,
429 struct perf_header *ph, int fd)
430{
286 lseek(fd, 0, SEEK_SET); 431 lseek(fd, 0, SEEK_SET);
287 do_read(fd, &f_header, sizeof(f_header)); 432 do_read(fd, self, sizeof(*self));
288 433
289 if (f_header.magic != PERF_MAGIC || 434 if (self->magic != PERF_MAGIC ||
290 f_header.attr_size != sizeof(f_attr)) 435 self->attr_size != sizeof(struct perf_file_attr))
291 die("incompatible file format"); 436 return -1;
292 437
293 if (f_header.size != sizeof(f_header)) { 438 if (self->size != sizeof(*self)) {
294 /* Support the previous format */ 439 /* Support the previous format */
295 if (f_header.size == offsetof(typeof(f_header), trace_info)) 440 if (self->size == offsetof(typeof(*self), adds_features))
296 f_header.trace_info.size = 0; 441 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
297 else 442 else
298 die("incompatible file format"); 443 return -1;
444 }
445
446 memcpy(&ph->adds_features, &self->adds_features,
447 sizeof(self->adds_features));
448
449 ph->event_offset = self->event_types.offset;
450 ph->event_size = self->event_types.size;
451 ph->data_offset = self->data.offset;
452 ph->data_size = self->data.size;
453 return 0;
454}
455
456static int perf_file_section__process(struct perf_file_section *self,
457 int feat, int fd)
458{
459 if (lseek(fd, self->offset, SEEK_SET) < 0) {
460 pr_debug("Failed to lseek to %Ld offset for feature %d, "
461 "continuing...\n", self->offset, feat);
462 return 0;
463 }
464
465 switch (feat) {
466 case HEADER_TRACE_INFO:
467 trace_report(fd);
468 break;
469
470 case HEADER_BUILD_ID:
471 if (perf_header__read_build_ids(fd, self->offset, self->size))
472 pr_debug("Failed to read buildids, continuing...\n");
473 break;
474 default:
475 pr_debug("unknown feature %d, continuing...\n", feat);
476 }
477
478 return 0;
479}
480
481int perf_header__read(struct perf_header *self, int fd)
482{
483 struct perf_file_header f_header;
484 struct perf_file_attr f_attr;
485 u64 f_id;
486 int nr_attrs, nr_ids, i, j;
487
488 if (perf_file_header__read(&f_header, self, fd) < 0) {
489 pr_debug("incompatible file format\n");
490 return -EINVAL;
299 } 491 }
492
300 nr_attrs = f_header.attrs.size / sizeof(f_attr); 493 nr_attrs = f_header.attrs.size / sizeof(f_attr);
301 lseek(fd, f_header.attrs.offset, SEEK_SET); 494 lseek(fd, f_header.attrs.offset, SEEK_SET);
302 495
@@ -308,6 +501,8 @@ struct perf_header *perf_header__read(int fd)
308 tmp = lseek(fd, 0, SEEK_CUR); 501 tmp = lseek(fd, 0, SEEK_CUR);
309 502
310 attr = perf_header_attr__new(&f_attr.attr); 503 attr = perf_header_attr__new(&f_attr.attr);
504 if (attr == NULL)
505 return -ENOMEM;
311 506
312 nr_ids = f_attr.ids.size / sizeof(u64); 507 nr_ids = f_attr.ids.size / sizeof(u64);
313 lseek(fd, f_attr.ids.offset, SEEK_SET); 508 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -315,40 +510,34 @@ struct perf_header *perf_header__read(int fd)
315 for (j = 0; j < nr_ids; j++) { 510 for (j = 0; j < nr_ids; j++) {
316 do_read(fd, &f_id, sizeof(f_id)); 511 do_read(fd, &f_id, sizeof(f_id));
317 512
318 perf_header_attr__add_id(attr, f_id); 513 if (perf_header_attr__add_id(attr, f_id) < 0) {
514 perf_header_attr__delete(attr);
515 return -ENOMEM;
516 }
517 }
518 if (perf_header__add_attr(self, attr) < 0) {
519 perf_header_attr__delete(attr);
520 return -ENOMEM;
319 } 521 }
320 perf_header__add_attr(self, attr); 522
321 lseek(fd, tmp, SEEK_SET); 523 lseek(fd, tmp, SEEK_SET);
322 } 524 }
323 525
324 if (f_header.event_types.size) { 526 if (f_header.event_types.size) {
325 lseek(fd, f_header.event_types.offset, SEEK_SET); 527 lseek(fd, f_header.event_types.offset, SEEK_SET);
326 events = malloc(f_header.event_types.size); 528 events = malloc(f_header.event_types.size);
327 if (!events) 529 if (events == NULL)
328 die("nomem"); 530 return -ENOMEM;
329 do_read(fd, events, f_header.event_types.size); 531 do_read(fd, events, f_header.event_types.size);
330 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 532 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
331 } 533 }
332 534
333 self->trace_info_offset = f_header.trace_info.offset; 535 perf_header__process_sections(self, fd, perf_file_section__process);
334 self->trace_info_size = f_header.trace_info.size;
335
336 if (self->trace_info_size) {
337 lseek(fd, self->trace_info_offset, SEEK_SET);
338 trace_report(fd);
339 }
340
341 self->event_offset = f_header.event_types.offset;
342 self->event_size = f_header.event_types.size;
343
344 self->data_offset = f_header.data.offset;
345 self->data_size = f_header.data.size;
346 536
347 lseek(fd, self->data_offset, SEEK_SET); 537 lseek(fd, self->data_offset, SEEK_SET);
348 538
349 self->frozen = 1; 539 self->frozen = 1;
350 540 return 0;
351 return self;
352} 541}
353 542
354u64 perf_header__sample_type(struct perf_header *header) 543u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 30aee5160dc0..d1dbe2b79c42 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -3,8 +3,11 @@
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7 8
9#include <linux/bitmap.h>
10
8struct perf_header_attr { 11struct perf_header_attr {
9 struct perf_event_attr attr; 12 struct perf_event_attr attr;
10 int ids, size; 13 int ids, size;
@@ -12,38 +15,71 @@ struct perf_header_attr {
12 off_t id_offset; 15 off_t id_offset;
13}; 16};
14 17
18enum {
19 HEADER_TRACE_INFO = 1,
20 HEADER_BUILD_ID,
21 HEADER_LAST_FEATURE,
22};
23
24#define HEADER_FEAT_BITS 256
25
26struct perf_file_section {
27 u64 offset;
28 u64 size;
29};
30
31struct perf_file_header {
32 u64 magic;
33 u64 size;
34 u64 attr_size;
35 struct perf_file_section attrs;
36 struct perf_file_section data;
37 struct perf_file_section event_types;
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39};
40
41struct perf_header;
42
43int perf_file_header__read(struct perf_file_header *self,
44 struct perf_header *ph, int fd);
45
15struct perf_header { 46struct perf_header {
16 int frozen; 47 int frozen;
17 int attrs, size; 48 int attrs, size;
18 struct perf_header_attr **attr; 49 struct perf_header_attr **attr;
19 s64 attr_offset; 50 s64 attr_offset;
20 u64 data_offset; 51 u64 data_offset;
21 u64 data_size; 52 u64 data_size;
22 u64 event_offset; 53 u64 event_offset;
23 u64 event_size; 54 u64 event_size;
24 u64 trace_info_offset; 55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
25 u64 trace_info_size;
26}; 56};
27 57
28struct perf_header *perf_header__read(int fd); 58struct perf_header *perf_header__new(void);
29void perf_header__write(struct perf_header *self, int fd); 59void perf_header__delete(struct perf_header *self);
60
61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
30 63
31void perf_header__add_attr(struct perf_header *self, 64int perf_header__add_attr(struct perf_header *self,
32 struct perf_header_attr *attr); 65 struct perf_header_attr *attr);
33 66
34void perf_header__push_event(u64 id, const char *name); 67void perf_header__push_event(u64 id, const char *name);
35char *perf_header__find_event(u64 id); 68char *perf_header__find_event(u64 id);
36 69
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
71void perf_header_attr__delete(struct perf_header_attr *self);
37 72
38struct perf_header_attr * 73int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39perf_header_attr__new(struct perf_event_attr *attr);
40void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
41 74
42u64 perf_header__sample_type(struct perf_header *header); 75u64 perf_header__sample_type(struct perf_header *header);
43struct perf_event_attr * 76struct perf_event_attr *
44perf_header__find_attr(u64 id, struct perf_header *header); 77perf_header__find_attr(u64 id, struct perf_header *header);
45void perf_header__set_trace_info(void); 78void perf_header__set_feat(struct perf_header *self, int feat);
79bool perf_header__has_feat(const struct perf_header *self, int feat);
46 80
47struct perf_header *perf_header__new(void); 81int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self,
83 int feat, int fd));
48 84
49#endif /* __PERF_HEADER_H */ 85#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 7393a02fd8d4..0ebf6ee16caa 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -10,31 +10,23 @@ struct callchain_param callchain_param = {
10 .min_percent = 0.5 10 .min_percent = 0.5
11}; 11};
12 12
13unsigned long total;
14unsigned long total_mmap;
15unsigned long total_comm;
16unsigned long total_fork;
17unsigned long total_unknown;
18unsigned long total_lost;
19
20/* 13/*
21 * histogram, sorted on item, collects counts 14 * histogram, sorted on item, collects counts
22 */ 15 */
23 16
24struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, 17struct hist_entry *__hist_entry__add(struct addr_location *al,
25 struct symbol *sym,
26 struct symbol *sym_parent, 18 struct symbol *sym_parent,
27 u64 ip, u64 count, char level, bool *hit) 19 u64 count, bool *hit)
28{ 20{
29 struct rb_node **p = &hist.rb_node; 21 struct rb_node **p = &hist.rb_node;
30 struct rb_node *parent = NULL; 22 struct rb_node *parent = NULL;
31 struct hist_entry *he; 23 struct hist_entry *he;
32 struct hist_entry entry = { 24 struct hist_entry entry = {
33 .thread = thread, 25 .thread = al->thread,
34 .map = map, 26 .map = al->map,
35 .sym = sym, 27 .sym = al->sym,
36 .ip = ip, 28 .ip = al->addr,
37 .level = level, 29 .level = al->level,
38 .count = count, 30 .count = count,
39 .parent = sym_parent, 31 .parent = sym_parent,
40 }; 32 };
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index ac2149c559b0..3020db0c9292 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -36,9 +36,9 @@ extern unsigned long total_fork;
36extern unsigned long total_unknown; 36extern unsigned long total_unknown;
37extern unsigned long total_lost; 37extern unsigned long total_lost;
38 38
39struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map, 39struct hist_entry *__hist_entry__add(struct addr_location *al,
40 struct symbol *sym, struct symbol *parent, 40 struct symbol *parent,
41 u64 ip, u64 count, char level, bool *hit); 41 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 44extern void hist_entry__free(struct hist_entry *);
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..94507639a8c4
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,3 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..8d63116e9435
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,29 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10#undef __KERNEL__
11
12static inline void set_bit(int nr, unsigned long *addr)
13{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15}
16
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{
19 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21}
22
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
24 long size, unsigned long offset);
25
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
27 long size, unsigned long offset);
28
29#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..a53d4ee1e0b7
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../util.h"
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index a6b87390cb52..21c0274c02fa 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -1,6 +1,16 @@
1#ifndef PERF_LINUX_KERNEL_H_ 1#ifndef PERF_LINUX_KERNEL_H_
2#define PERF_LINUX_KERNEL_H_ 2#define PERF_LINUX_KERNEL_H_
3 3
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8
9#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
10
11#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
12#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
13
4#ifndef offsetof 14#ifndef offsetof
5#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
6#endif 16#endif
@@ -26,4 +36,70 @@
26 _max1 > _max2 ? _max1 : _max2; }) 36 _max1 > _max2 ? _max1 : _max2; })
27#endif 37#endif
28 38
39#ifndef min
40#define min(x, y) ({ \
41 typeof(x) _min1 = (x); \
42 typeof(y) _min2 = (y); \
43 (void) (&_min1 == &_min2); \
44 _min1 < _min2 ? _min1 : _min2; })
45#endif
46
47#ifndef BUG_ON
48#define BUG_ON(cond) assert(!(cond))
49#endif
50
51/*
52 * Both need more care to handle endianness
53 * (Don't use bitmap_copy_le() for now)
54 */
55#define cpu_to_le64(x) (x)
56#define cpu_to_le32(x) (x)
57
58static inline int
59vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
60{
61 int i;
62 ssize_t ssize = size;
63
64 i = vsnprintf(buf, size, fmt, args);
65
66 return (i >= ssize) ? (ssize - 1) : i;
67}
68
69static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
70{
71 va_list args;
72 ssize_t ssize = size;
73 int i;
74
75 va_start(args, fmt);
76 i = vsnprintf(buf, size, fmt, args);
77 va_end(args);
78
79 return (i >= ssize) ? (ssize - 1) : i;
80}
81
82static inline unsigned long
83simple_strtoul(const char *nptr, char **endptr, int base)
84{
85 return strtoul(nptr, endptr, base);
86}
87
88#ifndef pr_fmt
89#define pr_fmt(fmt) fmt
90#endif
91
92#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
94#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
96#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
98#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
104
29#endif 105#endif
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
new file mode 100644
index 000000000000..3b2f5900276f
--- /dev/null
+++ b/tools/perf/util/include/linux/string.h
@@ -0,0 +1 @@
#include <string.h>
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
new file mode 100644
index 000000000000..196862a81a21
--- /dev/null
+++ b/tools/perf/util/include/linux/types.h
@@ -0,0 +1,9 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#define DECLARE_BITMAP(name,bits) \
7 unsigned long name[BITS_TO_LONGS(bits)]
8
9#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..69f94fe9db20 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <stdio.h> 5#include <stdio.h>
6#include "debug.h"
6 7
7static inline int is_anon_memory(const char *filename) 8static inline int is_anon_memory(const char *filename)
8{ 9{
@@ -19,13 +20,28 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
19 return n; 20 return n;
20} 21}
21 22
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen) 23void map__init(struct map *self, enum map_type type,
24 u64 start, u64 end, u64 pgoff, struct dso *dso)
25{
26 self->type = type;
27 self->start = start;
28 self->end = end;
29 self->pgoff = pgoff;
30 self->dso = dso;
31 self->map_ip = map__map_ip;
32 self->unmap_ip = map__unmap_ip;
33 RB_CLEAR_NODE(&self->rb_node);
34}
35
36struct map *map__new(struct mmap_event *event, enum map_type type,
37 char *cwd, int cwdlen)
23{ 38{
24 struct map *self = malloc(sizeof(*self)); 39 struct map *self = malloc(sizeof(*self));
25 40
26 if (self != NULL) { 41 if (self != NULL) {
27 const char *filename = event->filename; 42 const char *filename = event->filename;
28 char newfilename[PATH_MAX]; 43 char newfilename[PATH_MAX];
44 struct dso *dso;
29 int anon; 45 int anon;
30 46
31 if (cwd) { 47 if (cwd) {
@@ -45,18 +61,15 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
45 filename = newfilename; 61 filename = newfilename;
46 } 62 }
47 63
48 self->start = event->start; 64 dso = dsos__findnew(filename);
49 self->end = event->start + event->len; 65 if (dso == NULL)
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete; 66 goto out_delete;
55 67
68 map__init(self, type, event->start, event->start + event->len,
69 event->pgoff, dso);
70
56 if (self->dso == vdso || anon) 71 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip; 72 self->map_ip = self->unmap_ip = identity__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 } 73 }
61 return self; 74 return self;
62out_delete: 75out_delete:
@@ -64,6 +77,72 @@ out_delete:
64 return NULL; 77 return NULL;
65} 78}
66 79
80void map__delete(struct map *self)
81{
82 free(self);
83}
84
85void map__fixup_start(struct map *self)
86{
87 struct rb_root *symbols = &self->dso->symbols[self->type];
88 struct rb_node *nd = rb_first(symbols);
89 if (nd != NULL) {
90 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
91 self->start = sym->start;
92 }
93}
94
95void map__fixup_end(struct map *self)
96{
97 struct rb_root *symbols = &self->dso->symbols[self->type];
98 struct rb_node *nd = rb_last(symbols);
99 if (nd != NULL) {
100 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
101 self->end = sym->end;
102 }
103}
104
105#define DSO__DELETED "(deleted)"
106
107struct symbol *map__find_symbol(struct map *self, u64 addr,
108 symbol_filter_t filter)
109{
110 if (!dso__loaded(self->dso, self->type)) {
111 int nr = dso__load(self->dso, self, filter);
112
113 if (nr < 0) {
114 if (self->dso->has_build_id) {
115 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
116
117 build_id__sprintf(self->dso->build_id,
118 sizeof(self->dso->build_id),
119 sbuild_id);
120 pr_warning("%s with build id %s not found",
121 self->dso->long_name, sbuild_id);
122 } else
123 pr_warning("Failed to open %s",
124 self->dso->long_name);
125 pr_warning(", continuing without symbols\n");
126 return NULL;
127 } else if (nr == 0) {
128 const char *name = self->dso->long_name;
129 const size_t len = strlen(name);
130 const size_t real_len = len - sizeof(DSO__DELETED);
131
132 if (len > sizeof(DSO__DELETED) &&
133 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
134 pr_warning("%.*s was updated, restart the long running apps that use it!\n",
135 (int)real_len, name);
136 } else {
137 pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
138 }
139 return NULL;
140 }
141 }
142
143 return self->dso->find_symbol(self->dso, self->type, addr);
144}
145
67struct map *map__clone(struct map *self) 146struct map *map__clone(struct map *self)
68{ 147{
69 struct map *map = malloc(sizeof(*self)); 148 struct map *map = malloc(sizeof(*self));
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..9e5dbd66d34d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
1 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
@@ -7,10 +7,12 @@
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10#include "debugfs.h"
10 11
11int nr_counters; 12int nr_counters;
12 13
13struct perf_event_attr attrs[MAX_COUNTERS]; 14struct perf_event_attr attrs[MAX_COUNTERS];
15char *filters[MAX_COUNTERS];
14 16
15struct event_symbol { 17struct event_symbol {
16 u8 type; 18 u8 type;
@@ -46,6 +48,8 @@ static struct event_symbol event_symbols[] = {
46 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
47 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
49}; 53};
50 54
51#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -74,6 +78,8 @@ static const char *sw_event_names[] = {
74 "CPU-migrations", 78 "CPU-migrations",
75 "minor-faults", 79 "minor-faults",
76 "major-faults", 80 "major-faults",
81 "alignment-faults",
82 "emulation-faults",
77}; 83};
78 84
79#define MAX_ALIASES 8 85#define MAX_ALIASES 8
@@ -148,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
148 154
149#define MAX_EVENT_LENGTH 512 155#define MAX_EVENT_LENGTH 512
150 156
151int valid_debugfs_mount(const char *debugfs)
152{
153 struct statfs st_fs;
154
155 if (statfs(debugfs, &st_fs) < 0)
156 return -ENOENT;
157 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
158 return -ENOENT;
159 return 0;
160}
161 157
162struct tracepoint_path *tracepoint_id_to_path(u64 config) 158struct tracepoint_path *tracepoint_id_to_path(u64 config)
163{ 159{
@@ -170,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
170 char evt_path[MAXPATHLEN]; 166 char evt_path[MAXPATHLEN];
171 char dir_path[MAXPATHLEN]; 167 char dir_path[MAXPATHLEN];
172 168
173 if (valid_debugfs_mount(debugfs_path)) 169 if (debugfs_valid_mountpoint(debugfs_path))
174 return NULL; 170 return NULL;
175 171
176 sys_dir = opendir(debugfs_path); 172 sys_dir = opendir(debugfs_path);
@@ -201,7 +197,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
201 if (id == config) { 197 if (id == config) {
202 closedir(evt_dir); 198 closedir(evt_dir);
203 closedir(sys_dir); 199 closedir(sys_dir);
204 path = calloc(1, sizeof(path)); 200 path = zalloc(sizeof(path));
205 path->system = malloc(MAX_EVENT_LENGTH); 201 path->system = malloc(MAX_EVENT_LENGTH);
206 if (!path->system) { 202 if (!path->system) {
207 free(path); 203 free(path);
@@ -509,7 +505,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
509 char sys_name[MAX_EVENT_LENGTH]; 505 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length; 506 unsigned int sys_length, evt_length;
511 507
512 if (valid_debugfs_mount(debugfs_path)) 508 if (debugfs_valid_mountpoint(debugfs_path))
513 return 0; 509 return 0;
514 510
515 evt_name = strchr(*strp, ':'); 511 evt_name = strchr(*strp, ':');
@@ -544,6 +540,81 @@ static enum event_result parse_tracepoint_event(const char **strp,
544 attr, strp); 540 attr, strp);
545} 541}
546 542
543static enum event_result
544parse_breakpoint_type(const char *type, const char **strp,
545 struct perf_event_attr *attr)
546{
547 int i;
548
549 for (i = 0; i < 3; i++) {
550 if (!type[i])
551 break;
552
553 switch (type[i]) {
554 case 'r':
555 attr->bp_type |= HW_BREAKPOINT_R;
556 break;
557 case 'w':
558 attr->bp_type |= HW_BREAKPOINT_W;
559 break;
560 case 'x':
561 attr->bp_type |= HW_BREAKPOINT_X;
562 break;
563 default:
564 return EVT_FAILED;
565 }
566 }
567 if (!attr->bp_type) /* Default */
568 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
569
570 *strp = type + i;
571
572 return EVT_HANDLED;
573}
574
575static enum event_result
576parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
577{
578 const char *target;
579 const char *type;
580 char *endaddr;
581 u64 addr;
582 enum event_result err;
583
584 target = strchr(*strp, ':');
585 if (!target)
586 return EVT_FAILED;
587
588 if (strncmp(*strp, "mem", target - *strp) != 0)
589 return EVT_FAILED;
590
591 target++;
592
593 addr = strtoull(target, &endaddr, 0);
594 if (target == endaddr)
595 return EVT_FAILED;
596
597 attr->bp_addr = addr;
598 *strp = endaddr;
599
600 type = strchr(target, ':');
601
602 /* If no type is defined, just rw as default */
603 if (!type) {
604 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
605 } else {
606 err = parse_breakpoint_type(++type, strp, attr);
607 if (err == EVT_FAILED)
608 return EVT_FAILED;
609 }
610
611 /* We should find a nice way to override the access type */
612 attr->bp_len = HW_BREAKPOINT_LEN_4;
613 attr->type = PERF_TYPE_BREAKPOINT;
614
615 return EVT_HANDLED;
616}
617
547static int check_events(const char *str, unsigned int i) 618static int check_events(const char *str, unsigned int i)
548{ 619{
549 int n; 620 int n;
@@ -677,6 +748,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
677 if (ret != EVT_FAILED) 748 if (ret != EVT_FAILED)
678 goto modifier; 749 goto modifier;
679 750
751 ret = parse_breakpoint_event(str, attr);
752 if (ret != EVT_FAILED)
753 goto modifier;
754
755 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
756 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
680 return EVT_FAILED; 757 return EVT_FAILED;
681 758
682modifier: 759modifier:
@@ -708,7 +785,6 @@ static void store_event_type(const char *orgname)
708 perf_header__push_event(id, orgname); 785 perf_header__push_event(id, orgname);
709} 786}
710 787
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 788int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 789{
714 struct perf_event_attr attr; 790 struct perf_event_attr attr;
@@ -745,6 +821,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 821 return 0;
746} 822}
747 823
824int parse_filter(const struct option *opt __used, const char *str,
825 int unset __used)
826{
827 int i = nr_counters - 1;
828 int len = strlen(str);
829
830 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
831 fprintf(stderr,
832 "-F option should follow a -e tracepoint option\n");
833 return -1;
834 }
835
836 filters[i] = malloc(len + 1);
837 if (!filters[i]) {
838 fprintf(stderr, "not enough memory to hold filter string\n");
839 return -1;
840 }
841 strcpy(filters[i], str);
842
843 return 0;
844}
845
748static const char * const event_type_descriptors[] = { 846static const char * const event_type_descriptors[] = {
749 "", 847 "",
750 "Hardware event", 848 "Hardware event",
@@ -764,7 +862,7 @@ static void print_tracepoint_events(void)
764 char evt_path[MAXPATHLEN]; 862 char evt_path[MAXPATHLEN];
765 char dir_path[MAXPATHLEN]; 863 char dir_path[MAXPATHLEN];
766 864
767 if (valid_debugfs_mount(debugfs_path)) 865 if (debugfs_valid_mountpoint(debugfs_path))
768 return; 866 return;
769 867
770 sys_dir = opendir(debugfs_path); 868 sys_dir = opendir(debugfs_path);
@@ -782,7 +880,7 @@ static void print_tracepoint_events(void)
782 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 880 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
783 snprintf(evt_path, MAXPATHLEN, "%s:%s", 881 snprintf(evt_path, MAXPATHLEN, "%s:%s",
784 sys_dirent.d_name, evt_dirent.d_name); 882 sys_dirent.d_name, evt_dirent.d_name);
785 fprintf(stderr, " %-42s [%s]\n", evt_path, 883 printf(" %-42s [%s]\n", evt_path,
786 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 884 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
787 } 885 }
788 closedir(evt_dir); 886 closedir(evt_dir);
@@ -799,8 +897,8 @@ void print_events(void)
799 unsigned int i, type, op, prev_type = -1; 897 unsigned int i, type, op, prev_type = -1;
800 char name[40]; 898 char name[40];
801 899
802 fprintf(stderr, "\n"); 900 printf("\n");
803 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 901 printf("List of pre-defined events (to be used in -e):\n");
804 902
805 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 903 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
806 type = syms->type + 1; 904 type = syms->type + 1;
@@ -808,19 +906,19 @@ void print_events(void)
808 type = 0; 906 type = 0;
809 907
810 if (type != prev_type) 908 if (type != prev_type)
811 fprintf(stderr, "\n"); 909 printf("\n");
812 910
813 if (strlen(syms->alias)) 911 if (strlen(syms->alias))
814 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 912 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
815 else 913 else
816 strcpy(name, syms->symbol); 914 strcpy(name, syms->symbol);
817 fprintf(stderr, " %-42s [%s]\n", name, 915 printf(" %-42s [%s]\n", name,
818 event_type_descriptors[type]); 916 event_type_descriptors[type]);
819 917
820 prev_type = type; 918 prev_type = type;
821 } 919 }
822 920
823 fprintf(stderr, "\n"); 921 printf("\n");
824 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 922 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
825 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 923 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
826 /* skip invalid cache type */ 924 /* skip invalid cache type */
@@ -828,17 +926,20 @@ void print_events(void)
828 continue; 926 continue;
829 927
830 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 928 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
831 fprintf(stderr, " %-42s [%s]\n", 929 printf(" %-42s [%s]\n",
832 event_cache_name(type, op, i), 930 event_cache_name(type, op, i),
833 event_type_descriptors[4]); 931 event_type_descriptors[4]);
834 } 932 }
835 } 933 }
836 } 934 }
837 935
838 fprintf(stderr, "\n"); 936 printf("\n");
839 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 937 printf(" %-42s [raw hardware event descriptor]\n",
840 "rNNN"); 938 "rNNN");
841 fprintf(stderr, "\n"); 939 printf("\n");
940
941 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]");
942 printf("\n");
842 943
843 print_tracepoint_events(); 944 print_tracepoint_events();
844 945
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8626a439033d..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
17extern int nr_counters; 17extern int nr_counters;
18 18
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
20extern char *filters[MAX_COUNTERS];
20 21
21extern const char *event_name(int ctr); 22extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config); 23extern const char *__event_name(int type, u64 config);
23 24
24extern int parse_events(const struct option *opt, const char *str, int unset); 25extern int parse_events(const struct option *opt, const char *str, int unset);
26extern int parse_filter(const struct option *opt, const char *str, int unset);
25 27
26#define EVENTS_HELP_MAX (128*1024) 28#define EVENTS_HELP_MAX (128*1024)
27 29
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644
index 000000000000..cd7fbda5e2a5
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,484 @@
1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#define _GNU_SOURCE
23#include <sys/utsname.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <limits.h>
34
35#undef _GNU_SOURCE
36#include "event.h"
37#include "string.h"
38#include "strlist.h"
39#include "debug.h"
40#include "parse-events.h" /* For debugfs_path */
41#include "probe-event.h"
42
43#define MAX_CMDLEN 256
44#define MAX_PROBE_ARGS 128
45#define PERFPROBE_GROUP "probe"
46
47#define semantic_error(msg ...) die("Semantic error :" msg)
48
49/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...)
51{
52 int ret;
53 va_list ap;
54 va_start(ap, format);
55 ret = vsnprintf(str, size, format, ap);
56 va_end(ap);
57 if (ret >= (int)size)
58 ret = -E2BIG;
59 return ret;
60}
61
62/* Parse probepoint definition. */
63static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
64{
65 char *ptr, *tmp;
66 char c, nc = 0;
67 /*
68 * <Syntax>
69 * perf probe SRC:LN
70 * perf probe FUNC[+OFFS|%return][@SRC]
71 */
72
73 ptr = strpbrk(arg, ":+@%");
74 if (ptr) {
75 nc = *ptr;
76 *ptr++ = '\0';
77 }
78
79 /* Check arg is function or file and copy it */
80 if (strchr(arg, '.')) /* File */
81 pp->file = strdup(arg);
82 else /* Function */
83 pp->function = strdup(arg);
84 DIE_IF(pp->file == NULL && pp->function == NULL);
85
86 /* Parse other options */
87 while (ptr) {
88 arg = ptr;
89 c = nc;
90 ptr = strpbrk(arg, ":+@%");
91 if (ptr) {
92 nc = *ptr;
93 *ptr++ = '\0';
94 }
95 switch (c) {
96 case ':': /* Line number */
97 pp->line = strtoul(arg, &tmp, 0);
98 if (*tmp != '\0')
99 semantic_error("There is non-digit charactor"
100 " in line number.");
101 break;
102 case '+': /* Byte offset from a symbol */
103 pp->offset = strtoul(arg, &tmp, 0);
104 if (*tmp != '\0')
105 semantic_error("There is non-digit charactor"
106 " in offset.");
107 break;
108 case '@': /* File name */
109 if (pp->file)
110 semantic_error("SRC@SRC is not allowed.");
111 pp->file = strdup(arg);
112 DIE_IF(pp->file == NULL);
113 if (ptr)
114 semantic_error("@SRC must be the last "
115 "option.");
116 break;
117 case '%': /* Probe places */
118 if (strcmp(arg, "return") == 0) {
119 pp->retprobe = 1;
120 } else /* Others not supported yet */
121 semantic_error("%%%s is not supported.", arg);
122 break;
123 default:
124 DIE_IF("Program has a bug.");
125 break;
126 }
127 }
128
129 /* Exclusion check */
130 if (pp->line && pp->offset)
131 semantic_error("Offset can't be used with line number.");
132
133 if (!pp->line && pp->file && !pp->function)
134 semantic_error("File always requires line number.");
135
136 if (pp->offset && !pp->function)
137 semantic_error("Offset requires an entry function.");
138
139 if (pp->retprobe && !pp->function)
140 semantic_error("Return probe requires an entry function.");
141
142 if ((pp->offset || pp->line) && pp->retprobe)
143 semantic_error("Offset/Line can't be used with return probe.");
144
145 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
146 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
147}
148
149/* Parse perf-probe event definition */
150int parse_perf_probe_event(const char *str, struct probe_point *pp)
151{
152 char **argv;
153 int argc, i, need_dwarf = 0;
154
155 argv = argv_split(str, &argc);
156 if (!argv)
157 die("argv_split failed.");
158 if (argc > MAX_PROBE_ARGS + 1)
159 semantic_error("Too many arguments");
160
161 /* Parse probe point */
162 parse_perf_probe_probepoint(argv[0], pp);
163 if (pp->file || pp->line)
164 need_dwarf = 1;
165
166 /* Copy arguments and ensure return probe has no C argument */
167 pp->nr_args = argc - 1;
168 pp->args = zalloc(sizeof(char *) * pp->nr_args);
169 for (i = 0; i < pp->nr_args; i++) {
170 pp->args[i] = strdup(argv[i + 1]);
171 if (!pp->args[i])
172 die("Failed to copy argument.");
173 if (is_c_varname(pp->args[i])) {
174 if (pp->retprobe)
175 semantic_error("You can't specify local"
176 " variable for kretprobe");
177 need_dwarf = 1;
178 }
179 }
180
181 argv_free(argv);
182 return need_dwarf;
183}
184
185/* Parse kprobe_events event into struct probe_point */
186void parse_trace_kprobe_event(const char *str, char **group, char **event,
187 struct probe_point *pp)
188{
189 char pr;
190 char *p;
191 int ret, i, argc;
192 char **argv;
193
194 pr_debug("Parsing kprobe_events: %s\n", str);
195 argv = argv_split(str, &argc);
196 if (!argv)
197 die("argv_split failed.");
198 if (argc < 2)
199 semantic_error("Too less arguments.");
200
201 /* Scan event and group name. */
202 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
203 &pr, (float *)(void *)group, (float *)(void *)event);
204 if (ret != 3)
205 semantic_error("Failed to parse event name: %s", argv[0]);
206 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
207
208 if (!pp)
209 goto end;
210
211 pp->retprobe = (pr == 'r');
212
213 /* Scan function name and offset */
214 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
215 if (ret == 1)
216 pp->offset = 0;
217
218 /* kprobe_events doesn't have this information */
219 pp->line = 0;
220 pp->file = NULL;
221
222 pp->nr_args = argc - 2;
223 pp->args = zalloc(sizeof(char *) * pp->nr_args);
224 for (i = 0; i < pp->nr_args; i++) {
225 p = strchr(argv[i + 2], '=');
226 if (p) /* We don't need which register is assigned. */
227 *p = '\0';
228 pp->args[i] = strdup(argv[i + 2]);
229 if (!pp->args[i])
230 die("Failed to copy argument.");
231 }
232
233end:
234 argv_free(argv);
235}
236
237int synthesize_perf_probe_event(struct probe_point *pp)
238{
239 char *buf;
240 char offs[64] = "", line[64] = "";
241 int i, len, ret;
242
243 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
244 if (!buf)
245 die("Failed to allocate memory by zalloc.");
246 if (pp->offset) {
247 ret = e_snprintf(offs, 64, "+%d", pp->offset);
248 if (ret <= 0)
249 goto error;
250 }
251 if (pp->line) {
252 ret = e_snprintf(line, 64, ":%d", pp->line);
253 if (ret <= 0)
254 goto error;
255 }
256
257 if (pp->function)
258 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
259 offs, pp->retprobe ? "%return" : "", line);
260 else
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->file, line);
262 if (ret <= 0)
263 goto error;
264 len = ret;
265
266 for (i = 0; i < pp->nr_args; i++) {
267 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
268 pp->args[i]);
269 if (ret <= 0)
270 goto error;
271 len += ret;
272 }
273 pp->found = 1;
274
275 return pp->found;
276error:
277 free(pp->probes[0]);
278
279 return ret;
280}
281
282int synthesize_trace_kprobe_event(struct probe_point *pp)
283{
284 char *buf;
285 int i, len, ret;
286
287 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
288 if (!buf)
289 die("Failed to allocate memory by zalloc.");
290 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
291 if (ret <= 0)
292 goto error;
293 len = ret;
294
295 for (i = 0; i < pp->nr_args; i++) {
296 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
297 pp->args[i]);
298 if (ret <= 0)
299 goto error;
300 len += ret;
301 }
302 pp->found = 1;
303
304 return pp->found;
305error:
306 free(pp->probes[0]);
307
308 return ret;
309}
310
311static int open_kprobe_events(int flags, int mode)
312{
313 char buf[PATH_MAX];
314 int ret;
315
316 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
317 if (ret < 0)
318 die("Failed to make kprobe_events path.");
319
320 ret = open(buf, flags, mode);
321 if (ret < 0) {
322 if (errno == ENOENT)
323 die("kprobe_events file does not exist -"
324 " please rebuild with CONFIG_KPROBE_TRACER.");
325 else
326 die("Could not open kprobe_events file: %s",
327 strerror(errno));
328 }
329 return ret;
330}
331
332/* Get raw string list of current kprobe_events */
333static struct strlist *get_trace_kprobe_event_rawlist(int fd)
334{
335 int ret, idx;
336 FILE *fp;
337 char buf[MAX_CMDLEN];
338 char *p;
339 struct strlist *sl;
340
341 sl = strlist__new(true, NULL);
342
343 fp = fdopen(dup(fd), "r");
344 while (!feof(fp)) {
345 p = fgets(buf, MAX_CMDLEN, fp);
346 if (!p)
347 break;
348
349 idx = strlen(p) - 1;
350 if (p[idx] == '\n')
351 p[idx] = '\0';
352 ret = strlist__add(sl, buf);
353 if (ret < 0)
354 die("strlist__add failed: %s", strerror(-ret));
355 }
356 fclose(fp);
357
358 return sl;
359}
360
361/* Free and zero clear probe_point */
362static void clear_probe_point(struct probe_point *pp)
363{
364 int i;
365
366 if (pp->function)
367 free(pp->function);
368 if (pp->file)
369 free(pp->file);
370 for (i = 0; i < pp->nr_args; i++)
371 free(pp->args[i]);
372 if (pp->args)
373 free(pp->args);
374 for (i = 0; i < pp->found; i++)
375 free(pp->probes[i]);
376 memset(pp, 0, sizeof(pp));
377}
378
379/* List up current perf-probe events */
380void show_perf_probe_events(void)
381{
382 unsigned int i;
383 int fd;
384 char *group, *event;
385 struct probe_point pp;
386 struct strlist *rawlist;
387 struct str_node *ent;
388
389 fd = open_kprobe_events(O_RDONLY, 0);
390 rawlist = get_trace_kprobe_event_rawlist(fd);
391 close(fd);
392
393 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
394 ent = strlist__entry(rawlist, i);
395 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
396 synthesize_perf_probe_event(&pp);
397 printf("[%s:%s]\t%s\n", group, event, pp.probes[0]);
398 free(group);
399 free(event);
400 clear_probe_point(&pp);
401 }
402
403 strlist__delete(rawlist);
404}
405
406/* Get current perf-probe event names */
407static struct strlist *get_perf_event_names(int fd)
408{
409 unsigned int i;
410 char *group, *event;
411 struct strlist *sl, *rawlist;
412 struct str_node *ent;
413
414 rawlist = get_trace_kprobe_event_rawlist(fd);
415
416 sl = strlist__new(false, NULL);
417 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
418 ent = strlist__entry(rawlist, i);
419 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
420 strlist__add(sl, event);
421 free(group);
422 }
423
424 strlist__delete(rawlist);
425
426 return sl;
427}
428
429static int write_trace_kprobe_event(int fd, const char *buf)
430{
431 int ret;
432
433 ret = write(fd, buf, strlen(buf));
434 if (ret <= 0)
435 die("Failed to create event.");
436 else
437 printf("Added new event: %s\n", buf);
438
439 return ret;
440}
441
442static void get_new_event_name(char *buf, size_t len, const char *base,
443 struct strlist *namelist)
444{
445 int i, ret;
446 for (i = 0; i < MAX_EVENT_INDEX; i++) {
447 ret = e_snprintf(buf, len, "%s_%d", base, i);
448 if (ret < 0)
449 die("snprintf() failed: %s", strerror(-ret));
450 if (!strlist__has_entry(namelist, buf))
451 break;
452 }
453 if (i == MAX_EVENT_INDEX)
454 die("Too many events are on the same function.");
455}
456
457void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
458{
459 int i, j, fd;
460 struct probe_point *pp;
461 char buf[MAX_CMDLEN];
462 char event[64];
463 struct strlist *namelist;
464
465 fd = open_kprobe_events(O_RDWR, O_APPEND);
466 /* Get current event names */
467 namelist = get_perf_event_names(fd);
468
469 for (j = 0; j < nr_probes; j++) {
470 pp = probes + j;
471 for (i = 0; i < pp->found; i++) {
472 /* Get an unused new event name */
473 get_new_event_name(event, 64, pp->function, namelist);
474 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
475 pp->retprobe ? 'r' : 'p',
476 PERFPROBE_GROUP, event,
477 pp->probes[i]);
478 write_trace_kprobe_event(fd, buf);
479 /* Add added event name to namelist */
480 strlist__add(namelist, event);
481 }
482 }
483 close(fd);
484}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..0c6fe56fe38a
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,18 @@
1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H
3
4#include "probe-finder.h"
5#include "strlist.h"
6
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group,
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes);
13extern void show_perf_probe_events(void);
14
15/* Maximum index number of event-name postfix */
16#define MAX_EVENT_INDEX 1024
17
18#endif /*_PROBE_EVENT_H */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
new file mode 100644
index 000000000000..293cdfc1b8ca
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,732 @@
1/*
2 * probe-finder.c : C expression to kprobe event converter
3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <sys/utsname.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <ctype.h>
34
35#include "event.h"
36#include "debug.h"
37#include "util.h"
38#include "probe-finder.h"
39
40
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/*
51 * Generic dwarf analysis helpers
52 */
53
54#define X86_32_MAX_REGS 8
55const char *x86_32_regs_table[X86_32_MAX_REGS] = {
56 "%ax",
57 "%cx",
58 "%dx",
59 "%bx",
60 "$stack", /* Stack address instead of %sp */
61 "%bp",
62 "%si",
63 "%di",
64};
65
66#define X86_64_MAX_REGS 16
67const char *x86_64_regs_table[X86_64_MAX_REGS] = {
68 "%ax",
69 "%dx",
70 "%cx",
71 "%bx",
72 "%si",
73 "%di",
74 "%bp",
75 "%sp",
76 "%r8",
77 "%r9",
78 "%r10",
79 "%r11",
80 "%r12",
81 "%r13",
82 "%r14",
83 "%r15",
84};
85
86/* TODO: switching by dwarf address size */
87#ifdef __x86_64__
88#define ARCH_MAX_REGS X86_64_MAX_REGS
89#define arch_regs_table x86_64_regs_table
90#else
91#define ARCH_MAX_REGS X86_32_MAX_REGS
92#define arch_regs_table x86_32_regs_table
93#endif
94
95/* Return architecture dependent register string (for kprobe-tracer) */
96static const char *get_arch_regstr(unsigned int n)
97{
98 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
99}
100
101/*
102 * Compare the tail of two strings.
103 * Return 0 if whole of either string is same as another's tail part.
104 */
105static int strtailcmp(const char *s1, const char *s2)
106{
107 int i1 = strlen(s1);
108 int i2 = strlen(s2);
109 while (--i1 > 0 && --i2 > 0) {
110 if (s1[i1] != s2[i2])
111 return s1[i1] - s2[i2];
112 }
113 return 0;
114}
115
116/* Find the fileno of the target file. */
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
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
128 if (ret == DW_DLV_OK) {
129 for (i = 0; i < cnt && !found; i++) {
130 if (strtailcmp(srcs[i], fname) == 0)
131 found = i + 1;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
133 }
134 for (; i < cnt; i++)
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 }
138 if (found)
139 pr_debug("found fno: %d\n", (int)found);
140 return found;
141}
142
143/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname)
145{
146 char *name;
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
158/* Check the address is in the subprogram(function). */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr,
160 Dwarf_Signed *offs)
161{
162 Dwarf_Addr lopc, hipc;
163 int ret;
164
165 /* TODO: check ranges */
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}
178
179/* Check the die is inlined function */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
181{
182 /* TODO: check strictly */
183 Dwarf_Bool inl;
184 int ret;
185
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error);
187 DIE_IF(ret == DW_DLV_ERROR);
188 return inl;
189}
190
191/* Get the offset of abstruct_origin */
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
193{
194 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs;
196 int ret;
197
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error);
199 DIE_IF(ret != DW_DLV_OK);
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
201 DIE_IF(ret != DW_DLV_OK);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
203 return cu_offs;
204}
205
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
208{
209 Dwarf_Attribute attr;
210 Dwarf_Addr addr;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215
216 /* Try to get entry pc */
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error);
218 DIE_IF(ret == DW_DLV_ERROR);
219 if (ret == DW_DLV_OK) {
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 }
225
226 /* Try to get low pc */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
228 DIE_IF(ret == DW_DLV_ERROR);
229 if (ret == DW_DLV_OK)
230 return addr;
231
232 /* Try to get ranges */
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
234 DIE_IF(ret != DW_DLV_OK);
235 ret = dwarf_formref(attr, &offs, &__dw_error);
236 DIE_IF(ret != DW_DLV_OK);
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
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}
244
245/*
246 * Search a Die from Die tree.
247 * Note: cur_link->die should be deallocated in this function.
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{
253 Dwarf_Die new_die;
254 struct die_link new_link;
255 int ret;
256
257 if (!die_cb)
258 return 0;
259
260 /* Check current die */
261 while (!(ret = die_cb(cur_link, data))) {
262 /* Check child die */
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
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
273 /* Move to next sibling */
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
275 &__dw_error);
276 DIE_IF(ret == DW_DLV_ERROR);
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
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
294 new_link.parent = 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}
302
303/* Find a locdesc corresponding to the address */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
305 Dwarf_Addr addr)
306{
307 Dwarf_Signed lcnt;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310
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}
337
338/* Get decl_file attribute value (file number) */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
340{
341 Dwarf_Attribute attr;
342 Dwarf_Unsigned fno;
343 int ret;
344
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
346 DIE_IF(ret != DW_DLV_OK);
347 dwarf_formudata(attr, &fno, &__dw_error);
348 DIE_IF(ret != DW_DLV_OK);
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350 return fno;
351}
352
353/* Get decl_line attribute value (line number) */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
355{
356 Dwarf_Attribute attr;
357 Dwarf_Unsigned lno;
358 int ret;
359
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
361 DIE_IF(ret != DW_DLV_OK);
362 dwarf_formudata(attr, &lno, &__dw_error);
363 DIE_IF(ret != DW_DLV_OK);
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
365 return lno;
366}
367
368/*
369 * Probe finder related functions
370 */
371
372/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
374{
375 Dwarf_Small op;
376 Dwarf_Unsigned regn;
377 Dwarf_Signed offs;
378 int deref = 0, ret;
379 const char *regs;
380
381 op = loc->lr_atom;
382
383 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) {
385 deref = 1;
386 offs = (Dwarf_Signed)loc->lr_number;
387 op = pf->fbloc.ld_s[0].lr_atom;
388 loc = &pf->fbloc.ld_s[0];
389 } else
390 offs = 0;
391
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number;
395 deref = 1;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) {
399 regn = loc->lr_number;
400 offs += (Dwarf_Signed)loc->lr_number2;
401 deref = 1;
402 } else if (op == DW_OP_regx) {
403 regn = loc->lr_number;
404 } else
405 die("Dwarf_OP %d is not supported.\n", op);
406
407 regs = get_arch_regstr(regn);
408 if (!regs)
409 die("%lld exceeds max register number.\n", regn);
410
411 if (deref)
412 ret = snprintf(pf->buf, pf->len,
413 " %s=%+lld(%s)", pf->var, offs, regs);
414 else
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
416 DIE_IF(ret < 0);
417 DIE_IF(ret >= pf->len);
418}
419
420/* Show a variables in kprobe event format */
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf)
422{
423 Dwarf_Attribute attr;
424 Dwarf_Locdesc ld;
425 int ret;
426
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error);
428 if (ret != DW_DLV_OK)
429 goto error;
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base));
431 if (ret != DW_DLV_OK)
432 goto error;
433 /* TODO? */
434 DIE_IF(ld.ld_cents != 1);
435 show_location(&ld.ld_s[0], pf);
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ;
439error:
440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", 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}
461
462/* Find a variable in a subprogram die */
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
464{
465 int ret;
466
467 if (!is_c_varname(pf->var)) {
468 /* Output raw parameters */
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
470 DIE_IF(ret < 0);
471 DIE_IF(ret >= pf->len);
472 return ;
473 }
474
475 pr_debug("Searching '%s' variable in context.\n", pf->var);
476 /* Search child die for local variables and parameters. */
477 ret = search_die_from_children(sp_die, variable_callback, pf);
478 if (!ret)
479 die("Failed to find '%s' in this function.\n", pf->var);
480}
481
482/* Get a frame base on the address */
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}
500
501/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
503 struct probe_finder *pf)
504{
505 struct probe_point *pp = pf->pp;
506 char *name;
507 char tmp[MAX_PROBE_BUFFER];
508 int ret, i, len;
509
510 /* Output name of probe point */
511 ret = dwarf_diename(sp_die, &name, &__dw_error);
512 DIE_IF(ret == DW_DLV_ERROR);
513 if (ret == DW_DLV_OK) {
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name,
515 (unsigned int)offs);
516 /* Copy the function name if possible */
517 if (!pp->function) {
518 pp->function = strdup(name);
519 pp->offset = offs;
520 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
522 } else {
523 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr);
525 if (!pp->function) {
526 /* TODO: Use _stext */
527 pp->function = strdup("");
528 pp->offset = (int)pf->addr;
529 }
530 }
531 DIE_IF(ret < 0);
532 DIE_IF(ret >= MAX_PROBE_BUFFER);
533 len = ret;
534 pr_debug("Probe point found: %s\n", tmp);
535
536 /* Find each argument */
537 get_current_frame_base(sp_die, pf);
538 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i];
540 pf->buf = &tmp[len];
541 pf->len = MAX_PROBE_BUFFER - len;
542 find_variable(sp_die, pf);
543 len += strlen(pf->buf);
544 }
545 free_current_frame_base(pf);
546
547 pp->probes[pp->found] = strdup(tmp);
548 pp->found++;
549}
550
551static int probeaddr_callback(struct die_link *dlink, void *data)
552{
553 struct probe_finder *pf = (struct probe_finder *)data;
554 Dwarf_Half tag;
555 Dwarf_Signed offs;
556 int ret;
557
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
559 DIE_IF(ret == DW_DLV_ERROR);
560 /* Check the address is in this subprogram */
561 if (tag == DW_TAG_subprogram &&
562 die_within_subprogram(dlink->die, pf->addr, &offs)) {
563 show_probepoint(dlink->die, offs, pf);
564 return 1;
565 }
566 return 0;
567}
568
569/* Find probe point from its line number */
570static void find_by_line(struct probe_finder *pf)
571{
572 Dwarf_Signed cnt, i, clm;
573 Dwarf_Line *lines;
574 Dwarf_Unsigned lineno = 0;
575 Dwarf_Addr addr;
576 Dwarf_Unsigned fno;
577 int ret;
578
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
580 DIE_IF(ret != DW_DLV_OK);
581
582 for (i = 0; i < cnt; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
584 DIE_IF(ret != DW_DLV_OK);
585 if (fno != pf->fno)
586 continue;
587
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
589 DIE_IF(ret != DW_DLV_OK);
590 if (lineno != pf->lno)
591 continue;
592
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
594 DIE_IF(ret != DW_DLV_OK);
595
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
597 DIE_IF(ret != DW_DLV_OK);
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;
601 /* Search a real subprogram including this line, */
602 ret = search_die_from_children(pf->cu_die,
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. */
607 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
609}
610
611/* Search function from function name */
612static int probefunc_callback(struct die_link *dlink, void *data)
613{
614 struct probe_finder *pf = (struct probe_finder *)data;
615 struct probe_point *pp = pf->pp;
616 struct die_link *lk;
617 Dwarf_Signed offs;
618 Dwarf_Half tag;
619 int ret;
620
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
622 DIE_IF(ret == DW_DLV_ERROR);
623 if (tag == DW_TAG_subprogram) {
624 if (die_compare_name(dlink->die, pp->function) == 0) {
625 if (pp->line) { /* Function relative line */
626 pf->fno = die_get_decl_file(dlink->die);
627 pf->lno = die_get_decl_line(dlink->die)
628 + pp->line;
629 find_by_line(pf);
630 return 1;
631 }
632 if (die_inlined_subprogram(dlink->die)) {
633 /* Inlined function, save it. */
634 ret = dwarf_die_CU_offset(dlink->die,
635 &pf->inl_offs,
636 &__dw_error);
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;
645 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, 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 }
672 }
673 return 0;
674}
675
676static void find_by_func(struct probe_finder *pf)
677{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf);
679}
680
681/* Find a probe point */
682int find_probepoint(int fd, struct probe_point *pp)
683{
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};
688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK) {
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT;
693 }
694
695 pp->found = 0;
696 while (++cu_number) {
697 /* Search CU (Compilation Unit) */
698 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
699 &addr_size, &next_cuh, &__dw_error);
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 */
705 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
706 DIE_IF(ret != DW_DLV_OK);
707
708 /* Check if target file is included. */
709 if (pp->file)
710 pf.fno = cu_find_fileno(pf.cu_die, pp->file);
711
712 if (!pp->file || pf.fno) {
713 /* Save CU base address (for frame_base) */
714 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
715 DIE_IF(ret == DW_DLV_ERROR);
716 if (ret == DW_DLV_NO_ENTRY)
717 pf.cu_base = 0;
718 if (pp->function)
719 find_by_func(&pf);
720 else {
721 pf.lno = pp->line;
722 find_by_line(&pf);
723 }
724 }
725 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
726 }
727 ret = dwarf_finish(__dw_debug, &__dw_error);
728 DIE_IF(ret != DW_DLV_OK);
729
730 return pp->found;
731}
732
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..bdebca6697d2
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,57 @@
1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H
3
4#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128
7
8static inline int is_c_varname(const char *name)
9{
10 /* TODO */
11 return isalpha(name[0]) || name[0] == '_';
12}
13
14struct probe_point {
15 /* Inputs */
16 char *file; /* File name */
17 int line; /* Line number */
18
19 char *function; /* Function name */
20 int offset; /* Offset bytes */
21
22 int nr_args; /* Number of arguments */
23 char **args; /* Arguments */
24
25 int retprobe; /* Return probe */
26
27 /* Output */
28 int found; /* Number of found probe points */
29 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
30};
31
32#ifndef NO_LIBDWARF
33extern int find_probepoint(int fd, struct probe_point *pp);
34
35#include <libdwarf/dwarf.h>
36#include <libdwarf/libdwarf.h>
37
38struct probe_finder {
39 struct probe_point *pp; /* Target probe point */
40
41 /* For function searching */
42 Dwarf_Addr addr; /* Address */
43 Dwarf_Unsigned fno; /* File number */
44 Dwarf_Unsigned lno; /* Line number */
45 Dwarf_Off inl_offs; /* Inline offset */
46 Dwarf_Die cu_die; /* Current CU */
47
48 /* For variable searching */
49 Dwarf_Addr cu_base; /* Current CU base address */
50 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
51 const char *var; /* Current variable name */
52 char *buf; /* Current output buffer */
53 int len; /* Length of output buffer */
54};
55#endif /* NO_LIBDWARF */
56
57#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 40c9acd41cad..b490354d1b23 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -5,8 +5,10 @@ char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern; 5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol"; 6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order; 7char *sort_order = default_sort_order;
8int sort__need_collapse = 0; 8int sort__need_collapse = 0;
9int sort__has_parent = 0; 9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
10 12
11unsigned int dsos__col_width; 13unsigned int dsos__col_width;
12unsigned int comms__col_width; 14unsigned int comms__col_width;
@@ -265,6 +267,19 @@ int sort_dimension__add(const char *tok)
265 sort__has_parent = 1; 267 sort__has_parent = 1;
266 } 268 }
267 269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
268 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
269 sd->taken = 1; 284 sd->taken = 1;
270 285
@@ -273,4 +288,3 @@ int sort_dimension__add(const char *tok)
273 288
274 return -ESRCH; 289 return -ESRCH;
275} 290}
276
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 13806d782af6..333e664ff45f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width; 39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width; 40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width; 41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension;
42 43
43struct hist_entry { 44struct hist_entry {
44 struct rb_node rb_node; 45 struct rb_node rb_node;
@@ -53,6 +54,14 @@ struct hist_entry {
53 struct rb_root sorted_chain; 54 struct rb_root sorted_chain;
54}; 55};
55 56
57enum sort_type {
58 SORT_PID,
59 SORT_COMM,
60 SORT_DSO,
61 SORT_SYM,
62 SORT_PARENT
63};
64
56/* 65/*
57 * configurable sorting bits 66 * configurable sorting bits
58 */ 67 */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 04743d3e9039..f24a8cc933d5 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,5 @@
1#include <string.h>
2#include "string.h" 1#include "string.h"
2#include "util.h"
3 3
4static int hex(char ch) 4static int hex(char ch)
5{ 5{
@@ -43,3 +43,186 @@ char *strxfrchar(char *s, char from, char to)
43 43
44 return s; 44 return s;
45} 45}
46
47#define K 1024LL
48/*
49 * perf_atoll()
50 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51 * and return its numeric value
52 */
53s64 perf_atoll(const char *str)
54{
55 unsigned int i;
56 s64 length = -1, unit = 1;
57
58 if (!isdigit(str[0]))
59 goto out_err;
60
61 for (i = 1; i < strlen(str); i++) {
62 switch (str[i]) {
63 case 'B':
64 case 'b':
65 break;
66 case 'K':
67 if (str[i + 1] != 'B')
68 goto out_err;
69 else
70 goto kilo;
71 case 'k':
72 if (str[i + 1] != 'b')
73 goto out_err;
74kilo:
75 unit = K;
76 break;
77 case 'M':
78 if (str[i + 1] != 'B')
79 goto out_err;
80 else
81 goto mega;
82 case 'm':
83 if (str[i + 1] != 'b')
84 goto out_err;
85mega:
86 unit = K * K;
87 break;
88 case 'G':
89 if (str[i + 1] != 'B')
90 goto out_err;
91 else
92 goto giga;
93 case 'g':
94 if (str[i + 1] != 'b')
95 goto out_err;
96giga:
97 unit = K * K * K;
98 break;
99 case 'T':
100 if (str[i + 1] != 'B')
101 goto out_err;
102 else
103 goto tera;
104 case 't':
105 if (str[i + 1] != 'b')
106 goto out_err;
107tera:
108 unit = K * K * K * K;
109 break;
110 case '\0': /* only specified figures */
111 unit = 1;
112 break;
113 default:
114 if (!isdigit(str[i]))
115 goto out_err;
116 break;
117 }
118 }
119
120 length = atoll(str) * unit;
121 goto out;
122
123out_err:
124 length = -1;
125out:
126 return length;
127}
128
129/*
130 * Helper function for splitting a string into an argv-like array.
131 * originaly copied from lib/argv_split.c
132 */
133static const char *skip_sep(const char *cp)
134{
135 while (*cp && isspace(*cp))
136 cp++;
137
138 return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143 while (*cp && !isspace(*cp))
144 cp++;
145
146 return cp;
147}
148
149static int count_argc(const char *str)
150{
151 int count = 0;
152
153 while (*str) {
154 str = skip_sep(str);
155 if (*str) {
156 count++;
157 str = skip_arg(str);
158 }
159 }
160
161 return count;
162}
163
164/**
165 * argv_free - free an argv
166 * @argv - the argument vector to be freed
167 *
168 * Frees an argv and the strings it points to.
169 */
170void argv_free(char **argv)
171{
172 char **p;
173 for (p = argv; *p; p++)
174 free(*p);
175
176 free(argv);
177}
178
179/**
180 * argv_split - split a string at whitespace, returning an argv
181 * @str: the string to be split
182 * @argcp: returned argument count
183 *
184 * Returns an array of pointers to strings which are split out from
185 * @str. This is performed by strictly splitting on white-space; no
186 * quote processing is performed. Multiple whitespace characters are
187 * considered to be a single argument separator. The returned array
188 * is always NULL-terminated. Returns NULL on memory allocation
189 * failure.
190 */
191char **argv_split(const char *str, int *argcp)
192{
193 int argc = count_argc(str);
194 char **argv = zalloc(sizeof(*argv) * (argc+1));
195 char **argvp;
196
197 if (argv == NULL)
198 goto out;
199
200 if (argcp)
201 *argcp = argc;
202
203 argvp = argv;
204
205 while (*str) {
206 str = skip_sep(str);
207
208 if (*str) {
209 const char *p = str;
210 char *t;
211
212 str = skip_arg(str);
213
214 t = strndup(p, str-p);
215 if (t == NULL)
216 goto fail;
217 *argvp++ = t;
218 }
219 }
220 *argvp = NULL;
221
222out:
223 return argv;
224
225fail:
226 argv_free(argv);
227 return NULL;
228}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 2c84bf65ba0f..bfecec265a1a 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,6 +5,9 @@
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to); 7char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv);
8 11
9#define _STR(x) #x 12#define _STR(x) #x
10#define STR(x) _STR(x) 13#define STR(x) _STR(x)
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 856655d8b0b8..b3637db025a2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -103,7 +103,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 106 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n"); 108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n"); 109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index faa84f5d4f54..fffcb937cdcb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,12 +6,16 @@
6 6
7#include "debug.h" 7#include "debug.h"
8 8
9#include <asm/bug.h>
9#include <libelf.h> 10#include <libelf.h>
10#include <gelf.h> 11#include <gelf.h>
11#include <elf.h> 12#include <elf.h>
13#include <limits.h>
12#include <sys/utsname.h> 14#include <sys/utsname.h>
13 15
14const char *sym_hist_filter; 16#ifndef NT_GNU_BUILD_ID
17#define NT_GNU_BUILD_ID 3
18#endif
15 19
16enum dso_origin { 20enum dso_origin {
17 DSO__ORIG_KERNEL = 0, 21 DSO__ORIG_KERNEL = 0,
@@ -24,16 +28,37 @@ enum dso_origin {
24 DSO__ORIG_NOT_FOUND, 28 DSO__ORIG_NOT_FOUND,
25}; 29};
26 30
27static void dsos__add(struct dso *dso); 31static void dsos__add(struct list_head *head, struct dso *dso);
28static struct dso *dsos__find(const char *name); 32static struct map *thread__find_map_by_name(struct thread *self, char *name);
29static struct map *map__new2(u64 start, struct dso *dso); 33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
30static void kernel_maps__insert(struct map *map); 34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct thread *thread, symbol_filter_t filter);
37unsigned int symbol__priv_size;
38static int vmlinux_path__nr_entries;
39static char **vmlinux_path;
40
41static struct symbol_conf symbol_conf__defaults = {
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
46static struct thread kthread_mem;
47struct thread *kthread = &kthread_mem;
48
49bool dso__loaded(const struct dso *self, enum map_type type)
50{
51 return self->loaded & (1 << type);
52}
31 53
32static struct rb_root kernel_maps; 54static void dso__set_loaded(struct dso *self, enum map_type type)
55{
56 self->loaded |= (1 << type);
57}
33 58
34static void dso__fixup_sym_end(struct dso *self) 59static void symbols__fixup_end(struct rb_root *self)
35{ 60{
36 struct rb_node *nd, *prevnd = rb_first(&self->syms); 61 struct rb_node *nd, *prevnd = rb_first(self);
37 struct symbol *curr, *prev; 62 struct symbol *curr, *prev;
38 63
39 if (prevnd == NULL) 64 if (prevnd == NULL)
@@ -54,10 +79,10 @@ static void dso__fixup_sym_end(struct dso *self)
54 curr->end = roundup(curr->start, 4096); 79 curr->end = roundup(curr->start, 4096);
55} 80}
56 81
57static void kernel_maps__fixup_end(void) 82static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
58{ 83{
59 struct map *prev, *curr; 84 struct map *prev, *curr;
60 struct rb_node *nd, *prevnd = rb_first(&kernel_maps); 85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
61 86
62 if (prevnd == NULL) 87 if (prevnd == NULL)
63 return; 88 return;
@@ -70,46 +95,44 @@ static void kernel_maps__fixup_end(void)
70 prev->end = curr->start - 1; 95 prev->end = curr->start - 1;
71 } 96 }
72 97
73 nd = rb_last(&curr->dso->syms); 98 /*
74 if (nd) { 99 * We still haven't the actual symbols, so guess the
75 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 100 * last map final address.
76 curr->end = sym->end; 101 */
77 } 102 curr->end = ~0UL;
78} 103}
79 104
80static struct symbol *symbol__new(u64 start, u64 len, const char *name, 105static void thread__fixup_maps_end(struct thread *self)
81 unsigned int priv_size, int v)
82{ 106{
83 size_t namelen = strlen(name) + 1; 107 int i;
84 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 108 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i);
110}
85 111
86 if (!self) 112static struct symbol *symbol__new(u64 start, u64 len, const char *name)
113{
114 size_t namelen = strlen(name) + 1;
115 struct symbol *self = zalloc(symbol__priv_size +
116 sizeof(*self) + namelen);
117 if (self == NULL)
87 return NULL; 118 return NULL;
88 119
89 if (v > 2) 120 if (symbol__priv_size)
90 printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n", 121 self = ((void *)self) + symbol__priv_size;
91 start, (unsigned long)len, name, self->hist);
92
93 self->hist = NULL;
94 self->hist_sum = 0;
95 122
96 if (sym_hist_filter && !strcmp(name, sym_hist_filter))
97 self->hist = calloc(sizeof(u64), len);
98
99 if (priv_size) {
100 memset(self, 0, priv_size);
101 self = ((void *)self) + priv_size;
102 }
103 self->start = start; 123 self->start = start;
104 self->end = len ? start + len - 1 : start; 124 self->end = len ? start + len - 1 : start;
125
126 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
127
105 memcpy(self->name, name, namelen); 128 memcpy(self->name, name, namelen);
106 129
107 return self; 130 return self;
108} 131}
109 132
110static void symbol__delete(struct symbol *self, unsigned int priv_size) 133static void symbol__delete(struct symbol *self)
111{ 134{
112 free(((void *)self) - priv_size); 135 free(((void *)self) - symbol__priv_size);
113} 136}
114 137
115static size_t symbol__fprintf(struct symbol *self, FILE *fp) 138static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -118,48 +141,72 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
118 self->start, self->end, self->name); 141 self->start, self->end, self->name);
119} 142}
120 143
121struct dso *dso__new(const char *name, unsigned int sym_priv_size) 144static void dso__set_long_name(struct dso *self, char *name)
145{
146 if (name == NULL)
147 return;
148 self->long_name = name;
149 self->long_name_len = strlen(name);
150}
151
152static void dso__set_basename(struct dso *self)
153{
154 self->short_name = basename(self->long_name);
155}
156
157struct dso *dso__new(const char *name)
122{ 158{
123 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 159 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
124 160
125 if (self != NULL) { 161 if (self != NULL) {
162 int i;
126 strcpy(self->name, name); 163 strcpy(self->name, name);
127 self->long_name = self->name; 164 dso__set_long_name(self, self->name);
128 self->short_name = self->name; 165 self->short_name = self->name;
129 self->syms = RB_ROOT; 166 for (i = 0; i < MAP__NR_TYPES; ++i)
130 self->sym_priv_size = sym_priv_size; 167 self->symbols[i] = RB_ROOT;
131 self->find_symbol = dso__find_symbol; 168 self->find_symbol = dso__find_symbol;
132 self->slen_calculated = 0; 169 self->slen_calculated = 0;
133 self->origin = DSO__ORIG_NOT_FOUND; 170 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0;
172 self->has_build_id = 0;
134 } 173 }
135 174
136 return self; 175 return self;
137} 176}
138 177
139static void dso__delete_symbols(struct dso *self) 178static void symbols__delete(struct rb_root *self)
140{ 179{
141 struct symbol *pos; 180 struct symbol *pos;
142 struct rb_node *next = rb_first(&self->syms); 181 struct rb_node *next = rb_first(self);
143 182
144 while (next) { 183 while (next) {
145 pos = rb_entry(next, struct symbol, rb_node); 184 pos = rb_entry(next, struct symbol, rb_node);
146 next = rb_next(&pos->rb_node); 185 next = rb_next(&pos->rb_node);
147 rb_erase(&pos->rb_node, &self->syms); 186 rb_erase(&pos->rb_node, self);
148 symbol__delete(pos, self->sym_priv_size); 187 symbol__delete(pos);
149 } 188 }
150} 189}
151 190
152void dso__delete(struct dso *self) 191void dso__delete(struct dso *self)
153{ 192{
154 dso__delete_symbols(self); 193 int i;
194 for (i = 0; i < MAP__NR_TYPES; ++i)
195 symbols__delete(&self->symbols[i]);
155 if (self->long_name != self->name) 196 if (self->long_name != self->name)
156 free(self->long_name); 197 free(self->long_name);
157 free(self); 198 free(self);
158} 199}
159 200
160static void dso__insert_symbol(struct dso *self, struct symbol *sym) 201void dso__set_build_id(struct dso *self, void *build_id)
161{ 202{
162 struct rb_node **p = &self->syms.rb_node; 203 memcpy(self->build_id, build_id, sizeof(self->build_id));
204 self->has_build_id = 1;
205}
206
207static void symbols__insert(struct rb_root *self, struct symbol *sym)
208{
209 struct rb_node **p = &self->rb_node;
163 struct rb_node *parent = NULL; 210 struct rb_node *parent = NULL;
164 const u64 ip = sym->start; 211 const u64 ip = sym->start;
165 struct symbol *s; 212 struct symbol *s;
@@ -173,17 +220,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
173 p = &(*p)->rb_right; 220 p = &(*p)->rb_right;
174 } 221 }
175 rb_link_node(&sym->rb_node, parent, p); 222 rb_link_node(&sym->rb_node, parent, p);
176 rb_insert_color(&sym->rb_node, &self->syms); 223 rb_insert_color(&sym->rb_node, self);
177} 224}
178 225
179struct symbol *dso__find_symbol(struct dso *self, u64 ip) 226static struct symbol *symbols__find(struct rb_root *self, u64 ip)
180{ 227{
181 struct rb_node *n; 228 struct rb_node *n;
182 229
183 if (self == NULL) 230 if (self == NULL)
184 return NULL; 231 return NULL;
185 232
186 n = self->syms.rb_node; 233 n = self->rb_node;
187 234
188 while (n) { 235 while (n) {
189 struct symbol *s = rb_entry(n, struct symbol, rb_node); 236 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -199,12 +246,42 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
199 return NULL; 246 return NULL;
200} 247}
201 248
202size_t dso__fprintf(struct dso *self, FILE *fp) 249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
250{
251 return symbols__find(&self->symbols[type], addr);
252}
253
254int build_id__sprintf(u8 *self, int len, char *bf)
203{ 255{
204 size_t ret = fprintf(fp, "dso: %s\n", self->short_name); 256 char *bid = bf;
257 u8 *raw = self;
258 int i;
205 259
260 for (i = 0; i < len; ++i) {
261 sprintf(bid, "%02x", *raw);
262 ++raw;
263 bid += 2;
264 }
265
266 return raw - self;
267}
268
269size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
270{
271 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
272
273 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
274 return fprintf(fp, "%s", sbuild_id);
275}
276
277size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
278{
206 struct rb_node *nd; 279 struct rb_node *nd;
207 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 280 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
281
282 ret += dso__fprintf_buildid(self, fp);
283 ret += fprintf(fp, ")\n");
284 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
208 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 285 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
209 ret += symbol__fprintf(pos, fp); 286 ret += symbol__fprintf(pos, fp);
210 } 287 }
@@ -217,10 +294,11 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
217 * so that we can in the next step set the symbol ->end address and then 294 * so that we can in the next step set the symbol ->end address and then
218 * call kernel_maps__split_kallsyms. 295 * call kernel_maps__split_kallsyms.
219 */ 296 */
220static int kernel_maps__load_all_kallsyms(int v) 297static int dso__load_all_kallsyms(struct dso *self, struct map *map)
221{ 298{
222 char *line = NULL; 299 char *line = NULL;
223 size_t n; 300 size_t n;
301 struct rb_root *root = &self->symbols[map->type];
224 FILE *file = fopen("/proc/kallsyms", "r"); 302 FILE *file = fopen("/proc/kallsyms", "r");
225 303
226 if (file == NULL) 304 if (file == NULL)
@@ -259,13 +337,15 @@ static int kernel_maps__load_all_kallsyms(int v)
259 /* 337 /*
260 * Will fix up the end later, when we have all symbols sorted. 338 * Will fix up the end later, when we have all symbols sorted.
261 */ 339 */
262 sym = symbol__new(start, 0, symbol_name, 340 sym = symbol__new(start, 0, symbol_name);
263 kernel_map->dso->sym_priv_size, v);
264 341
265 if (sym == NULL) 342 if (sym == NULL)
266 goto out_delete_line; 343 goto out_delete_line;
267 344 /*
268 dso__insert_symbol(kernel_map->dso, sym); 345 * We will pass the symbols to the filter later, in
346 * map__split_kallsyms, when we have split the maps per module
347 */
348 symbols__insert(root, sym);
269 } 349 }
270 350
271 free(line); 351 free(line);
@@ -284,12 +364,14 @@ out_failure:
284 * kernel range is broken in several maps, named [kernel].N, as we don't have 364 * kernel range is broken in several maps, named [kernel].N, as we don't have
285 * the original ELF section names vmlinux have. 365 * the original ELF section names vmlinux have.
286 */ 366 */
287static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) 367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
368 symbol_filter_t filter)
288{ 369{
289 struct map *map = kernel_map; 370 struct map *curr_map = map;
290 struct symbol *pos; 371 struct symbol *pos;
291 int count = 0; 372 int count = 0;
292 struct rb_node *next = rb_first(&kernel_map->dso->syms); 373 struct rb_root *root = &self->symbols[map->type];
374 struct rb_node *next = rb_first(root);
293 int kernel_range = 0; 375 int kernel_range = 0;
294 376
295 while (next) { 377 while (next) {
@@ -300,16 +382,16 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
300 382
301 module = strchr(pos->name, '\t'); 383 module = strchr(pos->name, '\t');
302 if (module) { 384 if (module) {
303 if (!use_modules) 385 if (!thread->use_modules)
304 goto delete_symbol; 386 goto discard_symbol;
305 387
306 *module++ = '\0'; 388 *module++ = '\0';
307 389
308 if (strcmp(map->dso->name, module)) { 390 if (strcmp(self->name, module)) {
309 map = kernel_maps__find_by_dso_name(module); 391 curr_map = thread__find_map_by_name(thread, module);
310 if (!map) { 392 if (curr_map == NULL) {
311 fputs("/proc/{kallsyms,modules} " 393 pr_debug("/proc/{kallsyms,modules} "
312 "inconsistency!\n", stderr); 394 "inconsistency!\n");
313 return -1; 395 return -1;
314 } 396 }
315 } 397 }
@@ -317,39 +399,37 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
317 * So that we look just like we get from .ko files, 399 * So that we look just like we get from .ko files,
318 * i.e. not prelinked, relative to map->start. 400 * i.e. not prelinked, relative to map->start.
319 */ 401 */
320 pos->start = map->map_ip(map, pos->start); 402 pos->start = curr_map->map_ip(curr_map, pos->start);
321 pos->end = map->map_ip(map, pos->end); 403 pos->end = curr_map->map_ip(curr_map, pos->end);
322 } else if (map != kernel_map) { 404 } else if (curr_map != map) {
323 char dso_name[PATH_MAX]; 405 char dso_name[PATH_MAX];
324 struct dso *dso; 406 struct dso *dso;
325 407
326 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 408 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
327 kernel_range++); 409 kernel_range++);
328 410
329 dso = dso__new(dso_name, 411 dso = dso__new(dso_name);
330 kernel_map->dso->sym_priv_size);
331 if (dso == NULL) 412 if (dso == NULL)
332 return -1; 413 return -1;
333 414
334 map = map__new2(pos->start, dso); 415 curr_map = map__new2(pos->start, dso, map->type);
335 if (map == NULL) { 416 if (map == NULL) {
336 dso__delete(dso); 417 dso__delete(dso);
337 return -1; 418 return -1;
338 } 419 }
339 420
340 map->map_ip = vdso__map_ip; 421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
341 kernel_maps__insert(map); 422 __thread__insert_map(thread, curr_map);
342 ++kernel_range; 423 ++kernel_range;
343 } 424 }
344 425
345 if (filter && filter(map, pos)) { 426 if (filter && filter(curr_map, pos)) {
346delete_symbol: 427discard_symbol: rb_erase(&pos->rb_node, root);
347 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 428 symbol__delete(pos);
348 symbol__delete(pos, kernel_map->dso->sym_priv_size);
349 } else { 429 } else {
350 if (map != kernel_map) { 430 if (curr_map != map) {
351 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 431 rb_erase(&pos->rb_node, root);
352 dso__insert_symbol(map->dso, pos); 432 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
353 } 433 }
354 count++; 434 count++;
355 } 435 }
@@ -359,38 +439,27 @@ delete_symbol:
359} 439}
360 440
361 441
362static int kernel_maps__load_kallsyms(symbol_filter_t filter, 442static int dso__load_kallsyms(struct dso *self, struct map *map,
363 int use_modules, int v) 443 struct thread *thread, symbol_filter_t filter)
364{ 444{
365 if (kernel_maps__load_all_kallsyms(v)) 445 if (dso__load_all_kallsyms(self, map) < 0)
366 return -1; 446 return -1;
367 447
368 dso__fixup_sym_end(kernel_map->dso); 448 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL;
369 450
370 return kernel_maps__split_kallsyms(filter, use_modules); 451 return dso__split_kallsyms(self, map, thread, filter);
371} 452}
372 453
373static size_t kernel_maps__fprintf(FILE *fp, int v) 454size_t kernel_maps__fprintf(FILE *fp)
374{ 455{
375 size_t printed = fprintf(stderr, "Kernel maps:\n"); 456 size_t printed = fprintf(fp, "Kernel maps:\n");
376 struct rb_node *nd; 457 printed += thread__fprintf_maps(kthread, fp);
377 458 return printed + fprintf(fp, "END kernel maps\n");
378 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
379 struct map *pos = rb_entry(nd, struct map, rb_node);
380
381 printed += fprintf(fp, "Map:");
382 printed += map__fprintf(pos, fp);
383 if (v > 1) {
384 printed += dso__fprintf(pos->dso, fp);
385 printed += fprintf(fp, "--\n");
386 }
387 }
388
389 return printed + fprintf(stderr, "END kernel maps\n");
390} 459}
391 460
392static int dso__load_perf_map(struct dso *self, struct map *map, 461static int dso__load_perf_map(struct dso *self, struct map *map,
393 symbol_filter_t filter, int v) 462 symbol_filter_t filter)
394{ 463{
395 char *line = NULL; 464 char *line = NULL;
396 size_t n; 465 size_t n;
@@ -427,16 +496,15 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
427 if (len + 2 >= line_len) 496 if (len + 2 >= line_len)
428 continue; 497 continue;
429 498
430 sym = symbol__new(start, size, line + len, 499 sym = symbol__new(start, size, line + len);
431 self->sym_priv_size, v);
432 500
433 if (sym == NULL) 501 if (sym == NULL)
434 goto out_delete_line; 502 goto out_delete_line;
435 503
436 if (filter && filter(map, sym)) 504 if (filter && filter(map, sym))
437 symbol__delete(sym, self->sym_priv_size); 505 symbol__delete(sym);
438 else { 506 else {
439 dso__insert_symbol(self, sym); 507 symbols__insert(&self->symbols[map->type], sym);
440 nr_syms++; 508 nr_syms++;
441 } 509 }
442 } 510 }
@@ -542,7 +610,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
542 * And always look at the original dso, not at debuginfo packages, that 610 * And always look at the original dso, not at debuginfo packages, that
543 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 611 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
544 */ 612 */
545static int dso__synthesize_plt_symbols(struct dso *self, int v) 613static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
614 symbol_filter_t filter)
546{ 615{
547 uint32_t nr_rel_entries, idx; 616 uint32_t nr_rel_entries, idx;
548 GElf_Sym sym; 617 GElf_Sym sym;
@@ -562,7 +631,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
562 if (fd < 0) 631 if (fd < 0)
563 goto out; 632 goto out;
564 633
565 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 634 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
566 if (elf == NULL) 635 if (elf == NULL)
567 goto out_close; 636 goto out_close;
568 637
@@ -626,12 +695,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
626 "%s@plt", elf_sym__name(&sym, symstrs)); 695 "%s@plt", elf_sym__name(&sym, symstrs));
627 696
628 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 697 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
629 sympltname, self->sym_priv_size, v); 698 sympltname);
630 if (!f) 699 if (!f)
631 goto out_elf_end; 700 goto out_elf_end;
632 701
633 dso__insert_symbol(self, f); 702 if (filter && filter(map, f))
634 ++nr; 703 symbol__delete(f);
704 else {
705 symbols__insert(&self->symbols[map->type], f);
706 ++nr;
707 }
635 } 708 }
636 } else if (shdr_rel_plt.sh_type == SHT_REL) { 709 } else if (shdr_rel_plt.sh_type == SHT_REL) {
637 GElf_Rel pos_mem, *pos; 710 GElf_Rel pos_mem, *pos;
@@ -644,12 +717,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
644 "%s@plt", elf_sym__name(&sym, symstrs)); 717 "%s@plt", elf_sym__name(&sym, symstrs));
645 718
646 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 719 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
647 sympltname, self->sym_priv_size, v); 720 sympltname);
648 if (!f) 721 if (!f)
649 goto out_elf_end; 722 goto out_elf_end;
650 723
651 dso__insert_symbol(self, f); 724 if (filter && filter(map, f))
652 ++nr; 725 symbol__delete(f);
726 else {
727 symbols__insert(&self->symbols[map->type], f);
728 ++nr;
729 }
653 } 730 }
654 } 731 }
655 732
@@ -662,14 +739,14 @@ out_close:
662 if (err == 0) 739 if (err == 0)
663 return nr; 740 return nr;
664out: 741out:
665 fprintf(stderr, "%s: problems reading %s PLT info.\n", 742 pr_warning("%s: problems reading %s PLT info.\n",
666 __func__, self->long_name); 743 __func__, self->long_name);
667 return 0; 744 return 0;
668} 745}
669 746
670static int dso__load_sym(struct dso *self, struct map *map, const char *name, 747static int dso__load_sym(struct dso *self, struct map *map,
671 int fd, symbol_filter_t filter, int kernel, 748 struct thread *thread, const char *name, int fd,
672 int kmodule, int v) 749 symbol_filter_t filter, int kernel, int kmodule)
673{ 750{
674 struct map *curr_map = map; 751 struct map *curr_map = map;
675 struct dso *curr_dso = self; 752 struct dso *curr_dso = self;
@@ -686,17 +763,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
686 Elf *elf; 763 Elf *elf;
687 int nr = 0; 764 int nr = 0;
688 765
689 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 766 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
690 if (elf == NULL) { 767 if (elf == NULL) {
691 if (v) 768 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
692 fprintf(stderr, "%s: cannot read %s ELF file.\n",
693 __func__, name);
694 goto out_close; 769 goto out_close;
695 } 770 }
696 771
697 if (gelf_getehdr(elf, &ehdr) == NULL) { 772 if (gelf_getehdr(elf, &ehdr) == NULL) {
698 if (v) 773 pr_err("%s: cannot get elf header.\n", __func__);
699 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
700 goto out_elf_end; 774 goto out_elf_end;
701 } 775 }
702 776
@@ -775,25 +849,27 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
775 snprintf(dso_name, sizeof(dso_name), 849 snprintf(dso_name, sizeof(dso_name),
776 "%s%s", self->short_name, section_name); 850 "%s%s", self->short_name, section_name);
777 851
778 curr_map = kernel_maps__find_by_dso_name(dso_name); 852 curr_map = thread__find_map_by_name(thread, dso_name);
779 if (curr_map == NULL) { 853 if (curr_map == NULL) {
780 u64 start = sym.st_value; 854 u64 start = sym.st_value;
781 855
782 if (kmodule) 856 if (kmodule)
783 start += map->start + shdr.sh_offset; 857 start += map->start + shdr.sh_offset;
784 858
785 curr_dso = dso__new(dso_name, self->sym_priv_size); 859 curr_dso = dso__new(dso_name);
786 if (curr_dso == NULL) 860 if (curr_dso == NULL)
787 goto out_elf_end; 861 goto out_elf_end;
788 curr_map = map__new2(start, curr_dso); 862 curr_map = map__new2(start, curr_dso,
863 MAP__FUNCTION);
789 if (curr_map == NULL) { 864 if (curr_map == NULL) {
790 dso__delete(curr_dso); 865 dso__delete(curr_dso);
791 goto out_elf_end; 866 goto out_elf_end;
792 } 867 }
793 curr_map->map_ip = vdso__map_ip; 868 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip;
794 curr_dso->origin = DSO__ORIG_KERNEL; 870 curr_dso->origin = DSO__ORIG_KERNEL;
795 kernel_maps__insert(curr_map); 871 __thread__insert_map(kthread, curr_map);
796 dsos__add(curr_dso); 872 dsos__add(&dsos__kernel, curr_dso);
797 } else 873 } else
798 curr_dso = curr_map->dso; 874 curr_dso = curr_map->dso;
799 875
@@ -801,10 +877,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
801 } 877 }
802 878
803 if (curr_dso->adjust_symbols) { 879 if (curr_dso->adjust_symbols) {
804 if (v > 2) 880 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
805 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 881 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
806 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 882 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
807
808 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 883 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
809 } 884 }
810 /* 885 /*
@@ -816,16 +891,15 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
816 if (demangled != NULL) 891 if (demangled != NULL)
817 elf_name = demangled; 892 elf_name = demangled;
818new_symbol: 893new_symbol:
819 f = symbol__new(sym.st_value, sym.st_size, elf_name, 894 f = symbol__new(sym.st_value, sym.st_size, elf_name);
820 curr_dso->sym_priv_size, v);
821 free(demangled); 895 free(demangled);
822 if (!f) 896 if (!f)
823 goto out_elf_end; 897 goto out_elf_end;
824 898
825 if (filter && filter(curr_map, f)) 899 if (filter && filter(curr_map, f))
826 symbol__delete(f, curr_dso->sym_priv_size); 900 symbol__delete(f);
827 else { 901 else {
828 dso__insert_symbol(curr_dso, f); 902 symbols__insert(&curr_dso->symbols[curr_map->type], f);
829 nr++; 903 nr++;
830 } 904 }
831 } 905 }
@@ -834,7 +908,7 @@ new_symbol:
834 * For misannotated, zeroed, ASM function sizes. 908 * For misannotated, zeroed, ASM function sizes.
835 */ 909 */
836 if (nr > 0) 910 if (nr > 0)
837 dso__fixup_sym_end(self); 911 symbols__fixup_end(&self->symbols[map->type]);
838 err = nr; 912 err = nr;
839out_elf_end: 913out_elf_end:
840 elf_end(elf); 914 elf_end(elf);
@@ -842,63 +916,153 @@ out_close:
842 return err; 916 return err;
843} 917}
844 918
845#define BUILD_ID_SIZE 128 919static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
920{
921 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
922}
846 923
847static char *dso__read_build_id(struct dso *self, int v) 924static bool __dsos__read_build_ids(struct list_head *head)
848{ 925{
849 int i; 926 bool have_build_id = false;
927 struct dso *pos;
928
929 list_for_each_entry(pos, head, node)
930 if (filename__read_build_id(pos->long_name, pos->build_id,
931 sizeof(pos->build_id)) > 0) {
932 have_build_id = true;
933 pos->has_build_id = true;
934 }
935
936 return have_build_id;
937}
938
939bool dsos__read_build_ids(void)
940{
941 return __dsos__read_build_ids(&dsos__kernel) ||
942 __dsos__read_build_ids(&dsos__user);
943}
944
945/*
946 * Align offset to 4 bytes as needed for note name and descriptor data.
947 */
948#define NOTE_ALIGN(n) (((n) + 3) & -4U)
949
950int filename__read_build_id(const char *filename, void *bf, size_t size)
951{
952 int fd, err = -1;
850 GElf_Ehdr ehdr; 953 GElf_Ehdr ehdr;
851 GElf_Shdr shdr; 954 GElf_Shdr shdr;
852 Elf_Data *build_id_data; 955 Elf_Data *data;
853 Elf_Scn *sec; 956 Elf_Scn *sec;
854 char *build_id = NULL, *bid; 957 Elf_Kind ek;
855 unsigned char *raw; 958 void *ptr;
856 Elf *elf; 959 Elf *elf;
857 int fd = open(self->long_name, O_RDONLY);
858 960
961 if (size < BUILD_ID_SIZE)
962 goto out;
963
964 fd = open(filename, O_RDONLY);
859 if (fd < 0) 965 if (fd < 0)
860 goto out; 966 goto out;
861 967
862 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 968 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
863 if (elf == NULL) { 969 if (elf == NULL) {
864 if (v) 970 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
865 fprintf(stderr, "%s: cannot read %s ELF file.\n",
866 __func__, self->long_name);
867 goto out_close; 971 goto out_close;
868 } 972 }
869 973
974 ek = elf_kind(elf);
975 if (ek != ELF_K_ELF)
976 goto out_elf_end;
977
870 if (gelf_getehdr(elf, &ehdr) == NULL) { 978 if (gelf_getehdr(elf, &ehdr) == NULL) {
871 if (v) 979 pr_err("%s: cannot get elf header.\n", __func__);
872 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
873 goto out_elf_end; 980 goto out_elf_end;
874 } 981 }
875 982
876 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 983 sec = elf_section_by_name(elf, &ehdr, &shdr,
877 if (sec == NULL) 984 ".note.gnu.build-id", NULL);
878 goto out_elf_end; 985 if (sec == NULL) {
986 sec = elf_section_by_name(elf, &ehdr, &shdr,
987 ".notes", NULL);
988 if (sec == NULL)
989 goto out_elf_end;
990 }
879 991
880 build_id_data = elf_getdata(sec, NULL); 992 data = elf_getdata(sec, NULL);
881 if (build_id_data == NULL) 993 if (data == NULL)
882 goto out_elf_end; 994 goto out_elf_end;
883 build_id = malloc(BUILD_ID_SIZE);
884 if (build_id == NULL)
885 goto out_elf_end;
886 raw = build_id_data->d_buf + 16;
887 bid = build_id;
888 995
889 for (i = 0; i < 20; ++i) { 996 ptr = data->d_buf;
890 sprintf(bid, "%02x", *raw); 997 while (ptr < (data->d_buf + data->d_size)) {
891 ++raw; 998 GElf_Nhdr *nhdr = ptr;
892 bid += 2; 999 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1000 descsz = NOTE_ALIGN(nhdr->n_descsz);
1001 const char *name;
1002
1003 ptr += sizeof(*nhdr);
1004 name = ptr;
1005 ptr += namesz;
1006 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1007 nhdr->n_namesz == sizeof("GNU")) {
1008 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1009 memcpy(bf, ptr, BUILD_ID_SIZE);
1010 err = BUILD_ID_SIZE;
1011 break;
1012 }
1013 }
1014 ptr += descsz;
893 } 1015 }
894 if (v >= 2)
895 printf("%s(%s): %s\n", __func__, self->long_name, build_id);
896out_elf_end: 1016out_elf_end:
897 elf_end(elf); 1017 elf_end(elf);
898out_close: 1018out_close:
899 close(fd); 1019 close(fd);
900out: 1020out:
901 return build_id; 1021 return err;
1022}
1023
1024int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1025{
1026 int fd, err = -1;
1027
1028 if (size < BUILD_ID_SIZE)
1029 goto out;
1030
1031 fd = open(filename, O_RDONLY);
1032 if (fd < 0)
1033 goto out;
1034
1035 while (1) {
1036 char bf[BUFSIZ];
1037 GElf_Nhdr nhdr;
1038 int namesz, descsz;
1039
1040 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1041 break;
1042
1043 namesz = NOTE_ALIGN(nhdr.n_namesz);
1044 descsz = NOTE_ALIGN(nhdr.n_descsz);
1045 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1046 nhdr.n_namesz == sizeof("GNU")) {
1047 if (read(fd, bf, namesz) != namesz)
1048 break;
1049 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1050 if (read(fd, build_id,
1051 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1052 err = 0;
1053 break;
1054 }
1055 } else if (read(fd, bf, descsz) != descsz)
1056 break;
1057 } else {
1058 int n = namesz + descsz;
1059 if (read(fd, bf, n) != n)
1060 break;
1061 }
1062 }
1063 close(fd);
1064out:
1065 return err;
902} 1066}
903 1067
904char dso__symtab_origin(const struct dso *self) 1068char dso__symtab_origin(const struct dso *self)
@@ -918,20 +1082,27 @@ char dso__symtab_origin(const struct dso *self)
918 return origin[self->origin]; 1082 return origin[self->origin];
919} 1083}
920 1084
921int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v) 1085int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
922{ 1086{
923 int size = PATH_MAX; 1087 int size = PATH_MAX;
924 char *name = malloc(size), *build_id = NULL; 1088 char *name;
1089 u8 build_id[BUILD_ID_SIZE];
925 int ret = -1; 1090 int ret = -1;
926 int fd; 1091 int fd;
927 1092
1093 dso__set_loaded(self, map->type);
1094
1095 if (self->kernel)
1096 return dso__load_kernel_sym(self, map, kthread, filter);
1097
1098 name = malloc(size);
928 if (!name) 1099 if (!name)
929 return -1; 1100 return -1;
930 1101
931 self->adjust_symbols = 0; 1102 self->adjust_symbols = 0;
932 1103
933 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1104 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
934 ret = dso__load_perf_map(self, map, filter, v); 1105 ret = dso__load_perf_map(self, map, filter);
935 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1106 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
936 DSO__ORIG_NOT_FOUND; 1107 DSO__ORIG_NOT_FOUND;
937 return ret; 1108 return ret;
@@ -952,12 +1123,17 @@ more:
952 self->long_name); 1123 self->long_name);
953 break; 1124 break;
954 case DSO__ORIG_BUILDID: 1125 case DSO__ORIG_BUILDID:
955 build_id = dso__read_build_id(self, v); 1126 if (filename__read_build_id(self->long_name, build_id,
956 if (build_id != NULL) { 1127 sizeof(build_id))) {
1128 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1129
1130 build_id__sprintf(build_id, sizeof(build_id),
1131 build_id_hex);
957 snprintf(name, size, 1132 snprintf(name, size,
958 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1133 "/usr/lib/debug/.build-id/%.2s/%s.debug",
959 build_id, build_id + 2); 1134 build_id_hex, build_id_hex + 2);
960 free(build_id); 1135 if (self->has_build_id)
1136 goto compare_build_id;
961 break; 1137 break;
962 } 1138 }
963 self->origin++; 1139 self->origin++;
@@ -970,10 +1146,19 @@ more:
970 goto out; 1146 goto out;
971 } 1147 }
972 1148
1149 if (self->has_build_id) {
1150 if (filename__read_build_id(name, build_id,
1151 sizeof(build_id)) < 0)
1152 goto more;
1153compare_build_id:
1154 if (!dso__build_id_equal(self, build_id))
1155 goto more;
1156 }
1157
973 fd = open(name, O_RDONLY); 1158 fd = open(name, O_RDONLY);
974 } while (fd < 0); 1159 } while (fd < 0);
975 1160
976 ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v); 1161 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
977 close(fd); 1162 close(fd);
978 1163
979 /* 1164 /*
@@ -983,7 +1168,7 @@ more:
983 goto more; 1168 goto more;
984 1169
985 if (ret > 0) { 1170 if (ret > 0) {
986 int nr_plt = dso__synthesize_plt_symbols(self, v); 1171 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
987 if (nr_plt > 0) 1172 if (nr_plt > 0)
988 ret += nr_plt; 1173 ret += nr_plt;
989 } 1174 }
@@ -994,33 +1179,11 @@ out:
994 return ret; 1179 return ret;
995} 1180}
996 1181
997struct map *kernel_map; 1182static struct map *thread__find_map_by_name(struct thread *self, char *name)
998
999static void kernel_maps__insert(struct map *map)
1000{
1001 maps__insert(&kernel_maps, map);
1002}
1003
1004struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
1005{
1006 struct map *map = maps__find(&kernel_maps, ip);
1007
1008 if (mapp)
1009 *mapp = map;
1010
1011 if (map) {
1012 ip = map->map_ip(map, ip);
1013 return map->dso->find_symbol(map->dso, ip);
1014 }
1015
1016 return NULL;
1017}
1018
1019struct map *kernel_maps__find_by_dso_name(const char *name)
1020{ 1183{
1021 struct rb_node *nd; 1184 struct rb_node *nd;
1022 1185
1023 for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 1186 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
1024 struct map *map = rb_entry(nd, struct map, rb_node); 1187 struct map *map = rb_entry(nd, struct map, rb_node);
1025 1188
1026 if (map->dso && strcmp(map->dso->name, name) == 0) 1189 if (map->dso && strcmp(map->dso->name, name) == 0)
@@ -1030,35 +1193,13 @@ struct map *kernel_maps__find_by_dso_name(const char *name)
1030 return NULL; 1193 return NULL;
1031} 1194}
1032 1195
1033static int dso__load_module_sym(struct dso *self, struct map *map, 1196static int dsos__set_modules_path_dir(char *dirname)
1034 symbol_filter_t filter, int v)
1035{
1036 int err = 0, fd = open(self->long_name, O_RDONLY);
1037
1038 if (fd < 0) {
1039 if (v)
1040 fprintf(stderr, "%s: cannot open %s\n",
1041 __func__, self->long_name);
1042 return err;
1043 }
1044
1045 err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v);
1046 close(fd);
1047
1048 return err;
1049}
1050
1051static int dsos__load_modules_sym_dir(char *dirname,
1052 symbol_filter_t filter, int v)
1053{ 1197{
1054 struct dirent *dent; 1198 struct dirent *dent;
1055 int nr_symbols = 0, err;
1056 DIR *dir = opendir(dirname); 1199 DIR *dir = opendir(dirname);
1057 1200
1058 if (!dir) { 1201 if (!dir) {
1059 if (v) 1202 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1060 fprintf(stderr, "%s: cannot open %s dir\n", __func__,
1061 dirname);
1062 return -1; 1203 return -1;
1063 } 1204 }
1064 1205
@@ -1072,14 +1213,13 @@ static int dsos__load_modules_sym_dir(char *dirname,
1072 1213
1073 snprintf(path, sizeof(path), "%s/%s", 1214 snprintf(path, sizeof(path), "%s/%s",
1074 dirname, dent->d_name); 1215 dirname, dent->d_name);
1075 err = dsos__load_modules_sym_dir(path, filter, v); 1216 if (dsos__set_modules_path_dir(path) < 0)
1076 if (err < 0)
1077 goto failure; 1217 goto failure;
1078 } else { 1218 } else {
1079 char *dot = strrchr(dent->d_name, '.'), 1219 char *dot = strrchr(dent->d_name, '.'),
1080 dso_name[PATH_MAX]; 1220 dso_name[PATH_MAX];
1081 struct map *map; 1221 struct map *map;
1082 struct rb_node *last; 1222 char *long_name;
1083 1223
1084 if (dot == NULL || strcmp(dot, ".ko")) 1224 if (dot == NULL || strcmp(dot, ".ko"))
1085 continue; 1225 continue;
@@ -1087,45 +1227,27 @@ static int dsos__load_modules_sym_dir(char *dirname,
1087 (int)(dot - dent->d_name), dent->d_name); 1227 (int)(dot - dent->d_name), dent->d_name);
1088 1228
1089 strxfrchar(dso_name, '-', '_'); 1229 strxfrchar(dso_name, '-', '_');
1090 map = kernel_maps__find_by_dso_name(dso_name); 1230 map = thread__find_map_by_name(kthread, dso_name);
1091 if (map == NULL) 1231 if (map == NULL)
1092 continue; 1232 continue;
1093 1233
1094 snprintf(path, sizeof(path), "%s/%s", 1234 snprintf(path, sizeof(path), "%s/%s",
1095 dirname, dent->d_name); 1235 dirname, dent->d_name);
1096 1236
1097 map->dso->long_name = strdup(path); 1237 long_name = strdup(path);
1098 if (map->dso->long_name == NULL) 1238 if (long_name == NULL)
1099 goto failure; 1239 goto failure;
1100 1240 dso__set_long_name(map->dso, long_name);
1101 err = dso__load_module_sym(map->dso, map, filter, v);
1102 if (err < 0)
1103 goto failure;
1104 last = rb_last(&map->dso->syms);
1105 if (last) {
1106 struct symbol *sym;
1107 /*
1108 * We do this here as well, even having the
1109 * symbol size found in the symtab because
1110 * misannotated ASM symbols may have the size
1111 * set to zero.
1112 */
1113 dso__fixup_sym_end(map->dso);
1114
1115 sym = rb_entry(last, struct symbol, rb_node);
1116 map->end = map->start + sym->end;
1117 }
1118 } 1241 }
1119 nr_symbols += err;
1120 } 1242 }
1121 1243
1122 return nr_symbols; 1244 return 0;
1123failure: 1245failure:
1124 closedir(dir); 1246 closedir(dir);
1125 return -1; 1247 return -1;
1126} 1248}
1127 1249
1128static int dsos__load_modules_sym(symbol_filter_t filter, int v) 1250static int dsos__set_modules_path(void)
1129{ 1251{
1130 struct utsname uts; 1252 struct utsname uts;
1131 char modules_path[PATH_MAX]; 1253 char modules_path[PATH_MAX];
@@ -1136,7 +1258,7 @@ static int dsos__load_modules_sym(symbol_filter_t filter, int v)
1136 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1258 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1137 uts.release); 1259 uts.release);
1138 1260
1139 return dsos__load_modules_sym_dir(modules_path, filter, v); 1261 return dsos__set_modules_path_dir(modules_path);
1140} 1262}
1141 1263
1142/* 1264/*
@@ -1144,26 +1266,21 @@ static int dsos__load_modules_sym(symbol_filter_t filter, int v)
1144 * they are loaded) and for vmlinux, where only after we load all the 1266 * they are loaded) and for vmlinux, where only after we load all the
1145 * symbols we'll know where it starts and ends. 1267 * symbols we'll know where it starts and ends.
1146 */ 1268 */
1147static struct map *map__new2(u64 start, struct dso *dso) 1269static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1148{ 1270{
1149 struct map *self = malloc(sizeof(*self)); 1271 struct map *self = malloc(sizeof(*self));
1150 1272
1151 if (self != NULL) { 1273 if (self != NULL) {
1152 self->start = start;
1153 /* 1274 /*
1154 * Will be filled after we load all the symbols 1275 * ->end will be filled after we load all the symbols
1155 */ 1276 */
1156 self->end = 0; 1277 map__init(self, type, start, 0, 0, dso);
1157
1158 self->pgoff = 0;
1159 self->dso = dso;
1160 self->map_ip = map__map_ip;
1161 RB_CLEAR_NODE(&self->rb_node);
1162 } 1278 }
1279
1163 return self; 1280 return self;
1164} 1281}
1165 1282
1166static int dsos__load_modules(unsigned int sym_priv_size) 1283static int thread__create_module_maps(struct thread *self)
1167{ 1284{
1168 char *line = NULL; 1285 char *line = NULL;
1169 size_t n; 1286 size_t n;
@@ -1202,26 +1319,32 @@ static int dsos__load_modules(unsigned int sym_priv_size)
1202 *sep = '\0'; 1319 *sep = '\0';
1203 1320
1204 snprintf(name, sizeof(name), "[%s]", line); 1321 snprintf(name, sizeof(name), "[%s]", line);
1205 dso = dso__new(name, sym_priv_size); 1322 dso = dso__new(name);
1206 1323
1207 if (dso == NULL) 1324 if (dso == NULL)
1208 goto out_delete_line; 1325 goto out_delete_line;
1209 1326
1210 map = map__new2(start, dso); 1327 map = map__new2(start, dso, MAP__FUNCTION);
1211 if (map == NULL) { 1328 if (map == NULL) {
1212 dso__delete(dso); 1329 dso__delete(dso);
1213 goto out_delete_line; 1330 goto out_delete_line;
1214 } 1331 }
1215 1332
1333 snprintf(name, sizeof(name),
1334 "/sys/module/%s/notes/.note.gnu.build-id", line);
1335 if (sysfs__read_build_id(name, dso->build_id,
1336 sizeof(dso->build_id)) == 0)
1337 dso->has_build_id = true;
1338
1216 dso->origin = DSO__ORIG_KMODULE; 1339 dso->origin = DSO__ORIG_KMODULE;
1217 kernel_maps__insert(map); 1340 __thread__insert_map(self, map);
1218 dsos__add(dso); 1341 dsos__add(&dsos__kernel, dso);
1219 } 1342 }
1220 1343
1221 free(line); 1344 free(line);
1222 fclose(file); 1345 fclose(file);
1223 1346
1224 return 0; 1347 return dsos__set_modules_path();
1225 1348
1226out_delete_line: 1349out_delete_line:
1227 free(line); 1350 free(line);
@@ -1229,105 +1352,106 @@ out_failure:
1229 return -1; 1352 return -1;
1230} 1353}
1231 1354
1232static int dso__load_vmlinux(struct dso *self, struct map *map, 1355static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
1233 const char *vmlinux, 1356 const char *vmlinux, symbol_filter_t filter)
1234 symbol_filter_t filter, int v)
1235{ 1357{
1236 int err, fd = open(vmlinux, O_RDONLY); 1358 int err = -1, fd;
1237 1359
1360 if (self->has_build_id) {
1361 u8 build_id[BUILD_ID_SIZE];
1362
1363 if (filename__read_build_id(vmlinux, build_id,
1364 sizeof(build_id)) < 0) {
1365 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1366 return -1;
1367 }
1368 if (!dso__build_id_equal(self, build_id)) {
1369 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1370 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1371
1372 build_id__sprintf(self->build_id,
1373 sizeof(self->build_id),
1374 expected_build_id);
1375 build_id__sprintf(build_id, sizeof(build_id),
1376 vmlinux_build_id);
1377 pr_debug("build_id in %s is %s while expected is %s, "
1378 "ignoring it\n", vmlinux, vmlinux_build_id,
1379 expected_build_id);
1380 return -1;
1381 }
1382 }
1383
1384 fd = open(vmlinux, O_RDONLY);
1238 if (fd < 0) 1385 if (fd < 0)
1239 return -1; 1386 return -1;
1240 1387
1241 err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v); 1388 dso__set_loaded(self, map->type);
1242 1389 err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
1243 close(fd); 1390 close(fd);
1244 1391
1245 return err; 1392 return err;
1246} 1393}
1247 1394
1248int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, 1395static int dso__load_kernel_sym(struct dso *self, struct map *map,
1249 symbol_filter_t filter, int v, int use_modules) 1396 struct thread *thread, symbol_filter_t filter)
1250{ 1397{
1251 int err = -1; 1398 int err;
1252 struct dso *dso = dso__new(vmlinux, sym_priv_size); 1399 bool is_kallsyms;
1253 1400
1254 if (dso == NULL) 1401 if (vmlinux_path != NULL) {
1255 return -1; 1402 int i;
1256 1403 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1257 dso->short_name = "[kernel]"; 1404 vmlinux_path__nr_entries);
1258 kernel_map = map__new2(0, dso); 1405 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1259 if (kernel_map == NULL) 1406 err = dso__load_vmlinux(self, map, thread,
1260 goto out_delete_dso; 1407 vmlinux_path[i], filter);
1261 1408 if (err > 0) {
1262 kernel_map->map_ip = vdso__map_ip; 1409 pr_debug("Using %s for symbols\n",
1263 1410 vmlinux_path[i]);
1264 if (use_modules && dsos__load_modules(sym_priv_size) < 0) { 1411 dso__set_long_name(self,
1265 fprintf(stderr, "Failed to load list of modules in use! " 1412 strdup(vmlinux_path[i]));
1266 "Continuing...\n"); 1413 goto out_fixup;
1267 use_modules = 0; 1414 }
1268 }
1269
1270 if (vmlinux) {
1271 err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
1272 if (err > 0 && use_modules) {
1273 int syms = dsos__load_modules_sym(filter, v);
1274
1275 if (syms < 0)
1276 fprintf(stderr, "Failed to read module symbols!"
1277 " Continuing...\n");
1278 else
1279 err += syms;
1280 } 1415 }
1281 } 1416 }
1282 1417
1283 if (err <= 0) 1418 is_kallsyms = self->long_name[0] == '[';
1284 err = kernel_maps__load_kallsyms(filter, use_modules, v); 1419 if (is_kallsyms)
1420 goto do_kallsyms;
1421
1422 err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
1423 if (err <= 0) {
1424 pr_info("The file %s cannot be used, "
1425 "trying to use /proc/kallsyms...", self->long_name);
1426do_kallsyms:
1427 err = dso__load_kallsyms(self, map, thread, filter);
1428 if (err > 0 && !is_kallsyms)
1429 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1430 }
1285 1431
1286 if (err > 0) { 1432 if (err > 0) {
1287 struct rb_node *node = rb_first(&dso->syms); 1433out_fixup:
1288 struct symbol *sym = rb_entry(node, struct symbol, rb_node); 1434 map__fixup_start(map);
1289 1435 map__fixup_end(map);
1290 kernel_map->start = sym->start;
1291 node = rb_last(&dso->syms);
1292 sym = rb_entry(node, struct symbol, rb_node);
1293 kernel_map->end = sym->end;
1294
1295 dso->origin = DSO__ORIG_KERNEL;
1296 kernel_maps__insert(kernel_map);
1297 /*
1298 * Now that we have all sorted out, just set the ->end of all
1299 * maps:
1300 */
1301 kernel_maps__fixup_end();
1302 dsos__add(dso);
1303
1304 if (v > 0)
1305 kernel_maps__fprintf(stderr, v);
1306 } 1436 }
1307 1437
1308 return err; 1438 return err;
1309
1310out_delete_dso:
1311 dso__delete(dso);
1312 return -1;
1313} 1439}
1314 1440
1315LIST_HEAD(dsos); 1441LIST_HEAD(dsos__user);
1316struct dso *vdso; 1442LIST_HEAD(dsos__kernel);
1317 1443struct dso *vdso;
1318const char *vmlinux_name = "vmlinux";
1319int modules;
1320 1444
1321static void dsos__add(struct dso *dso) 1445static void dsos__add(struct list_head *head, struct dso *dso)
1322{ 1446{
1323 list_add_tail(&dso->node, &dsos); 1447 list_add_tail(&dso->node, head);
1324} 1448}
1325 1449
1326static struct dso *dsos__find(const char *name) 1450static struct dso *dsos__find(struct list_head *head, const char *name)
1327{ 1451{
1328 struct dso *pos; 1452 struct dso *pos;
1329 1453
1330 list_for_each_entry(pos, &dsos, node) 1454 list_for_each_entry(pos, head, node)
1331 if (strcmp(pos->name, name) == 0) 1455 if (strcmp(pos->name, name) == 0)
1332 return pos; 1456 return pos;
1333 return NULL; 1457 return NULL;
@@ -1335,56 +1459,170 @@ static struct dso *dsos__find(const char *name)
1335 1459
1336struct dso *dsos__findnew(const char *name) 1460struct dso *dsos__findnew(const char *name)
1337{ 1461{
1338 struct dso *dso = dsos__find(name); 1462 struct dso *dso = dsos__find(&dsos__user, name);
1339 int nr;
1340 1463
1341 if (dso) 1464 if (!dso) {
1342 return dso; 1465 dso = dso__new(name);
1343 1466 if (dso != NULL) {
1344 dso = dso__new(name, 0); 1467 dsos__add(&dsos__user, dso);
1345 if (!dso) 1468 dso__set_basename(dso);
1346 goto out_delete_dso; 1469 }
1347
1348 nr = dso__load(dso, NULL, NULL, verbose);
1349 if (nr < 0) {
1350 eprintf("Failed to open: %s\n", name);
1351 goto out_delete_dso;
1352 } 1470 }
1353 if (!nr)
1354 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
1355
1356 dsos__add(dso);
1357 1471
1358 return dso; 1472 return dso;
1473}
1359 1474
1360out_delete_dso: 1475static void __dsos__fprintf(struct list_head *head, FILE *fp)
1361 dso__delete(dso); 1476{
1362 return NULL; 1477 struct dso *pos;
1478
1479 list_for_each_entry(pos, head, node) {
1480 int i;
1481 for (i = 0; i < MAP__NR_TYPES; ++i)
1482 dso__fprintf(pos, i, fp);
1483 }
1363} 1484}
1364 1485
1365void dsos__fprintf(FILE *fp) 1486void dsos__fprintf(FILE *fp)
1366{ 1487{
1488 __dsos__fprintf(&dsos__kernel, fp);
1489 __dsos__fprintf(&dsos__user, fp);
1490}
1491
1492static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
1493{
1367 struct dso *pos; 1494 struct dso *pos;
1495 size_t ret = 0;
1368 1496
1369 list_for_each_entry(pos, &dsos, node) 1497 list_for_each_entry(pos, head, node) {
1370 dso__fprintf(pos, fp); 1498 ret += dso__fprintf_buildid(pos, fp);
1499 ret += fprintf(fp, " %s\n", pos->long_name);
1500 }
1501 return ret;
1502}
1503
1504size_t dsos__fprintf_buildid(FILE *fp)
1505{
1506 return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1507 __dsos__fprintf_buildid(&dsos__user, fp));
1371} 1508}
1372 1509
1373int load_kernel(void) 1510static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
1374{ 1511{
1375 if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0) 1512 struct map *kmap;
1513 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1514
1515 if (kernel == NULL)
1376 return -1; 1516 return -1;
1377 1517
1378 vdso = dso__new("[vdso]", 0); 1518 kmap = map__new2(0, kernel, MAP__FUNCTION);
1379 if (!vdso) 1519 if (kmap == NULL)
1520 goto out_delete_kernel_dso;
1521
1522 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1523 kernel->short_name = "[kernel]";
1524 kernel->kernel = 1;
1525
1526 vdso = dso__new("[vdso]");
1527 if (vdso == NULL)
1528 goto out_delete_kernel_map;
1529 dso__set_loaded(vdso, MAP__FUNCTION);
1530
1531 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1532 sizeof(kernel->build_id)) == 0)
1533 kernel->has_build_id = true;
1534
1535 __thread__insert_map(self, kmap);
1536 dsos__add(&dsos__kernel, kernel);
1537 dsos__add(&dsos__user, vdso);
1538
1539 return 0;
1540
1541out_delete_kernel_map:
1542 map__delete(kmap);
1543out_delete_kernel_dso:
1544 dso__delete(kernel);
1545 return -1;
1546}
1547
1548static void vmlinux_path__exit(void)
1549{
1550 while (--vmlinux_path__nr_entries >= 0) {
1551 free(vmlinux_path[vmlinux_path__nr_entries]);
1552 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1553 }
1554
1555 free(vmlinux_path);
1556 vmlinux_path = NULL;
1557}
1558
1559static int vmlinux_path__init(void)
1560{
1561 struct utsname uts;
1562 char bf[PATH_MAX];
1563
1564 if (uname(&uts) < 0)
1565 return -1;
1566
1567 vmlinux_path = malloc(sizeof(char *) * 5);
1568 if (vmlinux_path == NULL)
1380 return -1; 1569 return -1;
1381 1570
1382 dsos__add(vdso); 1571 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1572 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1573 goto out_fail;
1574 ++vmlinux_path__nr_entries;
1575 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1576 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1577 goto out_fail;
1578 ++vmlinux_path__nr_entries;
1579 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1580 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1581 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1582 goto out_fail;
1583 ++vmlinux_path__nr_entries;
1584 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1585 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1586 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1587 goto out_fail;
1588 ++vmlinux_path__nr_entries;
1589 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1590 uts.release);
1591 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1592 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1593 goto out_fail;
1594 ++vmlinux_path__nr_entries;
1383 1595
1384 return 0; 1596 return 0;
1597
1598out_fail:
1599 vmlinux_path__exit();
1600 return -1;
1385} 1601}
1386 1602
1387void symbol__init(void) 1603int symbol__init(struct symbol_conf *conf)
1388{ 1604{
1605 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1606
1389 elf_version(EV_CURRENT); 1607 elf_version(EV_CURRENT);
1608 symbol__priv_size = pconf->priv_size;
1609 thread__init(kthread, 0);
1610
1611 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1612 return -1;
1613
1614 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
1615 vmlinux_path__exit();
1616 return -1;
1617 }
1618
1619 kthread->use_modules = pconf->use_modules;
1620 if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
1621 pr_debug("Failed to load list of modules in use, "
1622 "continuing...\n");
1623 /*
1624 * Now that we have all the maps created, just set the ->end of them:
1625 */
1626 thread__fixup_maps_end(kthread);
1627 return 0;
1390} 1628}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 2e4522edeb07..17003efa0b39 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -2,6 +2,7 @@
2#define __PERF_SYMBOL 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h>
5#include "types.h" 6#include "types.h"
6#include <linux/list.h> 7#include <linux/list.h>
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
@@ -26,6 +27,16 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
26#endif 27#endif
27#endif 28#endif
28 29
30/*
31 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
32 * for newer versions we can use mmap to reduce memory usage:
33 */
34#ifdef LIBELF_NO_MMAP
35# define PERF_ELF_C_READ_MMAP ELF_C_READ
36#else
37# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
38#endif
39
29#ifndef DMGL_PARAMS 40#ifndef DMGL_PARAMS
30#define DMGL_PARAMS (1 << 0) /* Include function args */ 41#define DMGL_PARAMS (1 << 0) /* Include function args */
31#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 42#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
@@ -35,56 +46,75 @@ struct symbol {
35 struct rb_node rb_node; 46 struct rb_node rb_node;
36 u64 start; 47 u64 start;
37 u64 end; 48 u64 end;
38 u64 hist_sum;
39 u64 *hist;
40 void *priv;
41 char name[0]; 49 char name[0];
42}; 50};
43 51
52struct symbol_conf {
53 unsigned short priv_size;
54 bool try_vmlinux_path,
55 use_modules;
56 const char *vmlinux_name;
57};
58
59extern unsigned int symbol__priv_size;
60
61static inline void *symbol__priv(struct symbol *self)
62{
63 return ((void *)self) - symbol__priv_size;
64}
65
66struct addr_location {
67 struct thread *thread;
68 struct map *map;
69 struct symbol *sym;
70 u64 addr;
71 char level;
72};
73
44struct dso { 74struct dso {
45 struct list_head node; 75 struct list_head node;
46 struct rb_root syms; 76 struct rb_root symbols[MAP__NR_TYPES];
47 struct symbol *(*find_symbol)(struct dso *, u64 ip); 77 struct symbol *(*find_symbol)(struct dso *self,
48 unsigned int sym_priv_size; 78 enum map_type type, u64 addr);
49 unsigned char adjust_symbols; 79 u8 adjust_symbols:1;
50 unsigned char slen_calculated; 80 u8 slen_calculated:1;
81 u8 has_build_id:1;
82 u8 kernel:1;
51 unsigned char origin; 83 unsigned char origin;
84 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len;
52 const char *short_name; 87 const char *short_name;
53 char *long_name; 88 char *long_name;
54 char name[0]; 89 char name[0];
55}; 90};
56 91
57extern const char *sym_hist_filter; 92struct dso *dso__new(const char *name);
58
59typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
60
61struct dso *dso__new(const char *name, unsigned int sym_priv_size);
62void dso__delete(struct dso *self); 93void dso__delete(struct dso *self);
63 94
64static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 95bool dso__loaded(const struct dso *self, enum map_type type);
65{
66 return ((void *)sym) - self->sym_priv_size;
67}
68 96
69struct symbol *dso__find_symbol(struct dso *self, u64 ip);
70
71int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
72 symbol_filter_t filter, int verbose, int modules);
73int dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
74 int verbose);
75struct dso *dsos__findnew(const char *name); 97struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
76void dsos__fprintf(FILE *fp); 99void dsos__fprintf(FILE *fp);
100size_t dsos__fprintf_buildid(FILE *fp);
77 101
78size_t dso__fprintf(struct dso *self, FILE *fp); 102size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
103size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
79char dso__symtab_origin(const struct dso *self); 104char dso__symtab_origin(const struct dso *self);
105void dso__set_build_id(struct dso *self, void *build_id);
106
107int filename__read_build_id(const char *filename, void *bf, size_t size);
108int sysfs__read_build_id(const char *filename, void *bf, size_t size);
109bool dsos__read_build_ids(void);
110int build_id__sprintf(u8 *self, int len, char *bf);
80 111
81int load_kernel(void); 112size_t kernel_maps__fprintf(FILE *fp);
82 113
83void symbol__init(void); 114int symbol__init(struct symbol_conf *conf);
84 115
85extern struct list_head dsos; 116struct thread;
86extern struct map *kernel_map; 117struct thread *kthread;
118extern struct list_head dsos__user, dsos__kernel;
87extern struct dso *vdso; 119extern struct dso *vdso;
88extern const char *vmlinux_name;
89extern int modules;
90#endif /* __PERF_SYMBOL */ 120#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 3b56aebb1f4b..603f5610861b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,17 +6,29 @@
6#include "util.h" 6#include "util.h"
7#include "debug.h" 7#include "debug.h"
8 8
9static struct rb_root threads;
10static struct thread *last_match;
11
12void thread__init(struct thread *self, pid_t pid)
13{
14 int i;
15 self->pid = pid;
16 self->comm = NULL;
17 for (i = 0; i < MAP__NR_TYPES; ++i) {
18 self->maps[i] = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps[i]);
20 }
21}
22
9static struct thread *thread__new(pid_t pid) 23static struct thread *thread__new(pid_t pid)
10{ 24{
11 struct thread *self = calloc(1, sizeof(*self)); 25 struct thread *self = zalloc(sizeof(*self));
12 26
13 if (self != NULL) { 27 if (self != NULL) {
14 self->pid = pid; 28 thread__init(self, pid);
15 self->comm = malloc(32); 29 self->comm = malloc(32);
16 if (self->comm) 30 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 31 snprintf(self->comm, 32, ":%d", self->pid);
18 self->maps = RB_ROOT;
19 INIT_LIST_HEAD(&self->removed_maps);
20 } 32 }
21 33
22 return self; 34 return self;
@@ -30,30 +42,84 @@ int thread__set_comm(struct thread *self, const char *comm)
30 return self->comm ? 0 : -ENOMEM; 42 return self->comm ? 0 : -ENOMEM;
31} 43}
32 44
33static size_t thread__fprintf(struct thread *self, FILE *fp) 45int thread__comm_len(struct thread *self)
34{ 46{
47 if (!self->comm_len) {
48 if (!self->comm)
49 return 0;
50 self->comm_len = strlen(self->comm);
51 }
52
53 return self->comm_len;
54}
55
56static const char *map_type__name[MAP__NR_TYPES] = {
57 [MAP__FUNCTION] = "Functions",
58};
59
60static size_t __thread__fprintf_maps(struct thread *self,
61 enum map_type type, FILE *fp)
62{
63 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
35 struct rb_node *nd; 64 struct rb_node *nd;
36 struct map *pos;
37 size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
38 self->pid, self->comm);
39 65
40 for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { 66 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
41 pos = rb_entry(nd, struct map, rb_node); 67 struct map *pos = rb_entry(nd, struct map, rb_node);
42 ret += map__fprintf(pos, fp); 68 printed += fprintf(fp, "Map:");
69 printed += map__fprintf(pos, fp);
70 if (verbose > 1) {
71 printed += dso__fprintf(pos->dso, type, fp);
72 printed += fprintf(fp, "--\n");
73 }
43 } 74 }
44 75
45 ret = fprintf(fp, "Removed maps:\n"); 76 return printed;
77}
46 78
47 list_for_each_entry(pos, &self->removed_maps, node) 79size_t thread__fprintf_maps(struct thread *self, FILE *fp)
48 ret += map__fprintf(pos, fp); 80{
81 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __thread__fprintf_maps(self, i, fp);
84 return printed;
85}
49 86
50 return ret; 87static size_t __thread__fprintf_removed_maps(struct thread *self,
88 enum map_type type, FILE *fp)
89{
90 struct map *pos;
91 size_t printed = 0;
92
93 list_for_each_entry(pos, &self->removed_maps[type], node) {
94 printed += fprintf(fp, "Map:");
95 printed += map__fprintf(pos, fp);
96 if (verbose > 1) {
97 printed += dso__fprintf(pos->dso, type, fp);
98 printed += fprintf(fp, "--\n");
99 }
100 }
101 return printed;
102}
103
104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp)
105{
106 size_t printed = 0, i;
107 for (i = 0; i < MAP__NR_TYPES; ++i)
108 printed += __thread__fprintf_removed_maps(self, i, fp);
109 return printed;
51} 110}
52 111
53struct thread * 112static size_t thread__fprintf(struct thread *self, FILE *fp)
54threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
55{ 113{
56 struct rb_node **p = &threads->rb_node; 114 size_t printed = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
115 printed += thread__fprintf_removed_maps(self, fp);
116 printed += fprintf(fp, "Removed maps:\n");
117 return printed + thread__fprintf_removed_maps(self, fp);
118}
119
120struct thread *threads__findnew(pid_t pid)
121{
122 struct rb_node **p = &threads.rb_node;
57 struct rb_node *parent = NULL; 123 struct rb_node *parent = NULL;
58 struct thread *th; 124 struct thread *th;
59 125
@@ -62,15 +128,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
62 * so most of the time we dont have to look up 128 * so most of the time we dont have to look up
63 * the full rbtree: 129 * the full rbtree:
64 */ 130 */
65 if (*last_match && (*last_match)->pid == pid) 131 if (last_match && last_match->pid == pid)
66 return *last_match; 132 return last_match;
67 133
68 while (*p != NULL) { 134 while (*p != NULL) {
69 parent = *p; 135 parent = *p;
70 th = rb_entry(parent, struct thread, rb_node); 136 th = rb_entry(parent, struct thread, rb_node);
71 137
72 if (th->pid == pid) { 138 if (th->pid == pid) {
73 *last_match = th; 139 last_match = th;
74 return th; 140 return th;
75 } 141 }
76 142
@@ -83,17 +149,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
83 th = thread__new(pid); 149 th = thread__new(pid);
84 if (th != NULL) { 150 if (th != NULL) {
85 rb_link_node(&th->rb_node, parent, p); 151 rb_link_node(&th->rb_node, parent, p);
86 rb_insert_color(&th->rb_node, threads); 152 rb_insert_color(&th->rb_node, &threads);
87 *last_match = th; 153 last_match = th;
88 } 154 }
89 155
90 return th; 156 return th;
91} 157}
92 158
93struct thread * 159struct thread *register_idle_thread(void)
94register_idle_thread(struct rb_root *threads, struct thread **last_match)
95{ 160{
96 struct thread *thread = threads__findnew(0, threads, last_match); 161 struct thread *thread = threads__findnew(0);
97 162
98 if (!thread || thread__set_comm(thread, "swapper")) { 163 if (!thread || thread__set_comm(thread, "swapper")) {
99 fprintf(stderr, "problem inserting idle task.\n"); 164 fprintf(stderr, "problem inserting idle task.\n");
@@ -105,7 +170,8 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
105 170
106static void thread__remove_overlappings(struct thread *self, struct map *map) 171static void thread__remove_overlappings(struct thread *self, struct map *map)
107{ 172{
108 struct rb_node *next = rb_first(&self->maps); 173 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root);
109 175
110 while (next) { 176 while (next) {
111 struct map *pos = rb_entry(next, struct map, rb_node); 177 struct map *pos = rb_entry(next, struct map, rb_node);
@@ -115,18 +181,18 @@ static void thread__remove_overlappings(struct thread *self, struct map *map)
115 continue; 181 continue;
116 182
117 if (verbose >= 2) { 183 if (verbose >= 2) {
118 printf("overlapping maps:\n"); 184 fputs("overlapping maps:\n", stderr);
119 map__fprintf(map, stdout); 185 map__fprintf(map, stderr);
120 map__fprintf(pos, stdout); 186 map__fprintf(pos, stderr);
121 } 187 }
122 188
123 rb_erase(&pos->rb_node, &self->maps); 189 rb_erase(&pos->rb_node, root);
124 /* 190 /*
125 * We may have references to this map, for instance in some 191 * We may have references to this map, for instance in some
126 * hist_entry instances, so just move them to a separate 192 * hist_entry instances, so just move them to a separate
127 * list. 193 * list.
128 */ 194 */
129 list_add_tail(&pos->node, &self->removed_maps); 195 list_add_tail(&pos->node, &self->removed_maps[map->type]);
130 } 196 }
131} 197}
132 198
@@ -173,12 +239,26 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
173void thread__insert_map(struct thread *self, struct map *map) 239void thread__insert_map(struct thread *self, struct map *map)
174{ 240{
175 thread__remove_overlappings(self, map); 241 thread__remove_overlappings(self, map);
176 maps__insert(&self->maps, map); 242 maps__insert(&self->maps[map->type], map);
177} 243}
178 244
179int thread__fork(struct thread *self, struct thread *parent) 245static int thread__clone_maps(struct thread *self, struct thread *parent,
246 enum map_type type)
180{ 247{
181 struct rb_node *nd; 248 struct rb_node *nd;
249 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
250 struct map *map = rb_entry(nd, struct map, rb_node);
251 struct map *new = map__clone(map);
252 if (new == NULL)
253 return -ENOMEM;
254 thread__insert_map(self, new);
255 }
256 return 0;
257}
258
259int thread__fork(struct thread *self, struct thread *parent)
260{
261 int i;
182 262
183 if (self->comm) 263 if (self->comm)
184 free(self->comm); 264 free(self->comm);
@@ -186,23 +266,18 @@ int thread__fork(struct thread *self, struct thread *parent)
186 if (!self->comm) 266 if (!self->comm)
187 return -ENOMEM; 267 return -ENOMEM;
188 268
189 for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { 269 for (i = 0; i < MAP__NR_TYPES; ++i)
190 struct map *map = rb_entry(nd, struct map, rb_node); 270 if (thread__clone_maps(self, parent, i) < 0)
191 struct map *new = map__clone(map);
192 if (!new)
193 return -ENOMEM; 271 return -ENOMEM;
194 thread__insert_map(self, new);
195 }
196
197 return 0; 272 return 0;
198} 273}
199 274
200size_t threads__fprintf(FILE *fp, struct rb_root *threads) 275size_t threads__fprintf(FILE *fp)
201{ 276{
202 size_t ret = 0; 277 size_t ret = 0;
203 struct rb_node *nd; 278 struct rb_node *nd;
204 279
205 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 280 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
206 struct thread *pos = rb_entry(nd, struct thread, rb_node); 281 struct thread *pos = rb_entry(nd, struct thread, rb_node);
207 282
208 ret += thread__fprintf(pos, fp); 283 ret += thread__fprintf(pos, fp);
@@ -210,3 +285,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
210 285
211 return ret; 286 return ret;
212} 287}
288
289struct symbol *thread__find_symbol(struct thread *self,
290 enum map_type type, u64 addr,
291 symbol_filter_t filter)
292{
293 struct map *map = thread__find_map(self, type, addr);
294
295 if (map != NULL)
296 return map__find_symbol(map, map->map_ip(map, addr), filter);
297
298 return NULL;
299}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 845d9b62f96f..686d6e914d9e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -7,31 +7,50 @@
7 7
8struct thread { 8struct thread {
9 struct rb_node rb_node; 9 struct rb_node rb_node;
10 struct rb_root maps; 10 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps; 11 struct list_head removed_maps[MAP__NR_TYPES];
12 pid_t pid; 12 pid_t pid;
13 bool use_modules;
13 char shortname[3]; 14 char shortname[3];
14 char *comm; 15 char *comm;
16 int comm_len;
15}; 17};
16 18
19void thread__init(struct thread *self, pid_t pid);
17int thread__set_comm(struct thread *self, const char *comm); 20int thread__set_comm(struct thread *self, const char *comm);
18struct thread * 21int thread__comm_len(struct thread *self);
19threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 22struct thread *threads__findnew(pid_t pid);
20struct thread * 23struct thread *register_idle_thread(void);
21register_idle_thread(struct rb_root *threads, struct thread **last_match);
22void thread__insert_map(struct thread *self, struct map *map); 24void thread__insert_map(struct thread *self, struct map *map);
23int thread__fork(struct thread *self, struct thread *parent); 25int thread__fork(struct thread *self, struct thread *parent);
24size_t threads__fprintf(FILE *fp, struct rb_root *threads); 26size_t thread__fprintf_maps(struct thread *self, FILE *fp);
27size_t threads__fprintf(FILE *fp);
25 28
26void maps__insert(struct rb_root *maps, struct map *map); 29void maps__insert(struct rb_root *maps, struct map *map);
27struct map *maps__find(struct rb_root *maps, u64 ip); 30struct map *maps__find(struct rb_root *maps, u64 addr);
28 31
29struct symbol *kernel_maps__find_symbol(const u64 ip, struct map **mapp); 32static inline struct map *thread__find_map(struct thread *self,
30struct map *kernel_maps__find_by_dso_name(const char *name); 33 enum map_type type, u64 addr)
34{
35 return self ? maps__find(&self->maps[type], addr) : NULL;
36}
31 37
32static inline struct map *thread__find_map(struct thread *self, u64 ip) 38static inline void __thread__insert_map(struct thread *self, struct map *map)
33{ 39{
34 return self ? maps__find(&self->maps, ip) : NULL; 40 maps__insert(&self->maps[map->type], map);
35} 41}
36 42
43void thread__find_addr_location(struct thread *self, u8 cpumode,
44 enum map_type type, u64 addr,
45 struct addr_location *al,
46 symbol_filter_t filter);
47struct symbol *thread__find_symbol(struct thread *self,
48 enum map_type type, u64 addr,
49 symbol_filter_t filter);
50
51static inline struct symbol *
52thread__find_function(struct thread *self, u64 addr, symbol_filter_t filter)
53{
54 return thread__find_symbol(self, MAP__FUNCTION, addr, filter);
55}
37#endif /* __PERF_THREAD_H */ 56#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 831052d4b4fb..cace35595530 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -33,11 +33,11 @@
33#include <ctype.h> 33#include <ctype.h>
34#include <errno.h> 34#include <errno.h>
35#include <stdbool.h> 35#include <stdbool.h>
36#include <linux/kernel.h>
36 37
37#include "../perf.h" 38#include "../perf.h"
38#include "trace-event.h" 39#include "trace-event.h"
39 40
40
41#define VERSION "0.5" 41#define VERSION "0.5"
42 42
43#define _STR(x) #x 43#define _STR(x) #x
@@ -483,23 +483,31 @@ static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{ 484{
485 struct tracepoint_path path, *ppath = &path; 485 struct tracepoint_path path, *ppath = &path;
486 int i; 486 int i, nr_tracepoints = 0;
487 487
488 for (i = 0; i < nb_events; i++) { 488 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue; 490 continue;
491 ++nr_tracepoints;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config); 492 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next) 493 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list"); 494 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next; 495 ppath = ppath->next;
495 } 496 }
496 497
497 return path.next; 498 return nr_tracepoints > 0 ? path.next : NULL;
498} 499}
499void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 500
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
500{ 502{
501 char buf[BUFSIZ]; 503 char buf[BUFSIZ];
502 struct tracepoint_path *tps; 504 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events);
505
506 /*
507 * What? No tracepoints? No sense writing anything here, bail out.
508 */
509 if (tps == NULL)
510 return -1;
503 511
504 output_fd = fd; 512 output_fd = fd;
505 513
@@ -528,11 +536,11 @@ void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
528 page_size = getpagesize(); 536 page_size = getpagesize();
529 write_or_die(&page_size, 4); 537 write_or_die(&page_size, 4);
530 538
531 tps = get_tracepoints_path(pattrs, nb_events);
532
533 read_header_files(); 539 read_header_files();
534 read_ftrace_files(tps); 540 read_ftrace_files(tps);
535 read_event_files(tps); 541 read_event_files(tps);
536 read_proc_kallsyms(); 542 read_proc_kallsyms();
537 read_ftrace_printk(); 543 read_ftrace_printk();
544
545 return 0;
538} 546}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index eef60df7a5bf..0302405aa2ca 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,12 +40,19 @@ int header_page_size_size;
40int header_page_data_offset; 40int header_page_data_offset;
41int header_page_data_size; 41int header_page_data_size;
42 42
43int latency_format;
44
43static char *input_buf; 45static char *input_buf;
44static unsigned long long input_buf_ptr; 46static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz; 47static unsigned long long input_buf_siz;
46 48
47static int cpus; 49static int cpus;
48static int long_size; 50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
49 56
50static void init_input_buf(char *buf, unsigned long long size) 57static void init_input_buf(char *buf, unsigned long long size)
51{ 58{
@@ -284,18 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
284 char *line; 291 char *line;
285 char *next = NULL; 292 char *next = NULL;
286 char *addr_str; 293 char *addr_str;
287 int ret;
288 int i; 294 int i;
289 295
290 line = strtok_r(file, "\n", &next); 296 line = strtok_r(file, "\n", &next);
291 while (line) { 297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
292 item = malloc_or_die(sizeof(*item)); 303 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16); 304 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str); 305 /* fmt still has a space, skip it */
298 306 item->printk = strdup(line+1);
299 item->next = list; 307 item->next = list;
300 list = item; 308 list = item;
301 line = strtok_r(NULL, "\n", &next); 309 line = strtok_r(NULL, "\n", &next);
@@ -522,7 +530,10 @@ static enum event_type __read_token(char **tok)
522 last_ch = ch; 530 last_ch = ch;
523 ch = __read_char(); 531 ch = __read_char();
524 buf[i++] = ch; 532 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\'); 533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
526 /* remove the last quote */ 537 /* remove the last quote */
527 i--; 538 i--;
528 goto out; 539 goto out;
@@ -610,7 +621,7 @@ static enum event_type read_token_item(char **tok)
610static int test_type(enum event_type type, enum event_type expect) 621static int test_type(enum event_type type, enum event_type expect)
611{ 622{
612 if (type != expect) { 623 if (type != expect) {
613 die("Error: expected type %d but read %d", 624 warning("Error: expected type %d but read %d",
614 expect, type); 625 expect, type);
615 return -1; 626 return -1;
616 } 627 }
@@ -621,13 +632,13 @@ static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, const char *expect_tok) 632 enum event_type expect, const char *expect_tok)
622{ 633{
623 if (type != expect) { 634 if (type != expect) {
624 die("Error: expected type %d but read %d", 635 warning("Error: expected type %d but read %d",
625 expect, type); 636 expect, type);
626 return -1; 637 return -1;
627 } 638 }
628 639
629 if (strcmp(token, expect_tok) != 0) { 640 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'", 641 warning("Error: expected '%s' but read '%s'",
631 expect_tok, token); 642 expect_tok, token);
632 return -1; 643 return -1;
633 } 644 }
@@ -665,7 +676,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
665 676
666 free_token(token); 677 free_token(token);
667 678
668 return 0; 679 return ret;
669} 680}
670 681
671static int read_expected(enum event_type expect, const char *str) 682static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +693,10 @@ static char *event_read_name(void)
682{ 693{
683 char *token; 694 char *token;
684 695
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0) 696 if (read_expected(EVENT_ITEM, "name") < 0)
686 return NULL; 697 return NULL;
687 698
688 if (read_expected(EVENT_OP, (char *)":") < 0) 699 if (read_expected(EVENT_OP, ":") < 0)
689 return NULL; 700 return NULL;
690 701
691 if (read_expect_type(EVENT_ITEM, &token) < 0) 702 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +714,10 @@ static int event_read_id(void)
703 char *token; 714 char *token;
704 int id; 715 int id;
705 716
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) 717 if (read_expected_item(EVENT_ITEM, "ID") < 0)
707 return -1; 718 return -1;
708 719
709 if (read_expected(EVENT_OP, (char *)":") < 0) 720 if (read_expected(EVENT_OP, ":") < 0)
710 return -1; 721 return -1;
711 722
712 if (read_expect_type(EVENT_ITEM, &token) < 0) 723 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -756,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
756 767
757 count++; 768 count++;
758 769
759 if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) 770 if (test_type_token(type, token, EVENT_ITEM, "field"))
760 goto fail; 771 goto fail;
761 free_token(token); 772 free_token(token);
762 773
@@ -771,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
771 type = read_token(&token); 782 type = read_token(&token);
772 } 783 }
773 784
774 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) 785 if (test_type_token(type, token, EVENT_OP, ":") < 0)
775 return -1; 786 return -1;
776 787
777 if (read_expect_type(EVENT_ITEM, &token) < 0) 788 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -889,14 +900,14 @@ static int event_read_fields(struct event *event, struct format_field **fields)
889 field->flags |= FIELD_IS_DYNAMIC; 900 field->flags |= FIELD_IS_DYNAMIC;
890 } 901 }
891 902
892 if (test_type_token(type, token, EVENT_OP, (char *)";")) 903 if (test_type_token(type, token, EVENT_OP, ";"))
893 goto fail; 904 goto fail;
894 free_token(token); 905 free_token(token);
895 906
896 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 907 if (read_expected(EVENT_ITEM, "offset") < 0)
897 goto fail_expect; 908 goto fail_expect;
898 909
899 if (read_expected(EVENT_OP, (char *)":") < 0) 910 if (read_expected(EVENT_OP, ":") < 0)
900 goto fail_expect; 911 goto fail_expect;
901 912
902 if (read_expect_type(EVENT_ITEM, &token)) 913 if (read_expect_type(EVENT_ITEM, &token))
@@ -904,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
904 field->offset = strtoul(token, NULL, 0); 915 field->offset = strtoul(token, NULL, 0);
905 free_token(token); 916 free_token(token);
906 917
907 if (read_expected(EVENT_OP, (char *)";") < 0) 918 if (read_expected(EVENT_OP, ";") < 0)
908 goto fail_expect; 919 goto fail_expect;
909 920
910 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 921 if (read_expected(EVENT_ITEM, "size") < 0)
911 goto fail_expect; 922 goto fail_expect;
912 923
913 if (read_expected(EVENT_OP, (char *)":") < 0) 924 if (read_expected(EVENT_OP, ":") < 0)
914 goto fail_expect; 925 goto fail_expect;
915 926
916 if (read_expect_type(EVENT_ITEM, &token)) 927 if (read_expect_type(EVENT_ITEM, &token))
@@ -918,26 +929,34 @@ static int event_read_fields(struct event *event, struct format_field **fields)
918 field->size = strtoul(token, NULL, 0); 929 field->size = strtoul(token, NULL, 0);
919 free_token(token); 930 free_token(token);
920 931
921 if (read_expected(EVENT_OP, (char *)";") < 0) 932 if (read_expected(EVENT_OP, ";") < 0)
922 goto fail_expect; 933 goto fail_expect;
923 934
924 if (read_expected(EVENT_ITEM, (char *)"signed") < 0) 935 type = read_token(&token);
925 goto fail_expect; 936 if (type != EVENT_NEWLINE) {
937 /* newer versions of the kernel have a "signed" type */
938 if (test_type_token(type, token, EVENT_ITEM, "signed"))
939 goto fail;
926 940
927 if (read_expected(EVENT_OP, (char *)":") < 0) 941 free_token(token);
928 goto fail_expect;
929 942
930 if (read_expect_type(EVENT_ITEM, &token)) 943 if (read_expected(EVENT_OP, ":") < 0)
931 goto fail; 944 goto fail_expect;
932 if (strtoul(token, NULL, 0))
933 field->flags |= FIELD_IS_SIGNED;
934 free_token(token);
935 945
936 if (read_expected(EVENT_OP, (char *)";") < 0) 946 if (read_expect_type(EVENT_ITEM, &token))
937 goto fail_expect; 947 goto fail;
948
949 if (strtoul(token, NULL, 0))
950 field->flags |= FIELD_IS_SIGNED;
951
952 free_token(token);
953 if (read_expected(EVENT_OP, ";") < 0)
954 goto fail_expect;
955
956 if (read_expect_type(EVENT_NEWLINE, &token))
957 goto fail;
958 }
938 959
939 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
940 goto fail;
941 free_token(token); 960 free_token(token);
942 961
943 *fields = field; 962 *fields = field;
@@ -960,10 +979,10 @@ static int event_read_format(struct event *event)
960 char *token; 979 char *token;
961 int ret; 980 int ret;
962 981
963 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) 982 if (read_expected_item(EVENT_ITEM, "format") < 0)
964 return -1; 983 return -1;
965 984
966 if (read_expected(EVENT_OP, (char *)":") < 0) 985 if (read_expected(EVENT_OP, ":") < 0)
967 return -1; 986 return -1;
968 987
969 if (read_expect_type(EVENT_NEWLINE, &token)) 988 if (read_expect_type(EVENT_NEWLINE, &token))
@@ -1023,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
1023 1042
1024 *tok = NULL; 1043 *tok = NULL;
1025 type = process_arg(event, left, &token); 1044 type = process_arg(event, left, &token);
1026 if (test_type_token(type, token, EVENT_OP, (char *)":")) 1045 if (test_type_token(type, token, EVENT_OP, ":"))
1027 goto out_free; 1046 goto out_free;
1028 1047
1029 arg->op.op = token; 1048 arg->op.op = token;
@@ -1043,6 +1062,35 @@ out_free:
1043 return EVENT_ERROR; 1062 return EVENT_ERROR;
1044} 1063}
1045 1064
1065static enum event_type
1066process_array(struct event *event, struct print_arg *top, char **tok)
1067{
1068 struct print_arg *arg;
1069 enum event_type type;
1070 char *token = NULL;
1071
1072 arg = malloc_or_die(sizeof(*arg));
1073 memset(arg, 0, sizeof(*arg));
1074
1075 *tok = NULL;
1076 type = process_arg(event, arg, &token);
1077 if (test_type_token(type, token, EVENT_OP, "]"))
1078 goto out_free;
1079
1080 top->op.right = arg;
1081
1082 free_token(token);
1083 type = read_token_item(&token);
1084 *tok = token;
1085
1086 return type;
1087
1088out_free:
1089 free_token(*tok);
1090 free_arg(arg);
1091 return EVENT_ERROR;
1092}
1093
1046static int get_op_prio(char *op) 1094static int get_op_prio(char *op)
1047{ 1095{
1048 if (!op[1]) { 1096 if (!op[1]) {
@@ -1167,6 +1215,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1167 strcmp(token, "*") == 0 || 1215 strcmp(token, "*") == 0 ||
1168 strcmp(token, "^") == 0 || 1216 strcmp(token, "^") == 0 ||
1169 strcmp(token, "/") == 0 || 1217 strcmp(token, "/") == 0 ||
1218 strcmp(token, "<") == 0 ||
1219 strcmp(token, ">") == 0 ||
1170 strcmp(token, "==") == 0 || 1220 strcmp(token, "==") == 0 ||
1171 strcmp(token, "!=") == 0) { 1221 strcmp(token, "!=") == 0) {
1172 1222
@@ -1183,17 +1233,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1183 1233
1184 right = malloc_or_die(sizeof(*right)); 1234 right = malloc_or_die(sizeof(*right));
1185 1235
1186 type = process_arg(event, right, tok); 1236 type = read_token_item(&token);
1237 *tok = token;
1238
1239 /* could just be a type pointer */
1240 if ((strcmp(arg->op.op, "*") == 0) &&
1241 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1242 if (left->type != PRINT_ATOM)
1243 die("bad pointer type");
1244 left->atom.atom = realloc(left->atom.atom,
1245 sizeof(left->atom.atom) + 3);
1246 strcat(left->atom.atom, " *");
1247 *arg = *left;
1248 free(arg);
1249
1250 return type;
1251 }
1252
1253 type = process_arg_token(event, right, tok, type);
1187 1254
1188 arg->op.right = right; 1255 arg->op.right = right;
1189 1256
1257 } else if (strcmp(token, "[") == 0) {
1258
1259 left = malloc_or_die(sizeof(*left));
1260 *left = *arg;
1261
1262 arg->type = PRINT_OP;
1263 arg->op.op = token;
1264 arg->op.left = left;
1265
1266 arg->op.prio = 0;
1267 type = process_array(event, arg, tok);
1268
1190 } else { 1269 } else {
1191 die("unknown op '%s'", token); 1270 warning("unknown op '%s'", token);
1271 event->flags |= EVENT_FL_FAILED;
1192 /* the arg is now the left side */ 1272 /* the arg is now the left side */
1193 return EVENT_NONE; 1273 return EVENT_NONE;
1194 } 1274 }
1195 1275
1196
1197 if (type == EVENT_OP) { 1276 if (type == EVENT_OP) {
1198 int prio; 1277 int prio;
1199 1278
@@ -1217,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1217 char *field; 1296 char *field;
1218 char *token; 1297 char *token;
1219 1298
1220 if (read_expected(EVENT_OP, (char *)"->") < 0) 1299 if (read_expected(EVENT_OP, "->") < 0)
1221 return EVENT_ERROR; 1300 return EVENT_ERROR;
1222 1301
1223 if (read_expect_type(EVENT_ITEM, &token) < 0) 1302 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1227,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1227 arg->type = PRINT_FIELD; 1306 arg->type = PRINT_FIELD;
1228 arg->field.name = field; 1307 arg->field.name = field;
1229 1308
1309 if (is_flag_field) {
1310 arg->field.field = find_any_field(event, arg->field.name);
1311 arg->field.field->flags |= FIELD_IS_FLAG;
1312 is_flag_field = 0;
1313 } else if (is_symbolic_field) {
1314 arg->field.field = find_any_field(event, arg->field.name);
1315 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1316 is_symbolic_field = 0;
1317 }
1318
1230 type = read_token(&token); 1319 type = read_token(&token);
1231 *tok = token; 1320 *tok = token;
1232 1321
@@ -1377,14 +1466,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1377 do { 1466 do {
1378 free_token(token); 1467 free_token(token);
1379 type = read_token_item(&token); 1468 type = read_token_item(&token);
1380 if (test_type_token(type, token, EVENT_OP, (char *)"{")) 1469 if (test_type_token(type, token, EVENT_OP, "{"))
1381 break; 1470 break;
1382 1471
1383 arg = malloc_or_die(sizeof(*arg)); 1472 arg = malloc_or_die(sizeof(*arg));
1384 1473
1385 free_token(token); 1474 free_token(token);
1386 type = process_arg(event, arg, &token); 1475 type = process_arg(event, arg, &token);
1387 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1476 if (test_type_token(type, token, EVENT_DELIM, ","))
1388 goto out_free; 1477 goto out_free;
1389 1478
1390 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
@@ -1395,7 +1484,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1395 1484
1396 free_token(token); 1485 free_token(token);
1397 type = process_arg(event, arg, &token); 1486 type = process_arg(event, arg, &token);
1398 if (test_type_token(type, token, EVENT_OP, (char *)"}")) 1487 if (test_type_token(type, token, EVENT_OP, "}"))
1399 goto out_free; 1488 goto out_free;
1400 1489
1401 value = arg_eval(arg); 1490 value = arg_eval(arg);
@@ -1430,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1430 memset(arg, 0, sizeof(*arg)); 1519 memset(arg, 0, sizeof(*arg));
1431 arg->type = PRINT_FLAGS; 1520 arg->type = PRINT_FLAGS;
1432 1521
1433 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1522 if (read_expected_item(EVENT_DELIM, "(") < 0)
1434 return EVENT_ERROR; 1523 return EVENT_ERROR;
1435 1524
1436 field = malloc_or_die(sizeof(*field)); 1525 field = malloc_or_die(sizeof(*field));
1437 1526
1438 type = process_arg(event, field, &token); 1527 type = process_arg(event, field, &token);
1439 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1528 if (test_type_token(type, token, EVENT_DELIM, ","))
1440 goto out_free; 1529 goto out_free;
1441 1530
1442 arg->flags.field = field; 1531 arg->flags.field = field;
@@ -1447,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1447 type = read_token_item(&token); 1536 type = read_token_item(&token);
1448 } 1537 }
1449 1538
1450 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1539 if (test_type_token(type, token, EVENT_DELIM, ","))
1451 goto out_free; 1540 goto out_free;
1452 1541
1453 type = process_fields(event, &arg->flags.flags, &token); 1542 type = process_fields(event, &arg->flags.flags, &token);
1454 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1543 if (test_type_token(type, token, EVENT_DELIM, ")"))
1455 goto out_free; 1544 goto out_free;
1456 1545
1457 free_token(token); 1546 free_token(token);
@@ -1473,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
1473 memset(arg, 0, sizeof(*arg)); 1562 memset(arg, 0, sizeof(*arg));
1474 arg->type = PRINT_SYMBOL; 1563 arg->type = PRINT_SYMBOL;
1475 1564
1476 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1565 if (read_expected_item(EVENT_DELIM, "(") < 0)
1477 return EVENT_ERROR; 1566 return EVENT_ERROR;
1478 1567
1479 field = malloc_or_die(sizeof(*field)); 1568 field = malloc_or_die(sizeof(*field));
1480 1569
1481 type = process_arg(event, field, &token); 1570 type = process_arg(event, field, &token);
1482 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1571 if (test_type_token(type, token, EVENT_DELIM, ","))
1483 goto out_free; 1572 goto out_free;
1484 1573
1485 arg->symbol.field = field; 1574 arg->symbol.field = field;
1486 1575
1487 type = process_fields(event, &arg->symbol.symbols, &token); 1576 type = process_fields(event, &arg->symbol.symbols, &token);
1488 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1577 if (test_type_token(type, token, EVENT_DELIM, ")"))
1489 goto out_free; 1578 goto out_free;
1490 1579
1491 free_token(token); 1580 free_token(token);
@@ -1502,7 +1591,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1502{ 1591{
1503 struct print_arg *item_arg; 1592 struct print_arg *item_arg;
1504 enum event_type type; 1593 enum event_type type;
1505 int ptr_cast = 0;
1506 char *token; 1594 char *token;
1507 1595
1508 type = process_arg(event, arg, &token); 1596 type = process_arg(event, arg, &token);
@@ -1510,28 +1598,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1510 if (type == EVENT_ERROR) 1598 if (type == EVENT_ERROR)
1511 return EVENT_ERROR; 1599 return EVENT_ERROR;
1512 1600
1513 if (type == EVENT_OP) { 1601 if (type == EVENT_OP)
1514 /* handle the ptr casts */ 1602 type = process_op(event, arg, &token);
1515 if (!strcmp(token, "*")) {
1516 /*
1517 * FIXME: should we zapp whitespaces before ')' ?
1518 * (may require a peek_token_item())
1519 */
1520 if (__peek_char() == ')') {
1521 ptr_cast = 1;
1522 free_token(token);
1523 type = read_token_item(&token);
1524 }
1525 }
1526 if (!ptr_cast) {
1527 type = process_op(event, arg, &token);
1528 1603
1529 if (type == EVENT_ERROR) 1604 if (type == EVENT_ERROR)
1530 return EVENT_ERROR; 1605 return EVENT_ERROR;
1531 }
1532 }
1533 1606
1534 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { 1607 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1535 free_token(token); 1608 free_token(token);
1536 return EVENT_ERROR; 1609 return EVENT_ERROR;
1537 } 1610 }
@@ -1555,13 +1628,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1555 item_arg = malloc_or_die(sizeof(*item_arg)); 1628 item_arg = malloc_or_die(sizeof(*item_arg));
1556 1629
1557 arg->type = PRINT_TYPE; 1630 arg->type = PRINT_TYPE;
1558 if (ptr_cast) {
1559 char *old = arg->atom.atom;
1560
1561 arg->atom.atom = malloc_or_die(strlen(old + 3));
1562 sprintf(arg->atom.atom, "%s *", old);
1563 free(old);
1564 }
1565 arg->typecast.type = arg->atom.atom; 1631 arg->typecast.type = arg->atom.atom;
1566 arg->typecast.item = item_arg; 1632 arg->typecast.item = item_arg;
1567 type = process_arg_token(event, item_arg, &token, type); 1633 type = process_arg_token(event, item_arg, &token, type);
@@ -1579,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1579 enum event_type type; 1645 enum event_type type;
1580 char *token; 1646 char *token;
1581 1647
1582 if (read_expected(EVENT_DELIM, (char *)"(") < 0) 1648 if (read_expected(EVENT_DELIM, "(") < 0)
1583 return EVENT_ERROR; 1649 return EVENT_ERROR;
1584 1650
1585 if (read_expect_type(EVENT_ITEM, &token) < 0) 1651 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1589,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1589 arg->string.string = token; 1655 arg->string.string = token;
1590 arg->string.offset = -1; 1656 arg->string.offset = -1;
1591 1657
1592 if (read_expected(EVENT_DELIM, (char *)")") < 0) 1658 if (read_expected(EVENT_DELIM, ")") < 0)
1593 return EVENT_ERROR; 1659 return EVENT_ERROR;
1594 1660
1595 type = read_token(&token); 1661 type = read_token(&token);
@@ -1617,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
1617 type = process_entry(event, arg, &token); 1683 type = process_entry(event, arg, &token);
1618 } else if (strcmp(token, "__print_flags") == 0) { 1684 } else if (strcmp(token, "__print_flags") == 0) {
1619 free_token(token); 1685 free_token(token);
1686 is_flag_field = 1;
1620 type = process_flags(event, arg, &token); 1687 type = process_flags(event, arg, &token);
1621 } else if (strcmp(token, "__print_symbolic") == 0) { 1688 } else if (strcmp(token, "__print_symbolic") == 0) {
1622 free_token(token); 1689 free_token(token);
1690 is_symbolic_field = 1;
1623 type = process_symbols(event, arg, &token); 1691 type = process_symbols(event, arg, &token);
1624 } else if (strcmp(token, "__get_str") == 0) { 1692 } else if (strcmp(token, "__get_str") == 0) {
1625 free_token(token); 1693 free_token(token);
@@ -1676,12 +1744,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
1676 1744
1677static int event_read_print_args(struct event *event, struct print_arg **list) 1745static int event_read_print_args(struct event *event, struct print_arg **list)
1678{ 1746{
1679 enum event_type type; 1747 enum event_type type = EVENT_ERROR;
1680 struct print_arg *arg; 1748 struct print_arg *arg;
1681 char *token; 1749 char *token;
1682 int args = 0; 1750 int args = 0;
1683 1751
1684 do { 1752 do {
1753 if (type == EVENT_NEWLINE) {
1754 free_token(token);
1755 type = read_token_item(&token);
1756 continue;
1757 }
1758
1685 arg = malloc_or_die(sizeof(*arg)); 1759 arg = malloc_or_die(sizeof(*arg));
1686 memset(arg, 0, sizeof(*arg)); 1760 memset(arg, 0, sizeof(*arg));
1687 1761
@@ -1722,18 +1796,19 @@ static int event_read_print(struct event *event)
1722 char *token; 1796 char *token;
1723 int ret; 1797 int ret;
1724 1798
1725 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) 1799 if (read_expected_item(EVENT_ITEM, "print") < 0)
1726 return -1; 1800 return -1;
1727 1801
1728 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) 1802 if (read_expected(EVENT_ITEM, "fmt") < 0)
1729 return -1; 1803 return -1;
1730 1804
1731 if (read_expected(EVENT_OP, (char *)":") < 0) 1805 if (read_expected(EVENT_OP, ":") < 0)
1732 return -1; 1806 return -1;
1733 1807
1734 if (read_expect_type(EVENT_DQUOTE, &token) < 0) 1808 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1735 goto fail; 1809 goto fail;
1736 1810
1811 concat:
1737 event->print_fmt.format = token; 1812 event->print_fmt.format = token;
1738 event->print_fmt.args = NULL; 1813 event->print_fmt.args = NULL;
1739 1814
@@ -1743,7 +1818,22 @@ static int event_read_print(struct event *event)
1743 if (type == EVENT_NONE) 1818 if (type == EVENT_NONE)
1744 return 0; 1819 return 0;
1745 1820
1746 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1821 /* Handle concatination of print lines */
1822 if (type == EVENT_DQUOTE) {
1823 char *cat;
1824
1825 cat = malloc_or_die(strlen(event->print_fmt.format) +
1826 strlen(token) + 1);
1827 strcpy(cat, event->print_fmt.format);
1828 strcat(cat, token);
1829 free_token(token);
1830 free_token(event->print_fmt.format);
1831 event->print_fmt.format = NULL;
1832 token = cat;
1833 goto concat;
1834 }
1835
1836 if (test_type_token(type, token, EVENT_DELIM, ","))
1747 goto fail; 1837 goto fail;
1748 1838
1749 free_token(token); 1839 free_token(token);
@@ -1752,7 +1842,7 @@ static int event_read_print(struct event *event)
1752 if (ret < 0) 1842 if (ret < 0)
1753 return -1; 1843 return -1;
1754 1844
1755 return 0; 1845 return ret;
1756 1846
1757 fail: 1847 fail:
1758 free_token(token); 1848 free_token(token);
@@ -1798,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
1798 return find_field(event, name); 1888 return find_field(event, name);
1799} 1889}
1800 1890
1801static unsigned long long read_size(void *ptr, int size) 1891unsigned long long read_size(void *ptr, int size)
1802{ 1892{
1803 switch (size) { 1893 switch (size) {
1804 case 1: 1894 case 1:
@@ -1861,37 +1951,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1861 return 0; 1951 return 0;
1862} 1952}
1863 1953
1864int trace_parse_common_type(void *data) 1954static int __parse_common(void *data, int *size, int *offset,
1955 const char *name)
1865{ 1956{
1866 static int type_offset;
1867 static int type_size;
1868 int ret; 1957 int ret;
1869 1958
1870 if (!type_size) { 1959 if (!*size) {
1871 ret = get_common_info("common_type", 1960 ret = get_common_info(name, offset, size);
1872 &type_offset,
1873 &type_size);
1874 if (ret < 0) 1961 if (ret < 0)
1875 return ret; 1962 return ret;
1876 } 1963 }
1877 return read_size(data + type_offset, type_size); 1964 return read_size(data + *offset, *size);
1878} 1965}
1879 1966
1880static int parse_common_pid(void *data) 1967int trace_parse_common_type(void *data)
1968{
1969 static int type_offset;
1970 static int type_size;
1971
1972 return __parse_common(data, &type_size, &type_offset,
1973 "common_type");
1974}
1975
1976int trace_parse_common_pid(void *data)
1881{ 1977{
1882 static int pid_offset; 1978 static int pid_offset;
1883 static int pid_size; 1979 static int pid_size;
1980
1981 return __parse_common(data, &pid_size, &pid_offset,
1982 "common_pid");
1983}
1984
1985int parse_common_pc(void *data)
1986{
1987 static int pc_offset;
1988 static int pc_size;
1989
1990 return __parse_common(data, &pc_size, &pc_offset,
1991 "common_preempt_count");
1992}
1993
1994int parse_common_flags(void *data)
1995{
1996 static int flags_offset;
1997 static int flags_size;
1998
1999 return __parse_common(data, &flags_size, &flags_offset,
2000 "common_flags");
2001}
2002
2003int parse_common_lock_depth(void *data)
2004{
2005 static int ld_offset;
2006 static int ld_size;
1884 int ret; 2007 int ret;
1885 2008
1886 if (!pid_size) { 2009 ret = __parse_common(data, &ld_size, &ld_offset,
1887 ret = get_common_info("common_pid", 2010 "common_lock_depth");
1888 &pid_offset, 2011 if (ret < 0)
1889 &pid_size); 2012 return -1;
1890 if (ret < 0)
1891 return ret;
1892 }
1893 2013
1894 return read_size(data + pid_offset, pid_size); 2014 return ret;
1895} 2015}
1896 2016
1897struct event *trace_find_event(int id) 2017struct event *trace_find_event(int id)
@@ -1905,11 +2025,20 @@ struct event *trace_find_event(int id)
1905 return event; 2025 return event;
1906} 2026}
1907 2027
2028struct event *trace_find_next_event(struct event *event)
2029{
2030 if (!event)
2031 return event_list;
2032
2033 return event->next;
2034}
2035
1908static unsigned long long eval_num_arg(void *data, int size, 2036static unsigned long long eval_num_arg(void *data, int size,
1909 struct event *event, struct print_arg *arg) 2037 struct event *event, struct print_arg *arg)
1910{ 2038{
1911 unsigned long long val = 0; 2039 unsigned long long val = 0;
1912 unsigned long long left, right; 2040 unsigned long long left, right;
2041 struct print_arg *larg;
1913 2042
1914 switch (arg->type) { 2043 switch (arg->type) {
1915 case PRINT_NULL: 2044 case PRINT_NULL:
@@ -1936,6 +2065,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1936 return 0; 2065 return 0;
1937 break; 2066 break;
1938 case PRINT_OP: 2067 case PRINT_OP:
2068 if (strcmp(arg->op.op, "[") == 0) {
2069 /*
2070 * Arrays are special, since we don't want
2071 * to read the arg as is.
2072 */
2073 if (arg->op.left->type != PRINT_FIELD)
2074 goto default_op; /* oops, all bets off */
2075 larg = arg->op.left;
2076 if (!larg->field.field) {
2077 larg->field.field =
2078 find_any_field(event, larg->field.name);
2079 if (!larg->field.field)
2080 die("field %s not found", larg->field.name);
2081 }
2082 right = eval_num_arg(data, size, event, arg->op.right);
2083 val = read_size(data + larg->field.field->offset +
2084 right * long_size, long_size);
2085 break;
2086 }
2087 default_op:
1939 left = eval_num_arg(data, size, event, arg->op.left); 2088 left = eval_num_arg(data, size, event, arg->op.left);
1940 right = eval_num_arg(data, size, event, arg->op.right); 2089 right = eval_num_arg(data, size, event, arg->op.right);
1941 switch (arg->op.op[0]) { 2090 switch (arg->op.op[0]) {
@@ -1986,6 +2135,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1986 die("unknown op '%s'", arg->op.op); 2135 die("unknown op '%s'", arg->op.op);
1987 val = left == right; 2136 val = left == right;
1988 break; 2137 break;
2138 case '-':
2139 val = left - right;
2140 break;
2141 case '+':
2142 val = left + right;
2143 break;
1989 default: 2144 default:
1990 die("unknown op '%s'", arg->op.op); 2145 die("unknown op '%s'", arg->op.op);
1991 } 2146 }
@@ -2017,7 +2172,7 @@ static const struct flag flags[] = {
2017 { "HRTIMER_RESTART", 1 }, 2172 { "HRTIMER_RESTART", 1 },
2018}; 2173};
2019 2174
2020static unsigned long long eval_flag(const char *flag) 2175unsigned long long eval_flag(const char *flag)
2021{ 2176{
2022 int i; 2177 int i;
2023 2178
@@ -2184,8 +2339,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2184 case 'u': 2339 case 'u':
2185 case 'x': 2340 case 'x':
2186 case 'i': 2341 case 'i':
2187 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2342 /* the pointers are always 4 bytes aligned */
2188 ~(long_size - 1)); 2343 bptr = (void *)(((unsigned long)bptr + 3) &
2344 ~3);
2189 switch (ls) { 2345 switch (ls) {
2190 case 0: 2346 case 0:
2191 case 1: 2347 case 1:
@@ -2309,7 +2465,27 @@ static void pretty_print(void *data, int size, struct event *event)
2309 2465
2310 for (; *ptr; ptr++) { 2466 for (; *ptr; ptr++) {
2311 ls = 0; 2467 ls = 0;
2312 if (*ptr == '%') { 2468 if (*ptr == '\\') {
2469 ptr++;
2470 switch (*ptr) {
2471 case 'n':
2472 printf("\n");
2473 break;
2474 case 't':
2475 printf("\t");
2476 break;
2477 case 'r':
2478 printf("\r");
2479 break;
2480 case '\\':
2481 printf("\\");
2482 break;
2483 default:
2484 printf("%c", *ptr);
2485 break;
2486 }
2487
2488 } else if (*ptr == '%') {
2313 saveptr = ptr; 2489 saveptr = ptr;
2314 show_func = 0; 2490 show_func = 0;
2315 cont_process: 2491 cont_process:
@@ -2416,6 +2592,41 @@ static inline int log10_cpu(int nb)
2416 return 1; 2592 return 1;
2417} 2593}
2418 2594
2595static void print_lat_fmt(void *data, int size __unused)
2596{
2597 unsigned int lat_flags;
2598 unsigned int pc;
2599 int lock_depth;
2600 int hardirq;
2601 int softirq;
2602
2603 lat_flags = parse_common_flags(data);
2604 pc = parse_common_pc(data);
2605 lock_depth = parse_common_lock_depth(data);
2606
2607 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2608 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2609
2610 printf("%c%c%c",
2611 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2612 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2613 'X' : '.',
2614 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2615 'N' : '.',
2616 (hardirq && softirq) ? 'H' :
2617 hardirq ? 'h' : softirq ? 's' : '.');
2618
2619 if (pc)
2620 printf("%x", pc);
2621 else
2622 printf(".");
2623
2624 if (lock_depth < 0)
2625 printf(".");
2626 else
2627 printf("%d", lock_depth);
2628}
2629
2419/* taken from Linux, written by Frederic Weisbecker */ 2630/* taken from Linux, written by Frederic Weisbecker */
2420static void print_graph_cpu(int cpu) 2631static void print_graph_cpu(int cpu)
2421{ 2632{
@@ -2491,7 +2702,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2491 if (!(event->flags & EVENT_FL_ISFUNCRET)) 2702 if (!(event->flags & EVENT_FL_ISFUNCRET))
2492 return NULL; 2703 return NULL;
2493 2704
2494 pid = parse_common_pid(next->data); 2705 pid = trace_parse_common_pid(next->data);
2495 field = find_field(event, "func"); 2706 field = find_field(event, "func");
2496 if (!field) 2707 if (!field)
2497 die("function return does not have field func"); 2708 die("function return does not have field func");
@@ -2659,6 +2870,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2659 2870
2660 printf(" | "); 2871 printf(" | ");
2661 2872
2873 if (latency_format) {
2874 print_lat_fmt(data, size);
2875 printf(" | ");
2876 }
2877
2662 field = find_field(event, "func"); 2878 field = find_field(event, "func");
2663 if (!field) 2879 if (!field)
2664 die("function entry does not have func field"); 2880 die("function entry does not have func field");
@@ -2702,6 +2918,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2702 2918
2703 printf(" | "); 2919 printf(" | ");
2704 2920
2921 if (latency_format) {
2922 print_lat_fmt(data, size);
2923 printf(" | ");
2924 }
2925
2705 field = find_field(event, "rettime"); 2926 field = find_field(event, "rettime");
2706 if (!field) 2927 if (!field)
2707 die("can't find rettime in return graph"); 2928 die("can't find rettime in return graph");
@@ -2763,19 +2984,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2763 2984
2764 event = trace_find_event(type); 2985 event = trace_find_event(type);
2765 if (!event) { 2986 if (!event) {
2766 printf("ug! no event found for type %d\n", type); 2987 warning("ug! no event found for type %d", type);
2767 return; 2988 return;
2768 } 2989 }
2769 2990
2770 pid = parse_common_pid(data); 2991 pid = trace_parse_common_pid(data);
2771 2992
2772 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 2993 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2773 return pretty_print_func_graph(data, size, event, cpu, 2994 return pretty_print_func_graph(data, size, event, cpu,
2774 pid, comm, secs, usecs); 2995 pid, comm, secs, usecs);
2775 2996
2776 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 2997 if (latency_format) {
2777 comm, pid, cpu, 2998 printf("%8.8s-%-5d %3d",
2778 secs, nsecs, event->name); 2999 comm, pid, cpu);
3000 print_lat_fmt(data, size);
3001 } else
3002 printf("%16s-%-5d [%03d]", comm, pid, cpu);
3003
3004 printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
3005
3006 if (event->flags & EVENT_FL_FAILED) {
3007 printf("EVENT '%s' FAILED TO PARSE\n",
3008 event->name);
3009 return;
3010 }
2779 3011
2780 pretty_print(data, size, event); 3012 pretty_print(data, size, event);
2781 printf("\n"); 3013 printf("\n");
@@ -2846,55 +3078,71 @@ static void print_args(struct print_arg *args)
2846 } 3078 }
2847} 3079}
2848 3080
2849static void parse_header_field(char *type, 3081static void parse_header_field(const char *field,
2850 int *offset, int *size) 3082 int *offset, int *size)
2851{ 3083{
2852 char *token; 3084 char *token;
3085 int type;
2853 3086
2854 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3087 if (read_expected(EVENT_ITEM, "field") < 0)
2855 return; 3088 return;
2856 if (read_expected(EVENT_OP, (char *)":") < 0) 3089 if (read_expected(EVENT_OP, ":") < 0)
2857 return; 3090 return;
3091
2858 /* type */ 3092 /* type */
2859 if (read_expect_type(EVENT_ITEM, &token) < 0) 3093 if (read_expect_type(EVENT_ITEM, &token) < 0)
2860 return; 3094 goto fail;
2861 free_token(token); 3095 free_token(token);
2862 3096
2863 if (read_expected(EVENT_ITEM, type) < 0) 3097 if (read_expected(EVENT_ITEM, field) < 0)
2864 return; 3098 return;
2865 if (read_expected(EVENT_OP, (char *)";") < 0) 3099 if (read_expected(EVENT_OP, ";") < 0)
2866 return; 3100 return;
2867 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3101 if (read_expected(EVENT_ITEM, "offset") < 0)
2868 return; 3102 return;
2869 if (read_expected(EVENT_OP, (char *)":") < 0) 3103 if (read_expected(EVENT_OP, ":") < 0)
2870 return; 3104 return;
2871 if (read_expect_type(EVENT_ITEM, &token) < 0) 3105 if (read_expect_type(EVENT_ITEM, &token) < 0)
2872 return; 3106 goto fail;
2873 *offset = atoi(token); 3107 *offset = atoi(token);
2874 free_token(token); 3108 free_token(token);
2875 if (read_expected(EVENT_OP, (char *)";") < 0) 3109 if (read_expected(EVENT_OP, ";") < 0)
2876 return; 3110 return;
2877 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3111 if (read_expected(EVENT_ITEM, "size") < 0)
2878 return; 3112 return;
2879 if (read_expected(EVENT_OP, (char *)":") < 0) 3113 if (read_expected(EVENT_OP, ":") < 0)
2880 return; 3114 return;
2881 if (read_expect_type(EVENT_ITEM, &token) < 0) 3115 if (read_expect_type(EVENT_ITEM, &token) < 0)
2882 return; 3116 goto fail;
2883 *size = atoi(token); 3117 *size = atoi(token);
2884 free_token(token); 3118 free_token(token);
2885 if (read_expected(EVENT_OP, (char *)";") < 0) 3119 if (read_expected(EVENT_OP, ";") < 0)
2886 return;
2887 if (read_expected(EVENT_ITEM, (char *)"signed") < 0)
2888 return;
2889 if (read_expected(EVENT_OP, (char *)":") < 0)
2890 return;
2891 if (read_expect_type(EVENT_ITEM, &token) < 0)
2892 return;
2893 free_token(token);
2894 if (read_expected(EVENT_OP, (char *)";") < 0)
2895 return;
2896 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2897 return; 3120 return;
3121 type = read_token(&token);
3122 if (type != EVENT_NEWLINE) {
3123 /* newer versions of the kernel have a "signed" type */
3124 if (type != EVENT_ITEM)
3125 goto fail;
3126
3127 if (strcmp(token, "signed") != 0)
3128 goto fail;
3129
3130 free_token(token);
3131
3132 if (read_expected(EVENT_OP, ":") < 0)
3133 return;
3134
3135 if (read_expect_type(EVENT_ITEM, &token))
3136 goto fail;
3137
3138 free_token(token);
3139 if (read_expected(EVENT_OP, ";") < 0)
3140 return;
3141
3142 if (read_expect_type(EVENT_NEWLINE, &token))
3143 goto fail;
3144 }
3145 fail:
2898 free_token(token); 3146 free_token(token);
2899} 3147}
2900 3148
@@ -2902,11 +3150,11 @@ int parse_header_page(char *buf, unsigned long size)
2902{ 3150{
2903 init_input_buf(buf, size); 3151 init_input_buf(buf, size);
2904 3152
2905 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3153 parse_header_field("timestamp", &header_page_ts_offset,
2906 &header_page_ts_size); 3154 &header_page_ts_size);
2907 parse_header_field((char *)"commit", &header_page_size_offset, 3155 parse_header_field("commit", &header_page_size_offset,
2908 &header_page_size_size); 3156 &header_page_size_size);
2909 parse_header_field((char *)"data", &header_page_data_offset, 3157 parse_header_field("data", &header_page_data_offset,
2910 &header_page_data_size); 3158 &header_page_data_size);
2911 3159
2912 return 0; 3160 return 0;
@@ -2957,6 +3205,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2957 if (ret < 0) 3205 if (ret < 0)
2958 die("failed to read ftrace event print fmt"); 3206 die("failed to read ftrace event print fmt");
2959 3207
3208 /* New ftrace handles args */
3209 if (ret > 0)
3210 return 0;
2960 /* 3211 /*
2961 * The arguments for ftrace files are parsed by the fields. 3212 * The arguments for ftrace files are parsed by the fields.
2962 * Set up the fields as their arguments. 3213 * Set up the fields as their arguments.
@@ -2994,12 +3245,16 @@ int parse_event_file(char *buf, unsigned long size, char *sys)
2994 die("failed to read event id"); 3245 die("failed to read event id");
2995 3246
2996 ret = event_read_format(event); 3247 ret = event_read_format(event);
2997 if (ret < 0) 3248 if (ret < 0) {
2998 die("failed to read event format"); 3249 warning("failed to read event format for %s", event->name);
3250 goto event_failed;
3251 }
2999 3252
3000 ret = event_read_print(event); 3253 ret = event_read_print(event);
3001 if (ret < 0) 3254 if (ret < 0) {
3002 die("failed to read event print fmt"); 3255 warning("failed to read event print fmt for %s", event->name);
3256 goto event_failed;
3257 }
3003 3258
3004 event->system = strdup(sys); 3259 event->system = strdup(sys);
3005 3260
@@ -3009,6 +3264,12 @@ int parse_event_file(char *buf, unsigned long size, char *sys)
3009 3264
3010 add_event(event); 3265 add_event(event);
3011 return 0; 3266 return 0;
3267
3268 event_failed:
3269 event->flags |= EVENT_FL_FAILED;
3270 /* still add it even if it failed */
3271 add_event(event);
3272 return -1;
3012} 3273}
3013 3274
3014void parse_set_info(int nr_cpus, int long_sz) 3275void parse_set_info(int nr_cpus, int long_sz)
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
new file mode 100644
index 000000000000..51e833fd58c3
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.c
@@ -0,0 +1,598 @@
1/*
2 * trace-event-perl. Feed perf trace events to an embedded Perl interpreter.
3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31#include "trace-event-perl.h"
32
33void xs_init(pTHX);
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37
38void xs_init(pTHX)
39{
40 const char *file = __FILE__;
41 dXSUB_SYS;
42
43 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
44 file);
45 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
46}
47
48INTERP my_perl;
49
50#define FTRACE_MAX_EVENT \
51 ((1 << (sizeof(unsigned short) * 8)) - 1)
52
53struct event *events[FTRACE_MAX_EVENT];
54
55static struct scripting_context *scripting_context;
56
57static char *cur_field_name;
58static int zero_flag_atom;
59
60static void define_symbolic_value(const char *ev_name,
61 const char *field_name,
62 const char *field_value,
63 const char *field_str)
64{
65 unsigned long long value;
66 dSP;
67
68 value = eval_flag(field_value);
69
70 ENTER;
71 SAVETMPS;
72 PUSHMARK(SP);
73
74 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
75 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
76 XPUSHs(sv_2mortal(newSVuv(value)));
77 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
78
79 PUTBACK;
80 if (get_cv("main::define_symbolic_value", 0))
81 call_pv("main::define_symbolic_value", G_SCALAR);
82 SPAGAIN;
83 PUTBACK;
84 FREETMPS;
85 LEAVE;
86}
87
88static void define_symbolic_values(struct print_flag_sym *field,
89 const char *ev_name,
90 const char *field_name)
91{
92 define_symbolic_value(ev_name, field_name, field->value, field->str);
93 if (field->next)
94 define_symbolic_values(field->next, ev_name, field_name);
95}
96
97static void define_symbolic_field(const char *ev_name,
98 const char *field_name)
99{
100 dSP;
101
102 ENTER;
103 SAVETMPS;
104 PUSHMARK(SP);
105
106 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
107 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
108
109 PUTBACK;
110 if (get_cv("main::define_symbolic_field", 0))
111 call_pv("main::define_symbolic_field", G_SCALAR);
112 SPAGAIN;
113 PUTBACK;
114 FREETMPS;
115 LEAVE;
116}
117
118static void define_flag_value(const char *ev_name,
119 const char *field_name,
120 const char *field_value,
121 const char *field_str)
122{
123 unsigned long long value;
124 dSP;
125
126 value = eval_flag(field_value);
127
128 ENTER;
129 SAVETMPS;
130 PUSHMARK(SP);
131
132 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
133 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
134 XPUSHs(sv_2mortal(newSVuv(value)));
135 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
136
137 PUTBACK;
138 if (get_cv("main::define_flag_value", 0))
139 call_pv("main::define_flag_value", G_SCALAR);
140 SPAGAIN;
141 PUTBACK;
142 FREETMPS;
143 LEAVE;
144}
145
146static void define_flag_values(struct print_flag_sym *field,
147 const char *ev_name,
148 const char *field_name)
149{
150 define_flag_value(ev_name, field_name, field->value, field->str);
151 if (field->next)
152 define_flag_values(field->next, ev_name, field_name);
153}
154
155static void define_flag_field(const char *ev_name,
156 const char *field_name,
157 const char *delim)
158{
159 dSP;
160
161 ENTER;
162 SAVETMPS;
163 PUSHMARK(SP);
164
165 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
166 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
167 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
168
169 PUTBACK;
170 if (get_cv("main::define_flag_field", 0))
171 call_pv("main::define_flag_field", G_SCALAR);
172 SPAGAIN;
173 PUTBACK;
174 FREETMPS;
175 LEAVE;
176}
177
178static void define_event_symbols(struct event *event,
179 const char *ev_name,
180 struct print_arg *args)
181{
182 switch (args->type) {
183 case PRINT_NULL:
184 break;
185 case PRINT_ATOM:
186 define_flag_value(ev_name, cur_field_name, "0",
187 args->atom.atom);
188 zero_flag_atom = 0;
189 break;
190 case PRINT_FIELD:
191 if (cur_field_name)
192 free(cur_field_name);
193 cur_field_name = strdup(args->field.name);
194 break;
195 case PRINT_FLAGS:
196 define_event_symbols(event, ev_name, args->flags.field);
197 define_flag_field(ev_name, cur_field_name, args->flags.delim);
198 define_flag_values(args->flags.flags, ev_name, cur_field_name);
199 break;
200 case PRINT_SYMBOL:
201 define_event_symbols(event, ev_name, args->symbol.field);
202 define_symbolic_field(ev_name, cur_field_name);
203 define_symbolic_values(args->symbol.symbols, ev_name,
204 cur_field_name);
205 break;
206 case PRINT_STRING:
207 break;
208 case PRINT_TYPE:
209 define_event_symbols(event, ev_name, args->typecast.item);
210 break;
211 case PRINT_OP:
212 if (strcmp(args->op.op, ":") == 0)
213 zero_flag_atom = 1;
214 define_event_symbols(event, ev_name, args->op.left);
215 define_event_symbols(event, ev_name, args->op.right);
216 break;
217 default:
218 /* we should warn... */
219 return;
220 }
221
222 if (args->next)
223 define_event_symbols(event, ev_name, args->next);
224}
225
226static inline struct event *find_cache_event(int type)
227{
228 static char ev_name[256];
229 struct event *event;
230
231 if (events[type])
232 return events[type];
233
234 events[type] = event = trace_find_event(type);
235 if (!event)
236 return NULL;
237
238 sprintf(ev_name, "%s::%s", event->system, event->name);
239
240 define_event_symbols(event, ev_name, event->print_fmt.args);
241
242 return event;
243}
244
245int common_pc(struct scripting_context *context)
246{
247 int pc;
248
249 pc = parse_common_pc(context->event_data);
250
251 return pc;
252}
253
254int common_flags(struct scripting_context *context)
255{
256 int flags;
257
258 flags = parse_common_flags(context->event_data);
259
260 return flags;
261}
262
263int common_lock_depth(struct scripting_context *context)
264{
265 int lock_depth;
266
267 lock_depth = parse_common_lock_depth(context->event_data);
268
269 return lock_depth;
270}
271
272static void perl_process_event(int cpu, void *data,
273 int size __attribute((unused)),
274 unsigned long long nsecs, char *comm)
275{
276 struct format_field *field;
277 static char handler[256];
278 unsigned long long val;
279 unsigned long s, ns;
280 struct event *event;
281 int type;
282 int pid;
283
284 dSP;
285
286 type = trace_parse_common_type(data);
287
288 event = find_cache_event(type);
289 if (!event)
290 die("ug! no event found for type %d", type);
291
292 pid = trace_parse_common_pid(data);
293
294 sprintf(handler, "%s::%s", event->system, event->name);
295
296 s = nsecs / NSECS_PER_SEC;
297 ns = nsecs - s * NSECS_PER_SEC;
298
299 scripting_context->event_data = data;
300
301 ENTER;
302 SAVETMPS;
303 PUSHMARK(SP);
304
305 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
306 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
307 XPUSHs(sv_2mortal(newSVuv(cpu)));
308 XPUSHs(sv_2mortal(newSVuv(s)));
309 XPUSHs(sv_2mortal(newSVuv(ns)));
310 XPUSHs(sv_2mortal(newSViv(pid)));
311 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
312
313 /* common fields other than pid can be accessed via xsub fns */
314
315 for (field = event->format.fields; field; field = field->next) {
316 if (field->flags & FIELD_IS_STRING) {
317 int offset;
318 if (field->flags & FIELD_IS_DYNAMIC) {
319 offset = *(int *)(data + field->offset);
320 offset &= 0xffff;
321 } else
322 offset = field->offset;
323 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
324 } else { /* FIELD_IS_NUMERIC */
325 val = read_size(data + field->offset, field->size);
326 if (field->flags & FIELD_IS_SIGNED) {
327 XPUSHs(sv_2mortal(newSViv(val)));
328 } else {
329 XPUSHs(sv_2mortal(newSVuv(val)));
330 }
331 }
332 }
333
334 PUTBACK;
335
336 if (get_cv(handler, 0))
337 call_pv(handler, G_SCALAR);
338 else if (get_cv("main::trace_unhandled", 0)) {
339 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
340 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
341 XPUSHs(sv_2mortal(newSVuv(cpu)));
342 XPUSHs(sv_2mortal(newSVuv(nsecs)));
343 XPUSHs(sv_2mortal(newSViv(pid)));
344 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
345 call_pv("main::trace_unhandled", G_SCALAR);
346 }
347 SPAGAIN;
348 PUTBACK;
349 FREETMPS;
350 LEAVE;
351}
352
353static void run_start_sub(void)
354{
355 dSP; /* access to Perl stack */
356 PUSHMARK(SP);
357
358 if (get_cv("main::trace_begin", 0))
359 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
360}
361
362/*
363 * Start trace script
364 */
365static int perl_start_script(const char *script)
366{
367 const char *command_line[2] = { "", NULL };
368
369 command_line[1] = script;
370
371 my_perl = perl_alloc();
372 perl_construct(my_perl);
373
374 if (perl_parse(my_perl, xs_init, 2, (char **)command_line,
375 (char **)NULL))
376 return -1;
377
378 perl_run(my_perl);
379 if (SvTRUE(ERRSV))
380 return -1;
381
382 run_start_sub();
383
384 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
385
386 return 0;
387}
388
389/*
390 * Stop trace script
391 */
392static int perl_stop_script(void)
393{
394 dSP; /* access to Perl stack */
395 PUSHMARK(SP);
396
397 if (get_cv("main::trace_end", 0))
398 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
399
400 perl_destruct(my_perl);
401 perl_free(my_perl);
402
403 fprintf(stderr, "\nperf trace Perl script stopped\n");
404
405 return 0;
406}
407
408static int perl_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.pl", outfile);
417 ofp = fopen(fname, "w");
418 if (ofp == NULL) {
419 fprintf(stderr, "couldn't open %s\n", fname);
420 return -1;
421 }
422
423 fprintf(ofp, "# perf trace event handlers, "
424 "generated by perf trace -g perl\n");
425
426 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
427 " License version 2\n\n");
428
429 fprintf(ofp, "# The common_* event handler fields are the most useful "
430 "fields common to\n");
431
432 fprintf(ofp, "# all events. They don't necessarily correspond to "
433 "the 'common_*' fields\n");
434
435 fprintf(ofp, "# in the format files. Those fields not available as "
436 "handler params can\n");
437
438 fprintf(ofp, "# be retrieved using Perl functions of the form "
439 "common_*($context).\n");
440
441 fprintf(ofp, "# See Context.pm for the list of available "
442 "functions.\n\n");
443
444 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
445 "Perf-Trace-Util/lib\";\n");
446
447 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
448 fprintf(ofp, "use Perf::Trace::Core;\n");
449 fprintf(ofp, "use Perf::Trace::Context;\n");
450 fprintf(ofp, "use Perf::Trace::Util;\n\n");
451
452 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
453 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
454
455 while ((event = trace_find_next_event(event))) {
456 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
457 fprintf(ofp, "\tmy (");
458
459 fprintf(ofp, "$event_name, ");
460 fprintf(ofp, "$context, ");
461 fprintf(ofp, "$common_cpu, ");
462 fprintf(ofp, "$common_secs, ");
463 fprintf(ofp, "$common_nsecs,\n");
464 fprintf(ofp, "\t $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\n");
479
480 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
481 "$common_secs, $common_nsecs,\n\t "
482 "$common_pid, $common_comm);\n\n");
483
484 fprintf(ofp, "\tprintf(\"");
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 % 4 == 0) {
493 fprintf(ofp, "\".\n\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 ");
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 ");
519
520 if (f->flags & FIELD_IS_FLAG) {
521 if ((count - 1) % 5 != 0) {
522 fprintf(ofp, "\n\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 ");
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");
545 fprintf(ofp, "}\n\n");
546 }
547
548 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
549 "$common_cpu, $common_secs, $common_nsecs,\n\t "
550 "$common_pid, $common_comm) = @_;\n\n");
551
552 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
553 "$common_secs, $common_nsecs,\n\t $common_pid, "
554 "$common_comm);\n}\n\n");
555
556 fprintf(ofp, "sub print_header\n{\n"
557 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
558 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
559 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
560
561 fclose(ofp);
562
563 fprintf(stderr, "generated Perl script: %s\n", fname);
564
565 return 0;
566}
567
568struct scripting_ops perl_scripting_ops = {
569 .name = "Perl",
570 .start_script = perl_start_script,
571 .stop_script = perl_stop_script,
572 .process_event = perl_process_event,
573 .generate_script = perl_generate_script,
574};
575
576#ifdef NO_LIBPERL
577void setup_perl_scripting(void)
578{
579 fprintf(stderr, "Perl scripting not supported."
580 " Install libperl and rebuild perf to enable it. e.g. "
581 "apt-get install libperl-dev (ubuntu), yum install "
582 "perl-ExtUtils-Embed (Fedora), etc.\n");
583}
584#else
585void setup_perl_scripting(void)
586{
587 int err;
588 err = script_spec_register("Perl", &perl_scripting_ops);
589 if (err)
590 die("error registering Perl script extension");
591
592 err = script_spec_register("pl", &perl_scripting_ops);
593 if (err)
594 die("error registering pl script extension");
595
596 scripting_context = malloc(sizeof(struct scripting_context));
597}
598#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
new file mode 100644
index 000000000000..8fe0d866fe1a
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.h
@@ -0,0 +1,51 @@
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) {}
37#else
38#include <EXTERN.h>
39#include <perl.h>
40typedef PerlInterpreter * INTERP;
41#endif
42
43struct scripting_context {
44 void *event_data;
45};
46
47int common_pc(struct scripting_context *context);
48int common_flags(struct scripting_context *context);
49int common_lock_depth(struct scripting_context *context);
50
51#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 44292e06cca4..342dfdd43f87 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -471,11 +471,11 @@ void trace_report(int fd)
471 471
472 read_or_die(buf, 3); 472 read_or_die(buf, 3);
473 if (memcmp(buf, test, 3) != 0) 473 if (memcmp(buf, test, 3) != 0)
474 die("not an trace data file"); 474 die("no trace data in the file");
475 475
476 read_or_die(buf, 7); 476 read_or_die(buf, 7);
477 if (memcmp(buf, "tracing", 7) != 0) 477 if (memcmp(buf, "tracing", 7) != 0)
478 die("not a trace file (missing tracing)"); 478 die("not a trace file (missing 'tracing' tag)");
479 479
480 version = read_string(); 480 version = read_string();
481 if (show_version) 481 if (show_version)
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index da77e073c867..81698d5e6503 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -29,6 +29,8 @@ enum format_flags {
29 FIELD_IS_SIGNED = 4, 29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8, 30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16, 31 FIELD_IS_DYNAMIC = 16,
32 FIELD_IS_FLAG = 32,
33 FIELD_IS_SYMBOLIC = 64,
32}; 34};
33 35
34struct format_field { 36struct format_field {
@@ -139,12 +141,14 @@ struct event {
139}; 141};
140 142
141enum { 143enum {
142 EVENT_FL_ISFTRACE = 1, 144 EVENT_FL_ISFTRACE = 0x01,
143 EVENT_FL_ISPRINT = 2, 145 EVENT_FL_ISPRINT = 0x02,
144 EVENT_FL_ISBPRINT = 4, 146 EVENT_FL_ISBPRINT = 0x04,
145 EVENT_FL_ISFUNC = 8, 147 EVENT_FL_ISFUNC = 0x08,
146 EVENT_FL_ISFUNCENT = 16, 148 EVENT_FL_ISFUNCENT = 0x10,
147 EVENT_FL_ISFUNCRET = 32, 149 EVENT_FL_ISFUNCRET = 0x20,
150
151 EVENT_FL_FAILED = 0x80000000
148}; 152};
149 153
150struct record { 154struct record {
@@ -237,13 +241,45 @@ extern int header_page_size_size;
237extern int header_page_data_offset; 241extern int header_page_data_offset;
238extern int header_page_data_size; 242extern int header_page_data_size;
239 243
244extern int latency_format;
245
240int parse_header_page(char *buf, unsigned long size); 246int parse_header_page(char *buf, unsigned long size);
241int trace_parse_common_type(void *data); 247int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data);
250int parse_common_flags(void *data);
251int parse_common_lock_depth(void *data);
242struct event *trace_find_event(int id); 252struct event *trace_find_event(int id);
253struct event *trace_find_next_event(struct event *event);
254unsigned long long read_size(void *ptr, int size);
243unsigned long long 255unsigned long long
244raw_field_value(struct event *event, const char *name, void *data); 256raw_field_value(struct event *event, const char *name, void *data);
245void *raw_field_ptr(struct event *event, const char *name, void *data); 257void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag);
259
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
261
262/* taken from kernel/trace/trace.h */
263enum trace_flag_type {
264 TRACE_FLAG_IRQS_OFF = 0x01,
265 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
266 TRACE_FLAG_NEED_RESCHED = 0x04,
267 TRACE_FLAG_HARDIRQ = 0x08,
268 TRACE_FLAG_SOFTIRQ = 0x10,
269};
270
271struct scripting_ops {
272 const char *name;
273 int (*start_script) (const char *);
274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm);
277 int (*generate_script) (const char *outfile);
278};
279
280int script_spec_register(const char *spec, struct scripting_ops *ops);
246 281
247void read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void);
248 284
249#endif /* __PERF_TRACE_EVENTS_H */ 285#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 9de2329dd44d..c673d8825883 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -84,6 +84,9 @@
84#include <iconv.h> 84#include <iconv.h>
85#endif 85#endif
86 86
87extern const char *graph_line;
88extern const char *graph_dotted_line;
89
87/* On most systems <limits.h> would have given us this, but 90/* On most systems <limits.h> would have given us this, but
88 * not on some systems (e.g. GNU/Hurd). 91 * not on some systems (e.g. GNU/Hurd).
89 */ 92 */
@@ -134,6 +137,15 @@ extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1,
134extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); 137extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
135extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); 138extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
136 139
140#include "../../../include/linux/stringify.h"
141
142#define DIE_IF(cnd) \
143 do { if (cnd) \
144 die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
145 __stringify(cnd) "\n"); \
146 } while (0)
147
148
137extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 149extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
138 150
139extern int prefixcmp(const char *str, const char *prefix); 151extern int prefixcmp(const char *str, const char *prefix);
@@ -278,17 +290,15 @@ static inline char *gitstrchrnul(const char *s, int c)
278 * Wrappers: 290 * Wrappers:
279 */ 291 */
280extern char *xstrdup(const char *str); 292extern char *xstrdup(const char *str);
281extern void *xmalloc(size_t size); 293extern void *xmalloc(size_t size) __attribute__((weak));
282extern void *xmemdupz(const void *data, size_t len); 294extern void *xmemdupz(const void *data, size_t len);
283extern char *xstrndup(const char *str, size_t len); 295extern char *xstrndup(const char *str, size_t len);
284extern void *xrealloc(void *ptr, size_t size); 296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
285extern void *xcalloc(size_t nmemb, size_t size); 297
286extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 298static inline void *zalloc(size_t size)
287extern ssize_t xread(int fd, void *buf, size_t len); 299{
288extern ssize_t xwrite(int fd, const void *buf, size_t len); 300 return calloc(1, size);
289extern int xdup(int fd); 301}
290extern FILE *xfdopen(int fd, const char *mode);
291extern int xmkstemp(char *template);
292 302
293static inline size_t xsize_t(off_t len) 303static inline size_t xsize_t(off_t len)
294{ 304{
@@ -306,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
306#undef isascii 316#undef isascii
307#undef isspace 317#undef isspace
308#undef isdigit 318#undef isdigit
319#undef isxdigit
309#undef isalpha 320#undef isalpha
310#undef isprint 321#undef isprint
311#undef isalnum 322#undef isalnum
@@ -323,6 +334,8 @@ extern unsigned char sane_ctype[256];
323#define isascii(x) (((x) & ~0x7f) == 0) 334#define isascii(x) (((x) & ~0x7f) == 0)
324#define isspace(x) sane_istest(x,GIT_SPACE) 335#define isspace(x) sane_istest(x,GIT_SPACE)
325#define isdigit(x) sane_istest(x,GIT_DIGIT) 336#define isdigit(x) sane_istest(x,GIT_DIGIT)
337#define isxdigit(x) \
338 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
326#define isalpha(x) sane_istest(x,GIT_ALPHA) 339#define isalpha(x) sane_istest(x,GIT_ALPHA)
327#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 340#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
328#define isprint(x) sane_istest(x,GIT_PRINT) 341#define isprint(x) sane_istest(x,GIT_PRINT)
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 4574ac28396f..bf44ca85d23b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
79 return ret; 79 return ret;
80} 80}
81 81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/* 82/*
114 * xread() is the same a read(), but it automatically restarts read() 83 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread() 84 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. 85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */ 86 */
118ssize_t xread(int fd, void *buf, size_t len) 87static ssize_t xread(int fd, void *buf, size_t len)
119{ 88{
120 ssize_t nr; 89 ssize_t nr;
121 while (1) { 90 while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT 100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful. 101 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */ 102 */
134ssize_t xwrite(int fd, const void *buf, size_t len) 103static ssize_t xwrite(int fd, const void *buf, size_t len)
135{ 104{
136 ssize_t nr; 105 ssize_t nr;
137 while (1) { 106 while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
179 148
180 return total; 149 return total;
181} 150}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}