aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-15 11:49:32 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-12-15 11:49:32 -0500
commit7547a3e8a43d31aaf91c2daf5f597e43212ccddf (patch)
treeadd99b58ac3b490f6ede666b9dbf2333d87e24fa /tools
parent0f5e182dff576e6f3cd9b805834f18d11f2882aa (diff)
parent3ea6b3d0e6d0ffd91c0f8cadeb69b7133c038b32 (diff)
Merge commit 'linus' into next
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/Makefile160
-rw-r--r--tools/perf/bench/bench.h17
-rw-r--r--tools/perf/bench/mem-memcpy.c193
-rw-r--r--tools/perf/bench/sched-messaging.c338
-rw-r--r--tools/perf/bench/sched-pipe.c127
-rw-r--r--tools/perf/builtin-annotate.c890
-rw-r--r--tools/perf/builtin-bench.c245
-rw-r--r--tools/perf/builtin-buildid-list.c77
-rw-r--r--tools/perf/builtin-help.c16
-rw-r--r--tools/perf/builtin-kmem.c803
-rw-r--r--tools/perf/builtin-probe.c290
-rw-r--r--tools/perf/builtin-record.c352
-rw-r--r--tools/perf/builtin-report.c1186
-rw-r--r--tools/perf/builtin-sched.c546
-rw-r--r--tools/perf/builtin-stat.c34
-rw-r--r--tools/perf/builtin-timechart.c324
-rw-r--r--tools/perf/builtin-top.c503
-rw-r--r--tools/perf/builtin-trace.c458
-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.h24
-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.c242
-rw-r--r--tools/perf/util/data_map.h29
-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.c380
-rw-r--r--tools/perf/util/event.h95
-rw-r--r--tools/perf/util/exec_cmd.h6
-rw-r--r--tools/perf/util/header.c406
-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.c120
-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/session.c80
-rw-r--r--tools/perf/util/session.h16
-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.c1356
-rw-r--r--tools/perf/util/symbol.h97
-rw-r--r--tools/perf/util/thread.c259
-rw-r--r--tools/perf/util/thread.h64
-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
126 files changed, 12359 insertions, 4361 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..406999668cab 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -2,6 +2,7 @@
2all:: 2all::
3 3
4# Define V=1 to have a more verbose compile. 4# Define V=1 to have a more verbose compile.
5# Define V=2 to have an even more verbose compile.
5# 6#
6# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() 7# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf()
7# or vsnprintf() return -1 instead of number of characters which would 8# or vsnprintf() return -1 instead of number of characters which would
@@ -145,6 +146,10 @@ all::
145# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call 146# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call
146# your external grep (e.g., if your system lacks grep, if its grep is 147# your external grep (e.g., if your system lacks grep, if its grep is
147# broken, or spawning external process is slower than built-in grep perf has). 148# broken, or spawning external process is slower than built-in grep perf has).
149#
150# Define LDFLAGS=-static to build a static binary.
151#
152# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
148 153
149PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 154PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
150 @$(SHELL_PATH) util/PERF-VERSION-GEN 155 @$(SHELL_PATH) util/PERF-VERSION-GEN
@@ -157,20 +162,6 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
157uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 162uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
158uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 163uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
159 164
160#
161# Add -m32 for cross-builds:
162#
163ifdef NO_64BIT
164 MBITS := -m32
165else
166 #
167 # If we're on a 64-bit kernel, use -m64:
168 #
169 ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
170 MBITS := -m64
171 endif
172endif
173
174# CFLAGS and LDFLAGS are for the users to override from the command line. 165# CFLAGS and LDFLAGS are for the users to override from the command line.
175 166
176# 167#
@@ -200,8 +191,15 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
200EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes 191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
201EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement 192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
202 193
203CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) 194ifeq ("$(origin DEBUG)", "command line")
204LDFLAGS = -lpthread -lrt -lelf -lm 195 PERF_DEBUG = $(DEBUG)
196endif
197ifndef PERF_DEBUG
198 CFLAGS_OPTIMIZE = -O6
199endif
200
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm
205ALL_CFLAGS = $(CFLAGS) 203ALL_CFLAGS = $(CFLAGS)
206ALL_LDFLAGS = $(LDFLAGS) 204ALL_LDFLAGS = $(LDFLAGS)
207STRIP ?= strip 205STRIP ?= strip
@@ -239,8 +237,8 @@ lib = lib
239 237
240export prefix bindir sharedir sysconfdir 238export prefix bindir sharedir sysconfdir
241 239
242CC = gcc 240CC = $(CROSS_COMPILE)gcc
243AR = ar 241AR = $(CROSS_COMPILE)ar
244RM = rm -f 242RM = rm -f
245TAR = tar 243TAR = tar
246FIND = find 244FIND = find
@@ -252,6 +250,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,30 +328,59 @@ 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
335LIB_H += util/parse-events.h 356LIB_H += util/parse-events.h
336LIB_H += util/quote.h 357LIB_H += util/quote.h
337LIB_H += util/util.h 358LIB_H += util/util.h
359LIB_H += util/header.h
338LIB_H += util/help.h 360LIB_H += util/help.h
361LIB_H += util/session.h
339LIB_H += util/strbuf.h 362LIB_H += util/strbuf.h
340LIB_H += util/string.h 363LIB_H += util/string.h
341LIB_H += util/strlist.h 364LIB_H += util/strlist.h
342LIB_H += util/run-command.h 365LIB_H += util/run-command.h
343LIB_H += util/sigchain.h 366LIB_H += util/sigchain.h
344LIB_H += util/symbol.h 367LIB_H += util/symbol.h
345LIB_H += util/module.h
346LIB_H += util/color.h 368LIB_H += util/color.h
347LIB_H += util/values.h 369LIB_H += util/values.h
370LIB_H += util/sort.h
371LIB_H += util/hist.h
372LIB_H += util/thread.h
373LIB_H += util/data_map.h
374LIB_H += util/probe-finder.h
375LIB_H += util/probe-event.h
348 376
349LIB_OBJS += util/abspath.o 377LIB_OBJS += util/abspath.o
350LIB_OBJS += util/alias.o 378LIB_OBJS += util/alias.o
351LIB_OBJS += util/config.o 379LIB_OBJS += util/config.o
352LIB_OBJS += util/ctype.o 380LIB_OBJS += util/ctype.o
381LIB_OBJS += util/debugfs.o
353LIB_OBJS += util/environment.o 382LIB_OBJS += util/environment.o
383LIB_OBJS += util/event.o
354LIB_OBJS += util/exec_cmd.o 384LIB_OBJS += util/exec_cmd.o
355LIB_OBJS += util/help.o 385LIB_OBJS += util/help.o
356LIB_OBJS += util/levenshtein.o 386LIB_OBJS += util/levenshtein.o
@@ -358,6 +388,9 @@ LIB_OBJS += util/parse-options.o
358LIB_OBJS += util/parse-events.o 388LIB_OBJS += util/parse-events.o
359LIB_OBJS += util/path.o 389LIB_OBJS += util/path.o
360LIB_OBJS += util/rbtree.o 390LIB_OBJS += util/rbtree.o
391LIB_OBJS += util/bitmap.o
392LIB_OBJS += util/hweight.o
393LIB_OBJS += util/find_next_bit.o
361LIB_OBJS += util/run-command.o 394LIB_OBJS += util/run-command.o
362LIB_OBJS += util/quote.o 395LIB_OBJS += util/quote.o
363LIB_OBJS += util/strbuf.o 396LIB_OBJS += util/strbuf.o
@@ -367,7 +400,6 @@ LIB_OBJS += util/usage.o
367LIB_OBJS += util/wrapper.o 400LIB_OBJS += util/wrapper.o
368LIB_OBJS += util/sigchain.o 401LIB_OBJS += util/sigchain.o
369LIB_OBJS += util/symbol.o 402LIB_OBJS += util/symbol.o
370LIB_OBJS += util/module.o
371LIB_OBJS += util/color.o 403LIB_OBJS += util/color.o
372LIB_OBJS += util/pager.o 404LIB_OBJS += util/pager.o
373LIB_OBJS += util/header.o 405LIB_OBJS += util/header.o
@@ -375,15 +407,30 @@ LIB_OBJS += util/callchain.o
375LIB_OBJS += util/values.o 407LIB_OBJS += util/values.o
376LIB_OBJS += util/debug.o 408LIB_OBJS += util/debug.o
377LIB_OBJS += util/map.o 409LIB_OBJS += util/map.o
410LIB_OBJS += util/session.o
378LIB_OBJS += util/thread.o 411LIB_OBJS += util/thread.o
379LIB_OBJS += util/trace-event-parse.o 412LIB_OBJS += util/trace-event-parse.o
380LIB_OBJS += util/trace-event-read.o 413LIB_OBJS += util/trace-event-read.o
381LIB_OBJS += util/trace-event-info.o 414LIB_OBJS += util/trace-event-info.o
415LIB_OBJS += util/trace-event-perl.o
382LIB_OBJS += util/svghelper.o 416LIB_OBJS += util/svghelper.o
417LIB_OBJS += util/sort.o
418LIB_OBJS += util/hist.o
419LIB_OBJS += util/data_map.o
420LIB_OBJS += util/probe-event.o
383 421
384BUILTIN_OBJS += builtin-annotate.o 422BUILTIN_OBJS += builtin-annotate.o
423
424BUILTIN_OBJS += builtin-bench.o
425
426# Benchmark modules
427BUILTIN_OBJS += bench/sched-messaging.o
428BUILTIN_OBJS += bench/sched-pipe.o
429BUILTIN_OBJS += bench/mem-memcpy.o
430
385BUILTIN_OBJS += builtin-help.o 431BUILTIN_OBJS += builtin-help.o
386BUILTIN_OBJS += builtin-sched.o 432BUILTIN_OBJS += builtin-sched.o
433BUILTIN_OBJS += builtin-buildid-list.o
387BUILTIN_OBJS += builtin-list.o 434BUILTIN_OBJS += builtin-list.o
388BUILTIN_OBJS += builtin-record.o 435BUILTIN_OBJS += builtin-record.o
389BUILTIN_OBJS += builtin-report.o 436BUILTIN_OBJS += builtin-report.o
@@ -391,9 +438,16 @@ BUILTIN_OBJS += builtin-stat.o
391BUILTIN_OBJS += builtin-timechart.o 438BUILTIN_OBJS += builtin-timechart.o
392BUILTIN_OBJS += builtin-top.o 439BUILTIN_OBJS += builtin-top.o
393BUILTIN_OBJS += builtin-trace.o 440BUILTIN_OBJS += builtin-trace.o
441BUILTIN_OBJS += builtin-probe.o
442BUILTIN_OBJS += builtin-kmem.o
394 443
395PERFLIBS = $(LIB_FILE) 444PERFLIBS = $(LIB_FILE)
396 445
446ifeq ($(V), 2)
447 QUIET_STDERR = ">/dev/null"
448else
449 QUIET_STDERR = ">/dev/null 2>&1"
450endif
397# 451#
398# Platform specific tweaks 452# Platform specific tweaks
399# 453#
@@ -421,36 +475,60 @@ ifeq ($(uname_S),Darwin)
421 PTHREAD_LIBS = 475 PTHREAD_LIBS =
422endif 476endif
423 477
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) 478ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
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) 479ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
480 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
481endif
482
483 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
426 BASIC_CFLAGS += -DLIBELF_NO_MMAP 484 BASIC_CFLAGS += -DLIBELF_NO_MMAP
427 endif 485 endif
428else 486else
429 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 487 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
430endif 488endif
431 489
490ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
491 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231);
492 BASIC_CFLAGS += -DNO_LIBDWARF
493else
494 EXTLIBS += -lelf -ldwarf
495 LIB_OBJS += util/probe-finder.o
496endif
497
498ifndef NO_LIBPERL
499PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
500PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
501endif
502
503ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
504 BASIC_CFLAGS += -DNO_LIBPERL
505else
506 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
507 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
508endif
509
432ifdef NO_DEMANGLE 510ifdef NO_DEMANGLE
433 BASIC_CFLAGS += -DNO_DEMANGLE 511 BASIC_CFLAGS += -DNO_DEMANGLE
434else 512else
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") 513 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
436 514
437 ifeq ($(has_bfd),y) 515 ifeq ($(has_bfd),y)
438 EXTLIBS += -lbfd 516 EXTLIBS += -lbfd
439 else 517 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") 518 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
441 ifeq ($(has_bfd_iberty),y) 519 ifeq ($(has_bfd_iberty),y)
442 EXTLIBS += -lbfd -liberty 520 EXTLIBS += -lbfd -liberty
443 else 521 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") 522 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
445 ifeq ($(has_bfd_iberty_z),y) 523 ifeq ($(has_bfd_iberty_z),y)
446 EXTLIBS += -lbfd -liberty -lz 524 EXTLIBS += -lbfd -liberty -lz
447 else 525 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") 526 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
449 ifeq ($(has_cplus_demangle),y) 527 ifeq ($(has_cplus_demangle),y)
450 EXTLIBS += -liberty 528 EXTLIBS += -liberty
451 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 529 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
452 else 530 else
453 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) 531 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
454 BASIC_CFLAGS += -DNO_DEMANGLE 532 BASIC_CFLAGS += -DNO_DEMANGLE
455 endif 533 endif
456 endif 534 endif
@@ -787,6 +865,25 @@ util/config.o: util/config.c PERF-CFLAGS
787util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 865util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
788 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 866 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
789 867
868# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
869# from <string.h> that comes from kernel headers wrapping.
870KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
871
872util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
873 $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
874
875util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
876 $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
877
878util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
879 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
880
881util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS
882 $(QUIET_CC)$(CC) -o util/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
883
884scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
885 $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
886
790perf-%$X: %.o $(PERFLIBS) 887perf-%$X: %.o $(PERFLIBS)
791 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 888 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
792 889
@@ -894,6 +991,13 @@ export perfexec_instdir
894install: all 991install: all
895 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 992 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
896 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 993 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
994 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
995 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
996 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
997 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
998 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
999 $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
1000 $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
897ifdef BUILT_INS 1001ifdef BUILT_INS
898 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1002 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
899 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1003 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -979,7 +1083,7 @@ distclean: clean
979# $(RM) configure 1083# $(RM) configure
980 1084
981clean: 1085clean:
982 $(RM) *.o */*.o $(LIB_FILE) 1086 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
983 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1087 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
984 $(RM) $(TEST_PROGRAMS) 1088 $(RM) $(TEST_PROGRAMS)
985 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1089 $(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..81cee78181fa
--- /dev/null
+++ b/tools/perf/bench/sched-messaging.c
@@ -0,0 +1,338 @@
1/*
2 *
3 * sched-messaging.c
4 *
5 * messaging: Benchmark for scheduler and IPC mechanisms
6 *
7 * Based on hackbench by Rusty Russell <rusty@rustcorp.com.au>
8 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
9 *
10 */
11
12#include "../perf.h"
13#include "../util/util.h"
14#include "../util/parse-options.h"
15#include "../builtin.h"
16#include "bench.h"
17
18/* Test groups of 20 processes spraying to 20 receivers */
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#include <sys/time.h>
29#include <sys/poll.h>
30#include <limits.h>
31
32#define DATASIZE 100
33
34static int use_pipes = 0;
35static unsigned int loops = 100;
36static unsigned int thread_mode = 0;
37static unsigned int num_groups = 10;
38
39struct sender_context {
40 unsigned int num_fds;
41 int ready_out;
42 int wakefd;
43 int out_fds[0];
44};
45
46struct receiver_context {
47 unsigned int num_packets;
48 int in_fds[2];
49 int ready_out;
50 int wakefd;
51};
52
53static void barf(const char *msg)
54{
55 fprintf(stderr, "%s (error: %s)\n", msg, strerror(errno));
56 exit(1);
57}
58
59static void fdpair(int fds[2])
60{
61 if (use_pipes) {
62 if (pipe(fds) == 0)
63 return;
64 } else {
65 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0)
66 return;
67 }
68
69 barf(use_pipes ? "pipe()" : "socketpair()");
70}
71
72/* Block until we're ready to go */
73static void ready(int ready_out, int wakefd)
74{
75 char dummy;
76 struct pollfd pollfd = { .fd = wakefd, .events = POLLIN };
77
78 /* Tell them we're ready. */
79 if (write(ready_out, &dummy, 1) != 1)
80 barf("CLIENT: ready write");
81
82 /* Wait for "GO" signal */
83 if (poll(&pollfd, 1, -1) != 1)
84 barf("poll");
85}
86
87/* Sender sprays loops messages down each file descriptor */
88static void *sender(struct sender_context *ctx)
89{
90 char data[DATASIZE];
91 unsigned int i, j;
92
93 ready(ctx->ready_out, ctx->wakefd);
94
95 /* Now pump to every receiver. */
96 for (i = 0; i < loops; i++) {
97 for (j = 0; j < ctx->num_fds; j++) {
98 int ret, done = 0;
99
100again:
101 ret = write(ctx->out_fds[j], data + done,
102 sizeof(data)-done);
103 if (ret < 0)
104 barf("SENDER: write");
105 done += ret;
106 if (done < DATASIZE)
107 goto again;
108 }
109 }
110
111 return NULL;
112}
113
114
115/* One receiver per fd */
116static void *receiver(struct receiver_context* ctx)
117{
118 unsigned int i;
119
120 if (!thread_mode)
121 close(ctx->in_fds[1]);
122
123 /* Wait for start... */
124 ready(ctx->ready_out, ctx->wakefd);
125
126 /* Receive them all */
127 for (i = 0; i < ctx->num_packets; i++) {
128 char data[DATASIZE];
129 int ret, done = 0;
130
131again:
132 ret = read(ctx->in_fds[0], data + done, DATASIZE - done);
133 if (ret < 0)
134 barf("SERVER: read");
135 done += ret;
136 if (done < DATASIZE)
137 goto again;
138 }
139
140 return NULL;
141}
142
143static pthread_t create_worker(void *ctx, void *(*func)(void *))
144{
145 pthread_attr_t attr;
146 pthread_t childid;
147 int err;
148
149 if (!thread_mode) {
150 /* process mode */
151 /* Fork the receiver. */
152 switch (fork()) {
153 case -1:
154 barf("fork()");
155 break;
156 case 0:
157 (*func) (ctx);
158 exit(0);
159 break;
160 default:
161 break;
162 }
163
164 return (pthread_t)0;
165 }
166
167 if (pthread_attr_init(&attr) != 0)
168 barf("pthread_attr_init:");
169
170#ifndef __ia64__
171 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0)
172 barf("pthread_attr_setstacksize");
173#endif
174
175 err = pthread_create(&childid, &attr, func, ctx);
176 if (err != 0) {
177 fprintf(stderr, "pthread_create failed: %s (%d)\n",
178 strerror(err), err);
179 exit(-1);
180 }
181 return childid;
182}
183
184static void reap_worker(pthread_t id)
185{
186 int proc_status;
187 void *thread_status;
188
189 if (!thread_mode) {
190 /* process mode */
191 wait(&proc_status);
192 if (!WIFEXITED(proc_status))
193 exit(1);
194 } else {
195 pthread_join(id, &thread_status);
196 }
197}
198
199/* One group of senders and receivers */
200static unsigned int group(pthread_t *pth,
201 unsigned int num_fds,
202 int ready_out,
203 int wakefd)
204{
205 unsigned int i;
206 struct sender_context *snd_ctx = malloc(sizeof(struct sender_context)
207 + num_fds * sizeof(int));
208
209 if (!snd_ctx)
210 barf("malloc()");
211
212 for (i = 0; i < num_fds; i++) {
213 int fds[2];
214 struct receiver_context *ctx = malloc(sizeof(*ctx));
215
216 if (!ctx)
217 barf("malloc()");
218
219
220 /* Create the pipe between client and server */
221 fdpair(fds);
222
223 ctx->num_packets = num_fds * loops;
224 ctx->in_fds[0] = fds[0];
225 ctx->in_fds[1] = fds[1];
226 ctx->ready_out = ready_out;
227 ctx->wakefd = wakefd;
228
229 pth[i] = create_worker(ctx, (void *)receiver);
230
231 snd_ctx->out_fds[i] = fds[1];
232 if (!thread_mode)
233 close(fds[0]);
234 }
235
236 /* Now we have all the fds, fork the senders */
237 for (i = 0; i < num_fds; i++) {
238 snd_ctx->ready_out = ready_out;
239 snd_ctx->wakefd = wakefd;
240 snd_ctx->num_fds = num_fds;
241
242 pth[num_fds+i] = create_worker(snd_ctx, (void *)sender);
243 }
244
245 /* Close the fds we have left */
246 if (!thread_mode)
247 for (i = 0; i < num_fds; i++)
248 close(snd_ctx->out_fds[i]);
249
250 /* Return number of children to reap */
251 return num_fds * 2;
252}
253
254static const struct option options[] = {
255 OPT_BOOLEAN('p', "pipe", &use_pipes,
256 "Use pipe() instead of socketpair()"),
257 OPT_BOOLEAN('t', "thread", &thread_mode,
258 "Be multi thread instead of multi process"),
259 OPT_INTEGER('g', "group", &num_groups,
260 "Specify number of groups"),
261 OPT_INTEGER('l', "loop", &loops,
262 "Specify number of loops"),
263 OPT_END()
264};
265
266static const char * const bench_sched_message_usage[] = {
267 "perf bench sched messaging <options>",
268 NULL
269};
270
271int bench_sched_messaging(int argc, const char **argv,
272 const char *prefix __used)
273{
274 unsigned int i, total_children;
275 struct timeval start, stop, diff;
276 unsigned int num_fds = 20;
277 int readyfds[2], wakefds[2];
278 char dummy;
279 pthread_t *pth_tab;
280
281 argc = parse_options(argc, argv, options,
282 bench_sched_message_usage, 0);
283
284 pth_tab = malloc(num_fds * 2 * num_groups * sizeof(pthread_t));
285 if (!pth_tab)
286 barf("main:malloc()");
287
288 fdpair(readyfds);
289 fdpair(wakefds);
290
291 total_children = 0;
292 for (i = 0; i < num_groups; i++)
293 total_children += group(pth_tab+total_children, num_fds,
294 readyfds[1], wakefds[0]);
295
296 /* Wait for everyone to be ready */
297 for (i = 0; i < total_children; i++)
298 if (read(readyfds[0], &dummy, 1) != 1)
299 barf("Reading for readyfds");
300
301 gettimeofday(&start, NULL);
302
303 /* Kick them off */
304 if (write(wakefds[1], &dummy, 1) != 1)
305 barf("Writing to start them");
306
307 /* Reap them all */
308 for (i = 0; i < total_children; i++)
309 reap_worker(pth_tab[i]);
310
311 gettimeofday(&stop, NULL);
312
313 timersub(&stop, &start, &diff);
314
315 switch (bench_format) {
316 case BENCH_FORMAT_DEFAULT:
317 printf("# %d sender and receiver %s per group\n",
318 num_fds, thread_mode ? "threads" : "processes");
319 printf("# %d groups == %d %s run\n\n",
320 num_groups, num_groups * 2 * num_fds,
321 thread_mode ? "threads" : "processes");
322 printf(" %14s: %lu.%03lu [sec]\n", "Total time",
323 diff.tv_sec,
324 (unsigned long) (diff.tv_usec/1000));
325 break;
326 case BENCH_FORMAT_SIMPLE:
327 printf("%lu.%03lu\n", diff.tv_sec,
328 (unsigned long) (diff.tv_usec/1000));
329 break;
330 default:
331 /* reaching here is something disaster */
332 fprintf(stderr, "Unknown format:%d\n", bench_format);
333 exit(1);
334 break;
335 }
336
337 return 0;
338}
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
new file mode 100644
index 000000000000..4f77c7c27640
--- /dev/null
+++ b/tools/perf/bench/sched-pipe.c
@@ -0,0 +1,127 @@
1/*
2 *
3 * sched-pipe.c
4 *
5 * pipe: Benchmark for pipe()
6 *
7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
10 *
11 */
12
13#include "../perf.h"
14#include "../util/util.h"
15#include "../util/parse-options.h"
16#include "../builtin.h"
17#include "bench.h"
18
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <signal.h>
23#include <sys/wait.h>
24#include <linux/unistd.h>
25#include <string.h>
26#include <errno.h>
27#include <assert.h>
28#include <sys/time.h>
29#include <sys/types.h>
30
31#define LOOPS_DEFAULT 1000000
32static int loops = LOOPS_DEFAULT;
33
34static const struct option options[] = {
35 OPT_INTEGER('l', "loop", &loops,
36 "Specify number of loops"),
37 OPT_END()
38};
39
40static const char * const bench_sched_pipe_usage[] = {
41 "perf bench sched pipe <options>",
42 NULL
43};
44
45int bench_sched_pipe(int argc, const char **argv,
46 const char *prefix __used)
47{
48 int pipe_1[2], pipe_2[2];
49 int m = 0, i;
50 struct timeval start, stop, diff;
51 unsigned long long result_usec = 0;
52
53 /*
54 * why does "ret" exist?
55 * discarding returned value of read(), write()
56 * causes error in building environment for perf
57 */
58 int ret, wait_stat;
59 pid_t pid, retpid;
60
61 argc = parse_options(argc, argv, options,
62 bench_sched_pipe_usage, 0);
63
64 assert(!pipe(pipe_1));
65 assert(!pipe(pipe_2));
66
67 pid = fork();
68 assert(pid >= 0);
69
70 gettimeofday(&start, NULL);
71
72 if (!pid) {
73 for (i = 0; i < loops; i++) {
74 ret = read(pipe_1[0], &m, sizeof(int));
75 ret = write(pipe_2[1], &m, sizeof(int));
76 }
77 } else {
78 for (i = 0; i < loops; i++) {
79 ret = write(pipe_1[1], &m, sizeof(int));
80 ret = read(pipe_2[0], &m, sizeof(int));
81 }
82 }
83
84 gettimeofday(&stop, NULL);
85 timersub(&stop, &start, &diff);
86
87 if (pid) {
88 retpid = waitpid(pid, &wait_stat, 0);
89 assert((retpid == pid) && WIFEXITED(wait_stat));
90 } else {
91 exit(0);
92 }
93
94 switch (bench_format) {
95 case BENCH_FORMAT_DEFAULT:
96 printf("# Extecuted %d pipe operations between two tasks\n\n",
97 loops);
98
99 result_usec = diff.tv_sec * 1000000;
100 result_usec += diff.tv_usec;
101
102 printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
103 diff.tv_sec,
104 (unsigned long) (diff.tv_usec/1000));
105
106 printf(" %14lf usecs/op\n",
107 (double)result_usec / (double)loops);
108 printf(" %14d ops/sec\n",
109 (int)((double)loops /
110 ((double)result_usec / (double)1000000)));
111 break;
112
113 case BENCH_FORMAT_SIMPLE:
114 printf("%lu.%03lu\n",
115 diff.tv_sec,
116 (unsigned long) (diff.tv_usec / 1000));
117 break;
118
119 default:
120 /* reaching here is something disaster */
121 fprintf(stderr, "Unknown format:%d\n", bench_format);
122 exit(1);
123 break;
124 }
125
126 return 0;
127}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 1ec741615814..21a78d30d53d 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,29 +19,27 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/event.h"
22#include "util/parse-options.h" 23#include "util/parse-options.h"
23#include "util/parse-events.h" 24#include "util/parse-events.h"
24#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h"
27#include "util/hist.h"
28#include "util/session.h"
29#include "util/data_map.h"
25 30
26static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
27 32
28static char default_sort_order[] = "comm,symbol";
29static char *sort_order = default_sort_order;
30
31static int force; 33static int force;
32static int input;
33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
34 34
35static int full_paths; 35static int full_paths;
36 36
37static int print_line; 37static int print_line;
38 38
39static unsigned long page_size; 39struct sym_hist {
40static unsigned long mmap_window = 32; 40 u64 sum;
41 41 u64 ip[0];
42static struct rb_root threads; 42};
43static struct thread *last_match;
44
45 43
46struct sym_ext { 44struct sym_ext {
47 struct rb_node node; 45 struct rb_node node;
@@ -49,247 +47,38 @@ struct sym_ext {
49 char *path; 47 char *path;
50}; 48};
51 49
52/* 50struct sym_priv {
53 * histogram, sorted on item, collects counts 51 struct sym_hist *hist;
54 */ 52 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}; 53};
70 54
71/* 55static struct symbol_conf symbol_conf = {
72 * configurable sorting bits 56 .priv_size = sizeof(struct sym_priv),
73 */ 57 .try_vmlinux_path = true,
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}; 58};
104 59
105/* --sort comm */ 60static const char *sym_hist_filter;
106 61
107static int64_t 62static int symbol_filter(struct map *map __used, struct symbol *sym)
108sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
109{ 63{
110 return right->thread->pid - left->thread->pid; 64 if (sym_hist_filter == NULL ||
111} 65 strcmp(sym->name, sym_hist_filter) == 0) {
112 66 struct sym_priv *priv = symbol__priv(sym);
113static int64_t 67 const int size = (sizeof(*priv->hist) +
114sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 68 (sym->end - sym->start) * sizeof(u64));
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 69
128 return strcmp(comm_l, comm_r); 70 priv->hist = malloc(size);
129} 71 if (priv->hist)
130 72 memset(priv->hist, 0, size);
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; 73 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 } 74 }
209 75 /*
210 return ret; 76 * FIXME: We should really filter it out, as we don't want to go thru symbols
211} 77 * we're not interested, and if a DSO ends up with no symbols, delete it too,
212 78 * but right now the kernel loading routines in symbol.c bail out if no symbols
213static struct sort_entry sort_sym = { 79 * are found, fix it later.
214 .header = "Symbol", 80 */
215 .cmp = sort__sym_cmp, 81 return 0;
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};
226
227static struct sort_dimension sort_dimensions[] = {
228 { .name = "pid", .entry = &sort_thread, },
229 { .name = "comm", .entry = &sort_comm, },
230 { .name = "dso", .entry = &sort_dso, },
231 { .name = "symbol", .entry = &sort_sym, },
232};
233
234static LIST_HEAD(hist_entry__sort_list);
235
236static int sort_dimension__add(char *tok)
237{
238 unsigned int i;
239
240 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
241 struct sort_dimension *sd = &sort_dimensions[i];
242
243 if (sd->taken)
244 continue;
245
246 if (strncasecmp(tok, sd->name, strlen(tok)))
247 continue;
248
249 if (sd->entry->collapse)
250 sort__need_collapse = 1;
251
252 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
253 sd->taken = 1;
254
255 return 0;
256 }
257
258 return -ESRCH;
259}
260
261static int64_t
262hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
263{
264 struct sort_entry *se;
265 int64_t cmp = 0;
266
267 list_for_each_entry(se, &hist_entry__sort_list, list) {
268 cmp = se->cmp(left, right);
269 if (cmp)
270 break;
271 }
272
273 return cmp;
274}
275
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} 82}
294 83
295/* 84/*
@@ -299,380 +88,81 @@ static void hist_hit(struct hist_entry *he, u64 ip)
299{ 88{
300 unsigned int sym_size, offset; 89 unsigned int sym_size, offset;
301 struct symbol *sym = he->sym; 90 struct symbol *sym = he->sym;
91 struct sym_priv *priv;
92 struct sym_hist *h;
302 93
303 he->count++; 94 he->count++;
304 95
305 if (!sym || !sym->hist) 96 if (!sym || !he->map)
97 return;
98
99 priv = symbol__priv(sym);
100 if (!priv->hist)
306 return; 101 return;
307 102
308 sym_size = sym->end - sym->start; 103 sym_size = sym->end - sym->start;
309 offset = ip - sym->start; 104 offset = ip - sym->start;
310 105
106 if (verbose)
107 fprintf(stderr, "%s: ip=%Lx\n", __func__,
108 he->map->unmap_ip(he->map, ip));
109
311 if (offset >= sym_size) 110 if (offset >= sym_size)
312 return; 111 return;
313 112
314 sym->hist_sum++; 113 h = priv->hist;
315 sym->hist[offset]++; 114 h->sum++;
115 h->ip[offset]++;
316 116
317 if (verbose >= 3) 117 if (verbose >= 3)
318 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 118 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
319 (void *)(unsigned long)he->sym->start, 119 (void *)(unsigned long)he->sym->start,
320 he->sym->name, 120 he->sym->name,
321 (void *)(unsigned long)ip, ip - he->sym->start, 121 (void *)(unsigned long)ip, ip - he->sym->start,
322 sym->hist[offset]); 122 h->ip[offset]);
323} 123}
324 124
325static int 125static 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{ 126{
329 struct rb_node **p = &hist.rb_node; 127 bool hit;
330 struct rb_node *parent = NULL; 128 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit);
331 struct hist_entry *he; 129 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; 130 return -ENOMEM;
364 *he = entry; 131 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; 132 return 0;
369} 133}
370 134
371static void hist_entry__free(struct hist_entry *he) 135static int process_sample_event(event_t *event)
372{ 136{
373 free(he); 137 struct addr_location al;
374}
375
376/*
377 * collapse the histogram
378 */
379 138
380static struct rb_root collapse_hists; 139 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
140 event->ip.pid, (void *)(long)event->ip.ip);
381 141
382static void collapse__insert_entry(struct hist_entry *he) 142 if (event__preprocess_sample(event, &al, symbol_filter) < 0) {
383{
384 struct rb_node **p = &collapse_hists.rb_node;
385 struct rb_node *parent = NULL;
386 struct hist_entry *iter;
387 int64_t cmp;
388
389 while (*p != NULL) {
390 parent = *p;
391 iter = rb_entry(parent, struct hist_entry, rb_node);
392
393 cmp = hist_entry__collapse(iter, he);
394
395 if (!cmp) {
396 iter->count += he->count;
397 hist_entry__free(he);
398 return;
399 }
400
401 if (cmp < 0)
402 p = &(*p)->rb_left;
403 else
404 p = &(*p)->rb_right;
405 }
406
407 rb_link_node(&he->rb_node, parent, p);
408 rb_insert_color(&he->rb_node, &collapse_hists);
409}
410
411static void collapse__resort(void)
412{
413 struct rb_node *next;
414 struct hist_entry *n;
415
416 if (!sort__need_collapse)
417 return;
418
419 next = rb_first(&hist);
420 while (next) {
421 n = rb_entry(next, struct hist_entry, rb_node);
422 next = rb_next(&n->rb_node);
423
424 rb_erase(&n->rb_node, &hist);
425 collapse__insert_entry(n);
426 }
427}
428
429/*
430 * reverse the map, sort on count.
431 */
432
433static struct rb_root output_hists;
434
435static void output__insert_entry(struct hist_entry *he)
436{
437 struct rb_node **p = &output_hists.rb_node;
438 struct rb_node *parent = NULL;
439 struct hist_entry *iter;
440
441 while (*p != NULL) {
442 parent = *p;
443 iter = rb_entry(parent, struct hist_entry, rb_node);
444
445 if (he->count > iter->count)
446 p = &(*p)->rb_left;
447 else
448 p = &(*p)->rb_right;
449 }
450
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", 143 fprintf(stderr, "problem processing %d event, skipping it.\n",
504 event->header.type); 144 event->header.type);
505 return -1; 145 return -1;
506 } 146 }
507 147
508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 148 if (hist_entry__add(&al, 1)) {
509 show = SHOW_KERNEL; 149 fprintf(stderr, "problem incrementing symbol count, "
510 level = 'k'; 150 "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; 151 return -1;
663 } 152 }
664 153
665 return 0; 154 return 0;
666} 155}
667 156
668static int 157static int parse_line(FILE *file, struct hist_entry *he, u64 len)
669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
670{ 158{
159 struct symbol *sym = he->sym;
671 char *line = NULL, *tmp, *tmp2; 160 char *line = NULL, *tmp, *tmp2;
672 static const char *prev_line; 161 static const char *prev_line;
673 static const char *prev_color; 162 static const char *prev_color;
674 unsigned int offset; 163 unsigned int offset;
675 size_t line_len; 164 size_t line_len;
165 u64 start;
676 s64 line_ip; 166 s64 line_ip;
677 int ret; 167 int ret;
678 char *c; 168 char *c;
@@ -709,22 +199,26 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
709 line_ip = -1; 199 line_ip = -1;
710 } 200 }
711 201
202 start = he->map->unmap_ip(he->map, sym->start);
203
712 if (line_ip != -1) { 204 if (line_ip != -1) {
713 const char *path = NULL; 205 const char *path = NULL;
714 unsigned int hits = 0; 206 unsigned int hits = 0;
715 double percent = 0.0; 207 double percent = 0.0;
716 const char *color; 208 const char *color;
717 struct sym_ext *sym_ext = sym->priv; 209 struct sym_priv *priv = symbol__priv(sym);
210 struct sym_ext *sym_ext = priv->ext;
211 struct sym_hist *h = priv->hist;
718 212
719 offset = line_ip - start; 213 offset = line_ip - start;
720 if (offset < len) 214 if (offset < len)
721 hits = sym->hist[offset]; 215 hits = h->ip[offset];
722 216
723 if (offset < len && sym_ext) { 217 if (offset < len && sym_ext) {
724 path = sym_ext[offset].path; 218 path = sym_ext[offset].path;
725 percent = sym_ext[offset].percent; 219 percent = sym_ext[offset].percent;
726 } else if (sym->hist_sum) 220 } else if (h->sum)
727 percent = 100.0 * hits / sym->hist_sum; 221 percent = 100.0 * hits / h->sum;
728 222
729 color = get_percent_color(percent); 223 color = get_percent_color(percent);
730 224
@@ -777,9 +271,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
777 rb_insert_color(&sym_ext->node, &root_sym_ext); 271 rb_insert_color(&sym_ext->node, &root_sym_ext);
778} 272}
779 273
780static void free_source_line(struct symbol *sym, int len) 274static void free_source_line(struct hist_entry *he, int len)
781{ 275{
782 struct sym_ext *sym_ext = sym->priv; 276 struct sym_priv *priv = symbol__priv(he->sym);
277 struct sym_ext *sym_ext = priv->ext;
783 int i; 278 int i;
784 279
785 if (!sym_ext) 280 if (!sym_ext)
@@ -789,26 +284,30 @@ static void free_source_line(struct symbol *sym, int len)
789 free(sym_ext[i].path); 284 free(sym_ext[i].path);
790 free(sym_ext); 285 free(sym_ext);
791 286
792 sym->priv = NULL; 287 priv->ext = NULL;
793 root_sym_ext = RB_ROOT; 288 root_sym_ext = RB_ROOT;
794} 289}
795 290
796/* Get the filename:line for the colored entries */ 291/* Get the filename:line for the colored entries */
797static void 292static void
798get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 293get_source_line(struct hist_entry *he, int len, const char *filename)
799{ 294{
295 struct symbol *sym = he->sym;
296 u64 start;
800 int i; 297 int i;
801 char cmd[PATH_MAX * 2]; 298 char cmd[PATH_MAX * 2];
802 struct sym_ext *sym_ext; 299 struct sym_ext *sym_ext;
300 struct sym_priv *priv = symbol__priv(sym);
301 struct sym_hist *h = priv->hist;
803 302
804 if (!sym->hist_sum) 303 if (!h->sum)
805 return; 304 return;
806 305
807 sym->priv = calloc(len, sizeof(struct sym_ext)); 306 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
808 if (!sym->priv) 307 if (!priv->ext)
809 return; 308 return;
810 309
811 sym_ext = sym->priv; 310 start = he->map->unmap_ip(he->map, sym->start);
812 311
813 for (i = 0; i < len; i++) { 312 for (i = 0; i < len; i++) {
814 char *path = NULL; 313 char *path = NULL;
@@ -816,7 +315,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
816 u64 offset; 315 u64 offset;
817 FILE *fp; 316 FILE *fp;
818 317
819 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 318 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
820 if (sym_ext[i].percent <= 0.5) 319 if (sym_ext[i].percent <= 0.5)
821 continue; 320 continue;
822 321
@@ -870,33 +369,34 @@ static void print_summary(const char *filename)
870 } 369 }
871} 370}
872 371
873static void annotate_sym(struct dso *dso, struct symbol *sym) 372static void annotate_sym(struct hist_entry *he)
874{ 373{
875 const char *filename = dso->name, *d_filename; 374 struct map *map = he->map;
876 u64 start, end, len; 375 struct dso *dso = map->dso;
376 struct symbol *sym = he->sym;
377 const char *filename = dso->long_name, *d_filename;
378 u64 len;
877 char command[PATH_MAX*2]; 379 char command[PATH_MAX*2];
878 FILE *file; 380 FILE *file;
879 381
880 if (!filename) 382 if (!filename)
881 return; 383 return;
882 if (sym->module) 384
883 filename = sym->module->path; 385 if (verbose)
884 else if (dso == kernel_dso) 386 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
885 filename = vmlinux_name; 387 __func__, filename, sym->name,
886 388 map->unmap_ip(map, sym->start),
887 start = sym->obj_start; 389 map->unmap_ip(map, sym->end));
888 if (!start) 390
889 start = sym->start;
890 if (full_paths) 391 if (full_paths)
891 d_filename = filename; 392 d_filename = filename;
892 else 393 else
893 d_filename = basename(filename); 394 d_filename = basename(filename);
894 395
895 end = start + sym->end - sym->start + 1;
896 len = sym->end - sym->start; 396 len = sym->end - sym->start;
897 397
898 if (print_line) { 398 if (print_line) {
899 get_source_line(sym, start, len, filename); 399 get_source_line(he, len, filename);
900 print_summary(filename); 400 print_summary(filename);
901 } 401 }
902 402
@@ -905,10 +405,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
905 printf("------------------------------------------------\n"); 405 printf("------------------------------------------------\n");
906 406
907 if (verbose >= 2) 407 if (verbose >= 2)
908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 408 printf("annotating [%p] %30s : [%p] %30s\n",
409 dso, dso->long_name, sym, sym->name);
909 410
910 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 411 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
911 (u64)start, (u64)end, filename, filename); 412 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
413 filename, filename);
912 414
913 if (verbose >= 3) 415 if (verbose >= 3)
914 printf("doing: %s\n", command); 416 printf("doing: %s\n", command);
@@ -918,159 +420,82 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
918 return; 420 return;
919 421
920 while (!feof(file)) { 422 while (!feof(file)) {
921 if (parse_line(file, sym, start, len) < 0) 423 if (parse_line(file, he, len) < 0)
922 break; 424 break;
923 } 425 }
924 426
925 pclose(file); 427 pclose(file);
926 if (print_line) 428 if (print_line)
927 free_source_line(sym, len); 429 free_source_line(he, len);
928} 430}
929 431
930static void find_annotations(void) 432static void find_annotations(void)
931{ 433{
932 struct rb_node *nd; 434 struct rb_node *nd;
933 struct dso *dso;
934 int count = 0;
935 435
936 list_for_each_entry(dso, &dsos, node) { 436 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
437 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
438 struct sym_priv *priv;
937 439
938 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) { 440 if (he->sym == NULL)
939 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 441 continue;
940 442
941 if (sym->hist) { 443 priv = symbol__priv(he->sym);
942 annotate_sym(dso, sym); 444 if (priv->hist == NULL)
943 count++; 445 continue;
944 }
945 }
946 }
947 446
948 if (!count) 447 annotate_sym(he);
949 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter); 448 /*
449 * Since we have a hist_entry per IP for the same symbol, free
450 * he->sym->hist to signal we already processed this symbol.
451 */
452 free(priv->hist);
453 priv->hist = NULL;
454 }
950} 455}
951 456
457static struct perf_file_handler file_handler = {
458 .process_sample_event = process_sample_event,
459 .process_mmap_event = event__process_mmap,
460 .process_comm_event = event__process_comm,
461 .process_fork_event = event__process_task,
462};
463
952static int __cmd_annotate(void) 464static int __cmd_annotate(void)
953{ 465{
954 int ret, rc = EXIT_FAILURE; 466 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
955 unsigned long offset = 0; 467 struct thread *idle;
956 unsigned long head = 0; 468 int ret;
957 struct stat input_stat;
958 event_t *event;
959 uint32_t size;
960 char *buf;
961
962 register_idle_thread(&threads, &last_match);
963
964 input = open(input_name, O_RDONLY);
965 if (input < 0) {
966 perror("failed to open file");
967 exit(-1);
968 }
969
970 ret = fstat(input, &input_stat);
971 if (ret < 0) {
972 perror("failed to stat file");
973 exit(-1);
974 }
975
976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
978 exit(-1);
979 }
980
981 if (!input_stat.st_size) {
982 fprintf(stderr, "zero-sized file, nothing to do!\n");
983 exit(0);
984 }
985
986 if (load_kernel() < 0) {
987 perror("failed to load kernel symbols");
988 return EXIT_FAILURE;
989 }
990
991remap:
992 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
993 MAP_SHARED, input, offset);
994 if (buf == MAP_FAILED) {
995 perror("failed to mmap file");
996 exit(-1);
997 }
998
999more:
1000 event = (event_t *)(buf + head);
1001
1002 size = event->header.size;
1003 if (!size)
1004 size = 8;
1005
1006 if (head + event->header.size >= page_size * mmap_window) {
1007 unsigned long shift = page_size * (head / page_size);
1008 int munmap_ret;
1009
1010 munmap_ret = munmap(buf, page_size * mmap_window);
1011 assert(munmap_ret == 0);
1012
1013 offset += shift;
1014 head -= shift;
1015 goto remap;
1016 }
1017
1018 size = event->header.size;
1019
1020 dump_printf("%p [%p]: event: %d\n",
1021 (void *)(offset + head),
1022 (void *)(long)event->header.size,
1023 event->header.type);
1024
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 469
1032 total_unknown++; 470 if (session == NULL)
471 return -ENOMEM;
1033 472
1034 /* 473 idle = register_idle_thread();
1035 * assume we lost track of the stream, check alignment, and 474 register_perf_file_handler(&file_handler);
1036 * increment a single u64 in the hope to catch on again 'soon'.
1037 */
1038 475
1039 if (unlikely(head & 7)) 476 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1040 head &= ~7ULL; 477 if (ret)
478 goto out_delete;
1041 479
1042 size = 8; 480 if (dump_trace) {
481 event__print_totals();
482 goto out_delete;
1043 } 483 }
1044 484
1045 head += size; 485 if (verbose > 3)
1046 486 threads__fprintf(stdout);
1047 if (offset + head < (unsigned long)input_stat.st_size)
1048 goto more;
1049
1050 rc = EXIT_SUCCESS;
1051 close(input);
1052
1053 dump_printf(" IP events: %10ld\n", total);
1054 dump_printf(" mmap events: %10ld\n", total_mmap);
1055 dump_printf(" comm events: %10ld\n", total_comm);
1056 dump_printf(" fork events: %10ld\n", total_fork);
1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1058
1059 if (dump_trace)
1060 return 0;
1061
1062 if (verbose >= 3)
1063 threads__fprintf(stdout, &threads);
1064 487
1065 if (verbose >= 2) 488 if (verbose > 2)
1066 dsos__fprintf(stdout); 489 dsos__fprintf(stdout);
1067 490
1068 collapse__resort(); 491 collapse__resort();
1069 output__resort(); 492 output__resort(event__total[0]);
1070 493
1071 find_annotations(); 494 find_annotations();
495out_delete:
496 perf_session__delete(session);
1072 497
1073 return rc; 498 return ret;
1074} 499}
1075 500
1076static const char * const annotate_usage[] = { 501static const char * const annotate_usage[] = {
@@ -1088,8 +513,9 @@ static const struct option options[] = {
1088 "be more verbose (show symbol address, etc)"), 513 "be more verbose (show symbol address, etc)"),
1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 514 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1090 "dump raw trace in ASCII"), 515 "dump raw trace in ASCII"),
1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 516 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1092 OPT_BOOLEAN('m', "modules", &modules, 517 "file", "vmlinux pathname"),
518 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1093 "load module symbols - WARNING: use only with -k and LIVE kernel"), 519 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1094 OPT_BOOLEAN('l', "print-line", &print_line, 520 OPT_BOOLEAN('l', "print-line", &print_line,
1095 "print matching source lines (may be slow)"), 521 "print matching source lines (may be slow)"),
@@ -1115,9 +541,8 @@ static void setup_sorting(void)
1115 541
1116int cmd_annotate(int argc, const char **argv, const char *prefix __used) 542int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1117{ 543{
1118 symbol__init(); 544 if (symbol__init(&symbol_conf) < 0)
1119 545 return -1;
1120 page_size = getpagesize();
1121 546
1122 argc = parse_options(argc, argv, options, annotate_usage, 0); 547 argc = parse_options(argc, argv, options, annotate_usage, 0);
1123 548
@@ -1134,10 +559,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1134 sym_hist_filter = argv[0]; 559 sym_hist_filter = argv[0];
1135 } 560 }
1136 561
1137 if (!sym_hist_filter)
1138 usage_with_options(annotate_usage, options);
1139
1140 setup_pager(); 562 setup_pager();
1141 563
564 if (field_sep && *field_sep == '.') {
565 fputs("'.' is the only non valid --field-separator argument\n",
566 stderr);
567 exit(129);
568 }
569
1142 return __cmd_annotate(); 570 return __cmd_annotate();
1143} 571}
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
new file mode 100644
index 000000000000..46996774e559
--- /dev/null
+++ b/tools/perf/builtin-bench.c
@@ -0,0 +1,245 @@
1/*
2 *
3 * builtin-bench.c
4 *
5 * General benchmarking subsystem provided by perf
6 *
7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
8 *
9 */
10
11/*
12 *
13 * Available subsystem list:
14 * sched ... scheduler and IPC mechanism
15 * mem ... memory access performance
16 *
17 */
18
19#include "perf.h"
20#include "util/util.h"
21#include "util/parse-options.h"
22#include "builtin.h"
23#include "bench/bench.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29struct bench_suite {
30 const char *name;
31 const char *summary;
32 int (*fn)(int, const char **, const char *);
33};
34 \
35/* sentinel: easy for help */
36#define suite_all { "all", "test all suite (pseudo suite)", NULL }
37
38static struct bench_suite sched_suites[] = {
39 { "messaging",
40 "Benchmark for scheduler and IPC mechanisms",
41 bench_sched_messaging },
42 { "pipe",
43 "Flood of communication over pipe() between two processes",
44 bench_sched_pipe },
45 suite_all,
46 { NULL,
47 NULL,
48 NULL }
49};
50
51static struct bench_suite mem_suites[] = {
52 { "memcpy",
53 "Simple memory copy in various ways",
54 bench_mem_memcpy },
55 suite_all,
56 { NULL,
57 NULL,
58 NULL }
59};
60
61struct bench_subsys {
62 const char *name;
63 const char *summary;
64 struct bench_suite *suites;
65};
66
67static struct bench_subsys subsystems[] = {
68 { "sched",
69 "scheduler and IPC mechanism",
70 sched_suites },
71 { "mem",
72 "memory access performance",
73 mem_suites },
74 { "all", /* sentinel: easy for help */
75 "test all subsystem (pseudo subsystem)",
76 NULL },
77 { NULL,
78 NULL,
79 NULL }
80};
81
82static void dump_suites(int subsys_index)
83{
84 int i;
85
86 printf("# List of available suites for %s...\n\n",
87 subsystems[subsys_index].name);
88
89 for (i = 0; subsystems[subsys_index].suites[i].name; i++)
90 printf("%14s: %s\n",
91 subsystems[subsys_index].suites[i].name,
92 subsystems[subsys_index].suites[i].summary);
93
94 printf("\n");
95 return;
96}
97
98static char *bench_format_str;
99int bench_format = BENCH_FORMAT_DEFAULT;
100
101static const struct option bench_options[] = {
102 OPT_STRING('f', "format", &bench_format_str, "default",
103 "Specify format style"),
104 OPT_END()
105};
106
107static const char * const bench_usage[] = {
108 "perf bench [<common options>] <subsystem> <suite> [<options>]",
109 NULL
110};
111
112static void print_usage(void)
113{
114 int i;
115
116 printf("Usage: \n");
117 for (i = 0; bench_usage[i]; i++)
118 printf("\t%s\n", bench_usage[i]);
119 printf("\n");
120
121 printf("# List of available subsystems...\n\n");
122
123 for (i = 0; subsystems[i].name; i++)
124 printf("%14s: %s\n",
125 subsystems[i].name, subsystems[i].summary);
126 printf("\n");
127}
128
129static int bench_str2int(char *str)
130{
131 if (!str)
132 return BENCH_FORMAT_DEFAULT;
133
134 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
135 return BENCH_FORMAT_DEFAULT;
136 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
137 return BENCH_FORMAT_SIMPLE;
138
139 return BENCH_FORMAT_UNKNOWN;
140}
141
142static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
143{
144 int i;
145 const char *argv[2];
146 struct bench_suite *suites = subsys->suites;
147
148 argv[1] = NULL;
149 /*
150 * TODO:
151 * preparing preset parameters for
152 * embedded, ordinary PC, HPC, etc...
153 * will be helpful
154 */
155 for (i = 0; suites[i].fn; i++) {
156 printf("# Running %s/%s benchmark...\n",
157 subsys->name,
158 suites[i].name);
159
160 argv[1] = suites[i].name;
161 suites[i].fn(1, argv, NULL);
162 printf("\n");
163 }
164}
165
166static void all_subsystem(void)
167{
168 int i;
169 for (i = 0; subsystems[i].suites; i++)
170 all_suite(&subsystems[i]);
171}
172
173int cmd_bench(int argc, const char **argv, const char *prefix __used)
174{
175 int i, j, status = 0;
176
177 if (argc < 2) {
178 /* No subsystem specified. */
179 print_usage();
180 goto end;
181 }
182
183 argc = parse_options(argc, argv, bench_options, bench_usage,
184 PARSE_OPT_STOP_AT_NON_OPTION);
185
186 bench_format = bench_str2int(bench_format_str);
187 if (bench_format == BENCH_FORMAT_UNKNOWN) {
188 printf("Unknown format descriptor:%s\n", bench_format_str);
189 goto end;
190 }
191
192 if (argc < 1) {
193 print_usage();
194 goto end;
195 }
196
197 if (!strcmp(argv[0], "all")) {
198 all_subsystem();
199 goto end;
200 }
201
202 for (i = 0; subsystems[i].name; i++) {
203 if (strcmp(subsystems[i].name, argv[0]))
204 continue;
205
206 if (argc < 2) {
207 /* No suite specified. */
208 dump_suites(i);
209 goto end;
210 }
211
212 if (!strcmp(argv[1], "all")) {
213 all_suite(&subsystems[i]);
214 goto end;
215 }
216
217 for (j = 0; subsystems[i].suites[j].name; j++) {
218 if (strcmp(subsystems[i].suites[j].name, argv[1]))
219 continue;
220
221 if (bench_format == BENCH_FORMAT_DEFAULT)
222 printf("# Running %s/%s benchmark...\n",
223 subsystems[i].name,
224 subsystems[i].suites[j].name);
225 status = subsystems[i].suites[j].fn(argc - 1,
226 argv + 1, prefix);
227 goto end;
228 }
229
230 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
231 dump_suites(i);
232 goto end;
233 }
234
235 printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
236 status = 1;
237 goto end;
238 }
239
240 printf("Unknown subsystem:%s\n", argv[0]);
241 status = 1;
242
243end:
244 return status;
245}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
new file mode 100644
index 000000000000..bfd16a1594e4
--- /dev/null
+++ b/tools/perf/builtin-buildid-list.c
@@ -0,0 +1,77 @@
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/parse-options.h"
15#include "util/session.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_session *session = perf_session__new(input_name, O_RDONLY, force);
59
60 if (session == NULL)
61 return -1;
62
63 err = perf_header__process_sections(&session->header, session->fd,
64 perf_file_section__process_buildids);
65 if (err >= 0)
66 dsos__fprintf_buildid(stdout);
67
68 perf_session__delete(session);
69 return err;
70}
71
72int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
73{
74 argc = parse_options(argc, argv, options, buildid_list_usage, 0);
75 setup_pager();
76 return __cmd_buildid_list();
77}
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..2071d2485913
--- /dev/null
+++ b/tools/perf/builtin-kmem.c
@@ -0,0 +1,803 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9#include "util/session.h"
10
11#include "util/parse-options.h"
12#include "util/trace-event.h"
13
14#include "util/debug.h"
15#include "util/data_map.h"
16
17#include <linux/rbtree.h>
18
19struct alloc_stat;
20typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
21
22static char const *input_name = "perf.data";
23
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 int err;
371 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
372
373 if (session == NULL)
374 return -ENOMEM;
375
376 register_idle_thread();
377 register_perf_file_handler(&file_handler);
378
379 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
380 perf_session__delete(session);
381 return err;
382}
383
384static double fragmentation(unsigned long n_req, unsigned long n_alloc)
385{
386 if (n_alloc == 0)
387 return 0.0;
388 else
389 return 100.0 - (100.0 * n_req / n_alloc);
390}
391
392static void __print_result(struct rb_root *root, int n_lines, int is_caller)
393{
394 struct rb_node *next;
395
396 printf("%.102s\n", graph_dotted_line);
397 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
398 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
399 printf("%.102s\n", graph_dotted_line);
400
401 next = rb_first(root);
402
403 while (next && n_lines--) {
404 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
405 node);
406 struct symbol *sym = NULL;
407 char buf[BUFSIZ];
408 u64 addr;
409
410 if (is_caller) {
411 addr = data->call_site;
412 if (!raw_ip)
413 sym = map_groups__find_function(kmaps, addr, NULL);
414 } else
415 addr = data->ptr;
416
417 if (sym != NULL)
418 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
419 addr - sym->start);
420 else
421 snprintf(buf, sizeof(buf), "%#Lx", addr);
422 printf(" %-34s |", buf);
423
424 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
425 (unsigned long long)data->bytes_alloc,
426 (unsigned long)data->bytes_alloc / data->hit,
427 (unsigned long long)data->bytes_req,
428 (unsigned long)data->bytes_req / data->hit,
429 (unsigned long)data->hit,
430 (unsigned long)data->pingpong,
431 fragmentation(data->bytes_req, data->bytes_alloc));
432
433 next = rb_next(next);
434 }
435
436 if (n_lines == -1)
437 printf(" ... | ... | ... | ... | ... | ... \n");
438
439 printf("%.102s\n", graph_dotted_line);
440}
441
442static void print_summary(void)
443{
444 printf("\nSUMMARY\n=======\n");
445 printf("Total bytes requested: %lu\n", total_requested);
446 printf("Total bytes allocated: %lu\n", total_allocated);
447 printf("Total bytes wasted on internal fragmentation: %lu\n",
448 total_allocated - total_requested);
449 printf("Internal fragmentation: %f%%\n",
450 fragmentation(total_requested, total_allocated));
451 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
452}
453
454static void print_result(void)
455{
456 if (caller_flag)
457 __print_result(&root_caller_sorted, caller_lines, 1);
458 if (alloc_flag)
459 __print_result(&root_alloc_sorted, alloc_lines, 0);
460 print_summary();
461}
462
463struct sort_dimension {
464 const char name[20];
465 sort_fn_t cmp;
466 struct list_head list;
467};
468
469static LIST_HEAD(caller_sort);
470static LIST_HEAD(alloc_sort);
471
472static void sort_insert(struct rb_root *root, struct alloc_stat *data,
473 struct list_head *sort_list)
474{
475 struct rb_node **new = &(root->rb_node);
476 struct rb_node *parent = NULL;
477 struct sort_dimension *sort;
478
479 while (*new) {
480 struct alloc_stat *this;
481 int cmp = 0;
482
483 this = rb_entry(*new, struct alloc_stat, node);
484 parent = *new;
485
486 list_for_each_entry(sort, sort_list, list) {
487 cmp = sort->cmp(data, this);
488 if (cmp)
489 break;
490 }
491
492 if (cmp > 0)
493 new = &((*new)->rb_left);
494 else
495 new = &((*new)->rb_right);
496 }
497
498 rb_link_node(&data->node, parent, new);
499 rb_insert_color(&data->node, root);
500}
501
502static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
503 struct list_head *sort_list)
504{
505 struct rb_node *node;
506 struct alloc_stat *data;
507
508 for (;;) {
509 node = rb_first(root);
510 if (!node)
511 break;
512
513 rb_erase(node, root);
514 data = rb_entry(node, struct alloc_stat, node);
515 sort_insert(root_sorted, data, sort_list);
516 }
517}
518
519static void sort_result(void)
520{
521 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
522 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
523}
524
525static int __cmd_kmem(void)
526{
527 setup_pager();
528 read_events();
529 sort_result();
530 print_result();
531
532 return 0;
533}
534
535static const char * const kmem_usage[] = {
536 "perf kmem [<options>] {record|stat}",
537 NULL
538};
539
540static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
541{
542 if (l->ptr < r->ptr)
543 return -1;
544 else if (l->ptr > r->ptr)
545 return 1;
546 return 0;
547}
548
549static struct sort_dimension ptr_sort_dimension = {
550 .name = "ptr",
551 .cmp = ptr_cmp,
552};
553
554static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
555{
556 if (l->call_site < r->call_site)
557 return -1;
558 else if (l->call_site > r->call_site)
559 return 1;
560 return 0;
561}
562
563static struct sort_dimension callsite_sort_dimension = {
564 .name = "callsite",
565 .cmp = callsite_cmp,
566};
567
568static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
569{
570 if (l->hit < r->hit)
571 return -1;
572 else if (l->hit > r->hit)
573 return 1;
574 return 0;
575}
576
577static struct sort_dimension hit_sort_dimension = {
578 .name = "hit",
579 .cmp = hit_cmp,
580};
581
582static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
583{
584 if (l->bytes_alloc < r->bytes_alloc)
585 return -1;
586 else if (l->bytes_alloc > r->bytes_alloc)
587 return 1;
588 return 0;
589}
590
591static struct sort_dimension bytes_sort_dimension = {
592 .name = "bytes",
593 .cmp = bytes_cmp,
594};
595
596static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
597{
598 double x, y;
599
600 x = fragmentation(l->bytes_req, l->bytes_alloc);
601 y = fragmentation(r->bytes_req, r->bytes_alloc);
602
603 if (x < y)
604 return -1;
605 else if (x > y)
606 return 1;
607 return 0;
608}
609
610static struct sort_dimension frag_sort_dimension = {
611 .name = "frag",
612 .cmp = frag_cmp,
613};
614
615static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
616{
617 if (l->pingpong < r->pingpong)
618 return -1;
619 else if (l->pingpong > r->pingpong)
620 return 1;
621 return 0;
622}
623
624static struct sort_dimension pingpong_sort_dimension = {
625 .name = "pingpong",
626 .cmp = pingpong_cmp,
627};
628
629static struct sort_dimension *avail_sorts[] = {
630 &ptr_sort_dimension,
631 &callsite_sort_dimension,
632 &hit_sort_dimension,
633 &bytes_sort_dimension,
634 &frag_sort_dimension,
635 &pingpong_sort_dimension,
636};
637
638#define NUM_AVAIL_SORTS \
639 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
640
641static int sort_dimension__add(const char *tok, struct list_head *list)
642{
643 struct sort_dimension *sort;
644 int i;
645
646 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
647 if (!strcmp(avail_sorts[i]->name, tok)) {
648 sort = malloc(sizeof(*sort));
649 if (!sort)
650 die("malloc");
651 memcpy(sort, avail_sorts[i], sizeof(*sort));
652 list_add_tail(&sort->list, list);
653 return 0;
654 }
655 }
656
657 return -1;
658}
659
660static int setup_sorting(struct list_head *sort_list, const char *arg)
661{
662 char *tok;
663 char *str = strdup(arg);
664
665 if (!str)
666 die("strdup");
667
668 while (true) {
669 tok = strsep(&str, ",");
670 if (!tok)
671 break;
672 if (sort_dimension__add(tok, sort_list) < 0) {
673 error("Unknown --sort key: '%s'", tok);
674 return -1;
675 }
676 }
677
678 free(str);
679 return 0;
680}
681
682static int parse_sort_opt(const struct option *opt __used,
683 const char *arg, int unset __used)
684{
685 if (!arg)
686 return -1;
687
688 if (caller_flag > alloc_flag)
689 return setup_sorting(&caller_sort, arg);
690 else
691 return setup_sorting(&alloc_sort, arg);
692
693 return 0;
694}
695
696static int parse_caller_opt(const struct option *opt __used,
697 const char *arg __used, int unset __used)
698{
699 caller_flag = (alloc_flag + 1);
700 return 0;
701}
702
703static int parse_alloc_opt(const struct option *opt __used,
704 const char *arg __used, int unset __used)
705{
706 alloc_flag = (caller_flag + 1);
707 return 0;
708}
709
710static int parse_line_opt(const struct option *opt __used,
711 const char *arg, int unset __used)
712{
713 int lines;
714
715 if (!arg)
716 return -1;
717
718 lines = strtoul(arg, NULL, 10);
719
720 if (caller_flag > alloc_flag)
721 caller_lines = lines;
722 else
723 alloc_lines = lines;
724
725 return 0;
726}
727
728static const struct option kmem_options[] = {
729 OPT_STRING('i', "input", &input_name, "file",
730 "input file name"),
731 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
732 "show per-callsite statistics",
733 parse_caller_opt),
734 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
735 "show per-allocation statistics",
736 parse_alloc_opt),
737 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
738 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
739 parse_sort_opt),
740 OPT_CALLBACK('l', "line", NULL, "num",
741 "show n lines",
742 parse_line_opt),
743 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
744 OPT_END()
745};
746
747static const char *record_args[] = {
748 "record",
749 "-a",
750 "-R",
751 "-M",
752 "-f",
753 "-c", "1",
754 "-e", "kmem:kmalloc",
755 "-e", "kmem:kmalloc_node",
756 "-e", "kmem:kfree",
757 "-e", "kmem:kmem_cache_alloc",
758 "-e", "kmem:kmem_cache_alloc_node",
759 "-e", "kmem:kmem_cache_free",
760};
761
762static int __cmd_record(int argc, const char **argv)
763{
764 unsigned int rec_argc, i, j;
765 const char **rec_argv;
766
767 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
768 rec_argv = calloc(rec_argc + 1, sizeof(char *));
769
770 for (i = 0; i < ARRAY_SIZE(record_args); i++)
771 rec_argv[i] = strdup(record_args[i]);
772
773 for (j = 1; j < (unsigned int)argc; j++, i++)
774 rec_argv[i] = argv[j];
775
776 return cmd_record(i, rec_argv, NULL);
777}
778
779int cmd_kmem(int argc, const char **argv, const char *prefix __used)
780{
781 symbol__init(0);
782
783 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
784
785 if (!argc)
786 usage_with_options(kmem_usage, kmem_options);
787
788 if (!strncmp(argv[0], "rec", 3)) {
789 return __cmd_record(argc, argv);
790 } else if (!strcmp(argv[0], "stat")) {
791 setup_cpunode_map();
792
793 if (list_empty(&caller_sort))
794 setup_sorting(&caller_sort, default_sort_order);
795 if (list_empty(&alloc_sort))
796 setup_sorting(&alloc_sort, default_sort_order);
797
798 return __cmd_kmem();
799 }
800
801 return 0;
802}
803
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..4decbd14eaed 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,55 +17,53 @@
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/session.h"
21#include "util/symbol.h"
21 22
22#include <unistd.h> 23#include <unistd.h>
23#include <sched.h> 24#include <sched.h>
24 25
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]; 26static int fd[MAX_NR_CPUS][MAX_COUNTERS];
29 27
30static long default_interval = 100000; 28static long default_interval = 0;
31 29
32static int nr_cpus = 0; 30static int nr_cpus = 0;
33static unsigned int page_size; 31static unsigned int page_size;
34static unsigned int mmap_pages = 128; 32static unsigned int mmap_pages = 128;
35static int freq = 0; 33static int freq = 1000;
36static int output; 34static int output;
37static const char *output_name = "perf.data"; 35static const char *output_name = "perf.data";
38static int group = 0; 36static int group = 0;
39static unsigned int realtime_prio = 0; 37static unsigned int realtime_prio = 0;
40static int raw_samples = 0; 38static int raw_samples = 0;
41static int system_wide = 0; 39static int system_wide = 0;
42static int profile_cpu = -1; 40static int profile_cpu = -1;
43static pid_t target_pid = -1; 41static pid_t target_pid = -1;
44static pid_t child_pid = -1; 42static pid_t child_pid = -1;
45static int inherit = 1; 43static int inherit = 1;
46static int force = 0; 44static int force = 0;
47static int append_file = 0; 45static int append_file = 0;
48static int call_graph = 0; 46static int call_graph = 0;
49static int inherit_stat = 0; 47static int inherit_stat = 0;
50static int no_samples = 0; 48static int no_samples = 0;
51static int sample_address = 0; 49static int sample_address = 0;
52static int multiplex = 0; 50static int multiplex = 0;
53static int multiplex_fd = -1; 51static int multiplex_fd = -1;
54 52
55static long samples; 53static long samples = 0;
56static struct timeval last_read; 54static struct timeval last_read;
57static struct timeval this_read; 55static struct timeval this_read;
58 56
59static u64 bytes_written; 57static u64 bytes_written = 0;
60 58
61static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 59static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
62 60
63static int nr_poll; 61static int nr_poll = 0;
64static int nr_cpu; 62static int nr_cpu = 0;
65 63
66static int file_new = 1; 64static int file_new = 1;
67 65
68struct perf_header *header; 66static struct perf_session *session;
69 67
70struct mmap_data { 68struct mmap_data {
71 int counter; 69 int counter;
@@ -113,6 +111,24 @@ static void write_output(void *buf, size_t size)
113 } 111 }
114} 112}
115 113
114static void write_event(event_t *buf, size_t size)
115{
116 /*
117 * Add it to the list of DSOs, so that when we finish this
118 * record session we can pick the available build-ids.
119 */
120 if (buf->header.type == PERF_RECORD_MMAP)
121 dsos__findnew(buf->mmap.filename);
122
123 write_output(buf, size);
124}
125
126static int process_synthesized_event(event_t *event)
127{
128 write_event(event, event->header.size);
129 return 0;
130}
131
116static void mmap_read(struct mmap_data *md) 132static void mmap_read(struct mmap_data *md)
117{ 133{
118 unsigned int head = mmap_read_head(md); 134 unsigned int head = mmap_read_head(md);
@@ -161,14 +177,14 @@ static void mmap_read(struct mmap_data *md)
161 size = md->mask + 1 - (old & md->mask); 177 size = md->mask + 1 - (old & md->mask);
162 old += size; 178 old += size;
163 179
164 write_output(buf, size); 180 write_event(buf, size);
165 } 181 }
166 182
167 buf = &data[old & md->mask]; 183 buf = &data[old & md->mask];
168 size = head - old; 184 size = head - old;
169 old += size; 185 old += size;
170 186
171 write_output(buf, size); 187 write_event(buf, size);
172 188
173 md->prev = old; 189 md->prev = old;
174 mmap_write_tail(md, old); 190 mmap_write_tail(md, old);
@@ -195,179 +211,21 @@ static void sig_atexit(void)
195 kill(getpid(), signr); 211 kill(getpid(), signr);
196} 212}
197 213
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; 214static int group_fd;
361 215
362static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 216static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
363{ 217{
364 struct perf_header_attr *h_attr; 218 struct perf_header_attr *h_attr;
365 219
366 if (nr < header->attrs) { 220 if (nr < session->header.attrs) {
367 h_attr = header->attr[nr]; 221 h_attr = session->header.attr[nr];
368 } else { 222 } else {
369 h_attr = perf_header_attr__new(a); 223 h_attr = perf_header_attr__new(a);
370 perf_header__add_attr(header, h_attr); 224 if (h_attr != NULL)
225 if (perf_header__add_attr(&session->header, h_attr) < 0) {
226 perf_header_attr__delete(h_attr);
227 h_attr = NULL;
228 }
371 } 229 }
372 230
373 return h_attr; 231 return h_attr;
@@ -375,9 +233,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
375 233
376static void create_counter(int counter, int cpu, pid_t pid) 234static void create_counter(int counter, int cpu, pid_t pid)
377{ 235{
236 char *filter = filters[counter];
378 struct perf_event_attr *attr = attrs + counter; 237 struct perf_event_attr *attr = attrs + counter;
379 struct perf_header_attr *h_attr; 238 struct perf_header_attr *h_attr;
380 int track = !counter; /* only the first counter needs these */ 239 int track = !counter; /* only the first counter needs these */
240 int ret;
381 struct { 241 struct {
382 u64 count; 242 u64 count;
383 u64 time_enabled; 243 u64 time_enabled;
@@ -448,11 +308,19 @@ try_again:
448 printf("\n"); 308 printf("\n");
449 error("perfcounter syscall returned with %d (%s)\n", 309 error("perfcounter syscall returned with %d (%s)\n",
450 fd[nr_cpu][counter], strerror(err)); 310 fd[nr_cpu][counter], strerror(err));
311
312#if defined(__i386__) || defined(__x86_64__)
313 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
314 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");
315#endif
316
451 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 317 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
452 exit(-1); 318 exit(-1);
453 } 319 }
454 320
455 h_attr = get_header_attr(attr, counter); 321 h_attr = get_header_attr(attr, counter);
322 if (h_attr == NULL)
323 die("nomem\n");
456 324
457 if (!file_new) { 325 if (!file_new) {
458 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 326 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +334,10 @@ try_again:
466 exit(-1); 334 exit(-1);
467 } 335 }
468 336
469 perf_header_attr__add_id(h_attr, read_data.id); 337 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
338 pr_warning("Not enough memory to add id\n");
339 exit(-1);
340 }
470 341
471 assert(fd[nr_cpu][counter] >= 0); 342 assert(fd[nr_cpu][counter] >= 0);
472 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 343 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +351,6 @@ try_again:
480 multiplex_fd = fd[nr_cpu][counter]; 351 multiplex_fd = fd[nr_cpu][counter];
481 352
482 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 353 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
483 int ret;
484 354
485 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 355 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
486 assert(ret != -1); 356 assert(ret != -1);
@@ -500,6 +370,16 @@ try_again:
500 } 370 }
501 } 371 }
502 372
373 if (filter != NULL) {
374 ret = ioctl(fd[nr_cpu][counter],
375 PERF_EVENT_IOC_SET_FILTER, filter);
376 if (ret) {
377 error("failed to set filter with %d (%s)\n", errno,
378 strerror(errno));
379 exit(-1);
380 }
381 }
382
503 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 383 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
504} 384}
505 385
@@ -516,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
516 396
517static void atexit_header(void) 397static void atexit_header(void)
518{ 398{
519 header->data_size += bytes_written; 399 session->header.data_size += bytes_written;
520 400
521 perf_header__write(header, output); 401 perf_header__write(&session->header, output, true);
522} 402}
523 403
524static int __cmd_record(int argc, const char **argv) 404static int __cmd_record(int argc, const char **argv)
@@ -527,7 +407,7 @@ static int __cmd_record(int argc, const char **argv)
527 struct stat st; 407 struct stat st;
528 pid_t pid = 0; 408 pid_t pid = 0;
529 int flags; 409 int flags;
530 int ret; 410 int err;
531 unsigned long waking = 0; 411 unsigned long waking = 0;
532 412
533 page_size = sysconf(_SC_PAGE_SIZE); 413 page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,22 +441,29 @@ static int __cmd_record(int argc, const char **argv)
561 exit(-1); 441 exit(-1);
562 } 442 }
563 443
564 if (!file_new) 444 session = perf_session__new(output_name, O_WRONLY, force);
565 header = perf_header__read(output); 445 if (session == NULL) {
566 else 446 pr_err("Not enough memory for reading perf file header\n");
567 header = perf_header__new(); 447 return -1;
448 }
568 449
450 if (!file_new) {
451 err = perf_header__read(&session->header, output);
452 if (err < 0)
453 return err;
454 }
569 455
570 if (raw_samples) { 456 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 457 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
572 } else { 458 } else {
573 for (i = 0; i < nr_counters; i++) { 459 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 460 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 461 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
576 break; 462 break;
577 } 463 }
578 } 464 }
579 } 465 }
466
580 atexit(atexit_header); 467 atexit(atexit_header);
581 468
582 if (!system_wide) { 469 if (!system_wide) {
@@ -594,25 +481,36 @@ static int __cmd_record(int argc, const char **argv)
594 } 481 }
595 } 482 }
596 483
597 if (file_new) 484 if (file_new) {
598 perf_header__write(header, output); 485 err = perf_header__write(&session->header, output, false);
486 if (err < 0)
487 return err;
488 }
599 489
600 if (!system_wide) { 490 if (!system_wide)
601 pid_t tgid = pid_synthesize_comm_event(pid, 0); 491 event__synthesize_thread(pid, process_synthesized_event);
602 pid_synthesize_mmap_samples(pid, tgid); 492 else
603 } else 493 event__synthesize_threads(process_synthesized_event);
604 synthesize_all();
605 494
606 if (target_pid == -1 && argc) { 495 if (target_pid == -1 && argc) {
607 pid = fork(); 496 pid = fork();
608 if (pid < 0) 497 if (pid < 0)
609 perror("failed to fork"); 498 die("failed to fork");
610 499
611 if (!pid) { 500 if (!pid) {
612 if (execvp(argv[0], (char **)argv)) { 501 if (execvp(argv[0], (char **)argv)) {
613 perror(argv[0]); 502 perror(argv[0]);
614 exit(-1); 503 exit(-1);
615 } 504 }
505 } else {
506 /*
507 * Wait a bit for the execv'ed child to appear
508 * and be updated in /proc
509 * FIXME: Do you know a less heuristical solution?
510 */
511 usleep(1000);
512 event__synthesize_thread(pid,
513 process_synthesized_event);
616 } 514 }
617 515
618 child_pid = pid; 516 child_pid = pid;
@@ -623,7 +521,7 @@ static int __cmd_record(int argc, const char **argv)
623 521
624 param.sched_priority = realtime_prio; 522 param.sched_priority = realtime_prio;
625 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 523 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
626 printf("Could not set realtime priority.\n"); 524 pr_err("Could not set realtime priority.\n");
627 exit(-1); 525 exit(-1);
628 } 526 }
629 } 527 }
@@ -641,7 +539,7 @@ static int __cmd_record(int argc, const char **argv)
641 if (hits == samples) { 539 if (hits == samples) {
642 if (done) 540 if (done)
643 break; 541 break;
644 ret = poll(event_array, nr_poll, -1); 542 err = poll(event_array, nr_poll, -1);
645 waking++; 543 waking++;
646 } 544 }
647 545
@@ -677,6 +575,8 @@ static const struct option options[] = {
677 OPT_CALLBACK('e', "event", NULL, "event", 575 OPT_CALLBACK('e', "event", NULL, "event",
678 "event selector. use 'perf list' to list available events", 576 "event selector. use 'perf list' to list available events",
679 parse_events), 577 parse_events),
578 OPT_CALLBACK(0, "filter", NULL, "filter",
579 "event filter", parse_filter),
680 OPT_INTEGER('p', "pid", &target_pid, 580 OPT_INTEGER('p', "pid", &target_pid,
681 "record events on existing pid"), 581 "record events on existing pid"),
682 OPT_INTEGER('r', "realtime", &realtime_prio, 582 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -720,6 +620,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
720{ 620{
721 int counter; 621 int counter;
722 622
623 symbol__init(0);
624
723 argc = parse_options(argc, argv, options, record_usage, 625 argc = parse_options(argc, argv, options, record_usage,
724 PARSE_OPT_STOP_AT_NON_OPTION); 626 PARSE_OPT_STOP_AT_NON_OPTION);
725 if (!argc && target_pid == -1 && !system_wide) 627 if (!argc && target_pid == -1 && !system_wide)
@@ -731,6 +633,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 633 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 634 }
733 635
636 /*
637 * User specified count overrides default frequency.
638 */
639 if (default_interval)
640 freq = 0;
641 else if (freq) {
642 default_interval = freq;
643 } else {
644 fprintf(stderr, "frequency and count are zero, aborting\n");
645 exit(EXIT_FAILURE);
646 }
647
734 for (counter = 0; counter < nr_counters; counter++) { 648 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 649 if (attrs[counter].sample_period)
736 continue; 650 continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..e2ec49a9b731 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -22,24 +22,23 @@
22#include "perf.h" 22#include "perf.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/header.h" 24#include "util/header.h"
25#include "util/session.h"
25 26
26#include "util/parse-options.h" 27#include "util/parse-options.h"
27#include "util/parse-events.h" 28#include "util/parse-events.h"
28 29
30#include "util/data_map.h"
29#include "util/thread.h" 31#include "util/thread.h"
32#include "util/sort.h"
33#include "util/hist.h"
30 34
31static char const *input_name = "perf.data"; 35static char const *input_name = "perf.data";
32 36
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, 37static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str; 38 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list; 39static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
39 40
40static int force; 41static int force;
41static int input;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43 42
44static int full_paths; 43static int full_paths;
45static int show_nr_samples; 44static int show_nr_samples;
@@ -50,374 +49,38 @@ static struct perf_read_values show_threads_values;
50static char default_pretty_printing_style[] = "normal"; 49static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style; 50static char *pretty_printing_style = default_pretty_printing_style;
52 51
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; 52static int exclude_other = 1;
61 53
62static char callchain_default_opt[] = "fractal,0.5"; 54static char callchain_default_opt[] = "fractal,0.5";
63 55
64static int callchain; 56static struct perf_session *session;
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;
74
75static
76struct callchain_param callchain_param = {
77 .mode = CHAIN_GRAPH_REL,
78 .min_percent = 0.5
79};
80 57
81static u64 sample_type; 58static u64 sample_type;
82 59
83static int repsep_fprintf(FILE *fp, const char *fmt, ...) 60struct 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 61
230 return strcmp(dso_l->name, dso_r->name);
231}
232 62
233static size_t 63static size_t
234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 64callchain__fprintf_left_margin(FILE *fp, int left_margin)
235{ 65{
236 if (self->dso) 66 int i;
237 return repsep_fprintf(fp, "%-*s", width, self->dso->name); 67 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 68
274 ret += repsep_fprintf(fp, "[%c] ", self->level); 69 ret = fprintf(fp, " ");
275 if (self->sym) {
276 ret += repsep_fprintf(fp, "%s", self->sym->name);
277 70
278 if (self->sym->module) 71 for (i = 0; i < left_margin; i++)
279 ret += repsep_fprintf(fp, "\t[%s]", 72 ret += fprintf(fp, " ");
280 self->sym->module->name);
281 } else {
282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 }
284 73
285 return ret; 74 return ret;
286} 75}
287 76
288static struct sort_entry sort_sym = { 77static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
289 .header = "Symbol", 78 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{ 79{
417 int i; 80 int i;
418 size_t ret = 0; 81 size_t ret = 0;
419 82
420 ret += fprintf(fp, "%s", " "); 83 ret += callchain__fprintf_left_margin(fp, left_margin);
421 84
422 for (i = 0; i < depth; i++) 85 for (i = 0; i < depth; i++)
423 if (depth_mask & (1 << i)) 86 if (depth_mask & (1 << i))
@@ -432,12 +95,12 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
432static size_t 95static size_t
433ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, 96ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 int depth_mask, int count, u64 total_samples, 97 int depth_mask, int count, u64 total_samples,
435 int hits) 98 int hits, int left_margin)
436{ 99{
437 int i; 100 int i;
438 size_t ret = 0; 101 size_t ret = 0;
439 102
440 ret += fprintf(fp, "%s", " "); 103 ret += callchain__fprintf_left_margin(fp, left_margin);
441 for (i = 0; i < depth; i++) { 104 for (i = 0; i < depth; i++) {
442 if (depth_mask & (1 << i)) 105 if (depth_mask & (1 << i))
443 ret += fprintf(fp, "|"); 106 ret += fprintf(fp, "|");
@@ -475,8 +138,9 @@ static void init_rem_hits(void)
475} 138}
476 139
477static size_t 140static size_t
478callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 141__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 u64 total_samples, int depth, int depth_mask) 142 u64 total_samples, int depth, int depth_mask,
143 int left_margin)
480{ 144{
481 struct rb_node *node, *next; 145 struct rb_node *node, *next;
482 struct callchain_node *child; 146 struct callchain_node *child;
@@ -517,7 +181,8 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
517 * But we keep the older depth mask for the line seperator 181 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child 182 * to keep the level link until we reach the last child
519 */ 183 */
520 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask); 184 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
185 left_margin);
521 i = 0; 186 i = 0;
522 list_for_each_entry(chain, &child->val, list) { 187 list_for_each_entry(chain, &child->val, list) {
523 if (chain->ip >= PERF_CONTEXT_MAX) 188 if (chain->ip >= PERF_CONTEXT_MAX)
@@ -525,11 +190,13 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
525 ret += ipchain__fprintf_graph(fp, chain, depth, 190 ret += ipchain__fprintf_graph(fp, chain, depth,
526 new_depth_mask, i++, 191 new_depth_mask, i++,
527 new_total, 192 new_total,
528 cumul); 193 cumul,
194 left_margin);
529 } 195 }
530 ret += callchain__fprintf_graph(fp, child, new_total, 196 ret += __callchain__fprintf_graph(fp, child, new_total,
531 depth + 1, 197 depth + 1,
532 new_depth_mask | (1 << depth)); 198 new_depth_mask | (1 << depth),
199 left_margin);
533 node = next; 200 node = next;
534 } 201 }
535 202
@@ -543,12 +210,51 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
543 210
544 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 211 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 new_depth_mask, 0, new_total, 212 new_depth_mask, 0, new_total,
546 remaining); 213 remaining, left_margin);
547 } 214 }
548 215
549 return ret; 216 return ret;
550} 217}
551 218
219
220static size_t
221callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
222 u64 total_samples, int left_margin)
223{
224 struct callchain_list *chain;
225 bool printed = false;
226 int i = 0;
227 int ret = 0;
228
229 list_for_each_entry(chain, &self->val, list) {
230 if (chain->ip >= PERF_CONTEXT_MAX)
231 continue;
232
233 if (!i++ && sort__first_dimension == SORT_SYM)
234 continue;
235
236 if (!printed) {
237 ret += callchain__fprintf_left_margin(fp, left_margin);
238 ret += fprintf(fp, "|\n");
239 ret += callchain__fprintf_left_margin(fp, left_margin);
240 ret += fprintf(fp, "---");
241
242 left_margin += 3;
243 printed = true;
244 } else
245 ret += callchain__fprintf_left_margin(fp, left_margin);
246
247 if (chain->sym)
248 ret += fprintf(fp, " %s\n", chain->sym->name);
249 else
250 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
251 }
252
253 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
254
255 return ret;
256}
257
552static size_t 258static size_t
553callchain__fprintf_flat(FILE *fp, struct callchain_node *self, 259callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
554 u64 total_samples) 260 u64 total_samples)
@@ -577,7 +283,7 @@ callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
577 283
578static size_t 284static size_t
579hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, 285hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 u64 total_samples) 286 u64 total_samples, int left_margin)
581{ 287{
582 struct rb_node *rb_node; 288 struct rb_node *rb_node;
583 struct callchain_node *chain; 289 struct callchain_node *chain;
@@ -597,8 +303,8 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
597 break; 303 break;
598 case CHAIN_GRAPH_ABS: /* Falldown */ 304 case CHAIN_GRAPH_ABS: /* Falldown */
599 case CHAIN_GRAPH_REL: 305 case CHAIN_GRAPH_REL:
600 ret += callchain__fprintf_graph(fp, chain, 306 ret += callchain__fprintf_graph(fp, chain, total_samples,
601 total_samples, 1, 1); 307 left_margin);
602 case CHAIN_NONE: 308 case CHAIN_NONE:
603 default: 309 default:
604 break; 310 break;
@@ -610,7 +316,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
610 return ret; 316 return ret;
611} 317}
612 318
613
614static size_t 319static size_t
615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples) 320hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616{ 321{
@@ -644,8 +349,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
644 349
645 ret += fprintf(fp, "\n"); 350 ret += fprintf(fp, "\n");
646 351
647 if (callchain) 352 if (callchain) {
648 hist_entry_callchain__fprintf(fp, self, total_samples); 353 int left_margin = 0;
354
355 if (sort__first_dimension == SORT_COMM) {
356 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
357 list);
358 left_margin = se->width ? *se->width : 0;
359 left_margin -= thread__comm_len(self->thread);
360 }
361
362 hist_entry_callchain__fprintf(fp, self, total_samples,
363 left_margin);
364 }
649 365
650 return ret; 366 return ret;
651} 367}
@@ -693,63 +409,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
693 return 0; 409 return 0;
694} 410}
695 411
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) 412static int call__match(struct symbol *sym)
754{ 413{
755 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 414 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -758,11 +417,11 @@ static int call__match(struct symbol *sym)
758 return 0; 417 return 0;
759} 418}
760 419
761static struct symbol ** 420static struct symbol **resolve_callchain(struct thread *thread,
762resolve_callchain(struct thread *thread, struct map *map __used, 421 struct ip_callchain *chain,
763 struct ip_callchain *chain, struct hist_entry *entry) 422 struct symbol **parent)
764{ 423{
765 u64 context = PERF_CONTEXT_MAX; 424 u8 cpumode = PERF_RECORD_MISC_USER;
766 struct symbol **syms = NULL; 425 struct symbol **syms = NULL;
767 unsigned int i; 426 unsigned int i;
768 427
@@ -776,34 +435,31 @@ resolve_callchain(struct thread *thread, struct map *map __used,
776 435
777 for (i = 0; i < chain->nr; i++) { 436 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i]; 437 u64 ip = chain->ips[i];
779 struct dso *dso = NULL; 438 struct addr_location al;
780 struct symbol *sym;
781 439
782 if (ip >= PERF_CONTEXT_MAX) { 440 if (ip >= PERF_CONTEXT_MAX) {
783 context = ip; 441 switch (ip) {
442 case PERF_CONTEXT_HV:
443 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
444 case PERF_CONTEXT_KERNEL:
445 cpumode = PERF_RECORD_MISC_KERNEL; break;
446 case PERF_CONTEXT_USER:
447 cpumode = PERF_RECORD_MISC_USER; break;
448 default:
449 break;
450 }
784 continue; 451 continue;
785 } 452 }
786 453
787 switch (context) { 454 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
788 case PERF_CONTEXT_HV: 455 ip, &al, NULL);
789 dso = hypervisor_dso; 456 if (al.sym != NULL) {
790 break; 457 if (sort__has_parent && !*parent &&
791 case PERF_CONTEXT_KERNEL: 458 call__match(al.sym))
792 dso = kernel_dso; 459 *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) 460 if (!callchain)
805 break; 461 break;
806 syms[i] = sym; 462 syms[i] = al.sym;
807 } 463 }
808 } 464 }
809 465
@@ -814,178 +470,33 @@ resolve_callchain(struct thread *thread, struct map *map __used,
814 * collect histogram counts 470 * collect histogram counts
815 */ 471 */
816 472
817static int 473static int hist_entry__add(struct addr_location *al,
818hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 474 struct ip_callchain *chain, u64 count)
819 struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 char level, u64 count)
821{ 475{
822 struct rb_node **p = &hist.rb_node; 476 struct symbol **syms = NULL, *parent = NULL;
823 struct rb_node *parent = NULL; 477 bool hit;
824 struct hist_entry *he; 478 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 479
839 if ((sort__has_parent || callchain) && chain) 480 if ((sort__has_parent || callchain) && chain)
840 syms = resolve_callchain(thread, map, chain, &entry); 481 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 482
846 cmp = hist_entry__cmp(&entry, he); 483 he = __hist_entry__add(al, parent, count, &hit);
847 484 if (he == NULL)
848 if (!cmp) { 485 return -ENOMEM;
849 he->count += count;
850 if (callchain) {
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
854 return 0;
855 }
856 486
857 if (cmp < 0) 487 if (hit)
858 p = &(*p)->rb_left; 488 he->count += count;
859 else
860 p = &(*p)->rb_right;
861 }
862 489
863 he = malloc(sizeof(*he));
864 if (!he)
865 return -ENOMEM;
866 *he = entry;
867 if (callchain) { 490 if (callchain) {
868 callchain_init(&he->callchain); 491 if (!hit)
492 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms); 493 append_chain(&he->callchain, chain, syms);
870 free(syms); 494 free(syms);
871 } 495 }
872 rb_link_node(&he->rb_node, parent, p);
873 rb_insert_color(&he->rb_node, &hist);
874 496
875 return 0; 497 return 0;
876} 498}
877 499
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) 500static size_t output__fprintf(FILE *fp, u64 total_samples)
990{ 501{
991 struct hist_entry *pos; 502 struct hist_entry *pos;
@@ -1080,13 +591,6 @@ print_entries:
1080 return ret; 591 return ret;
1081} 592}
1082 593
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) 594static int validate_chain(struct ip_callchain *chain, event_t *event)
1091{ 595{
1092 unsigned int chain_size; 596 unsigned int chain_size;
@@ -1100,214 +604,105 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1100 return 0; 604 return 0;
1101} 605}
1102 606
1103static int 607static int process_sample_event(event_t *event)
1104process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105{ 608{
1106 char level; 609 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; 610 int cpumode;
611 struct addr_location al;
612 struct thread *thread;
1116 613
1117 thread = threads__findnew(event->ip.pid, &threads, &last_match); 614 memset(&data, 0, sizeof(data));
615 data.period = 1;
1118 616
1119 if (sample_type & PERF_SAMPLE_PERIOD) { 617 event__parse_sample(event, sample_type, &data);
1120 period = *(u64 *)more_data;
1121 more_data += sizeof(u64);
1122 }
1123 618
1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 619 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1125 (void *)(offset + head),
1126 (void *)(long)(event->header.size),
1127 event->header.misc, 620 event->header.misc,
1128 event->ip.pid, event->ip.tid, 621 data.pid, data.tid,
1129 (void *)(long)ip, 622 (void *)(long)data.ip,
1130 (long long)period); 623 (long long)data.period);
1131 624
1132 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 625 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1133 unsigned int i; 626 unsigned int i;
1134 627
1135 chain = (void *)more_data; 628 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
1136 629
1137 dump_printf("... chain: nr:%Lu\n", chain->nr); 630 if (validate_chain(data.callchain, event) < 0) {
1138 631 pr_debug("call-chain problem with event, "
1139 if (validate_chain(chain, event) < 0) { 632 "skipping it.\n");
1140 eprintf("call-chain problem with event, skipping it.\n");
1141 return 0; 633 return 0;
1142 } 634 }
1143 635
1144 if (dump_trace) { 636 if (dump_trace) {
1145 for (i = 0; i < chain->nr; i++) 637 for (i = 0; i < data.callchain->nr; i++)
1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 638 dump_printf("..... %2d: %016Lx\n",
639 i, data.callchain->ips[i]);
1147 } 640 }
1148 } 641 }
1149 642
1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 643 thread = threads__findnew(data.pid);
1151
1152 if (thread == NULL) { 644 if (thread == NULL) {
1153 eprintf("problem processing %d event, skipping it.\n", 645 pr_debug("problem processing %d event, skipping it.\n",
1154 event->header.type); 646 event->header.type);
1155 return -1; 647 return -1;
1156 } 648 }
1157 649
650 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
651
1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 652 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1159 return 0; 653 return 0;
1160 654
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 655 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162 656
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) { 657 thread__find_addr_location(thread, cpumode,
1164 show = SHOW_KERNEL; 658 MAP__FUNCTION, data.ip, &al, NULL);
1165 level = 'k'; 659 /*
1166 660 * We have to do this here as we may have a dso with no symbol hit that
1167 dso = kernel_dso; 661 * has a name longer than the ones with symbols sampled.
1168 662 */
1169 dump_printf(" ...... dso: %s\n", dso->name); 663 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
1170 664 dso__calc_col_width(al.map->dso);
1171 } else if (cpumode == PERF_RECORD_MISC_USER) { 665
1172 666 if (dso_list &&
1173 show = SHOW_USER; 667 (!al.map || !al.map->dso ||
1174 level = '.'; 668 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
1175 669 (al.map->dso->short_name != al.map->dso->long_name &&
1176 } else { 670 strlist__has_entry(dso_list, al.map->dso->long_name)))))
1177 show = SHOW_HV; 671 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 672
1205static int 673 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; 674 return 0;
675
676 if (hist_entry__add(&al, data.callchain, data.period)) {
677 pr_debug("problem incrementing symbol count, skipping event\n");
678 return -1;
1226 } 679 }
1227 680
1228 thread__insert_map(thread, map); 681 event__stats.total += data.period;
1229 total_mmap++;
1230 682
1231 return 0; 683 return 0;
1232} 684}
1233 685
1234static int 686static int process_comm_event(event_t *event)
1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1236{ 687{
1237 struct thread *thread; 688 struct thread *thread = threads__findnew(event->comm.pid);
1238 689
1239 thread = threads__findnew(event->comm.pid, &threads, &last_match); 690 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
1240
1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
1242 (void *)(offset + head),
1243 (void *)(long)(event->header.size),
1244 event->comm.comm, event->comm.pid);
1245 691
1246 if (thread == NULL || 692 if (thread == NULL ||
1247 thread__set_comm_adjust(thread, event->comm.comm)) { 693 thread__set_comm_adjust(thread, event->comm.comm)) {
1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 694 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1249 return -1; 695 return -1;
1250 } 696 }
1251 total_comm++;
1252 697
1253 return 0; 698 return 0;
1254} 699}
1255 700
1256static int 701static 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{ 702{
1308 struct perf_event_attr *attr; 703 struct perf_event_attr *attr;
1309 704
1310 attr = perf_header__find_attr(event->read.id, header); 705 attr = perf_header__find_attr(event->read.id, &session->header);
1311 706
1312 if (show_threads) { 707 if (show_threads) {
1313 const char *name = attr ? __event_name(attr->type, attr->config) 708 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -1319,238 +714,96 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1319 event->read.value); 714 event->read.value);
1320 } 715 }
1321 716
1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", 717 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
1323 (void *)(offset + head), 718 attr ? __event_name(attr->type, attr->config) : "FAIL",
1324 (void *)(long)(event->header.size), 719 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 720
1331 return 0; 721 return 0;
1332} 722}
1333 723
1334static int 724static int sample_type_check(u64 type)
1335process_event(event_t *event, unsigned long offset, unsigned long head)
1336{ 725{
1337 trace_event(event); 726 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 727
1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { 728 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 if (sort__has_parent) { 729 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no" 730 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call" 731 " callchain data. Did you call"
1425 " perf record without -g?\n"); 732 " perf record without -g?\n");
1426 exit(-1); 733 return -1;
1427 } 734 }
1428 if (callchain) { 735 if (callchain) {
1429 fprintf(stderr, "selected -g but no callchain data." 736 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without" 737 " Did you call perf record without"
1431 " -g?\n"); 738 " -g?\n");
1432 exit(-1); 739 return -1;
1433 } 740 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 741 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1435 callchain = 1; 742 callchain = 1;
1436 if (register_callchain_param(&callchain_param) < 0) { 743 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain" 744 fprintf(stderr, "Can't register callchain"
1438 " params\n"); 745 " params\n");
1439 exit(-1); 746 return -1;
1440 } 747 }
1441 } 748 }
1442 749
1443 if (load_kernel() < 0) { 750 return 0;
1444 perror("failed to load kernel symbols"); 751}
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 752
1486 offset += shift; 753static struct perf_file_handler file_handler = {
1487 head -= shift; 754 .process_sample_event = process_sample_event,
1488 goto remap; 755 .process_mmap_event = event__process_mmap,
1489 } 756 .process_comm_event = process_comm_event,
757 .process_exit_event = event__process_task,
758 .process_fork_event = event__process_task,
759 .process_lost_event = event__process_lost,
760 .process_read_event = process_read_event,
761 .sample_type_check = sample_type_check,
762};
1490 763
1491 size = event->header.size;
1492 764
1493 dump_printf("\n%p [%p]: event: %d\n", 765static int __cmd_report(void)
1494 (void *)(offset + head), 766{
1495 (void *)(long)event->header.size, 767 struct thread *idle;
1496 event->header.type); 768 int ret;
1497 769
1498 if (!size || process_event(event, offset, head) < 0) { 770 session = perf_session__new(input_name, O_RDONLY, force);
771 if (session == NULL)
772 return -ENOMEM;
1499 773
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n", 774 idle = register_idle_thread();
1501 (void *)(offset + head), 775 thread__comm_adjust(idle);
1502 (void *)(long)(event->header.size),
1503 event->header.type);
1504 776
1505 total_unknown++; 777 if (show_threads)
778 perf_read_values_init(&show_threads_values);
1506 779
1507 /* 780 register_perf_file_handler(&file_handler);
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 781
1512 if (unlikely(head & 7)) 782 ret = perf_session__process_events(session, full_paths,
1513 head &= ~7ULL; 783 &event__cwdlen, &event__cwd);
784 if (ret)
785 goto out_delete;
1514 786
1515 size = 8; 787 if (dump_trace) {
788 event__print_totals();
789 goto out_delete;
1516 } 790 }
1517 791
1518 head += size; 792 if (verbose > 3)
1519 793 threads__fprintf(stdout);
1520 if (offset + head >= header->data_offset + header->data_size)
1521 goto done;
1522
1523 if (offset + head < (unsigned long)input_stat.st_size)
1524 goto more;
1525
1526done:
1527 rc = EXIT_SUCCESS;
1528 close(input);
1529
1530 dump_printf(" IP events: %10ld\n", total);
1531 dump_printf(" mmap events: %10ld\n", total_mmap);
1532 dump_printf(" comm events: %10ld\n", total_comm);
1533 dump_printf(" fork events: %10ld\n", total_fork);
1534 dump_printf(" lost events: %10ld\n", total_lost);
1535 dump_printf(" unknown events: %10ld\n", total_unknown);
1536
1537 if (dump_trace)
1538 return 0;
1539
1540 if (verbose >= 3)
1541 threads__fprintf(stdout, &threads);
1542 794
1543 if (verbose >= 2) 795 if (verbose > 2)
1544 dsos__fprintf(stdout); 796 dsos__fprintf(stdout);
1545 797
1546 collapse__resort(); 798 collapse__resort();
1547 output__resort(total); 799 output__resort(event__stats.total);
1548 output__fprintf(stdout, total); 800 output__fprintf(stdout, event__stats.total);
1549 801
1550 if (show_threads) 802 if (show_threads)
1551 perf_read_values_destroy(&show_threads_values); 803 perf_read_values_destroy(&show_threads_values);
1552 804out_delete:
1553 return rc; 805 perf_session__delete(session);
806 return ret;
1554} 807}
1555 808
1556static int 809static int
@@ -1606,7 +859,8 @@ setup:
1606 return 0; 859 return 0;
1607} 860}
1608 861
1609static const char * const report_usage[] = { 862//static const char * const report_usage[] = {
863const char * const report_usage[] = {
1610 "perf report [<options>] <command>", 864 "perf report [<options>] <command>",
1611 NULL 865 NULL
1612}; 866};
@@ -1618,9 +872,10 @@ static const struct option options[] = {
1618 "be more verbose (show symbol address, etc)"), 872 "be more verbose (show symbol address, etc)"),
1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 873 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1620 "dump raw trace in ASCII"), 874 "dump raw trace in ASCII"),
1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 875 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
876 "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 877 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules, 878 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"), 879 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 880 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1626 "Show a column with the number of samples"), 881 "Show a column with the number of samples"),
@@ -1690,9 +945,8 @@ static void setup_list(struct strlist **list, const char *list_str,
1690 945
1691int cmd_report(int argc, const char **argv, const char *prefix __used) 946int cmd_report(int argc, const char **argv, const char *prefix __used)
1692{ 947{
1693 symbol__init(); 948 if (symbol__init(&symbol_conf) < 0)
1694 949 return -1;
1695 page_size = getpagesize();
1696 950
1697 argc = parse_options(argc, argv, options, report_usage, 0); 951 argc = parse_options(argc, argv, options, report_usage, 0);
1698 952
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ce2d5be4f30e..65021fe1361e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,13 +6,14 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
12 13
13#include "util/debug.h" 14#include "util/debug.h"
15#include "util/data_map.h"
14 16
15#include <sys/types.h>
16#include <sys/prctl.h> 17#include <sys/prctl.h>
17 18
18#include <semaphore.h> 19#include <semaphore.h>
@@ -20,26 +21,17 @@
20#include <math.h> 21#include <math.h>
21 22
22static char const *input_name = "perf.data"; 23static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26 24
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31
32static struct perf_header *header;
33static u64 sample_type; 25static u64 sample_type;
34 26
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,133 @@ 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 int err;
1656 unsigned long offset = 0; 1667 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
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
1722 size = event->header.size;
1723
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 1668
1740 if (offset + head < (unsigned long)perf_stat.st_size) 1669 if (session == NULL)
1741 goto more; 1670 return -ENOMEM;
1742 1671
1743 rc = EXIT_SUCCESS; 1672 register_idle_thread();
1744 close(input); 1673 register_perf_file_handler(&file_handler);
1745 1674
1746 return rc; 1675 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1676 perf_session__delete(session);
1677 return err;
1747} 1678}
1748 1679
1749static void print_bad_events(void) 1680static void print_bad_events(void)
@@ -1784,9 +1715,9 @@ static void __cmd_lat(void)
1784 read_events(); 1715 read_events();
1785 sort_lat(); 1716 sort_lat();
1786 1717
1787 printf("\n -----------------------------------------------------------------------------------------\n"); 1718 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1719 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n"); 1720 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1790 1721
1791 next = rb_first(&sorted_atom_root); 1722 next = rb_first(&sorted_atom_root);
1792 1723
@@ -1883,6 +1814,8 @@ static const struct option latency_options[] = {
1883 "sort by key(s): runtime, switch, avg, max"), 1814 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose, 1815 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"), 1816 "be more verbose (show symbol address, etc)"),
1817 OPT_INTEGER('C', "CPU", &profile_cpu,
1818 "CPU to profile on"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1819 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"), 1820 "dump raw trace in ASCII"),
1888 OPT_END() 1821 OPT_END()
@@ -1960,14 +1893,18 @@ static int __cmd_record(int argc, const char **argv)
1960 1893
1961int cmd_sched(int argc, const char **argv, const char *prefix __used) 1894int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{ 1895{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage, 1896 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION); 1897 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc) 1898 if (!argc)
1969 usage_with_options(sched_usage, sched_options); 1899 usage_with_options(sched_usage, sched_options);
1970 1900
1901 /*
1902 * Aliased to 'perf trace' for now:
1903 */
1904 if (!strcmp(argv[0], "trace"))
1905 return cmd_trace(argc, argv, prefix);
1906
1907 symbol__init(0);
1971 if (!strncmp(argv[0], "rec", 3)) { 1908 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv); 1909 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) { 1910 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1991,11 +1928,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1991 usage_with_options(replay_usage, replay_options); 1928 usage_with_options(replay_usage, replay_options);
1992 } 1929 }
1993 __cmd_replay(); 1930 __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 { 1931 } else {
2000 usage_with_options(sched_usage, sched_options); 1932 usage_with_options(sched_usage, sched_options);
2001 } 1933 }
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..759dd2b35fdb 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,40 @@ 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 } 1047 }
1073 1048
1074 size = event->header.size; 1049 return 0;
1075 1050}
1076 if (!size || process_event(event) < 0) {
1077
1078 printf("%p [%p]: skipping unknown header type: %d\n",
1079 (void *)(offset + head),
1080 (void *)(long)(event->header.size),
1081 event->header.type);
1082
1083 /*
1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087
1088 if (unlikely(head & 7))
1089 head &= ~7ULL;
1090
1091 size = 8;
1092 }
1093 1051
1094 head += size; 1052static struct perf_file_handler file_handler = {
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};
1095 1059
1096 if (offset + head >= header->data_offset + header->data_size) 1060static int __cmd_timechart(void)
1097 goto done; 1061{
1062 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1063 int ret;
1098 1064
1099 if (offset + head < (unsigned long)statbuf.st_size) 1065 if (session == NULL)
1100 goto more; 1066 return -ENOMEM;
1101 1067
1102done: 1068 register_perf_file_handler(&file_handler);
1103 rc = EXIT_SUCCESS;
1104 close(input);
1105 1069
1070 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1071 if (ret)
1072 goto out_delete;
1106 1073
1107 process_samples(); 1074 process_samples();
1108 1075
@@ -1112,9 +1079,11 @@ done:
1112 1079
1113 write_svg_file(output_name); 1080 write_svg_file(output_name);
1114 1081
1115 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1082 pr_info("Written %2.1f seconds of trace to %s.\n",
1116 1083 (last_time - first_time) / 1000000000.0, output_name);
1117 return rc; 1084out_delete:
1085 perf_session__delete(session);
1086 return ret;
1118} 1087}
1119 1088
1120static const char * const timechart_usage[] = { 1089static const char * const timechart_usage[] = {
@@ -1153,6 +1122,14 @@ static int __cmd_record(int argc, const char **argv)
1153 return cmd_record(i, rec_argv, NULL); 1122 return cmd_record(i, rec_argv, NULL);
1154} 1123}
1155 1124
1125static int
1126parse_process(const struct option *opt __used, const char *arg, int __used unset)
1127{
1128 if (arg)
1129 add_process_filter(arg);
1130 return 0;
1131}
1132
1156static const struct option options[] = { 1133static const struct option options[] = {
1157 OPT_STRING('i', "input", &input_name, "file", 1134 OPT_STRING('i', "input", &input_name, "file",
1158 "input file name"), 1135 "input file name"),
@@ -1160,17 +1137,18 @@ static const struct option options[] = {
1160 "output file name"), 1137 "output file name"),
1161 OPT_INTEGER('w', "width", &svg_page_width, 1138 OPT_INTEGER('w', "width", &svg_page_width,
1162 "page width"), 1139 "page width"),
1163 OPT_BOOLEAN('p', "power-only", &power_only, 1140 OPT_BOOLEAN('P', "power-only", &power_only,
1164 "output power data only"), 1141 "output power data only"),
1142 OPT_CALLBACK('p', "process", NULL, "process",
1143 "process selector. Pass a pid or process name.",
1144 parse_process),
1165 OPT_END() 1145 OPT_END()
1166}; 1146};
1167 1147
1168 1148
1169int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1149int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1170{ 1150{
1171 symbol__init(); 1151 symbol__init(0);
1172
1173 page_size = getpagesize();
1174 1152
1175 argc = parse_options(argc, argv, options, timechart_usage, 1153 argc = parse_options(argc, argv, options, timechart_usage,
1176 PARSE_OPT_STOP_AT_NON_OPTION); 1154 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..0756664666f1 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -5,256 +5,288 @@
5#include "util/symbol.h" 5#include "util/symbol.h"
6#include "util/thread.h" 6#include "util/thread.h"
7#include "util/header.h" 7#include "util/header.h"
8#include "util/exec_cmd.h"
9#include "util/trace-event.h"
10#include "util/session.h"
8 11
9#include "util/parse-options.h" 12static char const *script_name;
13static char const *generate_script_lang;
10 14
11#include "perf.h" 15static int default_start_script(const char *script __attribute((unused)))
12#include "util/debug.h" 16{
17 return 0;
18}
13 19
14#include "util/trace-event.h" 20static int default_stop_script(void)
21{
22 return 0;
23}
24
25static int default_generate_script(const char *outfile __attribute ((unused)))
26{
27 return 0;
28}
15 29
16static char const *input_name = "perf.data"; 30static struct scripting_ops default_scripting_ops = {
17static int input; 31 .start_script = default_start_script,
18static unsigned long page_size; 32 .stop_script = default_stop_script,
19static unsigned long mmap_window = 32; 33 .process_event = print_event,
34 .generate_script = default_generate_script,
35};
20 36
21static unsigned long total = 0; 37static struct scripting_ops *scripting_ops;
22static unsigned long total_comm = 0;
23 38
24static struct rb_root threads; 39static void setup_scripting(void)
25static struct thread *last_match; 40{
41 /* make sure PERF_EXEC_PATH is set for scripts */
42 perf_set_argv_exec_path(perf_exec_path());
26 43
27static struct perf_header *header; 44 setup_perl_scripting();
28static u64 sample_type;
29 45
46 scripting_ops = &default_scripting_ops;
47}
30 48
31static int 49static int cleanup_scripting(void)
32process_comm_event(event_t *event, unsigned long offset, unsigned long head)
33{ 50{
34 struct thread *thread; 51 return scripting_ops->stop_script();
52}
35 53
36 thread = threads__findnew(event->comm.pid, &threads, &last_match); 54#include "util/parse-options.h"
37 55
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 56#include "perf.h"
39 (void *)(offset + head), 57#include "util/debug.h"
40 (void *)(long)(event->header.size),
41 event->comm.comm, event->comm.pid);
42 58
43 if (thread == NULL || 59#include "util/trace-event.h"
44 thread__set_comm(thread, event->comm.comm)) { 60#include "util/data_map.h"
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 61#include "util/exec_cmd.h"
46 return -1;
47 }
48 total_comm++;
49 62
50 return 0; 63static char const *input_name = "perf.data";
51}
52 64
53static int 65static struct perf_session *session;
54process_sample_event(event_t *event, unsigned long offset, unsigned long head) 66static u64 sample_type;
67
68static int process_sample_event(event_t *event)
55{ 69{
56 char level; 70 struct sample_data data;
57 int show = 0;
58 struct dso *dso = NULL;
59 struct thread *thread; 71 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 72
74 if (sample_type & PERF_SAMPLE_CPU) { 73 memset(&data, 0, sizeof(data));
75 cpu = *(u32 *)more_data; 74 data.time = -1;
76 more_data += sizeof(u32); 75 data.cpu = -1;
77 more_data += sizeof(u32); /* reserved */ 76 data.period = 1;
78 }
79 77
80 if (sample_type & PERF_SAMPLE_PERIOD) { 78 event__parse_sample(event, sample_type, &data);
81 period = *(u64 *)more_data;
82 more_data += sizeof(u64);
83 }
84 79
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 80 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
86 (void *)(offset + head),
87 (void *)(long)(event->header.size),
88 event->header.misc, 81 event->header.misc,
89 event->ip.pid, event->ip.tid, 82 data.pid, data.tid,
90 (void *)(long)ip, 83 (void *)(long)data.ip,
91 (long long)period); 84 (long long)data.period);
92
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
94 85
86 thread = threads__findnew(event->ip.pid);
95 if (thread == NULL) { 87 if (thread == NULL) {
96 eprintf("problem processing %d event, skipping it.\n", 88 pr_debug("problem processing %d event, skipping it.\n",
97 event->header.type); 89 event->header.type);
98 return -1; 90 return -1;
99 } 91 }
100 92
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) { 93 if (sample_type & PERF_SAMPLE_RAW) {
126 struct {
127 u32 size;
128 char data[0];
129 } *raw = more_data;
130
131 /* 94 /*
132 * FIXME: better resolve from pid from the struct trace_entry 95 * FIXME: better resolve from pid from the struct trace_entry
133 * field, although it should be the same than this perf 96 * field, although it should be the same than this perf
134 * event pid 97 * event pid
135 */ 98 */
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm); 99 scripting_ops->process_event(data.cpu, data.raw_data,
100 data.raw_size,
101 data.time, thread->comm);
137 } 102 }
138 total += period; 103 event__stats.total += data.period;
139 104
140 return 0; 105 return 0;
141} 106}
142 107
143static int 108static int sample_type_check(u64 type)
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{ 109{
146 trace_event(event); 110 sample_type = type;
147
148 switch (event->header.type) {
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST:
150 return 0;
151
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 111
161 case PERF_RECORD_MAX: 112 if (!(sample_type & PERF_SAMPLE_RAW)) {
162 default: 113 fprintf(stderr,
114 "No trace sample to read. Did you call perf record "
115 "without -R?");
163 return -1; 116 return -1;
164 } 117 }
165 118
166 return 0; 119 return 0;
167} 120}
168 121
122static struct perf_file_handler file_handler = {
123 .process_sample_event = process_sample_event,
124 .process_comm_event = event__process_comm,
125 .sample_type_check = sample_type_check,
126};
127
169static int __cmd_trace(void) 128static int __cmd_trace(void)
170{ 129{
171 int ret, rc = EXIT_FAILURE; 130 int err;
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187 131
188 ret = fstat(input, &perf_stat); 132 session = perf_session__new(input_name, O_RDONLY, 0);
189 if (ret < 0) { 133 if (session == NULL)
190 perror("failed to stat file"); 134 return -ENOMEM;
191 exit(-1);
192 }
193 135
194 if (!perf_stat.st_size) { 136 register_idle_thread();
195 fprintf(stderr, "zero-sized file, nothing to do!\n"); 137 register_perf_file_handler(&file_handler);
196 exit(0);
197 }
198 header = perf_header__read(input);
199 head = header->data_offset;
200 sample_type = perf_header__sample_type(header);
201 138
202 if (!(sample_type & PERF_SAMPLE_RAW)) 139 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
203 die("No trace sample to read. Did you call perf record " 140 perf_session__delete(session);
204 "without -R?"); 141 return err;
142}
205 143
206 if (load_kernel() < 0) { 144struct script_spec {
207 perror("failed to load kernel symbols"); 145 struct list_head node;
208 return EXIT_FAILURE; 146 struct scripting_ops *ops;
209 } 147 char spec[0];
148};
149
150LIST_HEAD(script_specs);
210 151
211remap: 152static struct script_spec *script_spec__new(const char *spec,
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 153 struct scripting_ops *ops)
213 MAP_SHARED, input, offset); 154{
214 if (buf == MAP_FAILED) { 155 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
215 perror("failed to mmap file"); 156
216 exit(-1); 157 if (s != NULL) {
158 strcpy(s->spec, spec);
159 s->ops = ops;
217 } 160 }
218 161
219more: 162 return s;
220 event = (event_t *)(buf + head); 163}
164
165static void script_spec__delete(struct script_spec *s)
166{
167 free(s->spec);
168 free(s);
169}
221 170
222 if (head + event->header.size >= page_size * mmap_window) { 171static void script_spec__add(struct script_spec *s)
223 unsigned long shift = page_size * (head / page_size); 172{
224 int res; 173 list_add_tail(&s->node, &script_specs);
174}
225 175
226 res = munmap(buf, page_size * mmap_window); 176static struct script_spec *script_spec__find(const char *spec)
227 assert(res == 0); 177{
178 struct script_spec *s;
228 179
229 offset += shift; 180 list_for_each_entry(s, &script_specs, node)
230 head -= shift; 181 if (strcasecmp(s->spec, spec) == 0)
231 goto remap; 182 return s;
232 } 183 return NULL;
184}
233 185
234 size = event->header.size; 186static struct script_spec *script_spec__findnew(const char *spec,
187 struct scripting_ops *ops)
188{
189 struct script_spec *s = script_spec__find(spec);
235 190
236 if (!size || process_event(event, offset, head) < 0) { 191 if (s)
192 return s;
237 193
238 /* 194 s = script_spec__new(spec, ops);
239 * assume we lost track of the stream, check alignment, and 195 if (!s)
240 * increment a single u64 in the hope to catch on again 'soon'. 196 goto out_delete_spec;
241 */
242 197
243 if (unlikely(head & 7)) 198 script_spec__add(s);
244 head &= ~7ULL;
245 199
246 size = 8; 200 return s;
247 } 201
202out_delete_spec:
203 script_spec__delete(s);
204
205 return NULL;
206}
207
208int script_spec_register(const char *spec, struct scripting_ops *ops)
209{
210 struct script_spec *s;
211
212 s = script_spec__find(spec);
213 if (s)
214 return -1;
215
216 s = script_spec__findnew(spec, ops);
217 if (!s)
218 return -1;
248 219
249 head += size; 220 return 0;
221}
222
223static struct scripting_ops *script_spec__lookup(const char *spec)
224{
225 struct script_spec *s = script_spec__find(spec);
226 if (!s)
227 return NULL;
228
229 return s->ops;
230}
231
232static void list_available_languages(void)
233{
234 struct script_spec *s;
235
236 fprintf(stderr, "\n");
237 fprintf(stderr, "Scripting language extensions (used in "
238 "perf trace -s [spec:]script.[spec]):\n\n");
239
240 list_for_each_entry(s, &script_specs, node)
241 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
242
243 fprintf(stderr, "\n");
244}
245
246static int parse_scriptname(const struct option *opt __used,
247 const char *str, int unset __used)
248{
249 char spec[PATH_MAX];
250 const char *script, *ext;
251 int len;
250 252
251 if (offset + head < (unsigned long)perf_stat.st_size) 253 if (strcmp(str, "list") == 0) {
252 goto more; 254 list_available_languages();
255 return 0;
256 }
253 257
254 rc = EXIT_SUCCESS; 258 script = strchr(str, ':');
255 close(input); 259 if (script) {
260 len = script - str;
261 if (len >= PATH_MAX) {
262 fprintf(stderr, "invalid language specifier");
263 return -1;
264 }
265 strncpy(spec, str, len);
266 spec[len] = '\0';
267 scripting_ops = script_spec__lookup(spec);
268 if (!scripting_ops) {
269 fprintf(stderr, "invalid language specifier");
270 return -1;
271 }
272 script++;
273 } else {
274 script = str;
275 ext = strchr(script, '.');
276 if (!ext) {
277 fprintf(stderr, "invalid script extension");
278 return -1;
279 }
280 scripting_ops = script_spec__lookup(++ext);
281 if (!scripting_ops) {
282 fprintf(stderr, "invalid script extension");
283 return -1;
284 }
285 }
256 286
257 return rc; 287 script_name = strdup(script);
288
289 return 0;
258} 290}
259 291
260static const char * const annotate_usage[] = { 292static const char * const annotate_usage[] = {
@@ -267,13 +299,24 @@ static const struct option options[] = {
267 "dump raw trace in ASCII"), 299 "dump raw trace in ASCII"),
268 OPT_BOOLEAN('v', "verbose", &verbose, 300 OPT_BOOLEAN('v', "verbose", &verbose,
269 "be more verbose (show symbol address, etc)"), 301 "be more verbose (show symbol address, etc)"),
302 OPT_BOOLEAN('l', "latency", &latency_format,
303 "show latency attributes (irqs/preemption disabled, etc)"),
304 OPT_CALLBACK('s', "script", NULL, "name",
305 "script file name (lang:script name, script name, or *)",
306 parse_scriptname),
307 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
308 "generate perf-trace.xx script in specified language"),
309
270 OPT_END() 310 OPT_END()
271}; 311};
272 312
273int cmd_trace(int argc, const char **argv, const char *prefix __used) 313int cmd_trace(int argc, const char **argv, const char *prefix __used)
274{ 314{
275 symbol__init(); 315 int err;
276 page_size = getpagesize(); 316
317 symbol__init(0);
318
319 setup_scripting();
277 320
278 argc = parse_options(argc, argv, options, annotate_usage, 0); 321 argc = parse_options(argc, argv, options, annotate_usage, 0);
279 if (argc) { 322 if (argc) {
@@ -287,5 +330,46 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
287 330
288 setup_pager(); 331 setup_pager();
289 332
290 return __cmd_trace(); 333 if (generate_script_lang) {
334 struct stat perf_stat;
335
336 int input = open(input_name, O_RDONLY);
337 if (input < 0) {
338 perror("failed to open file");
339 exit(-1);
340 }
341
342 err = fstat(input, &perf_stat);
343 if (err < 0) {
344 perror("failed to stat file");
345 exit(-1);
346 }
347
348 if (!perf_stat.st_size) {
349 fprintf(stderr, "zero-sized file, nothing to do!\n");
350 exit(0);
351 }
352
353 scripting_ops = script_spec__lookup(generate_script_lang);
354 if (!scripting_ops) {
355 fprintf(stderr, "invalid language specifier");
356 return -1;
357 }
358
359 perf_header__read(&session->header, input);
360 err = scripting_ops->generate_script("perf-trace");
361 goto out;
362 }
363
364 if (script_name) {
365 err = scripting_ops->start_script(script_name);
366 if (err)
367 goto out;
368 }
369
370 err = __cmd_trace();
371
372 cleanup_scripting();
373out:
374 return err;
291} 375}
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..75f941bfba9e 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -47,6 +47,30 @@
47#define cpu_relax() asm volatile("":::"memory") 47#define cpu_relax() asm volatile("":::"memory")
48#endif 48#endif
49 49
50#ifdef __alpha__
51#include "../../arch/alpha/include/asm/unistd.h"
52#define rmb() asm volatile("mb" ::: "memory")
53#define cpu_relax() asm volatile("" ::: "memory")
54#endif
55
56#ifdef __ia64__
57#include "../../arch/ia64/include/asm/unistd.h"
58#define rmb() asm volatile ("mf" ::: "memory")
59#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
60#endif
61
62#ifdef __arm__
63#include "../../arch/arm/include/asm/unistd.h"
64/*
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory")
72#endif
73
50#include <time.h> 74#include <time.h>
51#include <unistd.h> 75#include <unistd.h>
52#include <sys/types.h> 76#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..6d46dda53a29
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,242 @@
1#include "data_map.h"
2#include "symbol.h"
3#include "util.h"
4#include "debug.h"
5
6
7static struct perf_file_handler *curr_handler;
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{
13 dump_printf(": unhandled!\n");
14 return 0;
15}
16
17void register_perf_file_handler(struct perf_file_handler *handler)
18{
19 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub;
21 if (!handler->process_mmap_event)
22 handler->process_mmap_event = process_event_stub;
23 if (!handler->process_comm_event)
24 handler->process_comm_event = process_event_stub;
25 if (!handler->process_fork_event)
26 handler->process_fork_event = process_event_stub;
27 if (!handler->process_exit_event)
28 handler->process_exit_event = process_event_stub;
29 if (!handler->process_lost_event)
30 handler->process_lost_event = process_event_stub;
31 if (!handler->process_read_event)
32 handler->process_read_event = process_event_stub;
33 if (!handler->process_throttle_event)
34 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39}
40
41static const char *event__name[] = {
42 [0] = "TOTAL",
43 [PERF_RECORD_MMAP] = "MMAP",
44 [PERF_RECORD_LOST] = "LOST",
45 [PERF_RECORD_COMM] = "COMM",
46 [PERF_RECORD_EXIT] = "EXIT",
47 [PERF_RECORD_THROTTLE] = "THROTTLE",
48 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
49 [PERF_RECORD_FORK] = "FORK",
50 [PERF_RECORD_READ] = "READ",
51 [PERF_RECORD_SAMPLE] = "SAMPLE",
52};
53
54unsigned long event__total[PERF_RECORD_MAX];
55
56void event__print_totals(void)
57{
58 int i;
59 for (i = 0; i < PERF_RECORD_MAX; ++i)
60 pr_info("%10s events: %10ld\n",
61 event__name[i], event__total[i]);
62}
63
64static int
65process_event(event_t *event, unsigned long offset, unsigned long head)
66{
67 trace_event(event);
68
69 if (event->header.type < PERF_RECORD_MAX) {
70 dump_printf("%p [%p]: PERF_RECORD_%s",
71 (void *)(offset + head),
72 (void *)(long)(event->header.size),
73 event__name[event->header.type]);
74 ++event__total[0];
75 ++event__total[event->header.type];
76 }
77
78 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event);
81 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event);
83 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event);
85 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event);
87 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event);
89 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event);
91 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event);
93 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event);
95 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event);
97 default:
98 curr_handler->total_unknown++;
99 return -1;
100 }
101}
102
103int perf_header__read_build_ids(int input, u64 offset, u64 size)
104{
105 struct build_id_event bev;
106 char filename[PATH_MAX];
107 u64 limit = offset + size;
108 int err = -1;
109
110 while (offset < limit) {
111 struct dso *dso;
112 ssize_t len;
113
114 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
115 goto out;
116
117 len = bev.header.size - sizeof(bev);
118 if (read(input, filename, len) != len)
119 goto out;
120
121 dso = dsos__findnew(filename);
122 if (dso != NULL)
123 dso__set_build_id(dso, &bev.build_id);
124
125 offset += bev.header.size;
126 }
127 err = 0;
128out:
129 return err;
130}
131
132int perf_session__process_events(struct perf_session *self,
133 int full_paths, int *cwdlen, char **cwd)
134{
135 int err;
136 unsigned long head, shift;
137 unsigned long offset = 0;
138 size_t page_size;
139 u64 sample_type;
140 event_t *event;
141 uint32_t size;
142 char *buf;
143
144 if (curr_handler == NULL) {
145 pr_debug("Forgot to register perf file handler\n");
146 return -EINVAL;
147 }
148
149 page_size = getpagesize();
150
151 head = self->header.data_offset;
152 sample_type = perf_header__sample_type(&self->header);
153
154 err = -EINVAL;
155 if (curr_handler->sample_type_check &&
156 curr_handler->sample_type_check(sample_type) < 0)
157 goto out_err;
158
159 if (!full_paths) {
160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
161 pr_err("failed to get the current directory\n");
162 err = -errno;
163 goto out_err;
164 }
165 *cwd = __cwd;
166 *cwdlen = strlen(*cwd);
167 } else {
168 *cwd = NULL;
169 *cwdlen = 0;
170 }
171
172 shift = page_size * (head / page_size);
173 offset += shift;
174 head -= shift;
175
176remap:
177 buf = mmap(NULL, page_size * mmap_window, PROT_READ,
178 MAP_SHARED, self->fd, offset);
179 if (buf == MAP_FAILED) {
180 pr_err("failed to mmap file\n");
181 err = -errno;
182 goto out_err;
183 }
184
185more:
186 event = (event_t *)(buf + head);
187
188 size = event->header.size;
189 if (!size)
190 size = 8;
191
192 if (head + event->header.size >= page_size * mmap_window) {
193 int munmap_ret;
194
195 shift = page_size * (head / page_size);
196
197 munmap_ret = munmap(buf, page_size * mmap_window);
198 assert(munmap_ret == 0);
199
200 offset += shift;
201 head -= shift;
202 goto remap;
203 }
204
205 size = event->header.size;
206
207 dump_printf("\n%p [%p]: event: %d\n",
208 (void *)(offset + head),
209 (void *)(long)event->header.size,
210 event->header.type);
211
212 if (!size || process_event(event, offset, head) < 0) {
213
214 dump_printf("%p [%p]: skipping unknown header type: %d\n",
215 (void *)(offset + head),
216 (void *)(long)(event->header.size),
217 event->header.type);
218
219 /*
220 * assume we lost track of the stream, check alignment, and
221 * increment a single u64 in the hope to catch on again 'soon'.
222 */
223
224 if (unlikely(head & 7))
225 head &= ~7ULL;
226
227 size = 8;
228 }
229
230 head += size;
231
232 if (offset + head >= self->header.data_offset + self->header.data_size)
233 goto done;
234
235 if (offset + head < self->size)
236 goto more;
237
238done:
239 err = 0;
240out_err:
241 return err;
242}
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
new file mode 100644
index 000000000000..98c5b823388c
--- /dev/null
+++ b/tools/perf/util/data_map.h
@@ -0,0 +1,29 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6#include "session.h"
7
8typedef int (*event_type_handler_t)(event_t *);
9
10struct perf_file_handler {
11 event_type_handler_t process_sample_event;
12 event_type_handler_t process_mmap_event;
13 event_type_handler_t process_comm_event;
14 event_type_handler_t process_fork_event;
15 event_type_handler_t process_exit_event;
16 event_type_handler_t process_lost_event;
17 event_type_handler_t process_read_event;
18 event_type_handler_t process_throttle_event;
19 event_type_handler_t process_unthrottle_event;
20 int (*sample_type_check)(u64 sample_type);
21 unsigned long total_unknown;
22};
23
24void register_perf_file_handler(struct perf_file_handler *handler);
25int perf_session__process_events(struct perf_session *self,
26 int full_paths, int *cwdlen, char **cwd);
27int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
28
29#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 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..ba0de90cd3d4
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,380 @@
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 map_groups *mg = &self->mg;
258
259 al->thread = self;
260 al->addr = addr;
261
262 if (cpumode & PERF_RECORD_MISC_KERNEL) {
263 al->level = 'k';
264 mg = kmaps;
265 } else if (cpumode & PERF_RECORD_MISC_USER)
266 al->level = '.';
267 else {
268 al->level = 'H';
269 al->map = NULL;
270 al->sym = NULL;
271 return;
272 }
273try_again:
274 al->map = map_groups__find(mg, type, al->addr);
275 if (al->map == NULL) {
276 /*
277 * If this is outside of all known maps, and is a negative
278 * address, try to look it up in the kernel dso, as it might be
279 * a vsyscall or vdso (which executes in user-mode).
280 *
281 * XXX This is nasty, we should have a symbol list in the
282 * "[vdso]" dso, but for now lets use the old trick of looking
283 * in the whole kernel symbol list.
284 */
285 if ((long long)al->addr < 0 && mg != kmaps) {
286 mg = kmaps;
287 goto try_again;
288 }
289 al->sym = NULL;
290 } else {
291 al->addr = al->map->map_ip(al->map, al->addr);
292 al->sym = map__find_symbol(al->map, al->addr, filter);
293 }
294}
295
296int event__preprocess_sample(const event_t *self, struct addr_location *al,
297 symbol_filter_t filter)
298{
299 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
300 struct thread *thread = threads__findnew(self->ip.pid);
301
302 if (thread == NULL)
303 return -1;
304
305 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
306
307 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
308 self->ip.ip, al, filter);
309 dump_printf(" ...... dso: %s\n",
310 al->map ? al->map->dso->long_name :
311 al->level == 'H' ? "[hypervisor]" : "<not found>");
312 return 0;
313}
314
315int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
316{
317 u64 *array = event->sample.array;
318
319 if (type & PERF_SAMPLE_IP) {
320 data->ip = event->ip.ip;
321 array++;
322 }
323
324 if (type & PERF_SAMPLE_TID) {
325 u32 *p = (u32 *)array;
326 data->pid = p[0];
327 data->tid = p[1];
328 array++;
329 }
330
331 if (type & PERF_SAMPLE_TIME) {
332 data->time = *array;
333 array++;
334 }
335
336 if (type & PERF_SAMPLE_ADDR) {
337 data->addr = *array;
338 array++;
339 }
340
341 if (type & PERF_SAMPLE_ID) {
342 data->id = *array;
343 array++;
344 }
345
346 if (type & PERF_SAMPLE_STREAM_ID) {
347 data->stream_id = *array;
348 array++;
349 }
350
351 if (type & PERF_SAMPLE_CPU) {
352 u32 *p = (u32 *)array;
353 data->cpu = *p;
354 array++;
355 }
356
357 if (type & PERF_SAMPLE_PERIOD) {
358 data->period = *array;
359 array++;
360 }
361
362 if (type & PERF_SAMPLE_READ) {
363 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
364 return -1;
365 }
366
367 if (type & PERF_SAMPLE_CALLCHAIN) {
368 data->callchain = (struct ip_callchain *)array;
369 array += 1 + data->callchain->nr;
370 }
371
372 if (type & PERF_SAMPLE_RAW) {
373 u32 *p = (u32 *)array;
374 data->raw_size = *p;
375 p++;
376 data->raw_data = p;
377 }
378
379 return 0;
380}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..51a96c2effde 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,31 @@ 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 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
80struct map { 111struct map {
81 struct list_head node; 112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
82 u64 start; 116 u64 start;
83 u64 end; 117 u64 end;
118 enum map_type type;
84 u64 pgoff; 119 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64); 120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
86 struct dso *dso; 122 struct dso *dso;
87}; 123};
88 124
@@ -91,14 +127,51 @@ static inline u64 map__map_ip(struct map *map, u64 ip)
91 return ip - map->start + map->pgoff; 127 return ip - map->start + map->pgoff;
92} 128}
93 129
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip) 130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
95{ 136{
96 return ip; 137 return ip;
97} 138}
98 139
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); 140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
100struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
152struct symbol *map__find_symbol(struct map *self, u64 addr,
153 symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
155 symbol_filter_t filter);
156void map__fixup_start(struct map *self);
157void map__fixup_end(struct map *self);
158
159int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
160void event__synthesize_threads(int (*process)(event_t *event));
161
162extern char *event__cwd;
163extern int event__cwdlen;
164extern struct events_stats event__stats;
165extern unsigned long event__total[PERF_RECORD_MAX];
166
167int event__process_comm(event_t *self);
168int event__process_lost(event_t *self);
169int event__process_mmap(event_t *self);
170int event__process_task(event_t *self);
171
172struct addr_location;
173int event__preprocess_sample(const event_t *self, struct addr_location *al,
174 symbol_filter_t filter);
175int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
103 176
104#endif 177#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..f2e8d8715111 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,75 +19,80 @@ 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/* 61int perf_header__init(struct perf_header *self)
45 * Create new perf.data header:
46 */
47struct perf_header *perf_header__new(void)
48{ 62{
49 struct perf_header *self = malloc(sizeof(*self));
50
51 if (!self)
52 die("nomem");
53
54 self->frozen = 0;
55
56 self->attrs = 0;
57 self->size = 1; 63 self->size = 1;
58 self->attr = malloc(sizeof(void *)); 64 self->attr = malloc(sizeof(void *));
59 65 return self->attr == NULL ? -ENOMEM : 0;
60 if (!self->attr)
61 die("nomem");
62
63 self->data_offset = 0;
64 self->data_size = 0;
65
66 return self;
67} 66}
68 67
69void perf_header__add_attr(struct perf_header *self, 68void perf_header__exit(struct perf_header *self)
70 struct perf_header_attr *attr)
71{ 69{
72 int pos = self->attrs; 70 int i;
71 for (i = 0; i < self->attrs; ++i)
72 perf_header_attr__delete(self->attr[i]);
73 free(self->attr);
74}
73 75
76int perf_header__add_attr(struct perf_header *self,
77 struct perf_header_attr *attr)
78{
74 if (self->frozen) 79 if (self->frozen)
75 die("frozen"); 80 return -1;
76 81
77 self->attrs++; 82 if (self->attrs == self->size) {
78 if (self->attrs > self->size) { 83 int nsize = self->size * 2;
79 self->size *= 2; 84 struct perf_header_attr **nattr;
80 self->attr = realloc(self->attr, self->size * sizeof(void *)); 85
81 if (!self->attr) 86 nattr = realloc(self->attr, nsize * sizeof(void *));
82 die("nomem"); 87 if (nattr == NULL)
88 return -1;
89
90 self->size = nsize;
91 self->attr = nattr;
83 } 92 }
84 self->attr[pos] = attr; 93
94 self->attr[self->attrs++] = attr;
95 return 0;
85} 96}
86 97
87#define MAX_EVENT_NAME 64 98#define MAX_EVENT_NAME 64
@@ -97,7 +108,7 @@ static struct perf_trace_event_type *events;
97void perf_header__push_event(u64 id, const char *name) 108void perf_header__push_event(u64 id, const char *name)
98{ 109{
99 if (strlen(name) > MAX_EVENT_NAME) 110 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name); 111 pr_warning("Event %s will be truncated\n", name);
101 112
102 if (!events) { 113 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type)); 114 events = malloc(sizeof(struct perf_trace_event_type));
@@ -128,44 +139,142 @@ static const char *__perf_magic = "PERFFILE";
128 139
129#define PERF_MAGIC (*(u64 *)__perf_magic) 140#define PERF_MAGIC (*(u64 *)__perf_magic)
130 141
131struct perf_file_section {
132 u64 offset;
133 u64 size;
134};
135
136struct perf_file_attr { 142struct perf_file_attr {
137 struct perf_event_attr attr; 143 struct perf_event_attr attr;
138 struct perf_file_section ids; 144 struct perf_file_section ids;
139}; 145};
140 146
141struct perf_file_header { 147void perf_header__set_feat(struct perf_header *self, int feat)
142 u64 magic; 148{
143 u64 size; 149 set_bit(feat, self->adds_features);
144 u64 attr_size; 150}
145 struct perf_file_section attrs; 151
146 struct perf_file_section data; 152bool perf_header__has_feat(const struct perf_header *self, int feat)
147 struct perf_file_section event_types; 153{
148}; 154 return test_bit(feat, self->adds_features);
155}
149 156
150static void do_write(int fd, void *buf, size_t size) 157static int do_write(int fd, const void *buf, size_t size)
151{ 158{
152 while (size) { 159 while (size) {
153 int ret = write(fd, buf, size); 160 int ret = write(fd, buf, size);
154 161
155 if (ret < 0) 162 if (ret < 0)
156 die("failed to write"); 163 return -errno;
157 164
158 size -= ret; 165 size -= ret;
159 buf += ret; 166 buf += ret;
160 } 167 }
168
169 return 0;
170}
171
172static int __dsos__write_buildid_table(struct list_head *head, int fd)
173{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN];
177
178 list_for_each_entry(pos, head, node) {
179 int err;
180 struct build_id_event b;
181 size_t len;
182
183 if (!pos->has_build_id)
184 continue;
185 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
189 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b));
191 if (err < 0)
192 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1);
194 if (err < 0)
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0)
198 return err;
199 }
200
201 return 0;
202}
203
204static int dsos__write_buildid_table(int fd)
205{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd);
207 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd);
209 return err;
210}
211
212static int perf_header__adds_write(struct perf_header *self, int fd)
213{
214 int nr_sections;
215 struct perf_file_section *feat_sec;
216 int sec_size;
217 u64 sec_start;
218 int idx = 0, err;
219
220 if (dsos__read_build_ids())
221 perf_header__set_feat(self, HEADER_BUILD_ID);
222
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
224 if (!nr_sections)
225 return 0;
226
227 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
228 if (feat_sec == NULL)
229 return -ENOMEM;
230
231 sec_size = sizeof(*feat_sec) * nr_sections;
232
233 sec_start = self->data_offset + self->data_size;
234 lseek(fd, sec_start + sec_size, SEEK_SET);
235
236 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
237 struct perf_file_section *trace_sec;
238
239 trace_sec = &feat_sec[idx++];
240
241 /* Write trace info */
242 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
243 read_tracing_data(fd, attrs, nr_counters);
244 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
245 }
246
247
248 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
249 struct perf_file_section *buildid_sec;
250
251 buildid_sec = &feat_sec[idx++];
252
253 /* Write build-ids */
254 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
255 err = dsos__write_buildid_table(fd);
256 if (err < 0) {
257 pr_debug("failed to write buildid table\n");
258 goto out_free;
259 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
261 }
262
263 lseek(fd, sec_start, SEEK_SET);
264 err = do_write(fd, feat_sec, sec_size);
265 if (err < 0)
266 pr_debug("failed to write feature section\n");
267out_free:
268 free(feat_sec);
269 return err;
161} 270}
162 271
163void perf_header__write(struct perf_header *self, int fd) 272int perf_header__write(struct perf_header *self, int fd, bool at_exit)
164{ 273{
165 struct perf_file_header f_header; 274 struct perf_file_header f_header;
166 struct perf_file_attr f_attr; 275 struct perf_file_attr f_attr;
167 struct perf_header_attr *attr; 276 struct perf_header_attr *attr;
168 int i; 277 int i, err;
169 278
170 lseek(fd, sizeof(f_header), SEEK_SET); 279 lseek(fd, sizeof(f_header), SEEK_SET);
171 280
@@ -174,7 +283,11 @@ void perf_header__write(struct perf_header *self, int fd)
174 attr = self->attr[i]; 283 attr = self->attr[i];
175 284
176 attr->id_offset = lseek(fd, 0, SEEK_CUR); 285 attr->id_offset = lseek(fd, 0, SEEK_CUR);
177 do_write(fd, attr->id, attr->ids * sizeof(u64)); 286 err = do_write(fd, attr->id, attr->ids * sizeof(u64));
287 if (err < 0) {
288 pr_debug("failed to write perf header\n");
289 return err;
290 }
178 } 291 }
179 292
180 293
@@ -190,17 +303,31 @@ void perf_header__write(struct perf_header *self, int fd)
190 .size = attr->ids * sizeof(u64), 303 .size = attr->ids * sizeof(u64),
191 } 304 }
192 }; 305 };
193 do_write(fd, &f_attr, sizeof(f_attr)); 306 err = do_write(fd, &f_attr, sizeof(f_attr));
307 if (err < 0) {
308 pr_debug("failed to write perf header attribute\n");
309 return err;
310 }
194 } 311 }
195 312
196 self->event_offset = lseek(fd, 0, SEEK_CUR); 313 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type); 314 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events) 315 if (events) {
199 do_write(fd, events, self->event_size); 316 err = do_write(fd, events, self->event_size);
200 317 if (err < 0) {
318 pr_debug("failed to write perf header events\n");
319 return err;
320 }
321 }
201 322
202 self->data_offset = lseek(fd, 0, SEEK_CUR); 323 self->data_offset = lseek(fd, 0, SEEK_CUR);
203 324
325 if (at_exit) {
326 err = perf_header__adds_write(self, fd);
327 if (err < 0)
328 return err;
329 }
330
204 f_header = (struct perf_file_header){ 331 f_header = (struct perf_file_header){
205 .magic = PERF_MAGIC, 332 .magic = PERF_MAGIC,
206 .size = sizeof(f_header), 333 .size = sizeof(f_header),
@@ -219,11 +346,18 @@ void perf_header__write(struct perf_header *self, int fd)
219 }, 346 },
220 }; 347 };
221 348
349 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
350
222 lseek(fd, 0, SEEK_SET); 351 lseek(fd, 0, SEEK_SET);
223 do_write(fd, &f_header, sizeof(f_header)); 352 err = do_write(fd, &f_header, sizeof(f_header));
353 if (err < 0) {
354 pr_debug("failed to write perf header\n");
355 return err;
356 }
224 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 357 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
225 358
226 self->frozen = 1; 359 self->frozen = 1;
360 return 0;
227} 361}
228 362
229static void do_read(int fd, void *buf, size_t size) 363static void do_read(int fd, void *buf, size_t size)
@@ -241,22 +375,109 @@ static void do_read(int fd, void *buf, size_t size)
241 } 375 }
242} 376}
243 377
244struct perf_header *perf_header__read(int fd) 378int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self,
380 int feat, int fd))
381{
382 struct perf_file_section *feat_sec;
383 int nr_sections;
384 int sec_size;
385 int idx = 0;
386 int err = 0, feat = 1;
387
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections)
390 return 0;
391
392 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
393 if (!feat_sec)
394 return -1;
395
396 sec_size = sizeof(*feat_sec) * nr_sections;
397
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399
400 do_read(fd, feat_sec, sec_size);
401
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++];
405
406 err = process(sec, feat, fd);
407 if (err < 0)
408 break;
409 }
410 ++feat;
411 }
412
413 free(feat_sec);
414 return err;
415};
416
417int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd)
419{
420 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422
423 if (self->magic != PERF_MAGIC ||
424 self->attr_size != sizeof(struct perf_file_attr))
425 return -1;
426
427 if (self->size != sizeof(*self)) {
428 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features))
430 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
431 else
432 return -1;
433 }
434
435 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features));
437
438 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size;
442 return 0;
443}
444
445static int perf_file_section__process(struct perf_file_section *self,
446 int feat, int fd)
447{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat);
451 return 0;
452 }
453
454 switch (feat) {
455 case HEADER_TRACE_INFO:
456 trace_report(fd);
457 break;
458
459 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n");
462 break;
463 default:
464 pr_debug("unknown feature %d, continuing...\n", feat);
465 }
466
467 return 0;
468}
469
470int perf_header__read(struct perf_header *self, int fd)
245{ 471{
246 struct perf_header *self = perf_header__new();
247 struct perf_file_header f_header; 472 struct perf_file_header f_header;
248 struct perf_file_attr f_attr; 473 struct perf_file_attr f_attr;
249 u64 f_id; 474 u64 f_id;
250
251 int nr_attrs, nr_ids, i, j; 475 int nr_attrs, nr_ids, i, j;
252 476
253 lseek(fd, 0, SEEK_SET); 477 if (perf_file_header__read(&f_header, self, fd) < 0) {
254 do_read(fd, &f_header, sizeof(f_header)); 478 pr_debug("incompatible file format\n");
255 479 return -EINVAL;
256 if (f_header.magic != PERF_MAGIC || 480 }
257 f_header.size != sizeof(f_header) ||
258 f_header.attr_size != sizeof(f_attr))
259 die("incompatible file format");
260 481
261 nr_attrs = f_header.attrs.size / sizeof(f_attr); 482 nr_attrs = f_header.attrs.size / sizeof(f_attr);
262 lseek(fd, f_header.attrs.offset, SEEK_SET); 483 lseek(fd, f_header.attrs.offset, SEEK_SET);
@@ -269,6 +490,8 @@ struct perf_header *perf_header__read(int fd)
269 tmp = lseek(fd, 0, SEEK_CUR); 490 tmp = lseek(fd, 0, SEEK_CUR);
270 491
271 attr = perf_header_attr__new(&f_attr.attr); 492 attr = perf_header_attr__new(&f_attr.attr);
493 if (attr == NULL)
494 return -ENOMEM;
272 495
273 nr_ids = f_attr.ids.size / sizeof(u64); 496 nr_ids = f_attr.ids.size / sizeof(u64);
274 lseek(fd, f_attr.ids.offset, SEEK_SET); 497 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -276,31 +499,34 @@ struct perf_header *perf_header__read(int fd)
276 for (j = 0; j < nr_ids; j++) { 499 for (j = 0; j < nr_ids; j++) {
277 do_read(fd, &f_id, sizeof(f_id)); 500 do_read(fd, &f_id, sizeof(f_id));
278 501
279 perf_header_attr__add_id(attr, f_id); 502 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr);
504 return -ENOMEM;
505 }
506 }
507 if (perf_header__add_attr(self, attr) < 0) {
508 perf_header_attr__delete(attr);
509 return -ENOMEM;
280 } 510 }
281 perf_header__add_attr(self, attr); 511
282 lseek(fd, tmp, SEEK_SET); 512 lseek(fd, tmp, SEEK_SET);
283 } 513 }
284 514
285 if (f_header.event_types.size) { 515 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET); 516 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size); 517 events = malloc(f_header.event_types.size);
288 if (!events) 518 if (events == NULL)
289 die("nomem"); 519 return -ENOMEM;
290 do_read(fd, events, f_header.event_types.size); 520 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 } 522 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295 523
296 self->data_offset = f_header.data.offset; 524 perf_header__process_sections(self, fd, perf_file_section__process);
297 self->data_size = f_header.data.size;
298 525
299 lseek(fd, self->data_offset, SEEK_SET); 526 lseek(fd, self->data_offset, SEEK_SET);
300 527
301 self->frozen = 1; 528 self->frozen = 1;
302 529 return 0;
303 return self;
304} 530}
305 531
306u64 perf_header__sample_type(struct perf_header *header) 532u64 perf_header__sample_type(struct perf_header *header)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a0761bc7863c..d118d05d3abe 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); 58int perf_header__init(struct perf_header *self);
27void perf_header__write(struct perf_header *self, int fd); 59void perf_header__exit(struct perf_header *self);
60
61int perf_header__read(struct perf_header *self, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit);
28 63
29void perf_header__add_attr(struct perf_header *self, 64int perf_header__add_attr(struct perf_header *self,
30 struct perf_header_attr *attr); 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..76bdca640a9b 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,93 @@ 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
107static int map__load(struct map *self, symbol_filter_t filter)
108{
109 const char *name = self->dso->long_name;
110 int nr = dso__load(self->dso, self, filter);
111
112 if (nr < 0) {
113 if (self->dso->has_build_id) {
114 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
115
116 build_id__sprintf(self->dso->build_id,
117 sizeof(self->dso->build_id),
118 sbuild_id);
119 pr_warning("%s with build id %s not found",
120 name, sbuild_id);
121 } else
122 pr_warning("Failed to open %s", name);
123
124 pr_warning(", continuing without symbols\n");
125 return -1;
126 } else if (nr == 0) {
127 const size_t len = strlen(name);
128 const size_t real_len = len - sizeof(DSO__DELETED);
129
130 if (len > sizeof(DSO__DELETED) &&
131 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
132 pr_warning("%.*s was updated, restart the long "
133 "running apps that use it!\n",
134 (int)real_len, name);
135 } else {
136 pr_warning("no symbols found in %s, maybe install "
137 "a debug package?\n", name);
138 }
139
140 return -1;
141 }
142
143 return 0;
144}
145
146struct symbol *map__find_symbol(struct map *self, u64 addr,
147 symbol_filter_t filter)
148{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
150 return NULL;
151
152 return dso__find_symbol(self->dso, self->type, addr);
153}
154
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
156 symbol_filter_t filter)
157{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
159 return NULL;
160
161 if (!dso__sorted_by_name(self->dso, self->type))
162 dso__sort_by_name(self->dso, self->type);
163
164 return dso__find_symbol_by_name(self->dso, self->type, name);
165}
166
67struct map *map__clone(struct map *self) 167struct map *map__clone(struct map *self)
68{ 168{
69 struct map *map = malloc(sizeof(*self)); 169 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/session.c b/tools/perf/util/session.c
new file mode 100644
index 000000000000..707ce1cb1621
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,80 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "util.h"
8
9static int perf_session__open(struct perf_session *self, bool force)
10{
11 struct stat input_stat;
12
13 self->fd = open(self->filename, O_RDONLY);
14 if (self->fd < 0) {
15 pr_err("failed to open file: %s", self->filename);
16 if (!strcmp(self->filename, "perf.data"))
17 pr_err(" (try 'perf record' first)");
18 pr_err("\n");
19 return -errno;
20 }
21
22 if (fstat(self->fd, &input_stat) < 0)
23 goto out_close;
24
25 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
26 pr_err("file %s not owned by current user or root\n",
27 self->filename);
28 goto out_close;
29 }
30
31 if (!input_stat.st_size) {
32 pr_info("zero-sized file (%s), nothing to do!\n",
33 self->filename);
34 goto out_close;
35 }
36
37 if (perf_header__read(&self->header, self->fd) < 0) {
38 pr_err("incompatible file format");
39 goto out_close;
40 }
41
42 self->size = input_stat.st_size;
43 return 0;
44
45out_close:
46 close(self->fd);
47 self->fd = -1;
48 return -1;
49}
50
51struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{
53 size_t len = strlen(filename) + 1;
54 struct perf_session *self = zalloc(sizeof(*self) + len);
55
56 if (self == NULL)
57 goto out;
58
59 if (perf_header__init(&self->header) < 0)
60 goto out_delete;
61
62 memcpy(self->filename, filename, len);
63
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) {
65 perf_session__delete(self);
66 self = NULL;
67 }
68out:
69 return self;
70out_delete:
71 free(self);
72 return NULL;
73}
74
75void perf_session__delete(struct perf_session *self)
76{
77 perf_header__exit(&self->header);
78 close(self->fd);
79 free(self);
80}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..f3699c8c8ed4
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,16 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "header.h"
5
6struct perf_session {
7 struct perf_header header;
8 unsigned long size;
9 int fd;
10 char filename[0];
11};
12
13struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self);
15
16#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..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..d3d9fed74f1d 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,209 @@ 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 *map__new2(u64 start, struct dso *dso, enum map_type type);
26 u64 obj_start, int v) 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
34 struct map_groups *mg, symbol_filter_t filter);
35unsigned int symbol__priv_size;
36static int vmlinux_path__nr_entries;
37static char **vmlinux_path;
38
39static struct symbol_conf symbol_conf__defaults = {
40 .use_modules = true,
41 .try_vmlinux_path = true,
42};
43
44static struct map_groups kmaps_mem;
45struct map_groups *kmaps = &kmaps_mem;
46
47bool dso__loaded(const struct dso *self, enum map_type type)
27{ 48{
28 size_t namelen = strlen(name) + 1; 49 return self->loaded & (1 << type);
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 50}
30 51
31 if (!self) 52bool dso__sorted_by_name(const struct dso *self, enum map_type type)
32 return NULL; 53{
54 return self->sorted_by_name & (1 << type);
55}
33 56
34 if (v >= 2) 57static void dso__set_loaded(struct dso *self, enum map_type type)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 58{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 59 self->loaded |= (1 << type);
60}
37 61
38 self->obj_start= obj_start; 62static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
39 self->hist = NULL; 63{
40 self->hist_sum = 0; 64 self->sorted_by_name |= (1 << type);
65}
41 66
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 67static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
43 self->hist = calloc(sizeof(u64), len); 68{
69 switch (map_type) {
70 case MAP__FUNCTION:
71 return symbol_type == 'T' || symbol_type == 'W';
72 case MAP__VARIABLE:
73 return symbol_type == 'D' || symbol_type == 'd';
74 default:
75 return false;
76 }
77}
78
79static void symbols__fixup_end(struct rb_root *self)
80{
81 struct rb_node *nd, *prevnd = rb_first(self);
82 struct symbol *curr, *prev;
44 83
45 if (priv_size) { 84 if (prevnd == NULL)
46 memset(self, 0, priv_size); 85 return;
47 self = ((void *)self) + priv_size; 86
87 curr = rb_entry(prevnd, struct symbol, rb_node);
88
89 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
90 prev = curr;
91 curr = rb_entry(nd, struct symbol, rb_node);
92
93 if (prev->end == prev->start)
94 prev->end = curr->start - 1;
48 } 95 }
96
97 /* Last entry */
98 if (curr->end == curr->start)
99 curr->end = roundup(curr->start, 4096);
100}
101
102static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
103{
104 struct map *prev, *curr;
105 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
106
107 if (prevnd == NULL)
108 return;
109
110 curr = rb_entry(prevnd, struct map, rb_node);
111
112 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
113 prev = curr;
114 curr = rb_entry(nd, struct map, rb_node);
115 prev->end = curr->start - 1;
116 }
117
118 /*
119 * We still haven't the actual symbols, so guess the
120 * last map final address.
121 */
122 curr->end = ~0UL;
123}
124
125static void map_groups__fixup_end(struct map_groups *self)
126{
127 int i;
128 for (i = 0; i < MAP__NR_TYPES; ++i)
129 __map_groups__fixup_end(self, i);
130}
131
132static struct symbol *symbol__new(u64 start, u64 len, const char *name)
133{
134 size_t namelen = strlen(name) + 1;
135 struct symbol *self = zalloc(symbol__priv_size +
136 sizeof(*self) + namelen);
137 if (self == NULL)
138 return NULL;
139
140 if (symbol__priv_size)
141 self = ((void *)self) + symbol__priv_size;
142
49 self->start = start; 143 self->start = start;
50 self->end = len ? start + len - 1 : start; 144 self->end = len ? start + len - 1 : start;
145
146 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
147
51 memcpy(self->name, name, namelen); 148 memcpy(self->name, name, namelen);
52 149
53 return self; 150 return self;
54} 151}
55 152
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 153static void symbol__delete(struct symbol *self)
57{ 154{
58 free(((void *)self) - priv_size); 155 free(((void *)self) - symbol__priv_size);
59} 156}
60 157
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 158static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 159{
63 if (!self->module) 160 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 161 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} 162}
70 163
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 164static void dso__set_long_name(struct dso *self, char *name)
165{
166 if (name == NULL)
167 return;
168 self->long_name = name;
169 self->long_name_len = strlen(name);
170}
171
172static void dso__set_basename(struct dso *self)
173{
174 self->short_name = basename(self->long_name);
175}
176
177struct dso *dso__new(const char *name)
72{ 178{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 179 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
74 180
75 if (self != NULL) { 181 if (self != NULL) {
182 int i;
76 strcpy(self->name, name); 183 strcpy(self->name, name);
77 self->syms = RB_ROOT; 184 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 185 self->short_name = self->name;
79 self->find_symbol = dso__find_symbol; 186 for (i = 0; i < MAP__NR_TYPES; ++i)
187 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
80 self->slen_calculated = 0; 188 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 189 self->origin = DSO__ORIG_NOT_FOUND;
190 self->loaded = 0;
191 self->sorted_by_name = 0;
192 self->has_build_id = 0;
82 } 193 }
83 194
84 return self; 195 return self;
85} 196}
86 197
87static void dso__delete_symbols(struct dso *self) 198static void symbols__delete(struct rb_root *self)
88{ 199{
89 struct symbol *pos; 200 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 201 struct rb_node *next = rb_first(self);
91 202
92 while (next) { 203 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 204 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 205 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 206 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 207 symbol__delete(pos);
97 } 208 }
98} 209}
99 210
100void dso__delete(struct dso *self) 211void dso__delete(struct dso *self)
101{ 212{
102 dso__delete_symbols(self); 213 int i;
214 for (i = 0; i < MAP__NR_TYPES; ++i)
215 symbols__delete(&self->symbols[i]);
216 if (self->long_name != self->name)
217 free(self->long_name);
103 free(self); 218 free(self);
104} 219}
105 220
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 221void dso__set_build_id(struct dso *self, void *build_id)
222{
223 memcpy(self->build_id, build_id, sizeof(self->build_id));
224 self->has_build_id = 1;
225}
226
227static void symbols__insert(struct rb_root *self, struct symbol *sym)
107{ 228{
108 struct rb_node **p = &self->syms.rb_node; 229 struct rb_node **p = &self->rb_node;
109 struct rb_node *parent = NULL; 230 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 231 const u64 ip = sym->start;
111 struct symbol *s; 232 struct symbol *s;
@@ -119,17 +240,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 240 p = &(*p)->rb_right;
120 } 241 }
121 rb_link_node(&sym->rb_node, parent, p); 242 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 243 rb_insert_color(&sym->rb_node, self);
123} 244}
124 245
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 246static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 247{
127 struct rb_node *n; 248 struct rb_node *n;
128 249
129 if (self == NULL) 250 if (self == NULL)
130 return NULL; 251 return NULL;
131 252
132 n = self->syms.rb_node; 253 n = self->rb_node;
133 254
134 while (n) { 255 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 256 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +266,116 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 266 return NULL;
146} 267}
147 268
148size_t dso__fprintf(struct dso *self, FILE *fp) 269struct symbol_name_rb_node {
270 struct rb_node rb_node;
271 struct symbol sym;
272};
273
274static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
149{ 275{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 276 struct rb_node **p = &self->rb_node;
277 struct rb_node *parent = NULL;
278 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
279
280 while (*p != NULL) {
281 parent = *p;
282 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
283 if (strcmp(sym->name, s->sym.name) < 0)
284 p = &(*p)->rb_left;
285 else
286 p = &(*p)->rb_right;
287 }
288 rb_link_node(&symn->rb_node, parent, p);
289 rb_insert_color(&symn->rb_node, self);
290}
151 291
292static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
293{
152 struct rb_node *nd; 294 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 295
296 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
297 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
298 symbols__insert_by_name(self, pos);
299 }
300}
301
302static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
303{
304 struct rb_node *n;
305
306 if (self == NULL)
307 return NULL;
308
309 n = self->rb_node;
310
311 while (n) {
312 struct symbol_name_rb_node *s;
313 int cmp;
314
315 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
316 cmp = strcmp(name, s->sym.name);
317
318 if (cmp < 0)
319 n = n->rb_left;
320 else if (cmp > 0)
321 n = n->rb_right;
322 else
323 return &s->sym;
324 }
325
326 return NULL;
327}
328
329struct symbol *dso__find_symbol(struct dso *self,
330 enum map_type type, u64 addr)
331{
332 return symbols__find(&self->symbols[type], addr);
333}
334
335struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
336 const char *name)
337{
338 return symbols__find_by_name(&self->symbol_names[type], name);
339}
340
341void dso__sort_by_name(struct dso *self, enum map_type type)
342{
343 dso__set_sorted_by_name(self, type);
344 return symbols__sort_by_name(&self->symbol_names[type],
345 &self->symbols[type]);
346}
347
348int build_id__sprintf(u8 *self, int len, char *bf)
349{
350 char *bid = bf;
351 u8 *raw = self;
352 int i;
353
354 for (i = 0; i < len; ++i) {
355 sprintf(bid, "%02x", *raw);
356 ++raw;
357 bid += 2;
358 }
359
360 return raw - self;
361}
362
363size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
364{
365 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
366
367 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
368 return fprintf(fp, "%s", sbuild_id);
369}
370
371size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
372{
373 struct rb_node *nd;
374 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
375
376 ret += dso__fprintf_buildid(self, fp);
377 ret += fprintf(fp, ")\n");
378 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 379 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 380 ret += symbol__fprintf(pos, fp);
156 } 381 }
@@ -158,13 +383,17 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 383 return ret;
159} 384}
160 385
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 386/*
387 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
388 * so that we can in the next step set the symbol ->end address and then
389 * call kernel_maps__split_kallsyms.
390 */
391static int dso__load_all_kallsyms(struct dso *self, struct map *map)
162{ 392{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 393 char *line = NULL;
165 size_t n; 394 size_t n;
395 struct rb_root *root = &self->symbols[map->type];
166 FILE *file = fopen("/proc/kallsyms", "r"); 396 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 397
169 if (file == NULL) 398 if (file == NULL)
170 goto out_failure; 399 goto out_failure;
@@ -174,6 +403,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 403 struct symbol *sym;
175 int line_len, len; 404 int line_len, len;
176 char symbol_type; 405 char symbol_type;
406 char *symbol_name;
177 407
178 line_len = getline(&line, &n, file); 408 line_len = getline(&line, &n, file);
179 if (line_len < 0) 409 if (line_len < 0)
@@ -191,49 +421,28 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
191 continue; 421 continue;
192 422
193 symbol_type = toupper(line[len]); 423 symbol_type = toupper(line[len]);
194 /* 424 if (!symbol_type__is_a(symbol_type, map->type))
195 * We're interested only in code ('T'ext)
196 */
197 if (symbol_type != 'T' && symbol_type != 'W')
198 continue; 425 continue;
426
427 symbol_name = line + len + 2;
199 /* 428 /*
200 * Well fix up the end later, when we have all sorted. 429 * Will fix up the end later, when we have all symbols sorted.
201 */ 430 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 431 sym = symbol__new(start, 0, symbol_name);
203 self->sym_priv_size, 0, v);
204 432
205 if (sym == NULL) 433 if (sym == NULL)
206 goto out_delete_line; 434 goto out_delete_line;
207 435 /*
208 if (filter && filter(self, sym)) 436 * We will pass the symbols to the filter later, in
209 symbol__delete(sym, self->sym_priv_size); 437 * map__split_kallsyms, when we have split the maps per module
210 else { 438 */
211 dso__insert_symbol(self, sym); 439 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 } 440 }
232 441
233 free(line); 442 free(line);
234 fclose(file); 443 fclose(file);
235 444
236 return count; 445 return 0;
237 446
238out_delete_line: 447out_delete_line:
239 free(line); 448 free(line);
@@ -241,14 +450,114 @@ out_failure:
241 return -1; 450 return -1;
242} 451}
243 452
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 453/*
454 * Split the symbols into maps, making sure there are no overlaps, i.e. the
455 * kernel range is broken in several maps, named [kernel].N, as we don't have
456 * the original ELF section names vmlinux have.
457 */
458static int dso__split_kallsyms(struct dso *self, struct map *map,
459 struct map_groups *mg, symbol_filter_t filter)
460{
461 struct map *curr_map = map;
462 struct symbol *pos;
463 int count = 0;
464 struct rb_root *root = &self->symbols[map->type];
465 struct rb_node *next = rb_first(root);
466 int kernel_range = 0;
467
468 while (next) {
469 char *module;
470
471 pos = rb_entry(next, struct symbol, rb_node);
472 next = rb_next(&pos->rb_node);
473
474 module = strchr(pos->name, '\t');
475 if (module) {
476 if (!mg->use_modules)
477 goto discard_symbol;
478
479 *module++ = '\0';
480
481 if (strcmp(self->name, module)) {
482 curr_map = map_groups__find_by_name(mg, map->type, module);
483 if (curr_map == NULL) {
484 pr_debug("/proc/{kallsyms,modules} "
485 "inconsistency!\n");
486 return -1;
487 }
488 }
489 /*
490 * So that we look just like we get from .ko files,
491 * i.e. not prelinked, relative to map->start.
492 */
493 pos->start = curr_map->map_ip(curr_map, pos->start);
494 pos->end = curr_map->map_ip(curr_map, pos->end);
495 } else if (curr_map != map) {
496 char dso_name[PATH_MAX];
497 struct dso *dso;
498
499 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
500 kernel_range++);
501
502 dso = dso__new(dso_name);
503 if (dso == NULL)
504 return -1;
505
506 curr_map = map__new2(pos->start, dso, map->type);
507 if (map == NULL) {
508 dso__delete(dso);
509 return -1;
510 }
511
512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
513 map_groups__insert(mg, curr_map);
514 ++kernel_range;
515 }
516
517 if (filter && filter(curr_map, pos)) {
518discard_symbol: rb_erase(&pos->rb_node, root);
519 symbol__delete(pos);
520 } else {
521 if (curr_map != map) {
522 rb_erase(&pos->rb_node, root);
523 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
524 }
525 count++;
526 }
527 }
528
529 return count;
530}
531
532
533static int dso__load_kallsyms(struct dso *self, struct map *map,
534 struct map_groups *mg, symbol_filter_t filter)
535{
536 if (dso__load_all_kallsyms(self, map) < 0)
537 return -1;
538
539 symbols__fixup_end(&self->symbols[map->type]);
540 self->origin = DSO__ORIG_KERNEL;
541
542 return dso__split_kallsyms(self, map, mg, filter);
543}
544
545size_t kernel_maps__fprintf(FILE *fp)
546{
547 size_t printed = fprintf(fp, "Kernel maps:\n");
548 printed += map_groups__fprintf_maps(kmaps, fp);
549 return printed + fprintf(fp, "END kernel maps\n");
550}
551
552static int dso__load_perf_map(struct dso *self, struct map *map,
553 symbol_filter_t filter)
245{ 554{
246 char *line = NULL; 555 char *line = NULL;
247 size_t n; 556 size_t n;
248 FILE *file; 557 FILE *file;
249 int nr_syms = 0; 558 int nr_syms = 0;
250 559
251 file = fopen(self->name, "r"); 560 file = fopen(self->long_name, "r");
252 if (file == NULL) 561 if (file == NULL)
253 goto out_failure; 562 goto out_failure;
254 563
@@ -278,16 +587,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 587 if (len + 2 >= line_len)
279 continue; 588 continue;
280 589
281 sym = symbol__new(start, size, line + len, 590 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 591
284 if (sym == NULL) 592 if (sym == NULL)
285 goto out_delete_line; 593 goto out_delete_line;
286 594
287 if (filter && filter(self, sym)) 595 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 596 symbol__delete(sym);
289 else { 597 else {
290 dso__insert_symbol(self, sym); 598 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 599 nr_syms++;
292 } 600 }
293 } 601 }
@@ -327,6 +635,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
327 sym->st_shndx != SHN_UNDEF; 635 sym->st_shndx != SHN_UNDEF;
328} 636}
329 637
638static inline bool elf_sym__is_object(const GElf_Sym *sym)
639{
640 return elf_sym__type(sym) == STT_OBJECT &&
641 sym->st_name != 0 &&
642 sym->st_shndx != SHN_UNDEF;
643}
644
330static inline int elf_sym__is_label(const GElf_Sym *sym) 645static inline int elf_sym__is_label(const GElf_Sym *sym)
331{ 646{
332 return elf_sym__type(sym) == STT_NOTYPE && 647 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -347,6 +662,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
347 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 662 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
348} 663}
349 664
665static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
666 const Elf_Data *secstrs)
667{
668 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
669}
670
350static inline const char *elf_sym__name(const GElf_Sym *sym, 671static inline const char *elf_sym__name(const GElf_Sym *sym,
351 const Elf_Data *symstrs) 672 const Elf_Data *symstrs)
352{ 673{
@@ -393,7 +714,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 714 * 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). 715 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 716 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 717static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
718 symbol_filter_t filter)
397{ 719{
398 uint32_t nr_rel_entries, idx; 720 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 721 GElf_Sym sym;
@@ -409,7 +731,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 731 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 732 int nr = 0, symidx, fd, err = 0;
411 733
412 fd = open(self->name, O_RDONLY); 734 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 735 if (fd < 0)
414 goto out; 736 goto out;
415 737
@@ -477,12 +799,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 799 "%s@plt", elf_sym__name(&sym, symstrs));
478 800
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 801 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 802 sympltname);
481 if (!f) 803 if (!f)
482 goto out_elf_end; 804 goto out_elf_end;
483 805
484 dso__insert_symbol(self, f); 806 if (filter && filter(map, f))
485 ++nr; 807 symbol__delete(f);
808 else {
809 symbols__insert(&self->symbols[map->type], f);
810 ++nr;
811 }
486 } 812 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 813 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 814 GElf_Rel pos_mem, *pos;
@@ -495,12 +821,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 821 "%s@plt", elf_sym__name(&sym, symstrs));
496 822
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 823 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 824 sympltname);
499 if (!f) 825 if (!f)
500 goto out_elf_end; 826 goto out_elf_end;
501 827
502 dso__insert_symbol(self, f); 828 if (filter && filter(map, f))
503 ++nr; 829 symbol__delete(f);
830 else {
831 symbols__insert(&self->symbols[map->type], f);
832 ++nr;
833 }
504 } 834 }
505 } 835 }
506 836
@@ -513,14 +843,42 @@ out_close:
513 if (err == 0) 843 if (err == 0)
514 return nr; 844 return nr;
515out: 845out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 846 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 847 __func__, self->long_name);
518 return 0; 848 return 0;
519} 849}
520 850
521static int dso__load_sym(struct dso *self, int fd, const char *name, 851static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
522 symbol_filter_t filter, int v, struct module *mod) 852{
853 switch (type) {
854 case MAP__FUNCTION:
855 return elf_sym__is_function(self);
856 case MAP__VARIABLE:
857 return elf_sym__is_object(self);
858 default:
859 return false;
860 }
861}
862
863static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
523{ 864{
865 switch (type) {
866 case MAP__FUNCTION:
867 return elf_sec__is_text(self, secstrs);
868 case MAP__VARIABLE:
869 return elf_sec__is_data(self, secstrs);
870 default:
871 return false;
872 }
873}
874
875static int dso__load_sym(struct dso *self, struct map *map,
876 struct map_groups *mg, const char *name, int fd,
877 symbol_filter_t filter, int kernel, int kmodule)
878{
879 struct map *curr_map = map;
880 struct dso *curr_dso = self;
881 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 882 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 883 uint32_t nr_syms;
526 int err = -1; 884 int err = -1;
@@ -531,19 +889,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 889 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 890 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 891 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 892 int nr = 0;
535 893
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 894 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 895 if (elf == NULL) {
538 if (v) 896 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; 897 goto out_close;
542 } 898 }
543 899
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 900 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 901 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 902 goto out_elf_end;
548 } 903 }
549 904
@@ -587,13 +942,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
587 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 942 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 943 struct symbol *f;
589 const char *elf_name; 944 const char *elf_name;
590 char *demangled; 945 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 946 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 947 const char *section_name;
595 948
596 if (!is_label && !elf_sym__is_function(&sym)) 949 if (!is_label && !elf_sym__is_a(&sym, map->type))
597 continue; 950 continue;
598 951
599 sec = elf_getscn(elf, sym.st_shndx); 952 sec = elf_getscn(elf, sym.st_shndx);
@@ -602,55 +955,88 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
602 955
603 gelf_getshdr(sec, &shdr); 956 gelf_getshdr(sec, &shdr);
604 957
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 958 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
606 continue; 959 continue;
607 960
961 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 962 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 963
611 if (self->adjust_symbols) { 964 if (kernel || kmodule) {
612 if (v >= 2) 965 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 966
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 967 if (strcmp(section_name,
617 } 968 curr_dso->short_name + dso_name_len) == 0)
969 goto new_symbol;
618 970
619 if (mod) { 971 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 972 curr_map = map;
621 if (section) 973 curr_dso = self;
622 sym.st_value += section->vma; 974 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 } 975 }
976
977 snprintf(dso_name, sizeof(dso_name),
978 "%s%s", self->short_name, section_name);
979
980 curr_map = map_groups__find_by_name(mg, map->type, dso_name);
981 if (curr_map == NULL) {
982 u64 start = sym.st_value;
983
984 if (kmodule)
985 start += map->start + shdr.sh_offset;
986
987 curr_dso = dso__new(dso_name);
988 if (curr_dso == NULL)
989 goto out_elf_end;
990 curr_map = map__new2(start, curr_dso,
991 MAP__FUNCTION);
992 if (curr_map == NULL) {
993 dso__delete(curr_dso);
994 goto out_elf_end;
995 }
996 curr_map->map_ip = identity__map_ip;
997 curr_map->unmap_ip = identity__map_ip;
998 curr_dso->origin = DSO__ORIG_KERNEL;
999 map_groups__insert(kmaps, curr_map);
1000 dsos__add(&dsos__kernel, curr_dso);
1001 } else
1002 curr_dso = curr_map->dso;
1003
1004 goto new_symbol;
1005 }
1006
1007 if (curr_dso->adjust_symbols) {
1008 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
1009 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
1010 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
1011 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 1012 }
629 /* 1013 /*
630 * We need to figure out if the object was created from C++ sources 1014 * 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 1015 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 1016 * to it...
633 */ 1017 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 1018 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 1019 if (demangled != NULL)
637 elf_name = demangled; 1020 elf_name = demangled;
638 1021new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 1022 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 1023 free(demangled);
642 if (!f) 1024 if (!f)
643 goto out_elf_end; 1025 goto out_elf_end;
644 1026
645 if (filter && filter(self, f)) 1027 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 1028 symbol__delete(f);
647 else { 1029 else {
648 f->module = mod; 1030 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 1031 nr++;
651 } 1032 }
652 } 1033 }
653 1034
1035 /*
1036 * For misannotated, zeroed, ASM function sizes.
1037 */
1038 if (nr > 0)
1039 symbols__fixup_end(&self->symbols[map->type]);
654 err = nr; 1040 err = nr;
655out_elf_end: 1041out_elf_end:
656 elf_end(elf); 1042 elf_end(elf);
@@ -658,63 +1044,154 @@ out_close:
658 return err; 1044 return err;
659} 1045}
660 1046
661#define BUILD_ID_SIZE 128 1047static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1048{
1049 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1050}
662 1051
663static char *dso__read_build_id(struct dso *self, int v) 1052static bool __dsos__read_build_ids(struct list_head *head)
664{ 1053{
665 int i; 1054 bool have_build_id = false;
1055 struct dso *pos;
1056
1057 list_for_each_entry(pos, head, node)
1058 if (filename__read_build_id(pos->long_name, pos->build_id,
1059 sizeof(pos->build_id)) > 0) {
1060 have_build_id = true;
1061 pos->has_build_id = true;
1062 }
1063
1064 return have_build_id;
1065}
1066
1067bool dsos__read_build_ids(void)
1068{
1069 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
1070 ubuildids = __dsos__read_build_ids(&dsos__user);
1071 return kbuildids || ubuildids;
1072}
1073
1074/*
1075 * Align offset to 4 bytes as needed for note name and descriptor data.
1076 */
1077#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1078
1079int filename__read_build_id(const char *filename, void *bf, size_t size)
1080{
1081 int fd, err = -1;
666 GElf_Ehdr ehdr; 1082 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 1083 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 1084 Elf_Data *data;
669 Elf_Scn *sec; 1085 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 1086 Elf_Kind ek;
671 unsigned char *raw; 1087 void *ptr;
672 Elf *elf; 1088 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 1089
1090 if (size < BUILD_ID_SIZE)
1091 goto out;
1092
1093 fd = open(filename, O_RDONLY);
675 if (fd < 0) 1094 if (fd < 0)
676 goto out; 1095 goto out;
677 1096
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1097 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 1098 if (elf == NULL) {
680 if (v) 1099 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; 1100 goto out_close;
684 } 1101 }
685 1102
1103 ek = elf_kind(elf);
1104 if (ek != ELF_K_ELF)
1105 goto out_elf_end;
1106
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 1107 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 1108 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 1109 goto out_elf_end;
690 } 1110 }
691 1111
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 1112 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 1113 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 1114 if (sec == NULL) {
1115 sec = elf_section_by_name(elf, &ehdr, &shdr,
1116 ".notes", NULL);
1117 if (sec == NULL)
1118 goto out_elf_end;
1119 }
695 1120
696 build_id_data = elf_getdata(sec, NULL); 1121 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 1122 if (data == NULL)
698 goto out_elf_end; 1123 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 1124
705 for (i = 0; i < 20; ++i) { 1125 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 1126 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 1127 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1128 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1129 descsz = NOTE_ALIGN(nhdr->n_descsz);
1130 const char *name;
1131
1132 ptr += sizeof(*nhdr);
1133 name = ptr;
1134 ptr += namesz;
1135 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1136 nhdr->n_namesz == sizeof("GNU")) {
1137 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1138 memcpy(bf, ptr, BUILD_ID_SIZE);
1139 err = BUILD_ID_SIZE;
1140 break;
1141 }
1142 }
1143 ptr += descsz;
709 } 1144 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1145out_elf_end:
713 elf_end(elf); 1146 elf_end(elf);
714out_close: 1147out_close:
715 close(fd); 1148 close(fd);
716out: 1149out:
717 return build_id; 1150 return err;
1151}
1152
1153int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1154{
1155 int fd, err = -1;
1156
1157 if (size < BUILD_ID_SIZE)
1158 goto out;
1159
1160 fd = open(filename, O_RDONLY);
1161 if (fd < 0)
1162 goto out;
1163
1164 while (1) {
1165 char bf[BUFSIZ];
1166 GElf_Nhdr nhdr;
1167 int namesz, descsz;
1168
1169 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1170 break;
1171
1172 namesz = NOTE_ALIGN(nhdr.n_namesz);
1173 descsz = NOTE_ALIGN(nhdr.n_descsz);
1174 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1175 nhdr.n_namesz == sizeof("GNU")) {
1176 if (read(fd, bf, namesz) != namesz)
1177 break;
1178 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1179 if (read(fd, build_id,
1180 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1181 err = 0;
1182 break;
1183 }
1184 } else if (read(fd, bf, descsz) != descsz)
1185 break;
1186 } else {
1187 int n = namesz + descsz;
1188 if (read(fd, bf, n) != n)
1189 break;
1190 }
1191 }
1192 close(fd);
1193out:
1194 return err;
718} 1195}
719 1196
720char dso__symtab_origin(const struct dso *self) 1197char dso__symtab_origin(const struct dso *self)
@@ -726,6 +1203,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 1203 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1204 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1205 [DSO__ORIG_DSO] = 'd',
1206 [DSO__ORIG_KMODULE] = 'K',
729 }; 1207 };
730 1208
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1209 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,20 +1211,27 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1211 return origin[self->origin];
734} 1212}
735 1213
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1214int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
737{ 1215{
738 int size = PATH_MAX; 1216 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1217 char *name;
1218 u8 build_id[BUILD_ID_SIZE];
740 int ret = -1; 1219 int ret = -1;
741 int fd; 1220 int fd;
742 1221
1222 dso__set_loaded(self, map->type);
1223
1224 if (self->kernel)
1225 return dso__load_kernel_sym(self, map, kmaps, filter);
1226
1227 name = malloc(size);
743 if (!name) 1228 if (!name)
744 return -1; 1229 return -1;
745 1230
746 self->adjust_symbols = 0; 1231 self->adjust_symbols = 0;
747 1232
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1233 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1234 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1235 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1236 DSO__ORIG_NOT_FOUND;
752 return ret; 1237 return ret;
@@ -759,34 +1244,50 @@ more:
759 self->origin++; 1244 self->origin++;
760 switch (self->origin) { 1245 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1246 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1247 snprintf(name, size, "/usr/lib/debug%s.debug",
1248 self->long_name);
763 break; 1249 break;
764 case DSO__ORIG_UBUNTU: 1250 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1251 snprintf(name, size, "/usr/lib/debug%s",
1252 self->long_name);
766 break; 1253 break;
767 case DSO__ORIG_BUILDID: 1254 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1255 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1256 sizeof(build_id))) {
1257 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1258
1259 build_id__sprintf(build_id, sizeof(build_id),
1260 build_id_hex);
770 snprintf(name, size, 1261 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1262 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1263 build_id_hex, build_id_hex + 2);
773 free(build_id); 1264 if (self->has_build_id)
1265 goto compare_build_id;
774 break; 1266 break;
775 } 1267 }
776 self->origin++; 1268 self->origin++;
777 /* Fall thru */ 1269 /* Fall thru */
778 case DSO__ORIG_DSO: 1270 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1271 snprintf(name, size, "%s", self->long_name);
780 break; 1272 break;
781 1273
782 default: 1274 default:
783 goto out; 1275 goto out;
784 } 1276 }
785 1277
1278 if (self->has_build_id) {
1279 if (filename__read_build_id(name, build_id,
1280 sizeof(build_id)) < 0)
1281 goto more;
1282compare_build_id:
1283 if (!dso__build_id_equal(self, build_id))
1284 goto more;
1285 }
1286
786 fd = open(name, O_RDONLY); 1287 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1288 } while (fd < 0);
788 1289
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1290 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
790 close(fd); 1291 close(fd);
791 1292
792 /* 1293 /*
@@ -796,7 +1297,7 @@ more:
796 goto more; 1297 goto more;
797 1298
798 if (ret > 0) { 1299 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1300 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1301 if (nr_plt > 0)
801 ret += nr_plt; 1302 ret += nr_plt;
802 } 1303 }
@@ -807,151 +1308,281 @@ out:
807 return ret; 1308 return ret;
808} 1309}
809 1310
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1311struct map *map_groups__find_by_name(struct map_groups *self,
811 symbol_filter_t filter, int v) 1312 enum map_type type, const char *name)
812{ 1313{
813 struct module *mod = mod_dso__find_module(mods, name); 1314 struct rb_node *nd;
814 int err = 0, fd; 1315
1316 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1317 struct map *map = rb_entry(nd, struct map, rb_node);
815 1318
816 if (mod == NULL || !mod->active) 1319 if (map->dso && strcmp(map->dso->name, name) == 0)
817 return err; 1320 return map;
1321 }
818 1322
819 fd = open(mod->path, O_RDONLY); 1323 return NULL;
1324}
820 1325
821 if (fd < 0) 1326static int dsos__set_modules_path_dir(char *dirname)
822 return err; 1327{
1328 struct dirent *dent;
1329 DIR *dir = opendir(dirname);
823 1330
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1331 if (!dir) {
825 close(fd); 1332 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1333 return -1;
1334 }
826 1335
827 return err; 1336 while ((dent = readdir(dir)) != NULL) {
1337 char path[PATH_MAX];
1338
1339 if (dent->d_type == DT_DIR) {
1340 if (!strcmp(dent->d_name, ".") ||
1341 !strcmp(dent->d_name, ".."))
1342 continue;
1343
1344 snprintf(path, sizeof(path), "%s/%s",
1345 dirname, dent->d_name);
1346 if (dsos__set_modules_path_dir(path) < 0)
1347 goto failure;
1348 } else {
1349 char *dot = strrchr(dent->d_name, '.'),
1350 dso_name[PATH_MAX];
1351 struct map *map;
1352 char *long_name;
1353
1354 if (dot == NULL || strcmp(dot, ".ko"))
1355 continue;
1356 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1357 (int)(dot - dent->d_name), dent->d_name);
1358
1359 strxfrchar(dso_name, '-', '_');
1360 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name);
1361 if (map == NULL)
1362 continue;
1363
1364 snprintf(path, sizeof(path), "%s/%s",
1365 dirname, dent->d_name);
1366
1367 long_name = strdup(path);
1368 if (long_name == NULL)
1369 goto failure;
1370 dso__set_long_name(map->dso, long_name);
1371 }
1372 }
1373
1374 return 0;
1375failure:
1376 closedir(dir);
1377 return -1;
828} 1378}
829 1379
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1380static int dsos__set_modules_path(void)
831{ 1381{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1382 struct utsname uts;
833 struct module *pos; 1383 char modules_path[PATH_MAX];
834 struct rb_node *next;
835 int err, count = 0;
836 1384
837 err = mod_dso__load_modules(mods); 1385 if (uname(&uts) < 0)
1386 return -1;
838 1387
839 if (err <= 0) 1388 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
840 return err; 1389 uts.release);
841 1390
842 /* 1391 return dsos__set_modules_path_dir(modules_path);
843 * Iterate over modules, and load active symbols. 1392}
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
850 if (err < 0)
851 break;
852 1393
853 next = rb_next(&pos->rb_node); 1394/*
854 count += err; 1395 * Constructor variant for modules (where we know from /proc/modules where
855 } 1396 * they are loaded) and for vmlinux, where only after we load all the
1397 * symbols we'll know where it starts and ends.
1398 */
1399static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1400{
1401 struct map *self = malloc(sizeof(*self));
856 1402
857 if (err < 0) { 1403 if (self != NULL) {
858 mod_dso__delete_modules(mods); 1404 /*
859 mod_dso__delete_self(mods); 1405 * ->end will be filled after we load all the symbols
860 return err; 1406 */
1407 map__init(self, type, start, 0, 0, dso);
861 } 1408 }
862 1409
863 return count; 1410 return self;
864} 1411}
865 1412
866static inline void dso__fill_symbol_holes(struct dso *self) 1413static int map_groups__create_module_maps(struct map_groups *self)
867{ 1414{
868 struct symbol *prev = NULL; 1415 char *line = NULL;
869 struct rb_node *nd; 1416 size_t n;
1417 FILE *file = fopen("/proc/modules", "r");
1418 struct map *map;
870 1419
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1420 if (file == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1421 return -1;
1422
1423 while (!feof(file)) {
1424 char name[PATH_MAX];
1425 u64 start;
1426 struct dso *dso;
1427 char *sep;
1428 int line_len;
873 1429
874 if (prev) { 1430 line_len = getline(&line, &n, file);
875 u64 hole = 0; 1431 if (line_len < 0)
876 int alias = pos->start == prev->start; 1432 break;
877 1433
878 if (!alias) 1434 if (!line)
879 hole = prev->start - pos->end - 1; 1435 goto out_failure;
880 1436
881 if (hole || alias) { 1437 line[--line_len] = '\0'; /* \n */
882 if (alias) 1438
883 pos->end = prev->end; 1439 sep = strrchr(line, 'x');
884 else if (hole) 1440 if (sep == NULL)
885 pos->end = prev->start - 1; 1441 continue;
886 } 1442
1443 hex2u64(sep + 1, &start);
1444
1445 sep = strchr(line, ' ');
1446 if (sep == NULL)
1447 continue;
1448
1449 *sep = '\0';
1450
1451 snprintf(name, sizeof(name), "[%s]", line);
1452 dso = dso__new(name);
1453
1454 if (dso == NULL)
1455 goto out_delete_line;
1456
1457 map = map__new2(start, dso, MAP__FUNCTION);
1458 if (map == NULL) {
1459 dso__delete(dso);
1460 goto out_delete_line;
887 } 1461 }
888 prev = pos; 1462
1463 snprintf(name, sizeof(name),
1464 "/sys/module/%s/notes/.note.gnu.build-id", line);
1465 if (sysfs__read_build_id(name, dso->build_id,
1466 sizeof(dso->build_id)) == 0)
1467 dso->has_build_id = true;
1468
1469 dso->origin = DSO__ORIG_KMODULE;
1470 map_groups__insert(self, map);
1471 dsos__add(&dsos__kernel, dso);
889 } 1472 }
1473
1474 free(line);
1475 fclose(file);
1476
1477 return dsos__set_modules_path();
1478
1479out_delete_line:
1480 free(line);
1481out_failure:
1482 return -1;
890} 1483}
891 1484
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1485static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1486 struct map_groups *mg,
1487 const char *vmlinux, symbol_filter_t filter)
894{ 1488{
895 int err, fd = open(vmlinux, O_RDONLY); 1489 int err = -1, fd;
896 1490
897 if (fd < 0) 1491 if (self->has_build_id) {
898 return -1; 1492 u8 build_id[BUILD_ID_SIZE];
899 1493
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1494 if (filename__read_build_id(vmlinux, build_id,
1495 sizeof(build_id)) < 0) {
1496 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1497 return -1;
1498 }
1499 if (!dso__build_id_equal(self, build_id)) {
1500 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1501 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1502
1503 build_id__sprintf(self->build_id,
1504 sizeof(self->build_id),
1505 expected_build_id);
1506 build_id__sprintf(build_id, sizeof(build_id),
1507 vmlinux_build_id);
1508 pr_debug("build_id in %s is %s while expected is %s, "
1509 "ignoring it\n", vmlinux, vmlinux_build_id,
1510 expected_build_id);
1511 return -1;
1512 }
1513 }
901 1514
902 if (err > 0) 1515 fd = open(vmlinux, O_RDONLY);
903 dso__fill_symbol_holes(self); 1516 if (fd < 0)
1517 return -1;
904 1518
1519 dso__set_loaded(self, map->type);
1520 err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0);
905 close(fd); 1521 close(fd);
906 1522
907 return err; 1523 return err;
908} 1524}
909 1525
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1526static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1527 struct map_groups *mg, symbol_filter_t filter)
912{ 1528{
913 int err = -1; 1529 int err;
914 1530 bool is_kallsyms;
915 if (vmlinux) { 1531
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1532 if (vmlinux_path != NULL) {
917 if (err > 0 && use_modules) { 1533 int i;
918 int syms = dso__load_modules(self, filter, v); 1534 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
919 1535 vmlinux_path__nr_entries);
920 if (syms < 0) { 1536 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
921 fprintf(stderr, "dso__load_modules failed!\n"); 1537 err = dso__load_vmlinux(self, map, mg,
922 return syms; 1538 vmlinux_path[i], filter);
1539 if (err > 0) {
1540 pr_debug("Using %s for symbols\n",
1541 vmlinux_path[i]);
1542 dso__set_long_name(self,
1543 strdup(vmlinux_path[i]));
1544 goto out_fixup;
923 } 1545 }
924 err += syms;
925 } 1546 }
926 } 1547 }
927 1548
928 if (err <= 0) 1549 is_kallsyms = self->long_name[0] == '[';
929 err = dso__load_kallsyms(self, filter, v); 1550 if (is_kallsyms)
1551 goto do_kallsyms;
930 1552
931 if (err > 0) 1553 err = dso__load_vmlinux(self, map, mg, self->long_name, filter);
932 self->origin = DSO__ORIG_KERNEL; 1554 if (err <= 0) {
1555 pr_info("The file %s cannot be used, "
1556 "trying to use /proc/kallsyms...", self->long_name);
1557do_kallsyms:
1558 err = dso__load_kallsyms(self, map, mg, filter);
1559 if (err > 0 && !is_kallsyms)
1560 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1561 }
1562
1563 if (err > 0) {
1564out_fixup:
1565 map__fixup_start(map);
1566 map__fixup_end(map);
1567 }
933 1568
934 return err; 1569 return err;
935} 1570}
936 1571
937LIST_HEAD(dsos); 1572LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1573LIST_HEAD(dsos__kernel);
939struct dso *vdso; 1574struct dso *vdso;
940struct dso *hypervisor_dso;
941
942const char *vmlinux_name = "vmlinux";
943int modules;
944 1575
945static void dsos__add(struct dso *dso) 1576static void dsos__add(struct list_head *head, struct dso *dso)
946{ 1577{
947 list_add_tail(&dso->node, &dsos); 1578 list_add_tail(&dso->node, head);
948} 1579}
949 1580
950static struct dso *dsos__find(const char *name) 1581static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1582{
952 struct dso *pos; 1583 struct dso *pos;
953 1584
954 list_for_each_entry(pos, &dsos, node) 1585 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1586 if (strcmp(pos->name, name) == 0)
956 return pos; 1587 return pos;
957 return NULL; 1588 return NULL;
@@ -959,79 +1590,190 @@ static struct dso *dsos__find(const char *name)
959 1590
960struct dso *dsos__findnew(const char *name) 1591struct dso *dsos__findnew(const char *name)
961{ 1592{
962 struct dso *dso = dsos__find(name); 1593 struct dso *dso = dsos__find(&dsos__user, name);
963 int nr;
964 1594
965 if (dso) 1595 if (!dso) {
966 return dso; 1596 dso = dso__new(name);
967 1597 if (dso != NULL) {
968 dso = dso__new(name, 0); 1598 dsos__add(&dsos__user, dso);
969 if (!dso) 1599 dso__set_basename(dso);
970 goto out_delete_dso; 1600 }
971
972 nr = dso__load(dso, NULL, verbose);
973 if (nr < 0) {
974 eprintf("Failed to open: %s\n", name);
975 goto out_delete_dso;
976 } 1601 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1602
982 return dso; 1603 return dso;
1604}
983 1605
984out_delete_dso: 1606static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1607{
986 return NULL; 1608 struct dso *pos;
1609
1610 list_for_each_entry(pos, head, node) {
1611 int i;
1612 for (i = 0; i < MAP__NR_TYPES; ++i)
1613 dso__fprintf(pos, i, fp);
1614 }
987} 1615}
988 1616
989void dsos__fprintf(FILE *fp) 1617void dsos__fprintf(FILE *fp)
990{ 1618{
1619 __dsos__fprintf(&dsos__kernel, fp);
1620 __dsos__fprintf(&dsos__user, fp);
1621}
1622
1623static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
1624{
991 struct dso *pos; 1625 struct dso *pos;
1626 size_t ret = 0;
992 1627
993 list_for_each_entry(pos, &dsos, node) 1628 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1629 ret += dso__fprintf_buildid(pos, fp);
1630 ret += fprintf(fp, " %s\n", pos->long_name);
1631 }
1632 return ret;
995} 1633}
996 1634
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1635size_t dsos__fprintf_buildid(FILE *fp)
998{ 1636{
999 return dso__find_symbol(dso, ip); 1637 return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1638 __dsos__fprintf_buildid(&dsos__user, fp));
1000} 1639}
1001 1640
1002int load_kernel(void) 1641static struct dso *dsos__create_kernel( const char *vmlinux)
1003{ 1642{
1004 int err; 1643 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1644
1645 if (kernel == NULL)
1646 return NULL;
1647
1648 kernel->short_name = "[kernel]";
1649 kernel->kernel = 1;
1005 1650
1006 kernel_dso = dso__new("[kernel]", 0); 1651 vdso = dso__new("[vdso]");
1007 if (!kernel_dso) 1652 if (vdso == NULL)
1653 goto out_delete_kernel_dso;
1654 dso__set_loaded(vdso, MAP__FUNCTION);
1655
1656 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1657 sizeof(kernel->build_id)) == 0)
1658 kernel->has_build_id = true;
1659
1660 dsos__add(&dsos__kernel, kernel);
1661 dsos__add(&dsos__user, vdso);
1662
1663 return kernel;
1664
1665out_delete_kernel_dso:
1666 dso__delete(kernel);
1667 return NULL;
1668}
1669
1670static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1671{
1672 struct map *functions, *variables;
1673 struct dso *kernel = dsos__create_kernel(vmlinux);
1674
1675 if (kernel == NULL)
1008 return -1; 1676 return -1;
1009 1677
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1678 functions = map__new2(0, kernel, MAP__FUNCTION);
1011 if (err <= 0) { 1679 if (functions == NULL)
1012 dso__delete(kernel_dso); 1680 return -1;
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1681
1017 vdso = dso__new("[vdso]", 0); 1682 variables = map__new2(0, kernel, MAP__VARIABLE);
1018 if (!vdso) 1683 if (variables == NULL) {
1684 map__delete(functions);
1019 return -1; 1685 return -1;
1686 }
1687
1688 functions->map_ip = functions->unmap_ip =
1689 variables->map_ip = variables->unmap_ip = identity__map_ip;
1690 map_groups__insert(self, functions);
1691 map_groups__insert(self, variables);
1020 1692
1021 vdso->find_symbol = vdso__find_symbol; 1693 return 0;
1694}
1022 1695
1023 dsos__add(vdso); 1696static void vmlinux_path__exit(void)
1697{
1698 while (--vmlinux_path__nr_entries >= 0) {
1699 free(vmlinux_path[vmlinux_path__nr_entries]);
1700 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1701 }
1024 1702
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1703 free(vmlinux_path);
1026 if (!hypervisor_dso) 1704 vmlinux_path = NULL;
1705}
1706
1707static int vmlinux_path__init(void)
1708{
1709 struct utsname uts;
1710 char bf[PATH_MAX];
1711
1712 if (uname(&uts) < 0)
1027 return -1; 1713 return -1;
1028 dsos__add(hypervisor_dso);
1029 1714
1030 return err; 1715 vmlinux_path = malloc(sizeof(char *) * 5);
1031} 1716 if (vmlinux_path == NULL)
1717 return -1;
1718
1719 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1720 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1721 goto out_fail;
1722 ++vmlinux_path__nr_entries;
1723 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1724 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1725 goto out_fail;
1726 ++vmlinux_path__nr_entries;
1727 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1728 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1729 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1730 goto out_fail;
1731 ++vmlinux_path__nr_entries;
1732 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1733 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1734 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1735 goto out_fail;
1736 ++vmlinux_path__nr_entries;
1737 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1738 uts.release);
1739 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1740 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1741 goto out_fail;
1742 ++vmlinux_path__nr_entries;
1743
1744 return 0;
1032 1745
1746out_fail:
1747 vmlinux_path__exit();
1748 return -1;
1749}
1033 1750
1034void symbol__init(void) 1751int symbol__init(struct symbol_conf *conf)
1035{ 1752{
1753 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults;
1754
1036 elf_version(EV_CURRENT); 1755 elf_version(EV_CURRENT);
1756 symbol__priv_size = pconf->priv_size;
1757 if (pconf->sort_by_name)
1758 symbol__priv_size += (sizeof(struct symbol_name_rb_node) -
1759 sizeof(struct symbol));
1760 map_groups__init(kmaps);
1761
1762 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0)
1763 return -1;
1764
1765 if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) {
1766 vmlinux_path__exit();
1767 return -1;
1768 }
1769
1770 kmaps->use_modules = pconf->use_modules;
1771 if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0)
1772 pr_debug("Failed to load list of modules in use, "
1773 "continuing...\n");
1774 /*
1775 * Now that we have all the maps created, just set the ->end of them:
1776 */
1777 map_groups__fixup_end(kmaps);
1778 return 0;
1037} 1779}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..cf99f88adf39 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,82 @@ 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 sort_by_name;
57 const char *vmlinux_name;
58};
59
60extern unsigned int symbol__priv_size;
61
62static inline void *symbol__priv(struct symbol *self)
63{
64 return ((void *)self) - symbol__priv_size;
65}
66
67struct addr_location {
68 struct thread *thread;
69 struct map *map;
70 struct symbol *sym;
71 u64 addr;
72 char level;
73};
74
57struct dso { 75struct dso {
58 struct list_head node; 76 struct list_head node;
59 struct rb_root syms; 77 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 78 struct rb_root symbol_names[MAP__NR_TYPES];
61 unsigned int sym_priv_size; 79 u8 adjust_symbols:1;
62 unsigned char adjust_symbols; 80 u8 slen_calculated:1;
63 unsigned char slen_calculated; 81 u8 has_build_id:1;
82 u8 kernel:1;
64 unsigned char origin; 83 unsigned char origin;
84 u8 sorted_by_name;
85 u8 loaded;
86 u8 build_id[BUILD_ID_SIZE];
87 u16 long_name_len;
88 const char *short_name;
89 char *long_name;
65 char name[0]; 90 char name[0];
66}; 91};
67 92
68extern const char *sym_hist_filter; 93struct 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); 94void dso__delete(struct dso *self);
74 95
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 96bool dso__loaded(const struct dso *self, enum map_type type);
76{ 97bool dso__sorted_by_name(const struct dso *self, enum map_type type);
77 return ((void *)sym) - self->sym_priv_size;
78}
79 98
80struct symbol *dso__find_symbol(struct dso *self, u64 ip); 99void dso__sort_by_name(struct dso *self, enum map_type type);
81 100
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); 101struct dso *dsos__findnew(const char *name);
102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
87void dsos__fprintf(FILE *fp); 103void dsos__fprintf(FILE *fp);
104size_t dsos__fprintf_buildid(FILE *fp);
88 105
89size_t dso__fprintf(struct dso *self, FILE *fp); 106size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
107size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
90char dso__symtab_origin(const struct dso *self); 108char dso__symtab_origin(const struct dso *self);
109void dso__set_build_id(struct dso *self, void *build_id);
110struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
111struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
112 const char *name);
113
114int filename__read_build_id(const char *filename, void *bf, size_t size);
115int sysfs__read_build_id(const char *filename, void *bf, size_t size);
116bool dsos__read_build_ids(void);
117int build_id__sprintf(u8 *self, int len, char *bf);
91 118
92int load_kernel(void); 119size_t kernel_maps__fprintf(FILE *fp);
93 120
94void symbol__init(void); 121int symbol__init(struct symbol_conf *conf);
95 122
96extern struct list_head dsos; 123struct map_groups;
97extern struct dso *kernel_dso; 124struct map_groups *kmaps;
125extern struct list_head dsos__user, dsos__kernel;
98extern struct dso *vdso; 126extern struct dso *vdso;
99extern struct dso *hypervisor_dso; 127#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..b68a00ea4121 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,16 +6,28 @@
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 map_groups__init(struct map_groups *self)
13{
14 int i;
15 for (i = 0; i < MAP__NR_TYPES; ++i) {
16 self->maps[i] = RB_ROOT;
17 INIT_LIST_HEAD(&self->removed_maps[i]);
18 }
19}
20
9static struct thread *thread__new(pid_t pid) 21static struct thread *thread__new(pid_t pid)
10{ 22{
11 struct thread *self = calloc(1, sizeof(*self)); 23 struct thread *self = zalloc(sizeof(*self));
12 24
13 if (self != NULL) { 25 if (self != NULL) {
26 map_groups__init(&self->mg);
14 self->pid = pid; 27 self->pid = pid;
15 self->comm = malloc(32); 28 self->comm = malloc(32);
16 if (self->comm) 29 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 30 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 } 31 }
20 32
21 return self; 33 return self;
@@ -29,21 +41,90 @@ int thread__set_comm(struct thread *self, const char *comm)
29 return self->comm ? 0 : -ENOMEM; 41 return self->comm ? 0 : -ENOMEM;
30} 42}
31 43
32static size_t thread__fprintf(struct thread *self, FILE *fp) 44int thread__comm_len(struct thread *self)
45{
46 if (!self->comm_len) {
47 if (!self->comm)
48 return 0;
49 self->comm_len = strlen(self->comm);
50 }
51
52 return self->comm_len;
53}
54
55static const char *map_type__name[MAP__NR_TYPES] = {
56 [MAP__FUNCTION] = "Functions",
57 [MAP__VARIABLE] = "Variables",
58};
59
60static size_t __map_groups__fprintf_maps(struct map_groups *self,
61 enum map_type type, FILE *fp)
62{
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 map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
80{
81 size_t printed = 0, i;
82 for (i = 0; i < MAP__NR_TYPES; ++i)
83 printed += __map_groups__fprintf_maps(self, i, fp);
84 return printed;
85}
86
87static size_t __map_groups__fprintf_removed_maps(struct map_groups *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 map_groups__fprintf_removed_maps(struct map_groups *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 += __map_groups__fprintf_removed_maps(self, i, fp);
109 return printed;
110}
39 111
40 return ret; 112static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
113{
114 size_t printed = map_groups__fprintf_maps(self, fp);
115 printed += fprintf(fp, "Removed maps:\n");
116 return printed + map_groups__fprintf_removed_maps(self, fp);
117}
118
119static size_t thread__fprintf(struct thread *self, FILE *fp)
120{
121 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
122 map_groups__fprintf(&self->mg, fp);
41} 123}
42 124
43struct thread * 125struct thread *threads__findnew(pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 126{
46 struct rb_node **p = &threads->rb_node; 127 struct rb_node **p = &threads.rb_node;
47 struct rb_node *parent = NULL; 128 struct rb_node *parent = NULL;
48 struct thread *th; 129 struct thread *th;
49 130
@@ -52,15 +133,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 133 * so most of the time we dont have to look up
53 * the full rbtree: 134 * the full rbtree:
54 */ 135 */
55 if (*last_match && (*last_match)->pid == pid) 136 if (last_match && last_match->pid == pid)
56 return *last_match; 137 return last_match;
57 138
58 while (*p != NULL) { 139 while (*p != NULL) {
59 parent = *p; 140 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 141 th = rb_entry(parent, struct thread, rb_node);
61 142
62 if (th->pid == pid) { 143 if (th->pid == pid) {
63 *last_match = th; 144 last_match = th;
64 return th; 145 return th;
65 } 146 }
66 147
@@ -73,17 +154,16 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 154 th = thread__new(pid);
74 if (th != NULL) { 155 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 156 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 157 rb_insert_color(&th->rb_node, &threads);
77 *last_match = th; 158 last_match = th;
78 } 159 }
79 160
80 return th; 161 return th;
81} 162}
82 163
83struct thread * 164struct thread *register_idle_thread(void)
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{ 165{
86 struct thread *thread = threads__findnew(0, threads, last_match); 166 struct thread *thread = threads__findnew(0);
87 167
88 if (!thread || thread__set_comm(thread, "swapper")) { 168 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n"); 169 fprintf(stderr, "problem inserting idle task.\n");
@@ -93,79 +173,120 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match)
93 return thread; 173 return thread;
94} 174}
95 175
96void thread__insert_map(struct thread *self, struct map *map) 176static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map)
97{ 178{
98 struct map *pos, *tmp; 179 struct rb_root *root = &self->maps[map->type];
180 struct rb_node *next = rb_first(root);
99 181
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 182 while (next) {
101 if (map__overlap(pos, map)) { 183 struct map *pos = rb_entry(next, struct map, rb_node);
102 if (verbose >= 2) { 184 next = rb_next(&pos->rb_node);
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 185
108 if (map->start <= pos->start && map->end > pos->start) 186 if (!map__overlap(pos, map))
109 pos->start = map->end; 187 continue;
110 188
111 if (map->end >= pos->end && map->start < pos->end) 189 if (verbose >= 2) {
112 pos->end = map->start; 190 fputs("overlapping maps:\n", stderr);
191 map__fprintf(map, stderr);
192 map__fprintf(pos, stderr);
193 }
113 194
114 if (verbose >= 2) { 195 rb_erase(&pos->rb_node, root);
115 printf("after collision:\n"); 196 /*
116 map__fprintf(pos, stdout); 197 * We may have references to this map, for instance in some
117 } 198 * hist_entry instances, so just move them to a separate
199 * list.
200 */
201 list_add_tail(&pos->node, &self->removed_maps[map->type]);
202 }
203}
118 204
119 if (pos->start >= pos->end) { 205void maps__insert(struct rb_root *maps, struct map *map)
120 list_del_init(&pos->node); 206{
121 free(pos); 207 struct rb_node **p = &maps->rb_node;
122 } 208 struct rb_node *parent = NULL;
123 } 209 const u64 ip = map->start;
210 struct map *m;
211
212 while (*p != NULL) {
213 parent = *p;
214 m = rb_entry(parent, struct map, rb_node);
215 if (ip < m->start)
216 p = &(*p)->rb_left;
217 else
218 p = &(*p)->rb_right;
124 } 219 }
125 220
126 list_add_tail(&map->node, &self->maps); 221 rb_link_node(&map->rb_node, parent, p);
222 rb_insert_color(&map->rb_node, maps);
127} 223}
128 224
129int thread__fork(struct thread *self, struct thread *parent) 225struct map *maps__find(struct rb_root *maps, u64 ip)
130{ 226{
131 struct map *map; 227 struct rb_node **p = &maps->rb_node;
228 struct rb_node *parent = NULL;
229 struct map *m;
132 230
133 if (self->comm) 231 while (*p != NULL) {
134 free(self->comm); 232 parent = *p;
135 self->comm = strdup(parent->comm); 233 m = rb_entry(parent, struct map, rb_node);
136 if (!self->comm) 234 if (ip < m->start)
137 return -ENOMEM; 235 p = &(*p)->rb_left;
236 else if (ip > m->end)
237 p = &(*p)->rb_right;
238 else
239 return m;
240 }
138 241
139 list_for_each_entry(map, &parent->maps, node) { 242 return NULL;
243}
244
245void thread__insert_map(struct thread *self, struct map *map)
246{
247 map_groups__remove_overlappings(&self->mg, map);
248 map_groups__insert(&self->mg, map);
249}
250
251/*
252 * XXX This should not really _copy_ te maps, but refcount them.
253 */
254static int map_groups__clone(struct map_groups *self,
255 struct map_groups *parent, enum map_type type)
256{
257 struct rb_node *nd;
258 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
259 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 260 struct map *new = map__clone(map);
141 if (!new) 261 if (new == NULL)
142 return -ENOMEM; 262 return -ENOMEM;
143 thread__insert_map(self, new); 263 map_groups__insert(self, new);
144 } 264 }
145
146 return 0; 265 return 0;
147} 266}
148 267
149struct map *thread__find_map(struct thread *self, u64 ip) 268int thread__fork(struct thread *self, struct thread *parent)
150{ 269{
151 struct map *pos; 270 int i;
152 271
153 if (self == NULL) 272 if (self->comm)
154 return NULL; 273 free(self->comm);
155 274 self->comm = strdup(parent->comm);
156 list_for_each_entry(pos, &self->maps, node) 275 if (!self->comm)
157 if (ip >= pos->start && ip <= pos->end) 276 return -ENOMEM;
158 return pos;
159 277
160 return NULL; 278 for (i = 0; i < MAP__NR_TYPES; ++i)
279 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
280 return -ENOMEM;
281 return 0;
161} 282}
162 283
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 284size_t threads__fprintf(FILE *fp)
164{ 285{
165 size_t ret = 0; 286 size_t ret = 0;
166 struct rb_node *nd; 287 struct rb_node *nd;
167 288
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 289 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 290 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 291
171 ret += thread__fprintf(pos, fp); 292 ret += thread__fprintf(pos, fp);
@@ -173,3 +294,15 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 294
174 return ret; 295 return ret;
175} 296}
297
298struct symbol *map_groups__find_symbol(struct map_groups *self,
299 enum map_type type, u64 addr,
300 symbol_filter_t filter)
301{
302 struct map *map = map_groups__find(self, type, addr);
303
304 if (map != NULL)
305 return map__find_symbol(map, map->map_ip(map, addr), filter);
306
307 return NULL;
308}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..1751802a09ba 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -1,22 +1,70 @@
1#ifndef __PERF_THREAD_H
2#define __PERF_THREAD_H
3
1#include <linux/rbtree.h> 4#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h> 5#include <unistd.h>
4#include "symbol.h" 6#include "symbol.h"
5 7
8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES];
11 bool use_modules;
12};
13
6struct thread { 14struct thread {
7 struct rb_node rb_node; 15 struct rb_node rb_node;
8 struct list_head maps; 16 struct map_groups mg;
9 pid_t pid; 17 pid_t pid;
10 char shortname[3]; 18 char shortname[3];
11 char *comm; 19 char *comm;
20 int comm_len;
12}; 21};
13 22
23void map_groups__init(struct map_groups *self);
14int thread__set_comm(struct thread *self, const char *comm); 24int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 25int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 26struct thread *threads__findnew(pid_t pid);
17struct thread * 27struct 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); 28void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 29int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 31size_t threads__fprintf(FILE *fp);
32
33void maps__insert(struct rb_root *maps, struct map *map);
34struct map *maps__find(struct rb_root *maps, u64 addr);
35
36static inline void map_groups__insert(struct map_groups *self, struct map *map)
37{
38 maps__insert(&self->maps[map->type], map);
39}
40
41static inline struct map *map_groups__find(struct map_groups *self,
42 enum map_type type, u64 addr)
43{
44 return maps__find(&self->maps[type], addr);
45}
46
47static inline struct map *thread__find_map(struct thread *self,
48 enum map_type type, u64 addr)
49{
50 return self ? map_groups__find(&self->mg, type, addr) : NULL;
51}
52
53void thread__find_addr_location(struct thread *self, u8 cpumode,
54 enum map_type type, u64 addr,
55 struct addr_location *al,
56 symbol_filter_t filter);
57struct symbol *map_groups__find_symbol(struct map_groups *self,
58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
60
61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, u64 addr,
63 symbol_filter_t filter)
64{
65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
70#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}