aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-12-15 04:29:06 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-15 04:29:06 -0500
commit709334c87dbdb44150ce436b3d13c814db0dcae9 (patch)
tree5861a45f70c1f283720337abd864498f5afb3dbe /tools
parent0d64b568fcd48b133721c1d322e7c51d85eb12df (diff)
parentf74890277a196949e4004fe2955e1d4fb3930f98 (diff)
Merge branch 'fixes' of git://git.alsa-project.org/alsa-kernel into for-linus
Diffstat (limited to 'tools')
-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.txt47
-rw-r--r--tools/perf/Documentation/perf-probe.txt60
-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/Makefile151
-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.c885
-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.c796
-rw-r--r--tools/perf/builtin-probe.c290
-rw-r--r--tools/perf/builtin-record.c345
-rw-r--r--tools/perf/builtin-report.c1176
-rw-r--r--tools/perf/builtin-sched.c541
-rw-r--r--tools/perf/builtin-stat.c34
-rw-r--r--tools/perf/builtin-timechart.c321
-rw-r--r--tools/perf/builtin-top.c503
-rw-r--r--tools/perf/builtin-trace.c454
-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
-rw-r--r--tools/perf/util/cache.h11
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/color.h6
-rw-r--r--tools/perf/util/ctype.c8
-rw-r--r--tools/perf/util/data_map.c291
-rw-r--r--tools/perf/util/data_map.h32
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/debug.h9
-rw-r--r--tools/perf/util/debugfs.c241
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c379
-rw-r--r--tools/perf/util/event.h92
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c408
-rw-r--r--tools/perf/util/header.h76
-rw-r--r--tools/perf/util/help.h6
-rw-r--r--tools/perf/util/hist.c202
-rw-r--r--tools/perf/util/hist.h50
-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/levenshtein.h6
-rw-r--r--tools/perf/util/map.c99
-rw-r--r--tools/perf/util/module.c545
-rw-r--r--tools/perf/util/module.h53
-rw-r--r--tools/perf/util/parse-events.c170
-rw-r--r--tools/perf/util/parse-events.h8
-rw-r--r--tools/perf/util/parse-options.c3
-rw-r--r--tools/perf/util/parse-options.h6
-rw-r--r--tools/perf/util/probe-event.c587
-rw-r--r--tools/perf/util/probe-event.h19
-rw-r--r--tools/perf/util/probe-finder.c732
-rw-r--r--tools/perf/util/probe-finder.h57
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c290
-rw-r--r--tools/perf/util/sort.h99
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c194
-rw-r--r--tools/perf/util/string.h10
-rw-r--r--tools/perf/util/strlist.h6
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c1194
-rw-r--r--tools/perf/util/symbol.h92
-rw-r--r--tools/perf/util/thread.c250
-rw-r--r--tools/perf/util/thread.h50
-rw-r--r--tools/perf/util/trace-event-info.c26
-rw-r--r--tools/perf/util/trace-event-parse.c577
-rw-r--r--tools/perf/util/trace-event-perl.c641
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c14
-rw-r--r--tools/perf/util/trace-event.h64
-rw-r--r--tools/perf/util/types.h6
-rw-r--r--tools/perf/util/util.h31
-rw-r--r--tools/perf/util/values.h6
-rw-r--r--tools/perf/util/wrapper.c61
124 files changed, 12043 insertions, 4343 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..eac4d852e7cd
--- /dev/null
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -0,0 +1,47 @@
1perf-kmem(1)
2==============
3
4NAME
5----
6perf-kmem - Tool to trace/measure kernel memory(slab) properties
7
8SYNOPSIS
9--------
10[verse]
11'perf kmem' {record|stat} [<options>]
12
13DESCRIPTION
14-----------
15There are two variants of perf kmem:
16
17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload.
19
20 'perf kmem stat' to report kernel memory statistics.
21
22OPTIONS
23-------
24-i <file>::
25--input=<file>::
26 Select the input file (default: perf.data)
27
28--caller::
29 Show per-callsite statistics
30
31--alloc::
32 Show per-allocation statistics
33
34-s <key[,key2...]>::
35--sort=<key[,key2...]>::
36 Sort the output (default: frag,hit,bytes)
37
38-l <num>::
39--line=<num>::
40 Print n lines only
41
42--raw-ip::
43 Print raw ip instead of symbol
44
45SEE ALSO
46--------
47linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644
index 000000000000..8fa6bf99fcb5
--- /dev/null
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -0,0 +1,60 @@
1perf-probe(1)
2=============
3
4NAME
5----
6perf-probe - Define new dynamic tracepoints
7
8SYNOPSIS
9--------
10[verse]
11'perf probe' [options] --add='PROBE' [...]
12or
13'perf probe' [options] PROBE
14or
15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or
17'perf probe' --list
18
19DESCRIPTION
20-----------
21This command defines dynamic tracepoint events, by symbol and registers
22without debuginfo, or by C expressions (C line numbers, C function names,
23and C local variables) with debuginfo.
24
25
26OPTIONS
27-------
28-k::
29--vmlinux=PATH::
30 Specify vmlinux path which has debuginfo (Dwarf binary).
31
32-v::
33--verbose::
34 Be more verbose (show parsed arguments, etc).
35
36-a::
37--add=::
38 Define a probe event (see PROBE SYNTAX for detail).
39
40-d::
41--del=::
42 Delete a probe event.
43
44-l::
45--list::
46 List up current probe events.
47
48PROBE SYNTAX
49------------
50Probe points are defined by following syntax.
51
52 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
53
54'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function.
55It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
56'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
57
58SEE ALSO
59--------
60linkperf: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 7e190d522cd5..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,20 +162,6 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 162uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 163uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 164
160#
161# Add -m32 for cross-builds:
162#
163ifdef NO_64BIT
164 MBITS := -m32
165else
166 #
167 # If we're on a 64-bit kernel, use -m64:
168 #
169 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
170 MBITS := -m64
171 endif
172endif
173
174# CFLAGS and LDFLAGS are for the users to override from the command line. 165# CFLAGS and LDFLAGS are for the users to override from the command line.
175 166
176# 167#
@@ -200,8 +191,15 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
200EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes 191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement 192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
202 193
203CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) 194ifeq ("$(origin DEBUG)", "command line")
204LDFLAGS = -lpthread -lrt -lelf -lm 195 PERF_DEBUG = $(DEBUG)
196endif
197ifndef PERF_DEBUG
198 CFLAGS_OPTIMIZE = -O6
199endif
200
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm
205ALL_CFLAGS = $(CFLAGS) 203ALL_CFLAGS = $(CFLAGS)
206ALL_LDFLAGS = $(LDFLAGS) 204ALL_LDFLAGS = $(LDFLAGS)
207STRIP ?= strip 205STRIP ?= strip
@@ -252,6 +250,9 @@ PTHREAD_LIBS = -lpthread
252# explicitly what architecture to check for. Fix this up for yours.. 250# explicitly what architecture to check for. Fix this up for yours..
253SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 251SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
254 252
253ifeq ($(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
255 256
256 257
257### --- END CONFIGURATION SECTION --- 258### --- END CONFIGURATION SECTION ---
@@ -327,8 +328,28 @@ LIB_FILE=libperf.a
327LIB_H += ../../include/linux/perf_event.h 328LIB_H += ../../include/linux/perf_event.h
328LIB_H += ../../include/linux/rbtree.h 329LIB_H += ../../include/linux/rbtree.h
329LIB_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
330LIB_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
331LIB_H += perf.h 350LIB_H += perf.h
351LIB_H += util/debugfs.h
352LIB_H += util/event.h
332LIB_H += util/types.h 353LIB_H += util/types.h
333LIB_H += util/levenshtein.h 354LIB_H += util/levenshtein.h
334LIB_H += util/parse-options.h 355LIB_H += util/parse-options.h
@@ -342,15 +363,22 @@ LIB_H += util/strlist.h
342LIB_H += util/run-command.h 363LIB_H += util/run-command.h
343LIB_H += util/sigchain.h 364LIB_H += util/sigchain.h
344LIB_H += util/symbol.h 365LIB_H += util/symbol.h
345LIB_H += util/module.h
346LIB_H += util/color.h 366LIB_H += util/color.h
347LIB_H += util/values.h 367LIB_H += util/values.h
368LIB_H += util/sort.h
369LIB_H += util/hist.h
370LIB_H += util/thread.h
371LIB_H += util/data_map.h
372LIB_H += util/probe-finder.h
373LIB_H += util/probe-event.h
348 374
349LIB_OBJS += util/abspath.o 375LIB_OBJS += util/abspath.o
350LIB_OBJS += util/alias.o 376LIB_OBJS += util/alias.o
351LIB_OBJS += util/config.o 377LIB_OBJS += util/config.o
352LIB_OBJS += util/ctype.o 378LIB_OBJS += util/ctype.o
379LIB_OBJS += util/debugfs.o
353LIB_OBJS += util/environment.o 380LIB_OBJS += util/environment.o
381LIB_OBJS += util/event.o
354LIB_OBJS += util/exec_cmd.o 382LIB_OBJS += util/exec_cmd.o
355LIB_OBJS += util/help.o 383LIB_OBJS += util/help.o
356LIB_OBJS += util/levenshtein.o 384LIB_OBJS += util/levenshtein.o
@@ -358,6 +386,9 @@ LIB_OBJS += util/parse-options.o
358LIB_OBJS += util/parse-events.o 386LIB_OBJS += util/parse-events.o
359LIB_OBJS += util/path.o 387LIB_OBJS += util/path.o
360LIB_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
361LIB_OBJS += util/run-command.o 392LIB_OBJS += util/run-command.o
362LIB_OBJS += util/quote.o 393LIB_OBJS += util/quote.o
363LIB_OBJS += util/strbuf.o 394LIB_OBJS += util/strbuf.o
@@ -367,7 +398,6 @@ LIB_OBJS += util/usage.o
367LIB_OBJS += util/wrapper.o 398LIB_OBJS += util/wrapper.o
368LIB_OBJS += util/sigchain.o 399LIB_OBJS += util/sigchain.o
369LIB_OBJS += util/symbol.o 400LIB_OBJS += util/symbol.o
370LIB_OBJS += util/module.o
371LIB_OBJS += util/color.o 401LIB_OBJS += util/color.o
372LIB_OBJS += util/pager.o 402LIB_OBJS += util/pager.o
373LIB_OBJS += util/header.o 403LIB_OBJS += util/header.o
@@ -379,11 +409,25 @@ LIB_OBJS += util/thread.o
379LIB_OBJS += util/trace-event-parse.o 409LIB_OBJS += util/trace-event-parse.o
380LIB_OBJS += util/trace-event-read.o 410LIB_OBJS += util/trace-event-read.o
381LIB_OBJS += util/trace-event-info.o 411LIB_OBJS += util/trace-event-info.o
412LIB_OBJS += util/trace-event-perl.o
382LIB_OBJS += util/svghelper.o 413LIB_OBJS += util/svghelper.o
414LIB_OBJS += util/sort.o
415LIB_OBJS += util/hist.o
416LIB_OBJS += util/data_map.o
417LIB_OBJS += util/probe-event.o
383 418
384BUILTIN_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
385BUILTIN_OBJS += builtin-help.o 428BUILTIN_OBJS += builtin-help.o
386BUILTIN_OBJS += builtin-sched.o 429BUILTIN_OBJS += builtin-sched.o
430BUILTIN_OBJS += builtin-buildid-list.o
387BUILTIN_OBJS += builtin-list.o 431BUILTIN_OBJS += builtin-list.o
388BUILTIN_OBJS += builtin-record.o 432BUILTIN_OBJS += builtin-record.o
389BUILTIN_OBJS += builtin-report.o 433BUILTIN_OBJS += builtin-report.o
@@ -391,9 +435,16 @@ BUILTIN_OBJS += builtin-stat.o
391BUILTIN_OBJS += builtin-timechart.o 435BUILTIN_OBJS += builtin-timechart.o
392BUILTIN_OBJS += builtin-top.o 436BUILTIN_OBJS += builtin-top.o
393BUILTIN_OBJS += builtin-trace.o 437BUILTIN_OBJS += builtin-trace.o
438BUILTIN_OBJS += builtin-probe.o
439BUILTIN_OBJS += builtin-kmem.o
394 440
395PERFLIBS = $(LIB_FILE) 441PERFLIBS = $(LIB_FILE)
396 442
443ifeq ($(V), 2)
444 QUIET_STDERR = ">/dev/null"
445else
446 QUIET_STDERR = ">/dev/null 2>&1"
447endif
397# 448#
398# Platform specific tweaks 449# Platform specific tweaks
399# 450#
@@ -421,36 +472,58 @@ ifeq ($(uname_S),Darwin)
421 PTHREAD_LIBS = 472 PTHREAD_LIBS =
422endif 473endif
423 474
424ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) 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)
425 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) > /dev/null 2>&1 && echo y"), y) 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)
426 BASIC_CFLAGS += -DLIBELF_NO_MMAP 481 BASIC_CFLAGS += -DLIBELF_NO_MMAP
427 endif 482 endif
428else 483else
429 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]);
430endif 485endif
431 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
432ifdef NO_DEMANGLE 505ifdef NO_DEMANGLE
433 BASIC_CFLAGS += -DNO_DEMANGLE 506 BASIC_CFLAGS += -DNO_DEMANGLE
434else 507else
435 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y") 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")
436 509
437 ifeq ($(has_bfd),y) 510 ifeq ($(has_bfd),y)
438 EXTLIBS += -lbfd 511 EXTLIBS += -lbfd
439 else 512 else
440 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") 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")
441 ifeq ($(has_bfd_iberty),y) 514 ifeq ($(has_bfd_iberty),y)
442 EXTLIBS += -lbfd -liberty 515 EXTLIBS += -lbfd -liberty
443 else 516 else
444 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") 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")
445 ifeq ($(has_bfd_iberty_z),y) 518 ifeq ($(has_bfd_iberty_z),y)
446 EXTLIBS += -lbfd -liberty -lz 519 EXTLIBS += -lbfd -liberty -lz
447 else 520 else
448 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y") 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")
449 ifeq ($(has_cplus_demangle),y) 522 ifeq ($(has_cplus_demangle),y)
450 EXTLIBS += -liberty 523 EXTLIBS += -liberty
451 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 524 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
452 else 525 else
453 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)
454 BASIC_CFLAGS += -DNO_DEMANGLE 527 BASIC_CFLAGS += -DNO_DEMANGLE
455 endif 528 endif
456 endif 529 endif
@@ -787,6 +860,25 @@ util/config.o: util/config.c PERF-CFLAGS
787util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 860util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
788 $(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)"' $<
789 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
790perf-%$X: %.o $(PERFLIBS) 882perf-%$X: %.o $(PERFLIBS)
791 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 883 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
792 884
@@ -894,6 +986,13 @@ export perfexec_instdir
894install: all 986install: all
895 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 987 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
896 $(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'
897ifdef BUILT_INS 996ifdef BUILT_INS
898 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 997 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
899 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 998 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -979,7 +1078,7 @@ distclean: clean
979# $(RM) configure 1078# $(RM) configure
980 1079
981clean: 1080clean:
982 $(RM) *.o */*.o $(LIB_FILE) 1081 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
983 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1082 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
984 $(RM) $(TEST_PROGRAMS) 1083 $(RM) $(TEST_PROGRAMS)
985 $(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 1ec741615814..0bf2e8f9af57 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,29 +19,26 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/event.h"
22#include "util/parse-options.h" 23#include "util/parse-options.h"
23#include "util/parse-events.h" 24#include "util/parse-events.h"
24#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h"
27#include "util/hist.h"
28#include "util/data_map.h"
25 29
26static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
27 31
28static char default_sort_order[] = "comm,symbol";
29static char *sort_order = default_sort_order;
30
31static int force; 32static int force;
32static int input;
33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
34 33
35static int full_paths; 34static int full_paths;
36 35
37static int print_line; 36static int print_line;
38 37
39static unsigned long page_size; 38struct sym_hist {
40static unsigned long mmap_window = 32; 39 u64 sum;
41 40 u64 ip[0];
42static struct rb_root threads; 41};
43static struct thread *last_match;
44
45 42
46struct sym_ext { 43struct sym_ext {
47 struct rb_node node; 44 struct rb_node node;
@@ -49,247 +46,38 @@ struct sym_ext {
49 char *path; 46 char *path;
50}; 47};
51 48
52/* 49struct sym_priv {
53 * histogram, sorted on item, collects counts 50 struct sym_hist *hist;
54 */ 51 struct sym_ext *ext;
55
56static struct rb_root hist;
57
58struct hist_entry {
59 struct rb_node rb_node;
60
61 struct thread *thread;
62 struct map *map;
63 struct dso *dso;
64 struct symbol *sym;
65 u64 ip;
66 char level;
67
68 uint32_t count;
69};
70
71/*
72 * configurable sorting bits
73 */
74
75struct sort_entry {
76 struct list_head list;
77
78 const char *header;
79
80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
82 size_t (*print)(FILE *fp, struct hist_entry *);
83};
84
85/* --sort pid */
86
87static int64_t
88sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
89{
90 return right->thread->pid - left->thread->pid;
91}
92
93static size_t
94sort__thread_print(FILE *fp, struct hist_entry *self)
95{
96 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
97}
98
99static struct sort_entry sort_thread = {
100 .header = " Command: Pid",
101 .cmp = sort__thread_cmp,
102 .print = sort__thread_print,
103};
104
105/* --sort comm */
106
107static int64_t
108sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
109{
110 return right->thread->pid - left->thread->pid;
111}
112
113static int64_t
114sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
115{
116 char *comm_l = left->thread->comm;
117 char *comm_r = right->thread->comm;
118
119 if (!comm_l || !comm_r) {
120 if (!comm_l && !comm_r)
121 return 0;
122 else if (!comm_l)
123 return -1;
124 else
125 return 1;
126 }
127
128 return strcmp(comm_l, comm_r);
129}
130
131static size_t
132sort__comm_print(FILE *fp, struct hist_entry *self)
133{
134 return fprintf(fp, "%16s", self->thread->comm);
135}
136
137static struct sort_entry sort_comm = {
138 .header = " Command",
139 .cmp = sort__comm_cmp,
140 .collapse = sort__comm_collapse,
141 .print = sort__comm_print,
142};
143
144/* --sort dso */
145
146static int64_t
147sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
148{
149 struct dso *dso_l = left->dso;
150 struct dso *dso_r = right->dso;
151
152 if (!dso_l || !dso_r) {
153 if (!dso_l && !dso_r)
154 return 0;
155 else if (!dso_l)
156 return -1;
157 else
158 return 1;
159 }
160
161 return strcmp(dso_l->name, dso_r->name);
162}
163
164static size_t
165sort__dso_print(FILE *fp, struct hist_entry *self)
166{
167 if (self->dso)
168 return fprintf(fp, "%-25s", self->dso->name);
169
170 return fprintf(fp, "%016llx ", (u64)self->ip);
171}
172
173static struct sort_entry sort_dso = {
174 .header = "Shared Object ",
175 .cmp = sort__dso_cmp,
176 .print = sort__dso_print,
177};
178
179/* --sort symbol */
180
181static int64_t
182sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183{
184 u64 ip_l, ip_r;
185
186 if (left->sym == right->sym)
187 return 0;
188
189 ip_l = left->sym ? left->sym->start : left->ip;
190 ip_r = right->sym ? right->sym->start : right->ip;
191
192 return (int64_t)(ip_r - ip_l);
193}
194
195static size_t
196sort__sym_print(FILE *fp, struct hist_entry *self)
197{
198 size_t ret = 0;
199
200 if (verbose)
201 ret += fprintf(fp, "%#018llx ", (u64)self->ip);
202
203 if (self->sym) {
204 ret += fprintf(fp, "[%c] %s",
205 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
206 } else {
207 ret += fprintf(fp, "%#016llx", (u64)self->ip);
208 }
209
210 return ret;
211}
212
213static struct sort_entry sort_sym = {
214 .header = "Symbol",
215 .cmp = sort__sym_cmp,
216 .print = sort__sym_print,
217};
218
219static int sort__need_collapse = 0;
220
221struct sort_dimension {
222 const char *name;
223 struct sort_entry *entry;
224 int taken;
225}; 52};
226 53
227static struct sort_dimension sort_dimensions[] = { 54static struct symbol_conf symbol_conf = {
228 { .name = "pid", .entry = &sort_thread, }, 55 .priv_size = sizeof(struct sym_priv),
229 { .name = "comm", .entry = &sort_comm, }, 56 .try_vmlinux_path = true,
230 { .name = "dso", .entry = &sort_dso, },
231 { .name = "symbol", .entry = &sort_sym, },
232}; 57};
233 58
234static LIST_HEAD(hist_entry__sort_list); 59static const char *sym_hist_filter;
235 60
236static int sort_dimension__add(char *tok) 61static int symbol_filter(struct map *map __used, struct symbol *sym)
237{ 62{
238 unsigned int i; 63 if (sym_hist_filter == NULL ||
239 64 strcmp(sym->name, sym_hist_filter) == 0) {
240 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 65 struct sym_priv *priv = symbol__priv(sym);
241 struct sort_dimension *sd = &sort_dimensions[i]; 66 const int size = (sizeof(*priv->hist) +
242 67 (sym->end - sym->start) * sizeof(u64));
243 if (sd->taken)
244 continue;
245
246 if (strncasecmp(tok, sd->name, strlen(tok)))
247 continue;
248
249 if (sd->entry->collapse)
250 sort__need_collapse = 1;
251
252 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
253 sd->taken = 1;
254 68
69 priv->hist = malloc(size);
70 if (priv->hist)
71 memset(priv->hist, 0, size);
255 return 0; 72 return 0;
256 } 73 }
257 74 /*
258 return -ESRCH; 75 * FIXME: We should really filter it out, as we don't want to go thru symbols
259} 76 * we're not interested, and if a DSO ends up with no symbols, delete it too,
260 77 * but right now the kernel loading routines in symbol.c bail out if no symbols
261static int64_t 78 * are found, fix it later.
262hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 79 */
263{ 80 return 0;
264 struct sort_entry *se;
265 int64_t cmp = 0;
266
267 list_for_each_entry(se, &hist_entry__sort_list, list) {
268 cmp = se->cmp(left, right);
269 if (cmp)
270 break;
271 }
272
273 return cmp;
274}
275
276static int64_t
277hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
278{
279 struct sort_entry *se;
280 int64_t cmp = 0;
281
282 list_for_each_entry(se, &hist_entry__sort_list, list) {
283 int64_t (*f)(struct hist_entry *, struct hist_entry *);
284
285 f = se->collapse ?: se->cmp;
286
287 cmp = f(left, right);
288 if (cmp)
289 break;
290 }
291
292 return cmp;
293} 81}
294 82
295/* 83/*
@@ -299,380 +87,81 @@ static void hist_hit(struct hist_entry *he, u64 ip)
299{ 87{
300 unsigned int sym_size, offset; 88 unsigned int sym_size, offset;
301 struct symbol *sym = he->sym; 89 struct symbol *sym = he->sym;
90 struct sym_priv *priv;
91 struct sym_hist *h;
302 92
303 he->count++; 93 he->count++;
304 94
305 if (!sym || !sym->hist) 95 if (!sym || !he->map)
96 return;
97
98 priv = symbol__priv(sym);
99 if (!priv->hist)
306 return; 100 return;
307 101
308 sym_size = sym->end - sym->start; 102 sym_size = sym->end - sym->start;
309 offset = ip - sym->start; 103 offset = ip - sym->start;
310 104
105 if (verbose)
106 fprintf(stderr, "%s: ip=%Lx\n", __func__,
107 he->map->unmap_ip(he->map, ip));
108
311 if (offset >= sym_size) 109 if (offset >= sym_size)
312 return; 110 return;
313 111
314 sym->hist_sum++; 112 h = priv->hist;
315 sym->hist[offset]++; 113 h->sum++;
114 h->ip[offset]++;
316 115
317 if (verbose >= 3) 116 if (verbose >= 3)
318 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 117 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
319 (void *)(unsigned long)he->sym->start, 118 (void *)(unsigned long)he->sym->start,
320 he->sym->name, 119 he->sym->name,
321 (void *)(unsigned long)ip, ip - he->sym->start, 120 (void *)(unsigned long)ip, ip - he->sym->start,
322 sym->hist[offset]); 121 h->ip[offset]);
323} 122}
324 123
325static int 124static int hist_entry__add(struct addr_location *al, u64 count)
326hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
327 struct symbol *sym, u64 ip, char level)
328{ 125{
329 struct rb_node **p = &hist.rb_node; 126 bool hit;
330 struct rb_node *parent = NULL; 127 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
331 struct hist_entry *he; 128 if (he == NULL)
332 struct hist_entry entry = {
333 .thread = thread,
334 .map = map,
335 .dso = dso,
336 .sym = sym,
337 .ip = ip,
338 .level = level,
339 .count = 1,
340 };
341 int cmp;
342
343 while (*p != NULL) {
344 parent = *p;
345 he = rb_entry(parent, struct hist_entry, rb_node);
346
347 cmp = hist_entry__cmp(&entry, he);
348
349 if (!cmp) {
350 hist_hit(he, ip);
351
352 return 0;
353 }
354
355 if (cmp < 0)
356 p = &(*p)->rb_left;
357 else
358 p = &(*p)->rb_right;
359 }
360
361 he = malloc(sizeof(*he));
362 if (!he)
363 return -ENOMEM; 129 return -ENOMEM;
364 *he = entry; 130 hist_hit(he, al->addr);
365 rb_link_node(&he->rb_node, parent, p);
366 rb_insert_color(&he->rb_node, &hist);
367
368 return 0; 131 return 0;
369} 132}
370 133
371static void hist_entry__free(struct hist_entry *he) 134static int process_sample_event(event_t *event)
372{
373 free(he);
374}
375
376/*
377 * collapse the histogram
378 */
379
380static struct rb_root collapse_hists;
381
382static void collapse__insert_entry(struct hist_entry *he)
383{
384 struct rb_node **p = &collapse_hists.rb_node;
385 struct rb_node *parent = NULL;
386 struct hist_entry *iter;
387 int64_t cmp;
388
389 while (*p != NULL) {
390 parent = *p;
391 iter = rb_entry(parent, struct hist_entry, rb_node);
392
393 cmp = hist_entry__collapse(iter, he);
394
395 if (!cmp) {
396 iter->count += he->count;
397 hist_entry__free(he);
398 return;
399 }
400
401 if (cmp < 0)
402 p = &(*p)->rb_left;
403 else
404 p = &(*p)->rb_right;
405 }
406
407 rb_link_node(&he->rb_node, parent, p);
408 rb_insert_color(&he->rb_node, &collapse_hists);
409}
410
411static void collapse__resort(void)
412{
413 struct rb_node *next;
414 struct hist_entry *n;
415
416 if (!sort__need_collapse)
417 return;
418
419 next = rb_first(&hist);
420 while (next) {
421 n = rb_entry(next, struct hist_entry, rb_node);
422 next = rb_next(&n->rb_node);
423
424 rb_erase(&n->rb_node, &hist);
425 collapse__insert_entry(n);
426 }
427}
428
429/*
430 * reverse the map, sort on count.
431 */
432
433static struct rb_root output_hists;
434
435static void output__insert_entry(struct hist_entry *he)
436{ 135{
437 struct rb_node **p = &output_hists.rb_node; 136 struct addr_location al;
438 struct rb_node *parent = NULL;
439 struct hist_entry *iter;
440 137
441 while (*p != NULL) { 138 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
442 parent = *p; 139 event->ip.pid, (void *)(long)event->ip.ip);
443 iter = rb_entry(parent, struct hist_entry, rb_node);
444 140
445 if (he->count > iter->count) 141 if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
446 p = &(*p)->rb_left;
447 else
448 p = &(*p)->rb_right;
449 }
450
451 rb_link_node(&he->rb_node, parent, p);
452 rb_insert_color(&he->rb_node, &output_hists);
453}
454
455static void output__resort(void)
456{
457 struct rb_node *next;
458 struct hist_entry *n;
459 struct rb_root *tree = &hist;
460
461 if (sort__need_collapse)
462 tree = &collapse_hists;
463
464 next = rb_first(tree);
465
466 while (next) {
467 n = rb_entry(next, struct hist_entry, rb_node);
468 next = rb_next(&n->rb_node);
469
470 rb_erase(&n->rb_node, tree);
471 output__insert_entry(n);
472 }
473}
474
475static unsigned long total = 0,
476 total_mmap = 0,
477 total_comm = 0,
478 total_fork = 0,
479 total_unknown = 0;
480
481static int
482process_sample_event(event_t *event, unsigned long offset, unsigned long head)
483{
484 char level;
485 int show = 0;
486 struct dso *dso = NULL;
487 struct thread *thread;
488 u64 ip = event->ip.ip;
489 struct map *map = NULL;
490
491 thread = threads__findnew(event->ip.pid, &threads, &last_match);
492
493 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
494 (void *)(offset + head),
495 (void *)(long)(event->header.size),
496 event->header.misc,
497 event->ip.pid,
498 (void *)(long)ip);
499
500 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
501
502 if (thread == NULL) {
503 fprintf(stderr, "problem processing %d event, skipping it.\n", 142 fprintf(stderr, "problem processing %d event, skipping it.\n",
504 event->header.type); 143 event->header.type);
505 return -1; 144 return -1;
506 } 145 }
507 146
508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 147 if (hist_entry__add(&al, 1)) {
509 show = SHOW_KERNEL; 148 fprintf(stderr, "problem incrementing symbol count, "
510 level = 'k'; 149 "skipping event\n");
511
512 dso = kernel_dso;
513
514 dump_printf(" ...... dso: %s\n", dso->name);
515
516 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
517
518 show = SHOW_USER;
519 level = '.';
520
521 map = thread__find_map(thread, ip);
522 if (map != NULL) {
523 ip = map->map_ip(map, ip);
524 dso = map->dso;
525 } else {
526 /*
527 * If this is outside of all known maps,
528 * and is a negative address, try to look it
529 * up in the kernel dso, as it might be a
530 * vsyscall (which executes in user-mode):
531 */
532 if ((long long)ip < 0)
533 dso = kernel_dso;
534 }
535 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
536
537 } else {
538 show = SHOW_HV;
539 level = 'H';
540 dump_printf(" ...... dso: [hypervisor]\n");
541 }
542
543 if (show & show_mask) {
544 struct symbol *sym = NULL;
545
546 if (dso)
547 sym = dso->find_symbol(dso, ip);
548
549 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
550 fprintf(stderr,
551 "problem incrementing symbol count, skipping event\n");
552 return -1;
553 }
554 }
555 total++;
556
557 return 0;
558}
559
560static int
561process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
562{
563 struct thread *thread;
564 struct map *map = map__new(&event->mmap, NULL, 0);
565
566 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
567
568 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
569 (void *)(offset + head),
570 (void *)(long)(event->header.size),
571 event->mmap.pid,
572 (void *)(long)event->mmap.start,
573 (void *)(long)event->mmap.len,
574 (void *)(long)event->mmap.pgoff,
575 event->mmap.filename);
576
577 if (thread == NULL || map == NULL) {
578 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
579 return 0;
580 }
581
582 thread__insert_map(thread, map);
583 total_mmap++;
584
585 return 0;
586}
587
588static int
589process_comm_event(event_t *event, unsigned long offset, unsigned long head)
590{
591 struct thread *thread;
592
593 thread = threads__findnew(event->comm.pid, &threads, &last_match);
594 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
595 (void *)(offset + head),
596 (void *)(long)(event->header.size),
597 event->comm.comm, event->comm.pid);
598
599 if (thread == NULL ||
600 thread__set_comm(thread, event->comm.comm)) {
601 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
602 return -1;
603 }
604 total_comm++;
605
606 return 0;
607}
608
609static int
610process_fork_event(event_t *event, unsigned long offset, unsigned long head)
611{
612 struct thread *thread;
613 struct thread *parent;
614
615 thread = threads__findnew(event->fork.pid, &threads, &last_match);
616 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
617 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
618 (void *)(offset + head),
619 (void *)(long)(event->header.size),
620 event->fork.pid, event->fork.ppid);
621
622 /*
623 * A thread clone will have the same PID for both
624 * parent and child.
625 */
626 if (thread == parent)
627 return 0;
628
629 if (!thread || !parent || thread__fork(thread, parent)) {
630 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
631 return -1;
632 }
633 total_fork++;
634
635 return 0;
636}
637
638static int
639process_event(event_t *event, unsigned long offset, unsigned long head)
640{
641 switch (event->header.type) {
642 case PERF_RECORD_SAMPLE:
643 return process_sample_event(event, offset, head);
644
645 case PERF_RECORD_MMAP:
646 return process_mmap_event(event, offset, head);
647
648 case PERF_RECORD_COMM:
649 return process_comm_event(event, offset, head);
650
651 case PERF_RECORD_FORK:
652 return process_fork_event(event, offset, head);
653 /*
654 * We dont process them right now but they are fine:
655 */
656
657 case PERF_RECORD_THROTTLE:
658 case PERF_RECORD_UNTHROTTLE:
659 return 0;
660
661 default:
662 return -1; 150 return -1;
663 } 151 }
664 152
665 return 0; 153 return 0;
666} 154}
667 155
668static int 156static int parse_line(FILE *file, struct hist_entry *he, u64 len)
669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
670{ 157{
158 struct symbol *sym = he->sym;
671 char *line = NULL, *tmp, *tmp2; 159 char *line = NULL, *tmp, *tmp2;
672 static const char *prev_line; 160 static const char *prev_line;
673 static const char *prev_color; 161 static const char *prev_color;
674 unsigned int offset; 162 unsigned int offset;
675 size_t line_len; 163 size_t line_len;
164 u64 start;
676 s64 line_ip; 165 s64 line_ip;
677 int ret; 166 int ret;
678 char *c; 167 char *c;
@@ -709,22 +198,26 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
709 line_ip = -1; 198 line_ip = -1;
710 } 199 }
711 200
201 start = he->map->unmap_ip(he->map, sym->start);
202
712 if (line_ip != -1) { 203 if (line_ip != -1) {
713 const char *path = NULL; 204 const char *path = NULL;
714 unsigned int hits = 0; 205 unsigned int hits = 0;
715 double percent = 0.0; 206 double percent = 0.0;
716 const char *color; 207 const char *color;
717 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;
718 211
719 offset = line_ip - start; 212 offset = line_ip - start;
720 if (offset < len) 213 if (offset < len)
721 hits = sym->hist[offset]; 214 hits = h->ip[offset];
722 215
723 if (offset < len && sym_ext) { 216 if (offset < len && sym_ext) {
724 path = sym_ext[offset].path; 217 path = sym_ext[offset].path;
725 percent = sym_ext[offset].percent; 218 percent = sym_ext[offset].percent;
726 } else if (sym->hist_sum) 219 } else if (h->sum)
727 percent = 100.0 * hits / sym->hist_sum; 220 percent = 100.0 * hits / h->sum;
728 221
729 color = get_percent_color(percent); 222 color = get_percent_color(percent);
730 223
@@ -777,9 +270,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
777 rb_insert_color(&sym_ext->node, &root_sym_ext); 270 rb_insert_color(&sym_ext->node, &root_sym_ext);
778} 271}
779 272
780static void free_source_line(struct symbol *sym, int len) 273static void free_source_line(struct hist_entry *he, int len)
781{ 274{
782 struct sym_ext *sym_ext = sym->priv; 275 struct sym_priv *priv = symbol__priv(he->sym);
276 struct sym_ext *sym_ext = priv->ext;
783 int i; 277 int i;
784 278
785 if (!sym_ext) 279 if (!sym_ext)
@@ -789,26 +283,30 @@ static void free_source_line(struct symbol *sym, int len)
789 free(sym_ext[i].path); 283 free(sym_ext[i].path);
790 free(sym_ext); 284 free(sym_ext);
791 285
792 sym->priv = NULL; 286 priv->ext = NULL;
793 root_sym_ext = RB_ROOT; 287 root_sym_ext = RB_ROOT;
794} 288}
795 289
796/* Get the filename:line for the colored entries */ 290/* Get the filename:line for the colored entries */
797static void 291static void
798get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 292get_source_line(struct hist_entry *he, int len, const char *filename)
799{ 293{
294 struct symbol *sym = he->sym;
295 u64 start;
800 int i; 296 int i;
801 char cmd[PATH_MAX * 2]; 297 char cmd[PATH_MAX * 2];
802 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;
803 301
804 if (!sym->hist_sum) 302 if (!h->sum)
805 return; 303 return;
806 304
807 sym->priv = calloc(len, sizeof(struct sym_ext)); 305 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
808 if (!sym->priv) 306 if (!priv->ext)
809 return; 307 return;
810 308
811 sym_ext = sym->priv; 309 start = he->map->unmap_ip(he->map, sym->start);
812 310
813 for (i = 0; i < len; i++) { 311 for (i = 0; i < len; i++) {
814 char *path = NULL; 312 char *path = NULL;
@@ -816,7 +314,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
816 u64 offset; 314 u64 offset;
817 FILE *fp; 315 FILE *fp;
818 316
819 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 317 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
820 if (sym_ext[i].percent <= 0.5) 318 if (sym_ext[i].percent <= 0.5)
821 continue; 319 continue;
822 320
@@ -870,33 +368,34 @@ static void print_summary(const char *filename)
870 } 368 }
871} 369}
872 370
873static void annotate_sym(struct dso *dso, struct symbol *sym) 371static void annotate_sym(struct hist_entry *he)
874{ 372{
875 const char *filename = dso->name, *d_filename; 373 struct map *map = he->map;
876 u64 start, end, len; 374 struct dso *dso = map->dso;
375 struct symbol *sym = he->sym;
376 const char *filename = dso->long_name, *d_filename;
377 u64 len;
877 char command[PATH_MAX*2]; 378 char command[PATH_MAX*2];
878 FILE *file; 379 FILE *file;
879 380
880 if (!filename) 381 if (!filename)
881 return; 382 return;
882 if (sym->module) 383
883 filename = sym->module->path; 384 if (verbose)
884 else if (dso == kernel_dso) 385 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
885 filename = vmlinux_name; 386 __func__, filename, sym->name,
886 387 map->unmap_ip(map, sym->start),
887 start = sym->obj_start; 388 map->unmap_ip(map, sym->end));
888 if (!start) 389
889 start = sym->start;
890 if (full_paths) 390 if (full_paths)
891 d_filename = filename; 391 d_filename = filename;
892 else 392 else
893 d_filename = basename(filename); 393 d_filename = basename(filename);
894 394
895 end = start + sym->end - sym->start + 1;
896 len = sym->end - sym->start; 395 len = sym->end - sym->start;
897 396
898 if (print_line) { 397 if (print_line) {
899 get_source_line(sym, start, len, filename); 398 get_source_line(he, len, filename);
900 print_summary(filename); 399 print_summary(filename);
901 } 400 }
902 401
@@ -905,10 +404,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
905 printf("------------------------------------------------\n"); 404 printf("------------------------------------------------\n");
906 405
907 if (verbose >= 2) 406 if (verbose >= 2)
908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 407 printf("annotating [%p] %30s : [%p] %30s\n",
408 dso, dso->long_name, sym, sym->name);
909 409
910 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",
911 (u64)start, (u64)end, filename, filename); 411 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
412 filename, filename);
912 413
913 if (verbose >= 3) 414 if (verbose >= 3)
914 printf("doing: %s\n", command); 415 printf("doing: %s\n", command);
@@ -918,159 +419,78 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
918 return; 419 return;
919 420
920 while (!feof(file)) { 421 while (!feof(file)) {
921 if (parse_line(file, sym, start, len) < 0) 422 if (parse_line(file, he, len) < 0)
922 break; 423 break;
923 } 424 }
924 425
925 pclose(file); 426 pclose(file);
926 if (print_line) 427 if (print_line)
927 free_source_line(sym, len); 428 free_source_line(he, len);
928} 429}
929 430
930static void find_annotations(void) 431static void find_annotations(void)
931{ 432{
932 struct rb_node *nd; 433 struct rb_node *nd;
933 struct dso *dso;
934 int count = 0;
935
936 list_for_each_entry(dso, &dsos, node) {
937
938 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
939 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
940
941 if (sym->hist) {
942 annotate_sym(dso, sym);
943 count++;
944 }
945 }
946 }
947
948 if (!count)
949 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
950}
951
952static int __cmd_annotate(void)
953{
954 int ret, rc = EXIT_FAILURE;
955 unsigned long offset = 0;
956 unsigned long head = 0;
957 struct stat input_stat;
958 event_t *event;
959 uint32_t size;
960 char *buf;
961
962 register_idle_thread(&threads, &last_match);
963
964 input = open(input_name, O_RDONLY);
965 if (input < 0) {
966 perror("failed to open file");
967 exit(-1);
968 }
969
970 ret = fstat(input, &input_stat);
971 if (ret < 0) {
972 perror("failed to stat file");
973 exit(-1);
974 }
975
976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
978 exit(-1);
979 }
980
981 if (!input_stat.st_size) {
982 fprintf(stderr, "zero-sized file, nothing to do!\n");
983 exit(0);
984 }
985
986 if (load_kernel() < 0) {
987 perror("failed to load kernel symbols");
988 return EXIT_FAILURE;
989 }
990
991remap:
992 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
993 MAP_SHARED, input, offset);
994 if (buf == MAP_FAILED) {
995 perror("failed to mmap file");
996 exit(-1);
997 }
998
999more:
1000 event = (event_t *)(buf + head);
1001 434
1002 size = event->header.size; 435 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1003 if (!size) 436 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1004 size = 8; 437 struct sym_priv *priv;
1005 438
1006 if (head + event->header.size >= page_size * mmap_window) { 439 if (he->sym == NULL)
1007 unsigned long shift = page_size * (head / page_size); 440 continue;
1008 int munmap_ret;
1009
1010 munmap_ret = munmap(buf, page_size * mmap_window);
1011 assert(munmap_ret == 0);
1012
1013 offset += shift;
1014 head -= shift;
1015 goto remap;
1016 }
1017
1018 size = event->header.size;
1019
1020 dump_printf("%p [%p]: event: %d\n",
1021 (void *)(offset + head),
1022 (void *)(long)event->header.size,
1023 event->header.type);
1024
1025 if (!size || process_event(event, offset, head) < 0) {
1026
1027 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1028 (void *)(offset + head),
1029 (void *)(long)(event->header.size),
1030 event->header.type);
1031 441
1032 total_unknown++; 442 priv = symbol__priv(he->sym);
443 if (priv->hist == NULL)
444 continue;
1033 445
446 annotate_sym(he);
1034 /* 447 /*
1035 * assume we lost track of the stream, check alignment, and 448 * Since we have a hist_entry per IP for the same symbol, free
1036 * increment a single u64 in the hope to catch on again 'soon'. 449 * he->sym->hist to signal we already processed this symbol.
1037 */ 450 */
1038 451 free(priv->hist);
1039 if (unlikely(head & 7)) 452 priv->hist = NULL;
1040 head &= ~7ULL;
1041
1042 size = 8;
1043 } 453 }
454}
1044 455
1045 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};
1046 462
1047 if (offset + head < (unsigned long)input_stat.st_size) 463static int __cmd_annotate(void)
1048 goto more; 464{
465 struct perf_header *header;
466 struct thread *idle;
467 int ret;
1049 468
1050 rc = EXIT_SUCCESS; 469 idle = register_idle_thread();
1051 close(input); 470 register_perf_file_handler(&file_handler);
1052 471
1053 dump_printf(" IP events: %10ld\n", total); 472 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
1054 dump_printf(" mmap events: %10ld\n", total_mmap); 473 &event__cwdlen, &event__cwd);
1055 dump_printf(" comm events: %10ld\n", total_comm); 474 if (ret)
1056 dump_printf(" fork events: %10ld\n", total_fork); 475 return ret;
1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1058 476
1059 if (dump_trace) 477 if (dump_trace) {
478 event__print_totals();
1060 return 0; 479 return 0;
480 }
1061 481
1062 if (verbose >= 3) 482 if (verbose > 3)
1063 threads__fprintf(stdout, &threads); 483 threads__fprintf(stdout);
1064 484
1065 if (verbose >= 2) 485 if (verbose > 2)
1066 dsos__fprintf(stdout); 486 dsos__fprintf(stdout);
1067 487
1068 collapse__resort(); 488 collapse__resort();
1069 output__resort(); 489 output__resort(event__total[0]);
1070 490
1071 find_annotations(); 491 find_annotations();
1072 492
1073 return rc; 493 return ret;
1074} 494}
1075 495
1076static const char * const annotate_usage[] = { 496static const char * const annotate_usage[] = {
@@ -1088,8 +508,9 @@ static const struct option options[] = {
1088 "be more verbose (show symbol address, etc)"), 508 "be more verbose (show symbol address, etc)"),
1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 509 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1090 "dump raw trace in ASCII"), 510 "dump raw trace in ASCII"),
1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 511 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1092 OPT_BOOLEAN('m', "modules", &modules, 512 "file", "vmlinux pathname"),
513 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1093 "load module symbols - WARNING: use only with -k and LIVE kernel"), 514 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1094 OPT_BOOLEAN('l', "print-line", &print_line, 515 OPT_BOOLEAN('l', "print-line", &print_line,
1095 "print matching source lines (may be slow)"), 516 "print matching source lines (may be slow)"),
@@ -1115,9 +536,8 @@ static void setup_sorting(void)
1115 536
1116int cmd_annotate(int argc, const char **argv, const char *prefix __used) 537int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1117{ 538{
1118 symbol__init(); 539 if (symbol__init(&symbol_conf) < 0)
1119 540 return -1;
1120 page_size = getpagesize();
1121 541
1122 argc = parse_options(argc, argv, options, annotate_usage, 0); 542 argc = parse_options(argc, argv, options, annotate_usage, 0);
1123 543
@@ -1134,10 +554,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1134 sym_hist_filter = argv[0]; 554 sym_hist_filter = argv[0];
1135 } 555 }
1136 556
1137 if (!sym_hist_filter)
1138 usage_with_options(annotate_usage, options);
1139
1140 setup_pager(); 557 setup_pager();
1141 558
559 if (field_sep && *field_sep == '.') {
560 fputs("'.' is the only non valid --field-separator argument\n",
561 stderr);
562 exit(129);
563 }
564
1142 return __cmd_annotate(); 565 return __cmd_annotate();
1143} 566}
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..dcb6143a0002
--- /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 buildid-list [<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..5f209514f657
--- /dev/null
+++ b/tools/perf/builtin-kmem.c
@@ -0,0 +1,796 @@
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
60#define PATH_SYS_NODE "/sys/devices/system/node"
61
62static void init_cpunode_map(void)
63{
64 FILE *fp;
65 int i;
66
67 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
68 if (!fp) {
69 max_cpu_num = 4096;
70 return;
71 }
72
73 if (fscanf(fp, "%d", &max_cpu_num) < 1)
74 die("Failed to read 'kernel_max' from sysfs");
75 max_cpu_num++;
76
77 cpunode_map = calloc(max_cpu_num, sizeof(int));
78 if (!cpunode_map)
79 die("calloc");
80 for (i = 0; i < max_cpu_num; i++)
81 cpunode_map[i] = -1;
82 fclose(fp);
83}
84
85static void setup_cpunode_map(void)
86{
87 struct dirent *dent1, *dent2;
88 DIR *dir1, *dir2;
89 unsigned int cpu, mem;
90 char buf[PATH_MAX];
91
92 init_cpunode_map();
93
94 dir1 = opendir(PATH_SYS_NODE);
95 if (!dir1)
96 return;
97
98 while (true) {
99 dent1 = readdir(dir1);
100 if (!dent1)
101 break;
102
103 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
104 continue;
105
106 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
107 dir2 = opendir(buf);
108 if (!dir2)
109 continue;
110 while (true) {
111 dent2 = readdir(dir2);
112 if (!dent2)
113 break;
114 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
115 continue;
116 cpunode_map[cpu] = mem;
117 }
118 }
119}
120
121static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
122 int bytes_req, int bytes_alloc, int cpu)
123{
124 struct rb_node **node = &root_alloc_stat.rb_node;
125 struct rb_node *parent = NULL;
126 struct alloc_stat *data = NULL;
127
128 while (*node) {
129 parent = *node;
130 data = rb_entry(*node, struct alloc_stat, node);
131
132 if (ptr > data->ptr)
133 node = &(*node)->rb_right;
134 else if (ptr < data->ptr)
135 node = &(*node)->rb_left;
136 else
137 break;
138 }
139
140 if (data && data->ptr == ptr) {
141 data->hit++;
142 data->bytes_req += bytes_req;
143 data->bytes_alloc += bytes_req;
144 } else {
145 data = malloc(sizeof(*data));
146 if (!data)
147 die("malloc");
148 data->ptr = ptr;
149 data->pingpong = 0;
150 data->hit = 1;
151 data->bytes_req = bytes_req;
152 data->bytes_alloc = bytes_alloc;
153
154 rb_link_node(&data->node, parent, node);
155 rb_insert_color(&data->node, &root_alloc_stat);
156 }
157 data->call_site = call_site;
158 data->alloc_cpu = cpu;
159}
160
161static void insert_caller_stat(unsigned long call_site,
162 int bytes_req, int bytes_alloc)
163{
164 struct rb_node **node = &root_caller_stat.rb_node;
165 struct rb_node *parent = NULL;
166 struct alloc_stat *data = NULL;
167
168 while (*node) {
169 parent = *node;
170 data = rb_entry(*node, struct alloc_stat, node);
171
172 if (call_site > data->call_site)
173 node = &(*node)->rb_right;
174 else if (call_site < data->call_site)
175 node = &(*node)->rb_left;
176 else
177 break;
178 }
179
180 if (data && data->call_site == call_site) {
181 data->hit++;
182 data->bytes_req += bytes_req;
183 data->bytes_alloc += bytes_req;
184 } else {
185 data = malloc(sizeof(*data));
186 if (!data)
187 die("malloc");
188 data->call_site = call_site;
189 data->pingpong = 0;
190 data->hit = 1;
191 data->bytes_req = bytes_req;
192 data->bytes_alloc = bytes_alloc;
193
194 rb_link_node(&data->node, parent, node);
195 rb_insert_color(&data->node, &root_caller_stat);
196 }
197}
198
199static void process_alloc_event(void *data,
200 struct event *event,
201 int cpu,
202 u64 timestamp __used,
203 struct thread *thread __used,
204 int node)
205{
206 unsigned long call_site;
207 unsigned long ptr;
208 int bytes_req;
209 int bytes_alloc;
210 int node1, node2;
211
212 ptr = raw_field_value(event, "ptr", data);
213 call_site = raw_field_value(event, "call_site", data);
214 bytes_req = raw_field_value(event, "bytes_req", data);
215 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
216
217 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
218 insert_caller_stat(call_site, bytes_req, bytes_alloc);
219
220 total_requested += bytes_req;
221 total_allocated += bytes_alloc;
222
223 if (node) {
224 node1 = cpunode_map[cpu];
225 node2 = raw_field_value(event, "node", data);
226 if (node1 != node2)
227 nr_cross_allocs++;
228 }
229 nr_allocs++;
230}
231
232static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
233static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
234
235static struct alloc_stat *search_alloc_stat(unsigned long ptr,
236 unsigned long call_site,
237 struct rb_root *root,
238 sort_fn_t sort_fn)
239{
240 struct rb_node *node = root->rb_node;
241 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
242
243 while (node) {
244 struct alloc_stat *data;
245 int cmp;
246
247 data = rb_entry(node, struct alloc_stat, node);
248
249 cmp = sort_fn(&key, data);
250 if (cmp < 0)
251 node = node->rb_left;
252 else if (cmp > 0)
253 node = node->rb_right;
254 else
255 return data;
256 }
257 return NULL;
258}
259
260static void process_free_event(void *data,
261 struct event *event,
262 int cpu,
263 u64 timestamp __used,
264 struct thread *thread __used)
265{
266 unsigned long ptr;
267 struct alloc_stat *s_alloc, *s_caller;
268
269 ptr = raw_field_value(event, "ptr", data);
270
271 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
272 if (!s_alloc)
273 return;
274
275 if (cpu != s_alloc->alloc_cpu) {
276 s_alloc->pingpong++;
277
278 s_caller = search_alloc_stat(0, s_alloc->call_site,
279 &root_caller_stat, callsite_cmp);
280 assert(s_caller);
281 s_caller->pingpong++;
282 }
283 s_alloc->alloc_cpu = -1;
284}
285
286static void
287process_raw_event(event_t *raw_event __used, void *data,
288 int cpu, u64 timestamp, struct thread *thread)
289{
290 struct event *event;
291 int type;
292
293 type = trace_parse_common_type(data);
294 event = trace_find_event(type);
295
296 if (!strcmp(event->name, "kmalloc") ||
297 !strcmp(event->name, "kmem_cache_alloc")) {
298 process_alloc_event(data, event, cpu, timestamp, thread, 0);
299 return;
300 }
301
302 if (!strcmp(event->name, "kmalloc_node") ||
303 !strcmp(event->name, "kmem_cache_alloc_node")) {
304 process_alloc_event(data, event, cpu, timestamp, thread, 1);
305 return;
306 }
307
308 if (!strcmp(event->name, "kfree") ||
309 !strcmp(event->name, "kmem_cache_free")) {
310 process_free_event(data, event, cpu, timestamp, thread);
311 return;
312 }
313}
314
315static int process_sample_event(event_t *event)
316{
317 struct sample_data data;
318 struct thread *thread;
319
320 memset(&data, 0, sizeof(data));
321 data.time = -1;
322 data.cpu = -1;
323 data.period = 1;
324
325 event__parse_sample(event, sample_type, &data);
326
327 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
328 event->header.misc,
329 data.pid, data.tid,
330 (void *)(long)data.ip,
331 (long long)data.period);
332
333 thread = threads__findnew(event->ip.pid);
334 if (thread == NULL) {
335 pr_debug("problem processing %d event, skipping it.\n",
336 event->header.type);
337 return -1;
338 }
339
340 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
341
342 process_raw_event(event, data.raw_data, data.cpu,
343 data.time, thread);
344
345 return 0;
346}
347
348static int sample_type_check(u64 type)
349{
350 sample_type = type;
351
352 if (!(sample_type & PERF_SAMPLE_RAW)) {
353 fprintf(stderr,
354 "No trace sample to read. Did you call perf record "
355 "without -R?");
356 return -1;
357 }
358
359 return 0;
360}
361
362static struct perf_file_handler file_handler = {
363 .process_sample_event = process_sample_event,
364 .process_comm_event = event__process_comm,
365 .sample_type_check = sample_type_check,
366};
367
368static int read_events(void)
369{
370 register_idle_thread();
371 register_perf_file_handler(&file_handler);
372
373 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
374 &event__cwdlen, &event__cwd);
375}
376
377static double fragmentation(unsigned long n_req, unsigned long n_alloc)
378{
379 if (n_alloc == 0)
380 return 0.0;
381 else
382 return 100.0 - (100.0 * n_req / n_alloc);
383}
384
385static void __print_result(struct rb_root *root, int n_lines, int is_caller)
386{
387 struct rb_node *next;
388
389 printf("%.102s\n", graph_dotted_line);
390 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
391 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
392 printf("%.102s\n", graph_dotted_line);
393
394 next = rb_first(root);
395
396 while (next && n_lines--) {
397 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
398 node);
399 struct symbol *sym = NULL;
400 char buf[BUFSIZ];
401 u64 addr;
402
403 if (is_caller) {
404 addr = data->call_site;
405 if (!raw_ip)
406 sym = thread__find_function(kthread, addr, NULL);
407 } else
408 addr = data->ptr;
409
410 if (sym != NULL)
411 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
412 addr - sym->start);
413 else
414 snprintf(buf, sizeof(buf), "%#Lx", addr);
415 printf(" %-34s |", buf);
416
417 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
418 (unsigned long long)data->bytes_alloc,
419 (unsigned long)data->bytes_alloc / data->hit,
420 (unsigned long long)data->bytes_req,
421 (unsigned long)data->bytes_req / data->hit,
422 (unsigned long)data->hit,
423 (unsigned long)data->pingpong,
424 fragmentation(data->bytes_req, data->bytes_alloc));
425
426 next = rb_next(next);
427 }
428
429 if (n_lines == -1)
430 printf(" ... | ... | ... | ... | ... | ... \n");
431
432 printf("%.102s\n", graph_dotted_line);
433}
434
435static void print_summary(void)
436{
437 printf("\nSUMMARY\n=======\n");
438 printf("Total bytes requested: %lu\n", total_requested);
439 printf("Total bytes allocated: %lu\n", total_allocated);
440 printf("Total bytes wasted on internal fragmentation: %lu\n",
441 total_allocated - total_requested);
442 printf("Internal fragmentation: %f%%\n",
443 fragmentation(total_requested, total_allocated));
444 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
445}
446
447static void print_result(void)
448{
449 if (caller_flag)
450 __print_result(&root_caller_sorted, caller_lines, 1);
451 if (alloc_flag)
452 __print_result(&root_alloc_sorted, alloc_lines, 0);
453 print_summary();
454}
455
456struct sort_dimension {
457 const char name[20];
458 sort_fn_t cmp;
459 struct list_head list;
460};
461
462static LIST_HEAD(caller_sort);
463static LIST_HEAD(alloc_sort);
464
465static void sort_insert(struct rb_root *root, struct alloc_stat *data,
466 struct list_head *sort_list)
467{
468 struct rb_node **new = &(root->rb_node);
469 struct rb_node *parent = NULL;
470 struct sort_dimension *sort;
471
472 while (*new) {
473 struct alloc_stat *this;
474 int cmp = 0;
475
476 this = rb_entry(*new, struct alloc_stat, node);
477 parent = *new;
478
479 list_for_each_entry(sort, sort_list, list) {
480 cmp = sort->cmp(data, this);
481 if (cmp)
482 break;
483 }
484
485 if (cmp > 0)
486 new = &((*new)->rb_left);
487 else
488 new = &((*new)->rb_right);
489 }
490
491 rb_link_node(&data->node, parent, new);
492 rb_insert_color(&data->node, root);
493}
494
495static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
496 struct list_head *sort_list)
497{
498 struct rb_node *node;
499 struct alloc_stat *data;
500
501 for (;;) {
502 node = rb_first(root);
503 if (!node)
504 break;
505
506 rb_erase(node, root);
507 data = rb_entry(node, struct alloc_stat, node);
508 sort_insert(root_sorted, data, sort_list);
509 }
510}
511
512static void sort_result(void)
513{
514 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
515 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
516}
517
518static int __cmd_kmem(void)
519{
520 setup_pager();
521 read_events();
522 sort_result();
523 print_result();
524
525 return 0;
526}
527
528static const char * const kmem_usage[] = {
529 "perf kmem [<options>] {record|stat}",
530 NULL
531};
532
533static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
534{
535 if (l->ptr < r->ptr)
536 return -1;
537 else if (l->ptr > r->ptr)
538 return 1;
539 return 0;
540}
541
542static struct sort_dimension ptr_sort_dimension = {
543 .name = "ptr",
544 .cmp = ptr_cmp,
545};
546
547static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
548{
549 if (l->call_site < r->call_site)
550 return -1;
551 else if (l->call_site > r->call_site)
552 return 1;
553 return 0;
554}
555
556static struct sort_dimension callsite_sort_dimension = {
557 .name = "callsite",
558 .cmp = callsite_cmp,
559};
560
561static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
562{
563 if (l->hit < r->hit)
564 return -1;
565 else if (l->hit > r->hit)
566 return 1;
567 return 0;
568}
569
570static struct sort_dimension hit_sort_dimension = {
571 .name = "hit",
572 .cmp = hit_cmp,
573};
574
575static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
576{
577 if (l->bytes_alloc < r->bytes_alloc)
578 return -1;
579 else if (l->bytes_alloc > r->bytes_alloc)
580 return 1;
581 return 0;
582}
583
584static struct sort_dimension bytes_sort_dimension = {
585 .name = "bytes",
586 .cmp = bytes_cmp,
587};
588
589static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
590{
591 double x, y;
592
593 x = fragmentation(l->bytes_req, l->bytes_alloc);
594 y = fragmentation(r->bytes_req, r->bytes_alloc);
595
596 if (x < y)
597 return -1;
598 else if (x > y)
599 return 1;
600 return 0;
601}
602
603static struct sort_dimension frag_sort_dimension = {
604 .name = "frag",
605 .cmp = frag_cmp,
606};
607
608static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
609{
610 if (l->pingpong < r->pingpong)
611 return -1;
612 else if (l->pingpong > r->pingpong)
613 return 1;
614 return 0;
615}
616
617static struct sort_dimension pingpong_sort_dimension = {
618 .name = "pingpong",
619 .cmp = pingpong_cmp,
620};
621
622static struct sort_dimension *avail_sorts[] = {
623 &ptr_sort_dimension,
624 &callsite_sort_dimension,
625 &hit_sort_dimension,
626 &bytes_sort_dimension,
627 &frag_sort_dimension,
628 &pingpong_sort_dimension,
629};
630
631#define NUM_AVAIL_SORTS \
632 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
633
634static int sort_dimension__add(const char *tok, struct list_head *list)
635{
636 struct sort_dimension *sort;
637 int i;
638
639 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
640 if (!strcmp(avail_sorts[i]->name, tok)) {
641 sort = malloc(sizeof(*sort));
642 if (!sort)
643 die("malloc");
644 memcpy(sort, avail_sorts[i], sizeof(*sort));
645 list_add_tail(&sort->list, list);
646 return 0;
647 }
648 }
649
650 return -1;
651}
652
653static int setup_sorting(struct list_head *sort_list, const char *arg)
654{
655 char *tok;
656 char *str = strdup(arg);
657
658 if (!str)
659 die("strdup");
660
661 while (true) {
662 tok = strsep(&str, ",");
663 if (!tok)
664 break;
665 if (sort_dimension__add(tok, sort_list) < 0) {
666 error("Unknown --sort key: '%s'", tok);
667 return -1;
668 }
669 }
670
671 free(str);
672 return 0;
673}
674
675static int parse_sort_opt(const struct option *opt __used,
676 const char *arg, int unset __used)
677{
678 if (!arg)
679 return -1;
680
681 if (caller_flag > alloc_flag)
682 return setup_sorting(&caller_sort, arg);
683 else
684 return setup_sorting(&alloc_sort, arg);
685
686 return 0;
687}
688
689static int parse_caller_opt(const struct option *opt __used,
690 const char *arg __used, int unset __used)
691{
692 caller_flag = (alloc_flag + 1);
693 return 0;
694}
695
696static int parse_alloc_opt(const struct option *opt __used,
697 const char *arg __used, int unset __used)
698{
699 alloc_flag = (caller_flag + 1);
700 return 0;
701}
702
703static int parse_line_opt(const struct option *opt __used,
704 const char *arg, int unset __used)
705{
706 int lines;
707
708 if (!arg)
709 return -1;
710
711 lines = strtoul(arg, NULL, 10);
712
713 if (caller_flag > alloc_flag)
714 caller_lines = lines;
715 else
716 alloc_lines = lines;
717
718 return 0;
719}
720
721static const struct option kmem_options[] = {
722 OPT_STRING('i', "input", &input_name, "file",
723 "input file name"),
724 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
725 "show per-callsite statistics",
726 parse_caller_opt),
727 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
728 "show per-allocation statistics",
729 parse_alloc_opt),
730 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
731 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
732 parse_sort_opt),
733 OPT_CALLBACK('l', "line", NULL, "num",
734 "show n lines",
735 parse_line_opt),
736 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
737 OPT_END()
738};
739
740static const char *record_args[] = {
741 "record",
742 "-a",
743 "-R",
744 "-M",
745 "-f",
746 "-c", "1",
747 "-e", "kmem:kmalloc",
748 "-e", "kmem:kmalloc_node",
749 "-e", "kmem:kfree",
750 "-e", "kmem:kmem_cache_alloc",
751 "-e", "kmem:kmem_cache_alloc_node",
752 "-e", "kmem:kmem_cache_free",
753};
754
755static int __cmd_record(int argc, const char **argv)
756{
757 unsigned int rec_argc, i, j;
758 const char **rec_argv;
759
760 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
761 rec_argv = calloc(rec_argc + 1, sizeof(char *));
762
763 for (i = 0; i < ARRAY_SIZE(record_args); i++)
764 rec_argv[i] = strdup(record_args[i]);
765
766 for (j = 1; j < (unsigned int)argc; j++, i++)
767 rec_argv[i] = argv[j];
768
769 return cmd_record(i, rec_argv, NULL);
770}
771
772int cmd_kmem(int argc, const char **argv, const char *prefix __used)
773{
774 symbol__init(0);
775
776 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
777
778 if (!argc)
779 usage_with_options(kmem_usage, kmem_options);
780
781 if (!strncmp(argv[0], "rec", 3)) {
782 return __cmd_record(argc, argv);
783 } else if (!strcmp(argv[0], "stat")) {
784 setup_cpunode_map();
785
786 if (list_empty(&caller_sort))
787 setup_sorting(&caller_sort, default_sort_order);
788 if (list_empty(&alloc_sort))
789 setup_sorting(&alloc_sort, default_sort_order);
790
791 return __cmd_kmem();
792 }
793
794 return 0;
795}
796
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644
index 000000000000..5a47c1e11f77
--- /dev/null
+++ b/tools/perf/builtin-probe.c
@@ -0,0 +1,290 @@
1/*
2 * builtin-probe.c
3 *
4 * Builtin probe command: Set up probe events by C expression
5 *
6 * Written by Masami Hiramatsu <mhiramat@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 */
23#define _GNU_SOURCE
24#include <sys/utsname.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#undef _GNU_SOURCE
35#include "perf.h"
36#include "builtin.h"
37#include "util/util.h"
38#include "util/strlist.h"
39#include "util/event.h"
40#include "util/debug.h"
41#include "util/parse-options.h"
42#include "util/parse-events.h" /* For debugfs_path */
43#include "util/probe-finder.h"
44#include "util/probe-event.h"
45
46/* Default vmlinux search paths */
47#define NR_SEARCH_PATH 4
48const char *default_search_path[NR_SEARCH_PATH] = {
49"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
50"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
51"/boot/vmlinux-debug-%s", /* Ubuntu */
52"./vmlinux", /* CWD */
53};
54
55#define MAX_PATH_LEN 256
56#define MAX_PROBES 128
57
58/* Session management structure */
59static struct {
60 char *vmlinux;
61 char *release;
62 int need_dwarf;
63 int nr_probe;
64 struct probe_point probes[MAX_PROBES];
65 struct strlist *dellist;
66} session;
67
68static bool listing;
69
70/* Parse an event definition. Note that any error must die. */
71static void parse_probe_event(const char *str)
72{
73 struct probe_point *pp = &session.probes[session.nr_probe];
74
75 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
76 if (++session.nr_probe == MAX_PROBES)
77 die("Too many probes (> %d) are specified.", MAX_PROBES);
78
79 /* Parse perf-probe event into probe_point */
80 session.need_dwarf = parse_perf_probe_event(str, pp);
81
82 pr_debug("%d arguments\n", pp->nr_args);
83}
84
85static void parse_probe_event_argv(int argc, const char **argv)
86{
87 int i, len;
88 char *buf;
89
90 /* Bind up rest arguments */
91 len = 0;
92 for (i = 0; i < argc; i++)
93 len += strlen(argv[i]) + 1;
94 buf = zalloc(len + 1);
95 if (!buf)
96 die("Failed to allocate memory for binding arguments.");
97 len = 0;
98 for (i = 0; i < argc; i++)
99 len += sprintf(&buf[len], "%s ", argv[i]);
100 parse_probe_event(buf);
101 free(buf);
102}
103
104static int opt_add_probe_event(const struct option *opt __used,
105 const char *str, int unset __used)
106{
107 if (str)
108 parse_probe_event(str);
109 return 0;
110}
111
112static int opt_del_probe_event(const struct option *opt __used,
113 const char *str, int unset __used)
114{
115 if (str) {
116 if (!session.dellist)
117 session.dellist = strlist__new(true, NULL);
118 strlist__add(session.dellist, str);
119 }
120 return 0;
121}
122
123#ifndef NO_LIBDWARF
124static int open_default_vmlinux(void)
125{
126 struct utsname uts;
127 char fname[MAX_PATH_LEN];
128 int fd, ret, i;
129
130 ret = uname(&uts);
131 if (ret) {
132 pr_debug("uname() failed.\n");
133 return -errno;
134 }
135 session.release = uts.release;
136 for (i = 0; i < NR_SEARCH_PATH; i++) {
137 ret = snprintf(fname, MAX_PATH_LEN,
138 default_search_path[i], session.release);
139 if (ret >= MAX_PATH_LEN || ret < 0) {
140 pr_debug("Filename(%d,%s) is too long.\n", i,
141 uts.release);
142 errno = E2BIG;
143 return -E2BIG;
144 }
145 pr_debug("try to open %s\n", fname);
146 fd = open(fname, O_RDONLY);
147 if (fd >= 0)
148 break;
149 }
150 return fd;
151}
152#endif
153
154static const char * const probe_usage[] = {
155 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
158 "perf probe --list",
159 NULL
160};
161
162static const struct option options[] = {
163 OPT_BOOLEAN('v', "verbose", &verbose,
164 "be more verbose (show parsed arguments, etc)"),
165#ifndef NO_LIBDWARF
166 OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
167 "vmlinux/module pathname"),
168#endif
169 OPT_BOOLEAN('l', "list", &listing, "list up current probe events"),
170 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
171 opt_del_probe_event),
172 OPT_CALLBACK('a', "add", NULL,
173#ifdef NO_LIBDWARF
174 "FUNC[+OFFS|%return] [ARG ...]",
175#else
176 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
177#endif
178 "probe point definition, where\n"
179 "\t\tGRP:\tGroup name (optional)\n"
180 "\t\tNAME:\tEvent name\n"
181 "\t\tFUNC:\tFunction name\n"
182 "\t\tOFFS:\tOffset from function entry (in byte)\n"
183 "\t\t%return:\tPut the probe at function return\n"
184#ifdef NO_LIBDWARF
185 "\t\tARG:\tProbe argument (only \n"
186#else
187 "\t\tSRC:\tSource code path\n"
188 "\t\tRLN:\tRelative line number from function entry.\n"
189 "\t\tALN:\tAbsolute line number in file.\n"
190 "\t\tARG:\tProbe argument (local variable name or\n"
191#endif
192 "\t\t\tkprobe-tracer argument format.)\n",
193 opt_add_probe_event),
194 OPT_END()
195};
196
197int cmd_probe(int argc, const char **argv, const char *prefix __used)
198{
199 int i, ret;
200#ifndef NO_LIBDWARF
201 int fd;
202#endif
203 struct probe_point *pp;
204
205 argc = parse_options(argc, argv, options, probe_usage,
206 PARSE_OPT_STOP_AT_NON_OPTION);
207 if (argc > 0)
208 parse_probe_event_argv(argc, argv);
209
210 if ((session.nr_probe == 0 && !session.dellist && !listing))
211 usage_with_options(probe_usage, options);
212
213 if (listing) {
214 if (session.nr_probe != 0 || session.dellist) {
215 pr_warning(" Error: Don't use --list with"
216 " --add/--del.\n");
217 usage_with_options(probe_usage, options);
218 }
219 show_perf_probe_events();
220 return 0;
221 }
222
223 if (session.dellist) {
224 del_trace_kprobe_events(session.dellist);
225 strlist__delete(session.dellist);
226 if (session.nr_probe == 0)
227 return 0;
228 }
229
230 if (session.need_dwarf)
231#ifdef NO_LIBDWARF
232 die("Debuginfo-analysis is not supported");
233#else /* !NO_LIBDWARF */
234 pr_debug("Some probes require debuginfo.\n");
235
236 if (session.vmlinux) {
237 pr_debug("Try to open %s.", session.vmlinux);
238 fd = open(session.vmlinux, O_RDONLY);
239 } else
240 fd = open_default_vmlinux();
241 if (fd < 0) {
242 if (session.need_dwarf)
243 die("Could not open debuginfo file.");
244
245 pr_debug("Could not open vmlinux/module file."
246 " Try to use symbols.\n");
247 goto end_dwarf;
248 }
249
250 /* Searching probe points */
251 for (i = 0; i < session.nr_probe; i++) {
252 pp = &session.probes[i];
253 if (pp->found)
254 continue;
255
256 lseek(fd, SEEK_SET, 0);
257 ret = find_probepoint(fd, pp);
258 if (ret < 0) {
259 if (session.need_dwarf)
260 die("Could not analyze debuginfo.");
261
262 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n");
263 break;
264 }
265 if (ret == 0) /* No error but failed to find probe point. */
266 die("No probe point found.");
267 }
268 close(fd);
269
270end_dwarf:
271#endif /* !NO_LIBDWARF */
272
273 /* Synthesize probes without dwarf */
274 for (i = 0; i < session.nr_probe; i++) {
275 pp = &session.probes[i];
276 if (pp->found) /* This probe is already found. */
277 continue;
278
279 ret = synthesize_trace_kprobe_event(pp);
280 if (ret == -E2BIG)
281 die("probe point definition becomes too long.");
282 else if (ret < 0)
283 die("Failed to synthesize a probe point.");
284 }
285
286 /* Settng up probe points */
287 add_trace_kprobe_events(session.probes, session.nr_probe);
288 return 0;
289}
290
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a4be453fc8a9..0e519c667e3a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,55 +17,52 @@
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/trace-event.h" 20#include "util/symbol.h"
21 21
22#include <unistd.h> 22#include <unistd.h>
23#include <sched.h> 23#include <sched.h>
24 24
25#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
26#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
27
28static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 25static int fd[MAX_NR_CPUS][MAX_COUNTERS];
29 26
30static long default_interval = 100000; 27static long default_interval = 0;
31 28
32static int nr_cpus = 0; 29static int nr_cpus = 0;
33static unsigned int page_size; 30static unsigned int page_size;
34static unsigned int mmap_pages = 128; 31static unsigned int mmap_pages = 128;
35static int freq = 0; 32static int freq = 1000;
36static int output; 33static int output;
37static const char *output_name = "perf.data"; 34static const char *output_name = "perf.data";
38static int group = 0; 35static int group = 0;
39static unsigned int realtime_prio = 0; 36static unsigned int realtime_prio = 0;
40static int raw_samples = 0; 37static int raw_samples = 0;
41static int system_wide = 0; 38static int system_wide = 0;
42static int profile_cpu = -1; 39static int profile_cpu = -1;
43static pid_t target_pid = -1; 40static pid_t target_pid = -1;
44static pid_t child_pid = -1; 41static pid_t child_pid = -1;
45static int inherit = 1; 42static int inherit = 1;
46static int force = 0; 43static int force = 0;
47static int append_file = 0; 44static int append_file = 0;
48static int call_graph = 0; 45static int call_graph = 0;
49static int inherit_stat = 0; 46static int inherit_stat = 0;
50static int no_samples = 0; 47static int no_samples = 0;
51static int sample_address = 0; 48static int sample_address = 0;
52static int multiplex = 0; 49static int multiplex = 0;
53static int multiplex_fd = -1; 50static int multiplex_fd = -1;
54 51
55static long samples; 52static long samples = 0;
56static struct timeval last_read; 53static struct timeval last_read;
57static struct timeval this_read; 54static struct timeval this_read;
58 55
59static u64 bytes_written; 56static u64 bytes_written = 0;
60 57
61static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 58static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
62 59
63static int nr_poll; 60static int nr_poll = 0;
64static int nr_cpu; 61static int nr_cpu = 0;
65 62
66static int file_new = 1; 63static int file_new = 1;
67 64
68struct perf_header *header; 65struct perf_header *header = NULL;
69 66
70struct mmap_data { 67struct mmap_data {
71 int counter; 68 int counter;
@@ -113,6 +110,24 @@ static void write_output(void *buf, size_t size)
113 } 110 }
114} 111}
115 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
116static void mmap_read(struct mmap_data *md) 131static void mmap_read(struct mmap_data *md)
117{ 132{
118 unsigned int head = mmap_read_head(md); 133 unsigned int head = mmap_read_head(md);
@@ -161,14 +176,14 @@ static void mmap_read(struct mmap_data *md)
161 size = md->mask + 1 - (old & md->mask); 176 size = md->mask + 1 - (old & md->mask);
162 old += size; 177 old += size;
163 178
164 write_output(buf, size); 179 write_event(buf, size);
165 } 180 }
166 181
167 buf = &data[old & md->mask]; 182 buf = &data[old & md->mask];
168 size = head - old; 183 size = head - old;
169 old += size; 184 old += size;
170 185
171 write_output(buf, size); 186 write_event(buf, size);
172 187
173 md->prev = old; 188 md->prev = old;
174 mmap_write_tail(md, old); 189 mmap_write_tail(md, old);
@@ -195,168 +210,6 @@ static void sig_atexit(void)
195 kill(getpid(), signr); 210 kill(getpid(), signr);
196} 211}
197 212
198static pid_t pid_synthesize_comm_event(pid_t pid, int full)
199{
200 struct comm_event comm_ev;
201 char filename[PATH_MAX];
202 char bf[BUFSIZ];
203 FILE *fp;
204 size_t size = 0;
205 DIR *tasks;
206 struct dirent dirent, *next;
207 pid_t tgid = 0;
208
209 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
210
211 fp = fopen(filename, "r");
212 if (fp == NULL) {
213 /*
214 * We raced with a task exiting - just return:
215 */
216 if (verbose)
217 fprintf(stderr, "couldn't open %s\n", filename);
218 return 0;
219 }
220
221 memset(&comm_ev, 0, sizeof(comm_ev));
222 while (!comm_ev.comm[0] || !comm_ev.pid) {
223 if (fgets(bf, sizeof(bf), fp) == NULL)
224 goto out_failure;
225
226 if (memcmp(bf, "Name:", 5) == 0) {
227 char *name = bf + 5;
228 while (*name && isspace(*name))
229 ++name;
230 size = strlen(name) - 1;
231 memcpy(comm_ev.comm, name, size++);
232 } else if (memcmp(bf, "Tgid:", 5) == 0) {
233 char *tgids = bf + 5;
234 while (*tgids && isspace(*tgids))
235 ++tgids;
236 tgid = comm_ev.pid = atoi(tgids);
237 }
238 }
239
240 comm_ev.header.type = PERF_RECORD_COMM;
241 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
243
244 if (!full) {
245 comm_ev.tid = pid;
246
247 write_output(&comm_ev, comm_ev.header.size);
248 goto out_fclose;
249 }
250
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
252
253 tasks = opendir(filename);
254 while (!readdir_r(tasks, &dirent, &next) && next) {
255 char *end;
256 pid = strtol(dirent.d_name, &end, 10);
257 if (*end)
258 continue;
259
260 comm_ev.tid = pid;
261
262 write_output(&comm_ev, comm_ev.header.size);
263 }
264 closedir(tasks);
265
266out_fclose:
267 fclose(fp);
268 return tgid;
269
270out_failure:
271 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
272 filename);
273 exit(EXIT_FAILURE);
274}
275
276static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
277{
278 char filename[PATH_MAX];
279 FILE *fp;
280
281 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
282
283 fp = fopen(filename, "r");
284 if (fp == NULL) {
285 /*
286 * We raced with a task exiting - just return:
287 */
288 if (verbose)
289 fprintf(stderr, "couldn't open %s\n", filename);
290 return;
291 }
292 while (1) {
293 char bf[BUFSIZ], *pbf = bf;
294 struct mmap_event mmap_ev = {
295 .header = { .type = PERF_RECORD_MMAP },
296 };
297 int n;
298 size_t size;
299 if (fgets(bf, sizeof(bf), fp) == NULL)
300 break;
301
302 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
303 n = hex2u64(pbf, &mmap_ev.start);
304 if (n < 0)
305 continue;
306 pbf += n + 1;
307 n = hex2u64(pbf, &mmap_ev.len);
308 if (n < 0)
309 continue;
310 pbf += n + 3;
311 if (*pbf == 'x') { /* vm_exec */
312 char *execname = strchr(bf, '/');
313
314 /* Catch VDSO */
315 if (execname == NULL)
316 execname = strstr(bf, "[vdso]");
317
318 if (execname == NULL)
319 continue;
320
321 size = strlen(execname);
322 execname[size - 1] = '\0'; /* Remove \n */
323 memcpy(mmap_ev.filename, execname, size);
324 size = ALIGN(size, sizeof(u64));
325 mmap_ev.len -= mmap_ev.start;
326 mmap_ev.header.size = (sizeof(mmap_ev) -
327 (sizeof(mmap_ev.filename) - size));
328 mmap_ev.pid = tgid;
329 mmap_ev.tid = pid;
330
331 write_output(&mmap_ev, mmap_ev.header.size);
332 }
333 }
334
335 fclose(fp);
336}
337
338static void synthesize_all(void)
339{
340 DIR *proc;
341 struct dirent dirent, *next;
342
343 proc = opendir("/proc");
344
345 while (!readdir_r(proc, &dirent, &next) && next) {
346 char *end;
347 pid_t pid, tgid;
348
349 pid = strtol(dirent.d_name, &end, 10);
350 if (*end) /* only interested in proper numerical dirents */
351 continue;
352
353 tgid = pid_synthesize_comm_event(pid, 1);
354 pid_synthesize_mmap_samples(pid, tgid);
355 }
356
357 closedir(proc);
358}
359
360static int group_fd; 213static int group_fd;
361 214
362static 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)
@@ -367,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
367 h_attr = header->attr[nr]; 220 h_attr = header->attr[nr];
368 } else { 221 } else {
369 h_attr = perf_header_attr__new(a); 222 h_attr = perf_header_attr__new(a);
370 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 }
371 } 228 }
372 229
373 return h_attr; 230 return h_attr;
@@ -375,9 +232,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
375 232
376static void create_counter(int counter, int cpu, pid_t pid) 233static void create_counter(int counter, int cpu, pid_t pid)
377{ 234{
235 char *filter = filters[counter];
378 struct perf_event_attr *attr = attrs + counter; 236 struct perf_event_attr *attr = attrs + counter;
379 struct perf_header_attr *h_attr; 237 struct perf_header_attr *h_attr;
380 int track = !counter; /* only the first counter needs these */ 238 int track = !counter; /* only the first counter needs these */
239 int ret;
381 struct { 240 struct {
382 u64 count; 241 u64 count;
383 u64 time_enabled; 242 u64 time_enabled;
@@ -448,11 +307,19 @@ try_again:
448 printf("\n"); 307 printf("\n");
449 error("perfcounter syscall returned with %d (%s)\n", 308 error("perfcounter syscall returned with %d (%s)\n",
450 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
451 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 316 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
452 exit(-1); 317 exit(-1);
453 } 318 }
454 319
455 h_attr = get_header_attr(attr, counter); 320 h_attr = get_header_attr(attr, counter);
321 if (h_attr == NULL)
322 die("nomem\n");
456 323
457 if (!file_new) { 324 if (!file_new) {
458 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 325 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +333,10 @@ try_again:
466 exit(-1); 333 exit(-1);
467 } 334 }
468 335
469 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 }
470 340
471 assert(fd[nr_cpu][counter] >= 0); 341 assert(fd[nr_cpu][counter] >= 0);
472 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 342 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +350,6 @@ try_again:
480 multiplex_fd = fd[nr_cpu][counter]; 350 multiplex_fd = fd[nr_cpu][counter];
481 351
482 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 352 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
483 int ret;
484 353
485 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);
486 assert(ret != -1); 355 assert(ret != -1);
@@ -500,6 +369,16 @@ try_again:
500 } 369 }
501 } 370 }
502 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
503 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 382 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
504} 383}
505 384
@@ -518,7 +397,7 @@ static void atexit_header(void)
518{ 397{
519 header->data_size += bytes_written; 398 header->data_size += bytes_written;
520 399
521 perf_header__write(header, output); 400 perf_header__write(header, output, true);
522} 401}
523 402
524static int __cmd_record(int argc, const char **argv) 403static int __cmd_record(int argc, const char **argv)
@@ -527,7 +406,7 @@ static int __cmd_record(int argc, const char **argv)
527 struct stat st; 406 struct stat st;
528 pid_t pid = 0; 407 pid_t pid = 0;
529 int flags; 408 int flags;
530 int ret; 409 int err;
531 unsigned long waking = 0; 410 unsigned long waking = 0;
532 411
533 page_size = sysconf(_SC_PAGE_SIZE); 412 page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,22 +440,29 @@ static int __cmd_record(int argc, const char **argv)
561 exit(-1); 440 exit(-1);
562 } 441 }
563 442
564 if (!file_new) 443 header = perf_header__new();
565 header = perf_header__read(output); 444 if (header == NULL) {
566 else 445 pr_err("Not enough memory for reading perf file header\n");
567 header = perf_header__new(); 446 return -1;
447 }
568 448
449 if (!file_new) {
450 err = perf_header__read(header, output);
451 if (err < 0)
452 return err;
453 }
569 454
570 if (raw_samples) { 455 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 456 perf_header__set_feat(header, HEADER_TRACE_INFO);
572 } else { 457 } else {
573 for (i = 0; i < nr_counters; i++) { 458 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 460 perf_header__set_feat(header, HEADER_TRACE_INFO);
576 break; 461 break;
577 } 462 }
578 } 463 }
579 } 464 }
465
580 atexit(atexit_header); 466 atexit(atexit_header);
581 467
582 if (!system_wide) { 468 if (!system_wide) {
@@ -594,25 +480,36 @@ static int __cmd_record(int argc, const char **argv)
594 } 480 }
595 } 481 }
596 482
597 if (file_new) 483 if (file_new) {
598 perf_header__write(header, output); 484 err = perf_header__write(header, output, false);
485 if (err < 0)
486 return err;
487 }
599 488
600 if (!system_wide) { 489 if (!system_wide)
601 pid_t tgid = pid_synthesize_comm_event(pid, 0); 490 event__synthesize_thread(pid, process_synthesized_event);
602 pid_synthesize_mmap_samples(pid, tgid); 491 else
603 } else 492 event__synthesize_threads(process_synthesized_event);
604 synthesize_all();
605 493
606 if (target_pid == -1 && argc) { 494 if (target_pid == -1 && argc) {
607 pid = fork(); 495 pid = fork();
608 if (pid < 0) 496 if (pid < 0)
609 perror("failed to fork"); 497 die("failed to fork");
610 498
611 if (!pid) { 499 if (!pid) {
612 if (execvp(argv[0], (char **)argv)) { 500 if (execvp(argv[0], (char **)argv)) {
613 perror(argv[0]); 501 perror(argv[0]);
614 exit(-1); 502 exit(-1);
615 } 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);
616 } 513 }
617 514
618 child_pid = pid; 515 child_pid = pid;
@@ -623,7 +520,7 @@ static int __cmd_record(int argc, const char **argv)
623 520
624 param.sched_priority = realtime_prio; 521 param.sched_priority = realtime_prio;
625 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 522 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
626 printf("Could not set realtime priority.\n"); 523 pr_err("Could not set realtime priority.\n");
627 exit(-1); 524 exit(-1);
628 } 525 }
629 } 526 }
@@ -641,7 +538,7 @@ static int __cmd_record(int argc, const char **argv)
641 if (hits == samples) { 538 if (hits == samples) {
642 if (done) 539 if (done)
643 break; 540 break;
644 ret = poll(event_array, nr_poll, -1); 541 err = poll(event_array, nr_poll, -1);
645 waking++; 542 waking++;
646 } 543 }
647 544
@@ -677,6 +574,8 @@ static const struct option options[] = {
677 OPT_CALLBACK('e', "event", NULL, "event", 574 OPT_CALLBACK('e', "event", NULL, "event",
678 "event selector. use 'perf list' to list available events", 575 "event selector. use 'perf list' to list available events",
679 parse_events), 576 parse_events),
577 OPT_CALLBACK(0, "filter", NULL, "filter",
578 "event filter", parse_filter),
680 OPT_INTEGER('p', "pid", &target_pid, 579 OPT_INTEGER('p', "pid", &target_pid,
681 "record events on existing pid"), 580 "record events on existing pid"),
682 OPT_INTEGER('r', "realtime", &realtime_prio, 581 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -720,6 +619,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
720{ 619{
721 int counter; 620 int counter;
722 621
622 symbol__init(0);
623
723 argc = parse_options(argc, argv, options, record_usage, 624 argc = parse_options(argc, argv, options, record_usage,
724 PARSE_OPT_STOP_AT_NON_OPTION); 625 PARSE_OPT_STOP_AT_NON_OPTION);
725 if (!argc && target_pid == -1 && !system_wide) 626 if (!argc && target_pid == -1 && !system_wide)
@@ -731,6 +632,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 632 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 633 }
733 634
635 /*
636 * User specified count overrides default frequency.
637 */
638 if (default_interval)
639 freq = 0;
640 else if (freq) {
641 default_interval = freq;
642 } else {
643 fprintf(stderr, "frequency and count are zero, aborting\n");
644 exit(EXIT_FAILURE);
645 }
646
734 for (counter = 0; counter < nr_counters; counter++) { 647 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 648 if (attrs[counter].sample_period)
736 continue; 649 continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..2b9eb3a553ed 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -26,20 +26,18 @@
26#include "util/parse-options.h" 26#include "util/parse-options.h"
27#include "util/parse-events.h" 27#include "util/parse-events.h"
28 28
29#include "util/data_map.h"
29#include "util/thread.h" 30#include "util/thread.h"
31#include "util/sort.h"
32#include "util/hist.h"
30 33
31static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
32 35
33static char default_sort_order[] = "comm,dso,symbol";
34static char *sort_order = default_sort_order;
35static char *dso_list_str, *comm_list_str, *sym_list_str, 36static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str; 37 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list; 38static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
39 39
40static int force; 40static int force;
41static int input;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43 41
44static int full_paths; 42static int full_paths;
45static int show_nr_samples; 43static int show_nr_samples;
@@ -50,374 +48,38 @@ static struct perf_read_values show_threads_values;
50static char default_pretty_printing_style[] = "normal"; 48static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style; 49static char *pretty_printing_style = default_pretty_printing_style;
52 50
53static unsigned long page_size;
54static unsigned long mmap_window = 32;
55
56static char default_parent_pattern[] = "^sys_|^do_page_fault";
57static char *parent_pattern = default_parent_pattern;
58static regex_t parent_regex;
59
60static int exclude_other = 1; 51static int exclude_other = 1;
61 52
62static char callchain_default_opt[] = "fractal,0.5"; 53static char callchain_default_opt[] = "fractal,0.5";
63 54
64static int callchain;
65
66static char __cwd[PATH_MAX];
67static char *cwd = __cwd;
68static int cwdlen;
69
70static struct rb_root threads;
71static struct thread *last_match;
72
73static struct perf_header *header; 55static struct perf_header *header;
74 56
75static
76struct callchain_param callchain_param = {
77 .mode = CHAIN_GRAPH_REL,
78 .min_percent = 0.5
79};
80
81static u64 sample_type; 57static u64 sample_type;
82 58
83static int repsep_fprintf(FILE *fp, const char *fmt, ...) 59struct symbol_conf symbol_conf;
84{
85 int n;
86 va_list ap;
87
88 va_start(ap, fmt);
89 if (!field_sep)
90 n = vfprintf(fp, fmt, ap);
91 else {
92 char *bf = NULL;
93 n = vasprintf(&bf, fmt, ap);
94 if (n > 0) {
95 char *sep = bf;
96
97 while (1) {
98 sep = strchr(sep, *field_sep);
99 if (sep == NULL)
100 break;
101 *sep = '.';
102 }
103 }
104 fputs(bf, fp);
105 free(bf);
106 }
107 va_end(ap);
108 return n;
109}
110
111static unsigned int dsos__col_width,
112 comms__col_width,
113 threads__col_width;
114
115/*
116 * histogram, sorted on item, collects counts
117 */
118
119static struct rb_root hist;
120
121struct hist_entry {
122 struct rb_node rb_node;
123
124 struct thread *thread;
125 struct map *map;
126 struct dso *dso;
127 struct symbol *sym;
128 struct symbol *parent;
129 u64 ip;
130 char level;
131 struct callchain_node callchain;
132 struct rb_root sorted_chain;
133
134 u64 count;
135};
136
137/*
138 * configurable sorting bits
139 */
140
141struct sort_entry {
142 struct list_head list;
143
144 const char *header;
145
146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
148 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 unsigned int *width;
150 bool elide;
151};
152
153static int64_t cmp_null(void *l, void *r)
154{
155 if (!l && !r)
156 return 0;
157 else if (!l)
158 return -1;
159 else
160 return 1;
161}
162
163/* --sort pid */
164
165static int64_t
166sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
167{
168 return right->thread->pid - left->thread->pid;
169}
170
171static size_t
172sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
173{
174 return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 self->thread->comm ?: "", self->thread->pid);
176}
177
178static struct sort_entry sort_thread = {
179 .header = "Command: Pid",
180 .cmp = sort__thread_cmp,
181 .print = sort__thread_print,
182 .width = &threads__col_width,
183};
184
185/* --sort comm */
186
187static int64_t
188sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
189{
190 return right->thread->pid - left->thread->pid;
191}
192
193static int64_t
194sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
195{
196 char *comm_l = left->thread->comm;
197 char *comm_r = right->thread->comm;
198
199 if (!comm_l || !comm_r)
200 return cmp_null(comm_l, comm_r);
201
202 return strcmp(comm_l, comm_r);
203}
204
205static size_t
206sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
207{
208 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
209}
210
211static struct sort_entry sort_comm = {
212 .header = "Command",
213 .cmp = sort__comm_cmp,
214 .collapse = sort__comm_collapse,
215 .print = sort__comm_print,
216 .width = &comms__col_width,
217};
218
219/* --sort dso */
220
221static int64_t
222sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
223{
224 struct dso *dso_l = left->dso;
225 struct dso *dso_r = right->dso;
226
227 if (!dso_l || !dso_r)
228 return cmp_null(dso_l, dso_r);
229 60
230 return strcmp(dso_l->name, dso_r->name);
231}
232 61
233static size_t 62static size_t
234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 63callchain__fprintf_left_margin(FILE *fp, int left_margin)
235{ 64{
236 if (self->dso) 65 int i;
237 return repsep_fprintf(fp, "%-*s", width, self->dso->name); 66 int ret;
238
239 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
240}
241
242static struct sort_entry sort_dso = {
243 .header = "Shared Object",
244 .cmp = sort__dso_cmp,
245 .print = sort__dso_print,
246 .width = &dsos__col_width,
247};
248
249/* --sort symbol */
250
251static int64_t
252sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
253{
254 u64 ip_l, ip_r;
255
256 if (left->sym == right->sym)
257 return 0;
258
259 ip_l = left->sym ? left->sym->start : left->ip;
260 ip_r = right->sym ? right->sym->start : right->ip;
261
262 return (int64_t)(ip_r - ip_l);
263}
264
265static size_t
266sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
267{
268 size_t ret = 0;
269
270 if (verbose)
271 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 dso__symtab_origin(self->dso));
273 67
274 ret += repsep_fprintf(fp, "[%c] ", self->level); 68 ret = fprintf(fp, " ");
275 if (self->sym) {
276 ret += repsep_fprintf(fp, "%s", self->sym->name);
277 69
278 if (self->sym->module) 70 for (i = 0; i < left_margin; i++)
279 ret += repsep_fprintf(fp, "\t[%s]", 71 ret += fprintf(fp, " ");
280 self->sym->module->name);
281 } else {
282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 }
284 72
285 return ret; 73 return ret;
286} 74}
287 75
288static struct sort_entry sort_sym = { 76static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
289 .header = "Symbol", 77 int left_margin)
290 .cmp = sort__sym_cmp,
291 .print = sort__sym_print,
292};
293
294/* --sort parent */
295
296static int64_t
297sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
298{
299 struct symbol *sym_l = left->parent;
300 struct symbol *sym_r = right->parent;
301
302 if (!sym_l || !sym_r)
303 return cmp_null(sym_l, sym_r);
304
305 return strcmp(sym_l->name, sym_r->name);
306}
307
308static size_t
309sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
310{
311 return repsep_fprintf(fp, "%-*s", width,
312 self->parent ? self->parent->name : "[other]");
313}
314
315static unsigned int parent_symbol__col_width;
316
317static struct sort_entry sort_parent = {
318 .header = "Parent symbol",
319 .cmp = sort__parent_cmp,
320 .print = sort__parent_print,
321 .width = &parent_symbol__col_width,
322};
323
324static int sort__need_collapse = 0;
325static int sort__has_parent = 0;
326
327struct sort_dimension {
328 const char *name;
329 struct sort_entry *entry;
330 int taken;
331};
332
333static struct sort_dimension sort_dimensions[] = {
334 { .name = "pid", .entry = &sort_thread, },
335 { .name = "comm", .entry = &sort_comm, },
336 { .name = "dso", .entry = &sort_dso, },
337 { .name = "symbol", .entry = &sort_sym, },
338 { .name = "parent", .entry = &sort_parent, },
339};
340
341static LIST_HEAD(hist_entry__sort_list);
342
343static int sort_dimension__add(const char *tok)
344{
345 unsigned int i;
346
347 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
348 struct sort_dimension *sd = &sort_dimensions[i];
349
350 if (sd->taken)
351 continue;
352
353 if (strncasecmp(tok, sd->name, strlen(tok)))
354 continue;
355
356 if (sd->entry->collapse)
357 sort__need_collapse = 1;
358
359 if (sd->entry == &sort_parent) {
360 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
361 if (ret) {
362 char err[BUFSIZ];
363
364 regerror(ret, &parent_regex, err, sizeof(err));
365 fprintf(stderr, "Invalid regex: %s\n%s",
366 parent_pattern, err);
367 exit(-1);
368 }
369 sort__has_parent = 1;
370 }
371
372 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
373 sd->taken = 1;
374
375 return 0;
376 }
377
378 return -ESRCH;
379}
380
381static int64_t
382hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct sort_entry *se;
385 int64_t cmp = 0;
386
387 list_for_each_entry(se, &hist_entry__sort_list, list) {
388 cmp = se->cmp(left, right);
389 if (cmp)
390 break;
391 }
392
393 return cmp;
394}
395
396static int64_t
397hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
398{
399 struct sort_entry *se;
400 int64_t cmp = 0;
401
402 list_for_each_entry(se, &hist_entry__sort_list, list) {
403 int64_t (*f)(struct hist_entry *, struct hist_entry *);
404
405 f = se->collapse ?: se->cmp;
406
407 cmp = f(left, right);
408 if (cmp)
409 break;
410 }
411
412 return cmp;
413}
414
415static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416{ 78{
417 int i; 79 int i;
418 size_t ret = 0; 80 size_t ret = 0;
419 81
420 ret += fprintf(fp, "%s", " "); 82 ret += callchain__fprintf_left_margin(fp, left_margin);
421 83
422 for (i = 0; i < depth; i++) 84 for (i = 0; i < depth; i++)
423 if (depth_mask & (1 << i)) 85 if (depth_mask & (1 << i))
@@ -432,12 +94,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
432static size_t 94static size_t
433ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, 95ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 int depth_mask, int count, u64 total_samples, 96 int depth_mask, int count, u64 total_samples,
435 int hits) 97 int hits, int left_margin)
436{ 98{
437 int i; 99 int i;
438 size_t ret = 0; 100 size_t ret = 0;
439 101
440 ret += fprintf(fp, "%s", " "); 102 ret += callchain__fprintf_left_margin(fp, left_margin);
441 for (i = 0; i < depth; i++) { 103 for (i = 0; i < depth; i++) {
442 if (depth_mask & (1 << i)) 104 if (depth_mask & (1 << i))
443 ret += fprintf(fp, "|"); 105 ret += fprintf(fp, "|");
@@ -475,8 +137,9 @@ static void init_rem_hits(void)
475} 137}
476 138
477static size_t 139static size_t
478callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 140__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 u64 total_samples, int depth, int depth_mask) 141 u64 total_samples, int depth, int depth_mask,
142 int left_margin)
480{ 143{
481 struct rb_node *node, *next; 144 struct rb_node *node, *next;
482 struct callchain_node *child; 145 struct callchain_node *child;
@@ -517,7 +180,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
517 * But we keep the older depth mask for the line seperator 180 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child 181 * to keep the level link until we reach the last child
519 */ 182 */
520 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask); 183 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
184 left_margin);
521 i = 0; 185 i = 0;
522 list_for_each_entry(chain, &child->val, list) { 186 list_for_each_entry(chain, &child->val, list) {
523 if (chain->ip >= PERF_CONTEXT_MAX) 187 if (chain->ip >= PERF_CONTEXT_MAX)
@@ -525,11 +189,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
525 ret += ipchain__fprintf_graph(fp, chain, depth, 189 ret += ipchain__fprintf_graph(fp, chain, depth,
526 new_depth_mask, i++, 190 new_depth_mask, i++,
527 new_total, 191 new_total,
528 cumul); 192 cumul,
193 left_margin);
529 } 194 }
530 ret += callchain__fprintf_graph(fp, child, new_total, 195 ret += __callchain__fprintf_graph(fp, child, new_total,
531 depth + 1, 196 depth + 1,
532 new_depth_mask | (1 << depth)); 197 new_depth_mask | (1 << depth),
198 left_margin);
533 node = next; 199 node = next;
534 } 200 }
535 201
@@ -543,9 +209,48 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
543 209
544 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 210 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 new_depth_mask, 0, new_total, 211 new_depth_mask, 0, new_total,
546 remaining); 212 remaining, left_margin);
213 }
214
215 return ret;
216}
217
218
219static size_t
220callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
221 u64 total_samples, int left_margin)
222{
223 struct callchain_list *chain;
224 bool printed = false;
225 int i = 0;
226 int ret = 0;
227
228 list_for_each_entry(chain, &self->val, list) {
229 if (chain->ip >= PERF_CONTEXT_MAX)
230 continue;
231
232 if (!i++ && sort__first_dimension == SORT_SYM)
233 continue;
234
235 if (!printed) {
236 ret += callchain__fprintf_left_margin(fp, left_margin);
237 ret += fprintf(fp, "|\n");
238 ret += callchain__fprintf_left_margin(fp, left_margin);
239 ret += fprintf(fp, "---");
240
241 left_margin += 3;
242 printed = true;
243 } else
244 ret += callchain__fprintf_left_margin(fp, left_margin);
245
246 if (chain->sym)
247 ret += fprintf(fp, " %s\n", chain->sym->name);
248 else
249 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
547 } 250 }
548 251
252 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
253
549 return ret; 254 return ret;
550} 255}
551 256
@@ -577,7 +282,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
577 282
578static size_t 283static size_t
579hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, 284hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 u64 total_samples) 285 u64 total_samples, int left_margin)
581{ 286{
582 struct rb_node *rb_node; 287 struct rb_node *rb_node;
583 struct callchain_node *chain; 288 struct callchain_node *chain;
@@ -597,8 +302,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
597 break; 302 break;
598 case CHAIN_GRAPH_ABS: /* Falldown */ 303 case CHAIN_GRAPH_ABS: /* Falldown */
599 case CHAIN_GRAPH_REL: 304 case CHAIN_GRAPH_REL:
600 ret += callchain__fprintf_graph(fp, chain, 305 ret += callchain__fprintf_graph(fp, chain, total_samples,
601 total_samples, 1, 1); 306 left_margin);
602 case CHAIN_NONE: 307 case CHAIN_NONE:
603 default: 308 default:
604 break; 309 break;
@@ -610,7 +315,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
610 return ret; 315 return ret;
611} 316}
612 317
613
614static size_t 318static size_t
615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 319hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616{ 320{
@@ -644,8 +348,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
644 348
645 ret += fprintf(fp, "\n"); 349 ret += fprintf(fp, "\n");
646 350
647 if (callchain) 351 if (callchain) {
648 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 }
649 364
650 return ret; 365 return ret;
651} 366}
@@ -693,63 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
693 return 0; 408 return 0;
694} 409}
695 410
696
697static struct symbol *
698resolve_symbol(struct thread *thread, struct map **mapp,
699 struct dso **dsop, u64 *ipp)
700{
701 struct dso *dso = dsop ? *dsop : NULL;
702 struct map *map = mapp ? *mapp : NULL;
703 u64 ip = *ipp;
704
705 if (!thread)
706 return NULL;
707
708 if (dso)
709 goto got_dso;
710
711 if (map)
712 goto got_map;
713
714 map = thread__find_map(thread, ip);
715 if (map != NULL) {
716 /*
717 * We have to do this here as we may have a dso
718 * with no symbol hit that has a name longer than
719 * the ones with symbols sampled.
720 */
721 if (!sort_dso.elide && !map->dso->slen_calculated)
722 dso__calc_col_width(map->dso);
723
724 if (mapp)
725 *mapp = map;
726got_map:
727 ip = map->map_ip(map, ip);
728
729 dso = map->dso;
730 } else {
731 /*
732 * If this is outside of all known maps,
733 * and is a negative address, try to look it
734 * up in the kernel dso, as it might be a
735 * vsyscall (which executes in user-mode):
736 */
737 if ((long long)ip < 0)
738 dso = kernel_dso;
739 }
740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 *ipp = ip;
743
744 if (dsop)
745 *dsop = dso;
746
747 if (!dso)
748 return NULL;
749got_dso:
750 return dso->find_symbol(dso, ip);
751}
752
753static int call__match(struct symbol *sym) 411static int call__match(struct symbol *sym)
754{ 412{
755 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 413 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -758,11 +416,11 @@ static int call__match(struct symbol *sym)
758 return 0; 416 return 0;
759} 417}
760 418
761static struct symbol ** 419static struct symbol **resolve_callchain(struct thread *thread,
762resolve_callchain(struct thread *thread, struct map *map __used, 420 struct ip_callchain *chain,
763 struct ip_callchain *chain, struct hist_entry *entry) 421 struct symbol **parent)
764{ 422{
765 u64 context = PERF_CONTEXT_MAX; 423 u8 cpumode = PERF_RECORD_MISC_USER;
766 struct symbol **syms = NULL; 424 struct symbol **syms = NULL;
767 unsigned int i; 425 unsigned int i;
768 426
@@ -776,34 +434,31 @@ resolve_callchain(struct thread *thread, struct map *map __used,
776 434
777 for (i = 0; i < chain->nr; i++) { 435 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i]; 436 u64 ip = chain->ips[i];
779 struct dso *dso = NULL; 437 struct addr_location al;
780 struct symbol *sym;
781 438
782 if (ip >= PERF_CONTEXT_MAX) { 439 if (ip >= PERF_CONTEXT_MAX) {
783 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 }
784 continue; 450 continue;
785 } 451 }
786 452
787 switch (context) { 453 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
788 case PERF_CONTEXT_HV: 454 ip, &al, NULL);
789 dso = hypervisor_dso; 455 if (al.sym != NULL) {
790 break; 456 if (sort__has_parent && !*parent &&
791 case PERF_CONTEXT_KERNEL: 457 call__match(al.sym))
792 dso = kernel_dso; 458 *parent = al.sym;
793 break;
794 default:
795 break;
796 }
797
798 sym = resolve_symbol(thread, NULL, &dso, &ip);
799
800 if (sym) {
801 if (sort__has_parent && call__match(sym) &&
802 !entry->parent)
803 entry->parent = sym;
804 if (!callchain) 459 if (!callchain)
805 break; 460 break;
806 syms[i] = sym; 461 syms[i] = al.sym;
807 } 462 }
808 } 463 }
809 464
@@ -814,178 +469,33 @@ resolve_callchain(struct thread *thread, struct map *map __used,
814 * collect histogram counts 469 * collect histogram counts
815 */ 470 */
816 471
817static int 472static int hist_entry__add(struct addr_location *al,
818hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 473 struct ip_callchain *chain, u64 count)
819 struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 char level, u64 count)
821{ 474{
822 struct rb_node **p = &hist.rb_node; 475 struct symbol **syms = NULL, *parent = NULL;
823 struct rb_node *parent = NULL; 476 bool hit;
824 struct hist_entry *he; 477 struct hist_entry *he;
825 struct symbol **syms = NULL;
826 struct hist_entry entry = {
827 .thread = thread,
828 .map = map,
829 .dso = dso,
830 .sym = sym,
831 .ip = ip,
832 .level = level,
833 .count = count,
834 .parent = NULL,
835 .sorted_chain = RB_ROOT
836 };
837 int cmp;
838 478
839 if ((sort__has_parent || callchain) && chain) 479 if ((sort__has_parent || callchain) && chain)
840 syms = resolve_callchain(thread, map, chain, &entry); 480 syms = resolve_callchain(al->thread, chain, &parent);
841
842 while (*p != NULL) {
843 parent = *p;
844 he = rb_entry(parent, struct hist_entry, rb_node);
845
846 cmp = hist_entry__cmp(&entry, he);
847 481
848 if (!cmp) { 482 he = __hist_entry__add(al, parent, count, &hit);
849 he->count += count; 483 if (he == NULL)
850 if (callchain) { 484 return -ENOMEM;
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
854 return 0;
855 }
856 485
857 if (cmp < 0) 486 if (hit)
858 p = &(*p)->rb_left; 487 he->count += count;
859 else
860 p = &(*p)->rb_right;
861 }
862 488
863 he = malloc(sizeof(*he));
864 if (!he)
865 return -ENOMEM;
866 *he = entry;
867 if (callchain) { 489 if (callchain) {
868 callchain_init(&he->callchain); 490 if (!hit)
491 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms); 492 append_chain(&he->callchain, chain, syms);
870 free(syms); 493 free(syms);
871 } 494 }
872 rb_link_node(&he->rb_node, parent, p);
873 rb_insert_color(&he->rb_node, &hist);
874 495
875 return 0; 496 return 0;
876} 497}
877 498
878static void hist_entry__free(struct hist_entry *he)
879{
880 free(he);
881}
882
883/*
884 * collapse the histogram
885 */
886
887static struct rb_root collapse_hists;
888
889static void collapse__insert_entry(struct hist_entry *he)
890{
891 struct rb_node **p = &collapse_hists.rb_node;
892 struct rb_node *parent = NULL;
893 struct hist_entry *iter;
894 int64_t cmp;
895
896 while (*p != NULL) {
897 parent = *p;
898 iter = rb_entry(parent, struct hist_entry, rb_node);
899
900 cmp = hist_entry__collapse(iter, he);
901
902 if (!cmp) {
903 iter->count += he->count;
904 hist_entry__free(he);
905 return;
906 }
907
908 if (cmp < 0)
909 p = &(*p)->rb_left;
910 else
911 p = &(*p)->rb_right;
912 }
913
914 rb_link_node(&he->rb_node, parent, p);
915 rb_insert_color(&he->rb_node, &collapse_hists);
916}
917
918static void collapse__resort(void)
919{
920 struct rb_node *next;
921 struct hist_entry *n;
922
923 if (!sort__need_collapse)
924 return;
925
926 next = rb_first(&hist);
927 while (next) {
928 n = rb_entry(next, struct hist_entry, rb_node);
929 next = rb_next(&n->rb_node);
930
931 rb_erase(&n->rb_node, &hist);
932 collapse__insert_entry(n);
933 }
934}
935
936/*
937 * reverse the map, sort on count.
938 */
939
940static struct rb_root output_hists;
941
942static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
943{
944 struct rb_node **p = &output_hists.rb_node;
945 struct rb_node *parent = NULL;
946 struct hist_entry *iter;
947
948 if (callchain)
949 callchain_param.sort(&he->sorted_chain, &he->callchain,
950 min_callchain_hits, &callchain_param);
951
952 while (*p != NULL) {
953 parent = *p;
954 iter = rb_entry(parent, struct hist_entry, rb_node);
955
956 if (he->count > iter->count)
957 p = &(*p)->rb_left;
958 else
959 p = &(*p)->rb_right;
960 }
961
962 rb_link_node(&he->rb_node, parent, p);
963 rb_insert_color(&he->rb_node, &output_hists);
964}
965
966static void output__resort(u64 total_samples)
967{
968 struct rb_node *next;
969 struct hist_entry *n;
970 struct rb_root *tree = &hist;
971 u64 min_callchain_hits;
972
973 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
974
975 if (sort__need_collapse)
976 tree = &collapse_hists;
977
978 next = rb_first(tree);
979
980 while (next) {
981 n = rb_entry(next, struct hist_entry, rb_node);
982 next = rb_next(&n->rb_node);
983
984 rb_erase(&n->rb_node, tree);
985 output__insert_entry(n, min_callchain_hits);
986 }
987}
988
989static size_t output__fprintf(FILE *fp, u64 total_samples) 499static size_t output__fprintf(FILE *fp, u64 total_samples)
990{ 500{
991 struct hist_entry *pos; 501 struct hist_entry *pos;
@@ -1080,13 +590,6 @@ print_entries:
1080 return ret; 590 return ret;
1081} 591}
1082 592
1083static unsigned long total = 0,
1084 total_mmap = 0,
1085 total_comm = 0,
1086 total_fork = 0,
1087 total_unknown = 0,
1088 total_lost = 0;
1089
1090static int validate_chain(struct ip_callchain *chain, event_t *event) 593static int validate_chain(struct ip_callchain *chain, event_t *event)
1091{ 594{
1092 unsigned int chain_size; 595 unsigned int chain_size;
@@ -1100,210 +603,101 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1100 return 0; 603 return 0;
1101} 604}
1102 605
1103static int 606static int process_sample_event(event_t *event)
1104process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105{ 607{
1106 char level; 608 struct sample_data data;
1107 int show = 0;
1108 struct dso *dso = NULL;
1109 struct thread *thread;
1110 u64 ip = event->ip.ip;
1111 u64 period = 1;
1112 struct map *map = NULL;
1113 void *more_data = event->ip.__more_data;
1114 struct ip_callchain *chain = NULL;
1115 int cpumode; 609 int cpumode;
610 struct addr_location al;
611 struct thread *thread;
1116 612
1117 thread = threads__findnew(event->ip.pid, &threads, &last_match); 613 memset(&data, 0, sizeof(data));
614 data.period = 1;
1118 615
1119 if (sample_type & PERF_SAMPLE_PERIOD) { 616 event__parse_sample(event, sample_type, &data);
1120 period = *(u64 *)more_data;
1121 more_data += sizeof(u64);
1122 }
1123 617
1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 618 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1125 (void *)(offset + head),
1126 (void *)(long)(event->header.size),
1127 event->header.misc, 619 event->header.misc,
1128 event->ip.pid, event->ip.tid, 620 data.pid, data.tid,
1129 (void *)(long)ip, 621 (void *)(long)data.ip,
1130 (long long)period); 622 (long long)data.period);
1131 623
1132 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 624 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1133 unsigned int i; 625 unsigned int i;
1134 626
1135 chain = (void *)more_data; 627 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
1136
1137 dump_printf("... chain: nr:%Lu\n", chain->nr);
1138 628
1139 if (validate_chain(chain, event) < 0) { 629 if (validate_chain(data.callchain, event) < 0) {
1140 eprintf("call-chain problem with event, skipping it.\n"); 630 pr_debug("call-chain problem with event, "
631 "skipping it.\n");
1141 return 0; 632 return 0;
1142 } 633 }
1143 634
1144 if (dump_trace) { 635 if (dump_trace) {
1145 for (i = 0; i < chain->nr; i++) 636 for (i = 0; i < data.callchain->nr; i++)
1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 637 dump_printf("..... %2d: %016Lx\n",
638 i, data.callchain->ips[i]);
1147 } 639 }
1148 } 640 }
1149 641
1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 642 thread = threads__findnew(data.pid);
1151
1152 if (thread == NULL) { 643 if (thread == NULL) {
1153 eprintf("problem processing %d event, skipping it.\n", 644 pr_debug("problem processing %d event, skipping it.\n",
1154 event->header.type); 645 event->header.type);
1155 return -1; 646 return -1;
1156 } 647 }
1157 648
649 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
650
1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 651 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1159 return 0; 652 return 0;
1160 653
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 654 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162 655
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) { 656 thread__find_addr_location(thread, cpumode,
1164 show = SHOW_KERNEL; 657 MAP__FUNCTION, data.ip, &al, NULL);
1165 level = 'k'; 658 /*
1166 659 * We have to do this here as we may have a dso with no symbol hit that
1167 dso = kernel_dso; 660 * has a name longer than the ones with symbols sampled.
1168 661 */
1169 dump_printf(" ...... dso: %s\n", dso->name); 662 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
1170 663 dso__calc_col_width(al.map->dso);
1171 } else if (cpumode == PERF_RECORD_MISC_USER) { 664
1172 665 if (dso_list &&
1173 show = SHOW_USER; 666 (!al.map || !al.map->dso ||
1174 level = '.'; 667 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
1175 668 (al.map->dso->short_name != al.map->dso->long_name &&
1176 } else { 669 strlist__has_entry(dso_list, al.map->dso->long_name)))))
1177 show = SHOW_HV; 670 return 0;
1178 level = 'H';
1179
1180 dso = hypervisor_dso;
1181
1182 dump_printf(" ...... dso: [hypervisor]\n");
1183 }
1184
1185 if (show & show_mask) {
1186 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1187
1188 if (dso_list && (!dso || !dso->name ||
1189 !strlist__has_entry(dso_list, dso->name)))
1190 return 0;
1191
1192 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1193 return 0;
1194
1195 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1196 eprintf("problem incrementing symbol count, skipping event\n");
1197 return -1;
1198 }
1199 }
1200 total += period;
1201
1202 return 0;
1203}
1204 671
1205static int 672 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
1206process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1207{
1208 struct thread *thread;
1209 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1210
1211 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1212
1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1214 (void *)(offset + head),
1215 (void *)(long)(event->header.size),
1216 event->mmap.pid,
1217 event->mmap.tid,
1218 (void *)(long)event->mmap.start,
1219 (void *)(long)event->mmap.len,
1220 (void *)(long)event->mmap.pgoff,
1221 event->mmap.filename);
1222
1223 if (thread == NULL || map == NULL) {
1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1225 return 0; 673 return 0;
674
675 if (hist_entry__add(&al, data.callchain, data.period)) {
676 pr_debug("problem incrementing symbol count, skipping event\n");
677 return -1;
1226 } 678 }
1227 679
1228 thread__insert_map(thread, map); 680 event__stats.total += data.period;
1229 total_mmap++;
1230 681
1231 return 0; 682 return 0;
1232} 683}
1233 684
1234static int 685static int process_comm_event(event_t *event)
1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1236{ 686{
1237 struct thread *thread; 687 struct thread *thread = threads__findnew(event->comm.pid);
1238
1239 thread = threads__findnew(event->comm.pid, &threads, &last_match);
1240 688
1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 689 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
1242 (void *)(offset + head),
1243 (void *)(long)(event->header.size),
1244 event->comm.comm, event->comm.pid);
1245 690
1246 if (thread == NULL || 691 if (thread == NULL ||
1247 thread__set_comm_adjust(thread, event->comm.comm)) { 692 thread__set_comm_adjust(thread, event->comm.comm)) {
1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 693 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1249 return -1; 694 return -1;
1250 } 695 }
1251 total_comm++;
1252 696
1253 return 0; 697 return 0;
1254} 698}
1255 699
1256static int 700static int process_read_event(event_t *event)
1257process_task_event(event_t *event, unsigned long offset, unsigned long head)
1258{
1259 struct thread *thread;
1260 struct thread *parent;
1261
1262 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1263 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
1264
1265 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1266 (void *)(offset + head),
1267 (void *)(long)(event->header.size),
1268 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
1269 event->fork.pid, event->fork.tid,
1270 event->fork.ppid, event->fork.ptid);
1271
1272 /*
1273 * A thread clone will have the same PID for both
1274 * parent and child.
1275 */
1276 if (thread == parent)
1277 return 0;
1278
1279 if (event->header.type == PERF_RECORD_EXIT)
1280 return 0;
1281
1282 if (!thread || !parent || thread__fork(thread, parent)) {
1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1284 return -1;
1285 }
1286 total_fork++;
1287
1288 return 0;
1289}
1290
1291static int
1292process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1293{
1294 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1295 (void *)(offset + head),
1296 (void *)(long)(event->header.size),
1297 event->lost.id,
1298 event->lost.lost);
1299
1300 total_lost += event->lost.lost;
1301
1302 return 0;
1303}
1304
1305static int
1306process_read_event(event_t *event, unsigned long offset, unsigned long head)
1307{ 701{
1308 struct perf_event_attr *attr; 702 struct perf_event_attr *attr;
1309 703
@@ -1319,238 +713,91 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1319 event->read.value); 713 event->read.value);
1320 } 714 }
1321 715
1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", 716 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
1323 (void *)(offset + head), 717 attr ? __event_name(attr->type, attr->config) : "FAIL",
1324 (void *)(long)(event->header.size), 718 event->read.value);
1325 event->read.pid,
1326 event->read.tid,
1327 attr ? __event_name(attr->type, attr->config)
1328 : "FAIL",
1329 event->read.value);
1330 719
1331 return 0; 720 return 0;
1332} 721}
1333 722
1334static int 723static int sample_type_check(u64 type)
1335process_event(event_t *event, unsigned long offset, unsigned long head)
1336{ 724{
1337 trace_event(event); 725 sample_type = type;
1338
1339 switch (event->header.type) {
1340 case PERF_RECORD_SAMPLE:
1341 return process_sample_event(event, offset, head);
1342
1343 case PERF_RECORD_MMAP:
1344 return process_mmap_event(event, offset, head);
1345
1346 case PERF_RECORD_COMM:
1347 return process_comm_event(event, offset, head);
1348
1349 case PERF_RECORD_FORK:
1350 case PERF_RECORD_EXIT:
1351 return process_task_event(event, offset, head);
1352
1353 case PERF_RECORD_LOST:
1354 return process_lost_event(event, offset, head);
1355
1356 case PERF_RECORD_READ:
1357 return process_read_event(event, offset, head);
1358
1359 /*
1360 * We dont process them right now but they are fine:
1361 */
1362
1363 case PERF_RECORD_THROTTLE:
1364 case PERF_RECORD_UNTHROTTLE:
1365 return 0;
1366
1367 default:
1368 return -1;
1369 }
1370
1371 return 0;
1372}
1373
1374static int __cmd_report(void)
1375{
1376 int ret, rc = EXIT_FAILURE;
1377 unsigned long offset = 0;
1378 unsigned long head, shift;
1379 struct stat input_stat;
1380 struct thread *idle;
1381 event_t *event;
1382 uint32_t size;
1383 char *buf;
1384
1385 idle = register_idle_thread(&threads, &last_match);
1386 thread__comm_adjust(idle);
1387
1388 if (show_threads)
1389 perf_read_values_init(&show_threads_values);
1390
1391 input = open(input_name, O_RDONLY);
1392 if (input < 0) {
1393 fprintf(stderr, " failed to open file: %s", input_name);
1394 if (!strcmp(input_name, "perf.data"))
1395 fprintf(stderr, " (try 'perf record' first)");
1396 fprintf(stderr, "\n");
1397 exit(-1);
1398 }
1399
1400 ret = fstat(input, &input_stat);
1401 if (ret < 0) {
1402 perror("failed to stat file");
1403 exit(-1);
1404 }
1405
1406 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1407 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1408 exit(-1);
1409 }
1410
1411 if (!input_stat.st_size) {
1412 fprintf(stderr, "zero-sized file, nothing to do!\n");
1413 exit(0);
1414 }
1415
1416 header = perf_header__read(input);
1417 head = header->data_offset;
1418
1419 sample_type = perf_header__sample_type(header);
1420 726
1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { 727 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 if (sort__has_parent) { 728 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no" 729 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call" 730 " callchain data. Did you call"
1425 " perf record without -g?\n"); 731 " perf record without -g?\n");
1426 exit(-1); 732 return -1;
1427 } 733 }
1428 if (callchain) { 734 if (callchain) {
1429 fprintf(stderr, "selected -g but no callchain data." 735 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without" 736 " Did you call perf record without"
1431 " -g?\n"); 737 " -g?\n");
1432 exit(-1); 738 return -1;
1433 } 739 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 740 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1435 callchain = 1; 741 callchain = 1;
1436 if (register_callchain_param(&callchain_param) < 0) { 742 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain" 743 fprintf(stderr, "Can't register callchain"
1438 " params\n"); 744 " params\n");
1439 exit(-1); 745 return -1;
1440 } 746 }
1441 } 747 }
1442 748
1443 if (load_kernel() < 0) { 749 return 0;
1444 perror("failed to load kernel symbols"); 750}
1445 return EXIT_FAILURE;
1446 }
1447
1448 if (!full_paths) {
1449 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1450 perror("failed to get the current directory");
1451 return EXIT_FAILURE;
1452 }
1453 cwdlen = strlen(cwd);
1454 } else {
1455 cwd = NULL;
1456 cwdlen = 0;
1457 }
1458
1459 shift = page_size * (head / page_size);
1460 offset += shift;
1461 head -= shift;
1462
1463remap:
1464 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1465 MAP_SHARED, input, offset);
1466 if (buf == MAP_FAILED) {
1467 perror("failed to mmap file");
1468 exit(-1);
1469 }
1470
1471more:
1472 event = (event_t *)(buf + head);
1473
1474 size = event->header.size;
1475 if (!size)
1476 size = 8;
1477
1478 if (head + event->header.size >= page_size * mmap_window) {
1479 int munmap_ret;
1480
1481 shift = page_size * (head / page_size);
1482
1483 munmap_ret = munmap(buf, page_size * mmap_window);
1484 assert(munmap_ret == 0);
1485
1486 offset += shift;
1487 head -= shift;
1488 goto remap;
1489 }
1490
1491 size = event->header.size;
1492
1493 dump_printf("\n%p [%p]: event: %d\n",
1494 (void *)(offset + head),
1495 (void *)(long)event->header.size,
1496 event->header.type);
1497
1498 if (!size || process_event(event, offset, head) < 0) {
1499
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1501 (void *)(offset + head),
1502 (void *)(long)(event->header.size),
1503 event->header.type);
1504
1505 total_unknown++;
1506
1507 /*
1508 * assume we lost track of the stream, check alignment, and
1509 * increment a single u64 in the hope to catch on again 'soon'.
1510 */
1511 751
1512 if (unlikely(head & 7)) 752static struct perf_file_handler file_handler = {
1513 head &= ~7ULL; 753 .process_sample_event = process_sample_event,
754 .process_mmap_event = event__process_mmap,
755 .process_comm_event = process_comm_event,
756 .process_exit_event = event__process_task,
757 .process_fork_event = event__process_task,
758 .process_lost_event = event__process_lost,
759 .process_read_event = process_read_event,
760 .sample_type_check = sample_type_check,
761};
1514 762
1515 size = 8;
1516 }
1517 763
1518 head += size; 764static int __cmd_report(void)
765{
766 struct thread *idle;
767 int ret;
1519 768
1520 if (offset + head >= header->data_offset + header->data_size) 769 idle = register_idle_thread();
1521 goto done; 770 thread__comm_adjust(idle);
1522 771
1523 if (offset + head < (unsigned long)input_stat.st_size) 772 if (show_threads)
1524 goto more; 773 perf_read_values_init(&show_threads_values);
1525 774
1526done: 775 register_perf_file_handler(&file_handler);
1527 rc = EXIT_SUCCESS;
1528 close(input);
1529 776
1530 dump_printf(" IP events: %10ld\n", total); 777 ret = mmap_dispatch_perf_file(&header, input_name, force,
1531 dump_printf(" mmap events: %10ld\n", total_mmap); 778 full_paths, &event__cwdlen, &event__cwd);
1532 dump_printf(" comm events: %10ld\n", total_comm); 779 if (ret)
1533 dump_printf(" fork events: %10ld\n", total_fork); 780 return ret;
1534 dump_printf(" lost events: %10ld\n", total_lost);
1535 dump_printf(" unknown events: %10ld\n", total_unknown);
1536 781
1537 if (dump_trace) 782 if (dump_trace) {
783 event__print_totals();
1538 return 0; 784 return 0;
785 }
1539 786
1540 if (verbose >= 3) 787 if (verbose > 3)
1541 threads__fprintf(stdout, &threads); 788 threads__fprintf(stdout);
1542 789
1543 if (verbose >= 2) 790 if (verbose > 2)
1544 dsos__fprintf(stdout); 791 dsos__fprintf(stdout);
1545 792
1546 collapse__resort(); 793 collapse__resort();
1547 output__resort(total); 794 output__resort(event__stats.total);
1548 output__fprintf(stdout, total); 795 output__fprintf(stdout, event__stats.total);
1549 796
1550 if (show_threads) 797 if (show_threads)
1551 perf_read_values_destroy(&show_threads_values); 798 perf_read_values_destroy(&show_threads_values);
1552 799
1553 return rc; 800 return ret;
1554} 801}
1555 802
1556static int 803static int
@@ -1606,7 +853,8 @@ setup:
1606 return 0; 853 return 0;
1607} 854}
1608 855
1609static const char * const report_usage[] = { 856//static const char * const report_usage[] = {
857const char * const report_usage[] = {
1610 "perf report [<options>] <command>", 858 "perf report [<options>] <command>",
1611 NULL 859 NULL
1612}; 860};
@@ -1618,9 +866,10 @@ static const struct option options[] = {
1618 "be more verbose (show symbol address, etc)"), 866 "be more verbose (show symbol address, etc)"),
1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 867 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1620 "dump raw trace in ASCII"), 868 "dump raw trace in ASCII"),
1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 869 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
870 "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 871 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules, 872 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"), 873 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 874 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1626 "Show a column with the number of samples"), 875 "Show a column with the number of samples"),
@@ -1690,9 +939,8 @@ static void setup_list(struct strlist **list, const char *list_str,
1690 939
1691int cmd_report(int argc, const char **argv, const char *prefix __used) 940int cmd_report(int argc, const char **argv, const char *prefix __used)
1692{ 941{
1693 symbol__init(); 942 if (symbol__init(&symbol_conf) < 0)
1694 943 return -1;
1695 page_size = getpagesize();
1696 944
1697 argc = parse_options(argc, argv, options, report_usage, 0); 945 argc = parse_options(argc, argv, options, report_usage, 0);
1698 946
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ce2d5be4f30e..7cca7c15b40a 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -11,8 +11,8 @@
11#include "util/trace-event.h" 11#include "util/trace-event.h"
12 12
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/data_map.h"
14 15
15#include <sys/types.h>
16#include <sys/prctl.h> 16#include <sys/prctl.h>
17 17
18#include <semaphore.h> 18#include <semaphore.h>
@@ -20,14 +20,6 @@
20#include <math.h> 20#include <math.h>
21 21
22static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31 23
32static struct perf_header *header; 24static struct perf_header *header;
33static u64 sample_type; 25static u64 sample_type;
@@ -35,11 +27,11 @@ static u64 sample_type;
35static char default_sort_order[] = "avg, max, switch, runtime"; 27static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order; 28static char *sort_order = default_sort_order;
37 29
30static int profile_cpu = -1;
31
38#define PR_SET_NAME 15 /* Set process name */ 32#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096 33#define MAX_CPUS 4096
40 34
41#define BUG_ON(x) assert(!(x))
42
43static u64 run_measurement_overhead; 35static u64 run_measurement_overhead;
44static u64 sleep_measurement_overhead; 36static u64 sleep_measurement_overhead;
45 37
@@ -74,6 +66,7 @@ enum sched_event_type {
74 SCHED_EVENT_RUN, 66 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP, 67 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP, 68 SCHED_EVENT_WAKEUP,
69 SCHED_EVENT_MIGRATION,
77}; 70};
78 71
79struct sched_atom { 72struct sched_atom {
@@ -147,6 +140,7 @@ struct work_atoms {
147 struct thread *thread; 140 struct thread *thread;
148 struct rb_node node; 141 struct rb_node node;
149 u64 max_lat; 142 u64 max_lat;
143 u64 max_lat_at;
150 u64 total_lat; 144 u64 total_lat;
151 u64 nb_atoms; 145 u64 nb_atoms;
152 u64 total_runtime; 146 u64 total_runtime;
@@ -226,7 +220,7 @@ static void calibrate_sleep_measurement_overhead(void)
226static struct sched_atom * 220static struct sched_atom *
227get_new_event(struct task_desc *task, u64 timestamp) 221get_new_event(struct task_desc *task, u64 timestamp)
228{ 222{
229 struct sched_atom *event = calloc(1, sizeof(*event)); 223 struct sched_atom *event = zalloc(sizeof(*event));
230 unsigned long idx = task->nr_events; 224 unsigned long idx = task->nr_events;
231 size_t size; 225 size_t size;
232 226
@@ -294,7 +288,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
294 return; 288 return;
295 } 289 }
296 290
297 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); 291 wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
298 sem_init(wakee_event->wait_sem, 0, 0); 292 sem_init(wakee_event->wait_sem, 0, 0);
299 wakee_event->specific_wait = 1; 293 wakee_event->specific_wait = 1;
300 event->wait_sem = wakee_event->wait_sem; 294 event->wait_sem = wakee_event->wait_sem;
@@ -324,7 +318,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
324 if (task) 318 if (task)
325 return task; 319 return task;
326 320
327 task = calloc(1, sizeof(*task)); 321 task = zalloc(sizeof(*task));
328 task->pid = pid; 322 task->pid = pid;
329 task->nr = nr_tasks; 323 task->nr = nr_tasks;
330 strcpy(task->comm, comm); 324 strcpy(task->comm, comm);
@@ -398,6 +392,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
398 ret = sem_post(atom->wait_sem); 392 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret); 393 BUG_ON(ret);
400 break; 394 break;
395 case SCHED_EVENT_MIGRATION:
396 break;
401 default: 397 default:
402 BUG_ON(1); 398 BUG_ON(1);
403 } 399 }
@@ -418,34 +414,33 @@ static u64 get_cpu_usage_nsec_parent(void)
418 return sum; 414 return sum;
419} 415}
420 416
421static u64 get_cpu_usage_nsec_self(void) 417static int self_open_counters(void)
422{ 418{
423 char filename [] = "/proc/1234567890/sched"; 419 struct perf_event_attr attr;
424 unsigned long msecs, nsecs; 420 int fd;
425 char *line = NULL;
426 u64 total = 0;
427 size_t len = 0;
428 ssize_t chars;
429 FILE *file;
430 int ret;
431 421
432 sprintf(filename, "/proc/%d/sched", getpid()); 422 memset(&attr, 0, sizeof(attr));
433 file = fopen(filename, "r");
434 BUG_ON(!file);
435 423
436 while ((chars = getline(&line, &len, file)) != -1) { 424 attr.type = PERF_TYPE_SOFTWARE;
437 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", 425 attr.config = PERF_COUNT_SW_TASK_CLOCK;
438 &msecs, &nsecs); 426
439 if (ret == 2) { 427 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
440 total = msecs*1e6 + nsecs; 428
441 break; 429 if (fd < 0)
442 } 430 die("Error: sys_perf_event_open() syscall returned"
443 } 431 "with %d (%s)\n", fd, strerror(errno));
444 if (line) 432 return fd;
445 free(line); 433}
446 fclose(file); 434
435static u64 get_cpu_usage_nsec_self(int fd)
436{
437 u64 runtime;
438 int ret;
439
440 ret = read(fd, &runtime, sizeof(runtime));
441 BUG_ON(ret != sizeof(runtime));
447 442
448 return total; 443 return runtime;
449} 444}
450 445
451static void *thread_func(void *ctx) 446static void *thread_func(void *ctx)
@@ -454,9 +449,11 @@ static void *thread_func(void *ctx)
454 u64 cpu_usage_0, cpu_usage_1; 449 u64 cpu_usage_0, cpu_usage_1;
455 unsigned long i, ret; 450 unsigned long i, ret;
456 char comm2[22]; 451 char comm2[22];
452 int fd;
457 453
458 sprintf(comm2, ":%s", this_task->comm); 454 sprintf(comm2, ":%s", this_task->comm);
459 prctl(PR_SET_NAME, comm2); 455 prctl(PR_SET_NAME, comm2);
456 fd = self_open_counters();
460 457
461again: 458again:
462 ret = sem_post(&this_task->ready_for_work); 459 ret = sem_post(&this_task->ready_for_work);
@@ -466,16 +463,15 @@ again:
466 ret = pthread_mutex_unlock(&start_work_mutex); 463 ret = pthread_mutex_unlock(&start_work_mutex);
467 BUG_ON(ret); 464 BUG_ON(ret);
468 465
469 cpu_usage_0 = get_cpu_usage_nsec_self(); 466 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
470 467
471 for (i = 0; i < this_task->nr_events; i++) { 468 for (i = 0; i < this_task->nr_events; i++) {
472 this_task->curr_event = i; 469 this_task->curr_event = i;
473 process_sched_event(this_task, this_task->atoms[i]); 470 process_sched_event(this_task, this_task->atoms[i]);
474 } 471 }
475 472
476 cpu_usage_1 = get_cpu_usage_nsec_self(); 473 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
477 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 474 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
478
479 ret = sem_post(&this_task->work_done_sem); 475 ret = sem_post(&this_task->work_done_sem);
480 BUG_ON(ret); 476 BUG_ON(ret);
481 477
@@ -632,34 +628,6 @@ static void test_calibrations(void)
632 printf("the sleep test took %Ld nsecs\n", T1-T0); 628 printf("the sleep test took %Ld nsecs\n", T1-T0);
633} 629}
634 630
635static int
636process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{
638 struct thread *thread;
639
640 thread = threads__findnew(event->comm.pid, &threads, &last_match);
641
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head),
644 (void *)(long)(event->header.size),
645 event->comm.comm, event->comm.pid);
646
647 if (thread == NULL ||
648 thread__set_comm(thread, event->comm.comm)) {
649 dump_printf("problem processing perf_event_comm, skipping event.\n");
650 return -1;
651 }
652 total_comm++;
653
654 return 0;
655}
656
657
658struct raw_event_sample {
659 u32 size;
660 char data[0];
661};
662
663#define FILL_FIELD(ptr, field, event, data) \ 631#define FILL_FIELD(ptr, field, event, data) \
664 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) 632 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
665 633
@@ -745,6 +713,22 @@ struct trace_fork_event {
745 u32 child_pid; 713 u32 child_pid;
746}; 714};
747 715
716struct trace_migrate_task_event {
717 u32 size;
718
719 u16 common_type;
720 u8 common_flags;
721 u8 common_preempt_count;
722 u32 common_pid;
723 u32 common_tgid;
724
725 char comm[16];
726 u32 pid;
727
728 u32 prio;
729 u32 cpu;
730};
731
748struct trace_sched_handler { 732struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *, 733 void (*switch_event)(struct trace_switch_event *,
750 struct event *, 734 struct event *,
@@ -769,6 +753,12 @@ struct trace_sched_handler {
769 int cpu, 753 int cpu,
770 u64 timestamp, 754 u64 timestamp,
771 struct thread *thread); 755 struct thread *thread);
756
757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct event *,
759 int cpu,
760 u64 timestamp,
761 struct thread *thread);
772}; 762};
773 763
774 764
@@ -941,9 +931,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
941 931
942static void thread_atoms_insert(struct thread *thread) 932static void thread_atoms_insert(struct thread *thread)
943{ 933{
944 struct work_atoms *atoms; 934 struct work_atoms *atoms = zalloc(sizeof(*atoms));
945
946 atoms = calloc(sizeof(*atoms), 1);
947 if (!atoms) 935 if (!atoms)
948 die("No memory"); 936 die("No memory");
949 937
@@ -975,9 +963,7 @@ add_sched_out_event(struct work_atoms *atoms,
975 char run_state, 963 char run_state,
976 u64 timestamp) 964 u64 timestamp)
977{ 965{
978 struct work_atom *atom; 966 struct work_atom *atom = zalloc(sizeof(*atom));
979
980 atom = calloc(sizeof(*atom), 1);
981 if (!atom) 967 if (!atom)
982 die("Non memory"); 968 die("Non memory");
983 969
@@ -1028,8 +1014,10 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1028 1014
1029 delta = atom->sched_in_time - atom->wake_up_time; 1015 delta = atom->sched_in_time - atom->wake_up_time;
1030 atoms->total_lat += delta; 1016 atoms->total_lat += delta;
1031 if (delta > atoms->max_lat) 1017 if (delta > atoms->max_lat) {
1032 atoms->max_lat = delta; 1018 atoms->max_lat = delta;
1019 atoms->max_lat_at = timestamp;
1020 }
1033 atoms->nb_atoms++; 1021 atoms->nb_atoms++;
1034} 1022}
1035 1023
@@ -1058,8 +1046,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1058 die("hm, delta: %Ld < 0 ?\n", delta); 1046 die("hm, delta: %Ld < 0 ?\n", delta);
1059 1047
1060 1048
1061 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1049 sched_out = threads__findnew(switch_event->prev_pid);
1062 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1050 sched_in = threads__findnew(switch_event->next_pid);
1063 1051
1064 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1052 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1065 if (!out_events) { 1053 if (!out_events) {
@@ -1092,13 +1080,10 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1092 u64 timestamp, 1080 u64 timestamp,
1093 struct thread *this_thread __used) 1081 struct thread *this_thread __used)
1094{ 1082{
1095 struct work_atoms *atoms; 1083 struct thread *thread = threads__findnew(runtime_event->pid);
1096 struct thread *thread; 1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1097 1085
1098 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1099
1100 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1101 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1102 if (!atoms) { 1087 if (!atoms) {
1103 thread_atoms_insert(thread); 1088 thread_atoms_insert(thread);
1104 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1089 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1125,7 +1110,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1125 if (!wakeup_event->success) 1110 if (!wakeup_event->success)
1126 return; 1111 return;
1127 1112
1128 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); 1113 wakee = threads__findnew(wakeup_event->pid);
1129 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1114 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1130 if (!atoms) { 1115 if (!atoms) {
1131 thread_atoms_insert(wakee); 1116 thread_atoms_insert(wakee);
@@ -1139,7 +1124,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1139 1124
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1125 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141 1126
1142 if (atom->state != THREAD_SLEEPING) 1127 /*
1128 * You WILL be missing events if you've recorded only
1129 * one CPU, or are only looking at only one, so don't
1130 * make useless noise.
1131 */
1132 if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++; 1133 nr_state_machine_bugs++;
1144 1134
1145 nr_timestamps++; 1135 nr_timestamps++;
@@ -1152,11 +1142,51 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1152 atom->wake_up_time = timestamp; 1142 atom->wake_up_time = timestamp;
1153} 1143}
1154 1144
1145static void
1146latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1147 struct event *__event __used,
1148 int cpu __used,
1149 u64 timestamp,
1150 struct thread *thread __used)
1151{
1152 struct work_atoms *atoms;
1153 struct work_atom *atom;
1154 struct thread *migrant;
1155
1156 /*
1157 * Only need to worry about migration when profiling one CPU.
1158 */
1159 if (profile_cpu == -1)
1160 return;
1161
1162 migrant = threads__findnew(migrate_task_event->pid);
1163 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1164 if (!atoms) {
1165 thread_atoms_insert(migrant);
1166 register_pid(migrant->pid, migrant->comm);
1167 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1168 if (!atoms)
1169 die("migration-event: Internal tree error");
1170 add_sched_out_event(atoms, 'R', timestamp);
1171 }
1172
1173 BUG_ON(list_empty(&atoms->work_list));
1174
1175 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1176 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1177
1178 nr_timestamps++;
1179
1180 if (atom->sched_out_time > timestamp)
1181 nr_unordered_timestamps++;
1182}
1183
1155static struct trace_sched_handler lat_ops = { 1184static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event, 1185 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event, 1186 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event, 1187 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event, 1188 .fork_event = latency_fork_event,
1189 .migrate_task_event = latency_migrate_task_event,
1160}; 1190};
1161 1191
1162static void output_lat_thread(struct work_atoms *work_list) 1192static void output_lat_thread(struct work_atoms *work_list)
@@ -1183,10 +1213,11 @@ static void output_lat_thread(struct work_atoms *work_list)
1183 1213
1184 avg = work_list->total_lat / work_list->nb_atoms; 1214 avg = work_list->total_lat / work_list->nb_atoms;
1185 1215
1186 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", 1216 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1187 (double)work_list->total_runtime / 1e6, 1217 (double)work_list->total_runtime / 1e6,
1188 work_list->nb_atoms, (double)avg / 1e6, 1218 work_list->nb_atoms, (double)avg / 1e6,
1189 (double)work_list->max_lat / 1e6); 1219 (double)work_list->max_lat / 1e6,
1220 (double)work_list->max_lat_at / 1e9);
1190} 1221}
1191 1222
1192static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1223static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1323,7 +1354,7 @@ static void sort_lat(void)
1323static struct trace_sched_handler *trace_handler; 1354static struct trace_sched_handler *trace_handler;
1324 1355
1325static void 1356static void
1326process_sched_wakeup_event(struct raw_event_sample *raw, 1357process_sched_wakeup_event(void *data,
1327 struct event *event, 1358 struct event *event,
1328 int cpu __used, 1359 int cpu __used,
1329 u64 timestamp __used, 1360 u64 timestamp __used,
@@ -1331,13 +1362,13 @@ process_sched_wakeup_event(struct raw_event_sample *raw,
1331{ 1362{
1332 struct trace_wakeup_event wakeup_event; 1363 struct trace_wakeup_event wakeup_event;
1333 1364
1334 FILL_COMMON_FIELDS(wakeup_event, event, raw->data); 1365 FILL_COMMON_FIELDS(wakeup_event, event, data);
1335 1366
1336 FILL_ARRAY(wakeup_event, comm, event, raw->data); 1367 FILL_ARRAY(wakeup_event, comm, event, data);
1337 FILL_FIELD(wakeup_event, pid, event, raw->data); 1368 FILL_FIELD(wakeup_event, pid, event, data);
1338 FILL_FIELD(wakeup_event, prio, event, raw->data); 1369 FILL_FIELD(wakeup_event, prio, event, data);
1339 FILL_FIELD(wakeup_event, success, event, raw->data); 1370 FILL_FIELD(wakeup_event, success, event, data);
1340 FILL_FIELD(wakeup_event, cpu, event, raw->data); 1371 FILL_FIELD(wakeup_event, cpu, event, data);
1341 1372
1342 if (trace_handler->wakeup_event) 1373 if (trace_handler->wakeup_event)
1343 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1374 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread);
@@ -1385,8 +1416,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1385 die("hm, delta: %Ld < 0 ?\n", delta); 1416 die("hm, delta: %Ld < 0 ?\n", delta);
1386 1417
1387 1418
1388 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1419 sched_out = threads__findnew(switch_event->prev_pid);
1389 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1420 sched_in = threads__findnew(switch_event->next_pid);
1390 1421
1391 curr_thread[this_cpu] = sched_in; 1422 curr_thread[this_cpu] = sched_in;
1392 1423
@@ -1436,7 +1467,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1436 1467
1437 1468
1438static void 1469static void
1439process_sched_switch_event(struct raw_event_sample *raw, 1470process_sched_switch_event(void *data,
1440 struct event *event, 1471 struct event *event,
1441 int this_cpu, 1472 int this_cpu,
1442 u64 timestamp __used, 1473 u64 timestamp __used,
@@ -1444,15 +1475,15 @@ process_sched_switch_event(struct raw_event_sample *raw,
1444{ 1475{
1445 struct trace_switch_event switch_event; 1476 struct trace_switch_event switch_event;
1446 1477
1447 FILL_COMMON_FIELDS(switch_event, event, raw->data); 1478 FILL_COMMON_FIELDS(switch_event, event, data);
1448 1479
1449 FILL_ARRAY(switch_event, prev_comm, event, raw->data); 1480 FILL_ARRAY(switch_event, prev_comm, event, data);
1450 FILL_FIELD(switch_event, prev_pid, event, raw->data); 1481 FILL_FIELD(switch_event, prev_pid, event, data);
1451 FILL_FIELD(switch_event, prev_prio, event, raw->data); 1482 FILL_FIELD(switch_event, prev_prio, event, data);
1452 FILL_FIELD(switch_event, prev_state, event, raw->data); 1483 FILL_FIELD(switch_event, prev_state, event, data);
1453 FILL_ARRAY(switch_event, next_comm, event, raw->data); 1484 FILL_ARRAY(switch_event, next_comm, event, data);
1454 FILL_FIELD(switch_event, next_pid, event, raw->data); 1485 FILL_FIELD(switch_event, next_pid, event, data);
1455 FILL_FIELD(switch_event, next_prio, event, raw->data); 1486 FILL_FIELD(switch_event, next_prio, event, data);
1456 1487
1457 if (curr_pid[this_cpu] != (u32)-1) { 1488 if (curr_pid[this_cpu] != (u32)-1) {
1458 /* 1489 /*
@@ -1469,7 +1500,7 @@ process_sched_switch_event(struct raw_event_sample *raw,
1469} 1500}
1470 1501
1471static void 1502static void
1472process_sched_runtime_event(struct raw_event_sample *raw, 1503process_sched_runtime_event(void *data,
1473 struct event *event, 1504 struct event *event,
1474 int cpu __used, 1505 int cpu __used,
1475 u64 timestamp __used, 1506 u64 timestamp __used,
@@ -1477,17 +1508,17 @@ process_sched_runtime_event(struct raw_event_sample *raw,
1477{ 1508{
1478 struct trace_runtime_event runtime_event; 1509 struct trace_runtime_event runtime_event;
1479 1510
1480 FILL_ARRAY(runtime_event, comm, event, raw->data); 1511 FILL_ARRAY(runtime_event, comm, event, data);
1481 FILL_FIELD(runtime_event, pid, event, raw->data); 1512 FILL_FIELD(runtime_event, pid, event, data);
1482 FILL_FIELD(runtime_event, runtime, event, raw->data); 1513 FILL_FIELD(runtime_event, runtime, event, data);
1483 FILL_FIELD(runtime_event, vruntime, event, raw->data); 1514 FILL_FIELD(runtime_event, vruntime, event, data);
1484 1515
1485 if (trace_handler->runtime_event) 1516 if (trace_handler->runtime_event)
1486 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1517 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread);
1487} 1518}
1488 1519
1489static void 1520static void
1490process_sched_fork_event(struct raw_event_sample *raw, 1521process_sched_fork_event(void *data,
1491 struct event *event, 1522 struct event *event,
1492 int cpu __used, 1523 int cpu __used,
1493 u64 timestamp __used, 1524 u64 timestamp __used,
@@ -1495,12 +1526,12 @@ process_sched_fork_event(struct raw_event_sample *raw,
1495{ 1526{
1496 struct trace_fork_event fork_event; 1527 struct trace_fork_event fork_event;
1497 1528
1498 FILL_COMMON_FIELDS(fork_event, event, raw->data); 1529 FILL_COMMON_FIELDS(fork_event, event, data);
1499 1530
1500 FILL_ARRAY(fork_event, parent_comm, event, raw->data); 1531 FILL_ARRAY(fork_event, parent_comm, event, data);
1501 FILL_FIELD(fork_event, parent_pid, event, raw->data); 1532 FILL_FIELD(fork_event, parent_pid, event, data);
1502 FILL_ARRAY(fork_event, child_comm, event, raw->data); 1533 FILL_ARRAY(fork_event, child_comm, event, data);
1503 FILL_FIELD(fork_event, child_pid, event, raw->data); 1534 FILL_FIELD(fork_event, child_pid, event, data);
1504 1535
1505 if (trace_handler->fork_event) 1536 if (trace_handler->fork_event)
1506 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1537 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread);
@@ -1517,233 +1548,126 @@ process_sched_exit_event(struct event *event,
1517} 1548}
1518 1549
1519static void 1550static void
1520process_raw_event(event_t *raw_event __used, void *more_data, 1551process_sched_migrate_task_event(void *data,
1552 struct event *event,
1553 int cpu __used,
1554 u64 timestamp __used,
1555 struct thread *thread __used)
1556{
1557 struct trace_migrate_task_event migrate_task_event;
1558
1559 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1560
1561 FILL_ARRAY(migrate_task_event, comm, event, data);
1562 FILL_FIELD(migrate_task_event, pid, event, data);
1563 FILL_FIELD(migrate_task_event, prio, event, data);
1564 FILL_FIELD(migrate_task_event, cpu, event, data);
1565
1566 if (trace_handler->migrate_task_event)
1567 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread);
1568}
1569
1570static void
1571process_raw_event(event_t *raw_event __used, void *data,
1521 int cpu, u64 timestamp, struct thread *thread) 1572 int cpu, u64 timestamp, struct thread *thread)
1522{ 1573{
1523 struct raw_event_sample *raw = more_data;
1524 struct event *event; 1574 struct event *event;
1525 int type; 1575 int type;
1526 1576
1527 type = trace_parse_common_type(raw->data); 1577
1578 type = trace_parse_common_type(data);
1528 event = trace_find_event(type); 1579 event = trace_find_event(type);
1529 1580
1530 if (!strcmp(event->name, "sched_switch")) 1581 if (!strcmp(event->name, "sched_switch"))
1531 process_sched_switch_event(raw, event, cpu, timestamp, thread); 1582 process_sched_switch_event(data, event, cpu, timestamp, thread);
1532 if (!strcmp(event->name, "sched_stat_runtime")) 1583 if (!strcmp(event->name, "sched_stat_runtime"))
1533 process_sched_runtime_event(raw, event, cpu, timestamp, thread); 1584 process_sched_runtime_event(data, event, cpu, timestamp, thread);
1534 if (!strcmp(event->name, "sched_wakeup")) 1585 if (!strcmp(event->name, "sched_wakeup"))
1535 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1586 process_sched_wakeup_event(data, event, cpu, timestamp, thread);
1536 if (!strcmp(event->name, "sched_wakeup_new")) 1587 if (!strcmp(event->name, "sched_wakeup_new"))
1537 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1588 process_sched_wakeup_event(data, event, cpu, timestamp, thread);
1538 if (!strcmp(event->name, "sched_process_fork")) 1589 if (!strcmp(event->name, "sched_process_fork"))
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1590 process_sched_fork_event(data, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit")) 1591 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread); 1592 process_sched_exit_event(event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_migrate_task"))
1594 process_sched_migrate_task_event(data, event, cpu, timestamp, thread);
1542} 1595}
1543 1596
1544static int 1597static int process_sample_event(event_t *event)
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{ 1598{
1547 char level; 1599 struct sample_data data;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread; 1600 struct thread *thread;
1551 u64 ip = event->ip.ip;
1552 u64 timestamp = -1;
1553 u32 cpu = -1;
1554 u64 period = 1;
1555 void *more_data = event->ip.__more_data;
1556 int cpumode;
1557
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559
1560 if (sample_type & PERF_SAMPLE_TIME) {
1561 timestamp = *(u64 *)more_data;
1562 more_data += sizeof(u64);
1563 }
1564 1601
1565 if (sample_type & PERF_SAMPLE_CPU) { 1602 if (!(sample_type & PERF_SAMPLE_RAW))
1566 cpu = *(u32 *)more_data; 1603 return 0;
1567 more_data += sizeof(u32);
1568 more_data += sizeof(u32); /* reserved */
1569 }
1570 1604
1571 if (sample_type & PERF_SAMPLE_PERIOD) { 1605 memset(&data, 0, sizeof(data));
1572 period = *(u64 *)more_data; 1606 data.time = -1;
1573 more_data += sizeof(u64); 1607 data.cpu = -1;
1574 } 1608 data.period = -1;
1575 1609
1576 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 1610 event__parse_sample(event, sample_type, &data);
1577 (void *)(offset + head),
1578 (void *)(long)(event->header.size),
1579 event->header.misc,
1580 event->ip.pid, event->ip.tid,
1581 (void *)(long)ip,
1582 (long long)period);
1583 1611
1584 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1612 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1613 event->header.misc,
1614 data.pid, data.tid,
1615 (void *)(long)data.ip,
1616 (long long)data.period);
1585 1617
1618 thread = threads__findnew(data.pid);
1586 if (thread == NULL) { 1619 if (thread == NULL) {
1587 eprintf("problem processing %d event, skipping it.\n", 1620 pr_debug("problem processing %d event, skipping it.\n",
1588 event->header.type); 1621 event->header.type);
1589 return -1; 1622 return -1;
1590 } 1623 }
1591 1624
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1625 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1593
1594 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1595 show = SHOW_KERNEL;
1596 level = 'k';
1597
1598 dso = kernel_dso;
1599
1600 dump_printf(" ...... dso: %s\n", dso->name);
1601
1602 } else if (cpumode == PERF_RECORD_MISC_USER) {
1603
1604 show = SHOW_USER;
1605 level = '.';
1606
1607 } else {
1608 show = SHOW_HV;
1609 level = 'H';
1610
1611 dso = hypervisor_dso;
1612 1626
1613 dump_printf(" ...... dso: [hypervisor]\n"); 1627 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1614 } 1628 return 0;
1615 1629
1616 if (sample_type & PERF_SAMPLE_RAW) 1630 process_raw_event(event, data.raw_data, data.cpu, data.time, thread);
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618 1631
1619 return 0; 1632 return 0;
1620} 1633}
1621 1634
1622static int 1635static int process_lost_event(event_t *event __used)
1623process_event(event_t *event, unsigned long offset, unsigned long head)
1624{ 1636{
1625 trace_event(event); 1637 nr_lost_chunks++;
1638 nr_lost_events += event->lost.lost;
1626 1639
1627 nr_events++; 1640 return 0;
1628 switch (event->header.type) { 1641}
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635
1636 case PERF_RECORD_COMM:
1637 return process_comm_event(event, offset, head);
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641 1642
1642 case PERF_RECORD_SAMPLE: 1643static int sample_type_check(u64 type)
1643 return process_sample_event(event, offset, head); 1644{
1645 sample_type = type;
1644 1646
1645 case PERF_RECORD_MAX: 1647 if (!(sample_type & PERF_SAMPLE_RAW)) {
1646 default: 1648 fprintf(stderr,
1649 "No trace sample to read. Did you call perf record "
1650 "without -R?");
1647 return -1; 1651 return -1;
1648 } 1652 }
1649 1653
1650 return 0; 1654 return 0;
1651} 1655}
1652 1656
1657static struct perf_file_handler file_handler = {
1658 .process_sample_event = process_sample_event,
1659 .process_comm_event = event__process_comm,
1660 .process_lost_event = process_lost_event,
1661 .sample_type_check = sample_type_check,
1662};
1663
1653static int read_events(void) 1664static int read_events(void)
1654{ 1665{
1655 int ret, rc = EXIT_FAILURE; 1666 register_idle_thread();
1656 unsigned long offset = 0; 1667 register_perf_file_handler(&file_handler);
1657 unsigned long head = 0;
1658 struct stat perf_stat;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match);
1665
1666 input = open(input_name, O_RDONLY);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721 1668
1722 size = event->header.size; 1669 return mmap_dispatch_perf_file(&header, input_name, 0, 0,
1723 1670 &event__cwdlen, &event__cwd);
1724
1725 if (!size || process_event(event, offset, head) < 0) {
1726
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745
1746 return rc;
1747} 1671}
1748 1672
1749static void print_bad_events(void) 1673static void print_bad_events(void)
@@ -1784,9 +1708,9 @@ static void __cmd_lat(void)
1784 read_events(); 1708 read_events();
1785 sort_lat(); 1709 sort_lat();
1786 1710
1787 printf("\n -----------------------------------------------------------------------------------------\n"); 1711 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1712 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n"); 1713 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1790 1714
1791 next = rb_first(&sorted_atom_root); 1715 next = rb_first(&sorted_atom_root);
1792 1716
@@ -1883,6 +1807,8 @@ static const struct option latency_options[] = {
1883 "sort by key(s): runtime, switch, avg, max"), 1807 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose, 1808 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"), 1809 "be more verbose (show symbol address, etc)"),
1810 OPT_INTEGER('C', "CPU", &profile_cpu,
1811 "CPU to profile on"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1812 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"), 1813 "dump raw trace in ASCII"),
1888 OPT_END() 1814 OPT_END()
@@ -1960,14 +1886,18 @@ static int __cmd_record(int argc, const char **argv)
1960 1886
1961int cmd_sched(int argc, const char **argv, const char *prefix __used) 1887int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{ 1888{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage, 1889 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION); 1890 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc) 1891 if (!argc)
1969 usage_with_options(sched_usage, sched_options); 1892 usage_with_options(sched_usage, sched_options);
1970 1893
1894 /*
1895 * Aliased to 'perf trace' for now:
1896 */
1897 if (!strcmp(argv[0], "trace"))
1898 return cmd_trace(argc, argv, prefix);
1899
1900 symbol__init(0);
1971 if (!strncmp(argv[0], "rec", 3)) { 1901 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv); 1902 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) { 1903 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1991,11 +1921,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1991 usage_with_options(replay_usage, replay_options); 1921 usage_with_options(replay_usage, replay_options);
1992 } 1922 }
1993 __cmd_replay(); 1923 __cmd_replay();
1994 } else if (!strcmp(argv[0], "trace")) {
1995 /*
1996 * Aliased to 'perf trace' for now:
1997 */
1998 return cmd_trace(argc, argv, prefix);
1999 } else { 1924 } else {
2000 usage_with_options(sched_usage, sched_options); 1925 usage_with_options(sched_usage, sched_options);
2001 } 1926 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 3db31e7bf173..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 e8a510d935e5..f472df9561ee 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;
@@ -293,12 +302,11 @@ process_exit_event(event_t *event)
293} 302}
294 303
295struct trace_entry { 304struct trace_entry {
296 u32 size;
297 unsigned short type; 305 unsigned short type;
298 unsigned char flags; 306 unsigned char flags;
299 unsigned char preempt_count; 307 unsigned char preempt_count;
300 int pid; 308 int pid;
301 int tgid; 309 int lock_depth;
302}; 310};
303 311
304struct power_entry { 312struct power_entry {
@@ -475,43 +483,22 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
475static int 483static int
476process_sample_event(event_t *event) 484process_sample_event(event_t *event)
477{ 485{
478 int cursor = 0; 486 struct sample_data data;
479 u64 addr = 0;
480 u64 stamp = 0;
481 u32 cpu = 0;
482 u32 pid = 0;
483 struct trace_entry *te; 487 struct trace_entry *te;
484 488
485 if (sample_type & PERF_SAMPLE_IP) 489 memset(&data, 0, sizeof(data));
486 cursor++;
487
488 if (sample_type & PERF_SAMPLE_TID) {
489 pid = event->sample.array[cursor]>>32;
490 cursor++;
491 }
492 if (sample_type & PERF_SAMPLE_TIME) {
493 stamp = event->sample.array[cursor++];
494 490
495 if (!first_time || first_time > stamp) 491 event__parse_sample(event, sample_type, &data);
496 first_time = stamp;
497 if (last_time < stamp)
498 last_time = stamp;
499 492
493 if (sample_type & PERF_SAMPLE_TIME) {
494 if (!first_time || first_time > data.time)
495 first_time = data.time;
496 if (last_time < data.time)
497 last_time = data.time;
500 } 498 }
501 if (sample_type & PERF_SAMPLE_ADDR)
502 addr = event->sample.array[cursor++];
503 if (sample_type & PERF_SAMPLE_ID)
504 cursor++;
505 if (sample_type & PERF_SAMPLE_STREAM_ID)
506 cursor++;
507 if (sample_type & PERF_SAMPLE_CPU)
508 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
509 if (sample_type & PERF_SAMPLE_PERIOD)
510 cursor++;
511
512 te = (void *)&event->sample.array[cursor];
513 499
514 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { 500 te = (void *)data.raw_data;
501 if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
515 char *event_str; 502 char *event_str;
516 struct power_entry *pe; 503 struct power_entry *pe;
517 504
@@ -523,19 +510,19 @@ process_sample_event(event_t *event)
523 return 0; 510 return 0;
524 511
525 if (strcmp(event_str, "power:power_start") == 0) 512 if (strcmp(event_str, "power:power_start") == 0)
526 c_state_start(cpu, stamp, pe->value); 513 c_state_start(data.cpu, data.time, pe->value);
527 514
528 if (strcmp(event_str, "power:power_end") == 0) 515 if (strcmp(event_str, "power:power_end") == 0)
529 c_state_end(cpu, stamp); 516 c_state_end(data.cpu, data.time);
530 517
531 if (strcmp(event_str, "power:power_frequency") == 0) 518 if (strcmp(event_str, "power:power_frequency") == 0)
532 p_state_change(cpu, stamp, pe->value); 519 p_state_change(data.cpu, data.time, pe->value);
533 520
534 if (strcmp(event_str, "sched:sched_wakeup") == 0) 521 if (strcmp(event_str, "sched:sched_wakeup") == 0)
535 sched_wakeup(cpu, stamp, pid, te); 522 sched_wakeup(data.cpu, data.time, data.pid, te);
536 523
537 if (strcmp(event_str, "sched:sched_switch") == 0) 524 if (strcmp(event_str, "sched:sched_switch") == 0)
538 sched_switch(cpu, stamp, te); 525 sched_switch(data.cpu, data.time, te);
539 } 526 }
540 return 0; 527 return 0;
541} 528}
@@ -763,11 +750,11 @@ static void draw_wakeups(void)
763 c = p->all; 750 c = p->all;
764 while (c) { 751 while (c) {
765 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { 752 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
766 if (p->pid == we->waker) { 753 if (p->pid == we->waker && !from) {
767 from = c->Y; 754 from = c->Y;
768 task_from = strdup(c->comm); 755 task_from = strdup(c->comm);
769 } 756 }
770 if (p->pid == we->wakee) { 757 if (p->pid == we->wakee && !to) {
771 to = c->Y; 758 to = c->Y;
772 task_to = strdup(c->comm); 759 task_to = strdup(c->comm);
773 } 760 }
@@ -882,12 +869,89 @@ static void draw_process_bars(void)
882 } 869 }
883} 870}
884 871
872static void add_process_filter(const char *string)
873{
874 struct process_filter *filt;
875 int pid;
876
877 pid = strtoull(string, NULL, 10);
878 filt = malloc(sizeof(struct process_filter));
879 if (!filt)
880 return;
881
882 filt->name = strdup(string);
883 filt->pid = pid;
884 filt->next = process_filter;
885
886 process_filter = filt;
887}
888
889static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
890{
891 struct process_filter *filt;
892 if (!process_filter)
893 return 1;
894
895 filt = process_filter;
896 while (filt) {
897 if (filt->pid && p->pid == filt->pid)
898 return 1;
899 if (strcmp(filt->name, c->comm) == 0)
900 return 1;
901 filt = filt->next;
902 }
903 return 0;
904}
905
906static int determine_display_tasks_filtered(void)
907{
908 struct per_pid *p;
909 struct per_pidcomm *c;
910 int count = 0;
911
912 p = all_data;
913 while (p) {
914 p->display = 0;
915 if (p->start_time == 1)
916 p->start_time = first_time;
917
918 /* no exit marker, task kept running to the end */
919 if (p->end_time == 0)
920 p->end_time = last_time;
921
922 c = p->all;
923
924 while (c) {
925 c->display = 0;
926
927 if (c->start_time == 1)
928 c->start_time = first_time;
929
930 if (passes_filter(p, c)) {
931 c->display = 1;
932 p->display = 1;
933 count++;
934 }
935
936 if (c->end_time == 0)
937 c->end_time = last_time;
938
939 c = c->next;
940 }
941 p = p->next;
942 }
943 return count;
944}
945
885static int determine_display_tasks(u64 threshold) 946static int determine_display_tasks(u64 threshold)
886{ 947{
887 struct per_pid *p; 948 struct per_pid *p;
888 struct per_pidcomm *c; 949 struct per_pidcomm *c;
889 int count = 0; 950 int count = 0;
890 951
952 if (process_filter)
953 return determine_display_tasks_filtered();
954
891 p = all_data; 955 p = all_data;
892 while (p) { 956 while (p) {
893 p->display = 0; 957 p->display = 0;
@@ -957,36 +1021,6 @@ static void write_svg_file(const char *filename)
957 svg_close(); 1021 svg_close();
958} 1022}
959 1023
960static int
961process_event(event_t *event)
962{
963
964 switch (event->header.type) {
965
966 case PERF_RECORD_COMM:
967 return process_comm_event(event);
968 case PERF_RECORD_FORK:
969 return process_fork_event(event);
970 case PERF_RECORD_EXIT:
971 return process_exit_event(event);
972 case PERF_RECORD_SAMPLE:
973 return queue_sample_event(event);
974
975 /*
976 * We dont process them right now but they are fine:
977 */
978 case PERF_RECORD_MMAP:
979 case PERF_RECORD_THROTTLE:
980 case PERF_RECORD_UNTHROTTLE:
981 return 0;
982
983 default:
984 return -1;
985 }
986
987 return 0;
988}
989
990static void process_samples(void) 1024static void process_samples(void)
991{ 1025{
992 struct sample_wrapper *cursor; 1026 struct sample_wrapper *cursor;
@@ -1002,107 +1036,38 @@ static void process_samples(void)
1002 } 1036 }
1003} 1037}
1004 1038
1005 1039static int sample_type_check(u64 type)
1006static int __cmd_timechart(void)
1007{ 1040{
1008 int ret, rc = EXIT_FAILURE; 1041 sample_type = type;
1009 unsigned long offset = 0;
1010 unsigned long head, shift;
1011 struct stat statbuf;
1012 event_t *event;
1013 uint32_t size;
1014 char *buf;
1015 int input;
1016
1017 input = open(input_name, O_RDONLY);
1018 if (input < 0) {
1019 fprintf(stderr, " failed to open file: %s", input_name);
1020 if (!strcmp(input_name, "perf.data"))
1021 fprintf(stderr, " (try 'perf record' first)");
1022 fprintf(stderr, "\n");
1023 exit(-1);
1024 }
1025 1042
1026 ret = fstat(input, &statbuf); 1043 if (!(sample_type & PERF_SAMPLE_RAW)) {
1027 if (ret < 0) { 1044 fprintf(stderr, "No trace samples found in the file.\n"
1028 perror("failed to stat file"); 1045 "Have you used 'perf timechart record' to record it?\n");
1029 exit(-1); 1046 return -1;
1030 }
1031
1032 if (!statbuf.st_size) {
1033 fprintf(stderr, "zero-sized file, nothing to do!\n");
1034 exit(0);
1035 }
1036
1037 header = perf_header__read(input);
1038 head = header->data_offset;
1039
1040 sample_type = perf_header__sample_type(header);
1041
1042 shift = page_size * (head / page_size);
1043 offset += shift;
1044 head -= shift;
1045
1046remap:
1047 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1048 MAP_SHARED, input, offset);
1049 if (buf == MAP_FAILED) {
1050 perror("failed to mmap file");
1051 exit(-1);
1052 }
1053
1054more:
1055 event = (event_t *)(buf + head);
1056
1057 size = event->header.size;
1058 if (!size)
1059 size = 8;
1060
1061 if (head + event->header.size >= page_size * mmap_window) {
1062 int ret2;
1063
1064 shift = page_size * (head / page_size);
1065
1066 ret2 = munmap(buf, page_size * mmap_window);
1067 assert(ret2 == 0);
1068
1069 offset += shift;
1070 head -= shift;
1071 goto remap;
1072 }
1073
1074 size = event->header.size;
1075
1076 if (!size || process_event(event) < 0) {
1077
1078 printf("%p [%p]: skipping unknown header type: %d\n",
1079 (void *)(offset + head),
1080 (void *)(long)(event->header.size),
1081 event->header.type);
1082
1083 /*
1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087
1088 if (unlikely(head & 7))
1089 head &= ~7ULL;
1090
1091 size = 8;
1092 } 1047 }
1093 1048
1094 head += size; 1049 return 0;
1050}
1095 1051
1096 if (offset + head >= header->data_offset + header->data_size) 1052static struct perf_file_handler file_handler = {
1097 goto done; 1053 .process_comm_event = process_comm_event,
1054 .process_fork_event = process_fork_event,
1055 .process_exit_event = process_exit_event,
1056 .process_sample_event = queue_sample_event,
1057 .sample_type_check = sample_type_check,
1058};
1098 1059
1099 if (offset + head < (unsigned long)statbuf.st_size) 1060static int __cmd_timechart(void)
1100 goto more; 1061{
1062 struct perf_header *header;
1063 int ret;
1101 1064
1102done: 1065 register_perf_file_handler(&file_handler);
1103 rc = EXIT_SUCCESS;
1104 close(input);
1105 1066
1067 ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
1068 &event__cwdlen, &event__cwd);
1069 if (ret)
1070 return EXIT_FAILURE;
1106 1071
1107 process_samples(); 1072 process_samples();
1108 1073
@@ -1112,9 +1077,10 @@ done:
1112 1077
1113 write_svg_file(output_name); 1078 write_svg_file(output_name);
1114 1079
1115 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1080 pr_info("Written %2.1f seconds of trace to %s.\n",
1081 (last_time - first_time) / 1000000000.0, output_name);
1116 1082
1117 return rc; 1083 return EXIT_SUCCESS;
1118} 1084}
1119 1085
1120static const char * const timechart_usage[] = { 1086static const char * const timechart_usage[] = {
@@ -1153,6 +1119,14 @@ static int __cmd_record(int argc, const char **argv)
1153 return cmd_record(i, rec_argv, NULL); 1119 return cmd_record(i, rec_argv, NULL);
1154} 1120}
1155 1121
1122static int
1123parse_process(const struct option *opt __used, const char *arg, int __used unset)
1124{
1125 if (arg)
1126 add_process_filter(arg);
1127 return 0;
1128}
1129
1156static const struct option options[] = { 1130static const struct option options[] = {
1157 OPT_STRING('i', "input", &input_name, "file", 1131 OPT_STRING('i', "input", &input_name, "file",
1158 "input file name"), 1132 "input file name"),
@@ -1160,17 +1134,18 @@ static const struct option options[] = {
1160 "output file name"), 1134 "output file name"),
1161 OPT_INTEGER('w', "width", &svg_page_width, 1135 OPT_INTEGER('w', "width", &svg_page_width,
1162 "page width"), 1136 "page width"),
1163 OPT_BOOLEAN('p', "power-only", &power_only, 1137 OPT_BOOLEAN('P', "power-only", &power_only,
1164 "output power data only"), 1138 "output power data only"),
1139 OPT_CALLBACK('p', "process", NULL, "process",
1140 "process selector. Pass a pid or process name.",
1141 parse_process),
1165 OPT_END() 1142 OPT_END()
1166}; 1143};
1167 1144
1168 1145
1169int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1146int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1170{ 1147{
1171 symbol__init(); 1148 symbol__init(0);
1172
1173 page_size = getpagesize();
1174 1149
1175 argc = parse_options(argc, argv, options, timechart_usage, 1150 argc = parse_options(argc, argv, options, timechart_usage,
1176 PARSE_OPT_STOP_AT_NON_OPTION); 1151 PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e23bc74e734f..e0a374d0e43a 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -22,6 +22,7 @@
22 22
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/color.h" 24#include "util/color.h"
25#include "util/thread.h"
25#include "util/util.h" 26#include "util/util.h"
26#include <linux/rbtree.h> 27#include <linux/rbtree.h>
27#include "util/parse-options.h" 28#include "util/parse-options.h"
@@ -54,26 +55,31 @@
54 55
55static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 56static int fd[MAX_NR_CPUS][MAX_COUNTERS];
56 57
57static int system_wide = 0; 58static int system_wide = 0;
58 59
59static int default_interval = 100000; 60static int default_interval = 0;
60 61
61static int count_filter = 5; 62static int count_filter = 5;
62static int print_entries = 15; 63static int print_entries;
63 64
64static int target_pid = -1; 65static int target_pid = -1;
65static int inherit = 0; 66static int inherit = 0;
66static int profile_cpu = -1; 67static int profile_cpu = -1;
67static int nr_cpus = 0; 68static int nr_cpus = 0;
68static unsigned int realtime_prio = 0; 69static unsigned int realtime_prio = 0;
69static int group = 0; 70static int group = 0;
70static unsigned int page_size; 71static unsigned int page_size;
71static unsigned int mmap_pages = 16; 72static unsigned int mmap_pages = 16;
72static int freq = 0; 73static int freq = 1000; /* 1 KHz */
73 74
74static int delay_secs = 2; 75static int delay_secs = 2;
75static int zero; 76static int zero = 0;
76static int dump_symtab; 77static int dump_symtab = 0;
78
79static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false;
81static struct winsize winsize;
82struct symbol_conf symbol_conf;
77 83
78/* 84/*
79 * Source 85 * Source
@@ -86,83 +92,126 @@ struct source_line {
86 struct source_line *next; 92 struct source_line *next;
87}; 93};
88 94
89static char *sym_filter = NULL; 95static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL; 96struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5; 97static int sym_pcnt_filter = 5;
92static int sym_counter = 0; 98static int sym_counter = 0;
93static int display_weighted = -1; 99static int display_weighted = -1;
94 100
95/* 101/*
96 * Symbols 102 * Symbols
97 */ 103 */
98 104
99static u64 min_ip; 105struct sym_entry_source {
100static u64 max_ip = -1ll; 106 struct source_line *source;
107 struct source_line *lines;
108 struct source_line **lines_tail;
109 pthread_mutex_t lock;
110};
101 111
102struct sym_entry { 112struct sym_entry {
103 struct rb_node rb_node; 113 struct rb_node rb_node;
104 struct list_head node; 114 struct list_head node;
105 unsigned long count[MAX_COUNTERS];
106 unsigned long snap_count; 115 unsigned long snap_count;
107 double weight; 116 double weight;
108 int skip; 117 int skip;
109 struct source_line *source; 118 u16 name_len;
110 struct source_line *lines; 119 u8 origin;
111 struct source_line **lines_tail; 120 struct map *map;
112 pthread_mutex_t source_lock; 121 struct sym_entry_source *src;
122 unsigned long count[0];
113}; 123};
114 124
115/* 125/*
116 * Source functions 126 * Source functions
117 */ 127 */
118 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
119static void parse_source(struct sym_entry *syme) 170static void parse_source(struct sym_entry *syme)
120{ 171{
121 struct symbol *sym; 172 struct symbol *sym;
122 struct module *module; 173 struct sym_entry_source *source;
123 struct section *section = NULL; 174 struct map *map;
124 FILE *file; 175 FILE *file;
125 char command[PATH_MAX*2]; 176 char command[PATH_MAX*2];
126 const char *path = vmlinux_name; 177 const char *path;
127 u64 start, end, len; 178 u64 len;
128 179
129 if (!syme) 180 if (!syme)
130 return; 181 return;
131 182
132 if (syme->lines) { 183 if (syme->src == NULL) {
133 pthread_mutex_lock(&syme->source_lock); 184 syme->src = zalloc(sizeof(*source));
134 goto out_assign; 185 if (syme->src == NULL)
186 return;
187 pthread_mutex_init(&syme->src->lock, NULL);
135 } 188 }
136 189
137 sym = (struct symbol *)(syme + 1); 190 source = syme->src;
138 module = sym->module;
139
140 if (module)
141 path = module->path;
142 if (!path)
143 return;
144
145 start = sym->obj_start;
146 if (!start)
147 start = sym->start;
148 191
149 if (module) { 192 if (source->lines) {
150 section = module->sections->find_section(module->sections, ".text"); 193 pthread_mutex_lock(&source->lock);
151 if (section) 194 goto out_assign;
152 start -= section->vma;
153 } 195 }
154 196
155 end = start + sym->end - sym->start + 1; 197 sym = sym_entry__symbol(syme);
198 map = syme->map;
199 path = map->dso->long_name;
200
156 len = sym->end - sym->start; 201 len = sym->end - sym->start;
157 202
158 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); 203 sprintf(command,
204 "objdump --start-address=0x%016Lx "
205 "--stop-address=0x%016Lx -dS %s",
206 map->unmap_ip(map, sym->start),
207 map->unmap_ip(map, sym->end), path);
159 208
160 file = popen(command, "r"); 209 file = popen(command, "r");
161 if (!file) 210 if (!file)
162 return; 211 return;
163 212
164 pthread_mutex_lock(&syme->source_lock); 213 pthread_mutex_lock(&source->lock);
165 syme->lines_tail = &syme->lines; 214 source->lines_tail = &source->lines;
166 while (!feof(file)) { 215 while (!feof(file)) {
167 struct source_line *src; 216 struct source_line *src;
168 size_t dummy = 0; 217 size_t dummy = 0;
@@ -182,24 +231,22 @@ static void parse_source(struct sym_entry *syme)
182 *c = 0; 231 *c = 0;
183 232
184 src->next = NULL; 233 src->next = NULL;
185 *syme->lines_tail = src; 234 *source->lines_tail = src;
186 syme->lines_tail = &src->next; 235 source->lines_tail = &src->next;
187 236
188 if (strlen(src->line)>8 && src->line[8] == ':') { 237 if (strlen(src->line)>8 && src->line[8] == ':') {
189 src->eip = strtoull(src->line, NULL, 16); 238 src->eip = strtoull(src->line, NULL, 16);
190 if (section) 239 src->eip = map->unmap_ip(map, src->eip);
191 src->eip += section->vma;
192 } 240 }
193 if (strlen(src->line)>8 && src->line[16] == ':') { 241 if (strlen(src->line)>8 && src->line[16] == ':') {
194 src->eip = strtoull(src->line, NULL, 16); 242 src->eip = strtoull(src->line, NULL, 16);
195 if (section) 243 src->eip = map->unmap_ip(map, src->eip);
196 src->eip += section->vma;
197 } 244 }
198 } 245 }
199 pclose(file); 246 pclose(file);
200out_assign: 247out_assign:
201 sym_filter_entry = syme; 248 sym_filter_entry = syme;
202 pthread_mutex_unlock(&syme->source_lock); 249 pthread_mutex_unlock(&source->lock);
203} 250}
204 251
205static void __zero_source_counters(struct sym_entry *syme) 252static void __zero_source_counters(struct sym_entry *syme)
@@ -207,7 +254,7 @@ static void __zero_source_counters(struct sym_entry *syme)
207 int i; 254 int i;
208 struct source_line *line; 255 struct source_line *line;
209 256
210 line = syme->lines; 257 line = syme->src->lines;
211 while (line) { 258 while (line) {
212 for (i = 0; i < nr_counters; i++) 259 for (i = 0; i < nr_counters; i++)
213 line->count[i] = 0; 260 line->count[i] = 0;
@@ -222,13 +269,13 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
222 if (syme != sym_filter_entry) 269 if (syme != sym_filter_entry)
223 return; 270 return;
224 271
225 if (pthread_mutex_trylock(&syme->source_lock)) 272 if (pthread_mutex_trylock(&syme->src->lock))
226 return; 273 return;
227 274
228 if (!syme->source) 275 if (syme->src == NULL || syme->src->source == NULL)
229 goto out_unlock; 276 goto out_unlock;
230 277
231 for (line = syme->lines; line; line = line->next) { 278 for (line = syme->src->lines; line; line = line->next) {
232 if (line->eip == ip) { 279 if (line->eip == ip) {
233 line->count[counter]++; 280 line->count[counter]++;
234 break; 281 break;
@@ -237,32 +284,25 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
237 break; 284 break;
238 } 285 }
239out_unlock: 286out_unlock:
240 pthread_mutex_unlock(&syme->source_lock); 287 pthread_mutex_unlock(&syme->src->lock);
241} 288}
242 289
243static void lookup_sym_source(struct sym_entry *syme) 290static void lookup_sym_source(struct sym_entry *syme)
244{ 291{
245 struct symbol *symbol = (struct symbol *)(syme + 1); 292 struct symbol *symbol = sym_entry__symbol(syme);
246 struct source_line *line; 293 struct source_line *line;
247 char pattern[PATH_MAX]; 294 char pattern[PATH_MAX];
248 char *idx;
249 295
250 sprintf(pattern, "<%s>:", symbol->name); 296 sprintf(pattern, "<%s>:", symbol->name);
251 297
252 if (symbol->module) { 298 pthread_mutex_lock(&syme->src->lock);
253 idx = strstr(pattern, "\t"); 299 for (line = syme->src->lines; line; line = line->next) {
254 if (idx)
255 *idx = 0;
256 }
257
258 pthread_mutex_lock(&syme->source_lock);
259 for (line = syme->lines; line; line = line->next) {
260 if (strstr(line->line, pattern)) { 300 if (strstr(line->line, pattern)) {
261 syme->source = line; 301 syme->src->source = line;
262 break; 302 break;
263 } 303 }
264 } 304 }
265 pthread_mutex_unlock(&syme->source_lock); 305 pthread_mutex_unlock(&syme->src->lock);
266} 306}
267 307
268static void show_lines(struct source_line *queue, int count, int total) 308static void show_lines(struct source_line *queue, int count, int total)
@@ -292,24 +332,24 @@ static void show_details(struct sym_entry *syme)
292 if (!syme) 332 if (!syme)
293 return; 333 return;
294 334
295 if (!syme->source) 335 if (!syme->src->source)
296 lookup_sym_source(syme); 336 lookup_sym_source(syme);
297 337
298 if (!syme->source) 338 if (!syme->src->source)
299 return; 339 return;
300 340
301 symbol = (struct symbol *)(syme + 1); 341 symbol = sym_entry__symbol(syme);
302 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);
303 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 343 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
304 344
305 pthread_mutex_lock(&syme->source_lock); 345 pthread_mutex_lock(&syme->src->lock);
306 line = syme->source; 346 line = syme->src->source;
307 while (line) { 347 while (line) {
308 total += line->count[sym_counter]; 348 total += line->count[sym_counter];
309 line = line->next; 349 line = line->next;
310 } 350 }
311 351
312 line = syme->source; 352 line = syme->src->source;
313 while (line) { 353 while (line) {
314 float pcnt = 0.0; 354 float pcnt = 0.0;
315 355
@@ -334,13 +374,13 @@ static void show_details(struct sym_entry *syme)
334 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;
335 line = line->next; 375 line = line->next;
336 } 376 }
337 pthread_mutex_unlock(&syme->source_lock); 377 pthread_mutex_unlock(&syme->src->lock);
338 if (more) 378 if (more)
339 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);
340} 380}
341 381
342/* 382/*
343 * 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
344 * after decayed. 384 * after decayed.
345 */ 385 */
346static LIST_HEAD(active_symbols); 386static LIST_HEAD(active_symbols);
@@ -411,6 +451,8 @@ static void print_sym_table(void)
411 struct sym_entry *syme, *n; 451 struct sym_entry *syme, *n;
412 struct rb_root tmp = RB_ROOT; 452 struct rb_root tmp = RB_ROOT;
413 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;
414 456
415 samples = userspace_samples = 0; 457 samples = userspace_samples = 0;
416 458
@@ -422,6 +464,14 @@ static void print_sym_table(void)
422 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 464 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
423 syme->snap_count = syme->count[snap]; 465 syme->snap_count = syme->count[snap];
424 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 }
425 syme->weight = sym_weight(syme); 475 syme->weight = sym_weight(syme);
426 rb_insert_active_sym(&tmp, syme); 476 rb_insert_active_sym(&tmp, syme);
427 sum_ksamples += syme->snap_count; 477 sum_ksamples += syme->snap_count;
@@ -434,8 +484,7 @@ static void print_sym_table(void)
434 484
435 puts(CONSOLE_CLEAR); 485 puts(CONSOLE_CLEAR);
436 486
437 printf( 487 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
438"------------------------------------------------------------------------------\n");
439 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 488 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
440 samples_per_sec, 489 samples_per_sec,
441 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)));
@@ -473,33 +522,57 @@ static void print_sym_table(void)
473 printf(", %d CPUs)\n", nr_cpus); 522 printf(", %d CPUs)\n", nr_cpus);
474 } 523 }
475 524
476 printf("------------------------------------------------------------------------------\n\n"); 525 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
477 526
478 if (sym_filter_entry) { 527 if (sym_filter_entry) {
479 show_details(sym_filter_entry); 528 show_details(sym_filter_entry);
480 return; 529 return;
481 } 530 }
482 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');
483 if (nr_counters == 1) 554 if (nr_counters == 1)
484 printf(" samples pcnt"); 555 printf(" samples pcnt");
485 else 556 else
486 printf(" weight samples pcnt"); 557 printf(" weight samples pcnt");
487 558
488 if (verbose) 559 if (verbose)
489 printf(" RIP "); 560 printf(" RIP ");
490 printf(" kernel function\n"); 561 printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
491 printf(" %s _______ _____", 562 printf(" %s _______ _____",
492 nr_counters == 1 ? " " : "______"); 563 nr_counters == 1 ? " " : "______");
493 if (verbose) 564 if (verbose)
494 printf(" ________________"); 565 printf(" ________________");
495 printf(" _______________\n\n"); 566 printf(" %-*.*s", sym_width, sym_width, graph_line);
567 printf(" %-*.*s", dso_width, dso_width, graph_line);
568 puts("\n");
496 569
497 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 570 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
498 struct symbol *sym; 571 struct symbol *sym;
499 double pcnt; 572 double pcnt;
500 573
501 syme = rb_entry(nd, struct sym_entry, rb_node); 574 syme = rb_entry(nd, struct sym_entry, rb_node);
502 sym = (struct symbol *)(syme + 1); 575 sym = sym_entry__symbol(syme);
503 576
504 if (++printed > print_entries || (int)syme->snap_count < count_filter) 577 if (++printed > print_entries || (int)syme->snap_count < count_filter)
505 continue; 578 continue;
@@ -508,17 +581,18 @@ static void print_sym_table(void)
508 sum_ksamples)); 581 sum_ksamples));
509 582
510 if (nr_counters == 1 || !display_weighted) 583 if (nr_counters == 1 || !display_weighted)
511 printf("%20.2f - ", syme->weight); 584 printf("%20.2f ", syme->weight);
512 else 585 else
513 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 586 printf("%9.1f %10ld ", syme->weight, syme->snap_count);
514 587
515 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 588 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
516 if (verbose) 589 if (verbose)
517 printf(" - %016llx", sym->start); 590 printf(" %016llx", sym->start);
518 printf(" : %s", sym->name); 591 printf(" %-*.*s", sym_width, sym_width, sym->name);
519 if (sym->module) 592 printf(" %-*.*s\n", dso_width, dso_width,
520 printf("\t[%s]", sym->module->name); 593 dso_width >= syme->map->dso->long_name_len ?
521 printf("\n"); 594 syme->map->dso->long_name :
595 syme->map->dso->short_name);
522 } 596 }
523} 597}
524 598
@@ -565,10 +639,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
565 639
566 /* zero counters of active symbol */ 640 /* zero counters of active symbol */
567 if (syme) { 641 if (syme) {
568 pthread_mutex_lock(&syme->source_lock); 642 pthread_mutex_lock(&syme->src->lock);
569 __zero_source_counters(syme); 643 __zero_source_counters(syme);
570 *target = NULL; 644 *target = NULL;
571 pthread_mutex_unlock(&syme->source_lock); 645 pthread_mutex_unlock(&syme->src->lock);
572 } 646 }
573 647
574 fprintf(stdout, "\n%s: ", msg); 648 fprintf(stdout, "\n%s: ", msg);
@@ -584,7 +658,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
584 pthread_mutex_unlock(&active_symbols_lock); 658 pthread_mutex_unlock(&active_symbols_lock);
585 659
586 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 660 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
587 struct symbol *sym = (struct symbol *)(syme + 1); 661 struct symbol *sym = sym_entry__symbol(syme);
588 662
589 if (!strcmp(buf, sym->name)) { 663 if (!strcmp(buf, sym->name)) {
590 found = syme; 664 found = syme;
@@ -608,7 +682,7 @@ static void print_mapped_keys(void)
608 char *name = NULL; 682 char *name = NULL;
609 683
610 if (sym_filter_entry) { 684 if (sym_filter_entry) {
611 struct symbol *sym = (struct symbol *)(sym_filter_entry+1); 685 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
612 name = sym->name; 686 name = sym->name;
613 } 687 }
614 688
@@ -621,7 +695,7 @@ static void print_mapped_keys(void)
621 695
622 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);
623 697
624 if (vmlinux_name) { 698 if (symbol_conf.vmlinux_name) {
625 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);
626 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
627 fprintf(stdout, "\t[S] stop annotation.\n"); 701 fprintf(stdout, "\t[S] stop annotation.\n");
@@ -630,6 +704,12 @@ static void print_mapped_keys(void)
630 if (nr_counters > 1) 704 if (nr_counters > 1)
631 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);
632 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");
633 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);
634 fprintf(stdout, "\t[qQ] quit.\n"); 714 fprintf(stdout, "\t[qQ] quit.\n");
635} 715}
@@ -643,6 +723,8 @@ static int key_mapped(int c)
643 case 'z': 723 case 'z':
644 case 'q': 724 case 'q':
645 case 'Q': 725 case 'Q':
726 case 'K':
727 case 'U':
646 return 1; 728 return 1;
647 case 'E': 729 case 'E':
648 case 'w': 730 case 'w':
@@ -650,7 +732,7 @@ static int key_mapped(int c)
650 case 'F': 732 case 'F':
651 case 's': 733 case 's':
652 case 'S': 734 case 'S':
653 return vmlinux_name ? 1 : 0; 735 return symbol_conf.vmlinux_name ? 1 : 0;
654 default: 736 default:
655 break; 737 break;
656 } 738 }
@@ -691,6 +773,11 @@ static void handle_keypress(int c)
691 break; 773 break;
692 case 'e': 774 case 'e':
693 prompt_integer(&print_entries, "Enter display entries (lines)"); 775 prompt_integer(&print_entries, "Enter display entries (lines)");
776 if (print_entries == 0) {
777 sig_winch_handler(SIGWINCH);
778 signal(SIGWINCH, sig_winch_handler);
779 } else
780 signal(SIGWINCH, SIG_DFL);
694 break; 781 break;
695 case 'E': 782 case 'E':
696 if (nr_counters > 1) { 783 if (nr_counters > 1) {
@@ -715,9 +802,14 @@ static void handle_keypress(int c)
715 case 'F': 802 case 'F':
716 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 803 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
717 break; 804 break;
805 case 'K':
806 hide_kernel_symbols = !hide_kernel_symbols;
807 break;
718 case 'q': 808 case 'q':
719 case 'Q': 809 case 'Q':
720 printf("exiting.\n"); 810 printf("exiting.\n");
811 if (dump_symtab)
812 dsos__fprintf(stderr);
721 exit(0); 813 exit(0);
722 case 's': 814 case 's':
723 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 815 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -728,12 +820,15 @@ static void handle_keypress(int c)
728 else { 820 else {
729 struct sym_entry *syme = sym_filter_entry; 821 struct sym_entry *syme = sym_filter_entry;
730 822
731 pthread_mutex_lock(&syme->source_lock); 823 pthread_mutex_lock(&syme->src->lock);
732 sym_filter_entry = NULL; 824 sym_filter_entry = NULL;
733 __zero_source_counters(syme); 825 __zero_source_counters(syme);
734 pthread_mutex_unlock(&syme->source_lock); 826 pthread_mutex_unlock(&syme->src->lock);
735 } 827 }
736 break; 828 break;
829 case 'U':
830 hide_user_symbols = !hide_user_symbols;
831 break;
737 case 'w': 832 case 'w':
738 display_weighted = ~display_weighted; 833 display_weighted = ~display_weighted;
739 break; 834 break;
@@ -790,7 +885,7 @@ static const char *skip_symbols[] = {
790 NULL 885 NULL
791}; 886};
792 887
793static int symbol_filter(struct dso *self, struct symbol *sym) 888static int symbol_filter(struct map *map, struct symbol *sym)
794{ 889{
795 struct sym_entry *syme; 890 struct sym_entry *syme;
796 const char *name = sym->name; 891 const char *name = sym->name;
@@ -812,8 +907,9 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
812 strstr(name, "_text_end")) 907 strstr(name, "_text_end"))
813 return 1; 908 return 1;
814 909
815 syme = dso__sym_priv(self, sym); 910 syme = symbol__priv(sym);
816 pthread_mutex_init(&syme->source_lock, NULL); 911 syme->map = map;
912 syme->src = NULL;
817 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
818 sym_filter_entry = syme; 914 sym_filter_entry = syme;
819 915
@@ -824,75 +920,65 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
824 } 920 }
825 } 921 }
826 922
827 return 0; 923 if (!syme->skip)
828} 924 syme->name_len = strlen(sym->name);
829
830static int parse_symbols(void)
831{
832 struct rb_node *node;
833 struct symbol *sym;
834 int use_modules = vmlinux_name ? 1 : 0;
835
836 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
837 if (kernel_dso == NULL)
838 return -1;
839
840 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
841 goto out_delete_dso;
842
843 node = rb_first(&kernel_dso->syms);
844 sym = rb_entry(node, struct symbol, rb_node);
845 min_ip = sym->start;
846
847 node = rb_last(&kernel_dso->syms);
848 sym = rb_entry(node, struct symbol, rb_node);
849 max_ip = sym->end;
850
851 if (dump_symtab)
852 dso__fprintf(kernel_dso, stderr);
853 925
854 return 0; 926 return 0;
855
856out_delete_dso:
857 dso__delete(kernel_dso);
858 kernel_dso = NULL;
859 return -1;
860} 927}
861 928
862/* 929static void event__process_sample(const event_t *self, int counter)
863 * Binary search in the histogram table and record the hit:
864 */
865static void record_ip(u64 ip, int counter)
866{ 930{
867 struct symbol *sym = dso__find_symbol(kernel_dso, ip); 931 u64 ip = self->ip.ip;
868 932 struct sym_entry *syme;
869 if (sym != NULL) { 933 struct addr_location al;
870 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 934 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
871 935
872 if (!syme->skip) { 936 switch (origin) {
873 syme->count[counter]++; 937 case PERF_RECORD_MISC_USER:
874 record_precise_ip(syme, counter, ip); 938 if (hide_user_symbols)
875 pthread_mutex_lock(&active_symbols_lock);
876 if (list_empty(&syme->node) || !syme->node.next)
877 __list_insert_active_sym(syme);
878 pthread_mutex_unlock(&active_symbols_lock);
879 return; 939 return;
880 } 940 break;
941 case PERF_RECORD_MISC_KERNEL:
942 if (hide_kernel_symbols)
943 return;
944 break;
945 default:
946 return;
881 } 947 }
882 948
883 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 }
884} 966}
885 967
886static void process_event(u64 ip, int counter, int user) 968static int event__process(event_t *event)
887{ 969{
888 samples++; 970 switch (event->header.type) {
889 971 case PERF_RECORD_COMM:
890 if (user) { 972 event__process_comm(event);
891 userspace_samples++; 973 break;
892 return; 974 case PERF_RECORD_MMAP:
975 event__process_mmap(event);
976 break;
977 default:
978 break;
893 } 979 }
894 980
895 record_ip(ip, counter); 981 return 0;
896} 982}
897 983
898struct mmap_data { 984struct mmap_data {
@@ -913,8 +999,6 @@ static unsigned int mmap_read_head(struct mmap_data *md)
913 return head; 999 return head;
914} 1000}
915 1001
916struct timeval last_read, this_read;
917
918static void mmap_read_counter(struct mmap_data *md) 1002static void mmap_read_counter(struct mmap_data *md)
919{ 1003{
920 unsigned int head = mmap_read_head(md); 1004 unsigned int head = mmap_read_head(md);
@@ -922,8 +1006,6 @@ static void mmap_read_counter(struct mmap_data *md)
922 unsigned char *data = md->base + page_size; 1006 unsigned char *data = md->base + page_size;
923 int diff; 1007 int diff;
924 1008
925 gettimeofday(&this_read, NULL);
926
927 /* 1009 /*
928 * 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
929 * 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.
@@ -934,14 +1016,7 @@ static void mmap_read_counter(struct mmap_data *md)
934 */ 1016 */
935 diff = head - old; 1017 diff = head - old;
936 if (diff > md->mask / 2 || diff < 0) { 1018 if (diff > md->mask / 2 || diff < 0) {
937 struct timeval iv; 1019 fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
938 unsigned long msecs;
939
940 timersub(&this_read, &last_read, &iv);
941 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
942
943 fprintf(stderr, "WARNING: failed to keep up with mmap data."
944 " Last read %lu msecs ago.\n", msecs);
945 1020
946 /* 1021 /*
947 * head points to a known good entry, start there. 1022 * head points to a known good entry, start there.
@@ -949,8 +1024,6 @@ static void mmap_read_counter(struct mmap_data *md)
949 old = head; 1024 old = head;
950 } 1025 }
951 1026
952 last_read = this_read;
953
954 for (; old != head;) { 1027 for (; old != head;) {
955 event_t *event = (event_t *)&data[old & md->mask]; 1028 event_t *event = (event_t *)&data[old & md->mask];
956 1029
@@ -978,13 +1051,11 @@ static void mmap_read_counter(struct mmap_data *md)
978 event = &event_copy; 1051 event = &event_copy;
979 } 1052 }
980 1053
1054 if (event->header.type == PERF_RECORD_SAMPLE)
1055 event__process_sample(event, md->counter);
1056 else
1057 event__process(event);
981 old += size; 1058 old += size;
982
983 if (event->header.type == PERF_RECORD_SAMPLE) {
984 int user =
985 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
986 process_event(event->ip.ip, md->counter, user);
987 }
988 } 1059 }
989 1060
990 md->prev = old; 1061 md->prev = old;
@@ -1018,8 +1089,15 @@ static void start_counter(int i, int counter)
1018 attr = attrs + counter; 1089 attr = attrs + counter;
1019 1090
1020 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1091 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1021 attr->freq = freq; 1092
1093 if (freq) {
1094 attr->sample_type |= PERF_SAMPLE_PERIOD;
1095 attr->freq = 1;
1096 attr->sample_freq = freq;
1097 }
1098
1022 attr->inherit = (cpu < 0) && inherit; 1099 attr->inherit = (cpu < 0) && inherit;
1100 attr->mmap = 1;
1023 1101
1024try_again: 1102try_again:
1025 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);
@@ -1078,6 +1156,11 @@ static int __cmd_top(void)
1078 int i, counter; 1156 int i, counter;
1079 int ret; 1157 int ret;
1080 1158
1159 if (target_pid != -1)
1160 event__synthesize_thread(target_pid, event__process);
1161 else
1162 event__synthesize_threads(event__process);
1163
1081 for (i = 0; i < nr_cpus; i++) { 1164 for (i = 0; i < nr_cpus; i++) {
1082 group_fd = -1; 1165 group_fd = -1;
1083 for (counter = 0; counter < nr_counters; counter++) 1166 for (counter = 0; counter < nr_counters; counter++)
@@ -1133,7 +1216,10 @@ static const struct option options[] = {
1133 "system-wide collection from all CPUs"), 1216 "system-wide collection from all CPUs"),
1134 OPT_INTEGER('C', "CPU", &profile_cpu, 1217 OPT_INTEGER('C', "CPU", &profile_cpu,
1135 "CPU to profile on"), 1218 "CPU to profile on"),
1136 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"),
1137 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1223 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1138 "number of mmap data pages"), 1224 "number of mmap data pages"),
1139 OPT_INTEGER('r', "realtime", &realtime_prio, 1225 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1156,6 +1242,8 @@ static const struct option options[] = {
1156 "profile at this frequency"), 1242 "profile at this frequency"),
1157 OPT_INTEGER('E', "entries", &print_entries, 1243 OPT_INTEGER('E', "entries", &print_entries,
1158 "display this many functions"), 1244 "display this many functions"),
1245 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1246 "hide user symbols"),
1159 OPT_BOOLEAN('v', "verbose", &verbose, 1247 OPT_BOOLEAN('v', "verbose", &verbose,
1160 "be more verbose (show counter open errors, etc)"), 1248 "be more verbose (show counter open errors, etc)"),
1161 OPT_END() 1249 OPT_END()
@@ -1165,19 +1253,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1165{ 1253{
1166 int counter; 1254 int counter;
1167 1255
1168 symbol__init();
1169
1170 page_size = sysconf(_SC_PAGE_SIZE); 1256 page_size = sysconf(_SC_PAGE_SIZE);
1171 1257
1172 argc = parse_options(argc, argv, options, top_usage, 0); 1258 argc = parse_options(argc, argv, options, top_usage, 0);
1173 if (argc) 1259 if (argc)
1174 usage_with_options(top_usage, options); 1260 usage_with_options(top_usage, options);
1175 1261
1176 if (freq) {
1177 default_interval = freq;
1178 freq = 1;
1179 }
1180
1181 /* CPU and PID are mutually exclusive */ 1262 /* CPU and PID are mutually exclusive */
1182 if (target_pid != -1 && profile_cpu != -1) { 1263 if (target_pid != -1 && profile_cpu != -1) {
1183 printf("WARNING: PID switch overriding CPU\n"); 1264 printf("WARNING: PID switch overriding CPU\n");
@@ -1188,13 +1269,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1188 if (!nr_counters) 1269 if (!nr_counters)
1189 nr_counters = 1; 1270 nr_counters = 1;
1190 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
1191 if (delay_secs < 1) 1279 if (delay_secs < 1)
1192 delay_secs = 1; 1280 delay_secs = 1;
1193 1281
1194 parse_symbols();
1195 parse_source(sym_filter_entry); 1282 parse_source(sym_filter_entry);
1196 1283
1197 /* 1284 /*
1285 * User specified count overrides default frequency.
1286 */
1287 if (default_interval)
1288 freq = 0;
1289 else if (freq) {
1290 default_interval = freq;
1291 } else {
1292 fprintf(stderr, "frequency and count are zero, aborting\n");
1293 exit(EXIT_FAILURE);
1294 }
1295
1296 /*
1198 * Fill in the ones not specifically initialized via -c: 1297 * Fill in the ones not specifically initialized via -c:
1199 */ 1298 */
1200 for (counter = 0; counter < nr_counters; counter++) { 1299 for (counter = 0; counter < nr_counters; counter++) {
@@ -1211,5 +1310,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1211 if (target_pid != -1 || profile_cpu != -1) 1310 if (target_pid != -1 || profile_cpu != -1)
1212 nr_cpus = 1; 1311 nr_cpus = 1;
1213 1312
1313 get_term_dimensions(&winsize);
1314 if (print_entries == 0) {
1315 update_print_entries(&winsize);
1316 signal(SIGWINCH, sig_winch_handler);
1317 }
1318
1214 return __cmd_top(); 1319 return __cmd_top();
1215} 1320}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0c5e4f72f2ba..c2fcc34486f5 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -5,256 +5,280 @@
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)
20{
21 return 0;
22}
23
24static int default_generate_script(const char *outfile __attribute ((unused)))
25{
26 return 0;
27}
15 28
16static char const *input_name = "perf.data"; 29static struct scripting_ops default_scripting_ops = {
17static int input; 30 .start_script = default_start_script,
18static unsigned long page_size; 31 .stop_script = default_stop_script,
19static unsigned long mmap_window = 32; 32 .process_event = print_event,
33 .generate_script = default_generate_script,
34};
20 35
21static unsigned long total = 0; 36static struct scripting_ops *scripting_ops;
22static unsigned long total_comm = 0;
23 37
24static struct rb_root threads; 38static void setup_scripting(void)
25static struct thread *last_match; 39{
40 /* make sure PERF_EXEC_PATH is set for scripts */
41 perf_set_argv_exec_path(perf_exec_path());
26 42
27static struct perf_header *header; 43 setup_perl_scripting();
28static u64 sample_type;
29 44
45 scripting_ops = &default_scripting_ops;
46}
30 47
31static int 48static int cleanup_scripting(void)
32process_comm_event(event_t *event, unsigned long offset, unsigned long head)
33{ 49{
34 struct thread *thread; 50 return scripting_ops->stop_script();
51}
35 52
36 thread = threads__findnew(event->comm.pid, &threads, &last_match); 53#include "util/parse-options.h"
37 54
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 55#include "perf.h"
39 (void *)(offset + head), 56#include "util/debug.h"
40 (void *)(long)(event->header.size),
41 event->comm.comm, event->comm.pid);
42 57
43 if (thread == NULL || 58#include "util/trace-event.h"
44 thread__set_comm(thread, event->comm.comm)) { 59#include "util/data_map.h"
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 60#include "util/exec_cmd.h"
46 return -1;
47 }
48 total_comm++;
49 61
50 return 0; 62static char const *input_name = "perf.data";
51}
52 63
53static int 64static struct perf_header *header;
54process_sample_event(event_t *event, unsigned long offset, unsigned long head) 65static u64 sample_type;
66
67static int process_sample_event(event_t *event)
55{ 68{
56 char level; 69 struct sample_data data;
57 int show = 0;
58 struct dso *dso = NULL;
59 struct thread *thread; 70 struct thread *thread;
60 u64 ip = event->ip.ip;
61 u64 timestamp = -1;
62 u32 cpu = -1;
63 u64 period = 1;
64 void *more_data = event->ip.__more_data;
65 int cpumode;
66
67 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68
69 if (sample_type & PERF_SAMPLE_TIME) {
70 timestamp = *(u64 *)more_data;
71 more_data += sizeof(u64);
72 }
73 71
74 if (sample_type & PERF_SAMPLE_CPU) { 72 memset(&data, 0, sizeof(data));
75 cpu = *(u32 *)more_data; 73 data.time = -1;
76 more_data += sizeof(u32); 74 data.cpu = -1;
77 more_data += sizeof(u32); /* reserved */ 75 data.period = 1;
78 }
79 76
80 if (sample_type & PERF_SAMPLE_PERIOD) { 77 event__parse_sample(event, sample_type, &data);
81 period = *(u64 *)more_data;
82 more_data += sizeof(u64);
83 }
84 78
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 79 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
86 (void *)(offset + head),
87 (void *)(long)(event->header.size),
88 event->header.misc, 80 event->header.misc,
89 event->ip.pid, event->ip.tid, 81 data.pid, data.tid,
90 (void *)(long)ip, 82 (void *)(long)data.ip,
91 (long long)period); 83 (long long)data.period);
92
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
94 84
85 thread = threads__findnew(event->ip.pid);
95 if (thread == NULL) { 86 if (thread == NULL) {
96 eprintf("problem processing %d event, skipping it.\n", 87 pr_debug("problem processing %d event, skipping it.\n",
97 event->header.type); 88 event->header.type);
98 return -1; 89 return -1;
99 } 90 }
100 91
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_RECORD_MISC_KERNEL) {
104 show = SHOW_KERNEL;
105 level = 'k';
106
107 dso = kernel_dso;
108
109 dump_printf(" ...... dso: %s\n", dso->name);
110
111 } else if (cpumode == PERF_RECORD_MISC_USER) {
112
113 show = SHOW_USER;
114 level = '.';
115
116 } else {
117 show = SHOW_HV;
118 level = 'H';
119
120 dso = hypervisor_dso;
121
122 dump_printf(" ...... dso: [hypervisor]\n");
123 }
124
125 if (sample_type & PERF_SAMPLE_RAW) { 92 if (sample_type & PERF_SAMPLE_RAW) {
126 struct {
127 u32 size;
128 char data[0];
129 } *raw = more_data;
130
131 /* 93 /*
132 * FIXME: better resolve from pid from the struct trace_entry 94 * FIXME: better resolve from pid from the struct trace_entry
133 * field, although it should be the same than this perf 95 * field, although it should be the same than this perf
134 * event pid 96 * event pid
135 */ 97 */
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm); 98 scripting_ops->process_event(data.cpu, data.raw_data,
99 data.raw_size,
100 data.time, thread->comm);
137 } 101 }
138 total += period; 102 event__stats.total += data.period;
139 103
140 return 0; 104 return 0;
141} 105}
142 106
143static int 107static int sample_type_check(u64 type)
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{ 108{
146 trace_event(event); 109 sample_type = type;
147 110
148 switch (event->header.type) { 111 if (!(sample_type & PERF_SAMPLE_RAW)) {
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST: 112 fprintf(stderr,
150 return 0; 113 "No trace sample to read. Did you call perf record "
151 114 "without -R?");
152 case PERF_RECORD_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
156 return 0;
157
158 case PERF_RECORD_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_RECORD_MAX:
162 default:
163 return -1; 115 return -1;
164 } 116 }
165 117
166 return 0; 118 return 0;
167} 119}
168 120
121static struct perf_file_handler file_handler = {
122 .process_sample_event = process_sample_event,
123 .process_comm_event = event__process_comm,
124 .sample_type_check = sample_type_check,
125};
126
169static int __cmd_trace(void) 127static int __cmd_trace(void)
170{ 128{
171 int ret, rc = EXIT_FAILURE; 129 register_idle_thread();
172 unsigned long offset = 0; 130 register_perf_file_handler(&file_handler);
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187 131
188 ret = fstat(input, &perf_stat); 132 return mmap_dispatch_perf_file(&header, input_name,
189 if (ret < 0) { 133 0, 0, &event__cwdlen, &event__cwd);
190 perror("failed to stat file"); 134}
191 exit(-1);
192 }
193 135
194 if (!perf_stat.st_size) { 136struct script_spec {
195 fprintf(stderr, "zero-sized file, nothing to do!\n"); 137 struct list_head node;
196 exit(0); 138 struct scripting_ops *ops;
197 } 139 char spec[0];
198 header = perf_header__read(input); 140};
199 head = header->data_offset;
200 sample_type = perf_header__sample_type(header);
201 141
202 if (!(sample_type & PERF_SAMPLE_RAW)) 142LIST_HEAD(script_specs);
203 die("No trace sample to read. Did you call perf record "
204 "without -R?");
205 143
206 if (load_kernel() < 0) { 144static struct script_spec *script_spec__new(const char *spec,
207 perror("failed to load kernel symbols"); 145 struct scripting_ops *ops)
208 return EXIT_FAILURE; 146{
209 } 147 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
210 148
211remap: 149 if (s != NULL) {
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 150 strcpy(s->spec, spec);
213 MAP_SHARED, input, offset); 151 s->ops = ops;
214 if (buf == MAP_FAILED) {
215 perror("failed to mmap file");
216 exit(-1);
217 } 152 }
218 153
219more: 154 return s;
220 event = (event_t *)(buf + head); 155}
156
157static void script_spec__delete(struct script_spec *s)
158{
159 free(s->spec);
160 free(s);
161}
221 162
222 if (head + event->header.size >= page_size * mmap_window) { 163static void script_spec__add(struct script_spec *s)
223 unsigned long shift = page_size * (head / page_size); 164{
224 int res; 165 list_add_tail(&s->node, &script_specs);
166}
225 167
226 res = munmap(buf, page_size * mmap_window); 168static struct script_spec *script_spec__find(const char *spec)
227 assert(res == 0); 169{
170 struct script_spec *s;
228 171
229 offset += shift; 172 list_for_each_entry(s, &script_specs, node)
230 head -= shift; 173 if (strcasecmp(s->spec, spec) == 0)
231 goto remap; 174 return s;
232 } 175 return NULL;
176}
233 177
234 size = event->header.size; 178static struct script_spec *script_spec__findnew(const char *spec,
179 struct scripting_ops *ops)
180{
181 struct script_spec *s = script_spec__find(spec);
235 182
236 if (!size || process_event(event, offset, head) < 0) { 183 if (s)
184 return s;
237 185
238 /* 186 s = script_spec__new(spec, ops);
239 * assume we lost track of the stream, check alignment, and 187 if (!s)
240 * increment a single u64 in the hope to catch on again 'soon'. 188 goto out_delete_spec;
241 */
242 189
243 if (unlikely(head & 7)) 190 script_spec__add(s);
244 head &= ~7ULL;
245 191
246 size = 8; 192 return s;
247 } 193
194out_delete_spec:
195 script_spec__delete(s);
196
197 return NULL;
198}
248 199
249 head += size; 200int script_spec_register(const char *spec, struct scripting_ops *ops)
201{
202 struct script_spec *s;
250 203
251 if (offset + head < (unsigned long)perf_stat.st_size) 204 s = script_spec__find(spec);
252 goto more; 205 if (s)
206 return -1;
253 207
254 rc = EXIT_SUCCESS; 208 s = script_spec__findnew(spec, ops);
255 close(input); 209 if (!s)
210 return -1;
256 211
257 return rc; 212 return 0;
213}
214
215static struct scripting_ops *script_spec__lookup(const char *spec)
216{
217 struct script_spec *s = script_spec__find(spec);
218 if (!s)
219 return NULL;
220
221 return s->ops;
222}
223
224static void list_available_languages(void)
225{
226 struct script_spec *s;
227
228 fprintf(stderr, "\n");
229 fprintf(stderr, "Scripting language extensions (used in "
230 "perf trace -s [spec:]script.[spec]):\n\n");
231
232 list_for_each_entry(s, &script_specs, node)
233 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
234
235 fprintf(stderr, "\n");
236}
237
238static int parse_scriptname(const struct option *opt __used,
239 const char *str, int unset __used)
240{
241 char spec[PATH_MAX];
242 const char *script, *ext;
243 int len;
244
245 if (strcmp(str, "list") == 0) {
246 list_available_languages();
247 return 0;
248 }
249
250 script = strchr(str, ':');
251 if (script) {
252 len = script - str;
253 if (len >= PATH_MAX) {
254 fprintf(stderr, "invalid language specifier");
255 return -1;
256 }
257 strncpy(spec, str, len);
258 spec[len] = '\0';
259 scripting_ops = script_spec__lookup(spec);
260 if (!scripting_ops) {
261 fprintf(stderr, "invalid language specifier");
262 return -1;
263 }
264 script++;
265 } else {
266 script = str;
267 ext = strchr(script, '.');
268 if (!ext) {
269 fprintf(stderr, "invalid script extension");
270 return -1;
271 }
272 scripting_ops = script_spec__lookup(++ext);
273 if (!scripting_ops) {
274 fprintf(stderr, "invalid script extension");
275 return -1;
276 }
277 }
278
279 script_name = strdup(script);
280
281 return 0;
258} 282}
259 283
260static const char * const annotate_usage[] = { 284static const char * const annotate_usage[] = {
@@ -267,13 +291,24 @@ static const struct option options[] = {
267 "dump raw trace in ASCII"), 291 "dump raw trace in ASCII"),
268 OPT_BOOLEAN('v', "verbose", &verbose, 292 OPT_BOOLEAN('v', "verbose", &verbose,
269 "be more verbose (show symbol address, etc)"), 293 "be more verbose (show symbol address, etc)"),
294 OPT_BOOLEAN('l', "latency", &latency_format,
295 "show latency attributes (irqs/preemption disabled, etc)"),
296 OPT_CALLBACK('s', "script", NULL, "name",
297 "script file name (lang:script name, script name, or *)",
298 parse_scriptname),
299 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
300 "generate perf-trace.xx script in specified language"),
301
270 OPT_END() 302 OPT_END()
271}; 303};
272 304
273int cmd_trace(int argc, const char **argv, const char *prefix __used) 305int cmd_trace(int argc, const char **argv, const char *prefix __used)
274{ 306{
275 symbol__init(); 307 int err;
276 page_size = getpagesize(); 308
309 symbol__init(0);
310
311 setup_scripting();
277 312
278 argc = parse_options(argc, argv, options, annotate_usage, 0); 313 argc = parse_options(argc, argv, options, annotate_usage, 0);
279 if (argc) { 314 if (argc) {
@@ -287,5 +322,50 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
287 322
288 setup_pager(); 323 setup_pager();
289 324
290 return __cmd_trace(); 325 if (generate_script_lang) {
326 struct stat perf_stat;
327
328 int input = open(input_name, O_RDONLY);
329 if (input < 0) {
330 perror("failed to open file");
331 exit(-1);
332 }
333
334 err = fstat(input, &perf_stat);
335 if (err < 0) {
336 perror("failed to stat file");
337 exit(-1);
338 }
339
340 if (!perf_stat.st_size) {
341 fprintf(stderr, "zero-sized file, nothing to do!\n");
342 exit(0);
343 }
344
345 scripting_ops = script_spec__lookup(generate_script_lang);
346 if (!scripting_ops) {
347 fprintf(stderr, "invalid language specifier");
348 return -1;
349 }
350
351 header = perf_header__new();
352 if (header == NULL)
353 return -1;
354
355 perf_header__read(header, input);
356 err = scripting_ops->generate_script("perf-trace");
357 goto out;
358 }
359
360 if (script_name) {
361 err = scripting_ops->start_script(script_name);
362 if (err)
363 goto out;
364 }
365
366 err = __cmd_trace();
367
368 cleanup_scripting();
369out:
370 return err;
291} 371}
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/cache.h b/tools/perf/util/cache.h
index 6f8ea9d210b6..918eb376abe3 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,10 +1,15 @@
1#ifndef CACHE_H 1#ifndef __PERF_CACHE_H
2#define CACHE_H 2#define __PERF_CACHE_H
3 3
4#include "util.h" 4#include "util.h"
5#include "strbuf.h" 5#include "strbuf.h"
6#include "../perf.h" 6#include "../perf.h"
7 7
8#define CMD_EXEC_PATH "--exec-path"
9#define CMD_PERF_DIR "--perf-dir="
10#define CMD_WORK_TREE "--work-tree="
11#define CMD_DEBUGFS_DIR "--debugfs-dir="
12
8#define PERF_DIR_ENVIRONMENT "PERF_DIR" 13#define PERF_DIR_ENVIRONMENT "PERF_DIR"
9#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
10#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
@@ -117,4 +122,4 @@ extern char *perf_pathdup(const char *fmt, ...)
117 122
118extern size_t strlcpy(char *dest, const char *src, size_t size); 123extern size_t strlcpy(char *dest, const char *src, size_t size);
119 124
120#endif /* CACHE_H */ 125#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 3b8380f1b478..b3b71258272a 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -206,7 +206,7 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
206 } 206 }
207 node->val_nr = chain->nr - start; 207 node->val_nr = chain->nr - start;
208 if (!node->val_nr) 208 if (!node->val_nr)
209 printf("Warning: empty node in callchain tree\n"); 209 pr_warning("Warning: empty node in callchain tree\n");
210} 210}
211 211
212static void 212static void
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 43cf3ea9e088..ad4626de4c2b 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -58,4 +58,4 @@ static inline u64 cumul_hits(struct callchain_node *node)
58int register_callchain_param(struct callchain_param *param); 58int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 59void append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 60 struct symbol **syms);
61#endif 61#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 58d597564b99..24e8809210bb 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -1,5 +1,5 @@
1#ifndef COLOR_H 1#ifndef __PERF_COLOR_H
2#define COLOR_H 2#define __PERF_COLOR_H
3 3
4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ 4/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
5#define COLOR_MAXLEN 24 5#define COLOR_MAXLEN 24
@@ -39,4 +39,4 @@ int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *bu
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
41 41
42#endif /* COLOR_H */ 42#endif /* __PERF_COLOR_H */
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index 0b791bd346bc..35073621e5de 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -29,3 +29,11 @@ unsigned char sane_ctype[256] = {
29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */ 29 A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
30 /* Nothing in the 128.. range */ 30 /* Nothing in the 128.. range */
31}; 31};
32
33const char *graph_line =
34 "_____________________________________________________________________"
35 "_____________________________________________________________________";
36const char *graph_dotted_line =
37 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------";
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
new file mode 100644
index 000000000000..59b65d0bd7c1
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,291 @@
1#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{
13 dump_printf(": unhandled!\n");
14 return 0;
15}
16
17void register_perf_file_handler(struct perf_file_handler *handler)
18{
19 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub;
21 if (!handler->process_mmap_event)
22 handler->process_mmap_event = process_event_stub;
23 if (!handler->process_comm_event)
24 handler->process_comm_event = process_event_stub;
25 if (!handler->process_fork_event)
26 handler->process_fork_event = process_event_stub;
27 if (!handler->process_exit_event)
28 handler->process_exit_event = process_event_stub;
29 if (!handler->process_lost_event)
30 handler->process_lost_event = process_event_stub;
31 if (!handler->process_read_event)
32 handler->process_read_event = process_event_stub;
33 if (!handler->process_throttle_event)
34 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39}
40
41static const char *event__name[] = {
42 [0] = "TOTAL",
43 [PERF_RECORD_MMAP] = "MMAP",
44 [PERF_RECORD_LOST] = "LOST",
45 [PERF_RECORD_COMM] = "COMM",
46 [PERF_RECORD_EXIT] = "EXIT",
47 [PERF_RECORD_THROTTLE] = "THROTTLE",
48 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
49 [PERF_RECORD_FORK] = "FORK",
50 [PERF_RECORD_READ] = "READ",
51 [PERF_RECORD_SAMPLE] = "SAMPLE",
52};
53
54unsigned long event__total[PERF_RECORD_MAX];
55
56void event__print_totals(void)
57{
58 int i;
59 for (i = 0; i < PERF_RECORD_MAX; ++i)
60 pr_info("%10s events: %10ld\n",
61 event__name[i], event__total[i]);
62}
63
64static int
65process_event(event_t *event, unsigned long offset, unsigned long head)
66{
67 trace_event(event);
68
69 if (event->header.type < PERF_RECORD_MAX) {
70 dump_printf("%p [%p]: PERF_RECORD_%s",
71 (void *)(offset + head),
72 (void *)(long)(event->header.size),
73 event__name[event->header.type]);
74 ++event__total[0];
75 ++event__total[event->header.type];
76 }
77
78 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event);
81 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event);
83 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event);
85 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event);
87 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event);
89 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event);
91 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event);
93 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event);
95 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event);
97 default:
98 curr_handler->total_unknown++;
99 return -1;
100 }
101}
102
103int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{
105 struct build_id_event bev;
106 char filename[PATH_MAX];
107 u64 limit = offset + size;
108 int err = -1;
109
110 while (offset < limit) {
111 struct dso *dso;
112 ssize_t len;
113
114 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
115 goto out;
116
117 len = bev.header.size - sizeof(bev);
118 if (read(input, filename, len) != len)
119 goto out;
120
121 dso = dsos__findnew(filename);
122 if (dso != NULL)
123 dso__set_build_id(dso, &bev.build_id);
124
125 offset += bev.header.size;
126 }
127 err = 0;
128out:
129 return err;
130}
131
132int mmap_dispatch_perf_file(struct perf_header **pheader,
133 const char *input_name,
134 int force,
135 int full_paths,
136 int *cwdlen,
137 char **cwd)
138{
139 int err;
140 struct perf_header *header;
141 unsigned long head, shift;
142 unsigned long offset = 0;
143 struct stat input_stat;
144 size_t page_size;
145 u64 sample_type;
146 event_t *event;
147 uint32_t size;
148 int input;
149 char *buf;
150
151 if (curr_handler == NULL) {
152 pr_debug("Forgot to register perf file handler\n");
153 return -EINVAL;
154 }
155
156 page_size = getpagesize();
157
158 input = open(input_name, O_RDONLY);
159 if (input < 0) {
160 pr_err("Failed to open file: %s", input_name);
161 if (!strcmp(input_name, "perf.data"))
162 pr_err(" (try 'perf record' first)");
163 pr_err("\n");
164 return -errno;
165 }
166
167 if (fstat(input, &input_stat) < 0) {
168 pr_err("failed to stat file");
169 err = -errno;
170 goto out_close;
171 }
172
173 err = -EACCES;
174 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
175 pr_err("file: %s not owned by current user or root\n",
176 input_name);
177 goto out_close;
178 }
179
180 if (input_stat.st_size == 0) {
181 pr_info("zero-sized file, nothing to do!\n");
182 goto done;
183 }
184
185 err = -ENOMEM;
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;
194 head = header->data_offset;
195
196 sample_type = perf_header__sample_type(header);
197
198 err = -EINVAL;
199 if (curr_handler->sample_type_check &&
200 curr_handler->sample_type_check(sample_type) < 0)
201 goto out_delete;
202
203 if (!full_paths) {
204 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
205 pr_err("failed to get the current directory\n");
206 err = -errno;
207 goto out_delete;
208 }
209 *cwd = __cwd;
210 *cwdlen = strlen(*cwd);
211 } else {
212 *cwd = NULL;
213 *cwdlen = 0;
214 }
215
216 shift = page_size * (head / page_size);
217 offset += shift;
218 head -= shift;
219
220remap:
221 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
222 MAP_SHARED, input, offset);
223 if (buf == MAP_FAILED) {
224 pr_err("failed to mmap file\n");
225 err = -errno;
226 goto out_delete;
227 }
228
229more:
230 event = (event_t *)(buf + head);
231
232 size = event->header.size;
233 if (!size)
234 size = 8;
235
236 if (head + event->header.size >= page_size * mmap_window) {
237 int munmap_ret;
238
239 shift = page_size * (head / page_size);
240
241 munmap_ret = munmap(buf, page_size * mmap_window);
242 assert(munmap_ret == 0);
243
244 offset += shift;
245 head -= shift;
246 goto remap;
247 }
248
249 size = event->header.size;
250
251 dump_printf("\n%p [%p]: event: %d\n",
252 (void *)(offset + head),
253 (void *)(long)event->header.size,
254 event->header.type);
255
256 if (!size || process_event(event, offset, head) < 0) {
257
258 dump_printf("%p [%p]: skipping unknown header type: %d\n",
259 (void *)(offset + head),
260 (void *)(long)(event->header.size),
261 event->header.type);
262
263 /*
264 * assume we lost track of the stream, check alignment, and
265 * increment a single u64 in the hope to catch on again 'soon'.
266 */
267
268 if (unlikely(head & 7))
269 head &= ~7ULL;
270
271 size = 8;
272 }
273
274 head += size;
275
276 if (offset + head >= header->data_offset + header->data_size)
277 goto done;
278
279 if (offset + head < (unsigned long)input_stat.st_size)
280 goto more;
281
282done:
283 err = 0;
284out_close:
285 close(input);
286
287 return err;
288out_delete:
289 perf_header__delete(header);
290 goto out_close;
291}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644
index 000000000000..258a87bcc4fb
--- /dev/null
+++ b/tools/perf/util/data_map.h
@@ -0,0 +1,32 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6
7typedef int (*event_type_handler_t)(event_t *);
8
9struct perf_file_handler {
10 event_type_handler_t process_sample_event;
11 event_type_handler_t process_mmap_event;
12 event_type_handler_t process_comm_event;
13 event_type_handler_t process_fork_event;
14 event_type_handler_t process_exit_event;
15 event_type_handler_t process_lost_event;
16 event_type_handler_t process_read_event;
17 event_type_handler_t process_throttle_event;
18 event_type_handler_t process_unthrottle_event;
19 int (*sample_type_check)(u64 sample_type);
20 unsigned long total_unknown;
21};
22
23void register_perf_file_handler(struct perf_file_handler *handler);
24int mmap_dispatch_perf_file(struct perf_header **pheader,
25 const char *input_name,
26 int force,
27 int full_paths,
28 int *cwdlen,
29 char **cwd);
30int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
31
32#endif
diff --git a/tools/perf/util/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 437eea58ce40..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -1,8 +1,15 @@
1/* For debugging general purposes */ 1/* For debugging general purposes */
2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H
4
5#include "event.h"
2 6
3extern int verbose; 7extern int verbose;
4extern int dump_trace; 8extern int dump_trace;
5 9
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event); 13void trace_event(event_t *event);
14
15#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..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..4dcecafa85dc
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,379 @@
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}
313
314int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
315{
316 u64 *array = event->sample.array;
317
318 if (type & PERF_SAMPLE_IP) {
319 data->ip = event->ip.ip;
320 array++;
321 }
322
323 if (type & PERF_SAMPLE_TID) {
324 u32 *p = (u32 *)array;
325 data->pid = p[0];
326 data->tid = p[1];
327 array++;
328 }
329
330 if (type & PERF_SAMPLE_TIME) {
331 data->time = *array;
332 array++;
333 }
334
335 if (type & PERF_SAMPLE_ADDR) {
336 data->addr = *array;
337 array++;
338 }
339
340 if (type & PERF_SAMPLE_ID) {
341 data->id = *array;
342 array++;
343 }
344
345 if (type & PERF_SAMPLE_STREAM_ID) {
346 data->stream_id = *array;
347 array++;
348 }
349
350 if (type & PERF_SAMPLE_CPU) {
351 u32 *p = (u32 *)array;
352 data->cpu = *p;
353 array++;
354 }
355
356 if (type & PERF_SAMPLE_PERIOD) {
357 data->period = *array;
358 array++;
359 }
360
361 if (type & PERF_SAMPLE_READ) {
362 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
363 return -1;
364 }
365
366 if (type & PERF_SAMPLE_CALLCHAIN) {
367 data->callchain = (struct ip_callchain *)array;
368 array += 1 + data->callchain->nr;
369 }
370
371 if (type & PERF_SAMPLE_RAW) {
372 u32 *p = (u32 *)array;
373 data->raw_size = *p;
374 p++;
375 data->raw_data = p;
376 }
377
378 return 0;
379}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..c7a78eef8e52 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,14 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3
3#include "../perf.h" 4#include "../perf.h"
4#include "util.h" 5#include "util.h"
5#include <linux/list.h> 6#include <linux/list.h>
6 7#include <linux/rbtree.h>
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12 8
13/* 9/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -60,11 +56,32 @@ struct read_event {
60 u64 id; 56 u64 id;
61}; 57};
62 58
63struct sample_event{ 59struct sample_event {
64 struct perf_event_header header; 60 struct perf_event_header header;
65 u64 array[]; 61 u64 array[];
66}; 62};
67 63
64struct sample_data {
65 u64 ip;
66 u32 pid, tid;
67 u64 time;
68 u64 addr;
69 u64 id;
70 u64 stream_id;
71 u32 cpu;
72 u64 period;
73 struct ip_callchain *callchain;
74 u32 raw_size;
75 void *raw_data;
76};
77
78#define BUILD_ID_SIZE 20
79
80struct build_id_event {
81 struct perf_event_header header;
82 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
83 char filename[];
84};
68 85
69typedef union event_union { 86typedef union event_union {
70 struct perf_event_header header; 87 struct perf_event_header header;
@@ -77,12 +94,30 @@ typedef union event_union {
77 struct sample_event sample; 94 struct sample_event sample;
78} event_t; 95} event_t;
79 96
97struct events_stats {
98 unsigned long total;
99 unsigned long lost;
100};
101
102void event__print_totals(void);
103
104enum map_type {
105 MAP__FUNCTION = 0,
106
107 MAP__NR_TYPES,
108};
109
80struct map { 110struct map {
81 struct list_head node; 111 union {
112 struct rb_node rb_node;
113 struct list_head node;
114 };
82 u64 start; 115 u64 start;
83 u64 end; 116 u64 end;
117 enum map_type type;
84 u64 pgoff; 118 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64); 119 u64 (*map_ip)(struct map *, u64);
120 u64 (*unmap_ip)(struct map *, u64);
86 struct dso *dso; 121 struct dso *dso;
87}; 122};
88 123
@@ -91,14 +126,49 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
91 return ip - map->start + map->pgoff; 126 return ip - map->start + map->pgoff;
92} 127}
93 128
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 129static inline u64 map__unmap_ip(struct map *map, u64 ip)
130{
131 return ip + map->start - map->pgoff;
132}
133
134static inline u64 identity__map_ip(struct map *map __used, u64 ip)
95{ 135{
96 return ip; 136 return ip;
97} 137}
98 138
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 139struct symbol;
140
141typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
142
143void map__init(struct map *self, enum map_type type,
144 u64 start, u64 end, u64 pgoff, struct dso *dso);
145struct map *map__new(struct mmap_event *event, enum map_type,
146 char *cwd, int cwdlen);
147void map__delete(struct map *self);
100struct map *map__clone(struct map *self); 148struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r); 149int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp); 150size_t map__fprintf(struct map *self, FILE *fp);
151struct symbol *map__find_symbol(struct map *self, u64 addr,
152 symbol_filter_t filter);
153void map__fixup_start(struct map *self);
154void map__fixup_end(struct map *self);
155
156int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
157void event__synthesize_threads(int (*process)(event_t *event));
158
159extern char *event__cwd;
160extern int event__cwdlen;
161extern struct events_stats event__stats;
162extern unsigned long event__total[PERF_RECORD_MAX];
163
164int event__process_comm(event_t *self);
165int event__process_lost(event_t *self);
166int event__process_mmap(event_t *self);
167int event__process_task(event_t *self);
168
169struct addr_location;
170int event__preprocess_sample(const event_t *self, struct addr_location *al,
171 symbol_filter_t filter);
172int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
103 173
104#endif 174#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index effe25eb1545..31647ac92ed1 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -1,5 +1,5 @@
1#ifndef PERF_EXEC_CMD_H 1#ifndef __PERF_EXEC_CMD_H
2#define PERF_EXEC_CMD_H 2#define __PERF_EXEC_CMD_H
3 3
4extern void perf_set_argv_exec_path(const char *exec_path); 4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
@@ -10,4 +10,4 @@ extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 10extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 11extern const char *system_path(const char *path);
12 12
13#endif /* PERF_EXEC_CMD_H */ 13#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index e306857b2c2b..59a9c0b3033e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,9 +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"
9#include "../perf.h"
10#include "trace-event.h"
11#include "symbol.h"
12#include "data_map.h"
13#include "debug.h"
8 14
9/* 15/*
10 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -13,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13{ 19{
14 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
15 21
16 if (!self) 22 if (self != NULL) {
17 die("nomem"); 23 self->attr = *attr;
18 24 self->ids = 0;
19 self->attr = *attr; 25 self->size = 1;
20 self->ids = 0; 26 self->id = malloc(sizeof(u64));
21 self->size = 1; 27 if (self->id == NULL) {
22 self->id = malloc(sizeof(u64)); 28 free(self);
23 29 self = NULL;
24 if (!self->id) 30 }
25 die("nomem"); 31 }
26 32
27 return self; 33 return self;
28} 34}
29 35
30void 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)
31{ 43{
32 int pos = self->ids; 44 int pos = self->ids;
33 45
34 self->ids++; 46 self->ids++;
35 if (self->ids > self->size) { 47 if (self->ids > self->size) {
36 self->size *= 2; 48 int nsize = self->size * 2;
37 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
38 if (!self->id) 50
39 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
40 } 56 }
41 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
42} 59}
43 60
44/* 61/*
@@ -46,42 +63,52 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
46 */ 63 */
47struct perf_header *perf_header__new(void) 64struct perf_header *perf_header__new(void)
48{ 65{
49 struct perf_header *self = malloc(sizeof(*self)); 66 struct perf_header *self = zalloc(sizeof(*self));
50 67
51 if (!self) 68 if (self != NULL) {
52 die("nomem"); 69 self->size = 1;
70 self->attr = malloc(sizeof(void *));
53 71
54 self->frozen = 0; 72 if (self->attr == NULL) {
73 free(self);
74 self = NULL;
75 }
76 }
55 77
56 self->attrs = 0; 78 return self;
57 self->size = 1; 79}
58 self->attr = malloc(sizeof(void *));
59 80
60 if (!self->attr) 81void perf_header__delete(struct perf_header *self)
61 die("nomem"); 82{
83 int i;
62 84
63 self->data_offset = 0; 85 for (i = 0; i < self->attrs; ++i)
64 self->data_size = 0; 86 perf_header_attr__delete(self->attr[i]);
65 87
66 return self; 88 free(self->attr);
89 free(self);
67} 90}
68 91
69void perf_header__add_attr(struct perf_header *self, 92int perf_header__add_attr(struct perf_header *self,
70 struct perf_header_attr *attr) 93 struct perf_header_attr *attr)
71{ 94{
72 int pos = self->attrs;
73
74 if (self->frozen) 95 if (self->frozen)
75 die("frozen"); 96 return -1;
76 97
77 self->attrs++; 98 if (self->attrs == self->size) {
78 if (self->attrs > self->size) { 99 int nsize = self->size * 2;
79 self->size *= 2; 100 struct perf_header_attr **nattr;
80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 101
81 if (!self->attr) 102 nattr = realloc(self->attr, nsize * sizeof(void *));
82 die("nomem"); 103 if (nattr == NULL)
104 return -1;
105
106 self->size = nsize;
107 self->attr = nattr;
83 } 108 }
84 self->attr[pos] = attr; 109
110 self->attr[self->attrs++] = attr;
111 return 0;
85} 112}
86 113
87#define MAX_EVENT_NAME 64 114#define MAX_EVENT_NAME 64
@@ -97,7 +124,7 @@ static struct perf_trace_event_type *events;
97void perf_header__push_event(u64 id, const char *name) 124void perf_header__push_event(u64 id, const char *name)
98{ 125{
99 if (strlen(name) > MAX_EVENT_NAME) 126 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 127 pr_warning("Event %s will be truncated\n", name);
101 128
102 if (!events) { 129 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 130 events = malloc(sizeof(struct perf_trace_event_type));
@@ -128,44 +155,142 @@ static const char *__perf_magic = "PERFFILE";
128 155
129#define PERF_MAGIC (*(u64 *)__perf_magic) 156#define PERF_MAGIC (*(u64 *)__perf_magic)
130 157
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr { 158struct perf_file_attr {
137 struct perf_event_attr attr; 159 struct perf_event_attr attr;
138 struct perf_file_section ids; 160 struct perf_file_section ids;
139}; 161};
140 162
141struct perf_file_header { 163void perf_header__set_feat(struct perf_header *self, int feat)
142 u64 magic; 164{
143 u64 size; 165 set_bit(feat, self->adds_features);
144 u64 attr_size; 166}
145 struct perf_file_section attrs;
146 struct perf_file_section data;
147 struct perf_file_section event_types;
148};
149 167
150static void do_write(int fd, void *buf, size_t size) 168bool perf_header__has_feat(const struct perf_header *self, int feat)
169{
170 return test_bit(feat, self->adds_features);
171}
172
173static int do_write(int fd, const void *buf, size_t size)
151{ 174{
152 while (size) { 175 while (size) {
153 int ret = write(fd, buf, size); 176 int ret = write(fd, buf, size);
154 177
155 if (ret < 0) 178 if (ret < 0)
156 die("failed to write"); 179 return -errno;
157 180
158 size -= ret; 181 size -= ret;
159 buf += ret; 182 buf += ret;
160 } 183 }
184
185 return 0;
186}
187
188static int __dsos__write_buildid_table(struct list_head *head, int fd)
189{
190#define NAME_ALIGN 64
191 struct dso *pos;
192 static const char zero_buf[NAME_ALIGN];
193
194 list_for_each_entry(pos, head, node) {
195 int err;
196 struct build_id_event b;
197 size_t len;
198
199 if (!pos->has_build_id)
200 continue;
201 len = pos->long_name_len + 1;
202 len = ALIGN(len, NAME_ALIGN);
203 memset(&b, 0, sizeof(b));
204 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
205 b.header.size = sizeof(b) + len;
206 err = do_write(fd, &b, sizeof(b));
207 if (err < 0)
208 return err;
209 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
210 if (err < 0)
211 return err;
212 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
213 if (err < 0)
214 return err;
215 }
216
217 return 0;
161} 218}
162 219
163void perf_header__write(struct perf_header *self, int fd) 220static int dsos__write_buildid_table(int fd)
221{
222 int err = __dsos__write_buildid_table(&dsos__kernel, fd);
223 if (err == 0)
224 err = __dsos__write_buildid_table(&dsos__user, fd);
225 return err;
226}
227
228static int perf_header__adds_write(struct perf_header *self, int fd)
229{
230 int nr_sections;
231 struct perf_file_section *feat_sec;
232 int sec_size;
233 u64 sec_start;
234 int idx = 0, err;
235
236 if (dsos__read_build_ids())
237 perf_header__set_feat(self, HEADER_BUILD_ID);
238
239 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
240 if (!nr_sections)
241 return 0;
242
243 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
244 if (feat_sec == NULL)
245 return -ENOMEM;
246
247 sec_size = sizeof(*feat_sec) * nr_sections;
248
249 sec_start = self->data_offset + self->data_size;
250 lseek(fd, sec_start + sec_size, SEEK_SET);
251
252 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
253 struct perf_file_section *trace_sec;
254
255 trace_sec = &feat_sec[idx++];
256
257 /* Write trace info */
258 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
259 read_tracing_data(fd, attrs, nr_counters);
260 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
261 }
262
263
264 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
265 struct perf_file_section *buildid_sec;
266
267 buildid_sec = &feat_sec[idx++];
268
269 /* Write build-ids */
270 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
271 err = dsos__write_buildid_table(fd);
272 if (err < 0) {
273 pr_debug("failed to write buildid table\n");
274 goto out_free;
275 }
276 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
277 }
278
279 lseek(fd, sec_start, SEEK_SET);
280 err = do_write(fd, feat_sec, sec_size);
281 if (err < 0)
282 pr_debug("failed to write feature section\n");
283out_free:
284 free(feat_sec);
285 return err;
286}
287
288int perf_header__write(struct perf_header *self, int fd, bool at_exit)
164{ 289{
165 struct perf_file_header f_header; 290 struct perf_file_header f_header;
166 struct perf_file_attr f_attr; 291 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr; 292 struct perf_header_attr *attr;
168 int i; 293 int i, err;
169 294
170 lseek(fd, sizeof(f_header), SEEK_SET); 295 lseek(fd, sizeof(f_header), SEEK_SET);
171 296
@@ -174,7 +299,11 @@ void perf_header__write(struct perf_header *self, int fd)
174 attr = self->attr[i]; 299 attr = self->attr[i];
175 300
176 attr->id_offset = lseek(fd, 0, SEEK_CUR); 301 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); 302 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
303 if (err < 0) {
304 pr_debug("failed to write perf header\n");
305 return err;
306 }
178 } 307 }
179 308
180 309
@@ -190,17 +319,31 @@ void perf_header__write(struct perf_header *self, int fd)
190 .size = attr->ids * sizeof(u64), 319 .size = attr->ids * sizeof(u64),
191 } 320 }
192 }; 321 };
193 do_write(fd, &f_attr, sizeof(f_attr)); 322 err = do_write(fd, &f_attr, sizeof(f_attr));
323 if (err < 0) {
324 pr_debug("failed to write perf header attribute\n");
325 return err;
326 }
194 } 327 }
195 328
196 self->event_offset = lseek(fd, 0, SEEK_CUR); 329 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 330 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events) 331 if (events) {
199 do_write(fd, events, self->event_size); 332 err = do_write(fd, events, self->event_size);
200 333 if (err < 0) {
334 pr_debug("failed to write perf header events\n");
335 return err;
336 }
337 }
201 338
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 339 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 340
341 if (at_exit) {
342 err = perf_header__adds_write(self, fd);
343 if (err < 0)
344 return err;
345 }
346
204 f_header = (struct perf_file_header){ 347 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC, 348 .magic = PERF_MAGIC,
206 .size = sizeof(f_header), 349 .size = sizeof(f_header),
@@ -219,11 +362,18 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 362 },
220 }; 363 };
221 364
365 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
366
222 lseek(fd, 0, SEEK_SET); 367 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 368 err = do_write(fd, &f_header, sizeof(f_header));
369 if (err < 0) {
370 pr_debug("failed to write perf header\n");
371 return err;
372 }
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 373 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225 374
226 self->frozen = 1; 375 self->frozen = 1;
376 return 0;
227} 377}
228 378
229static void do_read(int fd, void *buf, size_t size) 379static void do_read(int fd, void *buf, size_t size)
@@ -241,22 +391,109 @@ static void do_read(int fd, void *buf, size_t size)
241 } 391 }
242} 392}
243 393
244struct perf_header *perf_header__read(int fd) 394int perf_header__process_sections(struct perf_header *self, int fd,
395 int (*process)(struct perf_file_section *self,
396 int feat, int fd))
397{
398 struct perf_file_section *feat_sec;
399 int nr_sections;
400 int sec_size;
401 int idx = 0;
402 int err = 0, feat = 1;
403
404 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
405 if (!nr_sections)
406 return 0;
407
408 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
409 if (!feat_sec)
410 return -1;
411
412 sec_size = sizeof(*feat_sec) * nr_sections;
413
414 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
415
416 do_read(fd, feat_sec, sec_size);
417
418 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
419 if (perf_header__has_feat(self, feat)) {
420 struct perf_file_section *sec = &feat_sec[idx++];
421
422 err = process(sec, feat, fd);
423 if (err < 0)
424 break;
425 }
426 ++feat;
427 }
428
429 free(feat_sec);
430 return err;
431};
432
433int perf_file_header__read(struct perf_file_header *self,
434 struct perf_header *ph, int fd)
435{
436 lseek(fd, 0, SEEK_SET);
437 do_read(fd, self, sizeof(*self));
438
439 if (self->magic != PERF_MAGIC ||
440 self->attr_size != sizeof(struct perf_file_attr))
441 return -1;
442
443 if (self->size != sizeof(*self)) {
444 /* Support the previous format */
445 if (self->size == offsetof(typeof(*self), adds_features))
446 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
447 else
448 return -1;
449 }
450
451 memcpy(&ph->adds_features, &self->adds_features,
452 sizeof(self->adds_features));
453
454 ph->event_offset = self->event_types.offset;
455 ph->event_size = self->event_types.size;
456 ph->data_offset = self->data.offset;
457 ph->data_size = self->data.size;
458 return 0;
459}
460
461static int perf_file_section__process(struct perf_file_section *self,
462 int feat, int fd)
463{
464 if (lseek(fd, self->offset, SEEK_SET) < 0) {
465 pr_debug("Failed to lseek to %Ld offset for feature %d, "
466 "continuing...\n", self->offset, feat);
467 return 0;
468 }
469
470 switch (feat) {
471 case HEADER_TRACE_INFO:
472 trace_report(fd);
473 break;
474
475 case HEADER_BUILD_ID:
476 if (perf_header__read_build_ids(fd, self->offset, self->size))
477 pr_debug("Failed to read buildids, continuing...\n");
478 break;
479 default:
480 pr_debug("unknown feature %d, continuing...\n", feat);
481 }
482
483 return 0;
484}
485
486int perf_header__read(struct perf_header *self, int fd)
245{ 487{
246 struct perf_header *self = perf_header__new();
247 struct perf_file_header f_header; 488 struct perf_file_header f_header;
248 struct perf_file_attr f_attr; 489 struct perf_file_attr f_attr;
249 u64 f_id; 490 u64 f_id;
250
251 int nr_attrs, nr_ids, i, j; 491 int nr_attrs, nr_ids, i, j;
252 492
253 lseek(fd, 0, SEEK_SET); 493 if (perf_file_header__read(&f_header, self, fd) < 0) {
254 do_read(fd, &f_header, sizeof(f_header)); 494 pr_debug("incompatible file format\n");
255 495 return -EINVAL;
256 if (f_header.magic != PERF_MAGIC || 496 }
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format");
260 497
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 498 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 499 lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -269,6 +506,8 @@ struct perf_header *perf_header__read(int fd)
269 tmp = lseek(fd, 0, SEEK_CUR); 506 tmp = lseek(fd, 0, SEEK_CUR);
270 507
271 attr = perf_header_attr__new(&f_attr.attr); 508 attr = perf_header_attr__new(&f_attr.attr);
509 if (attr == NULL)
510 return -ENOMEM;
272 511
273 nr_ids = f_attr.ids.size / sizeof(u64); 512 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET); 513 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -276,31 +515,34 @@ struct perf_header *perf_header__read(int fd)
276 for (j = 0; j < nr_ids; j++) { 515 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id)); 516 do_read(fd, &f_id, sizeof(f_id));
278 517
279 perf_header_attr__add_id(attr, f_id); 518 if (perf_header_attr__add_id(attr, f_id) < 0) {
519 perf_header_attr__delete(attr);
520 return -ENOMEM;
521 }
280 } 522 }
281 perf_header__add_attr(self, attr); 523 if (perf_header__add_attr(self, attr) < 0) {
524 perf_header_attr__delete(attr);
525 return -ENOMEM;
526 }
527
282 lseek(fd, tmp, SEEK_SET); 528 lseek(fd, tmp, SEEK_SET);
283 } 529 }
284 530
285 if (f_header.event_types.size) { 531 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET); 532 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size); 533 events = malloc(f_header.event_types.size);
288 if (!events) 534 if (events == NULL)
289 die("nomem"); 535 return -ENOMEM;
290 do_read(fd, events, f_header.event_types.size); 536 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 537 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 538 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295 539
296 self->data_offset = f_header.data.offset; 540 perf_header__process_sections(self, fd, perf_file_section__process);
297 self->data_size = f_header.data.size;
298 541
299 lseek(fd, self->data_offset, SEEK_SET); 542 lseek(fd, self->data_offset, SEEK_SET);
300 543
301 self->frozen = 1; 544 self->frozen = 1;
302 545 return 0;
303 return self;
304} 546}
305 547
306u64 perf_header__sample_type(struct perf_header *header) 548u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..d1dbe2b79c42 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,10 +1,13 @@
1#ifndef _PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define _PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
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,36 +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;
55 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
24}; 56};
25 57
26struct perf_header *perf_header__read(int fd); 58struct perf_header *perf_header__new(void);
27void perf_header__write(struct perf_header *self, int fd); 59void perf_header__delete(struct perf_header *self);
28 60
29void perf_header__add_attr(struct perf_header *self, 61int perf_header__read(struct perf_header *self, int fd);
30 struct perf_header_attr *attr); 62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
63
64int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr);
31 66
32void perf_header__push_event(u64 id, const char *name); 67void perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id); 68char *perf_header__find_event(u64 id);
34 69
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
71void perf_header_attr__delete(struct perf_header_attr *self);
35 72
36struct perf_header_attr * 73int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
37perf_header_attr__new(struct perf_event_attr *attr);
38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
39 74
40u64 perf_header__sample_type(struct perf_header *header); 75u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr * 76struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header); 77perf_header__find_attr(u64 id, struct perf_header *header);
78void perf_header__set_feat(struct perf_header *self, int feat);
79bool perf_header__has_feat(const struct perf_header *self, int feat);
43 80
81int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self,
83 int feat, int fd));
44 84
45struct perf_header *perf_header__new(void); 85#endif /* __PERF_HEADER_H */
46
47#endif /* _PERF_HEADER_H */
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
index 7128783637b4..7f5c6dedd714 100644
--- a/tools/perf/util/help.h
+++ b/tools/perf/util/help.h
@@ -1,5 +1,5 @@
1#ifndef HELP_H 1#ifndef __PERF_HELP_H
2#define HELP_H 2#define __PERF_HELP_H
3 3
4struct cmdnames { 4struct cmdnames {
5 size_t alloc; 5 size_t alloc;
@@ -26,4 +26,4 @@ int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds, 26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds); 27 struct cmdnames *other_cmds);
28 28
29#endif /* HELP_H */ 29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
new file mode 100644
index 000000000000..0ebf6ee16caa
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,202 @@
1#include "hist.h"
2
3struct rb_root hist;
4struct rb_root collapse_hists;
5struct rb_root output_hists;
6int callchain;
7
8struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5
11};
12
13/*
14 * histogram, sorted on item, collects counts
15 */
16
17struct hist_entry *__hist_entry__add(struct addr_location *al,
18 struct symbol *sym_parent,
19 u64 count, bool *hit)
20{
21 struct rb_node **p = &hist.rb_node;
22 struct rb_node *parent = NULL;
23 struct hist_entry *he;
24 struct hist_entry entry = {
25 .thread = al->thread,
26 .map = al->map,
27 .sym = al->sym,
28 .ip = al->addr,
29 .level = al->level,
30 .count = count,
31 .parent = sym_parent,
32 };
33 int cmp;
34
35 while (*p != NULL) {
36 parent = *p;
37 he = rb_entry(parent, struct hist_entry, rb_node);
38
39 cmp = hist_entry__cmp(&entry, he);
40
41 if (!cmp) {
42 *hit = true;
43 return he;
44 }
45
46 if (cmp < 0)
47 p = &(*p)->rb_left;
48 else
49 p = &(*p)->rb_right;
50 }
51
52 he = malloc(sizeof(*he));
53 if (!he)
54 return NULL;
55 *he = entry;
56 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist);
58 *hit = false;
59 return he;
60}
61
62int64_t
63hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
64{
65 struct sort_entry *se;
66 int64_t cmp = 0;
67
68 list_for_each_entry(se, &hist_entry__sort_list, list) {
69 cmp = se->cmp(left, right);
70 if (cmp)
71 break;
72 }
73
74 return cmp;
75}
76
77int64_t
78hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
79{
80 struct sort_entry *se;
81 int64_t cmp = 0;
82
83 list_for_each_entry(se, &hist_entry__sort_list, list) {
84 int64_t (*f)(struct hist_entry *, struct hist_entry *);
85
86 f = se->collapse ?: se->cmp;
87
88 cmp = f(left, right);
89 if (cmp)
90 break;
91 }
92
93 return cmp;
94}
95
96void hist_entry__free(struct hist_entry *he)
97{
98 free(he);
99}
100
101/*
102 * collapse the histogram
103 */
104
105void collapse__insert_entry(struct hist_entry *he)
106{
107 struct rb_node **p = &collapse_hists.rb_node;
108 struct rb_node *parent = NULL;
109 struct hist_entry *iter;
110 int64_t cmp;
111
112 while (*p != NULL) {
113 parent = *p;
114 iter = rb_entry(parent, struct hist_entry, rb_node);
115
116 cmp = hist_entry__collapse(iter, he);
117
118 if (!cmp) {
119 iter->count += he->count;
120 hist_entry__free(he);
121 return;
122 }
123
124 if (cmp < 0)
125 p = &(*p)->rb_left;
126 else
127 p = &(*p)->rb_right;
128 }
129
130 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists);
132}
133
134void collapse__resort(void)
135{
136 struct rb_node *next;
137 struct hist_entry *n;
138
139 if (!sort__need_collapse)
140 return;
141
142 next = rb_first(&hist);
143 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node);
146
147 rb_erase(&n->rb_node, &hist);
148 collapse__insert_entry(n);
149 }
150}
151
152/*
153 * reverse the map, sort on count.
154 */
155
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
157{
158 struct rb_node **p = &output_hists.rb_node;
159 struct rb_node *parent = NULL;
160 struct hist_entry *iter;
161
162 if (callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param);
165
166 while (*p != NULL) {
167 parent = *p;
168 iter = rb_entry(parent, struct hist_entry, rb_node);
169
170 if (he->count > iter->count)
171 p = &(*p)->rb_left;
172 else
173 p = &(*p)->rb_right;
174 }
175
176 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists);
178}
179
180void output__resort(u64 total_samples)
181{
182 struct rb_node *next;
183 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits;
186
187 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100);
189
190 if (sort__need_collapse)
191 tree = &collapse_hists;
192
193 next = rb_first(tree);
194
195 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node);
198
199 rb_erase(&n->rb_node, tree);
200 output__insert_entry(n, min_callchain_hits);
201 }
202}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..3020db0c9292
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,50 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38
39struct hist_entry *__hist_entry__add(struct addr_location *al,
40 struct symbol *parent,
41 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(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 *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49
50#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..94507639a8c4
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,3 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..8d63116e9435
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,29 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10#undef __KERNEL__
11
12static inline void set_bit(int nr, unsigned long *addr)
13{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15}
16
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{
19 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21}
22
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
24 long size, unsigned long offset);
25
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
27 long size, unsigned long offset);
28
29#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..a53d4ee1e0b7
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../util.h"
diff --git a/tools/perf/util/include/linux/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/levenshtein.h b/tools/perf/util/levenshtein.h
index 0173abeef52c..b0fcb6d8a881 100644
--- a/tools/perf/util/levenshtein.h
+++ b/tools/perf/util/levenshtein.h
@@ -1,8 +1,8 @@
1#ifndef LEVENSHTEIN_H 1#ifndef __PERF_LEVENSHTEIN_H
2#define LEVENSHTEIN_H 2#define __PERF_LEVENSHTEIN_H
3 3
4int levenshtein(const char *string1, const char *string2, 4int levenshtein(const char *string1, const char *string2,
5 int swap_penalty, int substition_penalty, 5 int swap_penalty, int substition_penalty,
6 int insertion_penalty, int deletion_penalty); 6 int insertion_penalty, int deletion_penalty);
7 7
8#endif 8#endif /* __PERF_LEVENSHTEIN_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 804e02382739..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/module.c b/tools/perf/util/module.c
deleted file mode 100644
index 0d8c85defcd2..000000000000
--- a/tools/perf/util/module.c
+++ /dev/null
@@ -1,545 +0,0 @@
1#include "util.h"
2#include "../perf.h"
3#include "string.h"
4#include "module.h"
5
6#include <libelf.h>
7#include <libgen.h>
8#include <gelf.h>
9#include <elf.h>
10#include <dirent.h>
11#include <sys/utsname.h>
12
13static unsigned int crc32(const char *p, unsigned int len)
14{
15 int i;
16 unsigned int crc = 0;
17
18 while (len--) {
19 crc ^= *p++;
20 for (i = 0; i < 8; i++)
21 crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
22 }
23 return crc;
24}
25
26/* module section methods */
27
28struct sec_dso *sec_dso__new_dso(const char *name)
29{
30 struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
31
32 if (self != NULL) {
33 strcpy(self->name, name);
34 self->secs = RB_ROOT;
35 self->find_section = sec_dso__find_section;
36 }
37
38 return self;
39}
40
41static void sec_dso__delete_section(struct section *self)
42{
43 free(((void *)self));
44}
45
46void sec_dso__delete_sections(struct sec_dso *self)
47{
48 struct section *pos;
49 struct rb_node *next = rb_first(&self->secs);
50
51 while (next) {
52 pos = rb_entry(next, struct section, rb_node);
53 next = rb_next(&pos->rb_node);
54 rb_erase(&pos->rb_node, &self->secs);
55 sec_dso__delete_section(pos);
56 }
57}
58
59void sec_dso__delete_self(struct sec_dso *self)
60{
61 sec_dso__delete_sections(self);
62 free(self);
63}
64
65static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
66{
67 struct rb_node **p = &self->secs.rb_node;
68 struct rb_node *parent = NULL;
69 const u64 hash = sec->hash;
70 struct section *s;
71
72 while (*p != NULL) {
73 parent = *p;
74 s = rb_entry(parent, struct section, rb_node);
75 if (hash < s->hash)
76 p = &(*p)->rb_left;
77 else
78 p = &(*p)->rb_right;
79 }
80 rb_link_node(&sec->rb_node, parent, p);
81 rb_insert_color(&sec->rb_node, &self->secs);
82}
83
84struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
85{
86 struct rb_node *n;
87 u64 hash;
88 int len;
89
90 if (self == NULL)
91 return NULL;
92
93 len = strlen(name);
94 hash = crc32(name, len);
95
96 n = self->secs.rb_node;
97
98 while (n) {
99 struct section *s = rb_entry(n, struct section, rb_node);
100
101 if (hash < s->hash)
102 n = n->rb_left;
103 else if (hash > s->hash)
104 n = n->rb_right;
105 else {
106 if (!strcmp(name, s->name))
107 return s;
108 else
109 n = rb_next(&s->rb_node);
110 }
111 }
112
113 return NULL;
114}
115
116static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
117{
118 return fprintf(fp, "name:%s vma:%llx path:%s\n",
119 self->name, self->vma, self->path);
120}
121
122size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
123{
124 size_t ret = fprintf(fp, "dso: %s\n", self->name);
125
126 struct rb_node *nd;
127 for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
128 struct section *pos = rb_entry(nd, struct section, rb_node);
129 ret += sec_dso__fprintf_section(pos, fp);
130 }
131
132 return ret;
133}
134
135static struct section *section__new(const char *name, const char *path)
136{
137 struct section *self = calloc(1, sizeof(*self));
138
139 if (!self)
140 goto out_failure;
141
142 self->name = calloc(1, strlen(name) + 1);
143 if (!self->name)
144 goto out_failure;
145
146 self->path = calloc(1, strlen(path) + 1);
147 if (!self->path)
148 goto out_failure;
149
150 strcpy(self->name, name);
151 strcpy(self->path, path);
152 self->hash = crc32(self->name, strlen(name));
153
154 return self;
155
156out_failure:
157 if (self) {
158 if (self->name)
159 free(self->name);
160 if (self->path)
161 free(self->path);
162 free(self);
163 }
164
165 return NULL;
166}
167
168/* module methods */
169
170struct mod_dso *mod_dso__new_dso(const char *name)
171{
172 struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
173
174 if (self != NULL) {
175 strcpy(self->name, name);
176 self->mods = RB_ROOT;
177 self->find_module = mod_dso__find_module;
178 }
179
180 return self;
181}
182
183static void mod_dso__delete_module(struct module *self)
184{
185 free(((void *)self));
186}
187
188void mod_dso__delete_modules(struct mod_dso *self)
189{
190 struct module *pos;
191 struct rb_node *next = rb_first(&self->mods);
192
193 while (next) {
194 pos = rb_entry(next, struct module, rb_node);
195 next = rb_next(&pos->rb_node);
196 rb_erase(&pos->rb_node, &self->mods);
197 mod_dso__delete_module(pos);
198 }
199}
200
201void mod_dso__delete_self(struct mod_dso *self)
202{
203 mod_dso__delete_modules(self);
204 free(self);
205}
206
207static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
208{
209 struct rb_node **p = &self->mods.rb_node;
210 struct rb_node *parent = NULL;
211 const u64 hash = mod->hash;
212 struct module *m;
213
214 while (*p != NULL) {
215 parent = *p;
216 m = rb_entry(parent, struct module, rb_node);
217 if (hash < m->hash)
218 p = &(*p)->rb_left;
219 else
220 p = &(*p)->rb_right;
221 }
222 rb_link_node(&mod->rb_node, parent, p);
223 rb_insert_color(&mod->rb_node, &self->mods);
224}
225
226struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
227{
228 struct rb_node *n;
229 u64 hash;
230 int len;
231
232 if (self == NULL)
233 return NULL;
234
235 len = strlen(name);
236 hash = crc32(name, len);
237
238 n = self->mods.rb_node;
239
240 while (n) {
241 struct module *m = rb_entry(n, struct module, rb_node);
242
243 if (hash < m->hash)
244 n = n->rb_left;
245 else if (hash > m->hash)
246 n = n->rb_right;
247 else {
248 if (!strcmp(name, m->name))
249 return m;
250 else
251 n = rb_next(&m->rb_node);
252 }
253 }
254
255 return NULL;
256}
257
258static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
259{
260 return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
261}
262
263size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
264{
265 struct rb_node *nd;
266 size_t ret;
267
268 ret = fprintf(fp, "dso: %s\n", self->name);
269
270 for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
271 struct module *pos = rb_entry(nd, struct module, rb_node);
272
273 ret += mod_dso__fprintf_module(pos, fp);
274 }
275
276 return ret;
277}
278
279static struct module *module__new(const char *name, const char *path)
280{
281 struct module *self = calloc(1, sizeof(*self));
282
283 if (!self)
284 goto out_failure;
285
286 self->name = calloc(1, strlen(name) + 1);
287 if (!self->name)
288 goto out_failure;
289
290 self->path = calloc(1, strlen(path) + 1);
291 if (!self->path)
292 goto out_failure;
293
294 strcpy(self->name, name);
295 strcpy(self->path, path);
296 self->hash = crc32(self->name, strlen(name));
297
298 return self;
299
300out_failure:
301 if (self) {
302 if (self->name)
303 free(self->name);
304 if (self->path)
305 free(self->path);
306 free(self);
307 }
308
309 return NULL;
310}
311
312static int mod_dso__load_sections(struct module *mod)
313{
314 int count = 0, path_len;
315 struct dirent *entry;
316 char *line = NULL;
317 char *dir_path;
318 DIR *dir;
319 size_t n;
320
321 path_len = strlen("/sys/module/");
322 path_len += strlen(mod->name);
323 path_len += strlen("/sections/");
324
325 dir_path = calloc(1, path_len + 1);
326 if (dir_path == NULL)
327 goto out_failure;
328
329 strcat(dir_path, "/sys/module/");
330 strcat(dir_path, mod->name);
331 strcat(dir_path, "/sections/");
332
333 dir = opendir(dir_path);
334 if (dir == NULL)
335 goto out_free;
336
337 while ((entry = readdir(dir))) {
338 struct section *section;
339 char *path, *vma;
340 int line_len;
341 FILE *file;
342
343 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
344 continue;
345
346 path = calloc(1, path_len + strlen(entry->d_name) + 1);
347 if (path == NULL)
348 break;
349 strcat(path, dir_path);
350 strcat(path, entry->d_name);
351
352 file = fopen(path, "r");
353 if (file == NULL) {
354 free(path);
355 break;
356 }
357
358 line_len = getline(&line, &n, file);
359 if (line_len < 0) {
360 free(path);
361 fclose(file);
362 break;
363 }
364
365 if (!line) {
366 free(path);
367 fclose(file);
368 break;
369 }
370
371 line[--line_len] = '\0'; /* \n */
372
373 vma = strstr(line, "0x");
374 if (!vma) {
375 free(path);
376 fclose(file);
377 break;
378 }
379 vma += 2;
380
381 section = section__new(entry->d_name, path);
382 if (!section) {
383 fprintf(stderr, "load_sections: allocation error\n");
384 free(path);
385 fclose(file);
386 break;
387 }
388
389 hex2u64(vma, &section->vma);
390 sec_dso__insert_section(mod->sections, section);
391
392 free(path);
393 fclose(file);
394 count++;
395 }
396
397 closedir(dir);
398 free(line);
399 free(dir_path);
400
401 return count;
402
403out_free:
404 free(dir_path);
405
406out_failure:
407 return count;
408}
409
410static int mod_dso__load_module_paths(struct mod_dso *self)
411{
412 struct utsname uts;
413 int count = 0, len, err = -1;
414 char *line = NULL;
415 FILE *file;
416 char *dpath, *dir;
417 size_t n;
418
419 if (uname(&uts) < 0)
420 return err;
421
422 len = strlen("/lib/modules/");
423 len += strlen(uts.release);
424 len += strlen("/modules.dep");
425
426 dpath = calloc(1, len + 1);
427 if (dpath == NULL)
428 return err;
429
430 strcat(dpath, "/lib/modules/");
431 strcat(dpath, uts.release);
432 strcat(dpath, "/modules.dep");
433
434 file = fopen(dpath, "r");
435 if (file == NULL)
436 goto out_failure;
437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
443 while (!feof(file)) {
444 struct module *module;
445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
448
449 line_len = getline(&line, &n, file);
450 if (line_len < 0)
451 break;
452
453 if (!line)
454 break;
455
456 line[--line_len] = '\0'; /* \n */
457
458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
464 if (!path)
465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
483
484 name = strdup(path);
485 if (!name)
486 break;
487
488 name = strtok(name, "/");
489 tmp = name;
490
491 while (tmp) {
492 tmp = strtok(NULL, "/");
493 if (tmp)
494 name = tmp;
495 }
496
497 name = strsep(&name, ".");
498 if (!name)
499 break;
500
501 /* Quirk: replace '-' with '_' in all modules */
502 for (len = strlen(name); len; len--) {
503 if (*(name+len) == '-')
504 *(name+len) = '_';
505 }
506
507 module = module__new(name, path);
508 if (!module)
509 break;
510 mod_dso__insert_module(self, module);
511
512 module->sections = sec_dso__new_dso("sections");
513 if (!module->sections)
514 break;
515
516 module->active = mod_dso__load_sections(module);
517
518 if (module->active > 0)
519 count++;
520 }
521
522 if (feof(file))
523 err = count;
524 else
525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
526
527out_failure:
528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
536}
537
538int mod_dso__load_modules(struct mod_dso *dso)
539{
540 int err;
541
542 err = mod_dso__load_module_paths(dso);
543
544 return err;
545}
diff --git a/tools/perf/util/module.h b/tools/perf/util/module.h
deleted file mode 100644
index 8a592ef641ca..000000000000
--- a/tools/perf/util/module.h
+++ /dev/null
@@ -1,53 +0,0 @@
1#ifndef _PERF_MODULE_
2#define _PERF_MODULE_ 1
3
4#include <linux/types.h>
5#include "../types.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8
9struct section {
10 struct rb_node rb_node;
11 u64 hash;
12 u64 vma;
13 char *name;
14 char *path;
15};
16
17struct sec_dso {
18 struct list_head node;
19 struct rb_root secs;
20 struct section *(*find_section)(struct sec_dso *, const char *name);
21 char name[0];
22};
23
24struct module {
25 struct rb_node rb_node;
26 u64 hash;
27 char *name;
28 char *path;
29 struct sec_dso *sections;
30 int active;
31};
32
33struct mod_dso {
34 struct list_head node;
35 struct rb_root mods;
36 struct module *(*find_module)(struct mod_dso *, const char *name);
37 char name[0];
38};
39
40struct sec_dso *sec_dso__new_dso(const char *name);
41void sec_dso__delete_sections(struct sec_dso *self);
42void sec_dso__delete_self(struct sec_dso *self);
43size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp);
44struct section *sec_dso__find_section(struct sec_dso *self, const char *name);
45
46struct mod_dso *mod_dso__new_dso(const char *name);
47void mod_dso__delete_modules(struct mod_dso *self);
48void mod_dso__delete_self(struct mod_dso *self);
49size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp);
50struct module *mod_dso__find_module(struct mod_dso *self, const char *name);
51int mod_dso__load_modules(struct mod_dso *dso);
52
53#endif /* _PERF_MODULE_ */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 8cfb48cbbea0..e5bc0fb016b2 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);
@@ -471,7 +467,6 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
471 while ((evt_ent = readdir(evt_dir))) { 467 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1]; 468 char event_opt[MAX_EVOPT_LEN + 1];
473 int len; 469 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475 470
476 if (!strcmp(evt_ent->d_name, ".") 471 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..") 472 || !strcmp(evt_ent->d_name, "..")
@@ -479,20 +474,12 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
479 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
480 continue; 475 continue;
481 476
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name, 477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
483 evt_ent->d_name); 478 evt_ent->d_name, flags ? ":" : "",
479 flags ?: "");
484 if (len < 0) 480 if (len < 0)
485 return EVT_FAILED; 481 return EVT_FAILED;
486 482
487 rem -= len;
488 if (flags) {
489 if (rem < strlen(flags) + 1)
490 return EVT_FAILED;
491
492 strcat(event_opt, ":");
493 strcat(event_opt, flags);
494 }
495
496 if (parse_events(NULL, event_opt, 0)) 483 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED; 484 return EVT_FAILED;
498 } 485 }
@@ -509,7 +496,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
509 char sys_name[MAX_EVENT_LENGTH]; 496 char sys_name[MAX_EVENT_LENGTH];
510 unsigned int sys_length, evt_length; 497 unsigned int sys_length, evt_length;
511 498
512 if (valid_debugfs_mount(debugfs_path)) 499 if (debugfs_valid_mountpoint(debugfs_path))
513 return 0; 500 return 0;
514 501
515 evt_name = strchr(*strp, ':'); 502 evt_name = strchr(*strp, ':');
@@ -544,6 +531,81 @@ static enum event_result parse_tracepoint_event(const char **strp,
544 attr, strp); 531 attr, strp);
545} 532}
546 533
534static enum event_result
535parse_breakpoint_type(const char *type, const char **strp,
536 struct perf_event_attr *attr)
537{
538 int i;
539
540 for (i = 0; i < 3; i++) {
541 if (!type[i])
542 break;
543
544 switch (type[i]) {
545 case 'r':
546 attr->bp_type |= HW_BREAKPOINT_R;
547 break;
548 case 'w':
549 attr->bp_type |= HW_BREAKPOINT_W;
550 break;
551 case 'x':
552 attr->bp_type |= HW_BREAKPOINT_X;
553 break;
554 default:
555 return EVT_FAILED;
556 }
557 }
558 if (!attr->bp_type) /* Default */
559 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
560
561 *strp = type + i;
562
563 return EVT_HANDLED;
564}
565
566static enum event_result
567parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
568{
569 const char *target;
570 const char *type;
571 char *endaddr;
572 u64 addr;
573 enum event_result err;
574
575 target = strchr(*strp, ':');
576 if (!target)
577 return EVT_FAILED;
578
579 if (strncmp(*strp, "mem", target - *strp) != 0)
580 return EVT_FAILED;
581
582 target++;
583
584 addr = strtoull(target, &endaddr, 0);
585 if (target == endaddr)
586 return EVT_FAILED;
587
588 attr->bp_addr = addr;
589 *strp = endaddr;
590
591 type = strchr(target, ':');
592
593 /* If no type is defined, just rw as default */
594 if (!type) {
595 attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
596 } else {
597 err = parse_breakpoint_type(++type, strp, attr);
598 if (err == EVT_FAILED)
599 return EVT_FAILED;
600 }
601
602 /* We should find a nice way to override the access type */
603 attr->bp_len = HW_BREAKPOINT_LEN_4;
604 attr->type = PERF_TYPE_BREAKPOINT;
605
606 return EVT_HANDLED;
607}
608
547static int check_events(const char *str, unsigned int i) 609static int check_events(const char *str, unsigned int i)
548{ 610{
549 int n; 611 int n;
@@ -677,6 +739,12 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
677 if (ret != EVT_FAILED) 739 if (ret != EVT_FAILED)
678 goto modifier; 740 goto modifier;
679 741
742 ret = parse_breakpoint_event(str, attr);
743 if (ret != EVT_FAILED)
744 goto modifier;
745
746 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
747 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
680 return EVT_FAILED; 748 return EVT_FAILED;
681 749
682modifier: 750modifier:
@@ -708,7 +776,6 @@ static void store_event_type(const char *orgname)
708 perf_header__push_event(id, orgname); 776 perf_header__push_event(id, orgname);
709} 777}
710 778
711
712int parse_events(const struct option *opt __used, const char *str, int unset __used) 779int parse_events(const struct option *opt __used, const char *str, int unset __used)
713{ 780{
714 struct perf_event_attr attr; 781 struct perf_event_attr attr;
@@ -745,6 +812,28 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
745 return 0; 812 return 0;
746} 813}
747 814
815int parse_filter(const struct option *opt __used, const char *str,
816 int unset __used)
817{
818 int i = nr_counters - 1;
819 int len = strlen(str);
820
821 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) {
822 fprintf(stderr,
823 "-F option should follow a -e tracepoint option\n");
824 return -1;
825 }
826
827 filters[i] = malloc(len + 1);
828 if (!filters[i]) {
829 fprintf(stderr, "not enough memory to hold filter string\n");
830 return -1;
831 }
832 strcpy(filters[i], str);
833
834 return 0;
835}
836
748static const char * const event_type_descriptors[] = { 837static const char * const event_type_descriptors[] = {
749 "", 838 "",
750 "Hardware event", 839 "Hardware event",
@@ -764,7 +853,7 @@ static void print_tracepoint_events(void)
764 char evt_path[MAXPATHLEN]; 853 char evt_path[MAXPATHLEN];
765 char dir_path[MAXPATHLEN]; 854 char dir_path[MAXPATHLEN];
766 855
767 if (valid_debugfs_mount(debugfs_path)) 856 if (debugfs_valid_mountpoint(debugfs_path))
768 return; 857 return;
769 858
770 sys_dir = opendir(debugfs_path); 859 sys_dir = opendir(debugfs_path);
@@ -782,7 +871,7 @@ static void print_tracepoint_events(void)
782 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 871 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
783 snprintf(evt_path, MAXPATHLEN, "%s:%s", 872 snprintf(evt_path, MAXPATHLEN, "%s:%s",
784 sys_dirent.d_name, evt_dirent.d_name); 873 sys_dirent.d_name, evt_dirent.d_name);
785 fprintf(stderr, " %-42s [%s]\n", evt_path, 874 printf(" %-42s [%s]\n", evt_path,
786 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
787 } 876 }
788 closedir(evt_dir); 877 closedir(evt_dir);
@@ -799,8 +888,8 @@ void print_events(void)
799 unsigned int i, type, op, prev_type = -1; 888 unsigned int i, type, op, prev_type = -1;
800 char name[40]; 889 char name[40];
801 890
802 fprintf(stderr, "\n"); 891 printf("\n");
803 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 892 printf("List of pre-defined events (to be used in -e):\n");
804 893
805 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
806 type = syms->type + 1; 895 type = syms->type + 1;
@@ -808,19 +897,19 @@ void print_events(void)
808 type = 0; 897 type = 0;
809 898
810 if (type != prev_type) 899 if (type != prev_type)
811 fprintf(stderr, "\n"); 900 printf("\n");
812 901
813 if (strlen(syms->alias)) 902 if (strlen(syms->alias))
814 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 903 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
815 else 904 else
816 strcpy(name, syms->symbol); 905 strcpy(name, syms->symbol);
817 fprintf(stderr, " %-42s [%s]\n", name, 906 printf(" %-42s [%s]\n", name,
818 event_type_descriptors[type]); 907 event_type_descriptors[type]);
819 908
820 prev_type = type; 909 prev_type = type;
821 } 910 }
822 911
823 fprintf(stderr, "\n"); 912 printf("\n");
824 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 913 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
825 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 914 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
826 /* skip invalid cache type */ 915 /* skip invalid cache type */
@@ -828,17 +917,20 @@ void print_events(void)
828 continue; 917 continue;
829 918
830 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
831 fprintf(stderr, " %-42s [%s]\n", 920 printf(" %-42s [%s]\n",
832 event_cache_name(type, op, i), 921 event_cache_name(type, op, i),
833 event_type_descriptors[4]); 922 event_type_descriptors[4]);
834 } 923 }
835 } 924 }
836 } 925 }
837 926
838 fprintf(stderr, "\n"); 927 printf("\n");
839 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 928 printf(" %-42s [raw hardware event descriptor]\n",
840 "rNNN"); 929 "rNNN");
841 fprintf(stderr, "\n"); 930 printf("\n");
931
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]");
933 printf("\n");
842 934
843 print_tracepoint_events(); 935 print_tracepoint_events();
844 936
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 30c608112845..b8c1f64bc935 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,5 +1,5 @@
1#ifndef _PARSE_EVENTS_H 1#ifndef __PERF_PARSE_EVENTS_H
2#define _PARSE_EVENTS_H 2#define __PERF_PARSE_EVENTS_H
3/* 3/*
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
@@ -17,11 +17,13 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
17extern int nr_counters; 17extern int nr_counters;
18 18
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
20extern char *filters[MAX_COUNTERS];
20 21
21extern const char *event_name(int ctr); 22extern const char *event_name(int ctr);
22extern const char *__event_name(int type, u64 config); 23extern const char *__event_name(int type, u64 config);
23 24
24extern int parse_events(const struct option *opt, const char *str, int unset); 25extern int parse_events(const struct option *opt, const char *str, int unset);
26extern int parse_filter(const struct option *opt, const char *str, int unset);
25 27
26#define EVENTS_HELP_MAX (128*1024) 28#define EVENTS_HELP_MAX (128*1024)
27 29
@@ -31,4 +33,4 @@ extern char debugfs_path[];
31extern int valid_debugfs_mount(const char *debugfs); 33extern int valid_debugfs_mount(const char *debugfs);
32 34
33 35
34#endif /* _PARSE_EVENTS_H */ 36#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 6d8af48c925e..efebd5b476b3 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -430,6 +430,9 @@ int usage_with_options_internal(const char * const *usagestr,
430 pos = fprintf(stderr, " "); 430 pos = fprintf(stderr, " ");
431 if (opts->short_name) 431 if (opts->short_name)
432 pos += fprintf(stderr, "-%c", opts->short_name); 432 pos += fprintf(stderr, "-%c", opts->short_name);
433 else
434 pos += fprintf(stderr, " ");
435
433 if (opts->long_name && opts->short_name) 436 if (opts->long_name && opts->short_name)
434 pos += fprintf(stderr, ", "); 437 pos += fprintf(stderr, ", ");
435 if (opts->long_name) 438 if (opts->long_name)
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 2ee248ff27e5..948805af43c2 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,5 +1,5 @@
1#ifndef PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4enum parse_opt_type { 4enum parse_opt_type {
5 /* special types */ 5 /* special types */
@@ -174,4 +174,4 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
174 174
175extern const char *parse_options_fix_filename(const char *prefix, const char *file); 175extern const char *parse_options_fix_filename(const char *prefix, const char *file);
176 176
177#endif 177#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
new file mode 100644
index 000000000000..d14a4585bcaf
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,587 @@
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 __attribute__((format(printf, 3, 4)));
52
53static int e_snprintf(char *str, size_t size, const char *format, ...)
54{
55 int ret;
56 va_list ap;
57 va_start(ap, format);
58 ret = vsnprintf(str, size, format, ap);
59 va_end(ap);
60 if (ret >= (int)size)
61 ret = -E2BIG;
62 return ret;
63}
64
65/* Parse probepoint definition. */
66static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
67{
68 char *ptr, *tmp;
69 char c, nc = 0;
70 /*
71 * <Syntax>
72 * perf probe SRC:LN
73 * perf probe FUNC[+OFFS|%return][@SRC]
74 */
75
76 ptr = strpbrk(arg, ":+@%");
77 if (ptr) {
78 nc = *ptr;
79 *ptr++ = '\0';
80 }
81
82 /* Check arg is function or file and copy it */
83 if (strchr(arg, '.')) /* File */
84 pp->file = strdup(arg);
85 else /* Function */
86 pp->function = strdup(arg);
87 DIE_IF(pp->file == NULL && pp->function == NULL);
88
89 /* Parse other options */
90 while (ptr) {
91 arg = ptr;
92 c = nc;
93 ptr = strpbrk(arg, ":+@%");
94 if (ptr) {
95 nc = *ptr;
96 *ptr++ = '\0';
97 }
98 switch (c) {
99 case ':': /* Line number */
100 pp->line = strtoul(arg, &tmp, 0);
101 if (*tmp != '\0')
102 semantic_error("There is non-digit charactor"
103 " in line number.");
104 break;
105 case '+': /* Byte offset from a symbol */
106 pp->offset = strtoul(arg, &tmp, 0);
107 if (*tmp != '\0')
108 semantic_error("There is non-digit charactor"
109 " in offset.");
110 break;
111 case '@': /* File name */
112 if (pp->file)
113 semantic_error("SRC@SRC is not allowed.");
114 pp->file = strdup(arg);
115 DIE_IF(pp->file == NULL);
116 if (ptr)
117 semantic_error("@SRC must be the last "
118 "option.");
119 break;
120 case '%': /* Probe places */
121 if (strcmp(arg, "return") == 0) {
122 pp->retprobe = 1;
123 } else /* Others not supported yet */
124 semantic_error("%%%s is not supported.", arg);
125 break;
126 default:
127 DIE_IF("Program has a bug.");
128 break;
129 }
130 }
131
132 /* Exclusion check */
133 if (pp->line && pp->offset)
134 semantic_error("Offset can't be used with line number.");
135
136 if (!pp->line && pp->file && !pp->function)
137 semantic_error("File always requires line number.");
138
139 if (pp->offset && !pp->function)
140 semantic_error("Offset requires an entry function.");
141
142 if (pp->retprobe && !pp->function)
143 semantic_error("Return probe requires an entry function.");
144
145 if ((pp->offset || pp->line) && pp->retprobe)
146 semantic_error("Offset/Line can't be used with return probe.");
147
148 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
149 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
150}
151
152/* Parse perf-probe event definition */
153int parse_perf_probe_event(const char *str, struct probe_point *pp)
154{
155 char **argv;
156 int argc, i, need_dwarf = 0;
157
158 argv = argv_split(str, &argc);
159 if (!argv)
160 die("argv_split failed.");
161 if (argc > MAX_PROBE_ARGS + 1)
162 semantic_error("Too many arguments");
163
164 /* Parse probe point */
165 parse_perf_probe_probepoint(argv[0], pp);
166 if (pp->file || pp->line)
167 need_dwarf = 1;
168
169 /* Copy arguments and ensure return probe has no C argument */
170 pp->nr_args = argc - 1;
171 pp->args = zalloc(sizeof(char *) * pp->nr_args);
172 for (i = 0; i < pp->nr_args; i++) {
173 pp->args[i] = strdup(argv[i + 1]);
174 if (!pp->args[i])
175 die("Failed to copy argument.");
176 if (is_c_varname(pp->args[i])) {
177 if (pp->retprobe)
178 semantic_error("You can't specify local"
179 " variable for kretprobe");
180 need_dwarf = 1;
181 }
182 }
183
184 argv_free(argv);
185 return need_dwarf;
186}
187
188/* Parse kprobe_events event into struct probe_point */
189void parse_trace_kprobe_event(const char *str, char **group, char **event,
190 struct probe_point *pp)
191{
192 char pr;
193 char *p;
194 int ret, i, argc;
195 char **argv;
196
197 pr_debug("Parsing kprobe_events: %s\n", str);
198 argv = argv_split(str, &argc);
199 if (!argv)
200 die("argv_split failed.");
201 if (argc < 2)
202 semantic_error("Too less arguments.");
203
204 /* Scan event and group name. */
205 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
206 &pr, (float *)(void *)group, (float *)(void *)event);
207 if (ret != 3)
208 semantic_error("Failed to parse event name: %s", argv[0]);
209 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr);
210
211 if (!pp)
212 goto end;
213
214 pp->retprobe = (pr == 'r');
215
216 /* Scan function name and offset */
217 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset);
218 if (ret == 1)
219 pp->offset = 0;
220
221 /* kprobe_events doesn't have this information */
222 pp->line = 0;
223 pp->file = NULL;
224
225 pp->nr_args = argc - 2;
226 pp->args = zalloc(sizeof(char *) * pp->nr_args);
227 for (i = 0; i < pp->nr_args; i++) {
228 p = strchr(argv[i + 2], '=');
229 if (p) /* We don't need which register is assigned. */
230 *p = '\0';
231 pp->args[i] = strdup(argv[i + 2]);
232 if (!pp->args[i])
233 die("Failed to copy argument.");
234 }
235
236end:
237 argv_free(argv);
238}
239
240int synthesize_perf_probe_event(struct probe_point *pp)
241{
242 char *buf;
243 char offs[64] = "", line[64] = "";
244 int i, len, ret;
245
246 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
247 if (!buf)
248 die("Failed to allocate memory by zalloc.");
249 if (pp->offset) {
250 ret = e_snprintf(offs, 64, "+%d", pp->offset);
251 if (ret <= 0)
252 goto error;
253 }
254 if (pp->line) {
255 ret = e_snprintf(line, 64, ":%d", pp->line);
256 if (ret <= 0)
257 goto error;
258 }
259
260 if (pp->function)
261 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
262 offs, pp->retprobe ? "%return" : "", line);
263 else
264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
265 if (ret <= 0)
266 goto error;
267 len = ret;
268
269 for (i = 0; i < pp->nr_args; i++) {
270 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
271 pp->args[i]);
272 if (ret <= 0)
273 goto error;
274 len += ret;
275 }
276 pp->found = 1;
277
278 return pp->found;
279error:
280 free(pp->probes[0]);
281
282 return ret;
283}
284
285int synthesize_trace_kprobe_event(struct probe_point *pp)
286{
287 char *buf;
288 int i, len, ret;
289
290 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
291 if (!buf)
292 die("Failed to allocate memory by zalloc.");
293 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
294 if (ret <= 0)
295 goto error;
296 len = ret;
297
298 for (i = 0; i < pp->nr_args; i++) {
299 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
300 pp->args[i]);
301 if (ret <= 0)
302 goto error;
303 len += ret;
304 }
305 pp->found = 1;
306
307 return pp->found;
308error:
309 free(pp->probes[0]);
310
311 return ret;
312}
313
314static int open_kprobe_events(int flags, int mode)
315{
316 char buf[PATH_MAX];
317 int ret;
318
319 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
320 if (ret < 0)
321 die("Failed to make kprobe_events path.");
322
323 ret = open(buf, flags, mode);
324 if (ret < 0) {
325 if (errno == ENOENT)
326 die("kprobe_events file does not exist -"
327 " please rebuild with CONFIG_KPROBE_TRACER.");
328 else
329 die("Could not open kprobe_events file: %s",
330 strerror(errno));
331 }
332 return ret;
333}
334
335/* Get raw string list of current kprobe_events */
336static struct strlist *get_trace_kprobe_event_rawlist(int fd)
337{
338 int ret, idx;
339 FILE *fp;
340 char buf[MAX_CMDLEN];
341 char *p;
342 struct strlist *sl;
343
344 sl = strlist__new(true, NULL);
345
346 fp = fdopen(dup(fd), "r");
347 while (!feof(fp)) {
348 p = fgets(buf, MAX_CMDLEN, fp);
349 if (!p)
350 break;
351
352 idx = strlen(p) - 1;
353 if (p[idx] == '\n')
354 p[idx] = '\0';
355 ret = strlist__add(sl, buf);
356 if (ret < 0)
357 die("strlist__add failed: %s", strerror(-ret));
358 }
359 fclose(fp);
360
361 return sl;
362}
363
364/* Free and zero clear probe_point */
365static void clear_probe_point(struct probe_point *pp)
366{
367 int i;
368
369 if (pp->function)
370 free(pp->function);
371 if (pp->file)
372 free(pp->file);
373 for (i = 0; i < pp->nr_args; i++)
374 free(pp->args[i]);
375 if (pp->args)
376 free(pp->args);
377 for (i = 0; i < pp->found; i++)
378 free(pp->probes[i]);
379 memset(pp, 0, sizeof(*pp));
380}
381
382/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event,
384 const char *place, struct probe_point *pp)
385{
386 int i;
387 char buf[128];
388
389 e_snprintf(buf, 128, "%s:%s", group, event);
390 printf(" %-40s (on %s", buf, place);
391
392 if (pp->nr_args > 0) {
393 printf(" with");
394 for (i = 0; i < pp->nr_args; i++)
395 printf(" %s", pp->args[i]);
396 }
397 printf(")\n");
398}
399
400/* List up current perf-probe events */
401void show_perf_probe_events(void)
402{
403 unsigned int i;
404 int fd, nr;
405 char *group, *event;
406 struct probe_point pp;
407 struct strlist *rawlist;
408 struct str_node *ent;
409
410 fd = open_kprobe_events(O_RDONLY, 0);
411 rawlist = get_trace_kprobe_event_rawlist(fd);
412 close(fd);
413
414 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
415 ent = strlist__entry(rawlist, i);
416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */
418 nr = pp.nr_args;
419 pp.nr_args = 0;
420 synthesize_perf_probe_event(&pp);
421 pp.nr_args = nr;
422 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp);
424 free(group);
425 free(event);
426 clear_probe_point(&pp);
427 }
428
429 strlist__delete(rawlist);
430}
431
432/* Get current perf-probe event names */
433static struct strlist *get_perf_event_names(int fd, bool include_group)
434{
435 unsigned int i;
436 char *group, *event;
437 char buf[128];
438 struct strlist *sl, *rawlist;
439 struct str_node *ent;
440
441 rawlist = get_trace_kprobe_event_rawlist(fd);
442
443 sl = strlist__new(true, NULL);
444 for (i = 0; i < strlist__nr_entries(rawlist); i++) {
445 ent = strlist__entry(rawlist, i);
446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
447 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
449 die("Failed to copy group:event name.");
450 strlist__add(sl, buf);
451 } else
452 strlist__add(sl, event);
453 free(group);
454 free(event);
455 }
456
457 strlist__delete(rawlist);
458
459 return sl;
460}
461
462static void write_trace_kprobe_event(int fd, const char *buf)
463{
464 int ret;
465
466 pr_debug("Writing event: %s\n", buf);
467 ret = write(fd, buf, strlen(buf));
468 if (ret <= 0)
469 die("Failed to write event: %s", strerror(errno));
470}
471
472static void get_new_event_name(char *buf, size_t len, const char *base,
473 struct strlist *namelist)
474{
475 int i, ret;
476
477 /* Try no suffix */
478 ret = e_snprintf(buf, len, "%s", base);
479 if (ret < 0)
480 die("snprintf() failed: %s", strerror(-ret));
481 if (!strlist__has_entry(namelist, buf))
482 return;
483
484 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) {
486 ret = e_snprintf(buf, len, "%s_%d", base, i);
487 if (ret < 0)
488 die("snprintf() failed: %s", strerror(-ret));
489 if (!strlist__has_entry(namelist, buf))
490 break;
491 }
492 if (i == MAX_EVENT_INDEX)
493 die("Too many events are on the same function.");
494}
495
496void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
497{
498 int i, j, fd;
499 struct probe_point *pp;
500 char buf[MAX_CMDLEN];
501 char event[64];
502 struct strlist *namelist;
503
504 fd = open_kprobe_events(O_RDWR, O_APPEND);
505 /* Get current event names */
506 namelist = get_perf_event_names(fd, false);
507
508 for (j = 0; j < nr_probes; j++) {
509 pp = probes + j;
510 for (i = 0; i < pp->found; i++) {
511 /* Get an unused new event name */
512 get_new_event_name(event, 64, pp->function, namelist);
513 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
514 pp->retprobe ? 'r' : 'p',
515 PERFPROBE_GROUP, event,
516 pp->probes[i]);
517 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event,
522 buf, pp);
523 /* Add added event name to namelist */
524 strlist__add(namelist, event);
525 }
526 }
527 /* Show how to use the event. */
528 printf("\nYou can now use it on all perf tools, such as:\n\n");
529 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
530
531 strlist__delete(namelist);
532 close(fd);
533}
534
535static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist)
537{
538 char buf[128];
539
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549
550 write_trace_kprobe_event(fd, buf);
551 printf("Remove event: %s:%s\n", group, event);
552}
553
554void del_trace_kprobe_events(struct strlist *dellist)
555{
556 int fd;
557 unsigned int i;
558 const char *group, *event;
559 char *p, *str;
560 struct str_node *ent;
561 struct strlist *namelist;
562
563 fd = open_kprobe_events(O_RDWR, O_APPEND);
564 /* Get current event names */
565 namelist = get_perf_event_names(fd, true);
566
567 for (i = 0; i < strlist__nr_entries(dellist); i++) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s);
570 if (!str)
571 die("Failed to copy event.");
572 p = strchr(str, ':');
573 if (p) {
574 group = str;
575 *p = '\0';
576 event = p + 1;
577 } else {
578 group = PERFPROBE_GROUP;
579 event = str;
580 }
581 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str);
583 }
584 strlist__delete(namelist);
585 close(fd);
586}
587
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..f752159124ae
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,19 @@
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 del_trace_kprobe_events(struct strlist *dellist);
14extern void show_perf_probe_events(void);
15
16/* Maximum index number of event-name postfix */
17#define MAX_EVENT_INDEX 1024
18
19#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..4585f1d86792
--- /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/quote.h b/tools/perf/util/quote.h
index a5454a1d1c13..b6a019733919 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -1,5 +1,5 @@
1#ifndef QUOTE_H 1#ifndef __PERF_QUOTE_H
2#define QUOTE_H 2#define __PERF_QUOTE_H
3 3
4#include <stddef.h> 4#include <stddef.h>
5#include <stdio.h> 5#include <stdio.h>
@@ -65,4 +65,4 @@ extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src); 65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src); 66extern void tcl_quote_print(FILE *stream, const char *src);
67 67
68#endif 68#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index cc1837deba88..d79028727ce2 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -1,5 +1,5 @@
1#ifndef RUN_COMMAND_H 1#ifndef __PERF_RUN_COMMAND_H
2#define RUN_COMMAND_H 2#define __PERF_RUN_COMMAND_H
3 3
4enum { 4enum {
5 ERR_RUN_COMMAND_FORK = 10000, 5 ERR_RUN_COMMAND_FORK = 10000,
@@ -85,4 +85,4 @@ struct async {
85int start_async(struct async *async); 85int start_async(struct async *async);
86int finish_async(struct async *async); 86int finish_async(struct async *async);
87 87
88#endif 88#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..b490354d1b23
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,290 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
12
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep;
18
19LIST_HEAD(hist_entry__sort_list);
20
21struct sort_entry sort_thread = {
22 .header = "Command: Pid",
23 .cmp = sort__thread_cmp,
24 .print = sort__thread_print,
25 .width = &threads__col_width,
26};
27
28struct sort_entry sort_comm = {
29 .header = "Command",
30 .cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse,
32 .print = sort__comm_print,
33 .width = &comms__col_width,
34};
35
36struct sort_entry sort_dso = {
37 .header = "Shared Object",
38 .cmp = sort__dso_cmp,
39 .print = sort__dso_print,
40 .width = &dsos__col_width,
41};
42
43struct sort_entry sort_sym = {
44 .header = "Symbol",
45 .cmp = sort__sym_cmp,
46 .print = sort__sym_print,
47};
48
49struct sort_entry sort_parent = {
50 .header = "Parent symbol",
51 .cmp = sort__parent_cmp,
52 .print = sort__parent_print,
53 .width = &parent_symbol__col_width,
54};
55
56struct sort_dimension {
57 const char *name;
58 struct sort_entry *entry;
59 int taken;
60};
61
62static struct sort_dimension sort_dimensions[] = {
63 { .name = "pid", .entry = &sort_thread, },
64 { .name = "comm", .entry = &sort_comm, },
65 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, },
68};
69
70int64_t cmp_null(void *l, void *r)
71{
72 if (!l && !r)
73 return 0;
74 else if (!l)
75 return -1;
76 else
77 return 1;
78}
79
80/* --sort pid */
81
82int64_t
83sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
84{
85 return right->thread->pid - left->thread->pid;
86}
87
88int repsep_fprintf(FILE *fp, const char *fmt, ...)
89{
90 int n;
91 va_list ap;
92
93 va_start(ap, fmt);
94 if (!field_sep)
95 n = vfprintf(fp, fmt, ap);
96 else {
97 char *bf = NULL;
98 n = vasprintf(&bf, fmt, ap);
99 if (n > 0) {
100 char *sep = bf;
101
102 while (1) {
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 }
109 fputs(bf, fp);
110 free(bf);
111 }
112 va_end(ap);
113 return n;
114}
115
116size_t
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
118{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6,
120 self->thread->comm ?: "", self->thread->pid);
121}
122
123size_t
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
125{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
127}
128
129/* --sort dso */
130
131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL;
136 const char *dso_name_l, *dso_name_r;
137
138 if (!dso_l || !dso_r)
139 return cmp_null(dso_l, dso_r);
140
141 if (verbose) {
142 dso_name_l = dso_l->long_name;
143 dso_name_r = dso_r->long_name;
144 } else {
145 dso_name_l = dso_l->short_name;
146 dso_name_r = dso_r->short_name;
147 }
148
149 return strcmp(dso_name_l, dso_name_r);
150}
151
152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{
155 if (self->map && self->map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name :
157 self->map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 }
160
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
162}
163
164/* --sort symbol */
165
166int64_t
167sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{
169 u64 ip_l, ip_r;
170
171 if (left->sym == right->sym)
172 return 0;
173
174 ip_l = left->sym ? left->sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180
181size_t
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{
184 size_t ret = 0;
185
186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 }
190
191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name);
194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196
197 return ret;
198}
199
200/* --sort comm */
201
202int64_t
203sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
204{
205 return right->thread->pid - left->thread->pid;
206}
207
208int64_t
209sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
210{
211 char *comm_l = left->thread->comm;
212 char *comm_r = right->thread->comm;
213
214 if (!comm_l || !comm_r)
215 return cmp_null(comm_l, comm_r);
216
217 return strcmp(comm_l, comm_r);
218}
219
220/* --sort parent */
221
222int64_t
223sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
224{
225 struct symbol *sym_l = left->parent;
226 struct symbol *sym_r = right->parent;
227
228 if (!sym_l || !sym_r)
229 return cmp_null(sym_l, sym_r);
230
231 return strcmp(sym_l->name, sym_r->name);
232}
233
234size_t
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
236{
237 return repsep_fprintf(fp, "%-*s", width,
238 self->parent ? self->parent->name : "[other]");
239}
240
241int sort_dimension__add(const char *tok)
242{
243 unsigned int i;
244
245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
246 struct sort_dimension *sd = &sort_dimensions[i];
247
248 if (sd->taken)
249 continue;
250
251 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue;
253
254 if (sd->entry->collapse)
255 sort__need_collapse = 1;
256
257 if (sd->entry == &sort_parent) {
258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
259 if (ret) {
260 char err[BUFSIZ];
261
262 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s",
264 parent_pattern, err);
265 exit(-1);
266 }
267 sort__has_parent = 1;
268 }
269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
284 sd->taken = 1;
285
286 return 0;
287 }
288
289 return -ESRCH;
290}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..333e664ff45f
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,99 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension;
43
44struct hist_entry {
45 struct rb_node rb_node;
46 u64 count;
47 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip;
51 char level;
52 struct symbol *parent;
53 struct callchain_node callchain;
54 struct rb_root sorted_chain;
55};
56
57enum sort_type {
58 SORT_PID,
59 SORT_COMM,
60 SORT_DSO,
61 SORT_SYM,
62 SORT_PARENT
63};
64
65/*
66 * configurable sorting bits
67 */
68
69struct sort_entry {
70 struct list_head list;
71
72 const char *header;
73
74 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
75 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
76 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
77 unsigned int *width;
78 bool elide;
79};
80
81extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list;
83
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
87extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
88extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
89extern int64_t cmp_null(void *, void *);
90extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
91extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
92extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
93extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
94extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *);
98
99#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..f24a8cc933d5 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,4 +1,5 @@
1#include "string.h" 1#include "string.h"
2#include "util.h"
2 3
3static int hex(char ch) 4static int hex(char ch)
4{ 5{
@@ -32,3 +33,196 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46
47#define K 1024LL
48/*
49 * perf_atoll()
50 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51 * and return its numeric value
52 */
53s64 perf_atoll(const char *str)
54{
55 unsigned int i;
56 s64 length = -1, unit = 1;
57
58 if (!isdigit(str[0]))
59 goto out_err;
60
61 for (i = 1; i < strlen(str); i++) {
62 switch (str[i]) {
63 case 'B':
64 case 'b':
65 break;
66 case 'K':
67 if (str[i + 1] != 'B')
68 goto out_err;
69 else
70 goto kilo;
71 case 'k':
72 if (str[i + 1] != 'b')
73 goto out_err;
74kilo:
75 unit = K;
76 break;
77 case 'M':
78 if (str[i + 1] != 'B')
79 goto out_err;
80 else
81 goto mega;
82 case 'm':
83 if (str[i + 1] != 'b')
84 goto out_err;
85mega:
86 unit = K * K;
87 break;
88 case 'G':
89 if (str[i + 1] != 'B')
90 goto out_err;
91 else
92 goto giga;
93 case 'g':
94 if (str[i + 1] != 'b')
95 goto out_err;
96giga:
97 unit = K * K * K;
98 break;
99 case 'T':
100 if (str[i + 1] != 'B')
101 goto out_err;
102 else
103 goto tera;
104 case 't':
105 if (str[i + 1] != 'b')
106 goto out_err;
107tera:
108 unit = K * K * K * K;
109 break;
110 case '\0': /* only specified figures */
111 unit = 1;
112 break;
113 default:
114 if (!isdigit(str[i]))
115 goto out_err;
116 break;
117 }
118 }
119
120 length = atoll(str) * unit;
121 goto out;
122
123out_err:
124 length = -1;
125out:
126 return length;
127}
128
129/*
130 * Helper function for splitting a string into an argv-like array.
131 * originaly copied from lib/argv_split.c
132 */
133static const char *skip_sep(const char *cp)
134{
135 while (*cp && isspace(*cp))
136 cp++;
137
138 return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143 while (*cp && !isspace(*cp))
144 cp++;
145
146 return cp;
147}
148
149static int count_argc(const char *str)
150{
151 int count = 0;
152
153 while (*str) {
154 str = skip_sep(str);
155 if (*str) {
156 count++;
157 str = skip_arg(str);
158 }
159 }
160
161 return count;
162}
163
164/**
165 * argv_free - free an argv
166 * @argv - the argument vector to be freed
167 *
168 * Frees an argv and the strings it points to.
169 */
170void argv_free(char **argv)
171{
172 char **p;
173 for (p = argv; *p; p++)
174 free(*p);
175
176 free(argv);
177}
178
179/**
180 * argv_split - split a string at whitespace, returning an argv
181 * @str: the string to be split
182 * @argcp: returned argument count
183 *
184 * Returns an array of pointers to strings which are split out from
185 * @str. This is performed by strictly splitting on white-space; no
186 * quote processing is performed. Multiple whitespace characters are
187 * considered to be a single argument separator. The returned array
188 * is always NULL-terminated. Returns NULL on memory allocation
189 * failure.
190 */
191char **argv_split(const char *str, int *argcp)
192{
193 int argc = count_argc(str);
194 char **argv = zalloc(sizeof(*argv) * (argc+1));
195 char **argvp;
196
197 if (argv == NULL)
198 goto out;
199
200 if (argcp)
201 *argcp = argc;
202
203 argvp = argv;
204
205 while (*str) {
206 str = skip_sep(str);
207
208 if (*str) {
209 const char *p = str;
210 char *t;
211
212 str = skip_arg(str);
213
214 t = strndup(p, str-p);
215 if (t == NULL)
216 goto fail;
217 *argvp++ = t;
218 }
219 }
220 *argvp = NULL;
221
222out:
223 return argv;
224
225fail:
226 argv_free(argv);
227 return NULL;
228}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..bfecec265a1a 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,15 @@
1#ifndef _PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include "types.h" 4#include "types.h"
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
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);
7 11
8#define _STR(x) #x 12#define _STR(x) #x
9#define STR(x) _STR(x) 13#define STR(x) _STR(x)
10 14
11#endif 15#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..cb4659306d7b 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
@@ -36,4 +36,4 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
36} 36}
37 37
38int strlist__parse_list(struct strlist *self, const char *s); 38int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */ 39#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 226f44a2357d..e7508ad3450f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2,14 +2,20 @@
2#include "../perf.h" 2#include "../perf.h"
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5#include "thread.h"
5 6
6#include "debug.h" 7#include "debug.h"
7 8
9#include <asm/bug.h>
8#include <libelf.h> 10#include <libelf.h>
9#include <gelf.h> 11#include <gelf.h>
10#include <elf.h> 12#include <elf.h>
13#include <limits.h>
14#include <sys/utsname.h>
11 15
12const char *sym_hist_filter; 16#ifndef NT_GNU_BUILD_ID
17#define NT_GNU_BUILD_ID 3
18#endif
13 19
14enum dso_origin { 20enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 21 DSO__ORIG_KERNEL = 0,
@@ -18,94 +24,189 @@ enum dso_origin {
18 DSO__ORIG_UBUNTU, 24 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 25 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 26 DSO__ORIG_DSO,
27 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 28 DSO__ORIG_NOT_FOUND,
22}; 29};
23 30
24static struct symbol *symbol__new(u64 start, u64 len, 31static void dsos__add(struct list_head *head, struct dso *dso);
25 const char *name, unsigned int priv_size, 32static struct map *thread__find_map_by_name(struct thread *self, char *name);
26 u64 obj_start, int v) 33static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
34struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
35static int dso__load_kernel_sym(struct dso *self, struct map *map,
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)
27{ 50{
28 size_t namelen = strlen(name) + 1; 51 return self->loaded & (1 << type);
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 52}
30 53
31 if (!self) 54static void dso__set_loaded(struct dso *self, enum map_type type)
32 return NULL; 55{
56 self->loaded |= (1 << type);
57}
33 58
34 if (v >= 2) 59static void symbols__fixup_end(struct rb_root *self)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 60{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 61 struct rb_node *nd, *prevnd = rb_first(self);
62 struct symbol *curr, *prev;
63
64 if (prevnd == NULL)
65 return;
37 66
38 self->obj_start= obj_start; 67 curr = rb_entry(prevnd, struct symbol, rb_node);
39 self->hist = NULL;
40 self->hist_sum = 0;
41 68
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 69 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
43 self->hist = calloc(sizeof(u64), len); 70 prev = curr;
71 curr = rb_entry(nd, struct symbol, rb_node);
44 72
45 if (priv_size) { 73 if (prev->end == prev->start)
46 memset(self, 0, priv_size); 74 prev->end = curr->start - 1;
47 self = ((void *)self) + priv_size;
48 } 75 }
76
77 /* Last entry */
78 if (curr->end == curr->start)
79 curr->end = roundup(curr->start, 4096);
80}
81
82static void __thread__fixup_maps_end(struct thread *self, enum map_type type)
83{
84 struct map *prev, *curr;
85 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
86
87 if (prevnd == NULL)
88 return;
89
90 curr = rb_entry(prevnd, struct map, rb_node);
91
92 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
93 prev = curr;
94 curr = rb_entry(nd, struct map, rb_node);
95 prev->end = curr->start - 1;
96 }
97
98 /*
99 * We still haven't the actual symbols, so guess the
100 * last map final address.
101 */
102 curr->end = ~0UL;
103}
104
105static void thread__fixup_maps_end(struct thread *self)
106{
107 int i;
108 for (i = 0; i < MAP__NR_TYPES; ++i)
109 __thread__fixup_maps_end(self, i);
110}
111
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)
118 return NULL;
119
120 if (symbol__priv_size)
121 self = ((void *)self) + symbol__priv_size;
122
49 self->start = start; 123 self->start = start;
50 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
51 memcpy(self->name, name, namelen); 128 memcpy(self->name, name, namelen);
52 129
53 return self; 130 return self;
54} 131}
55 132
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 133static void symbol__delete(struct symbol *self)
57{ 134{
58 free(((void *)self) - priv_size); 135 free(((void *)self) - symbol__priv_size);
59} 136}
60 137
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 138static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 139{
63 if (!self->module) 140 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 141 self->start, self->end, self->name);
66 else
67 return fprintf(fp, " %llx-%llx %s \t[%s]\n",
68 self->start, self->end, self->name, self->module->name);
69} 142}
70 143
71struct 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)
72{ 158{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 159 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
74 160
75 if (self != NULL) { 161 if (self != NULL) {
162 int i;
76 strcpy(self->name, name); 163 strcpy(self->name, name);
77 self->syms = RB_ROOT; 164 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 165 self->short_name = self->name;
166 for (i = 0; i < MAP__NR_TYPES; ++i)
167 self->symbols[i] = RB_ROOT;
79 self->find_symbol = dso__find_symbol; 168 self->find_symbol = dso__find_symbol;
80 self->slen_calculated = 0; 169 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 170 self->origin = DSO__ORIG_NOT_FOUND;
171 self->loaded = 0;
172 self->has_build_id = 0;
82 } 173 }
83 174
84 return self; 175 return self;
85} 176}
86 177
87static void dso__delete_symbols(struct dso *self) 178static void symbols__delete(struct rb_root *self)
88{ 179{
89 struct symbol *pos; 180 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 181 struct rb_node *next = rb_first(self);
91 182
92 while (next) { 183 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 184 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 185 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 186 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 187 symbol__delete(pos);
97 } 188 }
98} 189}
99 190
100void dso__delete(struct dso *self) 191void dso__delete(struct dso *self)
101{ 192{
102 dso__delete_symbols(self); 193 int i;
194 for (i = 0; i < MAP__NR_TYPES; ++i)
195 symbols__delete(&self->symbols[i]);
196 if (self->long_name != self->name)
197 free(self->long_name);
103 free(self); 198 free(self);
104} 199}
105 200
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 201void dso__set_build_id(struct dso *self, void *build_id)
107{ 202{
108 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;
109 struct rb_node *parent = NULL; 210 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 211 const u64 ip = sym->start;
111 struct symbol *s; 212 struct symbol *s;
@@ -119,17 +220,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 220 p = &(*p)->rb_right;
120 } 221 }
121 rb_link_node(&sym->rb_node, parent, p); 222 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 223 rb_insert_color(&sym->rb_node, self);
123} 224}
124 225
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 226static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 227{
127 struct rb_node *n; 228 struct rb_node *n;
128 229
129 if (self == NULL) 230 if (self == NULL)
130 return NULL; 231 return NULL;
131 232
132 n = self->syms.rb_node; 233 n = self->rb_node;
133 234
134 while (n) { 235 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 236 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +246,42 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 246 return NULL;
146} 247}
147 248
148size_t dso__fprintf(struct dso *self, FILE *fp) 249struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr)
149{ 250{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 251 return symbols__find(&self->symbols[type], addr);
252}
253
254int build_id__sprintf(u8 *self, int len, char *bf)
255{
256 char *bid = bf;
257 u8 *raw = self;
258 int i;
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}
151 276
277size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
278{
152 struct rb_node *nd; 279 struct rb_node *nd;
153 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)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 285 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 286 ret += symbol__fprintf(pos, fp);
156 } 287 }
@@ -158,13 +289,17 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 289 return ret;
159} 290}
160 291
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 292/*
293 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
294 * so that we can in the next step set the symbol ->end address and then
295 * call kernel_maps__split_kallsyms.
296 */
297static int dso__load_all_kallsyms(struct dso *self, struct map *map)
162{ 298{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 299 char *line = NULL;
165 size_t n; 300 size_t n;
301 struct rb_root *root = &self->symbols[map->type];
166 FILE *file = fopen("/proc/kallsyms", "r"); 302 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 303
169 if (file == NULL) 304 if (file == NULL)
170 goto out_failure; 305 goto out_failure;
@@ -174,6 +309,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 309 struct symbol *sym;
175 int line_len, len; 310 int line_len, len;
176 char symbol_type; 311 char symbol_type;
312 char *symbol_name;
177 313
178 line_len = getline(&line, &n, file); 314 line_len = getline(&line, &n, file);
179 if (line_len < 0) 315 if (line_len < 0)
@@ -196,44 +332,26 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
196 */ 332 */
197 if (symbol_type != 'T' && symbol_type != 'W') 333 if (symbol_type != 'T' && symbol_type != 'W')
198 continue; 334 continue;
335
336 symbol_name = line + len + 2;
199 /* 337 /*
200 * Well fix up the end later, when we have all sorted. 338 * Will fix up the end later, when we have all symbols sorted.
201 */ 339 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 340 sym = symbol__new(start, 0, symbol_name);
203 self->sym_priv_size, 0, v);
204 341
205 if (sym == NULL) 342 if (sym == NULL)
206 goto out_delete_line; 343 goto out_delete_line;
207 344 /*
208 if (filter && filter(self, sym)) 345 * We will pass the symbols to the filter later, in
209 symbol__delete(sym, self->sym_priv_size); 346 * map__split_kallsyms, when we have split the maps per module
210 else { 347 */
211 dso__insert_symbol(self, sym); 348 symbols__insert(root, sym);
212 count++;
213 }
214 }
215
216 /*
217 * Now that we have all sorted out, just set the ->end of all
218 * symbols
219 */
220 prevnd = rb_first(&self->syms);
221
222 if (prevnd == NULL)
223 goto out_delete_line;
224
225 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
226 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
227 *curr = rb_entry(nd, struct symbol, rb_node);
228
229 prev->end = curr->start - 1;
230 prevnd = nd;
231 } 349 }
232 350
233 free(line); 351 free(line);
234 fclose(file); 352 fclose(file);
235 353
236 return count; 354 return 0;
237 355
238out_delete_line: 356out_delete_line:
239 free(line); 357 free(line);
@@ -241,14 +359,114 @@ out_failure:
241 return -1; 359 return -1;
242} 360}
243 361
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 362/*
363 * Split the symbols into maps, making sure there are no overlaps, i.e. the
364 * kernel range is broken in several maps, named [kernel].N, as we don't have
365 * the original ELF section names vmlinux have.
366 */
367static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread,
368 symbol_filter_t filter)
369{
370 struct map *curr_map = map;
371 struct symbol *pos;
372 int count = 0;
373 struct rb_root *root = &self->symbols[map->type];
374 struct rb_node *next = rb_first(root);
375 int kernel_range = 0;
376
377 while (next) {
378 char *module;
379
380 pos = rb_entry(next, struct symbol, rb_node);
381 next = rb_next(&pos->rb_node);
382
383 module = strchr(pos->name, '\t');
384 if (module) {
385 if (!thread->use_modules)
386 goto discard_symbol;
387
388 *module++ = '\0';
389
390 if (strcmp(self->name, module)) {
391 curr_map = thread__find_map_by_name(thread, module);
392 if (curr_map == NULL) {
393 pr_debug("/proc/{kallsyms,modules} "
394 "inconsistency!\n");
395 return -1;
396 }
397 }
398 /*
399 * So that we look just like we get from .ko files,
400 * i.e. not prelinked, relative to map->start.
401 */
402 pos->start = curr_map->map_ip(curr_map, pos->start);
403 pos->end = curr_map->map_ip(curr_map, pos->end);
404 } else if (curr_map != map) {
405 char dso_name[PATH_MAX];
406 struct dso *dso;
407
408 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
409 kernel_range++);
410
411 dso = dso__new(dso_name);
412 if (dso == NULL)
413 return -1;
414
415 curr_map = map__new2(pos->start, dso, map->type);
416 if (map == NULL) {
417 dso__delete(dso);
418 return -1;
419 }
420
421 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
422 __thread__insert_map(thread, curr_map);
423 ++kernel_range;
424 }
425
426 if (filter && filter(curr_map, pos)) {
427discard_symbol: rb_erase(&pos->rb_node, root);
428 symbol__delete(pos);
429 } else {
430 if (curr_map != map) {
431 rb_erase(&pos->rb_node, root);
432 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
433 }
434 count++;
435 }
436 }
437
438 return count;
439}
440
441
442static int dso__load_kallsyms(struct dso *self, struct map *map,
443 struct thread *thread, symbol_filter_t filter)
444{
445 if (dso__load_all_kallsyms(self, map) < 0)
446 return -1;
447
448 symbols__fixup_end(&self->symbols[map->type]);
449 self->origin = DSO__ORIG_KERNEL;
450
451 return dso__split_kallsyms(self, map, thread, filter);
452}
453
454size_t kernel_maps__fprintf(FILE *fp)
455{
456 size_t printed = fprintf(fp, "Kernel maps:\n");
457 printed += thread__fprintf_maps(kthread, fp);
458 return printed + fprintf(fp, "END kernel maps\n");
459}
460
461static int dso__load_perf_map(struct dso *self, struct map *map,
462 symbol_filter_t filter)
245{ 463{
246 char *line = NULL; 464 char *line = NULL;
247 size_t n; 465 size_t n;
248 FILE *file; 466 FILE *file;
249 int nr_syms = 0; 467 int nr_syms = 0;
250 468
251 file = fopen(self->name, "r"); 469 file = fopen(self->long_name, "r");
252 if (file == NULL) 470 if (file == NULL)
253 goto out_failure; 471 goto out_failure;
254 472
@@ -278,16 +496,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 496 if (len + 2 >= line_len)
279 continue; 497 continue;
280 498
281 sym = symbol__new(start, size, line + len, 499 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 500
284 if (sym == NULL) 501 if (sym == NULL)
285 goto out_delete_line; 502 goto out_delete_line;
286 503
287 if (filter && filter(self, sym)) 504 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 505 symbol__delete(sym);
289 else { 506 else {
290 dso__insert_symbol(self, sym); 507 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 508 nr_syms++;
292 } 509 }
293 } 510 }
@@ -393,7 +610,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
393 * And always look at the original dso, not at debuginfo packages, that 610 * And always look at the original dso, not at debuginfo packages, that
394 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 611 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 612 */
396static 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)
397{ 615{
398 uint32_t nr_rel_entries, idx; 616 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 617 GElf_Sym sym;
@@ -409,7 +627,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 627 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 628 int nr = 0, symidx, fd, err = 0;
411 629
412 fd = open(self->name, O_RDONLY); 630 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 631 if (fd < 0)
414 goto out; 632 goto out;
415 633
@@ -477,12 +695,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 695 "%s@plt", elf_sym__name(&sym, symstrs));
478 696
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 697 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 698 sympltname);
481 if (!f) 699 if (!f)
482 goto out_elf_end; 700 goto out_elf_end;
483 701
484 dso__insert_symbol(self, f); 702 if (filter && filter(map, f))
485 ++nr; 703 symbol__delete(f);
704 else {
705 symbols__insert(&self->symbols[map->type], f);
706 ++nr;
707 }
486 } 708 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 709 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 710 GElf_Rel pos_mem, *pos;
@@ -495,12 +717,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 717 "%s@plt", elf_sym__name(&sym, symstrs));
496 718
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 719 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 720 sympltname);
499 if (!f) 721 if (!f)
500 goto out_elf_end; 722 goto out_elf_end;
501 723
502 dso__insert_symbol(self, f); 724 if (filter && filter(map, f))
503 ++nr; 725 symbol__delete(f);
726 else {
727 symbols__insert(&self->symbols[map->type], f);
728 ++nr;
729 }
504 } 730 }
505 } 731 }
506 732
@@ -513,14 +739,18 @@ out_close:
513 if (err == 0) 739 if (err == 0)
514 return nr; 740 return nr;
515out: 741out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 742 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 743 __func__, self->long_name);
518 return 0; 744 return 0;
519} 745}
520 746
521static int dso__load_sym(struct dso *self, int fd, const char *name, 747static int dso__load_sym(struct dso *self, struct map *map,
522 symbol_filter_t filter, int v, struct module *mod) 748 struct thread *thread, const char *name, int fd,
749 symbol_filter_t filter, int kernel, int kmodule)
523{ 750{
751 struct map *curr_map = map;
752 struct dso *curr_dso = self;
753 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 754 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 755 uint32_t nr_syms;
526 int err = -1; 756 int err = -1;
@@ -531,19 +761,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 761 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 762 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 763 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 764 int nr = 0;
535 765
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 766 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 767 if (elf == NULL) {
538 if (v) 768 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
539 fprintf(stderr, "%s: cannot read %s ELF file.\n",
540 __func__, name);
541 goto out_close; 769 goto out_close;
542 } 770 }
543 771
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 772 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 773 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 774 goto out_elf_end;
548 } 775 }
549 776
@@ -587,9 +814,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 814 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 815 struct symbol *f;
589 const char *elf_name; 816 const char *elf_name;
590 char *demangled; 817 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 818 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 819 const char *section_name;
595 820
@@ -605,52 +830,85 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 830 if (is_label && !elf_sec__is_text(&shdr, secstrs))
606 continue; 831 continue;
607 832
833 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 834 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 835
611 if (self->adjust_symbols) { 836 if (kernel || kmodule) {
612 if (v >= 2) 837 char dso_name[PATH_MAX];
613 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615 838
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 839 if (strcmp(section_name,
617 } 840 curr_dso->short_name + dso_name_len) == 0)
841 goto new_symbol;
618 842
619 if (mod) { 843 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 844 curr_map = map;
621 if (section) 845 curr_dso = self;
622 sym.st_value += section->vma; 846 goto new_symbol;
623 else {
624 fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
625 mod->name, section_name);
626 goto out_elf_end;
627 } 847 }
848
849 snprintf(dso_name, sizeof(dso_name),
850 "%s%s", self->short_name, section_name);
851
852 curr_map = thread__find_map_by_name(thread, dso_name);
853 if (curr_map == NULL) {
854 u64 start = sym.st_value;
855
856 if (kmodule)
857 start += map->start + shdr.sh_offset;
858
859 curr_dso = dso__new(dso_name);
860 if (curr_dso == NULL)
861 goto out_elf_end;
862 curr_map = map__new2(start, curr_dso,
863 MAP__FUNCTION);
864 if (curr_map == NULL) {
865 dso__delete(curr_dso);
866 goto out_elf_end;
867 }
868 curr_map->map_ip = identity__map_ip;
869 curr_map->unmap_ip = identity__map_ip;
870 curr_dso->origin = DSO__ORIG_KERNEL;
871 __thread__insert_map(kthread, curr_map);
872 dsos__add(&dsos__kernel, curr_dso);
873 } else
874 curr_dso = curr_map->dso;
875
876 goto new_symbol;
877 }
878
879 if (curr_dso->adjust_symbols) {
880 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
881 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
882 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
883 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 884 }
629 /* 885 /*
630 * We need to figure out if the object was created from C++ sources 886 * We need to figure out if the object was created from C++ sources
631 * DWARF DW_compile_unit has this, but we don't always have access 887 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 888 * to it...
633 */ 889 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 890 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 891 if (demangled != NULL)
637 elf_name = demangled; 892 elf_name = demangled;
638 893new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 894 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 895 free(demangled);
642 if (!f) 896 if (!f)
643 goto out_elf_end; 897 goto out_elf_end;
644 898
645 if (filter && filter(self, f)) 899 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 900 symbol__delete(f);
647 else { 901 else {
648 f->module = mod; 902 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 903 nr++;
651 } 904 }
652 } 905 }
653 906
907 /*
908 * For misannotated, zeroed, ASM function sizes.
909 */
910 if (nr > 0)
911 symbols__fixup_end(&self->symbols[map->type]);
654 err = nr; 912 err = nr;
655out_elf_end: 913out_elf_end:
656 elf_end(elf); 914 elf_end(elf);
@@ -658,63 +916,154 @@ out_close:
658 return err; 916 return err;
659} 917}
660 918
661#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}
662 923
663static char *dso__read_build_id(struct dso *self, int v) 924static bool __dsos__read_build_ids(struct list_head *head)
664{ 925{
665 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 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
942 ubuildids = __dsos__read_build_ids(&dsos__user);
943 return kbuildids || ubuildids;
944}
945
946/*
947 * Align offset to 4 bytes as needed for note name and descriptor data.
948 */
949#define NOTE_ALIGN(n) (((n) + 3) & -4U)
950
951int filename__read_build_id(const char *filename, void *bf, size_t size)
952{
953 int fd, err = -1;
666 GElf_Ehdr ehdr; 954 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 955 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 956 Elf_Data *data;
669 Elf_Scn *sec; 957 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 958 Elf_Kind ek;
671 unsigned char *raw; 959 void *ptr;
672 Elf *elf; 960 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 961
962 if (size < BUILD_ID_SIZE)
963 goto out;
964
965 fd = open(filename, O_RDONLY);
675 if (fd < 0) 966 if (fd < 0)
676 goto out; 967 goto out;
677 968
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 969 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 970 if (elf == NULL) {
680 if (v) 971 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
681 fprintf(stderr, "%s: cannot read %s ELF file.\n",
682 __func__, self->name);
683 goto out_close; 972 goto out_close;
684 } 973 }
685 974
975 ek = elf_kind(elf);
976 if (ek != ELF_K_ELF)
977 goto out_elf_end;
978
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 979 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 980 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 981 goto out_elf_end;
690 } 982 }
691 983
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 984 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 985 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 986 if (sec == NULL) {
987 sec = elf_section_by_name(elf, &ehdr, &shdr,
988 ".notes", NULL);
989 if (sec == NULL)
990 goto out_elf_end;
991 }
695 992
696 build_id_data = elf_getdata(sec, NULL); 993 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 994 if (data == NULL)
698 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end; 995 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 996
705 for (i = 0; i < 20; ++i) { 997 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 998 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 999 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1000 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1001 descsz = NOTE_ALIGN(nhdr->n_descsz);
1002 const char *name;
1003
1004 ptr += sizeof(*nhdr);
1005 name = ptr;
1006 ptr += namesz;
1007 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1008 nhdr->n_namesz == sizeof("GNU")) {
1009 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1010 memcpy(bf, ptr, BUILD_ID_SIZE);
1011 err = BUILD_ID_SIZE;
1012 break;
1013 }
1014 }
1015 ptr += descsz;
709 } 1016 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1017out_elf_end:
713 elf_end(elf); 1018 elf_end(elf);
714out_close: 1019out_close:
715 close(fd); 1020 close(fd);
716out: 1021out:
717 return build_id; 1022 return err;
1023}
1024
1025int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1026{
1027 int fd, err = -1;
1028
1029 if (size < BUILD_ID_SIZE)
1030 goto out;
1031
1032 fd = open(filename, O_RDONLY);
1033 if (fd < 0)
1034 goto out;
1035
1036 while (1) {
1037 char bf[BUFSIZ];
1038 GElf_Nhdr nhdr;
1039 int namesz, descsz;
1040
1041 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1042 break;
1043
1044 namesz = NOTE_ALIGN(nhdr.n_namesz);
1045 descsz = NOTE_ALIGN(nhdr.n_descsz);
1046 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1047 nhdr.n_namesz == sizeof("GNU")) {
1048 if (read(fd, bf, namesz) != namesz)
1049 break;
1050 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1051 if (read(fd, build_id,
1052 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1053 err = 0;
1054 break;
1055 }
1056 } else if (read(fd, bf, descsz) != descsz)
1057 break;
1058 } else {
1059 int n = namesz + descsz;
1060 if (read(fd, bf, n) != n)
1061 break;
1062 }
1063 }
1064 close(fd);
1065out:
1066 return err;
718} 1067}
719 1068
720char dso__symtab_origin(const struct dso *self) 1069char dso__symtab_origin(const struct dso *self)
@@ -726,6 +1075,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 1075 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1076 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1077 [DSO__ORIG_DSO] = 'd',
1078 [DSO__ORIG_KMODULE] = 'K',
729 }; 1079 };
730 1080
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1081 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,20 +1083,27 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1083 return origin[self->origin];
734} 1084}
735 1085
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1086int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
737{ 1087{
738 int size = PATH_MAX; 1088 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1089 char *name;
1090 u8 build_id[BUILD_ID_SIZE];
740 int ret = -1; 1091 int ret = -1;
741 int fd; 1092 int fd;
742 1093
1094 dso__set_loaded(self, map->type);
1095
1096 if (self->kernel)
1097 return dso__load_kernel_sym(self, map, kthread, filter);
1098
1099 name = malloc(size);
743 if (!name) 1100 if (!name)
744 return -1; 1101 return -1;
745 1102
746 self->adjust_symbols = 0; 1103 self->adjust_symbols = 0;
747 1104
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1105 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1106 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1107 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1108 DSO__ORIG_NOT_FOUND;
752 return ret; 1109 return ret;
@@ -759,34 +1116,50 @@ more:
759 self->origin++; 1116 self->origin++;
760 switch (self->origin) { 1117 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1118 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1119 snprintf(name, size, "/usr/lib/debug%s.debug",
1120 self->long_name);
763 break; 1121 break;
764 case DSO__ORIG_UBUNTU: 1122 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1123 snprintf(name, size, "/usr/lib/debug%s",
1124 self->long_name);
766 break; 1125 break;
767 case DSO__ORIG_BUILDID: 1126 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1127 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1128 sizeof(build_id))) {
1129 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1130
1131 build_id__sprintf(build_id, sizeof(build_id),
1132 build_id_hex);
770 snprintf(name, size, 1133 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1134 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1135 build_id_hex, build_id_hex + 2);
773 free(build_id); 1136 if (self->has_build_id)
1137 goto compare_build_id;
774 break; 1138 break;
775 } 1139 }
776 self->origin++; 1140 self->origin++;
777 /* Fall thru */ 1141 /* Fall thru */
778 case DSO__ORIG_DSO: 1142 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1143 snprintf(name, size, "%s", self->long_name);
780 break; 1144 break;
781 1145
782 default: 1146 default:
783 goto out; 1147 goto out;
784 } 1148 }
785 1149
1150 if (self->has_build_id) {
1151 if (filename__read_build_id(name, build_id,
1152 sizeof(build_id)) < 0)
1153 goto more;
1154compare_build_id:
1155 if (!dso__build_id_equal(self, build_id))
1156 goto more;
1157 }
1158
786 fd = open(name, O_RDONLY); 1159 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1160 } while (fd < 0);
788 1161
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1162 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
790 close(fd); 1163 close(fd);
791 1164
792 /* 1165 /*
@@ -796,7 +1169,7 @@ more:
796 goto more; 1169 goto more;
797 1170
798 if (ret > 0) { 1171 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1172 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1173 if (nr_plt > 0)
801 ret += nr_plt; 1174 ret += nr_plt;
802 } 1175 }
@@ -807,151 +1180,279 @@ out:
807 return ret; 1180 return ret;
808} 1181}
809 1182
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1183static struct map *thread__find_map_by_name(struct thread *self, char *name)
811 symbol_filter_t filter, int v)
812{ 1184{
813 struct module *mod = mod_dso__find_module(mods, name); 1185 struct rb_node *nd;
814 int err = 0, fd;
815 1186
816 if (mod == NULL || !mod->active) 1187 for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
817 return err; 1188 struct map *map = rb_entry(nd, struct map, rb_node);
818 1189
819 fd = open(mod->path, O_RDONLY); 1190 if (map->dso && strcmp(map->dso->name, name) == 0)
1191 return map;
1192 }
820 1193
821 if (fd < 0) 1194 return NULL;
822 return err; 1195}
823 1196
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1197static int dsos__set_modules_path_dir(char *dirname)
825 close(fd); 1198{
1199 struct dirent *dent;
1200 DIR *dir = opendir(dirname);
826 1201
827 return err; 1202 if (!dir) {
1203 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1204 return -1;
1205 }
1206
1207 while ((dent = readdir(dir)) != NULL) {
1208 char path[PATH_MAX];
1209
1210 if (dent->d_type == DT_DIR) {
1211 if (!strcmp(dent->d_name, ".") ||
1212 !strcmp(dent->d_name, ".."))
1213 continue;
1214
1215 snprintf(path, sizeof(path), "%s/%s",
1216 dirname, dent->d_name);
1217 if (dsos__set_modules_path_dir(path) < 0)
1218 goto failure;
1219 } else {
1220 char *dot = strrchr(dent->d_name, '.'),
1221 dso_name[PATH_MAX];
1222 struct map *map;
1223 char *long_name;
1224
1225 if (dot == NULL || strcmp(dot, ".ko"))
1226 continue;
1227 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1228 (int)(dot - dent->d_name), dent->d_name);
1229
1230 strxfrchar(dso_name, '-', '_');
1231 map = thread__find_map_by_name(kthread, dso_name);
1232 if (map == NULL)
1233 continue;
1234
1235 snprintf(path, sizeof(path), "%s/%s",
1236 dirname, dent->d_name);
1237
1238 long_name = strdup(path);
1239 if (long_name == NULL)
1240 goto failure;
1241 dso__set_long_name(map->dso, long_name);
1242 }
1243 }
1244
1245 return 0;
1246failure:
1247 closedir(dir);
1248 return -1;
828} 1249}
829 1250
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1251static int dsos__set_modules_path(void)
831{ 1252{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1253 struct utsname uts;
833 struct module *pos; 1254 char modules_path[PATH_MAX];
834 struct rb_node *next;
835 int err, count = 0;
836 1255
837 err = mod_dso__load_modules(mods); 1256 if (uname(&uts) < 0)
838 1257 return -1;
839 if (err <= 0)
840 return err;
841 1258
842 /* 1259 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
843 * Iterate over modules, and load active symbols. 1260 uts.release);
844 */
845 next = rb_first(&mods->mods);
846 while (next) {
847 pos = rb_entry(next, struct module, rb_node);
848 err = dso__load_module(self, mods, pos->name, filter, v);
849 1261
850 if (err < 0) 1262 return dsos__set_modules_path_dir(modules_path);
851 break; 1263}
852 1264
853 next = rb_next(&pos->rb_node); 1265/*
854 count += err; 1266 * Constructor variant for modules (where we know from /proc/modules where
855 } 1267 * they are loaded) and for vmlinux, where only after we load all the
1268 * symbols we'll know where it starts and ends.
1269 */
1270static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1271{
1272 struct map *self = malloc(sizeof(*self));
856 1273
857 if (err < 0) { 1274 if (self != NULL) {
858 mod_dso__delete_modules(mods); 1275 /*
859 mod_dso__delete_self(mods); 1276 * ->end will be filled after we load all the symbols
860 return err; 1277 */
1278 map__init(self, type, start, 0, 0, dso);
861 } 1279 }
862 1280
863 return count; 1281 return self;
864} 1282}
865 1283
866static inline void dso__fill_symbol_holes(struct dso *self) 1284static int thread__create_module_maps(struct thread *self)
867{ 1285{
868 struct symbol *prev = NULL; 1286 char *line = NULL;
869 struct rb_node *nd; 1287 size_t n;
1288 FILE *file = fopen("/proc/modules", "r");
1289 struct map *map;
870 1290
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1291 if (file == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1292 return -1;
873 1293
874 if (prev) { 1294 while (!feof(file)) {
875 u64 hole = 0; 1295 char name[PATH_MAX];
876 int alias = pos->start == prev->start; 1296 u64 start;
1297 struct dso *dso;
1298 char *sep;
1299 int line_len;
877 1300
878 if (!alias) 1301 line_len = getline(&line, &n, file);
879 hole = prev->start - pos->end - 1; 1302 if (line_len < 0)
1303 break;
880 1304
881 if (hole || alias) { 1305 if (!line)
882 if (alias) 1306 goto out_failure;
883 pos->end = prev->end; 1307
884 else if (hole) 1308 line[--line_len] = '\0'; /* \n */
885 pos->end = prev->start - 1; 1309
886 } 1310 sep = strrchr(line, 'x');
1311 if (sep == NULL)
1312 continue;
1313
1314 hex2u64(sep + 1, &start);
1315
1316 sep = strchr(line, ' ');
1317 if (sep == NULL)
1318 continue;
1319
1320 *sep = '\0';
1321
1322 snprintf(name, sizeof(name), "[%s]", line);
1323 dso = dso__new(name);
1324
1325 if (dso == NULL)
1326 goto out_delete_line;
1327
1328 map = map__new2(start, dso, MAP__FUNCTION);
1329 if (map == NULL) {
1330 dso__delete(dso);
1331 goto out_delete_line;
887 } 1332 }
888 prev = pos; 1333
1334 snprintf(name, sizeof(name),
1335 "/sys/module/%s/notes/.note.gnu.build-id", line);
1336 if (sysfs__read_build_id(name, dso->build_id,
1337 sizeof(dso->build_id)) == 0)
1338 dso->has_build_id = true;
1339
1340 dso->origin = DSO__ORIG_KMODULE;
1341 __thread__insert_map(self, map);
1342 dsos__add(&dsos__kernel, dso);
889 } 1343 }
1344
1345 free(line);
1346 fclose(file);
1347
1348 return dsos__set_modules_path();
1349
1350out_delete_line:
1351 free(line);
1352out_failure:
1353 return -1;
890} 1354}
891 1355
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1356static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread,
893 symbol_filter_t filter, int v) 1357 const char *vmlinux, symbol_filter_t filter)
894{ 1358{
895 int err, fd = open(vmlinux, O_RDONLY); 1359 int err = -1, fd;
896 1360
897 if (fd < 0) 1361 if (self->has_build_id) {
898 return -1; 1362 u8 build_id[BUILD_ID_SIZE];
899 1363
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1364 if (filename__read_build_id(vmlinux, build_id,
1365 sizeof(build_id)) < 0) {
1366 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1367 return -1;
1368 }
1369 if (!dso__build_id_equal(self, build_id)) {
1370 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1371 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1372
1373 build_id__sprintf(self->build_id,
1374 sizeof(self->build_id),
1375 expected_build_id);
1376 build_id__sprintf(build_id, sizeof(build_id),
1377 vmlinux_build_id);
1378 pr_debug("build_id in %s is %s while expected is %s, "
1379 "ignoring it\n", vmlinux, vmlinux_build_id,
1380 expected_build_id);
1381 return -1;
1382 }
1383 }
901 1384
902 if (err > 0) 1385 fd = open(vmlinux, O_RDONLY);
903 dso__fill_symbol_holes(self); 1386 if (fd < 0)
1387 return -1;
904 1388
1389 dso__set_loaded(self, map->type);
1390 err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0);
905 close(fd); 1391 close(fd);
906 1392
907 return err; 1393 return err;
908} 1394}
909 1395
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1396static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1397 struct thread *thread, symbol_filter_t filter)
912{ 1398{
913 int err = -1; 1399 int err;
914 1400 bool is_kallsyms;
915 if (vmlinux) { 1401
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1402 if (vmlinux_path != NULL) {
917 if (err > 0 && use_modules) { 1403 int i;
918 int syms = dso__load_modules(self, filter, v); 1404 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
919 1405 vmlinux_path__nr_entries);
920 if (syms < 0) { 1406 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
921 fprintf(stderr, "dso__load_modules failed!\n"); 1407 err = dso__load_vmlinux(self, map, thread,
922 return syms; 1408 vmlinux_path[i], filter);
1409 if (err > 0) {
1410 pr_debug("Using %s for symbols\n",
1411 vmlinux_path[i]);
1412 dso__set_long_name(self,
1413 strdup(vmlinux_path[i]));
1414 goto out_fixup;
923 } 1415 }
924 err += syms;
925 } 1416 }
926 } 1417 }
927 1418
928 if (err <= 0) 1419 is_kallsyms = self->long_name[0] == '[';
929 err = dso__load_kallsyms(self, filter, v); 1420 if (is_kallsyms)
1421 goto do_kallsyms;
930 1422
931 if (err > 0) 1423 err = dso__load_vmlinux(self, map, thread, self->long_name, filter);
932 self->origin = DSO__ORIG_KERNEL; 1424 if (err <= 0) {
1425 pr_info("The file %s cannot be used, "
1426 "trying to use /proc/kallsyms...", self->long_name);
1427do_kallsyms:
1428 err = dso__load_kallsyms(self, map, thread, filter);
1429 if (err > 0 && !is_kallsyms)
1430 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1431 }
1432
1433 if (err > 0) {
1434out_fixup:
1435 map__fixup_start(map);
1436 map__fixup_end(map);
1437 }
933 1438
934 return err; 1439 return err;
935} 1440}
936 1441
937LIST_HEAD(dsos); 1442LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1443LIST_HEAD(dsos__kernel);
939struct dso *vdso; 1444struct dso *vdso;
940struct dso *hypervisor_dso;
941
942const char *vmlinux_name = "vmlinux";
943int modules;
944 1445
945static void dsos__add(struct dso *dso) 1446static void dsos__add(struct list_head *head, struct dso *dso)
946{ 1447{
947 list_add_tail(&dso->node, &dsos); 1448 list_add_tail(&dso->node, head);
948} 1449}
949 1450
950static struct dso *dsos__find(const char *name) 1451static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1452{
952 struct dso *pos; 1453 struct dso *pos;
953 1454
954 list_for_each_entry(pos, &dsos, node) 1455 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1456 if (strcmp(pos->name, name) == 0)
956 return pos; 1457 return pos;
957 return NULL; 1458 return NULL;
@@ -959,79 +1460,170 @@ static struct dso *dsos__find(const char *name)
959 1460
960struct dso *dsos__findnew(const char *name) 1461struct dso *dsos__findnew(const char *name)
961{ 1462{
962 struct dso *dso = dsos__find(name); 1463 struct dso *dso = dsos__find(&dsos__user, name);
963 int nr;
964
965 if (dso)
966 return dso;
967
968 dso = dso__new(name, 0);
969 if (!dso)
970 goto out_delete_dso;
971 1464
972 nr = dso__load(dso, NULL, verbose); 1465 if (!dso) {
973 if (nr < 0) { 1466 dso = dso__new(name);
974 eprintf("Failed to open: %s\n", name); 1467 if (dso != NULL) {
975 goto out_delete_dso; 1468 dsos__add(&dsos__user, dso);
1469 dso__set_basename(dso);
1470 }
976 } 1471 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1472
982 return dso; 1473 return dso;
1474}
983 1475
984out_delete_dso: 1476static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1477{
986 return NULL; 1478 struct dso *pos;
1479
1480 list_for_each_entry(pos, head, node) {
1481 int i;
1482 for (i = 0; i < MAP__NR_TYPES; ++i)
1483 dso__fprintf(pos, i, fp);
1484 }
987} 1485}
988 1486
989void dsos__fprintf(FILE *fp) 1487void dsos__fprintf(FILE *fp)
990{ 1488{
1489 __dsos__fprintf(&dsos__kernel, fp);
1490 __dsos__fprintf(&dsos__user, fp);
1491}
1492
1493static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
1494{
991 struct dso *pos; 1495 struct dso *pos;
1496 size_t ret = 0;
992 1497
993 list_for_each_entry(pos, &dsos, node) 1498 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1499 ret += dso__fprintf_buildid(pos, fp);
1500 ret += fprintf(fp, " %s\n", pos->long_name);
1501 }
1502 return ret;
995} 1503}
996 1504
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1505size_t dsos__fprintf_buildid(FILE *fp)
998{ 1506{
999 return dso__find_symbol(dso, ip); 1507 return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1508 __dsos__fprintf_buildid(&dsos__user, fp));
1000} 1509}
1001 1510
1002int load_kernel(void) 1511static int thread__create_kernel_map(struct thread *self, const char *vmlinux)
1003{ 1512{
1004 int err; 1513 struct map *kmap;
1514 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1005 1515
1006 kernel_dso = dso__new("[kernel]", 0); 1516 if (kernel == NULL)
1007 if (!kernel_dso)
1008 return -1; 1517 return -1;
1009 1518
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1519 kmap = map__new2(0, kernel, MAP__FUNCTION);
1011 if (err <= 0) { 1520 if (kmap == NULL)
1012 dso__delete(kernel_dso); 1521 goto out_delete_kernel_dso;
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1522
1017 vdso = dso__new("[vdso]", 0); 1523 kmap->map_ip = kmap->unmap_ip = identity__map_ip;
1018 if (!vdso) 1524 kernel->short_name = "[kernel]";
1019 return -1; 1525 kernel->kernel = 1;
1020 1526
1021 vdso->find_symbol = vdso__find_symbol; 1527 vdso = dso__new("[vdso]");
1528 if (vdso == NULL)
1529 goto out_delete_kernel_map;
1530 dso__set_loaded(vdso, MAP__FUNCTION);
1022 1531
1023 dsos__add(vdso); 1532 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1533 sizeof(kernel->build_id)) == 0)
1534 kernel->has_build_id = true;
1024 1535
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1536 __thread__insert_map(self, kmap);
1026 if (!hypervisor_dso) 1537 dsos__add(&dsos__kernel, kernel);
1027 return -1; 1538 dsos__add(&dsos__user, vdso);
1028 dsos__add(hypervisor_dso);
1029 1539
1030 return err; 1540 return 0;
1541
1542out_delete_kernel_map:
1543 map__delete(kmap);
1544out_delete_kernel_dso:
1545 dso__delete(kernel);
1546 return -1;
1547}
1548
1549static void vmlinux_path__exit(void)
1550{
1551 while (--vmlinux_path__nr_entries >= 0) {
1552 free(vmlinux_path[vmlinux_path__nr_entries]);
1553 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1554 }
1555
1556 free(vmlinux_path);
1557 vmlinux_path = NULL;
1031} 1558}
1032 1559
1560static int vmlinux_path__init(void)
1561{
1562 struct utsname uts;
1563 char bf[PATH_MAX];
1564
1565 if (uname(&uts) < 0)
1566 return -1;
1567
1568 vmlinux_path = malloc(sizeof(char *) * 5);
1569 if (vmlinux_path == NULL)
1570 return -1;
1571
1572 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1573 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1574 goto out_fail;
1575 ++vmlinux_path__nr_entries;
1576 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1577 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1578 goto out_fail;
1579 ++vmlinux_path__nr_entries;
1580 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1581 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1582 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1583 goto out_fail;
1584 ++vmlinux_path__nr_entries;
1585 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1586 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1587 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1588 goto out_fail;
1589 ++vmlinux_path__nr_entries;
1590 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1591 uts.release);
1592 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1593 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1594 goto out_fail;
1595 ++vmlinux_path__nr_entries;
1596
1597 return 0;
1598
1599out_fail:
1600 vmlinux_path__exit();
1601 return -1;
1602}
1033 1603
1034void symbol__init(void) 1604int symbol__init(struct symbol_conf *conf)
1035{ 1605{
1606 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1607
1036 elf_version(EV_CURRENT); 1608 elf_version(EV_CURRENT);
1609 symbol__priv_size = pconf->priv_size;
1610 thread__init(kthread, 0);
1611
1612 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1613 return -1;
1614
1615 if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) {
1616 vmlinux_path__exit();
1617 return -1;
1618 }
1619
1620 kthread->use_modules = pconf->use_modules;
1621 if (pconf->use_modules && thread__create_module_maps(kthread) < 0)
1622 pr_debug("Failed to load list of modules in use, "
1623 "continuing...\n");
1624 /*
1625 * Now that we have all the maps created, just set the ->end of them:
1626 */
1627 thread__fixup_maps_end(kthread);
1628 return 0;
1037} 1629}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..17003efa0b39 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -1,11 +1,11 @@
1#ifndef _PERF_SYMBOL_ 1#ifndef __PERF_SYMBOL
2#define _PERF_SYMBOL_ 1 2#define __PERF_SYMBOL 1
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h>
5#include "types.h" 6#include "types.h"
6#include <linux/list.h> 7#include <linux/list.h>
7#include <linux/rbtree.h> 8#include <linux/rbtree.h>
8#include "module.h"
9#include "event.h" 9#include "event.h"
10 10
11#ifdef HAVE_CPLUS_DEMANGLE 11#ifdef HAVE_CPLUS_DEMANGLE
@@ -46,57 +46,75 @@ struct symbol {
46 struct rb_node rb_node; 46 struct rb_node rb_node;
47 u64 start; 47 u64 start;
48 u64 end; 48 u64 end;
49 u64 obj_start;
50 u64 hist_sum;
51 u64 *hist;
52 struct module *module;
53 void *priv;
54 char name[0]; 49 char name[0];
55}; 50};
56 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
57struct dso { 74struct dso {
58 struct list_head node; 75 struct list_head node;
59 struct rb_root syms; 76 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 77 struct symbol *(*find_symbol)(struct dso *self,
61 unsigned int sym_priv_size; 78 enum map_type type, u64 addr);
62 unsigned char adjust_symbols; 79 u8 adjust_symbols:1;
63 unsigned char slen_calculated; 80 u8 slen_calculated:1;
81 u8 has_build_id:1;
82 u8 kernel:1;
64 unsigned char origin; 83 unsigned char origin;
84 u8 loaded;
85 u8 build_id[BUILD_ID_SIZE];
86 u16 long_name_len;
87 const char *short_name;
88 char *long_name;
65 char name[0]; 89 char name[0];
66}; 90};
67 91
68extern const char *sym_hist_filter; 92struct dso *dso__new(const char *name);
69
70typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
71
72struct dso *dso__new(const char *name, unsigned int sym_priv_size);
73void dso__delete(struct dso *self); 93void dso__delete(struct dso *self);
74 94
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 95bool dso__loaded(const struct dso *self, enum map_type type);
76{
77 return ((void *)sym) - self->sym_priv_size;
78}
79
80struct symbol *dso__find_symbol(struct dso *self, u64 ip);
81 96
82int dso__load_kernel(struct dso *self, const char *vmlinux,
83 symbol_filter_t filter, int verbose, int modules);
84int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
85int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
86struct dso *dsos__findnew(const char *name); 97struct dso *dsos__findnew(const char *name);
98int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
87void dsos__fprintf(FILE *fp); 99void dsos__fprintf(FILE *fp);
100size_t dsos__fprintf_buildid(FILE *fp);
88 101
89size_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);
90char 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);
91 111
92int load_kernel(void); 112size_t kernel_maps__fprintf(FILE *fp);
93 113
94void symbol__init(void); 114int symbol__init(struct symbol_conf *conf);
95 115
96extern struct list_head dsos; 116struct thread;
97extern struct dso *kernel_dso; 117struct thread *kthread;
118extern struct list_head dsos__user, dsos__kernel;
98extern struct dso *vdso; 119extern struct dso *vdso;
99extern struct dso *hypervisor_dso; 120#endif /* __PERF_SYMBOL */
100extern const char *vmlinux_name;
101extern int modules;
102#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 45efb5db0d19..603f5610861b 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,16 +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 INIT_LIST_HEAD(&self->maps);
19 } 32 }
20 33
21 return self; 34 return self;
@@ -29,21 +42,84 @@ int thread__set_comm(struct thread *self, const char *comm)
29 return self->comm ? 0 : -ENOMEM; 42 return self->comm ? 0 : -ENOMEM;
30} 43}
31 44
32static size_t thread__fprintf(struct thread *self, FILE *fp) 45int thread__comm_len(struct thread *self)
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]);
64 struct rb_node *nd;
65
66 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
67 struct map *pos = rb_entry(nd, struct map, rb_node);
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 }
74 }
75
76 return printed;
77}
78
79size_t thread__fprintf_maps(struct thread *self, FILE *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}
86
87static size_t __thread__fprintf_removed_maps(struct thread *self,
88 enum map_type type, FILE *fp)
33{ 89{
34 struct map *pos; 90 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 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}
36 103
37 list_for_each_entry(pos, &self->maps, node) 104static size_t thread__fprintf_removed_maps(struct thread *self, FILE *fp)
38 ret += map__fprintf(pos, 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;
110}
39 111
40 return ret; 112static size_t thread__fprintf(struct thread *self, FILE *fp)
113{
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);
41} 118}
42 119
43struct thread * 120struct thread *threads__findnew(pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 121{
46 struct rb_node **p = &threads->rb_node; 122 struct rb_node **p = &threads.rb_node;
47 struct rb_node *parent = NULL; 123 struct rb_node *parent = NULL;
48 struct thread *th; 124 struct thread *th;
49 125
@@ -52,15 +128,15 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
52 * so most of the time we dont have to look up 128 * so most of the time we dont have to look up
53 * the full rbtree: 129 * the full rbtree:
54 */ 130 */
55 if (*last_match && (*last_match)->pid == pid) 131 if (last_match && last_match->pid == pid)
56 return *last_match; 132 return last_match;
57 133
58 while (*p != NULL) { 134 while (*p != NULL) {
59 parent = *p; 135 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 136 th = rb_entry(parent, struct thread, rb_node);
61 137
62 if (th->pid == pid) { 138 if (th->pid == pid) {
63 *last_match = th; 139 last_match = th;
64 return th; 140 return th;
65 } 141 }
66 142
@@ -73,17 +149,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 149 th = thread__new(pid);
74 if (th != NULL) { 150 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 151 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 152 rb_insert_color(&th->rb_node, &threads);
77 *last_match = th; 153 last_match = th;
78 } 154 }
79 155
80 return th; 156 return th;
81} 157}
82 158
83struct thread * 159struct thread *register_idle_thread(void)
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{ 160{
86 struct thread *thread = threads__findnew(0, threads, last_match); 161 struct thread *thread = threads__findnew(0);
87 162
88 if (!thread || thread__set_comm(thread, "swapper")) { 163 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n"); 164 fprintf(stderr, "problem inserting idle task.\n");
@@ -93,79 +168,116 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
93 return thread; 168 return thread;
94} 169}
95 170
96void thread__insert_map(struct thread *self, struct map *map) 171static void thread__remove_overlappings(struct thread *self, struct map *map)
97{ 172{
98 struct map *pos, *tmp; 173 struct rb_root *root = &self->maps[map->type];
174 struct rb_node *next = rb_first(root);
99 175
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 176 while (next) {
101 if (map__overlap(pos, map)) { 177 struct map *pos = rb_entry(next, struct map, rb_node);
102 if (verbose >= 2) { 178 next = rb_next(&pos->rb_node);
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 179
108 if (map->start <= pos->start && map->end > pos->start) 180 if (!map__overlap(pos, map))
109 pos->start = map->end; 181 continue;
110 182
111 if (map->end >= pos->end && map->start < pos->end) 183 if (verbose >= 2) {
112 pos->end = map->start; 184 fputs("overlapping maps:\n", stderr);
185 map__fprintf(map, stderr);
186 map__fprintf(pos, stderr);
187 }
113 188
114 if (verbose >= 2) { 189 rb_erase(&pos->rb_node, root);
115 printf("after collision:\n"); 190 /*
116 map__fprintf(pos, stdout); 191 * We may have references to this map, for instance in some
117 } 192 * hist_entry instances, so just move them to a separate
193 * list.
194 */
195 list_add_tail(&pos->node, &self->removed_maps[map->type]);
196 }
197}
118 198
119 if (pos->start >= pos->end) { 199void maps__insert(struct rb_root *maps, struct map *map)
120 list_del_init(&pos->node); 200{
121 free(pos); 201 struct rb_node **p = &maps->rb_node;
122 } 202 struct rb_node *parent = NULL;
123 } 203 const u64 ip = map->start;
204 struct map *m;
205
206 while (*p != NULL) {
207 parent = *p;
208 m = rb_entry(parent, struct map, rb_node);
209 if (ip < m->start)
210 p = &(*p)->rb_left;
211 else
212 p = &(*p)->rb_right;
124 } 213 }
125 214
126 list_add_tail(&map->node, &self->maps); 215 rb_link_node(&map->rb_node, parent, p);
216 rb_insert_color(&map->rb_node, maps);
127} 217}
128 218
129int thread__fork(struct thread *self, struct thread *parent) 219struct map *maps__find(struct rb_root *maps, u64 ip)
130{ 220{
131 struct map *map; 221 struct rb_node **p = &maps->rb_node;
222 struct rb_node *parent = NULL;
223 struct map *m;
132 224
133 if (self->comm) 225 while (*p != NULL) {
134 free(self->comm); 226 parent = *p;
135 self->comm = strdup(parent->comm); 227 m = rb_entry(parent, struct map, rb_node);
136 if (!self->comm) 228 if (ip < m->start)
137 return -ENOMEM; 229 p = &(*p)->rb_left;
230 else if (ip > m->end)
231 p = &(*p)->rb_right;
232 else
233 return m;
234 }
235
236 return NULL;
237}
238
239void thread__insert_map(struct thread *self, struct map *map)
240{
241 thread__remove_overlappings(self, map);
242 maps__insert(&self->maps[map->type], map);
243}
138 244
139 list_for_each_entry(map, &parent->maps, node) { 245static int thread__clone_maps(struct thread *self, struct thread *parent,
246 enum map_type type)
247{
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);
140 struct map *new = map__clone(map); 251 struct map *new = map__clone(map);
141 if (!new) 252 if (new == NULL)
142 return -ENOMEM; 253 return -ENOMEM;
143 thread__insert_map(self, new); 254 thread__insert_map(self, new);
144 } 255 }
145
146 return 0; 256 return 0;
147} 257}
148 258
149struct map *thread__find_map(struct thread *self, u64 ip) 259int thread__fork(struct thread *self, struct thread *parent)
150{ 260{
151 struct map *pos; 261 int i;
152 262
153 if (self == NULL) 263 if (self->comm)
154 return NULL; 264 free(self->comm);
155 265 self->comm = strdup(parent->comm);
156 list_for_each_entry(pos, &self->maps, node) 266 if (!self->comm)
157 if (ip >= pos->start && ip <= pos->end) 267 return -ENOMEM;
158 return pos;
159 268
160 return NULL; 269 for (i = 0; i < MAP__NR_TYPES; ++i)
270 if (thread__clone_maps(self, parent, i) < 0)
271 return -ENOMEM;
272 return 0;
161} 273}
162 274
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 275size_t threads__fprintf(FILE *fp)
164{ 276{
165 size_t ret = 0; 277 size_t ret = 0;
166 struct rb_node *nd; 278 struct rb_node *nd;
167 279
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 280 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 281 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 282
171 ret += thread__fprintf(pos, fp); 283 ret += thread__fprintf(pos, fp);
@@ -173,3 +285,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 285
174 return ret; 286 return ret;
175} 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 32aea3c1c2ad..686d6e914d9e 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,56 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
6struct thread { 8struct thread {
7 struct rb_node rb_node; 9 struct rb_node rb_node;
8 struct list_head maps; 10 struct rb_root maps[MAP__NR_TYPES];
11 struct list_head removed_maps[MAP__NR_TYPES];
9 pid_t pid; 12 pid_t pid;
13 bool use_modules;
10 char shortname[3]; 14 char shortname[3];
11 char *comm; 15 char *comm;
16 int comm_len;
12}; 17};
13 18
19void thread__init(struct thread *self, pid_t pid);
14int thread__set_comm(struct thread *self, const char *comm); 20int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 21int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 22struct thread *threads__findnew(pid_t pid);
17struct thread * 23struct thread *register_idle_thread(void);
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 24void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 25int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 26size_t thread__fprintf_maps(struct thread *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 27size_t threads__fprintf(FILE *fp);
28
29void maps__insert(struct rb_root *maps, struct map *map);
30struct map *maps__find(struct rb_root *maps, u64 addr);
31
32static inline struct map *thread__find_map(struct thread *self,
33 enum map_type type, u64 addr)
34{
35 return self ? maps__find(&self->maps[type], addr) : NULL;
36}
37
38static inline void __thread__insert_map(struct thread *self, struct map *map)
39{
40 maps__insert(&self->maps[map->type], map);
41}
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}
56#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index af4b0573b37f..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,27 +483,33 @@ 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(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 = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644); 512 output_fd = fd;
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507 513
508 buf[0] = 23; 514 buf[0] = 23;
509 buf[1] = 8; 515 buf[1] = 8;
@@ -530,11 +536,11 @@ void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
530 page_size = getpagesize(); 536 page_size = getpagesize();
531 write_or_die(&page_size, 4); 537 write_or_die(&page_size, 4);
532 538
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files(); 539 read_header_files();
536 read_ftrace_files(tps); 540 read_ftrace_files(tps);
537 read_event_files(tps); 541 read_event_files(tps);
538 read_proc_kallsyms(); 542 read_proc_kallsyms();
539 read_ftrace_printk(); 543 read_ftrace_printk();
544
545 return 0;
540} 546}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 55c9659a56e2..c5c32be040bf 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -40,12 +40,19 @@ int header_page_size_size;
40int header_page_data_offset; 40int header_page_data_offset;
41int header_page_data_size; 41int header_page_data_size;
42 42
43int latency_format;
44
43static char *input_buf; 45static char *input_buf;
44static unsigned long long input_buf_ptr; 46static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz; 47static unsigned long long input_buf_siz;
46 48
47static int cpus; 49static int cpus;
48static int long_size; 50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
49 56
50static void init_input_buf(char *buf, unsigned long long size) 57static void init_input_buf(char *buf, unsigned long long size)
51{ 58{
@@ -170,7 +177,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
170 func_count++; 177 func_count++;
171 } 178 }
172 179
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1); 180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
174 181
175 i = 0; 182 i = 0;
176 while (list) { 183 while (list) {
@@ -284,18 +291,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
284 char *line; 291 char *line;
285 char *next = NULL; 292 char *next = NULL;
286 char *addr_str; 293 char *addr_str;
287 int ret;
288 int i; 294 int i;
289 295
290 line = strtok_r(file, "\n", &next); 296 line = strtok_r(file, "\n", &next);
291 while (line) { 297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
292 item = malloc_or_die(sizeof(*item)); 303 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16); 304 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str); 305 /* fmt still has a space, skip it */
298 306 item->printk = strdup(line+1);
299 item->next = list; 307 item->next = list;
300 list = item; 308 list = item;
301 line = strtok_r(NULL, "\n", &next); 309 line = strtok_r(NULL, "\n", &next);
@@ -522,7 +530,10 @@ static enum event_type __read_token(char **tok)
522 last_ch = ch; 530 last_ch = ch;
523 ch = __read_char(); 531 ch = __read_char();
524 buf[i++] = ch; 532 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\'); 533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
526 /* remove the last quote */ 537 /* remove the last quote */
527 i--; 538 i--;
528 goto out; 539 goto out;
@@ -610,7 +621,7 @@ static enum event_type read_token_item(char **tok)
610static int test_type(enum event_type type, enum event_type expect) 621static int test_type(enum event_type type, enum event_type expect)
611{ 622{
612 if (type != expect) { 623 if (type != expect) {
613 die("Error: expected type %d but read %d", 624 warning("Error: expected type %d but read %d",
614 expect, type); 625 expect, type);
615 return -1; 626 return -1;
616 } 627 }
@@ -621,13 +632,13 @@ static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, const char *expect_tok) 632 enum event_type expect, const char *expect_tok)
622{ 633{
623 if (type != expect) { 634 if (type != expect) {
624 die("Error: expected type %d but read %d", 635 warning("Error: expected type %d but read %d",
625 expect, type); 636 expect, type);
626 return -1; 637 return -1;
627 } 638 }
628 639
629 if (strcmp(token, expect_tok) != 0) { 640 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'", 641 warning("Error: expected '%s' but read '%s'",
631 expect_tok, token); 642 expect_tok, token);
632 return -1; 643 return -1;
633 } 644 }
@@ -665,7 +676,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
665 676
666 free_token(token); 677 free_token(token);
667 678
668 return 0; 679 return ret;
669} 680}
670 681
671static int read_expected(enum event_type expect, const char *str) 682static int read_expected(enum event_type expect, const char *str)
@@ -682,10 +693,10 @@ static char *event_read_name(void)
682{ 693{
683 char *token; 694 char *token;
684 695
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0) 696 if (read_expected(EVENT_ITEM, "name") < 0)
686 return NULL; 697 return NULL;
687 698
688 if (read_expected(EVENT_OP, (char *)":") < 0) 699 if (read_expected(EVENT_OP, ":") < 0)
689 return NULL; 700 return NULL;
690 701
691 if (read_expect_type(EVENT_ITEM, &token) < 0) 702 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -703,10 +714,10 @@ static int event_read_id(void)
703 char *token; 714 char *token;
704 int id; 715 int id;
705 716
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0) 717 if (read_expected_item(EVENT_ITEM, "ID") < 0)
707 return -1; 718 return -1;
708 719
709 if (read_expected(EVENT_OP, (char *)":") < 0) 720 if (read_expected(EVENT_OP, ":") < 0)
710 return -1; 721 return -1;
711 722
712 if (read_expect_type(EVENT_ITEM, &token) < 0) 723 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -721,6 +732,24 @@ static int event_read_id(void)
721 return -1; 732 return -1;
722} 733}
723 734
735static int field_is_string(struct format_field *field)
736{
737 if ((field->flags & FIELD_IS_ARRAY) &&
738 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
739 !strstr(field->type, "s8")))
740 return 1;
741
742 return 0;
743}
744
745static int field_is_dynamic(struct format_field *field)
746{
747 if (!strcmp(field->type, "__data_loc"))
748 return 1;
749
750 return 0;
751}
752
724static int event_read_fields(struct event *event, struct format_field **fields) 753static int event_read_fields(struct event *event, struct format_field **fields)
725{ 754{
726 struct format_field *field = NULL; 755 struct format_field *field = NULL;
@@ -738,7 +767,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
738 767
739 count++; 768 count++;
740 769
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field")) 770 if (test_type_token(type, token, EVENT_ITEM, "field"))
742 goto fail; 771 goto fail;
743 free_token(token); 772 free_token(token);
744 773
@@ -753,7 +782,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
753 type = read_token(&token); 782 type = read_token(&token);
754 } 783 }
755 784
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0) 785 if (test_type_token(type, token, EVENT_OP, ":") < 0)
757 return -1; 786 return -1;
758 787
759 if (read_expect_type(EVENT_ITEM, &token) < 0) 788 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -865,14 +894,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
865 free(brackets); 894 free(brackets);
866 } 895 }
867 896
868 if (test_type_token(type, token, EVENT_OP, (char *)";")) 897 if (field_is_string(field)) {
898 field->flags |= FIELD_IS_STRING;
899 if (field_is_dynamic(field))
900 field->flags |= FIELD_IS_DYNAMIC;
901 }
902
903 if (test_type_token(type, token, EVENT_OP, ";"))
869 goto fail; 904 goto fail;
870 free_token(token); 905 free_token(token);
871 906
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 907 if (read_expected(EVENT_ITEM, "offset") < 0)
873 goto fail_expect; 908 goto fail_expect;
874 909
875 if (read_expected(EVENT_OP, (char *)":") < 0) 910 if (read_expected(EVENT_OP, ":") < 0)
876 goto fail_expect; 911 goto fail_expect;
877 912
878 if (read_expect_type(EVENT_ITEM, &token)) 913 if (read_expect_type(EVENT_ITEM, &token))
@@ -880,13 +915,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
880 field->offset = strtoul(token, NULL, 0); 915 field->offset = strtoul(token, NULL, 0);
881 free_token(token); 916 free_token(token);
882 917
883 if (read_expected(EVENT_OP, (char *)";") < 0) 918 if (read_expected(EVENT_OP, ";") < 0)
884 goto fail_expect; 919 goto fail_expect;
885 920
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 921 if (read_expected(EVENT_ITEM, "size") < 0)
887 goto fail_expect; 922 goto fail_expect;
888 923
889 if (read_expected(EVENT_OP, (char *)":") < 0) 924 if (read_expected(EVENT_OP, ":") < 0)
890 goto fail_expect; 925 goto fail_expect;
891 926
892 if (read_expect_type(EVENT_ITEM, &token)) 927 if (read_expect_type(EVENT_ITEM, &token))
@@ -894,11 +929,34 @@ static int event_read_fields(struct event *event, struct format_field **fields)
894 field->size = strtoul(token, NULL, 0); 929 field->size = strtoul(token, NULL, 0);
895 free_token(token); 930 free_token(token);
896 931
897 if (read_expected(EVENT_OP, (char *)";") < 0) 932 if (read_expected(EVENT_OP, ";") < 0)
898 goto fail_expect; 933 goto fail_expect;
899 934
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0) 935 type = read_token(&token);
901 goto fail; 936 if (type != EVENT_NEWLINE) {
937 /* newer versions of the kernel have a "signed" type */
938 if (test_type_token(type, token, EVENT_ITEM, "signed"))
939 goto fail;
940
941 free_token(token);
942
943 if (read_expected(EVENT_OP, ":") < 0)
944 goto fail_expect;
945
946 if (read_expect_type(EVENT_ITEM, &token))
947 goto fail;
948
949 if (strtoul(token, NULL, 0))
950 field->flags |= FIELD_IS_SIGNED;
951
952 free_token(token);
953 if (read_expected(EVENT_OP, ";") < 0)
954 goto fail_expect;
955
956 if (read_expect_type(EVENT_NEWLINE, &token))
957 goto fail;
958 }
959
902 free_token(token); 960 free_token(token);
903 961
904 *fields = field; 962 *fields = field;
@@ -921,10 +979,10 @@ static int event_read_format(struct event *event)
921 char *token; 979 char *token;
922 int ret; 980 int ret;
923 981
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0) 982 if (read_expected_item(EVENT_ITEM, "format") < 0)
925 return -1; 983 return -1;
926 984
927 if (read_expected(EVENT_OP, (char *)":") < 0) 985 if (read_expected(EVENT_OP, ":") < 0)
928 return -1; 986 return -1;
929 987
930 if (read_expect_type(EVENT_NEWLINE, &token)) 988 if (read_expect_type(EVENT_NEWLINE, &token))
@@ -984,7 +1042,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
984 1042
985 *tok = NULL; 1043 *tok = NULL;
986 type = process_arg(event, left, &token); 1044 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":")) 1045 if (test_type_token(type, token, EVENT_OP, ":"))
988 goto out_free; 1046 goto out_free;
989 1047
990 arg->op.op = token; 1048 arg->op.op = token;
@@ -1004,6 +1062,35 @@ out_free:
1004 return EVENT_ERROR; 1062 return EVENT_ERROR;
1005} 1063}
1006 1064
1065static enum event_type
1066process_array(struct event *event, struct print_arg *top, char **tok)
1067{
1068 struct print_arg *arg;
1069 enum event_type type;
1070 char *token = NULL;
1071
1072 arg = malloc_or_die(sizeof(*arg));
1073 memset(arg, 0, sizeof(*arg));
1074
1075 *tok = NULL;
1076 type = process_arg(event, arg, &token);
1077 if (test_type_token(type, token, EVENT_OP, "]"))
1078 goto out_free;
1079
1080 top->op.right = arg;
1081
1082 free_token(token);
1083 type = read_token_item(&token);
1084 *tok = token;
1085
1086 return type;
1087
1088out_free:
1089 free_token(*tok);
1090 free_arg(arg);
1091 return EVENT_ERROR;
1092}
1093
1007static int get_op_prio(char *op) 1094static int get_op_prio(char *op)
1008{ 1095{
1009 if (!op[1]) { 1096 if (!op[1]) {
@@ -1128,6 +1215,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1128 strcmp(token, "*") == 0 || 1215 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 || 1216 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 || 1217 strcmp(token, "/") == 0 ||
1218 strcmp(token, "<") == 0 ||
1219 strcmp(token, ">") == 0 ||
1131 strcmp(token, "==") == 0 || 1220 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) { 1221 strcmp(token, "!=") == 0) {
1133 1222
@@ -1144,17 +1233,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
1144 1233
1145 right = malloc_or_die(sizeof(*right)); 1234 right = malloc_or_die(sizeof(*right));
1146 1235
1147 type = process_arg(event, right, tok); 1236 type = read_token_item(&token);
1237 *tok = token;
1238
1239 /* could just be a type pointer */
1240 if ((strcmp(arg->op.op, "*") == 0) &&
1241 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1242 if (left->type != PRINT_ATOM)
1243 die("bad pointer type");
1244 left->atom.atom = realloc(left->atom.atom,
1245 sizeof(left->atom.atom) + 3);
1246 strcat(left->atom.atom, " *");
1247 *arg = *left;
1248 free(arg);
1249
1250 return type;
1251 }
1252
1253 type = process_arg_token(event, right, tok, type);
1148 1254
1149 arg->op.right = right; 1255 arg->op.right = right;
1150 1256
1257 } else if (strcmp(token, "[") == 0) {
1258
1259 left = malloc_or_die(sizeof(*left));
1260 *left = *arg;
1261
1262 arg->type = PRINT_OP;
1263 arg->op.op = token;
1264 arg->op.left = left;
1265
1266 arg->op.prio = 0;
1267 type = process_array(event, arg, tok);
1268
1151 } else { 1269 } else {
1152 die("unknown op '%s'", token); 1270 warning("unknown op '%s'", token);
1271 event->flags |= EVENT_FL_FAILED;
1153 /* the arg is now the left side */ 1272 /* the arg is now the left side */
1154 return EVENT_NONE; 1273 return EVENT_NONE;
1155 } 1274 }
1156 1275
1157
1158 if (type == EVENT_OP) { 1276 if (type == EVENT_OP) {
1159 int prio; 1277 int prio;
1160 1278
@@ -1178,7 +1296,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1178 char *field; 1296 char *field;
1179 char *token; 1297 char *token;
1180 1298
1181 if (read_expected(EVENT_OP, (char *)"->") < 0) 1299 if (read_expected(EVENT_OP, "->") < 0)
1182 return EVENT_ERROR; 1300 return EVENT_ERROR;
1183 1301
1184 if (read_expect_type(EVENT_ITEM, &token) < 0) 1302 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1188,6 +1306,16 @@ process_entry(struct event *event __unused, struct print_arg *arg,
1188 arg->type = PRINT_FIELD; 1306 arg->type = PRINT_FIELD;
1189 arg->field.name = field; 1307 arg->field.name = field;
1190 1308
1309 if (is_flag_field) {
1310 arg->field.field = find_any_field(event, arg->field.name);
1311 arg->field.field->flags |= FIELD_IS_FLAG;
1312 is_flag_field = 0;
1313 } else if (is_symbolic_field) {
1314 arg->field.field = find_any_field(event, arg->field.name);
1315 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1316 is_symbolic_field = 0;
1317 }
1318
1191 type = read_token(&token); 1319 type = read_token(&token);
1192 *tok = token; 1320 *tok = token;
1193 1321
@@ -1338,25 +1466,25 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1338 do { 1466 do {
1339 free_token(token); 1467 free_token(token);
1340 type = read_token_item(&token); 1468 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{")) 1469 if (test_type_token(type, token, EVENT_OP, "{"))
1342 break; 1470 break;
1343 1471
1344 arg = malloc_or_die(sizeof(*arg)); 1472 arg = malloc_or_die(sizeof(*arg));
1345 1473
1346 free_token(token); 1474 free_token(token);
1347 type = process_arg(event, arg, &token); 1475 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1476 if (test_type_token(type, token, EVENT_DELIM, ","))
1349 goto out_free; 1477 goto out_free;
1350 1478
1351 field = malloc_or_die(sizeof(*field)); 1479 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field)); 1480 memset(field, 0, sizeof(*field));
1353 1481
1354 value = arg_eval(arg); 1482 value = arg_eval(arg);
1355 field->value = strdup(value); 1483 field->value = strdup(value);
1356 1484
1357 free_token(token); 1485 free_token(token);
1358 type = process_arg(event, arg, &token); 1486 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}")) 1487 if (test_type_token(type, token, EVENT_OP, "}"))
1360 goto out_free; 1488 goto out_free;
1361 1489
1362 value = arg_eval(arg); 1490 value = arg_eval(arg);
@@ -1391,13 +1519,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1391 memset(arg, 0, sizeof(*arg)); 1519 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS; 1520 arg->type = PRINT_FLAGS;
1393 1521
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1522 if (read_expected_item(EVENT_DELIM, "(") < 0)
1395 return EVENT_ERROR; 1523 return EVENT_ERROR;
1396 1524
1397 field = malloc_or_die(sizeof(*field)); 1525 field = malloc_or_die(sizeof(*field));
1398 1526
1399 type = process_arg(event, field, &token); 1527 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1528 if (test_type_token(type, token, EVENT_DELIM, ","))
1401 goto out_free; 1529 goto out_free;
1402 1530
1403 arg->flags.field = field; 1531 arg->flags.field = field;
@@ -1408,11 +1536,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
1408 type = read_token_item(&token); 1536 type = read_token_item(&token);
1409 } 1537 }
1410 1538
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1539 if (test_type_token(type, token, EVENT_DELIM, ","))
1412 goto out_free; 1540 goto out_free;
1413 1541
1414 type = process_fields(event, &arg->flags.flags, &token); 1542 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1543 if (test_type_token(type, token, EVENT_DELIM, ")"))
1416 goto out_free; 1544 goto out_free;
1417 1545
1418 free_token(token); 1546 free_token(token);
@@ -1434,19 +1562,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
1434 memset(arg, 0, sizeof(*arg)); 1562 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL; 1563 arg->type = PRINT_SYMBOL;
1436 1564
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0) 1565 if (read_expected_item(EVENT_DELIM, "(") < 0)
1438 return EVENT_ERROR; 1566 return EVENT_ERROR;
1439 1567
1440 field = malloc_or_die(sizeof(*field)); 1568 field = malloc_or_die(sizeof(*field));
1441 1569
1442 type = process_arg(event, field, &token); 1570 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1571 if (test_type_token(type, token, EVENT_DELIM, ","))
1444 goto out_free; 1572 goto out_free;
1445 1573
1446 arg->symbol.field = field; 1574 arg->symbol.field = field;
1447 1575
1448 type = process_fields(event, &arg->symbol.symbols, &token); 1576 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) 1577 if (test_type_token(type, token, EVENT_DELIM, ")"))
1450 goto out_free; 1578 goto out_free;
1451 1579
1452 free_token(token); 1580 free_token(token);
@@ -1463,7 +1591,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{ 1591{
1464 struct print_arg *item_arg; 1592 struct print_arg *item_arg;
1465 enum event_type type; 1593 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token; 1594 char *token;
1468 1595
1469 type = process_arg(event, arg, &token); 1596 type = process_arg(event, arg, &token);
@@ -1471,28 +1598,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1471 if (type == EVENT_ERROR) 1598 if (type == EVENT_ERROR)
1472 return EVENT_ERROR; 1599 return EVENT_ERROR;
1473 1600
1474 if (type == EVENT_OP) { 1601 if (type == EVENT_OP)
1475 /* handle the ptr casts */ 1602 type = process_op(event, arg, &token);
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489 1603
1490 if (type == EVENT_ERROR) 1604 if (type == EVENT_ERROR)
1491 return EVENT_ERROR; 1605 return EVENT_ERROR;
1492 }
1493 }
1494 1606
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) { 1607 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1496 free_token(token); 1608 free_token(token);
1497 return EVENT_ERROR; 1609 return EVENT_ERROR;
1498 } 1610 }
@@ -1516,13 +1628,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
1516 item_arg = malloc_or_die(sizeof(*item_arg)); 1628 item_arg = malloc_or_die(sizeof(*item_arg));
1517 1629
1518 arg->type = PRINT_TYPE; 1630 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom; 1631 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg; 1632 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type); 1633 type = process_arg_token(event, item_arg, &token, type);
@@ -1540,7 +1645,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1540 enum event_type type; 1645 enum event_type type;
1541 char *token; 1646 char *token;
1542 1647
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0) 1648 if (read_expected(EVENT_DELIM, "(") < 0)
1544 return EVENT_ERROR; 1649 return EVENT_ERROR;
1545 1650
1546 if (read_expect_type(EVENT_ITEM, &token) < 0) 1651 if (read_expect_type(EVENT_ITEM, &token) < 0)
@@ -1550,7 +1655,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1550 arg->string.string = token; 1655 arg->string.string = token;
1551 arg->string.offset = -1; 1656 arg->string.offset = -1;
1552 1657
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0) 1658 if (read_expected(EVENT_DELIM, ")") < 0)
1554 return EVENT_ERROR; 1659 return EVENT_ERROR;
1555 1660
1556 type = read_token(&token); 1661 type = read_token(&token);
@@ -1578,9 +1683,11 @@ process_arg_token(struct event *event, struct print_arg *arg,
1578 type = process_entry(event, arg, &token); 1683 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) { 1684 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token); 1685 free_token(token);
1686 is_flag_field = 1;
1581 type = process_flags(event, arg, &token); 1687 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) { 1688 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token); 1689 free_token(token);
1690 is_symbolic_field = 1;
1584 type = process_symbols(event, arg, &token); 1691 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) { 1692 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token); 1693 free_token(token);
@@ -1637,12 +1744,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
1637 1744
1638static int event_read_print_args(struct event *event, struct print_arg **list) 1745static int event_read_print_args(struct event *event, struct print_arg **list)
1639{ 1746{
1640 enum event_type type; 1747 enum event_type type = EVENT_ERROR;
1641 struct print_arg *arg; 1748 struct print_arg *arg;
1642 char *token; 1749 char *token;
1643 int args = 0; 1750 int args = 0;
1644 1751
1645 do { 1752 do {
1753 if (type == EVENT_NEWLINE) {
1754 free_token(token);
1755 type = read_token_item(&token);
1756 continue;
1757 }
1758
1646 arg = malloc_or_die(sizeof(*arg)); 1759 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg)); 1760 memset(arg, 0, sizeof(*arg));
1648 1761
@@ -1683,18 +1796,19 @@ static int event_read_print(struct event *event)
1683 char *token; 1796 char *token;
1684 int ret; 1797 int ret;
1685 1798
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0) 1799 if (read_expected_item(EVENT_ITEM, "print") < 0)
1687 return -1; 1800 return -1;
1688 1801
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0) 1802 if (read_expected(EVENT_ITEM, "fmt") < 0)
1690 return -1; 1803 return -1;
1691 1804
1692 if (read_expected(EVENT_OP, (char *)":") < 0) 1805 if (read_expected(EVENT_OP, ":") < 0)
1693 return -1; 1806 return -1;
1694 1807
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0) 1808 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail; 1809 goto fail;
1697 1810
1811 concat:
1698 event->print_fmt.format = token; 1812 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL; 1813 event->print_fmt.args = NULL;
1700 1814
@@ -1704,7 +1818,22 @@ static int event_read_print(struct event *event)
1704 if (type == EVENT_NONE) 1818 if (type == EVENT_NONE)
1705 return 0; 1819 return 0;
1706 1820
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)",")) 1821 /* Handle concatination of print lines */
1822 if (type == EVENT_DQUOTE) {
1823 char *cat;
1824
1825 cat = malloc_or_die(strlen(event->print_fmt.format) +
1826 strlen(token) + 1);
1827 strcpy(cat, event->print_fmt.format);
1828 strcat(cat, token);
1829 free_token(token);
1830 free_token(event->print_fmt.format);
1831 event->print_fmt.format = NULL;
1832 token = cat;
1833 goto concat;
1834 }
1835
1836 if (test_type_token(type, token, EVENT_DELIM, ","))
1708 goto fail; 1837 goto fail;
1709 1838
1710 free_token(token); 1839 free_token(token);
@@ -1713,7 +1842,7 @@ static int event_read_print(struct event *event)
1713 if (ret < 0) 1842 if (ret < 0)
1714 return -1; 1843 return -1;
1715 1844
1716 return 0; 1845 return ret;
1717 1846
1718 fail: 1847 fail:
1719 free_token(token); 1848 free_token(token);
@@ -1759,7 +1888,7 @@ find_any_field(struct event *event, const char *name)
1759 return find_field(event, name); 1888 return find_field(event, name);
1760} 1889}
1761 1890
1762static unsigned long long read_size(void *ptr, int size) 1891unsigned long long read_size(void *ptr, int size)
1763{ 1892{
1764 switch (size) { 1893 switch (size) {
1765 case 1: 1894 case 1:
@@ -1822,37 +1951,67 @@ static int get_common_info(const char *type, int *offset, int *size)
1822 return 0; 1951 return 0;
1823} 1952}
1824 1953
1825int trace_parse_common_type(void *data) 1954static int __parse_common(void *data, int *size, int *offset,
1955 const char *name)
1826{ 1956{
1827 static int type_offset;
1828 static int type_size;
1829 int ret; 1957 int ret;
1830 1958
1831 if (!type_size) { 1959 if (!*size) {
1832 ret = get_common_info("common_type", 1960 ret = get_common_info(name, offset, size);
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0) 1961 if (ret < 0)
1836 return ret; 1962 return ret;
1837 } 1963 }
1838 return read_size(data + type_offset, type_size); 1964 return read_size(data + *offset, *size);
1965}
1966
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");
1839} 1974}
1840 1975
1841static int parse_common_pid(void *data) 1976int trace_parse_common_pid(void *data)
1842{ 1977{
1843 static int pid_offset; 1978 static int pid_offset;
1844 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;
1845 int ret; 2007 int ret;
1846 2008
1847 if (!pid_size) { 2009 ret = __parse_common(data, &ld_size, &ld_offset,
1848 ret = get_common_info("common_pid", 2010 "common_lock_depth");
1849 &pid_offset, 2011 if (ret < 0)
1850 &pid_size); 2012 return -1;
1851 if (ret < 0)
1852 return ret;
1853 }
1854 2013
1855 return read_size(data + pid_offset, pid_size); 2014 return ret;
1856} 2015}
1857 2016
1858struct event *trace_find_event(int id) 2017struct event *trace_find_event(int id)
@@ -1866,11 +2025,20 @@ struct event *trace_find_event(int id)
1866 return event; 2025 return event;
1867} 2026}
1868 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
1869static unsigned long long eval_num_arg(void *data, int size, 2036static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg) 2037 struct event *event, struct print_arg *arg)
1871{ 2038{
1872 unsigned long long val = 0; 2039 unsigned long long val = 0;
1873 unsigned long long left, right; 2040 unsigned long long left, right;
2041 struct print_arg *larg;
1874 2042
1875 switch (arg->type) { 2043 switch (arg->type) {
1876 case PRINT_NULL: 2044 case PRINT_NULL:
@@ -1897,6 +2065,26 @@ static unsigned long long eval_num_arg(void *data, int size,
1897 return 0; 2065 return 0;
1898 break; 2066 break;
1899 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:
1900 left = eval_num_arg(data, size, event, arg->op.left); 2088 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right); 2089 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) { 2090 switch (arg->op.op[0]) {
@@ -1947,6 +2135,12 @@ static unsigned long long eval_num_arg(void *data, int size,
1947 die("unknown op '%s'", arg->op.op); 2135 die("unknown op '%s'", arg->op.op);
1948 val = left == right; 2136 val = left == right;
1949 break; 2137 break;
2138 case '-':
2139 val = left - right;
2140 break;
2141 case '+':
2142 val = left + right;
2143 break;
1950 default: 2144 default:
1951 die("unknown op '%s'", arg->op.op); 2145 die("unknown op '%s'", arg->op.op);
1952 } 2146 }
@@ -1978,7 +2172,7 @@ static const struct flag flags[] = {
1978 { "HRTIMER_RESTART", 1 }, 2172 { "HRTIMER_RESTART", 1 },
1979}; 2173};
1980 2174
1981static unsigned long long eval_flag(const char *flag) 2175unsigned long long eval_flag(const char *flag)
1982{ 2176{
1983 int i; 2177 int i;
1984 2178
@@ -2145,8 +2339,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
2145 case 'u': 2339 case 'u':
2146 case 'x': 2340 case 'x':
2147 case 'i': 2341 case 'i':
2148 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & 2342 /* the pointers are always 4 bytes aligned */
2149 ~(long_size - 1)); 2343 bptr = (void *)(((unsigned long)bptr + 3) &
2344 ~3);
2150 switch (ls) { 2345 switch (ls) {
2151 case 0: 2346 case 0:
2152 case 1: 2347 case 1:
@@ -2270,7 +2465,27 @@ static void pretty_print(void *data, int size, struct event *event)
2270 2465
2271 for (; *ptr; ptr++) { 2466 for (; *ptr; ptr++) {
2272 ls = 0; 2467 ls = 0;
2273 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 == '%') {
2274 saveptr = ptr; 2489 saveptr = ptr;
2275 show_func = 0; 2490 show_func = 0;
2276 cont_process: 2491 cont_process:
@@ -2377,6 +2592,41 @@ static inline int log10_cpu(int nb)
2377 return 1; 2592 return 1;
2378} 2593}
2379 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
2380/* taken from Linux, written by Frederic Weisbecker */ 2630/* taken from Linux, written by Frederic Weisbecker */
2381static void print_graph_cpu(int cpu) 2631static void print_graph_cpu(int cpu)
2382{ 2632{
@@ -2452,7 +2702,7 @@ get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2452 if (!(event->flags & EVENT_FL_ISFUNCRET)) 2702 if (!(event->flags & EVENT_FL_ISFUNCRET))
2453 return NULL; 2703 return NULL;
2454 2704
2455 pid = parse_common_pid(next->data); 2705 pid = trace_parse_common_pid(next->data);
2456 field = find_field(event, "func"); 2706 field = find_field(event, "func");
2457 if (!field) 2707 if (!field)
2458 die("function return does not have field func"); 2708 die("function return does not have field func");
@@ -2620,6 +2870,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
2620 2870
2621 printf(" | "); 2871 printf(" | ");
2622 2872
2873 if (latency_format) {
2874 print_lat_fmt(data, size);
2875 printf(" | ");
2876 }
2877
2623 field = find_field(event, "func"); 2878 field = find_field(event, "func");
2624 if (!field) 2879 if (!field)
2625 die("function entry does not have func field"); 2880 die("function entry does not have func field");
@@ -2663,6 +2918,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
2663 2918
2664 printf(" | "); 2919 printf(" | ");
2665 2920
2921 if (latency_format) {
2922 print_lat_fmt(data, size);
2923 printf(" | ");
2924 }
2925
2666 field = find_field(event, "rettime"); 2926 field = find_field(event, "rettime");
2667 if (!field) 2927 if (!field)
2668 die("can't find rettime in return graph"); 2928 die("can't find rettime in return graph");
@@ -2724,19 +2984,30 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2724 2984
2725 event = trace_find_event(type); 2985 event = trace_find_event(type);
2726 if (!event) { 2986 if (!event) {
2727 printf("ug! no event found for type %d\n", type); 2987 warning("ug! no event found for type %d", type);
2728 return; 2988 return;
2729 } 2989 }
2730 2990
2731 pid = parse_common_pid(data); 2991 pid = trace_parse_common_pid(data);
2732 2992
2733 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) 2993 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2734 return pretty_print_func_graph(data, size, event, cpu, 2994 return pretty_print_func_graph(data, size, event, cpu,
2735 pid, comm, secs, usecs); 2995 pid, comm, secs, usecs);
2736 2996
2737 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ", 2997 if (latency_format) {
2738 comm, pid, cpu, 2998 printf("%8.8s-%-5d %3d",
2739 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 }
2740 3011
2741 pretty_print(data, size, event); 3012 pretty_print(data, size, event);
2742 printf("\n"); 3013 printf("\n");
@@ -2807,46 +3078,71 @@ static void print_args(struct print_arg *args)
2807 } 3078 }
2808} 3079}
2809 3080
2810static void parse_header_field(char *type, 3081static void parse_header_field(const char *field,
2811 int *offset, int *size) 3082 int *offset, int *size)
2812{ 3083{
2813 char *token; 3084 char *token;
3085 int type;
2814 3086
2815 if (read_expected(EVENT_ITEM, (char *)"field") < 0) 3087 if (read_expected(EVENT_ITEM, "field") < 0)
2816 return; 3088 return;
2817 if (read_expected(EVENT_OP, (char *)":") < 0) 3089 if (read_expected(EVENT_OP, ":") < 0)
2818 return; 3090 return;
3091
2819 /* type */ 3092 /* type */
2820 if (read_expect_type(EVENT_ITEM, &token) < 0) 3093 if (read_expect_type(EVENT_ITEM, &token) < 0)
2821 return; 3094 goto fail;
2822 free_token(token); 3095 free_token(token);
2823 3096
2824 if (read_expected(EVENT_ITEM, type) < 0) 3097 if (read_expected(EVENT_ITEM, field) < 0)
2825 return; 3098 return;
2826 if (read_expected(EVENT_OP, (char *)";") < 0) 3099 if (read_expected(EVENT_OP, ";") < 0)
2827 return; 3100 return;
2828 if (read_expected(EVENT_ITEM, (char *)"offset") < 0) 3101 if (read_expected(EVENT_ITEM, "offset") < 0)
2829 return; 3102 return;
2830 if (read_expected(EVENT_OP, (char *)":") < 0) 3103 if (read_expected(EVENT_OP, ":") < 0)
2831 return; 3104 return;
2832 if (read_expect_type(EVENT_ITEM, &token) < 0) 3105 if (read_expect_type(EVENT_ITEM, &token) < 0)
2833 return; 3106 goto fail;
2834 *offset = atoi(token); 3107 *offset = atoi(token);
2835 free_token(token); 3108 free_token(token);
2836 if (read_expected(EVENT_OP, (char *)";") < 0) 3109 if (read_expected(EVENT_OP, ";") < 0)
2837 return; 3110 return;
2838 if (read_expected(EVENT_ITEM, (char *)"size") < 0) 3111 if (read_expected(EVENT_ITEM, "size") < 0)
2839 return; 3112 return;
2840 if (read_expected(EVENT_OP, (char *)":") < 0) 3113 if (read_expected(EVENT_OP, ":") < 0)
2841 return; 3114 return;
2842 if (read_expect_type(EVENT_ITEM, &token) < 0) 3115 if (read_expect_type(EVENT_ITEM, &token) < 0)
2843 return; 3116 goto fail;
2844 *size = atoi(token); 3117 *size = atoi(token);
2845 free_token(token); 3118 free_token(token);
2846 if (read_expected(EVENT_OP, (char *)";") < 0) 3119 if (read_expected(EVENT_OP, ";") < 0)
2847 return;
2848 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2849 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:
2850 free_token(token); 3146 free_token(token);
2851} 3147}
2852 3148
@@ -2854,11 +3150,11 @@ int parse_header_page(char *buf, unsigned long size)
2854{ 3150{
2855 init_input_buf(buf, size); 3151 init_input_buf(buf, size);
2856 3152
2857 parse_header_field((char *)"timestamp", &header_page_ts_offset, 3153 parse_header_field("timestamp", &header_page_ts_offset,
2858 &header_page_ts_size); 3154 &header_page_ts_size);
2859 parse_header_field((char *)"commit", &header_page_size_offset, 3155 parse_header_field("commit", &header_page_size_offset,
2860 &header_page_size_size); 3156 &header_page_size_size);
2861 parse_header_field((char *)"data", &header_page_data_offset, 3157 parse_header_field("data", &header_page_data_offset,
2862 &header_page_data_size); 3158 &header_page_data_size);
2863 3159
2864 return 0; 3160 return 0;
@@ -2909,6 +3205,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
2909 if (ret < 0) 3205 if (ret < 0)
2910 die("failed to read ftrace event print fmt"); 3206 die("failed to read ftrace event print fmt");
2911 3207
3208 /* New ftrace handles args */
3209 if (ret > 0)
3210 return 0;
2912 /* 3211 /*
2913 * The arguments for ftrace files are parsed by the fields. 3212 * The arguments for ftrace files are parsed by the fields.
2914 * Set up the fields as their arguments. 3213 * Set up the fields as their arguments.
@@ -2926,7 +3225,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
2926 return 0; 3225 return 0;
2927} 3226}
2928 3227
2929int parse_event_file(char *buf, unsigned long size, char *system__unused __unused) 3228int parse_event_file(char *buf, unsigned long size, char *sys)
2930{ 3229{
2931 struct event *event; 3230 struct event *event;
2932 int ret; 3231 int ret;
@@ -2946,12 +3245,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2946 die("failed to read event id"); 3245 die("failed to read event id");
2947 3246
2948 ret = event_read_format(event); 3247 ret = event_read_format(event);
2949 if (ret < 0) 3248 if (ret < 0) {
2950 die("failed to read event format"); 3249 warning("failed to read event format for %s", event->name);
3250 goto event_failed;
3251 }
2951 3252
2952 ret = event_read_print(event); 3253 ret = event_read_print(event);
2953 if (ret < 0) 3254 if (ret < 0) {
2954 die("failed to read event print fmt"); 3255 warning("failed to read event print fmt for %s", event->name);
3256 goto event_failed;
3257 }
3258
3259 event->system = strdup(sys);
2955 3260
2956#define PRINT_ARGS 0 3261#define PRINT_ARGS 0
2957 if (PRINT_ARGS && event->print_fmt.args) 3262 if (PRINT_ARGS && event->print_fmt.args)
@@ -2959,6 +3264,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
2959 3264
2960 add_event(event); 3265 add_event(event);
2961 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;
2962} 3273}
2963 3274
2964void 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..a5ffe60db5d6
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.c
@@ -0,0 +1,641 @@
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 xs_init(pTHX)
36{
37 const char *file = __FILE__;
38 dXSUB_SYS;
39
40 newXS("Perf::Trace::Context::bootstrap", boot_Perf__Trace__Context,
41 file);
42 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
43}
44
45INTERP my_perl;
46
47#define FTRACE_MAX_EVENT \
48 ((1 << (sizeof(unsigned short) * 8)) - 1)
49
50struct event *events[FTRACE_MAX_EVENT];
51
52static struct scripting_context *scripting_context;
53
54static char *cur_field_name;
55static int zero_flag_atom;
56
57static void define_symbolic_value(const char *ev_name,
58 const char *field_name,
59 const char *field_value,
60 const char *field_str)
61{
62 unsigned long long value;
63 dSP;
64
65 value = eval_flag(field_value);
66
67 ENTER;
68 SAVETMPS;
69 PUSHMARK(SP);
70
71 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
72 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
73 XPUSHs(sv_2mortal(newSVuv(value)));
74 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
75
76 PUTBACK;
77 if (get_cv("main::define_symbolic_value", 0))
78 call_pv("main::define_symbolic_value", G_SCALAR);
79 SPAGAIN;
80 PUTBACK;
81 FREETMPS;
82 LEAVE;
83}
84
85static void define_symbolic_values(struct print_flag_sym *field,
86 const char *ev_name,
87 const char *field_name)
88{
89 define_symbolic_value(ev_name, field_name, field->value, field->str);
90 if (field->next)
91 define_symbolic_values(field->next, ev_name, field_name);
92}
93
94static void define_symbolic_field(const char *ev_name,
95 const char *field_name)
96{
97 dSP;
98
99 ENTER;
100 SAVETMPS;
101 PUSHMARK(SP);
102
103 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
104 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
105
106 PUTBACK;
107 if (get_cv("main::define_symbolic_field", 0))
108 call_pv("main::define_symbolic_field", G_SCALAR);
109 SPAGAIN;
110 PUTBACK;
111 FREETMPS;
112 LEAVE;
113}
114
115static void define_flag_value(const char *ev_name,
116 const char *field_name,
117 const char *field_value,
118 const char *field_str)
119{
120 unsigned long long value;
121 dSP;
122
123 value = eval_flag(field_value);
124
125 ENTER;
126 SAVETMPS;
127 PUSHMARK(SP);
128
129 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
130 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
131 XPUSHs(sv_2mortal(newSVuv(value)));
132 XPUSHs(sv_2mortal(newSVpv(field_str, 0)));
133
134 PUTBACK;
135 if (get_cv("main::define_flag_value", 0))
136 call_pv("main::define_flag_value", G_SCALAR);
137 SPAGAIN;
138 PUTBACK;
139 FREETMPS;
140 LEAVE;
141}
142
143static void define_flag_values(struct print_flag_sym *field,
144 const char *ev_name,
145 const char *field_name)
146{
147 define_flag_value(ev_name, field_name, field->value, field->str);
148 if (field->next)
149 define_flag_values(field->next, ev_name, field_name);
150}
151
152static void define_flag_field(const char *ev_name,
153 const char *field_name,
154 const char *delim)
155{
156 dSP;
157
158 ENTER;
159 SAVETMPS;
160 PUSHMARK(SP);
161
162 XPUSHs(sv_2mortal(newSVpv(ev_name, 0)));
163 XPUSHs(sv_2mortal(newSVpv(field_name, 0)));
164 XPUSHs(sv_2mortal(newSVpv(delim, 0)));
165
166 PUTBACK;
167 if (get_cv("main::define_flag_field", 0))
168 call_pv("main::define_flag_field", G_SCALAR);
169 SPAGAIN;
170 PUTBACK;
171 FREETMPS;
172 LEAVE;
173}
174
175static void define_event_symbols(struct event *event,
176 const char *ev_name,
177 struct print_arg *args)
178{
179 switch (args->type) {
180 case PRINT_NULL:
181 break;
182 case PRINT_ATOM:
183 define_flag_value(ev_name, cur_field_name, "0",
184 args->atom.atom);
185 zero_flag_atom = 0;
186 break;
187 case PRINT_FIELD:
188 if (cur_field_name)
189 free(cur_field_name);
190 cur_field_name = strdup(args->field.name);
191 break;
192 case PRINT_FLAGS:
193 define_event_symbols(event, ev_name, args->flags.field);
194 define_flag_field(ev_name, cur_field_name, args->flags.delim);
195 define_flag_values(args->flags.flags, ev_name, cur_field_name);
196 break;
197 case PRINT_SYMBOL:
198 define_event_symbols(event, ev_name, args->symbol.field);
199 define_symbolic_field(ev_name, cur_field_name);
200 define_symbolic_values(args->symbol.symbols, ev_name,
201 cur_field_name);
202 break;
203 case PRINT_STRING:
204 break;
205 case PRINT_TYPE:
206 define_event_symbols(event, ev_name, args->typecast.item);
207 break;
208 case PRINT_OP:
209 if (strcmp(args->op.op, ":") == 0)
210 zero_flag_atom = 1;
211 define_event_symbols(event, ev_name, args->op.left);
212 define_event_symbols(event, ev_name, args->op.right);
213 break;
214 default:
215 /* we should warn... */
216 return;
217 }
218
219 if (args->next)
220 define_event_symbols(event, ev_name, args->next);
221}
222
223static inline struct event *find_cache_event(int type)
224{
225 static char ev_name[256];
226 struct event *event;
227
228 if (events[type])
229 return events[type];
230
231 events[type] = event = trace_find_event(type);
232 if (!event)
233 return NULL;
234
235 sprintf(ev_name, "%s::%s", event->system, event->name);
236
237 define_event_symbols(event, ev_name, event->print_fmt.args);
238
239 return event;
240}
241
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data,
270 int size __attribute((unused)),
271 unsigned long long nsecs, char *comm)
272{
273 struct format_field *field;
274 static char handler[256];
275 unsigned long long val;
276 unsigned long s, ns;
277 struct event *event;
278 int type;
279 int pid;
280
281 dSP;
282
283 type = trace_parse_common_type(data);
284
285 event = find_cache_event(type);
286 if (!event)
287 die("ug! no event found for type %d", type);
288
289 pid = trace_parse_common_pid(data);
290
291 sprintf(handler, "%s::%s", event->system, event->name);
292
293 s = nsecs / NSECS_PER_SEC;
294 ns = nsecs - s * NSECS_PER_SEC;
295
296 scripting_context->event_data = data;
297
298 ENTER;
299 SAVETMPS;
300 PUSHMARK(SP);
301
302 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
303 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
304 XPUSHs(sv_2mortal(newSVuv(cpu)));
305 XPUSHs(sv_2mortal(newSVuv(s)));
306 XPUSHs(sv_2mortal(newSVuv(ns)));
307 XPUSHs(sv_2mortal(newSViv(pid)));
308 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
309
310 /* common fields other than pid can be accessed via xsub fns */
311
312 for (field = event->format.fields; field; field = field->next) {
313 if (field->flags & FIELD_IS_STRING) {
314 int offset;
315 if (field->flags & FIELD_IS_DYNAMIC) {
316 offset = *(int *)(data + field->offset);
317 offset &= 0xffff;
318 } else
319 offset = field->offset;
320 XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
321 } else { /* FIELD_IS_NUMERIC */
322 val = read_size(data + field->offset, field->size);
323 if (field->flags & FIELD_IS_SIGNED) {
324 XPUSHs(sv_2mortal(newSViv(val)));
325 } else {
326 XPUSHs(sv_2mortal(newSVuv(val)));
327 }
328 }
329 }
330
331 PUTBACK;
332
333 if (get_cv(handler, 0))
334 call_pv(handler, G_SCALAR);
335 else if (get_cv("main::trace_unhandled", 0)) {
336 XPUSHs(sv_2mortal(newSVpv(handler, 0)));
337 XPUSHs(sv_2mortal(newSViv(PTR2IV(scripting_context))));
338 XPUSHs(sv_2mortal(newSVuv(cpu)));
339 XPUSHs(sv_2mortal(newSVuv(nsecs)));
340 XPUSHs(sv_2mortal(newSViv(pid)));
341 XPUSHs(sv_2mortal(newSVpv(comm, 0)));
342 call_pv("main::trace_unhandled", G_SCALAR);
343 }
344 SPAGAIN;
345 PUTBACK;
346 FREETMPS;
347 LEAVE;
348}
349
350static void run_start_sub(void)
351{
352 dSP; /* access to Perl stack */
353 PUSHMARK(SP);
354
355 if (get_cv("main::trace_begin", 0))
356 call_pv("main::trace_begin", G_DISCARD | G_NOARGS);
357}
358
359/*
360 * Start trace script
361 */
362static int perl_start_script(const char *script)
363{
364 const char *command_line[2] = { "", NULL };
365
366 command_line[1] = script;
367
368 my_perl = perl_alloc();
369 perl_construct(my_perl);
370
371 if (perl_parse(my_perl, xs_init, 2, (char **)command_line,
372 (char **)NULL))
373 return -1;
374
375 perl_run(my_perl);
376 if (SvTRUE(ERRSV))
377 return -1;
378
379 run_start_sub();
380
381 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
382
383 return 0;
384}
385
386/*
387 * Stop trace script
388 */
389static int perl_stop_script(void)
390{
391 dSP; /* access to Perl stack */
392 PUSHMARK(SP);
393
394 if (get_cv("main::trace_end", 0))
395 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
396
397 perl_destruct(my_perl);
398 perl_free(my_perl);
399
400 fprintf(stderr, "\nperf trace Perl script stopped\n");
401
402 return 0;
403}
404
405static int perl_generate_script(const char *outfile)
406{
407 struct event *event = NULL;
408 struct format_field *f;
409 char fname[PATH_MAX];
410 int not_first, count;
411 FILE *ofp;
412
413 sprintf(fname, "%s.pl", outfile);
414 ofp = fopen(fname, "w");
415 if (ofp == NULL) {
416 fprintf(stderr, "couldn't open %s\n", fname);
417 return -1;
418 }
419
420 fprintf(ofp, "# perf trace event handlers, "
421 "generated by perf trace -g perl\n");
422
423 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
424 " License version 2\n\n");
425
426 fprintf(ofp, "# The common_* event handler fields are the most useful "
427 "fields common to\n");
428
429 fprintf(ofp, "# all events. They don't necessarily correspond to "
430 "the 'common_*' fields\n");
431
432 fprintf(ofp, "# in the format files. Those fields not available as "
433 "handler params can\n");
434
435 fprintf(ofp, "# be retrieved using Perl functions of the form "
436 "common_*($context).\n");
437
438 fprintf(ofp, "# See Context.pm for the list of available "
439 "functions.\n\n");
440
441 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
442 "Perf-Trace-Util/lib\";\n");
443
444 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
445 fprintf(ofp, "use Perf::Trace::Core;\n");
446 fprintf(ofp, "use Perf::Trace::Context;\n");
447 fprintf(ofp, "use Perf::Trace::Util;\n\n");
448
449 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
450 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
451
452 while ((event = trace_find_next_event(event))) {
453 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
454 fprintf(ofp, "\tmy (");
455
456 fprintf(ofp, "$event_name, ");
457 fprintf(ofp, "$context, ");
458 fprintf(ofp, "$common_cpu, ");
459 fprintf(ofp, "$common_secs, ");
460 fprintf(ofp, "$common_nsecs,\n");
461 fprintf(ofp, "\t $common_pid, ");
462 fprintf(ofp, "$common_comm,\n\t ");
463
464 not_first = 0;
465 count = 0;
466
467 for (f = event->format.fields; f; f = f->next) {
468 if (not_first++)
469 fprintf(ofp, ", ");
470 if (++count % 5 == 0)
471 fprintf(ofp, "\n\t ");
472
473 fprintf(ofp, "$%s", f->name);
474 }
475 fprintf(ofp, ") = @_;\n\n");
476
477 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
478 "$common_secs, $common_nsecs,\n\t "
479 "$common_pid, $common_comm);\n\n");
480
481 fprintf(ofp, "\tprintf(\"");
482
483 not_first = 0;
484 count = 0;
485
486 for (f = event->format.fields; f; f = f->next) {
487 if (not_first++)
488 fprintf(ofp, ", ");
489 if (count && count % 4 == 0) {
490 fprintf(ofp, "\".\n\t \"");
491 }
492 count++;
493
494 fprintf(ofp, "%s=", f->name);
495 if (f->flags & FIELD_IS_STRING ||
496 f->flags & FIELD_IS_FLAG ||
497 f->flags & FIELD_IS_SYMBOLIC)
498 fprintf(ofp, "%%s");
499 else if (f->flags & FIELD_IS_SIGNED)
500 fprintf(ofp, "%%d");
501 else
502 fprintf(ofp, "%%u");
503 }
504
505 fprintf(ofp, "\\n\",\n\t ");
506
507 not_first = 0;
508 count = 0;
509
510 for (f = event->format.fields; f; f = f->next) {
511 if (not_first++)
512 fprintf(ofp, ", ");
513
514 if (++count % 5 == 0)
515 fprintf(ofp, "\n\t ");
516
517 if (f->flags & FIELD_IS_FLAG) {
518 if ((count - 1) % 5 != 0) {
519 fprintf(ofp, "\n\t ");
520 count = 4;
521 }
522 fprintf(ofp, "flag_str(\"");
523 fprintf(ofp, "%s::%s\", ", event->system,
524 event->name);
525 fprintf(ofp, "\"%s\", $%s)", f->name,
526 f->name);
527 } else if (f->flags & FIELD_IS_SYMBOLIC) {
528 if ((count - 1) % 5 != 0) {
529 fprintf(ofp, "\n\t ");
530 count = 4;
531 }
532 fprintf(ofp, "symbol_str(\"");
533 fprintf(ofp, "%s::%s\", ", event->system,
534 event->name);
535 fprintf(ofp, "\"%s\", $%s)", f->name,
536 f->name);
537 } else
538 fprintf(ofp, "$%s", f->name);
539 }
540
541 fprintf(ofp, ");\n");
542 fprintf(ofp, "}\n\n");
543 }
544
545 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
546 "$common_cpu, $common_secs, $common_nsecs,\n\t "
547 "$common_pid, $common_comm) = @_;\n\n");
548
549 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
550 "$common_secs, $common_nsecs,\n\t $common_pid, "
551 "$common_comm);\n}\n\n");
552
553 fprintf(ofp, "sub print_header\n{\n"
554 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
555 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
556 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
557
558 fclose(ofp);
559
560 fprintf(stderr, "generated Perl script: %s\n", fname);
561
562 return 0;
563}
564
565struct scripting_ops perl_scripting_ops = {
566 .name = "Perl",
567 .start_script = perl_start_script,
568 .stop_script = perl_stop_script,
569 .process_event = perl_process_event,
570 .generate_script = perl_generate_script,
571};
572
573static void print_unsupported_msg(void)
574{
575 fprintf(stderr, "Perl scripting not supported."
576 " Install libperl and rebuild perf to enable it.\n"
577 "For example:\n # apt-get install libperl-dev (ubuntu)"
578 "\n # yum install perl-ExtUtils-Embed (Fedora)"
579 "\n etc.\n");
580}
581
582static int perl_start_script_unsupported(const char *script __unused)
583{
584 print_unsupported_msg();
585
586 return -1;
587}
588
589static int perl_stop_script_unsupported(void)
590{
591 return 0;
592}
593
594static void perl_process_event_unsupported(int cpu __unused,
595 void *data __unused,
596 int size __unused,
597 unsigned long long nsecs __unused,
598 char *comm __unused)
599{
600}
601
602static int perl_generate_script_unsupported(const char *outfile __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609struct scripting_ops perl_scripting_unsupported_ops = {
610 .name = "Perl",
611 .start_script = perl_start_script_unsupported,
612 .stop_script = perl_stop_script_unsupported,
613 .process_event = perl_process_event_unsupported,
614 .generate_script = perl_generate_script_unsupported,
615};
616
617static void register_perl_scripting(struct scripting_ops *scripting_ops)
618{
619 int err;
620 err = script_spec_register("Perl", scripting_ops);
621 if (err)
622 die("error registering Perl script extension");
623
624 err = script_spec_register("pl", scripting_ops);
625 if (err)
626 die("error registering pl script extension");
627
628 scripting_context = malloc(sizeof(struct scripting_context));
629}
630
631#ifdef NO_LIBPERL
632void setup_perl_scripting(void)
633{
634 register_perl_scripting(&perl_scripting_unsupported_ops);
635}
636#else
637void setup_perl_scripting(void)
638{
639 register_perl_scripting(&perl_scripting_ops);
640}
641#endif
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
new file mode 100644
index 000000000000..e88fb26137bb
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.h
@@ -0,0 +1,55 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1b5c847d2c22..1744422cafcb 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -145,8 +145,9 @@ static void read_proc_kallsyms(void)
145 if (!size) 145 if (!size)
146 return; 146 return;
147 147
148 buf = malloc_or_die(size); 148 buf = malloc_or_die(size + 1);
149 read_or_die(buf, size); 149 read_or_die(buf, size);
150 buf[size] = '\0';
150 151
151 parse_proc_kallsyms(buf, size); 152 parse_proc_kallsyms(buf, size);
152 153
@@ -458,9 +459,8 @@ struct record *trace_read_data(int cpu)
458 return data; 459 return data;
459} 460}
460 461
461void trace_report(void) 462void trace_report(int fd)
462{ 463{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ]; 464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 465 char test[] = { 23, 8, 68 };
466 char *version; 466 char *version;
@@ -468,17 +468,15 @@ void trace_report(void)
468 int show_funcs = 0; 468 int show_funcs = 0;
469 int show_printk = 0; 469 int show_printk = 0;
470 470
471 input_fd = open(input_file, O_RDONLY); 471 input_fd = fd;
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474 472
475 read_or_die(buf, 3); 473 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0) 474 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file"); 475 die("no trace data in the file");
478 476
479 read_or_die(buf, 7); 477 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0) 478 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)"); 479 die("not a trace file (missing 'tracing' tag)");
482 480
483 version = read_string(); 481 version = read_string();
484 if (show_version) 482 if (show_version)
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 693f815c9429..81698d5e6503 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,5 +1,5 @@
1#ifndef _TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define _TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include "parse-events.h" 4#include "parse-events.h"
5 5
@@ -26,6 +26,11 @@ enum {
26enum format_flags { 26enum format_flags {
27 FIELD_IS_ARRAY = 1, 27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2, 28 FIELD_IS_POINTER = 2,
29 FIELD_IS_SIGNED = 4,
30 FIELD_IS_STRING = 8,
31 FIELD_IS_DYNAMIC = 16,
32 FIELD_IS_FLAG = 32,
33 FIELD_IS_SYMBOLIC = 64,
29}; 34};
30 35
31struct format_field { 36struct format_field {
@@ -132,15 +137,18 @@ struct event {
132 int flags; 137 int flags;
133 struct format format; 138 struct format format;
134 struct print_fmt print_fmt; 139 struct print_fmt print_fmt;
140 char *system;
135}; 141};
136 142
137enum { 143enum {
138 EVENT_FL_ISFTRACE = 1, 144 EVENT_FL_ISFTRACE = 0x01,
139 EVENT_FL_ISPRINT = 2, 145 EVENT_FL_ISPRINT = 0x02,
140 EVENT_FL_ISBPRINT = 4, 146 EVENT_FL_ISBPRINT = 0x04,
141 EVENT_FL_ISFUNC = 8, 147 EVENT_FL_ISFUNC = 0x08,
142 EVENT_FL_ISFUNCENT = 16, 148 EVENT_FL_ISFUNCENT = 0x10,
143 EVENT_FL_ISFUNCRET = 32, 149 EVENT_FL_ISFUNCRET = 0x20,
150
151 EVENT_FL_FAILED = 0x80000000
144}; 152};
145 153
146struct record { 154struct record {
@@ -154,7 +162,7 @@ struct record *trace_read_data(int cpu);
154 162
155void parse_set_info(int nr_cpus, int long_sz); 163void parse_set_info(int nr_cpus, int long_sz);
156 164
157void trace_report(void); 165void trace_report(int fd);
158 166
159void *malloc_or_die(unsigned int size); 167void *malloc_or_die(unsigned int size);
160 168
@@ -166,7 +174,7 @@ void print_funcs(void);
166void print_printk(void); 174void print_printk(void);
167 175
168int parse_ftrace_file(char *buf, unsigned long size); 176int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system); 177int parse_event_file(char *buf, unsigned long size, char *sys);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs, 178void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm); 179 char *comm);
172 180
@@ -233,13 +241,45 @@ extern int header_page_size_size;
233extern int header_page_data_offset; 241extern int header_page_data_offset;
234extern int header_page_data_size; 242extern int header_page_data_size;
235 243
244extern int latency_format;
245
236int parse_header_page(char *buf, unsigned long size); 246int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data); 247int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data);
250int parse_common_flags(void *data);
251int parse_common_lock_depth(void *data);
238struct event *trace_find_event(int id); 252struct event *trace_find_event(int id);
253struct event *trace_find_next_event(struct event *event);
254unsigned long long read_size(void *ptr, int size);
239unsigned long long 255unsigned long long
240raw_field_value(struct event *event, const char *name, void *data); 256raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data); 257void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag);
259
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
261
262/* taken from kernel/trace/trace.h */
263enum trace_flag_type {
264 TRACE_FLAG_IRQS_OFF = 0x01,
265 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
266 TRACE_FLAG_NEED_RESCHED = 0x04,
267 TRACE_FLAG_HARDIRQ = 0x08,
268 TRACE_FLAG_SOFTIRQ = 0x10,
269};
270
271struct scripting_ops {
272 const char *name;
273 int (*start_script) (const char *);
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);
242 281
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events); 282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void);
244 284
245#endif /* _TRACE_EVENTS_H */ 285#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5e75f9005940..7d6b8331f898 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_TYPES_H 1#ifndef __PERF_TYPES_H
2#define _PERF_TYPES_H 2#define __PERF_TYPES_H
3 3
4/* 4/*
5 * We define u64 as unsigned long long for every architecture 5 * We define u64 as unsigned long long for every architecture
@@ -14,4 +14,4 @@ typedef signed short s16;
14typedef unsigned char u8; 14typedef unsigned char u8;
15typedef signed char s8; 15typedef signed char s8;
16 16
17#endif /* _PERF_TYPES_H */ 17#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/util.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/values.h b/tools/perf/util/values.h
index cadf8cf2a590..2fa967e1a88a 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define _PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -24,4 +24,4 @@ void perf_read_values_add_value(struct perf_read_values *values,
24void perf_read_values_display(FILE *fp, struct perf_read_values *values, 24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw); 25 int raw);
26 26
27#endif /* _PERF_VALUES_H */ 27#endif /* __PERF_VALUES_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 4574ac28396f..bf44ca85d23b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -79,43 +79,12 @@ void *xrealloc(void *ptr, size_t size)
79 return ret; 79 return ret;
80} 80}
81 81
82void *xcalloc(size_t nmemb, size_t size)
83{
84 void *ret = calloc(nmemb, size);
85 if (!ret && (!nmemb || !size))
86 ret = calloc(1, 1);
87 if (!ret) {
88 release_pack_memory(nmemb * size, -1);
89 ret = calloc(nmemb, size);
90 if (!ret && (!nmemb || !size))
91 ret = calloc(1, 1);
92 if (!ret)
93 die("Out of memory, calloc failed");
94 }
95 return ret;
96}
97
98void *xmmap(void *start, size_t length,
99 int prot, int flags, int fd, off_t offset)
100{
101 void *ret = mmap(start, length, prot, flags, fd, offset);
102 if (ret == MAP_FAILED) {
103 if (!length)
104 return NULL;
105 release_pack_memory(length, fd);
106 ret = mmap(start, length, prot, flags, fd, offset);
107 if (ret == MAP_FAILED)
108 die("Out of memory? mmap failed: %s", strerror(errno));
109 }
110 return ret;
111}
112
113/* 82/*
114 * xread() is the same a read(), but it automatically restarts read() 83 * xread() is the same a read(), but it automatically restarts read()
115 * operations with a recoverable error (EAGAIN and EINTR). xread() 84 * operations with a recoverable error (EAGAIN and EINTR). xread()
116 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. 85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
117 */ 86 */
118ssize_t xread(int fd, void *buf, size_t len) 87static ssize_t xread(int fd, void *buf, size_t len)
119{ 88{
120 ssize_t nr; 89 ssize_t nr;
121 while (1) { 90 while (1) {
@@ -131,7 +100,7 @@ ssize_t xread(int fd, void *buf, size_t len)
131 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT 100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
132 * GUARANTEE that "len" bytes is written even if the operation is successful. 101 * GUARANTEE that "len" bytes is written even if the operation is successful.
133 */ 102 */
134ssize_t xwrite(int fd, const void *buf, size_t len) 103static ssize_t xwrite(int fd, const void *buf, size_t len)
135{ 104{
136 ssize_t nr; 105 ssize_t nr;
137 while (1) { 106 while (1) {
@@ -179,29 +148,3 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
179 148
180 return total; 149 return total;
181} 150}
182
183int xdup(int fd)
184{
185 int ret = dup(fd);
186 if (ret < 0)
187 die("dup failed: %s", strerror(errno));
188 return ret;
189}
190
191FILE *xfdopen(int fd, const char *mode)
192{
193 FILE *stream = fdopen(fd, mode);
194 if (stream == NULL)
195 die("Out of memory? fdopen failed: %s", strerror(errno));
196 return stream;
197}
198
199int xmkstemp(char *template)
200{
201 int fd;
202
203 fd = mkstemp(template);
204 if (fd < 0)
205 die("Unable to create temporary file: %s", strerror(errno));
206 return fd;
207}