aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
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-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-kmem.txt47
-rw-r--r--tools/perf/Documentation/perf-probe.txt61
-rw-r--r--tools/perf/Documentation/perf-record.txt16
-rw-r--r--tools/perf/Documentation/perf-report.txt12
-rw-r--r--tools/perf/Documentation/perf-timechart.txt5
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt219
-rw-r--r--tools/perf/Documentation/perf-trace.txt38
-rw-r--r--tools/perf/Makefile159
-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.c916
-rw-r--r--tools/perf/builtin-bench.c245
-rw-r--r--tools/perf/builtin-buildid-list.c77
-rw-r--r--tools/perf/builtin-diff.c248
-rw-r--r--tools/perf/builtin-help.c16
-rw-r--r--tools/perf/builtin-kmem.c791
-rw-r--r--tools/perf/builtin-probe.c309
-rw-r--r--tools/perf/builtin-record.c457
-rw-r--r--tools/perf/builtin-report.c1601
-rw-r--r--tools/perf/builtin-sched.c573
-rw-r--r--tools/perf/builtin-stat.c34
-rw-r--r--tools/perf/builtin-timechart.c361
-rw-r--r--tools/perf/builtin-top.c524
-rw-r--r--tools/perf/builtin-trace.c715
-rw-r--r--tools/perf/builtin.h5
-rw-r--r--tools/perf/command-list.txt5
-rw-r--r--tools/perf/design.txt2
-rw-r--r--tools/perf/perf.c87
-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-report6
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report7
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report6
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record6
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report6
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report7
-rw-r--r--tools/perf/scripts/perl/check-perf-trace.pl106
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl106
-rw-r--r--tools/perf/scripts/perl/rw-by-pid.pl170
-rw-r--r--tools/perf/scripts/perl/wakeup-latency.pl103
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/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.c252
-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.c456
-rw-r--r--tools/perf/util/event.h101
-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.c662
-rw-r--r--tools/perf/util/hist.h27
-rw-r--r--tools/perf/util/include/asm/asm-offsets.h1
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/bug.h22
-rw-r--r--tools/perf/util/include/asm/byteorder.h2
-rw-r--r--tools/perf/util/include/asm/swab.h1
-rw-r--r--tools/perf/util/include/asm/uaccess.h14
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/bitops.h29
-rw-r--r--tools/perf/util/include/linux/compiler.h10
-rw-r--r--tools/perf/util/include/linux/ctype.h1
-rw-r--r--tools/perf/util/include/linux/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.c126
-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.c677
-rw-r--r--tools/perf/util/probe-event.h22
-rw-r--r--tools/perf/util/probe-finder.c730
-rw-r--r--tools/perf/util/probe-finder.h65
-rw-r--r--tools/perf/util/quote.h6
-rw-r--r--tools/perf/util/run-command.h6
-rw-r--r--tools/perf/util/session.c150
-rw-r--r--tools/perf/util/session.h61
-rw-r--r--tools/perf/util/sigchain.h6
-rw-r--r--tools/perf/util/sort.c316
-rw-r--r--tools/perf/util/sort.h107
-rw-r--r--tools/perf/util/strbuf.h6
-rw-r--r--tools/perf/util/string.c219
-rw-r--r--tools/perf/util/string.h12
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h47
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol.c1384
-rw-r--r--tools/perf/util/symbol.h111
-rw-r--r--tools/perf/util/thread.c260
-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.c661
-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
128 files changed, 13878 insertions, 4972 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-diff.txt b/tools/perf/Documentation/perf-diff.txt
new file mode 100644
index 000000000000..8974e208cba6
--- /dev/null
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -0,0 +1,55 @@
1perf-diff(1)
2==============
3
4NAME
5----
6perf-diff - Read two perf.data files and display the differential profile
7
8SYNOPSIS
9--------
10[verse]
11'perf diff' [oldfile] [newfile]
12
13DESCRIPTION
14-----------
15This command displays the performance difference amongst two perf.data files
16captured via perf record.
17
18If no parameters are passed it will assume perf.data.old and perf.data.
19
20OPTIONS
21-------
22-d::
23--dsos=::
24 Only consider symbols in these dsos. CSV that understands
25 file://filename entries.
26
27-C::
28--comms=::
29 Only consider symbols in these comms. CSV that understands
30 file://filename entries.
31
32-S::
33--symbols=::
34 Only consider these symbols. CSV that understands
35 file://filename entries.
36
37-s::
38--sort=::
39 Sort by key(s): pid, comm, dso, symbol.
40
41-t::
42--field-separator=::
43
44 Use a special separator character and don't pad with spaces, replacing
45 all occurances of this separator in symbol names (and other output)
46 with a '.' character, that thus it's the only non valid separator.
47
48-v::
49--verbose::
50 Be verbose, for instance, show the raw counts in addition to the
51 diff.
52
53SEE ALSO
54--------
55linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
new file mode 100644
index 000000000000..eac4d852e7cd
--- /dev/null
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -0,0 +1,47 @@
1perf-kmem(1)
2==============
3
4NAME
5----
6perf-kmem - Tool to trace/measure kernel memory(slab) properties
7
8SYNOPSIS
9--------
10[verse]
11'perf kmem' {record|stat} [<options>]
12
13DESCRIPTION
14-----------
15There are two variants of perf kmem:
16
17 'perf kmem record <command>' to record the kmem events
18 of an arbitrary workload.
19
20 'perf kmem stat' to report kernel memory statistics.
21
22OPTIONS
23-------
24-i <file>::
25--input=<file>::
26 Select the input file (default: perf.data)
27
28--caller::
29 Show per-callsite statistics
30
31--alloc::
32 Show per-allocation statistics
33
34-s <key[,key2...]>::
35--sort=<key[,key2...]>::
36 Sort the output (default: frag,hit,bytes)
37
38-l <num>::
39--line=<num>::
40 Print n lines only
41
42--raw-ip::
43 Print raw ip instead of symbol
44
45SEE ALSO
46--------
47linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
new file mode 100644
index 000000000000..250e391b4bc8
--- /dev/null
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -0,0 +1,61 @@
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 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
53
54'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
55'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.
56It 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.
57'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).
58
59SEE ALSO
60--------
61linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 0ff23de9e453..fc46c0b40f6e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -26,11 +26,19 @@ OPTIONS
26 26
27-e:: 27-e::
28--event=:: 28--event=::
29 Select the PMU event. Selection can be a symbolic event name 29 Select the PMU event. Selection can be:
30 (use 'perf list' to list all events) or a raw PMU
31 event (eventsel+umask) in the form of rNNN where NNN is a
32 hexadecimal event descriptor.
33 30
31 - a symbolic event name (use 'perf list' to list all events)
32
33 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
34 hexadecimal event descriptor.
35
36 - a hardware breakpoint event in the form of '\mem:addr[:access]'
37 where addr is the address in memory you want to break in.
38 Access is the memory access type (read, write, execute) it can
39 be passed as follows: '\mem:addr[:[r][w][x]]'.
40 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'.
34-a:: 42-a::
35 System-wide collection. 43 System-wide collection.
36 44
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 59f0b846cd71..abfabe9147a4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -24,11 +24,11 @@ OPTIONS
24--dsos=:: 24--dsos=::
25 Only consider symbols in these dsos. CSV that understands 25 Only consider symbols in these dsos. CSV that understands
26 file://filename entries. 26 file://filename entries.
27-n 27-n::
28--show-nr-samples 28--show-nr-samples::
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T 30-T::
31--threads 31--threads::
32 Show per-thread event counters 32 Show per-thread event counters
33-C:: 33-C::
34--comms=:: 34--comms=::
@@ -39,6 +39,10 @@ OPTIONS
39 Only consider these symbols. CSV that understands 39 Only consider these symbols. CSV that understands
40 file://filename entries. 40 file://filename entries.
41 41
42-s::
43--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent.
45
42-w:: 46-w::
43--field-width=:: 47--field-width=::
44 Force each column width to the provided list, for large terminal 48 Force each column width to the provided list, for large terminal
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index a7910099d6fd..4b1788355eca 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -31,9 +31,12 @@ OPTIONS
31-w:: 31-w::
32--width=:: 32--width=::
33 Select the width of the SVG file (default: 1000) 33 Select the width of the SVG file (default: 1000)
34-p:: 34-P::
35--power-only:: 35--power-only::
36 Only output the CPU power section of the diagram 36 Only output the CPU power section of the diagram
37-p::
38--process::
39 Select the processes to display, by name or PID
37 40
38 41
39SEE ALSO 42SEE ALSO
diff --git a/tools/perf/Documentation/perf-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..60e5900da483 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,18 +8,52 @@ perf-trace - Read perf.data (created by perf record) and display trace output
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-i <file> | --input=file] symbol_name 11'perf trace' {record <script> | report <script> [args] }
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command reads the input file and displays the trace recorded. 15This command reads the input file and displays the trace recorded.
16 16
17There are several variants of perf trace:
18
19 'perf trace' to see a detailed trace of the workload that was
20 recorded.
21
22 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language
25 extension.
26
27 'perf trace report <script>' to run and display the results of
28 <script>. <script> is the name displayed in the output of 'perf
29 trace --list' i.e. the actual script name minus any language
30 extension. The perf.data output from a previous run of 'perf trace
31 record <script>' is used and should be present for this command to
32 succeed.
33
17OPTIONS 34OPTIONS
18------- 35-------
19-D:: 36-D::
20--dump-raw-trace=:: 37--dump-raw-trace=::
21 Display verbose dump of the trace data. 38 Display verbose dump of the trace data.
22 39
40-L::
41--Latency=::
42 Show latency attributes (irqs/preemption disabled, etc).
43
44-l::
45--list=::
46 Display a list of available trace scripts.
47
48-s::
49--script=::
50 Process trace data with the given script ([lang]:script[.ext]).
51
52-g::
53--gen-script=::
54 Generate perf-trace.[ext] starter script for given language,
55 using current perf.data.
56
23SEE ALSO 57SEE ALSO
24-------- 58--------
25linkperf:perf-record[1] 59linkperf:perf-record[1], linkperf:perf-trace-perl[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 7e190d522cd5..4390d225686d 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,58 @@ 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/probe-finder.h
374LIB_H += util/probe-event.h
348 375
349LIB_OBJS += util/abspath.o 376LIB_OBJS += util/abspath.o
350LIB_OBJS += util/alias.o 377LIB_OBJS += util/alias.o
351LIB_OBJS += util/config.o 378LIB_OBJS += util/config.o
352LIB_OBJS += util/ctype.o 379LIB_OBJS += util/ctype.o
380LIB_OBJS += util/debugfs.o
353LIB_OBJS += util/environment.o 381LIB_OBJS += util/environment.o
382LIB_OBJS += util/event.o
354LIB_OBJS += util/exec_cmd.o 383LIB_OBJS += util/exec_cmd.o
355LIB_OBJS += util/help.o 384LIB_OBJS += util/help.o
356LIB_OBJS += util/levenshtein.o 385LIB_OBJS += util/levenshtein.o
@@ -358,6 +387,9 @@ LIB_OBJS += util/parse-options.o
358LIB_OBJS += util/parse-events.o 387LIB_OBJS += util/parse-events.o
359LIB_OBJS += util/path.o 388LIB_OBJS += util/path.o
360LIB_OBJS += util/rbtree.o 389LIB_OBJS += util/rbtree.o
390LIB_OBJS += util/bitmap.o
391LIB_OBJS += util/hweight.o
392LIB_OBJS += util/find_next_bit.o
361LIB_OBJS += util/run-command.o 393LIB_OBJS += util/run-command.o
362LIB_OBJS += util/quote.o 394LIB_OBJS += util/quote.o
363LIB_OBJS += util/strbuf.o 395LIB_OBJS += util/strbuf.o
@@ -367,7 +399,6 @@ LIB_OBJS += util/usage.o
367LIB_OBJS += util/wrapper.o 399LIB_OBJS += util/wrapper.o
368LIB_OBJS += util/sigchain.o 400LIB_OBJS += util/sigchain.o
369LIB_OBJS += util/symbol.o 401LIB_OBJS += util/symbol.o
370LIB_OBJS += util/module.o
371LIB_OBJS += util/color.o 402LIB_OBJS += util/color.o
372LIB_OBJS += util/pager.o 403LIB_OBJS += util/pager.o
373LIB_OBJS += util/header.o 404LIB_OBJS += util/header.o
@@ -375,15 +406,31 @@ LIB_OBJS += util/callchain.o
375LIB_OBJS += util/values.o 406LIB_OBJS += util/values.o
376LIB_OBJS += util/debug.o 407LIB_OBJS += util/debug.o
377LIB_OBJS += util/map.o 408LIB_OBJS += util/map.o
409LIB_OBJS += util/session.o
378LIB_OBJS += util/thread.o 410LIB_OBJS += util/thread.o
379LIB_OBJS += util/trace-event-parse.o 411LIB_OBJS += util/trace-event-parse.o
380LIB_OBJS += util/trace-event-read.o 412LIB_OBJS += util/trace-event-read.o
381LIB_OBJS += util/trace-event-info.o 413LIB_OBJS += util/trace-event-info.o
414LIB_OBJS += util/trace-event-perl.o
382LIB_OBJS += util/svghelper.o 415LIB_OBJS += util/svghelper.o
416LIB_OBJS += util/sort.o
417LIB_OBJS += util/hist.o
418LIB_OBJS += util/data_map.o
419LIB_OBJS += util/probe-event.o
383 420
384BUILTIN_OBJS += builtin-annotate.o 421BUILTIN_OBJS += builtin-annotate.o
422
423BUILTIN_OBJS += builtin-bench.o
424
425# Benchmark modules
426BUILTIN_OBJS += bench/sched-messaging.o
427BUILTIN_OBJS += bench/sched-pipe.o
428BUILTIN_OBJS += bench/mem-memcpy.o
429
430BUILTIN_OBJS += builtin-diff.o
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,61 @@ 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 '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <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 -I/usr/include/libdwarf -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 BASIC_CFLAGS += -I/usr/include/libdwarf
495 EXTLIBS += -lelf -ldwarf
496 LIB_OBJS += util/probe-finder.o
497endif
498
499ifndef NO_LIBPERL
500PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
501PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
502endif
503
504ifneq ($(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)
505 BASIC_CFLAGS += -DNO_LIBPERL
506else
507 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
508 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o
509endif
510
432ifdef NO_DEMANGLE 511ifdef NO_DEMANGLE
433 BASIC_CFLAGS += -DNO_DEMANGLE 512 BASIC_CFLAGS += -DNO_DEMANGLE
434else 513else
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") 514 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 515
437 ifeq ($(has_bfd),y) 516 ifeq ($(has_bfd),y)
438 EXTLIBS += -lbfd 517 EXTLIBS += -lbfd
439 else 518 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") 519 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) 520 ifeq ($(has_bfd_iberty),y)
442 EXTLIBS += -lbfd -liberty 521 EXTLIBS += -lbfd -liberty
443 else 522 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") 523 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) 524 ifeq ($(has_bfd_iberty_z),y)
446 EXTLIBS += -lbfd -liberty -lz 525 EXTLIBS += -lbfd -liberty -lz
447 else 526 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") 527 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) 528 ifeq ($(has_cplus_demangle),y)
450 EXTLIBS += -liberty 529 EXTLIBS += -liberty
451 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 530 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
452 else 531 else
453 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) 532 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
454 BASIC_CFLAGS += -DNO_DEMANGLE 533 BASIC_CFLAGS += -DNO_DEMANGLE
455 endif 534 endif
456 endif 535 endif
@@ -787,6 +866,25 @@ util/config.o: util/config.c PERF-CFLAGS
787util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 866util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS
788 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 867 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
789 868
869# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing
870# from <string.h> that comes from kernel headers wrapping.
871KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
872
873util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS
874 $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
875
876util/hweight.o: ../../lib/hweight.c PERF-CFLAGS
877 $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
878
879util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS
880 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
881
882util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS
883 $(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 $<
884
885scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS
886 $(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 $<
887
790perf-%$X: %.o $(PERFLIBS) 888perf-%$X: %.o $(PERFLIBS)
791 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 889 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
792 890
@@ -894,6 +992,11 @@ export perfexec_instdir
894install: all 992install: all
895 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 993 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
896 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 994 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
995 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
996 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
997 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
998 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
999 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
897ifdef BUILT_INS 1000ifdef BUILT_INS
898 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1001 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
899 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1002 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
@@ -979,7 +1082,7 @@ distclean: clean
979# $(RM) configure 1082# $(RM) configure
980 1083
981clean: 1084clean:
982 $(RM) *.o */*.o $(LIB_FILE) 1085 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
983 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1086 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
984 $(RM) $(TEST_PROGRAMS) 1087 $(RM) $(TEST_PROGRAMS)
985 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1088 $(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..593ff25006de 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -19,29 +19,26 @@
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h" 20#include "util/debug.h"
21 21
22#include "util/event.h"
22#include "util/parse-options.h" 23#include "util/parse-options.h"
23#include "util/parse-events.h" 24#include "util/parse-events.h"
24#include "util/thread.h" 25#include "util/thread.h"
26#include "util/sort.h"
27#include "util/hist.h"
28#include "util/session.h"
25 29
26static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
27 31
28static char default_sort_order[] = "comm,symbol";
29static char *sort_order = default_sort_order;
30
31static int force; 32static int force;
32static int input;
33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
34 33
35static int full_paths; 34static int full_paths;
36 35
37static int print_line; 36static int print_line;
38 37
39static unsigned long page_size; 38struct sym_hist {
40static unsigned long mmap_window = 32; 39 u64 sum;
41 40 u64 ip[0];
42static struct rb_root threads; 41};
43static struct thread *last_match;
44
45 42
46struct sym_ext { 43struct sym_ext {
47 struct rb_node node; 44 struct rb_node node;
@@ -49,247 +46,33 @@ struct sym_ext {
49 char *path; 46 char *path;
50}; 47};
51 48
52/* 49struct sym_priv {
53 * histogram, sorted on item, collects counts 50 struct sym_hist *hist;
54 */ 51 struct sym_ext *ext;
55
56static struct rb_root hist;
57
58struct hist_entry {
59 struct rb_node rb_node;
60
61 struct thread *thread;
62 struct map *map;
63 struct dso *dso;
64 struct symbol *sym;
65 u64 ip;
66 char level;
67
68 uint32_t count;
69};
70
71/*
72 * configurable sorting bits
73 */
74
75struct sort_entry {
76 struct list_head list;
77
78 const char *header;
79
80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
82 size_t (*print)(FILE *fp, struct hist_entry *);
83};
84
85/* --sort pid */
86
87static int64_t
88sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
89{
90 return right->thread->pid - left->thread->pid;
91}
92
93static size_t
94sort__thread_print(FILE *fp, struct hist_entry *self)
95{
96 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
97}
98
99static struct sort_entry sort_thread = {
100 .header = " Command: Pid",
101 .cmp = sort__thread_cmp,
102 .print = sort__thread_print,
103};
104
105/* --sort comm */
106
107static int64_t
108sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
109{
110 return right->thread->pid - left->thread->pid;
111}
112
113static int64_t
114sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
115{
116 char *comm_l = left->thread->comm;
117 char *comm_r = right->thread->comm;
118
119 if (!comm_l || !comm_r) {
120 if (!comm_l && !comm_r)
121 return 0;
122 else if (!comm_l)
123 return -1;
124 else
125 return 1;
126 }
127
128 return strcmp(comm_l, comm_r);
129}
130
131static size_t
132sort__comm_print(FILE *fp, struct hist_entry *self)
133{
134 return fprintf(fp, "%16s", self->thread->comm);
135}
136
137static struct sort_entry sort_comm = {
138 .header = " Command",
139 .cmp = sort__comm_cmp,
140 .collapse = sort__comm_collapse,
141 .print = sort__comm_print,
142};
143
144/* --sort dso */
145
146static int64_t
147sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
148{
149 struct dso *dso_l = left->dso;
150 struct dso *dso_r = right->dso;
151
152 if (!dso_l || !dso_r) {
153 if (!dso_l && !dso_r)
154 return 0;
155 else if (!dso_l)
156 return -1;
157 else
158 return 1;
159 }
160
161 return strcmp(dso_l->name, dso_r->name);
162}
163
164static size_t
165sort__dso_print(FILE *fp, struct hist_entry *self)
166{
167 if (self->dso)
168 return fprintf(fp, "%-25s", self->dso->name);
169
170 return fprintf(fp, "%016llx ", (u64)self->ip);
171}
172
173static struct sort_entry sort_dso = {
174 .header = "Shared Object ",
175 .cmp = sort__dso_cmp,
176 .print = sort__dso_print,
177}; 52};
178 53
179/* --sort symbol */ 54static const char *sym_hist_filter;
180 55
181static int64_t 56static int symbol_filter(struct map *map __used, struct symbol *sym)
182sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183{ 57{
184 u64 ip_l, ip_r; 58 if (sym_hist_filter == NULL ||
59 strcmp(sym->name, sym_hist_filter) == 0) {
60 struct sym_priv *priv = symbol__priv(sym);
61 const int size = (sizeof(*priv->hist) +
62 (sym->end - sym->start) * sizeof(u64));
185 63
186 if (left->sym == right->sym) 64 priv->hist = malloc(size);
65 if (priv->hist)
66 memset(priv->hist, 0, size);
187 return 0; 67 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 } 68 }
209 69 /*
210 return ret; 70 * FIXME: We should really filter it out, as we don't want to go thru symbols
211} 71 * we're not interested, and if a DSO ends up with no symbols, delete it too,
212 72 * but right now the kernel loading routines in symbol.c bail out if no symbols
213static struct sort_entry sort_sym = { 73 * are found, fix it later.
214 .header = "Symbol", 74 */
215 .cmp = sort__sym_cmp, 75 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} 76}
294 77
295/* 78/*
@@ -299,380 +82,83 @@ static void hist_hit(struct hist_entry *he, u64 ip)
299{ 82{
300 unsigned int sym_size, offset; 83 unsigned int sym_size, offset;
301 struct symbol *sym = he->sym; 84 struct symbol *sym = he->sym;
85 struct sym_priv *priv;
86 struct sym_hist *h;
302 87
303 he->count++; 88 he->count++;
304 89
305 if (!sym || !sym->hist) 90 if (!sym || !he->map)
91 return;
92
93 priv = symbol__priv(sym);
94 if (!priv->hist)
306 return; 95 return;
307 96
308 sym_size = sym->end - sym->start; 97 sym_size = sym->end - sym->start;
309 offset = ip - sym->start; 98 offset = ip - sym->start;
310 99
100 if (verbose)
101 fprintf(stderr, "%s: ip=%Lx\n", __func__,
102 he->map->unmap_ip(he->map, ip));
103
311 if (offset >= sym_size) 104 if (offset >= sym_size)
312 return; 105 return;
313 106
314 sym->hist_sum++; 107 h = priv->hist;
315 sym->hist[offset]++; 108 h->sum++;
109 h->ip[offset]++;
316 110
317 if (verbose >= 3) 111 if (verbose >= 3)
318 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", 112 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
319 (void *)(unsigned long)he->sym->start, 113 (void *)(unsigned long)he->sym->start,
320 he->sym->name, 114 he->sym->name,
321 (void *)(unsigned long)ip, ip - he->sym->start, 115 (void *)(unsigned long)ip, ip - he->sym->start,
322 sym->hist[offset]); 116 h->ip[offset]);
323} 117}
324 118
325static int 119static int perf_session__add_hist_entry(struct perf_session *self,
326hist_entry__add(struct thread *thread, struct map *map, struct dso *dso, 120 struct addr_location *al, u64 count)
327 struct symbol *sym, u64 ip, char level)
328{ 121{
329 struct rb_node **p = &hist.rb_node; 122 bool hit;
330 struct rb_node *parent = NULL; 123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
331 struct hist_entry *he; 124 count, &hit);
332 struct hist_entry entry = { 125 if (he == NULL)
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; 126 return -ENOMEM;
364 *he = entry; 127 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; 128 return 0;
369} 129}
370 130
371static void hist_entry__free(struct hist_entry *he) 131static int process_sample_event(event_t *event, struct perf_session *session)
372{
373 free(he);
374}
375
376/*
377 * collapse the histogram
378 */
379
380static struct rb_root collapse_hists;
381
382static void collapse__insert_entry(struct hist_entry *he)
383{
384 struct rb_node **p = &collapse_hists.rb_node;
385 struct rb_node *parent = NULL;
386 struct hist_entry *iter;
387 int64_t cmp;
388
389 while (*p != NULL) {
390 parent = *p;
391 iter = rb_entry(parent, struct hist_entry, rb_node);
392
393 cmp = hist_entry__collapse(iter, he);
394
395 if (!cmp) {
396 iter->count += he->count;
397 hist_entry__free(he);
398 return;
399 }
400
401 if (cmp < 0)
402 p = &(*p)->rb_left;
403 else
404 p = &(*p)->rb_right;
405 }
406
407 rb_link_node(&he->rb_node, parent, p);
408 rb_insert_color(&he->rb_node, &collapse_hists);
409}
410
411static void collapse__resort(void)
412{
413 struct rb_node *next;
414 struct hist_entry *n;
415
416 if (!sort__need_collapse)
417 return;
418
419 next = rb_first(&hist);
420 while (next) {
421 n = rb_entry(next, struct hist_entry, rb_node);
422 next = rb_next(&n->rb_node);
423
424 rb_erase(&n->rb_node, &hist);
425 collapse__insert_entry(n);
426 }
427}
428
429/*
430 * reverse the map, sort on count.
431 */
432
433static struct rb_root output_hists;
434
435static void output__insert_entry(struct hist_entry *he)
436{
437 struct rb_node **p = &output_hists.rb_node;
438 struct rb_node *parent = NULL;
439 struct hist_entry *iter;
440
441 while (*p != NULL) {
442 parent = *p;
443 iter = rb_entry(parent, struct hist_entry, rb_node);
444
445 if (he->count > iter->count)
446 p = &(*p)->rb_left;
447 else
448 p = &(*p)->rb_right;
449 }
450
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{ 132{
457 struct rb_node *next; 133 struct addr_location al;
458 struct hist_entry *n;
459 struct rb_root *tree = &hist;
460
461 if (sort__need_collapse)
462 tree = &collapse_hists;
463
464 next = rb_first(tree);
465 134
466 while (next) { 135 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
467 n = rb_entry(next, struct hist_entry, rb_node); 136 event->ip.pid, (void *)(long)event->ip.ip);
468 next = rb_next(&n->rb_node);
469 137
470 rb_erase(&n->rb_node, tree); 138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) {
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", 139 fprintf(stderr, "problem processing %d event, skipping it.\n",
504 event->header.type); 140 event->header.type);
505 return -1; 141 return -1;
506 } 142 }
507 143
508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) { 144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
509 show = SHOW_KERNEL; 145 fprintf(stderr, "problem incrementing symbol count, "
510 level = 'k'; 146 "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; 147 return -1;
632 } 148 }
633 total_fork++;
634 149
635 return 0; 150 return 0;
636} 151}
637 152
638static int 153static int parse_line(FILE *file, struct hist_entry *he, u64 len)
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;
663 }
664
665 return 0;
666}
667
668static int
669parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
670{ 154{
155 struct symbol *sym = he->sym;
671 char *line = NULL, *tmp, *tmp2; 156 char *line = NULL, *tmp, *tmp2;
672 static const char *prev_line; 157 static const char *prev_line;
673 static const char *prev_color; 158 static const char *prev_color;
674 unsigned int offset; 159 unsigned int offset;
675 size_t line_len; 160 size_t line_len;
161 u64 start;
676 s64 line_ip; 162 s64 line_ip;
677 int ret; 163 int ret;
678 char *c; 164 char *c;
@@ -709,22 +195,26 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
709 line_ip = -1; 195 line_ip = -1;
710 } 196 }
711 197
198 start = he->map->unmap_ip(he->map, sym->start);
199
712 if (line_ip != -1) { 200 if (line_ip != -1) {
713 const char *path = NULL; 201 const char *path = NULL;
714 unsigned int hits = 0; 202 unsigned int hits = 0;
715 double percent = 0.0; 203 double percent = 0.0;
716 const char *color; 204 const char *color;
717 struct sym_ext *sym_ext = sym->priv; 205 struct sym_priv *priv = symbol__priv(sym);
206 struct sym_ext *sym_ext = priv->ext;
207 struct sym_hist *h = priv->hist;
718 208
719 offset = line_ip - start; 209 offset = line_ip - start;
720 if (offset < len) 210 if (offset < len)
721 hits = sym->hist[offset]; 211 hits = h->ip[offset];
722 212
723 if (offset < len && sym_ext) { 213 if (offset < len && sym_ext) {
724 path = sym_ext[offset].path; 214 path = sym_ext[offset].path;
725 percent = sym_ext[offset].percent; 215 percent = sym_ext[offset].percent;
726 } else if (sym->hist_sum) 216 } else if (h->sum)
727 percent = 100.0 * hits / sym->hist_sum; 217 percent = 100.0 * hits / h->sum;
728 218
729 color = get_percent_color(percent); 219 color = get_percent_color(percent);
730 220
@@ -777,9 +267,10 @@ static void insert_source_line(struct sym_ext *sym_ext)
777 rb_insert_color(&sym_ext->node, &root_sym_ext); 267 rb_insert_color(&sym_ext->node, &root_sym_ext);
778} 268}
779 269
780static void free_source_line(struct symbol *sym, int len) 270static void free_source_line(struct hist_entry *he, int len)
781{ 271{
782 struct sym_ext *sym_ext = sym->priv; 272 struct sym_priv *priv = symbol__priv(he->sym);
273 struct sym_ext *sym_ext = priv->ext;
783 int i; 274 int i;
784 275
785 if (!sym_ext) 276 if (!sym_ext)
@@ -789,26 +280,30 @@ static void free_source_line(struct symbol *sym, int len)
789 free(sym_ext[i].path); 280 free(sym_ext[i].path);
790 free(sym_ext); 281 free(sym_ext);
791 282
792 sym->priv = NULL; 283 priv->ext = NULL;
793 root_sym_ext = RB_ROOT; 284 root_sym_ext = RB_ROOT;
794} 285}
795 286
796/* Get the filename:line for the colored entries */ 287/* Get the filename:line for the colored entries */
797static void 288static void
798get_source_line(struct symbol *sym, u64 start, int len, const char *filename) 289get_source_line(struct hist_entry *he, int len, const char *filename)
799{ 290{
291 struct symbol *sym = he->sym;
292 u64 start;
800 int i; 293 int i;
801 char cmd[PATH_MAX * 2]; 294 char cmd[PATH_MAX * 2];
802 struct sym_ext *sym_ext; 295 struct sym_ext *sym_ext;
296 struct sym_priv *priv = symbol__priv(sym);
297 struct sym_hist *h = priv->hist;
803 298
804 if (!sym->hist_sum) 299 if (!h->sum)
805 return; 300 return;
806 301
807 sym->priv = calloc(len, sizeof(struct sym_ext)); 302 sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
808 if (!sym->priv) 303 if (!priv->ext)
809 return; 304 return;
810 305
811 sym_ext = sym->priv; 306 start = he->map->unmap_ip(he->map, sym->start);
812 307
813 for (i = 0; i < len; i++) { 308 for (i = 0; i < len; i++) {
814 char *path = NULL; 309 char *path = NULL;
@@ -816,7 +311,7 @@ get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
816 u64 offset; 311 u64 offset;
817 FILE *fp; 312 FILE *fp;
818 313
819 sym_ext[i].percent = 100.0 * sym->hist[i] / sym->hist_sum; 314 sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
820 if (sym_ext[i].percent <= 0.5) 315 if (sym_ext[i].percent <= 0.5)
821 continue; 316 continue;
822 317
@@ -870,33 +365,34 @@ static void print_summary(const char *filename)
870 } 365 }
871} 366}
872 367
873static void annotate_sym(struct dso *dso, struct symbol *sym) 368static void annotate_sym(struct hist_entry *he)
874{ 369{
875 const char *filename = dso->name, *d_filename; 370 struct map *map = he->map;
876 u64 start, end, len; 371 struct dso *dso = map->dso;
372 struct symbol *sym = he->sym;
373 const char *filename = dso->long_name, *d_filename;
374 u64 len;
877 char command[PATH_MAX*2]; 375 char command[PATH_MAX*2];
878 FILE *file; 376 FILE *file;
879 377
880 if (!filename) 378 if (!filename)
881 return; 379 return;
882 if (sym->module) 380
883 filename = sym->module->path; 381 if (verbose)
884 else if (dso == kernel_dso) 382 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
885 filename = vmlinux_name; 383 __func__, filename, sym->name,
886 384 map->unmap_ip(map, sym->start),
887 start = sym->obj_start; 385 map->unmap_ip(map, sym->end));
888 if (!start) 386
889 start = sym->start;
890 if (full_paths) 387 if (full_paths)
891 d_filename = filename; 388 d_filename = filename;
892 else 389 else
893 d_filename = basename(filename); 390 d_filename = basename(filename);
894 391
895 end = start + sym->end - sym->start + 1;
896 len = sym->end - sym->start; 392 len = sym->end - sym->start;
897 393
898 if (print_line) { 394 if (print_line) {
899 get_source_line(sym, start, len, filename); 395 get_source_line(he, len, filename);
900 print_summary(filename); 396 print_summary(filename);
901 } 397 }
902 398
@@ -905,10 +401,12 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
905 printf("------------------------------------------------\n"); 401 printf("------------------------------------------------\n");
906 402
907 if (verbose >= 2) 403 if (verbose >= 2)
908 printf("annotating [%p] %30s : [%p] %30s\n", dso, dso->name, sym, sym->name); 404 printf("annotating [%p] %30s : [%p] %30s\n",
405 dso, dso->long_name, sym, sym->name);
909 406
910 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s", 407 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
911 (u64)start, (u64)end, filename, filename); 408 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
409 filename, filename);
912 410
913 if (verbose >= 3) 411 if (verbose >= 3)
914 printf("doing: %s\n", command); 412 printf("doing: %s\n", command);
@@ -918,159 +416,78 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
918 return; 416 return;
919 417
920 while (!feof(file)) { 418 while (!feof(file)) {
921 if (parse_line(file, sym, start, len) < 0) 419 if (parse_line(file, he, len) < 0)
922 break; 420 break;
923 } 421 }
924 422
925 pclose(file); 423 pclose(file);
926 if (print_line) 424 if (print_line)
927 free_source_line(sym, len); 425 free_source_line(he, len);
928} 426}
929 427
930static void find_annotations(void) 428static void perf_session__find_annotations(struct perf_session *self)
931{ 429{
932 struct rb_node *nd; 430 struct rb_node *nd;
933 struct dso *dso;
934 int count = 0;
935
936 list_for_each_entry(dso, &dsos, node) {
937
938 for (nd = rb_first(&dso->syms); nd; nd = rb_next(nd)) {
939 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
940
941 if (sym->hist) {
942 annotate_sym(dso, sym);
943 count++;
944 }
945 }
946 }
947
948 if (!count)
949 printf(" Error: symbol '%s' not present amongst the samples.\n", sym_hist_filter);
950}
951
952static int __cmd_annotate(void)
953{
954 int ret, rc = EXIT_FAILURE;
955 unsigned long offset = 0;
956 unsigned long head = 0;
957 struct stat input_stat;
958 event_t *event;
959 uint32_t size;
960 char *buf;
961
962 register_idle_thread(&threads, &last_match);
963
964 input = open(input_name, O_RDONLY);
965 if (input < 0) {
966 perror("failed to open file");
967 exit(-1);
968 }
969
970 ret = fstat(input, &input_stat);
971 if (ret < 0) {
972 perror("failed to stat file");
973 exit(-1);
974 }
975
976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
978 exit(-1);
979 }
980
981 if (!input_stat.st_size) {
982 fprintf(stderr, "zero-sized file, nothing to do!\n");
983 exit(0);
984 }
985
986 if (load_kernel() < 0) {
987 perror("failed to load kernel symbols");
988 return EXIT_FAILURE;
989 }
990
991remap:
992 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
993 MAP_SHARED, input, offset);
994 if (buf == MAP_FAILED) {
995 perror("failed to mmap file");
996 exit(-1);
997 }
998
999more:
1000 event = (event_t *)(buf + head);
1001
1002 size = event->header.size;
1003 if (!size)
1004 size = 8;
1005 431
1006 if (head + event->header.size >= page_size * mmap_window) { 432 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
1007 unsigned long shift = page_size * (head / page_size); 433 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
1008 int munmap_ret; 434 struct sym_priv *priv;
1009 435
1010 munmap_ret = munmap(buf, page_size * mmap_window); 436 if (he->sym == NULL)
1011 assert(munmap_ret == 0); 437 continue;
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 438
1032 total_unknown++; 439 priv = symbol__priv(he->sym);
440 if (priv->hist == NULL)
441 continue;
1033 442
443 annotate_sym(he);
1034 /* 444 /*
1035 * assume we lost track of the stream, check alignment, and 445 * Since we have a hist_entry per IP for the same symbol, free
1036 * increment a single u64 in the hope to catch on again 'soon'. 446 * he->sym->hist to signal we already processed this symbol.
1037 */ 447 */
1038 448 free(priv->hist);
1039 if (unlikely(head & 7)) 449 priv->hist = NULL;
1040 head &= ~7ULL;
1041
1042 size = 8;
1043 } 450 }
451}
1044 452
1045 head += size; 453static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event,
455 .process_mmap_event = event__process_mmap,
456 .process_comm_event = event__process_comm,
457 .process_fork_event = event__process_task,
458};
1046 459
1047 if (offset + head < (unsigned long)input_stat.st_size) 460static int __cmd_annotate(void)
1048 goto more; 461{
462 int ret;
463 struct perf_session *session;
1049 464
1050 rc = EXIT_SUCCESS; 465 session = perf_session__new(input_name, O_RDONLY, force);
1051 close(input); 466 if (session == NULL)
467 return -ENOMEM;
1052 468
1053 dump_printf(" IP events: %10ld\n", total); 469 ret = perf_session__process_events(session, &event_ops);
1054 dump_printf(" mmap events: %10ld\n", total_mmap); 470 if (ret)
1055 dump_printf(" comm events: %10ld\n", total_comm); 471 goto out_delete;
1056 dump_printf(" fork events: %10ld\n", total_fork);
1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1058 472
1059 if (dump_trace) 473 if (dump_trace) {
1060 return 0; 474 event__print_totals();
475 goto out_delete;
476 }
1061 477
1062 if (verbose >= 3) 478 if (verbose > 3)
1063 threads__fprintf(stdout, &threads); 479 perf_session__fprintf(session, stdout);
1064 480
1065 if (verbose >= 2) 481 if (verbose > 2)
1066 dsos__fprintf(stdout); 482 dsos__fprintf(stdout);
1067 483
1068 collapse__resort(); 484 perf_session__collapse_resort(session);
1069 output__resort(); 485 perf_session__output_resort(session, session->event_total[0]);
486 perf_session__find_annotations(session);
487out_delete:
488 perf_session__delete(session);
1070 489
1071 find_annotations(); 490 return ret;
1072
1073 return rc;
1074} 491}
1075 492
1076static const char * const annotate_usage[] = { 493static const char * const annotate_usage[] = {
@@ -1088,8 +505,9 @@ static const struct option options[] = {
1088 "be more verbose (show symbol address, etc)"), 505 "be more verbose (show symbol address, etc)"),
1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 506 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1090 "dump raw trace in ASCII"), 507 "dump raw trace in ASCII"),
1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 508 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1092 OPT_BOOLEAN('m', "modules", &modules, 509 "file", "vmlinux pathname"),
510 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1093 "load module symbols - WARNING: use only with -k and LIVE kernel"), 511 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1094 OPT_BOOLEAN('l', "print-line", &print_line, 512 OPT_BOOLEAN('l', "print-line", &print_line,
1095 "print matching source lines (may be slow)"), 513 "print matching source lines (may be slow)"),
@@ -1098,30 +516,17 @@ static const struct option options[] = {
1098 OPT_END() 516 OPT_END()
1099}; 517};
1100 518
1101static void setup_sorting(void)
1102{
1103 char *tmp, *tok, *str = strdup(sort_order);
1104
1105 for (tok = strtok_r(str, ", ", &tmp);
1106 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1107 if (sort_dimension__add(tok) < 0) {
1108 error("Unknown --sort key: `%s'", tok);
1109 usage_with_options(annotate_usage, options);
1110 }
1111 }
1112
1113 free(str);
1114}
1115
1116int cmd_annotate(int argc, const char **argv, const char *prefix __used) 519int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1117{ 520{
1118 symbol__init(); 521 argc = parse_options(argc, argv, options, annotate_usage, 0);
1119 522
1120 page_size = getpagesize(); 523 symbol_conf.priv_size = sizeof(struct sym_priv);
524 symbol_conf.try_vmlinux_path = true;
1121 525
1122 argc = parse_options(argc, argv, options, annotate_usage, 0); 526 if (symbol__init() < 0)
527 return -1;
1123 528
1124 setup_sorting(); 529 setup_sorting(annotate_usage, options);
1125 530
1126 if (argc) { 531 if (argc) {
1127 /* 532 /*
@@ -1134,10 +539,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
1134 sym_hist_filter = argv[0]; 539 sym_hist_filter = argv[0];
1135 } 540 }
1136 541
1137 if (!sym_hist_filter)
1138 usage_with_options(annotate_usage, options);
1139
1140 setup_pager(); 542 setup_pager();
1141 543
544 if (field_sep && *field_sep == '.') {
545 fputs("'.' is the only non valid --field-separator argument\n",
546 stderr);
547 exit(129);
548 }
549
1142 return __cmd_annotate(); 550 return __cmd_annotate();
1143} 551}
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..e693e6777af5
--- /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/debug.h"
13#include "util/parse-options.h"
14#include "util/session.h"
15#include "util/symbol.h"
16
17static char const *input_name = "perf.data";
18static int force;
19
20static const char *const buildid_list_usage[] = {
21 "perf buildid-list [<options>]",
22 NULL
23};
24
25static const struct option options[] = {
26 OPT_STRING('i', "input", &input_name, "file",
27 "input file name"),
28 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
29 OPT_BOOLEAN('v', "verbose", &verbose,
30 "be more verbose"),
31 OPT_END()
32};
33
34static int perf_file_section__process_buildids(struct perf_file_section *self,
35 int feat, int fd)
36{
37 if (feat != HEADER_BUILD_ID)
38 return 0;
39
40 if (lseek(fd, self->offset, SEEK_SET) < 0) {
41 pr_warning("Failed to lseek to %Ld offset for buildids!\n",
42 self->offset);
43 return -1;
44 }
45
46 if (perf_header__read_build_ids(fd, self->offset, self->size)) {
47 pr_warning("Failed to read buildids!\n");
48 return -1;
49 }
50
51 return 0;
52}
53
54static int __cmd_buildid_list(void)
55{
56 int err = -1;
57 struct perf_session *session;
58
59 session = perf_session__new(input_name, O_RDONLY, force);
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-diff.c b/tools/perf/builtin-diff.c
new file mode 100644
index 000000000000..4d33b55d5584
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,248 @@
1/*
2 * builtin-diff.c
3 *
4 * Builtin diff command: Analyze two perf.data input files, look up and read
5 * DSOs and symbol information, sort them and produce a diff.
6 */
7#include "builtin.h"
8
9#include "util/debug.h"
10#include "util/event.h"
11#include "util/hist.h"
12#include "util/session.h"
13#include "util/sort.h"
14#include "util/symbol.h"
15#include "util/util.h"
16
17#include <stdlib.h>
18
19static char const *input_old = "perf.data.old",
20 *input_new = "perf.data";
21static char diff__default_sort_order[] = "dso,symbol";
22static int force;
23static bool show_displacement;
24
25static int perf_session__add_hist_entry(struct perf_session *self,
26 struct addr_location *al, u64 count)
27{
28 bool hit;
29 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
30 count, &hit);
31 if (he == NULL)
32 return -ENOMEM;
33
34 if (hit)
35 he->count += count;
36
37 return 0;
38}
39
40static int diff__process_sample_event(event_t *event, struct perf_session *session)
41{
42 struct addr_location al;
43 struct sample_data data = { .period = 1, };
44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip);
47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n",
50 event->header.type);
51 return -1;
52 }
53
54 if (al.filtered)
55 return 0;
56
57 event__parse_sample(event, session->sample_type, &data);
58
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1;
62 }
63
64 session->events_stats.total += data.period;
65 return 0;
66}
67
68static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap,
71 .process_comm_event = event__process_comm,
72 .process_exit_event = event__process_task,
73 .process_fork_event = event__process_task,
74 .process_lost_event = event__process_lost,
75};
76
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
78 struct hist_entry *he)
79{
80 struct rb_node **p = &root->rb_node;
81 struct rb_node *parent = NULL;
82 struct hist_entry *iter;
83
84 while (*p != NULL) {
85 int cmp;
86 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node);
88
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left;
92 else if (cmp < 0)
93 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 }
102
103 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root);
105}
106
107static void perf_session__resort_by_name(struct perf_session *self)
108{
109 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT;
111 struct rb_node *next = rb_first(&self->hists);
112
113 while (next != NULL) {
114 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
115
116 next = rb_next(&n->rb_node);
117 rb_erase(&n->rb_node, &self->hists);
118 n->position = position++;
119 perf_session__insert_hist_entry_by_name(&tmp, n);
120 }
121
122 self->hists = tmp;
123}
124
125static struct hist_entry *
126perf_session__find_hist_entry_by_name(struct perf_session *self,
127 struct hist_entry *he)
128{
129 struct rb_node *n = self->hists.rb_node;
130
131 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name);
134
135 if (cmp > 0)
136 n = n->rb_left;
137 else if (cmp < 0)
138 n = n->rb_right;
139 else {
140 cmp = strcmp(he->sym->name, iter->sym->name);
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 }
149
150 return NULL;
151}
152
153static void perf_session__match_hists(struct perf_session *old_session,
154 struct perf_session *new_session)
155{
156 struct rb_node *nd;
157
158 perf_session__resort_by_name(old_session);
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos);
163 }
164}
165
166static int __cmd_diff(void)
167{
168 int ret, i;
169 struct perf_session *session[2];
170
171 session[0] = perf_session__new(input_old, O_RDONLY, force);
172 session[1] = perf_session__new(input_new, O_RDONLY, force);
173 if (session[0] == NULL || session[1] == NULL)
174 return -ENOMEM;
175
176 for (i = 0; i < 2; ++i) {
177 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret)
179 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 }
182
183 perf_session__match_hists(session[0], session[1]);
184 perf_session__fprintf_hists(session[1], session[0],
185 show_displacement, stdout);
186out_delete:
187 for (i = 0; i < 2; ++i)
188 perf_session__delete(session[i]);
189 return ret;
190}
191
192static const char *const diff_usage[] = {
193 "perf diff [<options>] [old_file] [new_file]",
194};
195
196static const struct option options[] = {
197 OPT_BOOLEAN('v', "verbose", &verbose,
198 "be more verbose (show symbol address, etc)"),
199 OPT_BOOLEAN('m', "displacement", &show_displacement,
200 "Show position displacement relative to baseline"),
201 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
202 "dump raw trace in ASCII"),
203 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
204 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
205 "load module symbols - WARNING: use only with -k and LIVE kernel"),
206 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
207 "Don't shorten the pathnames taking into account the cwd"),
208 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
209 "only consider symbols in these dsos"),
210 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
211 "only consider symbols in these comms"),
212 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
213 "only consider these symbols"),
214 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
215 "sort by key(s): pid, comm, dso, symbol, parent"),
216 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
217 "separator for columns, no spaces will be added between "
218 "columns '.' is reserved."),
219 OPT_END()
220};
221
222int cmd_diff(int argc, const char **argv, const char *prefix __used)
223{
224 sort_order = diff__default_sort_order;
225 argc = parse_options(argc, argv, options, diff_usage, 0);
226 if (argc) {
227 if (argc > 2)
228 usage_with_options(diff_usage, options);
229 if (argc == 2) {
230 input_old = argv[0];
231 input_new = argv[1];
232 } else
233 input_new = argv[0];
234 }
235
236 symbol_conf.exclude_other = false;
237 if (symbol__init() < 0)
238 return -1;
239
240 setup_sorting(diff_usage, options);
241 setup_pager();
242
243 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
244 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
245 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
246
247 return __cmd_diff();
248}
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..fc21ad79dd83
--- /dev/null
+++ b/tools/perf/builtin-kmem.c
@@ -0,0 +1,791 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9#include "util/session.h"
10
11#include "util/parse-options.h"
12#include "util/trace-event.h"
13
14#include "util/debug.h"
15
16#include <linux/rbtree.h>
17
18struct alloc_stat;
19typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20
21static char const *input_name = "perf.data";
22
23static int alloc_flag;
24static int caller_flag;
25
26static int alloc_lines = -1;
27static int caller_lines = -1;
28
29static bool raw_ip;
30
31static char default_sort_order[] = "frag,hit,bytes";
32
33static int *cpunode_map;
34static int max_cpu_num;
35
36struct alloc_stat {
37 u64 call_site;
38 u64 ptr;
39 u64 bytes_req;
40 u64 bytes_alloc;
41 u32 hit;
42 u32 pingpong;
43
44 short alloc_cpu;
45
46 struct rb_node node;
47};
48
49static struct rb_root root_alloc_stat;
50static struct rb_root root_alloc_sorted;
51static struct rb_root root_caller_stat;
52static struct rb_root root_caller_sorted;
53
54static unsigned long total_requested, total_allocated;
55static unsigned long nr_allocs, nr_cross_allocs;
56
57#define PATH_SYS_NODE "/sys/devices/system/node"
58
59static void init_cpunode_map(void)
60{
61 FILE *fp;
62 int i;
63
64 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
65 if (!fp) {
66 max_cpu_num = 4096;
67 return;
68 }
69
70 if (fscanf(fp, "%d", &max_cpu_num) < 1)
71 die("Failed to read 'kernel_max' from sysfs");
72 max_cpu_num++;
73
74 cpunode_map = calloc(max_cpu_num, sizeof(int));
75 if (!cpunode_map)
76 die("calloc");
77 for (i = 0; i < max_cpu_num; i++)
78 cpunode_map[i] = -1;
79 fclose(fp);
80}
81
82static void setup_cpunode_map(void)
83{
84 struct dirent *dent1, *dent2;
85 DIR *dir1, *dir2;
86 unsigned int cpu, mem;
87 char buf[PATH_MAX];
88
89 init_cpunode_map();
90
91 dir1 = opendir(PATH_SYS_NODE);
92 if (!dir1)
93 return;
94
95 while (true) {
96 dent1 = readdir(dir1);
97 if (!dent1)
98 break;
99
100 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
101 continue;
102
103 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
104 dir2 = opendir(buf);
105 if (!dir2)
106 continue;
107 while (true) {
108 dent2 = readdir(dir2);
109 if (!dent2)
110 break;
111 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
112 continue;
113 cpunode_map[cpu] = mem;
114 }
115 }
116}
117
118static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
119 int bytes_req, int bytes_alloc, int cpu)
120{
121 struct rb_node **node = &root_alloc_stat.rb_node;
122 struct rb_node *parent = NULL;
123 struct alloc_stat *data = NULL;
124
125 while (*node) {
126 parent = *node;
127 data = rb_entry(*node, struct alloc_stat, node);
128
129 if (ptr > data->ptr)
130 node = &(*node)->rb_right;
131 else if (ptr < data->ptr)
132 node = &(*node)->rb_left;
133 else
134 break;
135 }
136
137 if (data && data->ptr == ptr) {
138 data->hit++;
139 data->bytes_req += bytes_req;
140 data->bytes_alloc += bytes_req;
141 } else {
142 data = malloc(sizeof(*data));
143 if (!data)
144 die("malloc");
145 data->ptr = ptr;
146 data->pingpong = 0;
147 data->hit = 1;
148 data->bytes_req = bytes_req;
149 data->bytes_alloc = bytes_alloc;
150
151 rb_link_node(&data->node, parent, node);
152 rb_insert_color(&data->node, &root_alloc_stat);
153 }
154 data->call_site = call_site;
155 data->alloc_cpu = cpu;
156}
157
158static void insert_caller_stat(unsigned long call_site,
159 int bytes_req, int bytes_alloc)
160{
161 struct rb_node **node = &root_caller_stat.rb_node;
162 struct rb_node *parent = NULL;
163 struct alloc_stat *data = NULL;
164
165 while (*node) {
166 parent = *node;
167 data = rb_entry(*node, struct alloc_stat, node);
168
169 if (call_site > data->call_site)
170 node = &(*node)->rb_right;
171 else if (call_site < data->call_site)
172 node = &(*node)->rb_left;
173 else
174 break;
175 }
176
177 if (data && data->call_site == call_site) {
178 data->hit++;
179 data->bytes_req += bytes_req;
180 data->bytes_alloc += bytes_req;
181 } else {
182 data = malloc(sizeof(*data));
183 if (!data)
184 die("malloc");
185 data->call_site = call_site;
186 data->pingpong = 0;
187 data->hit = 1;
188 data->bytes_req = bytes_req;
189 data->bytes_alloc = bytes_alloc;
190
191 rb_link_node(&data->node, parent, node);
192 rb_insert_color(&data->node, &root_caller_stat);
193 }
194}
195
196static void process_alloc_event(void *data,
197 struct event *event,
198 int cpu,
199 u64 timestamp __used,
200 struct thread *thread __used,
201 int node)
202{
203 unsigned long call_site;
204 unsigned long ptr;
205 int bytes_req;
206 int bytes_alloc;
207 int node1, node2;
208
209 ptr = raw_field_value(event, "ptr", data);
210 call_site = raw_field_value(event, "call_site", data);
211 bytes_req = raw_field_value(event, "bytes_req", data);
212 bytes_alloc = raw_field_value(event, "bytes_alloc", data);
213
214 insert_alloc_stat(call_site, ptr, bytes_req, bytes_alloc, cpu);
215 insert_caller_stat(call_site, bytes_req, bytes_alloc);
216
217 total_requested += bytes_req;
218 total_allocated += bytes_alloc;
219
220 if (node) {
221 node1 = cpunode_map[cpu];
222 node2 = raw_field_value(event, "node", data);
223 if (node1 != node2)
224 nr_cross_allocs++;
225 }
226 nr_allocs++;
227}
228
229static int ptr_cmp(struct alloc_stat *, struct alloc_stat *);
230static int callsite_cmp(struct alloc_stat *, struct alloc_stat *);
231
232static struct alloc_stat *search_alloc_stat(unsigned long ptr,
233 unsigned long call_site,
234 struct rb_root *root,
235 sort_fn_t sort_fn)
236{
237 struct rb_node *node = root->rb_node;
238 struct alloc_stat key = { .ptr = ptr, .call_site = call_site };
239
240 while (node) {
241 struct alloc_stat *data;
242 int cmp;
243
244 data = rb_entry(node, struct alloc_stat, node);
245
246 cmp = sort_fn(&key, data);
247 if (cmp < 0)
248 node = node->rb_left;
249 else if (cmp > 0)
250 node = node->rb_right;
251 else
252 return data;
253 }
254 return NULL;
255}
256
257static void process_free_event(void *data,
258 struct event *event,
259 int cpu,
260 u64 timestamp __used,
261 struct thread *thread __used)
262{
263 unsigned long ptr;
264 struct alloc_stat *s_alloc, *s_caller;
265
266 ptr = raw_field_value(event, "ptr", data);
267
268 s_alloc = search_alloc_stat(ptr, 0, &root_alloc_stat, ptr_cmp);
269 if (!s_alloc)
270 return;
271
272 if (cpu != s_alloc->alloc_cpu) {
273 s_alloc->pingpong++;
274
275 s_caller = search_alloc_stat(0, s_alloc->call_site,
276 &root_caller_stat, callsite_cmp);
277 assert(s_caller);
278 s_caller->pingpong++;
279 }
280 s_alloc->alloc_cpu = -1;
281}
282
283static void
284process_raw_event(event_t *raw_event __used, void *data,
285 int cpu, u64 timestamp, struct thread *thread)
286{
287 struct event *event;
288 int type;
289
290 type = trace_parse_common_type(data);
291 event = trace_find_event(type);
292
293 if (!strcmp(event->name, "kmalloc") ||
294 !strcmp(event->name, "kmem_cache_alloc")) {
295 process_alloc_event(data, event, cpu, timestamp, thread, 0);
296 return;
297 }
298
299 if (!strcmp(event->name, "kmalloc_node") ||
300 !strcmp(event->name, "kmem_cache_alloc_node")) {
301 process_alloc_event(data, event, cpu, timestamp, thread, 1);
302 return;
303 }
304
305 if (!strcmp(event->name, "kfree") ||
306 !strcmp(event->name, "kmem_cache_free")) {
307 process_free_event(data, event, cpu, timestamp, thread);
308 return;
309 }
310}
311
312static int process_sample_event(event_t *event, struct perf_session *session)
313{
314 struct sample_data data;
315 struct thread *thread;
316
317 memset(&data, 0, sizeof(data));
318 data.time = -1;
319 data.cpu = -1;
320 data.period = 1;
321
322 event__parse_sample(event, session->sample_type, &data);
323
324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
325 event->header.misc,
326 data.pid, data.tid,
327 (void *)(long)data.ip,
328 (long long)data.period);
329
330 thread = perf_session__findnew(session, event->ip.pid);
331 if (thread == NULL) {
332 pr_debug("problem processing %d event, skipping it.\n",
333 event->header.type);
334 return -1;
335 }
336
337 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
338
339 process_raw_event(event, data.raw_data, data.cpu,
340 data.time, thread);
341
342 return 0;
343}
344
345static int sample_type_check(struct perf_session *session)
346{
347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
348 fprintf(stderr,
349 "No trace sample to read. Did you call perf record "
350 "without -R?");
351 return -1;
352 }
353
354 return 0;
355}
356
357static struct perf_event_ops event_ops = {
358 .process_sample_event = process_sample_event,
359 .process_comm_event = event__process_comm,
360 .sample_type_check = sample_type_check,
361};
362
363static double fragmentation(unsigned long n_req, unsigned long n_alloc)
364{
365 if (n_alloc == 0)
366 return 0.0;
367 else
368 return 100.0 - (100.0 * n_req / n_alloc);
369}
370
371static void __print_result(struct rb_root *root, struct perf_session *session,
372 int n_lines, int is_caller)
373{
374 struct rb_node *next;
375
376 printf("%.102s\n", graph_dotted_line);
377 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
378 printf(" Total_alloc/Per | Total_req/Per | Hit | Ping-pong | Frag\n");
379 printf("%.102s\n", graph_dotted_line);
380
381 next = rb_first(root);
382
383 while (next && n_lines--) {
384 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
385 node);
386 struct symbol *sym = NULL;
387 char buf[BUFSIZ];
388 u64 addr;
389
390 if (is_caller) {
391 addr = data->call_site;
392 if (!raw_ip)
393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL);
394 } else
395 addr = data->ptr;
396
397 if (sym != NULL)
398 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
399 addr - sym->start);
400 else
401 snprintf(buf, sizeof(buf), "%#Lx", addr);
402 printf(" %-34s |", buf);
403
404 printf(" %9llu/%-5lu | %9llu/%-5lu | %6lu | %8lu | %6.3f%%\n",
405 (unsigned long long)data->bytes_alloc,
406 (unsigned long)data->bytes_alloc / data->hit,
407 (unsigned long long)data->bytes_req,
408 (unsigned long)data->bytes_req / data->hit,
409 (unsigned long)data->hit,
410 (unsigned long)data->pingpong,
411 fragmentation(data->bytes_req, data->bytes_alloc));
412
413 next = rb_next(next);
414 }
415
416 if (n_lines == -1)
417 printf(" ... | ... | ... | ... | ... | ... \n");
418
419 printf("%.102s\n", graph_dotted_line);
420}
421
422static void print_summary(void)
423{
424 printf("\nSUMMARY\n=======\n");
425 printf("Total bytes requested: %lu\n", total_requested);
426 printf("Total bytes allocated: %lu\n", total_allocated);
427 printf("Total bytes wasted on internal fragmentation: %lu\n",
428 total_allocated - total_requested);
429 printf("Internal fragmentation: %f%%\n",
430 fragmentation(total_requested, total_allocated));
431 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
432}
433
434static void print_result(struct perf_session *session)
435{
436 if (caller_flag)
437 __print_result(&root_caller_sorted, session, caller_lines, 1);
438 if (alloc_flag)
439 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
440 print_summary();
441}
442
443struct sort_dimension {
444 const char name[20];
445 sort_fn_t cmp;
446 struct list_head list;
447};
448
449static LIST_HEAD(caller_sort);
450static LIST_HEAD(alloc_sort);
451
452static void sort_insert(struct rb_root *root, struct alloc_stat *data,
453 struct list_head *sort_list)
454{
455 struct rb_node **new = &(root->rb_node);
456 struct rb_node *parent = NULL;
457 struct sort_dimension *sort;
458
459 while (*new) {
460 struct alloc_stat *this;
461 int cmp = 0;
462
463 this = rb_entry(*new, struct alloc_stat, node);
464 parent = *new;
465
466 list_for_each_entry(sort, sort_list, list) {
467 cmp = sort->cmp(data, this);
468 if (cmp)
469 break;
470 }
471
472 if (cmp > 0)
473 new = &((*new)->rb_left);
474 else
475 new = &((*new)->rb_right);
476 }
477
478 rb_link_node(&data->node, parent, new);
479 rb_insert_color(&data->node, root);
480}
481
482static void __sort_result(struct rb_root *root, struct rb_root *root_sorted,
483 struct list_head *sort_list)
484{
485 struct rb_node *node;
486 struct alloc_stat *data;
487
488 for (;;) {
489 node = rb_first(root);
490 if (!node)
491 break;
492
493 rb_erase(node, root);
494 data = rb_entry(node, struct alloc_stat, node);
495 sort_insert(root_sorted, data, sort_list);
496 }
497}
498
499static void sort_result(void)
500{
501 __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort);
502 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
503}
504
505static int __cmd_kmem(void)
506{
507 int err;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
509 if (session == NULL)
510 return -ENOMEM;
511
512 setup_pager();
513 err = perf_session__process_events(session, &event_ops);
514 if (err != 0)
515 goto out_delete;
516 sort_result();
517 print_result(session);
518out_delete:
519 perf_session__delete(session);
520 return err;
521}
522
523static const char * const kmem_usage[] = {
524 "perf kmem [<options>] {record|stat}",
525 NULL
526};
527
528static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
529{
530 if (l->ptr < r->ptr)
531 return -1;
532 else if (l->ptr > r->ptr)
533 return 1;
534 return 0;
535}
536
537static struct sort_dimension ptr_sort_dimension = {
538 .name = "ptr",
539 .cmp = ptr_cmp,
540};
541
542static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r)
543{
544 if (l->call_site < r->call_site)
545 return -1;
546 else if (l->call_site > r->call_site)
547 return 1;
548 return 0;
549}
550
551static struct sort_dimension callsite_sort_dimension = {
552 .name = "callsite",
553 .cmp = callsite_cmp,
554};
555
556static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r)
557{
558 if (l->hit < r->hit)
559 return -1;
560 else if (l->hit > r->hit)
561 return 1;
562 return 0;
563}
564
565static struct sort_dimension hit_sort_dimension = {
566 .name = "hit",
567 .cmp = hit_cmp,
568};
569
570static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r)
571{
572 if (l->bytes_alloc < r->bytes_alloc)
573 return -1;
574 else if (l->bytes_alloc > r->bytes_alloc)
575 return 1;
576 return 0;
577}
578
579static struct sort_dimension bytes_sort_dimension = {
580 .name = "bytes",
581 .cmp = bytes_cmp,
582};
583
584static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r)
585{
586 double x, y;
587
588 x = fragmentation(l->bytes_req, l->bytes_alloc);
589 y = fragmentation(r->bytes_req, r->bytes_alloc);
590
591 if (x < y)
592 return -1;
593 else if (x > y)
594 return 1;
595 return 0;
596}
597
598static struct sort_dimension frag_sort_dimension = {
599 .name = "frag",
600 .cmp = frag_cmp,
601};
602
603static int pingpong_cmp(struct alloc_stat *l, struct alloc_stat *r)
604{
605 if (l->pingpong < r->pingpong)
606 return -1;
607 else if (l->pingpong > r->pingpong)
608 return 1;
609 return 0;
610}
611
612static struct sort_dimension pingpong_sort_dimension = {
613 .name = "pingpong",
614 .cmp = pingpong_cmp,
615};
616
617static struct sort_dimension *avail_sorts[] = {
618 &ptr_sort_dimension,
619 &callsite_sort_dimension,
620 &hit_sort_dimension,
621 &bytes_sort_dimension,
622 &frag_sort_dimension,
623 &pingpong_sort_dimension,
624};
625
626#define NUM_AVAIL_SORTS \
627 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
628
629static int sort_dimension__add(const char *tok, struct list_head *list)
630{
631 struct sort_dimension *sort;
632 int i;
633
634 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
635 if (!strcmp(avail_sorts[i]->name, tok)) {
636 sort = malloc(sizeof(*sort));
637 if (!sort)
638 die("malloc");
639 memcpy(sort, avail_sorts[i], sizeof(*sort));
640 list_add_tail(&sort->list, list);
641 return 0;
642 }
643 }
644
645 return -1;
646}
647
648static int setup_sorting(struct list_head *sort_list, const char *arg)
649{
650 char *tok;
651 char *str = strdup(arg);
652
653 if (!str)
654 die("strdup");
655
656 while (true) {
657 tok = strsep(&str, ",");
658 if (!tok)
659 break;
660 if (sort_dimension__add(tok, sort_list) < 0) {
661 error("Unknown --sort key: '%s'", tok);
662 return -1;
663 }
664 }
665
666 free(str);
667 return 0;
668}
669
670static int parse_sort_opt(const struct option *opt __used,
671 const char *arg, int unset __used)
672{
673 if (!arg)
674 return -1;
675
676 if (caller_flag > alloc_flag)
677 return setup_sorting(&caller_sort, arg);
678 else
679 return setup_sorting(&alloc_sort, arg);
680
681 return 0;
682}
683
684static int parse_caller_opt(const struct option *opt __used,
685 const char *arg __used, int unset __used)
686{
687 caller_flag = (alloc_flag + 1);
688 return 0;
689}
690
691static int parse_alloc_opt(const struct option *opt __used,
692 const char *arg __used, int unset __used)
693{
694 alloc_flag = (caller_flag + 1);
695 return 0;
696}
697
698static int parse_line_opt(const struct option *opt __used,
699 const char *arg, int unset __used)
700{
701 int lines;
702
703 if (!arg)
704 return -1;
705
706 lines = strtoul(arg, NULL, 10);
707
708 if (caller_flag > alloc_flag)
709 caller_lines = lines;
710 else
711 alloc_lines = lines;
712
713 return 0;
714}
715
716static const struct option kmem_options[] = {
717 OPT_STRING('i', "input", &input_name, "file",
718 "input file name"),
719 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
720 "show per-callsite statistics",
721 parse_caller_opt),
722 OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
723 "show per-allocation statistics",
724 parse_alloc_opt),
725 OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
726 "sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
727 parse_sort_opt),
728 OPT_CALLBACK('l', "line", NULL, "num",
729 "show n lines",
730 parse_line_opt),
731 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
732 OPT_END()
733};
734
735static const char *record_args[] = {
736 "record",
737 "-a",
738 "-R",
739 "-M",
740 "-f",
741 "-c", "1",
742 "-e", "kmem:kmalloc",
743 "-e", "kmem:kmalloc_node",
744 "-e", "kmem:kfree",
745 "-e", "kmem:kmem_cache_alloc",
746 "-e", "kmem:kmem_cache_alloc_node",
747 "-e", "kmem:kmem_cache_free",
748};
749
750static int __cmd_record(int argc, const char **argv)
751{
752 unsigned int rec_argc, i, j;
753 const char **rec_argv;
754
755 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
756 rec_argv = calloc(rec_argc + 1, sizeof(char *));
757
758 for (i = 0; i < ARRAY_SIZE(record_args); i++)
759 rec_argv[i] = strdup(record_args[i]);
760
761 for (j = 1; j < (unsigned int)argc; j++, i++)
762 rec_argv[i] = argv[j];
763
764 return cmd_record(i, rec_argv, NULL);
765}
766
767int cmd_kmem(int argc, const char **argv, const char *prefix __used)
768{
769 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
770
771 if (!argc)
772 usage_with_options(kmem_usage, kmem_options);
773
774 symbol__init();
775
776 if (!strncmp(argv[0], "rec", 3)) {
777 return __cmd_record(argc, argv);
778 } else if (!strcmp(argv[0], "stat")) {
779 setup_cpunode_map();
780
781 if (list_empty(&caller_sort))
782 setup_sorting(&caller_sort, default_sort_order);
783 if (list_empty(&alloc_sort))
784 setup_sorting(&alloc_sort, default_sort_order);
785
786 return __cmd_kmem();
787 }
788
789 return 0;
790}
791
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
new file mode 100644
index 000000000000..c1e6774fd3ed
--- /dev/null
+++ b/tools/perf/builtin-probe.c
@@ -0,0 +1,309 @@
1/*
2 * builtin-probe.c
3 *
4 * Builtin probe command: Set up probe events by C expression
5 *
6 * Written by Masami Hiramatsu <mhiramat@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 *
22 */
23#define _GNU_SOURCE
24#include <sys/utsname.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#undef _GNU_SOURCE
35#include "perf.h"
36#include "builtin.h"
37#include "util/util.h"
38#include "util/strlist.h"
39#include "util/event.h"
40#include "util/debug.h"
41#include "util/debugfs.h"
42#include "util/symbol.h"
43#include "util/thread.h"
44#include "util/session.h"
45#include "util/parse-options.h"
46#include "util/parse-events.h" /* For debugfs_path */
47#include "util/probe-finder.h"
48#include "util/probe-event.h"
49
50#define MAX_PATH_LEN 256
51#define MAX_PROBES 128
52
53/* Session management structure */
54static struct {
55 bool need_dwarf;
56 bool list_events;
57 bool force_add;
58 int nr_probe;
59 struct probe_point probes[MAX_PROBES];
60 struct strlist *dellist;
61 struct perf_session *psession;
62 struct map *kmap;
63} session;
64
65
66/* Parse an event definition. Note that any error must die. */
67static void parse_probe_event(const char *str)
68{
69 struct probe_point *pp = &session.probes[session.nr_probe];
70
71 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
72 if (++session.nr_probe == MAX_PROBES)
73 die("Too many probes (> %d) are specified.", MAX_PROBES);
74
75 /* Parse perf-probe event into probe_point */
76 parse_perf_probe_event(str, pp, &session.need_dwarf);
77
78 pr_debug("%d arguments\n", pp->nr_args);
79}
80
81static void parse_probe_event_argv(int argc, const char **argv)
82{
83 int i, len;
84 char *buf;
85
86 /* Bind up rest arguments */
87 len = 0;
88 for (i = 0; i < argc; i++)
89 len += strlen(argv[i]) + 1;
90 buf = zalloc(len + 1);
91 if (!buf)
92 die("Failed to allocate memory for binding arguments.");
93 len = 0;
94 for (i = 0; i < argc; i++)
95 len += sprintf(&buf[len], "%s ", argv[i]);
96 parse_probe_event(buf);
97 free(buf);
98}
99
100static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used)
102{
103 if (str)
104 parse_probe_event(str);
105 return 0;
106}
107
108static int opt_del_probe_event(const struct option *opt __used,
109 const char *str, int unset __used)
110{
111 if (str) {
112 if (!session.dellist)
113 session.dellist = strlist__new(true, NULL);
114 strlist__add(session.dellist, str);
115 }
116 return 0;
117}
118
119/* Currently just checking function name from symbol map */
120static void evaluate_probe_point(struct probe_point *pp)
121{
122 struct symbol *sym;
123 sym = map__find_symbol_by_name(session.kmap, pp->function,
124 session.psession, NULL);
125 if (!sym)
126 die("Kernel symbol \'%s\' not found - probe not added.",
127 pp->function);
128}
129
130#ifndef NO_LIBDWARF
131static int open_vmlinux(void)
132{
133 if (map__load(session.kmap, session.psession, NULL) < 0) {
134 pr_debug("Failed to load kernel map.\n");
135 return -EINVAL;
136 }
137 pr_debug("Try to open %s\n", session.kmap->dso->long_name);
138 return open(session.kmap->dso->long_name, O_RDONLY);
139}
140#endif
141
142static const char * const probe_usage[] = {
143 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
146 "perf probe --list",
147 NULL
148};
149
150static const struct option options[] = {
151 OPT_BOOLEAN('v', "verbose", &verbose,
152 "be more verbose (show parsed arguments, etc)"),
153#ifndef NO_LIBDWARF
154 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
155 "file", "vmlinux pathname"),
156#endif
157 OPT_BOOLEAN('l', "list", &session.list_events,
158 "list up current probe events"),
159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
160 opt_del_probe_event),
161 OPT_CALLBACK('a', "add", NULL,
162#ifdef NO_LIBDWARF
163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]",
164#else
165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
166#endif
167 "probe point definition, where\n"
168 "\t\tGROUP:\tGroup name (optional)\n"
169 "\t\tEVENT:\tEvent name\n"
170 "\t\tFUNC:\tFunction name\n"
171 "\t\tOFFS:\tOffset from function entry (in byte)\n"
172 "\t\t%return:\tPut the probe at function return\n"
173#ifdef NO_LIBDWARF
174 "\t\tARG:\tProbe argument (only \n"
175#else
176 "\t\tSRC:\tSource code path\n"
177 "\t\tRLN:\tRelative line number from function entry.\n"
178 "\t\tALN:\tAbsolute line number in file.\n"
179 "\t\tARG:\tProbe argument (local variable name or\n"
180#endif
181 "\t\t\tkprobe-tracer argument format.)\n",
182 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
184 " with existing name"),
185 OPT_END()
186};
187
188int cmd_probe(int argc, const char **argv, const char *prefix __used)
189{
190 int i, ret;
191#ifndef NO_LIBDWARF
192 int fd;
193#endif
194 struct probe_point *pp;
195
196 argc = parse_options(argc, argv, options, probe_usage,
197 PARSE_OPT_STOP_AT_NON_OPTION);
198 if (argc > 0) {
199 if (strcmp(argv[0], "-") == 0) {
200 pr_warning(" Error: '-' is not supported.\n");
201 usage_with_options(probe_usage, options);
202 }
203 parse_probe_event_argv(argc, argv);
204 }
205
206 if ((!session.nr_probe && !session.dellist && !session.list_events))
207 usage_with_options(probe_usage, options);
208
209 if (debugfs_valid_mountpoint(debugfs_path) < 0)
210 die("Failed to find debugfs path.");
211
212 if (session.list_events) {
213 if (session.nr_probe != 0 || session.dellist) {
214 pr_warning(" Error: Don't use --list with"
215 " --add/--del.\n");
216 usage_with_options(probe_usage, options);
217 }
218 show_perf_probe_events();
219 return 0;
220 }
221
222 if (session.dellist) {
223 del_trace_kprobe_events(session.dellist);
224 strlist__delete(session.dellist);
225 if (session.nr_probe == 0)
226 return 0;
227 }
228
229 /* Initialize symbol maps for vmlinux */
230 symbol_conf.sort_by_name = true;
231 if (symbol_conf.vmlinux_name == NULL)
232 symbol_conf.try_vmlinux_path = true;
233 if (symbol__init() < 0)
234 die("Failed to init symbol map.");
235 session.psession = perf_session__new(NULL, O_WRONLY, false);
236 if (session.psession == NULL)
237 die("Failed to init perf_session.");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
239 MAP__FUNCTION,
240 "[kernel.kallsyms]");
241 if (!session.kmap)
242 die("Could not find kernel map.\n");
243
244 if (session.need_dwarf)
245#ifdef NO_LIBDWARF
246 die("Debuginfo-analysis is not supported");
247#else /* !NO_LIBDWARF */
248 pr_debug("Some probes require debuginfo.\n");
249
250 fd = open_vmlinux();
251 if (fd < 0) {
252 if (session.need_dwarf)
253 die("Could not open debuginfo file.");
254
255 pr_debug("Could not open vmlinux/module file."
256 " Try to use symbols.\n");
257 goto end_dwarf;
258 }
259
260 /* Searching probe points */
261 for (i = 0; i < session.nr_probe; i++) {
262 pp = &session.probes[i];
263 if (pp->found)
264 continue;
265
266 lseek(fd, SEEK_SET, 0);
267 ret = find_probepoint(fd, pp);
268 if (ret > 0)
269 continue;
270 if (ret == 0) { /* No error but failed to find probe point. */
271 synthesize_perf_probe_point(pp);
272 die("Probe point '%s' not found. - probe not added.",
273 pp->probes[0]);
274 }
275 /* Error path */
276 if (session.need_dwarf) {
277 if (ret == -ENOENT)
278 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
279 die("Could not analyze debuginfo.");
280 }
281 pr_debug("An error occurred in debuginfo analysis."
282 " Try to use symbols.\n");
283 break;
284 }
285 close(fd);
286
287end_dwarf:
288#endif /* !NO_LIBDWARF */
289
290 /* Synthesize probes without dwarf */
291 for (i = 0; i < session.nr_probe; i++) {
292 pp = &session.probes[i];
293 if (pp->found) /* This probe is already found. */
294 continue;
295
296 evaluate_probe_point(pp);
297 ret = synthesize_trace_kprobe_event(pp);
298 if (ret == -E2BIG)
299 die("probe point definition becomes too long.");
300 else if (ret < 0)
301 die("Failed to synthesize a probe point.");
302 }
303
304 /* Settng up probe points */
305 add_trace_kprobe_events(session.probes, session.nr_probe,
306 session.force_add);
307 return 0;
308}
309
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a4be453fc8a9..63136d0534d4 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,25 @@ 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 struct perf_session *self __used)
128{
129 write_event(event, event->header.size);
130 return 0;
131}
132
116static void mmap_read(struct mmap_data *md) 133static void mmap_read(struct mmap_data *md)
117{ 134{
118 unsigned int head = mmap_read_head(md); 135 unsigned int head = mmap_read_head(md);
@@ -161,14 +178,14 @@ static void mmap_read(struct mmap_data *md)
161 size = md->mask + 1 - (old & md->mask); 178 size = md->mask + 1 - (old & md->mask);
162 old += size; 179 old += size;
163 180
164 write_output(buf, size); 181 write_event(buf, size);
165 } 182 }
166 183
167 buf = &data[old & md->mask]; 184 buf = &data[old & md->mask];
168 size = head - old; 185 size = head - old;
169 old += size; 186 old += size;
170 187
171 write_output(buf, size); 188 write_event(buf, size);
172 189
173 md->prev = old; 190 md->prev = old;
174 mmap_write_tail(md, old); 191 mmap_write_tail(md, old);
@@ -195,179 +212,21 @@ static void sig_atexit(void)
195 kill(getpid(), signr); 212 kill(getpid(), signr);
196} 213}
197 214
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; 215static int group_fd;
361 216
362static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 217static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
363{ 218{
364 struct perf_header_attr *h_attr; 219 struct perf_header_attr *h_attr;
365 220
366 if (nr < header->attrs) { 221 if (nr < session->header.attrs) {
367 h_attr = header->attr[nr]; 222 h_attr = session->header.attr[nr];
368 } else { 223 } else {
369 h_attr = perf_header_attr__new(a); 224 h_attr = perf_header_attr__new(a);
370 perf_header__add_attr(header, h_attr); 225 if (h_attr != NULL)
226 if (perf_header__add_attr(&session->header, h_attr) < 0) {
227 perf_header_attr__delete(h_attr);
228 h_attr = NULL;
229 }
371 } 230 }
372 231
373 return h_attr; 232 return h_attr;
@@ -375,9 +234,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
375 234
376static void create_counter(int counter, int cpu, pid_t pid) 235static void create_counter(int counter, int cpu, pid_t pid)
377{ 236{
237 char *filter = filters[counter];
378 struct perf_event_attr *attr = attrs + counter; 238 struct perf_event_attr *attr = attrs + counter;
379 struct perf_header_attr *h_attr; 239 struct perf_header_attr *h_attr;
380 int track = !counter; /* only the first counter needs these */ 240 int track = !counter; /* only the first counter needs these */
241 int ret;
381 struct { 242 struct {
382 u64 count; 243 u64 count;
383 u64 time_enabled; 244 u64 time_enabled;
@@ -417,7 +278,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
417 278
418 attr->mmap = track; 279 attr->mmap = track;
419 attr->comm = track; 280 attr->comm = track;
420 attr->inherit = (cpu < 0) && inherit; 281 attr->inherit = inherit;
421 attr->disabled = 1; 282 attr->disabled = 1;
422 283
423try_again: 284try_again:
@@ -448,11 +309,19 @@ try_again:
448 printf("\n"); 309 printf("\n");
449 error("perfcounter syscall returned with %d (%s)\n", 310 error("perfcounter syscall returned with %d (%s)\n",
450 fd[nr_cpu][counter], strerror(err)); 311 fd[nr_cpu][counter], strerror(err));
312
313#if defined(__i386__) || defined(__x86_64__)
314 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
315 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");
316#endif
317
451 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 318 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
452 exit(-1); 319 exit(-1);
453 } 320 }
454 321
455 h_attr = get_header_attr(attr, counter); 322 h_attr = get_header_attr(attr, counter);
323 if (h_attr == NULL)
324 die("nomem\n");
456 325
457 if (!file_new) { 326 if (!file_new) {
458 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 327 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +335,10 @@ try_again:
466 exit(-1); 335 exit(-1);
467 } 336 }
468 337
469 perf_header_attr__add_id(h_attr, read_data.id); 338 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
339 pr_warning("Not enough memory to add id\n");
340 exit(-1);
341 }
470 342
471 assert(fd[nr_cpu][counter] >= 0); 343 assert(fd[nr_cpu][counter] >= 0);
472 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 344 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +352,6 @@ try_again:
480 multiplex_fd = fd[nr_cpu][counter]; 352 multiplex_fd = fd[nr_cpu][counter];
481 353
482 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 354 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
483 int ret;
484 355
485 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 356 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
486 assert(ret != -1); 357 assert(ret != -1);
@@ -500,6 +371,16 @@ try_again:
500 } 371 }
501 } 372 }
502 373
374 if (filter != NULL) {
375 ret = ioctl(fd[nr_cpu][counter],
376 PERF_EVENT_IOC_SET_FILTER, filter);
377 if (ret) {
378 error("failed to set filter with %d (%s)\n", errno,
379 strerror(errno));
380 exit(-1);
381 }
382 }
383
503 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 384 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
504} 385}
505 386
@@ -516,19 +397,21 @@ static void open_counters(int cpu, pid_t pid)
516 397
517static void atexit_header(void) 398static void atexit_header(void)
518{ 399{
519 header->data_size += bytes_written; 400 session->header.data_size += bytes_written;
520 401
521 perf_header__write(header, output); 402 perf_header__write(&session->header, output, true);
522} 403}
523 404
524static int __cmd_record(int argc, const char **argv) 405static int __cmd_record(int argc __used, const char **argv)
525{ 406{
526 int i, counter; 407 int i, counter;
527 struct stat st; 408 struct stat st;
528 pid_t pid = 0; 409 pid_t pid = 0;
529 int flags; 410 int flags;
530 int ret; 411 int err;
531 unsigned long waking = 0; 412 unsigned long waking = 0;
413 int child_ready_pipe[2], go_pipe[2];
414 char buf;
532 415
533 page_size = sysconf(_SC_PAGE_SIZE); 416 page_size = sysconf(_SC_PAGE_SIZE);
534 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 417 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -539,11 +422,25 @@ static int __cmd_record(int argc, const char **argv)
539 signal(SIGCHLD, sig_handler); 422 signal(SIGCHLD, sig_handler);
540 signal(SIGINT, sig_handler); 423 signal(SIGINT, sig_handler);
541 424
425 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
426 perror("failed to create pipes");
427 exit(-1);
428 }
429
542 if (!stat(output_name, &st) && st.st_size) { 430 if (!stat(output_name, &st) && st.st_size) {
543 if (!force && !append_file) { 431 if (!force) {
544 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 432 if (!append_file) {
545 output_name); 433 pr_err("Error, output file %s exists, use -A "
546 exit(-1); 434 "to append or -f to overwrite.\n",
435 output_name);
436 exit(-1);
437 }
438 } else {
439 char oldname[PATH_MAX];
440 snprintf(oldname, sizeof(oldname), "%s.old",
441 output_name);
442 unlink(oldname);
443 rename(output_name, oldname);
547 } 444 }
548 } else { 445 } else {
549 append_file = 0; 446 append_file = 0;
@@ -561,73 +458,119 @@ static int __cmd_record(int argc, const char **argv)
561 exit(-1); 458 exit(-1);
562 } 459 }
563 460
564 if (!file_new) 461 session = perf_session__new(output_name, O_WRONLY, force);
565 header = perf_header__read(output); 462 if (session == NULL) {
566 else 463 pr_err("Not enough memory for reading perf file header\n");
567 header = perf_header__new(); 464 return -1;
465 }
568 466
467 if (!file_new) {
468 err = perf_header__read(&session->header, output);
469 if (err < 0)
470 return err;
471 }
569 472
570 if (raw_samples) { 473 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 474 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
572 } else { 475 } else {
573 for (i = 0; i < nr_counters; i++) { 476 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 477 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 478 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
576 break; 479 break;
577 } 480 }
578 } 481 }
579 } 482 }
580 atexit(atexit_header);
581
582 if (!system_wide) {
583 pid = target_pid;
584 if (pid == -1)
585 pid = getpid();
586
587 open_counters(profile_cpu, pid);
588 } else {
589 if (profile_cpu != -1) {
590 open_counters(profile_cpu, target_pid);
591 } else {
592 for (i = 0; i < nr_cpus; i++)
593 open_counters(i, target_pid);
594 }
595 }
596
597 if (file_new)
598 perf_header__write(header, output);
599 483
600 if (!system_wide) { 484 atexit(atexit_header);
601 pid_t tgid = pid_synthesize_comm_event(pid, 0);
602 pid_synthesize_mmap_samples(pid, tgid);
603 } else
604 synthesize_all();
605 485
606 if (target_pid == -1 && argc) { 486 if (target_pid == -1) {
607 pid = fork(); 487 pid = fork();
608 if (pid < 0) 488 if (pid < 0) {
609 perror("failed to fork"); 489 perror("failed to fork");
490 exit(-1);
491 }
610 492
611 if (!pid) { 493 if (!pid) {
612 if (execvp(argv[0], (char **)argv)) { 494 close(child_ready_pipe[0]);
613 perror(argv[0]); 495 close(go_pipe[1]);
614 exit(-1); 496 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
615 } 497
498 /*
499 * Do a dummy execvp to get the PLT entry resolved,
500 * so we avoid the resolver overhead on the real
501 * execvp call.
502 */
503 execvp("", (char **)argv);
504
505 /*
506 * Tell the parent we're ready to go
507 */
508 close(child_ready_pipe[1]);
509
510 /*
511 * Wait until the parent tells us to go.
512 */
513 if (read(go_pipe[0], &buf, 1) == -1)
514 perror("unable to read pipe");
515
516 execvp(argv[0], (char **)argv);
517
518 perror(argv[0]);
519 exit(-1);
616 } 520 }
617 521
618 child_pid = pid; 522 child_pid = pid;
523
524 if (!system_wide)
525 target_pid = pid;
526
527 close(child_ready_pipe[1]);
528 close(go_pipe[0]);
529 /*
530 * wait for child to settle
531 */
532 if (read(child_ready_pipe[0], &buf, 1) == -1) {
533 perror("unable to read pipe");
534 exit(-1);
535 }
536 close(child_ready_pipe[0]);
619 } 537 }
620 538
539
540 if ((!system_wide && !inherit) || profile_cpu != -1) {
541 open_counters(profile_cpu, target_pid);
542 } else {
543 for (i = 0; i < nr_cpus; i++)
544 open_counters(i, target_pid);
545 }
546
547 if (file_new) {
548 err = perf_header__write(&session->header, output, false);
549 if (err < 0)
550 return err;
551 }
552
553 if (!system_wide)
554 event__synthesize_thread(pid, process_synthesized_event,
555 session);
556 else
557 event__synthesize_threads(process_synthesized_event, session);
558
621 if (realtime_prio) { 559 if (realtime_prio) {
622 struct sched_param param; 560 struct sched_param param;
623 561
624 param.sched_priority = realtime_prio; 562 param.sched_priority = realtime_prio;
625 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 563 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
626 printf("Could not set realtime priority.\n"); 564 pr_err("Could not set realtime priority.\n");
627 exit(-1); 565 exit(-1);
628 } 566 }
629 } 567 }
630 568
569 /*
570 * Let the child rip
571 */
572 close(go_pipe[1]);
573
631 for (;;) { 574 for (;;) {
632 int hits = samples; 575 int hits = samples;
633 576
@@ -641,7 +584,7 @@ static int __cmd_record(int argc, const char **argv)
641 if (hits == samples) { 584 if (hits == samples) {
642 if (done) 585 if (done)
643 break; 586 break;
644 ret = poll(event_array, nr_poll, -1); 587 err = poll(event_array, nr_poll, -1);
645 waking++; 588 waking++;
646 } 589 }
647 590
@@ -677,6 +620,8 @@ static const struct option options[] = {
677 OPT_CALLBACK('e', "event", NULL, "event", 620 OPT_CALLBACK('e', "event", NULL, "event",
678 "event selector. use 'perf list' to list available events", 621 "event selector. use 'perf list' to list available events",
679 parse_events), 622 parse_events),
623 OPT_CALLBACK(0, "filter", NULL, "filter",
624 "event filter", parse_filter),
680 OPT_INTEGER('p', "pid", &target_pid, 625 OPT_INTEGER('p', "pid", &target_pid,
681 "record events on existing pid"), 626 "record events on existing pid"),
682 OPT_INTEGER('r', "realtime", &realtime_prio, 627 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -721,16 +666,30 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
721 int counter; 666 int counter;
722 667
723 argc = parse_options(argc, argv, options, record_usage, 668 argc = parse_options(argc, argv, options, record_usage,
724 PARSE_OPT_STOP_AT_NON_OPTION); 669 PARSE_OPT_STOP_AT_NON_OPTION);
725 if (!argc && target_pid == -1 && !system_wide) 670 if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1))
726 usage_with_options(record_usage, options); 671 usage_with_options(record_usage, options);
727 672
673 symbol__init();
674
728 if (!nr_counters) { 675 if (!nr_counters) {
729 nr_counters = 1; 676 nr_counters = 1;
730 attrs[0].type = PERF_TYPE_HARDWARE; 677 attrs[0].type = PERF_TYPE_HARDWARE;
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 678 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 679 }
733 680
681 /*
682 * User specified count overrides default frequency.
683 */
684 if (default_interval)
685 freq = 0;
686 else if (freq) {
687 default_interval = freq;
688 } else {
689 fprintf(stderr, "frequency and count are zero, aborting\n");
690 exit(EXIT_FAILURE);
691 }
692
734 for (counter = 0; counter < nr_counters; counter++) { 693 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 694 if (attrs[counter].sample_period)
736 continue; 695 continue;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 19669c20088e..5c2ab5357ec6 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -22,27 +22,18 @@
22#include "perf.h" 22#include "perf.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/header.h" 24#include "util/header.h"
25#include "util/session.h"
25 26
26#include "util/parse-options.h" 27#include "util/parse-options.h"
27#include "util/parse-events.h" 28#include "util/parse-events.h"
28 29
29#include "util/thread.h" 30#include "util/thread.h"
31#include "util/sort.h"
32#include "util/hist.h"
30 33
31static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
32 35
33static char default_sort_order[] = "comm,dso,symbol";
34static char *sort_order = default_sort_order;
35static char *dso_list_str, *comm_list_str, *sym_list_str,
36 *col_width_list_str;
37static struct strlist *dso_list, *comm_list, *sym_list;
38static char *field_sep;
39
40static int force; 36static int force;
41static int input;
42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43
44static int full_paths;
45static int show_nr_samples;
46 37
47static int show_threads; 38static int show_threads;
48static struct perf_read_values show_threads_values; 39static struct perf_read_values show_threads_values;
@@ -50,1043 +41,36 @@ static struct perf_read_values show_threads_values;
50static char default_pretty_printing_style[] = "normal"; 41static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style; 42static char *pretty_printing_style = default_pretty_printing_style;
52 43
53static unsigned long page_size;
54static unsigned long mmap_window = 32;
55
56static char default_parent_pattern[] = "^sys_|^do_page_fault";
57static char *parent_pattern = default_parent_pattern;
58static regex_t parent_regex;
59
60static int exclude_other = 1;
61
62static char callchain_default_opt[] = "fractal,0.5"; 44static char callchain_default_opt[] = "fractal,0.5";
63 45
64static int callchain; 46static int perf_session__add_hist_entry(struct perf_session *self,
65 47 struct addr_location *al,
66static char __cwd[PATH_MAX]; 48 struct ip_callchain *chain, u64 count)
67static char *cwd = __cwd;
68static int cwdlen;
69
70static struct rb_root threads;
71static struct thread *last_match;
72
73static struct perf_header *header;
74
75static
76struct callchain_param callchain_param = {
77 .mode = CHAIN_GRAPH_REL,
78 .min_percent = 0.5
79};
80
81static u64 sample_type;
82
83static int repsep_fprintf(FILE *fp, const char *fmt, ...)
84{
85 int n;
86 va_list ap;
87
88 va_start(ap, fmt);
89 if (!field_sep)
90 n = vfprintf(fp, fmt, ap);
91 else {
92 char *bf = NULL;
93 n = vasprintf(&bf, fmt, ap);
94 if (n > 0) {
95 char *sep = bf;
96
97 while (1) {
98 sep = strchr(sep, *field_sep);
99 if (sep == NULL)
100 break;
101 *sep = '.';
102 }
103 }
104 fputs(bf, fp);
105 free(bf);
106 }
107 va_end(ap);
108 return n;
109}
110
111static unsigned int dsos__col_width,
112 comms__col_width,
113 threads__col_width;
114
115/*
116 * histogram, sorted on item, collects counts
117 */
118
119static struct rb_root hist;
120
121struct hist_entry {
122 struct rb_node rb_node;
123
124 struct thread *thread;
125 struct map *map;
126 struct dso *dso;
127 struct symbol *sym;
128 struct symbol *parent;
129 u64 ip;
130 char level;
131 struct callchain_node callchain;
132 struct rb_root sorted_chain;
133
134 u64 count;
135};
136
137/*
138 * configurable sorting bits
139 */
140
141struct sort_entry {
142 struct list_head list;
143
144 const char *header;
145
146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
148 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 unsigned int *width;
150 bool elide;
151};
152
153static int64_t cmp_null(void *l, void *r)
154{
155 if (!l && !r)
156 return 0;
157 else if (!l)
158 return -1;
159 else
160 return 1;
161}
162
163/* --sort pid */
164
165static int64_t
166sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
167{
168 return right->thread->pid - left->thread->pid;
169}
170
171static size_t
172sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
173{
174 return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 self->thread->comm ?: "", self->thread->pid);
176}
177
178static struct sort_entry sort_thread = {
179 .header = "Command: Pid",
180 .cmp = sort__thread_cmp,
181 .print = sort__thread_print,
182 .width = &threads__col_width,
183};
184
185/* --sort comm */
186
187static int64_t
188sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
189{
190 return right->thread->pid - left->thread->pid;
191}
192
193static int64_t
194sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
195{
196 char *comm_l = left->thread->comm;
197 char *comm_r = right->thread->comm;
198
199 if (!comm_l || !comm_r)
200 return cmp_null(comm_l, comm_r);
201
202 return strcmp(comm_l, comm_r);
203}
204
205static size_t
206sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
207{
208 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
209}
210
211static struct sort_entry sort_comm = {
212 .header = "Command",
213 .cmp = sort__comm_cmp,
214 .collapse = sort__comm_collapse,
215 .print = sort__comm_print,
216 .width = &comms__col_width,
217};
218
219/* --sort dso */
220
221static int64_t
222sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
223{ 49{
224 struct dso *dso_l = left->dso; 50 struct symbol **syms = NULL, *parent = NULL;
225 struct dso *dso_r = right->dso; 51 bool hit;
226
227 if (!dso_l || !dso_r)
228 return cmp_null(dso_l, dso_r);
229
230 return strcmp(dso_l->name, dso_r->name);
231}
232
233static size_t
234sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
235{
236 if (self->dso)
237 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
238
239 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
240}
241
242static struct sort_entry sort_dso = {
243 .header = "Shared Object",
244 .cmp = sort__dso_cmp,
245 .print = sort__dso_print,
246 .width = &dsos__col_width,
247};
248
249/* --sort symbol */
250
251static int64_t
252sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
253{
254 u64 ip_l, ip_r;
255
256 if (left->sym == right->sym)
257 return 0;
258
259 ip_l = left->sym ? left->sym->start : left->ip;
260 ip_r = right->sym ? right->sym->start : right->ip;
261
262 return (int64_t)(ip_r - ip_l);
263}
264
265static size_t
266sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
267{
268 size_t ret = 0;
269
270 if (verbose)
271 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 dso__symtab_origin(self->dso));
273
274 ret += repsep_fprintf(fp, "[%c] ", self->level);
275 if (self->sym) {
276 ret += repsep_fprintf(fp, "%s", self->sym->name);
277
278 if (self->sym->module)
279 ret += repsep_fprintf(fp, "\t[%s]",
280 self->sym->module->name);
281 } else {
282 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 }
284
285 return ret;
286}
287
288static struct sort_entry sort_sym = {
289 .header = "Symbol",
290 .cmp = sort__sym_cmp,
291 .print = sort__sym_print,
292};
293
294/* --sort parent */
295
296static int64_t
297sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
298{
299 struct symbol *sym_l = left->parent;
300 struct symbol *sym_r = right->parent;
301
302 if (!sym_l || !sym_r)
303 return cmp_null(sym_l, sym_r);
304
305 return strcmp(sym_l->name, sym_r->name);
306}
307
308static size_t
309sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
310{
311 return repsep_fprintf(fp, "%-*s", width,
312 self->parent ? self->parent->name : "[other]");
313}
314
315static unsigned int parent_symbol__col_width;
316
317static struct sort_entry sort_parent = {
318 .header = "Parent symbol",
319 .cmp = sort__parent_cmp,
320 .print = sort__parent_print,
321 .width = &parent_symbol__col_width,
322};
323
324static int sort__need_collapse = 0;
325static int sort__has_parent = 0;
326
327struct sort_dimension {
328 const char *name;
329 struct sort_entry *entry;
330 int taken;
331};
332
333static struct sort_dimension sort_dimensions[] = {
334 { .name = "pid", .entry = &sort_thread, },
335 { .name = "comm", .entry = &sort_comm, },
336 { .name = "dso", .entry = &sort_dso, },
337 { .name = "symbol", .entry = &sort_sym, },
338 { .name = "parent", .entry = &sort_parent, },
339};
340
341static LIST_HEAD(hist_entry__sort_list);
342
343static int sort_dimension__add(const char *tok)
344{
345 unsigned int i;
346
347 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
348 struct sort_dimension *sd = &sort_dimensions[i];
349
350 if (sd->taken)
351 continue;
352
353 if (strncasecmp(tok, sd->name, strlen(tok)))
354 continue;
355
356 if (sd->entry->collapse)
357 sort__need_collapse = 1;
358
359 if (sd->entry == &sort_parent) {
360 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
361 if (ret) {
362 char err[BUFSIZ];
363
364 regerror(ret, &parent_regex, err, sizeof(err));
365 fprintf(stderr, "Invalid regex: %s\n%s",
366 parent_pattern, err);
367 exit(-1);
368 }
369 sort__has_parent = 1;
370 }
371
372 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
373 sd->taken = 1;
374
375 return 0;
376 }
377
378 return -ESRCH;
379}
380
381static int64_t
382hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct sort_entry *se;
385 int64_t cmp = 0;
386
387 list_for_each_entry(se, &hist_entry__sort_list, list) {
388 cmp = se->cmp(left, right);
389 if (cmp)
390 break;
391 }
392
393 return cmp;
394}
395
396static int64_t
397hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
398{
399 struct sort_entry *se;
400 int64_t cmp = 0;
401
402 list_for_each_entry(se, &hist_entry__sort_list, list) {
403 int64_t (*f)(struct hist_entry *, struct hist_entry *);
404
405 f = se->collapse ?: se->cmp;
406
407 cmp = f(left, right);
408 if (cmp)
409 break;
410 }
411
412 return cmp;
413}
414
415static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416{
417 int i;
418 size_t ret = 0;
419
420 ret += fprintf(fp, "%s", " ");
421
422 for (i = 0; i < depth; i++)
423 if (depth_mask & (1 << i))
424 ret += fprintf(fp, "| ");
425 else
426 ret += fprintf(fp, " ");
427
428 ret += fprintf(fp, "\n");
429
430 return ret;
431}
432static size_t
433ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 int depth_mask, int count, u64 total_samples,
435 int hits)
436{
437 int i;
438 size_t ret = 0;
439
440 ret += fprintf(fp, "%s", " ");
441 for (i = 0; i < depth; i++) {
442 if (depth_mask & (1 << i))
443 ret += fprintf(fp, "|");
444 else
445 ret += fprintf(fp, " ");
446 if (!count && i == depth - 1) {
447 double percent;
448
449 percent = hits * 100.0 / total_samples;
450 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
451 } else
452 ret += fprintf(fp, "%s", " ");
453 }
454 if (chain->sym)
455 ret += fprintf(fp, "%s\n", chain->sym->name);
456 else
457 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
458
459 return ret;
460}
461
462static struct symbol *rem_sq_bracket;
463static struct callchain_list rem_hits;
464
465static void init_rem_hits(void)
466{
467 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
468 if (!rem_sq_bracket) {
469 fprintf(stderr, "Not enough memory to display remaining hits\n");
470 return;
471 }
472
473 strcpy(rem_sq_bracket->name, "[...]");
474 rem_hits.sym = rem_sq_bracket;
475}
476
477static size_t
478callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 u64 total_samples, int depth, int depth_mask)
480{
481 struct rb_node *node, *next;
482 struct callchain_node *child;
483 struct callchain_list *chain;
484 int new_depth_mask = depth_mask;
485 u64 new_total;
486 u64 remaining;
487 size_t ret = 0;
488 int i;
489
490 if (callchain_param.mode == CHAIN_GRAPH_REL)
491 new_total = self->children_hit;
492 else
493 new_total = total_samples;
494
495 remaining = new_total;
496
497 node = rb_first(&self->rb_root);
498 while (node) {
499 u64 cumul;
500
501 child = rb_entry(node, struct callchain_node, rb_node);
502 cumul = cumul_hits(child);
503 remaining -= cumul;
504
505 /*
506 * The depth mask manages the output of pipes that show
507 * the depth. We don't want to keep the pipes of the current
508 * level for the last child of this depth.
509 * Except if we have remaining filtered hits. They will
510 * supersede the last child
511 */
512 next = rb_next(node);
513 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
514 new_depth_mask &= ~(1 << (depth - 1));
515
516 /*
517 * But we keep the older depth mask for the line seperator
518 * to keep the level link until we reach the last child
519 */
520 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
521 i = 0;
522 list_for_each_entry(chain, &child->val, list) {
523 if (chain->ip >= PERF_CONTEXT_MAX)
524 continue;
525 ret += ipchain__fprintf_graph(fp, chain, depth,
526 new_depth_mask, i++,
527 new_total,
528 cumul);
529 }
530 ret += callchain__fprintf_graph(fp, child, new_total,
531 depth + 1,
532 new_depth_mask | (1 << depth));
533 node = next;
534 }
535
536 if (callchain_param.mode == CHAIN_GRAPH_REL &&
537 remaining && remaining != new_total) {
538
539 if (!rem_sq_bracket)
540 return ret;
541
542 new_depth_mask &= ~(1 << (depth - 1));
543
544 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 new_depth_mask, 0, new_total,
546 remaining);
547 }
548
549 return ret;
550}
551
552static size_t
553callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
554 u64 total_samples)
555{
556 struct callchain_list *chain;
557 size_t ret = 0;
558
559 if (!self)
560 return 0;
561
562 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
563
564
565 list_for_each_entry(chain, &self->val, list) {
566 if (chain->ip >= PERF_CONTEXT_MAX)
567 continue;
568 if (chain->sym)
569 ret += fprintf(fp, " %s\n", chain->sym->name);
570 else
571 ret += fprintf(fp, " %p\n",
572 (void *)(long)chain->ip);
573 }
574
575 return ret;
576}
577
578static size_t
579hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 u64 total_samples)
581{
582 struct rb_node *rb_node;
583 struct callchain_node *chain;
584 size_t ret = 0;
585
586 rb_node = rb_first(&self->sorted_chain);
587 while (rb_node) {
588 double percent;
589
590 chain = rb_entry(rb_node, struct callchain_node, rb_node);
591 percent = chain->hit * 100.0 / total_samples;
592 switch (callchain_param.mode) {
593 case CHAIN_FLAT:
594 ret += percent_color_fprintf(fp, " %6.2f%%\n",
595 percent);
596 ret += callchain__fprintf_flat(fp, chain, total_samples);
597 break;
598 case CHAIN_GRAPH_ABS: /* Falldown */
599 case CHAIN_GRAPH_REL:
600 ret += callchain__fprintf_graph(fp, chain,
601 total_samples, 1, 1);
602 case CHAIN_NONE:
603 default:
604 break;
605 }
606 ret += fprintf(fp, "\n");
607 rb_node = rb_next(rb_node);
608 }
609
610 return ret;
611}
612
613
614static size_t
615hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616{
617 struct sort_entry *se;
618 size_t ret;
619
620 if (exclude_other && !self->parent)
621 return 0;
622
623 if (total_samples)
624 ret = percent_color_fprintf(fp,
625 field_sep ? "%.2f" : " %6.2f%%",
626 (self->count * 100.0) / total_samples);
627 else
628 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
629
630 if (show_nr_samples) {
631 if (field_sep)
632 fprintf(fp, "%c%lld", *field_sep, self->count);
633 else
634 fprintf(fp, "%11lld", self->count);
635 }
636
637 list_for_each_entry(se, &hist_entry__sort_list, list) {
638 if (se->elide)
639 continue;
640
641 fprintf(fp, "%s", field_sep ?: " ");
642 ret += se->print(fp, self, se->width ? *se->width : 0);
643 }
644
645 ret += fprintf(fp, "\n");
646
647 if (callchain)
648 hist_entry_callchain__fprintf(fp, self, total_samples);
649
650 return ret;
651}
652
653/*
654 *
655 */
656
657static void dso__calc_col_width(struct dso *self)
658{
659 if (!col_width_list_str && !field_sep &&
660 (!dso_list || strlist__has_entry(dso_list, self->name))) {
661 unsigned int slen = strlen(self->name);
662 if (slen > dsos__col_width)
663 dsos__col_width = slen;
664 }
665
666 self->slen_calculated = 1;
667}
668
669static void thread__comm_adjust(struct thread *self)
670{
671 char *comm = self->comm;
672
673 if (!col_width_list_str && !field_sep &&
674 (!comm_list || strlist__has_entry(comm_list, comm))) {
675 unsigned int slen = strlen(comm);
676
677 if (slen > comms__col_width) {
678 comms__col_width = slen;
679 threads__col_width = slen + 6;
680 }
681 }
682}
683
684static int thread__set_comm_adjust(struct thread *self, const char *comm)
685{
686 int ret = thread__set_comm(self, comm);
687
688 if (ret)
689 return ret;
690
691 thread__comm_adjust(self);
692
693 return 0;
694}
695
696
697static struct symbol *
698resolve_symbol(struct thread *thread, struct map **mapp,
699 struct dso **dsop, u64 *ipp)
700{
701 struct dso *dso = dsop ? *dsop : NULL;
702 struct map *map = mapp ? *mapp : NULL;
703 u64 ip = *ipp;
704
705 if (!thread)
706 return NULL;
707
708 if (dso)
709 goto got_dso;
710
711 if (map)
712 goto got_map;
713
714 map = thread__find_map(thread, ip);
715 if (map != NULL) {
716 /*
717 * We have to do this here as we may have a dso
718 * with no symbol hit that has a name longer than
719 * the ones with symbols sampled.
720 */
721 if (!sort_dso.elide && !map->dso->slen_calculated)
722 dso__calc_col_width(map->dso);
723
724 if (mapp)
725 *mapp = map;
726got_map:
727 ip = map->map_ip(map, ip);
728
729 dso = map->dso;
730 } else {
731 /*
732 * If this is outside of all known maps,
733 * and is a negative address, try to look it
734 * up in the kernel dso, as it might be a
735 * vsyscall (which executes in user-mode):
736 */
737 if ((long long)ip < 0)
738 dso = kernel_dso;
739 }
740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 *ipp = ip;
743
744 if (dsop)
745 *dsop = dso;
746
747 if (!dso)
748 return NULL;
749got_dso:
750 return dso->find_symbol(dso, ip);
751}
752
753static int call__match(struct symbol *sym)
754{
755 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
756 return 1;
757
758 return 0;
759}
760
761static struct symbol **
762resolve_callchain(struct thread *thread, struct map *map __used,
763 struct ip_callchain *chain, struct hist_entry *entry)
764{
765 u64 context = PERF_CONTEXT_MAX;
766 struct symbol **syms = NULL;
767 unsigned int i;
768
769 if (callchain) {
770 syms = calloc(chain->nr, sizeof(*syms));
771 if (!syms) {
772 fprintf(stderr, "Can't allocate memory for symbols\n");
773 exit(-1);
774 }
775 }
776
777 for (i = 0; i < chain->nr; i++) {
778 u64 ip = chain->ips[i];
779 struct dso *dso = NULL;
780 struct symbol *sym;
781
782 if (ip >= PERF_CONTEXT_MAX) {
783 context = ip;
784 continue;
785 }
786
787 switch (context) {
788 case PERF_CONTEXT_HV:
789 dso = hypervisor_dso;
790 break;
791 case PERF_CONTEXT_KERNEL:
792 dso = kernel_dso;
793 break;
794 default:
795 break;
796 }
797
798 sym = resolve_symbol(thread, NULL, &dso, &ip);
799
800 if (sym) {
801 if (sort__has_parent && call__match(sym) &&
802 !entry->parent)
803 entry->parent = sym;
804 if (!callchain)
805 break;
806 syms[i] = sym;
807 }
808 }
809
810 return syms;
811}
812
813/*
814 * collect histogram counts
815 */
816
817static int
818hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
819 struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 char level, u64 count)
821{
822 struct rb_node **p = &hist.rb_node;
823 struct rb_node *parent = NULL;
824 struct hist_entry *he; 52 struct hist_entry *he;
825 struct symbol **syms = NULL;
826 struct hist_entry entry = {
827 .thread = thread,
828 .map = map,
829 .dso = dso,
830 .sym = sym,
831 .ip = ip,
832 .level = level,
833 .count = count,
834 .parent = NULL,
835 .sorted_chain = RB_ROOT
836 };
837 int cmp;
838
839 if ((sort__has_parent || callchain) && chain)
840 syms = resolve_callchain(thread, map, chain, &entry);
841
842 while (*p != NULL) {
843 parent = *p;
844 he = rb_entry(parent, struct hist_entry, rb_node);
845
846 cmp = hist_entry__cmp(&entry, he);
847
848 if (!cmp) {
849 he->count += count;
850 if (callchain) {
851 append_chain(&he->callchain, chain, syms);
852 free(syms);
853 }
854 return 0;
855 }
856
857 if (cmp < 0)
858 p = &(*p)->rb_left;
859 else
860 p = &(*p)->rb_right;
861 }
862 53
863 he = malloc(sizeof(*he)); 54 if ((sort__has_parent || symbol_conf.use_callchain) && chain)
864 if (!he) 55 syms = perf_session__resolve_callchain(self, al->thread,
56 chain, &parent);
57 he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
58 if (he == NULL)
865 return -ENOMEM; 59 return -ENOMEM;
866 *he = entry; 60
867 if (callchain) { 61 if (hit)
868 callchain_init(&he->callchain); 62 he->count += count;
63
64 if (symbol_conf.use_callchain) {
65 if (!hit)
66 callchain_init(&he->callchain);
869 append_chain(&he->callchain, chain, syms); 67 append_chain(&he->callchain, chain, syms);
870 free(syms); 68 free(syms);
871 } 69 }
872 rb_link_node(&he->rb_node, parent, p);
873 rb_insert_color(&he->rb_node, &hist);
874 70
875 return 0; 71 return 0;
876} 72}
877 73
878static void hist_entry__free(struct hist_entry *he)
879{
880 free(he);
881}
882
883/*
884 * collapse the histogram
885 */
886
887static struct rb_root collapse_hists;
888
889static void collapse__insert_entry(struct hist_entry *he)
890{
891 struct rb_node **p = &collapse_hists.rb_node;
892 struct rb_node *parent = NULL;
893 struct hist_entry *iter;
894 int64_t cmp;
895
896 while (*p != NULL) {
897 parent = *p;
898 iter = rb_entry(parent, struct hist_entry, rb_node);
899
900 cmp = hist_entry__collapse(iter, he);
901
902 if (!cmp) {
903 iter->count += he->count;
904 hist_entry__free(he);
905 return;
906 }
907
908 if (cmp < 0)
909 p = &(*p)->rb_left;
910 else
911 p = &(*p)->rb_right;
912 }
913
914 rb_link_node(&he->rb_node, parent, p);
915 rb_insert_color(&he->rb_node, &collapse_hists);
916}
917
918static void collapse__resort(void)
919{
920 struct rb_node *next;
921 struct hist_entry *n;
922
923 if (!sort__need_collapse)
924 return;
925
926 next = rb_first(&hist);
927 while (next) {
928 n = rb_entry(next, struct hist_entry, rb_node);
929 next = rb_next(&n->rb_node);
930
931 rb_erase(&n->rb_node, &hist);
932 collapse__insert_entry(n);
933 }
934}
935
936/*
937 * reverse the map, sort on count.
938 */
939
940static struct rb_root output_hists;
941
942static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
943{
944 struct rb_node **p = &output_hists.rb_node;
945 struct rb_node *parent = NULL;
946 struct hist_entry *iter;
947
948 if (callchain)
949 callchain_param.sort(&he->sorted_chain, &he->callchain,
950 min_callchain_hits, &callchain_param);
951
952 while (*p != NULL) {
953 parent = *p;
954 iter = rb_entry(parent, struct hist_entry, rb_node);
955
956 if (he->count > iter->count)
957 p = &(*p)->rb_left;
958 else
959 p = &(*p)->rb_right;
960 }
961
962 rb_link_node(&he->rb_node, parent, p);
963 rb_insert_color(&he->rb_node, &output_hists);
964}
965
966static void output__resort(u64 total_samples)
967{
968 struct rb_node *next;
969 struct hist_entry *n;
970 struct rb_root *tree = &hist;
971 u64 min_callchain_hits;
972
973 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
974
975 if (sort__need_collapse)
976 tree = &collapse_hists;
977
978 next = rb_first(tree);
979
980 while (next) {
981 n = rb_entry(next, struct hist_entry, rb_node);
982 next = rb_next(&n->rb_node);
983
984 rb_erase(&n->rb_node, tree);
985 output__insert_entry(n, min_callchain_hits);
986 }
987}
988
989static size_t output__fprintf(FILE *fp, u64 total_samples)
990{
991 struct hist_entry *pos;
992 struct sort_entry *se;
993 struct rb_node *nd;
994 size_t ret = 0;
995 unsigned int width;
996 char *col_width = col_width_list_str;
997 int raw_printing_style;
998
999 raw_printing_style = !strcmp(pretty_printing_style, "raw");
1000
1001 init_rem_hits();
1002
1003 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1004 fprintf(fp, "#\n");
1005
1006 fprintf(fp, "# Overhead");
1007 if (show_nr_samples) {
1008 if (field_sep)
1009 fprintf(fp, "%cSamples", *field_sep);
1010 else
1011 fputs(" Samples ", fp);
1012 }
1013 list_for_each_entry(se, &hist_entry__sort_list, list) {
1014 if (se->elide)
1015 continue;
1016 if (field_sep) {
1017 fprintf(fp, "%c%s", *field_sep, se->header);
1018 continue;
1019 }
1020 width = strlen(se->header);
1021 if (se->width) {
1022 if (col_width_list_str) {
1023 if (col_width) {
1024 *se->width = atoi(col_width);
1025 col_width = strchr(col_width, ',');
1026 if (col_width)
1027 ++col_width;
1028 }
1029 }
1030 width = *se->width = max(*se->width, width);
1031 }
1032 fprintf(fp, " %*s", width, se->header);
1033 }
1034 fprintf(fp, "\n");
1035
1036 if (field_sep)
1037 goto print_entries;
1038
1039 fprintf(fp, "# ........");
1040 if (show_nr_samples)
1041 fprintf(fp, " ..........");
1042 list_for_each_entry(se, &hist_entry__sort_list, list) {
1043 unsigned int i;
1044
1045 if (se->elide)
1046 continue;
1047
1048 fprintf(fp, " ");
1049 if (se->width)
1050 width = *se->width;
1051 else
1052 width = strlen(se->header);
1053 for (i = 0; i < width; i++)
1054 fprintf(fp, ".");
1055 }
1056 fprintf(fp, "\n");
1057
1058 fprintf(fp, "#\n");
1059
1060print_entries:
1061 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1062 pos = rb_entry(nd, struct hist_entry, rb_node);
1063 ret += hist_entry__fprintf(fp, pos, total_samples);
1064 }
1065
1066 if (sort_order == default_sort_order &&
1067 parent_pattern == default_parent_pattern) {
1068 fprintf(fp, "#\n");
1069 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1070 fprintf(fp, "#\n");
1071 }
1072 fprintf(fp, "\n");
1073
1074 free(rem_sq_bracket);
1075
1076 if (show_threads)
1077 perf_read_values_display(fp, &show_threads_values,
1078 raw_printing_style);
1079
1080 return ret;
1081}
1082
1083static unsigned long total = 0,
1084 total_mmap = 0,
1085 total_comm = 0,
1086 total_fork = 0,
1087 total_unknown = 0,
1088 total_lost = 0;
1089
1090static int validate_chain(struct ip_callchain *chain, event_t *event) 74static int validate_chain(struct ip_callchain *chain, event_t *event)
1091{ 75{
1092 unsigned int chain_size; 76 unsigned int chain_size;
@@ -1100,214 +84,60 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
1100 return 0; 84 return 0;
1101} 85}
1102 86
1103static int 87static int process_sample_event(event_t *event, struct perf_session *session)
1104process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105{ 88{
1106 char level; 89 struct sample_data data = { .period = 1, };
1107 int show = 0; 90 struct addr_location al;
1108 struct dso *dso = NULL; 91
1109 struct thread *thread; 92 event__parse_sample(event, session->sample_type, &data);
1110 u64 ip = event->ip.ip;
1111 u64 period = 1;
1112 struct map *map = NULL;
1113 void *more_data = event->ip.__more_data;
1114 struct ip_callchain *chain = NULL;
1115 int cpumode;
1116
1117 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1118
1119 if (sample_type & PERF_SAMPLE_PERIOD) {
1120 period = *(u64 *)more_data;
1121 more_data += sizeof(u64);
1122 }
1123 93
1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1125 (void *)(offset + head),
1126 (void *)(long)(event->header.size),
1127 event->header.misc, 95 event->header.misc,
1128 event->ip.pid, event->ip.tid, 96 data.pid, data.tid,
1129 (void *)(long)ip, 97 (void *)(long)data.ip,
1130 (long long)period); 98 (long long)data.period);
1131 99
1132 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
1133 unsigned int i; 101 unsigned int i;
1134 102
1135 chain = (void *)more_data; 103 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
1136 104
1137 dump_printf("... chain: nr:%Lu\n", chain->nr); 105 if (validate_chain(data.callchain, event) < 0) {
1138 106 pr_debug("call-chain problem with event, "
1139 if (validate_chain(chain, event) < 0) { 107 "skipping it.\n");
1140 eprintf("call-chain problem with event, skipping it.\n");
1141 return 0; 108 return 0;
1142 } 109 }
1143 110
1144 if (dump_trace) { 111 if (dump_trace) {
1145 for (i = 0; i < chain->nr; i++) 112 for (i = 0; i < data.callchain->nr; i++)
1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]); 113 dump_printf("..... %2d: %016Lx\n",
114 i, data.callchain->ips[i]);
1147 } 115 }
1148 } 116 }
1149 117
1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 118 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
1151 119 fprintf(stderr, "problem processing %d event, skipping it.\n",
1152 if (thread == NULL) {
1153 eprintf("problem processing %d event, skipping it.\n",
1154 event->header.type); 120 event->header.type);
1155 return -1; 121 return -1;
1156 } 122 }
1157 123
1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 124 if (al.filtered)
1159 return 0;
1160
1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162
1163 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1164 show = SHOW_KERNEL;
1165 level = 'k';
1166
1167 dso = kernel_dso;
1168
1169 dump_printf(" ...... dso: %s\n", dso->name);
1170
1171 } else if (cpumode == PERF_RECORD_MISC_USER) {
1172
1173 show = SHOW_USER;
1174 level = '.';
1175
1176 } else {
1177 show = SHOW_HV;
1178 level = 'H';
1179
1180 dso = hypervisor_dso;
1181
1182 dump_printf(" ...... dso: [hypervisor]\n");
1183 }
1184
1185 if (show & show_mask) {
1186 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1187
1188 if (dso_list && (!dso || !dso->name ||
1189 !strlist__has_entry(dso_list, dso->name)))
1190 return 0;
1191
1192 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1193 return 0;
1194
1195 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1196 eprintf("problem incrementing symbol count, skipping event\n");
1197 return -1;
1198 }
1199 }
1200 total += period;
1201
1202 return 0;
1203}
1204
1205static int
1206process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1207{
1208 struct thread *thread;
1209 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1210
1211 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1212
1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1214 (void *)(offset + head),
1215 (void *)(long)(event->header.size),
1216 event->mmap.pid,
1217 event->mmap.tid,
1218 (void *)(long)event->mmap.start,
1219 (void *)(long)event->mmap.len,
1220 (void *)(long)event->mmap.pgoff,
1221 event->mmap.filename);
1222
1223 if (thread == NULL || map == NULL) {
1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1225 return 0;
1226 }
1227
1228 thread__insert_map(thread, map);
1229 total_mmap++;
1230
1231 return 0;
1232}
1233
1234static int
1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1236{
1237 struct thread *thread;
1238
1239 thread = threads__findnew(event->comm.pid, &threads, &last_match);
1240
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
1246 if (thread == NULL ||
1247 thread__set_comm_adjust(thread, event->comm.comm)) {
1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1249 return -1;
1250 }
1251 total_comm++;
1252
1253 return 0;
1254}
1255
1256static int
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; 125 return 0;
1281 126
1282 if (!thread || !parent || thread__fork(thread, parent)) { 127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 128 pr_debug("problem incrementing symbol count, skipping event\n");
1284 return -1; 129 return -1;
1285 } 130 }
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 131
132 session->events_stats.total += data.period;
1302 return 0; 133 return 0;
1303} 134}
1304 135
1305static int 136static int process_read_event(event_t *event, struct perf_session *session __used)
1306process_read_event(event_t *event, unsigned long offset, unsigned long head)
1307{ 137{
1308 struct perf_event_attr *attr; 138 struct perf_event_attr *attr;
1309 139
1310 attr = perf_header__find_attr(event->read.id, header); 140 attr = perf_header__find_attr(event->read.id, &session->header);
1311 141
1312 if (show_threads) { 142 if (show_threads) {
1313 const char *name = attr ? __event_name(attr->type, attr->config) 143 const char *name = attr ? __event_name(attr->type, attr->config)
@@ -1319,238 +149,96 @@ process_read_event(event_t *event, unsigned long offset, unsigned long head)
1319 event->read.value); 149 event->read.value);
1320 } 150 }
1321 151
1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n", 152 dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
1323 (void *)(offset + head), 153 attr ? __event_name(attr->type, attr->config) : "FAIL",
1324 (void *)(long)(event->header.size), 154 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 155
1331 return 0; 156 return 0;
1332} 157}
1333 158
1334static int 159static int sample_type_check(struct perf_session *session)
1335process_event(event_t *event, unsigned long offset, unsigned long head)
1336{ 160{
1337 trace_event(event); 161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
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
1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 if (sort__has_parent) { 162 if (sort__has_parent) {
1423 fprintf(stderr, "selected --sort parent, but no" 163 fprintf(stderr, "selected --sort parent, but no"
1424 " callchain data. Did you call" 164 " callchain data. Did you call"
1425 " perf record without -g?\n"); 165 " perf record without -g?\n");
1426 exit(-1); 166 return -1;
1427 } 167 }
1428 if (callchain) { 168 if (symbol_conf.use_callchain) {
1429 fprintf(stderr, "selected -g but no callchain data." 169 fprintf(stderr, "selected -g but no callchain data."
1430 " Did you call perf record without" 170 " Did you call perf record without"
1431 " -g?\n"); 171 " -g?\n");
1432 exit(-1); 172 return -1;
1433 } 173 }
1434 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) {
1435 callchain = 1; 175 symbol_conf.use_callchain = true;
1436 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
1437 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
1438 " params\n"); 178 " params\n");
1439 exit(-1); 179 return -1;
1440 } 180 }
1441 } 181 }
1442 182
1443 if (load_kernel() < 0) { 183 return 0;
1444 perror("failed to load kernel symbols"); 184}
1445 return EXIT_FAILURE;
1446 }
1447
1448 if (!full_paths) {
1449 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1450 perror("failed to get the current directory");
1451 return EXIT_FAILURE;
1452 }
1453 cwdlen = strlen(cwd);
1454 } else {
1455 cwd = NULL;
1456 cwdlen = 0;
1457 }
1458
1459 shift = page_size * (head / page_size);
1460 offset += shift;
1461 head -= shift;
1462
1463remap:
1464 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1465 MAP_SHARED, input, offset);
1466 if (buf == MAP_FAILED) {
1467 perror("failed to mmap file");
1468 exit(-1);
1469 }
1470
1471more:
1472 event = (event_t *)(buf + head);
1473
1474 size = event->header.size;
1475 if (!size)
1476 size = 8;
1477
1478 if (head + event->header.size >= page_size * mmap_window) {
1479 int munmap_ret;
1480
1481 shift = page_size * (head / page_size);
1482
1483 munmap_ret = munmap(buf, page_size * mmap_window);
1484 assert(munmap_ret == 0);
1485
1486 offset += shift;
1487 head -= shift;
1488 goto remap;
1489 }
1490
1491 size = event->header.size;
1492 185
1493 dump_printf("\n%p [%p]: event: %d\n", 186static struct perf_event_ops event_ops = {
1494 (void *)(offset + head), 187 .process_sample_event = process_sample_event,
1495 (void *)(long)event->header.size, 188 .process_mmap_event = event__process_mmap,
1496 event->header.type); 189 .process_comm_event = event__process_comm,
190 .process_exit_event = event__process_task,
191 .process_fork_event = event__process_task,
192 .process_lost_event = event__process_lost,
193 .process_read_event = process_read_event,
194 .sample_type_check = sample_type_check,
195};
1497 196
1498 if (!size || process_event(event, offset, head) < 0) {
1499 197
1500 dump_printf("%p [%p]: skipping unknown header type: %d\n", 198static int __cmd_report(void)
1501 (void *)(offset + head), 199{
1502 (void *)(long)(event->header.size), 200 int ret;
1503 event->header.type); 201 struct perf_session *session;
1504 202
1505 total_unknown++; 203 session = perf_session__new(input_name, O_RDONLY, force);
204 if (session == NULL)
205 return -ENOMEM;
1506 206
1507 /* 207 if (show_threads)
1508 * assume we lost track of the stream, check alignment, and 208 perf_read_values_init(&show_threads_values);
1509 * increment a single u64 in the hope to catch on again 'soon'.
1510 */
1511 209
1512 if (unlikely(head & 7)) 210 ret = perf_session__process_events(session, &event_ops);
1513 head &= ~7ULL; 211 if (ret)
212 goto out_delete;
1514 213
1515 size = 8; 214 if (dump_trace) {
215 event__print_totals();
216 goto out_delete;
1516 } 217 }
1517 218
1518 head += size; 219 if (verbose > 3)
1519 220 perf_session__fprintf(session, 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 221
1537 if (dump_trace) 222 if (verbose > 2)
1538 return 0;
1539
1540 if (verbose >= 3)
1541 threads__fprintf(stdout, &threads);
1542
1543 if (verbose >= 2)
1544 dsos__fprintf(stdout); 223 dsos__fprintf(stdout);
1545 224
1546 collapse__resort(); 225 perf_session__collapse_resort(session);
1547 output__resort(total); 226 perf_session__output_resort(session, session->events_stats.total);
1548 output__fprintf(stdout, total); 227 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total);
228 perf_session__fprintf_hists(session, NULL, false, stdout);
229 if (sort_order == default_sort_order &&
230 parent_pattern == default_parent_pattern)
231 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
1549 232
1550 if (show_threads) 233 if (show_threads) {
234 bool raw_printing_style = !strcmp(pretty_printing_style, "raw");
235 perf_read_values_display(stdout, &show_threads_values,
236 raw_printing_style);
1551 perf_read_values_destroy(&show_threads_values); 237 perf_read_values_destroy(&show_threads_values);
1552 238 }
1553 return rc; 239out_delete:
240 perf_session__delete(session);
241 return ret;
1554} 242}
1555 243
1556static int 244static int
@@ -1560,7 +248,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1560 char *tok; 248 char *tok;
1561 char *endptr; 249 char *endptr;
1562 250
1563 callchain = 1; 251 symbol_conf.use_callchain = true;
1564 252
1565 if (!arg) 253 if (!arg)
1566 return 0; 254 return 0;
@@ -1581,7 +269,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1581 269
1582 else if (!strncmp(tok, "none", strlen(arg))) { 270 else if (!strncmp(tok, "none", strlen(arg))) {
1583 callchain_param.mode = CHAIN_NONE; 271 callchain_param.mode = CHAIN_NONE;
1584 callchain = 0; 272 symbol_conf.use_callchain = true;
1585 273
1586 return 0; 274 return 0;
1587 } 275 }
@@ -1606,7 +294,8 @@ setup:
1606 return 0; 294 return 0;
1607} 295}
1608 296
1609static const char * const report_usage[] = { 297//static const char * const report_usage[] = {
298const char * const report_usage[] = {
1610 "perf report [<options>] <command>", 299 "perf report [<options>] <command>",
1611 NULL 300 NULL
1612}; 301};
@@ -1618,11 +307,12 @@ static const struct option options[] = {
1618 "be more verbose (show symbol address, etc)"), 307 "be more verbose (show symbol address, etc)"),
1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 308 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1620 "dump raw trace in ASCII"), 309 "dump raw trace in ASCII"),
1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 310 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
311 "file", "vmlinux pathname"),
1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 312 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 OPT_BOOLEAN('m', "modules", &modules, 313 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1624 "load module symbols - WARNING: use only with -k and LIVE kernel"), 314 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 315 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1626 "Show a column with the number of samples"), 316 "Show a column with the number of samples"),
1627 OPT_BOOLEAN('T', "threads", &show_threads, 317 OPT_BOOLEAN('T', "threads", &show_threads,
1628 "Show per-thread event counters"), 318 "Show per-thread event counters"),
@@ -1630,79 +320,46 @@ static const struct option options[] = {
1630 "pretty printing style key: normal raw"), 320 "pretty printing style key: normal raw"),
1631 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 321 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1632 "sort by key(s): pid, comm, dso, symbol, parent"), 322 "sort by key(s): pid, comm, dso, symbol, parent"),
1633 OPT_BOOLEAN('P', "full-paths", &full_paths, 323 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
1634 "Don't shorten the pathnames taking into account the cwd"), 324 "Don't shorten the pathnames taking into account the cwd"),
1635 OPT_STRING('p', "parent", &parent_pattern, "regex", 325 OPT_STRING('p', "parent", &parent_pattern, "regex",
1636 "regex filter to identify parent, see: '--sort parent'"), 326 "regex filter to identify parent, see: '--sort parent'"),
1637 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 327 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
1638 "Only display entries with parent-match"), 328 "Only display entries with parent-match"),
1639 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 329 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1640 "Display callchains using output_type and min percent threshold. " 330 "Display callchains using output_type and min percent threshold. "
1641 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 331 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1642 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 332 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1643 "only consider symbols in these dsos"), 333 "only consider symbols in these dsos"),
1644 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 334 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1645 "only consider symbols in these comms"), 335 "only consider symbols in these comms"),
1646 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 336 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1647 "only consider these symbols"), 337 "only consider these symbols"),
1648 OPT_STRING('w', "column-widths", &col_width_list_str, 338 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
1649 "width[,width...]", 339 "width[,width...]",
1650 "don't try to adjust column width, use these fixed values"), 340 "don't try to adjust column width, use these fixed values"),
1651 OPT_STRING('t', "field-separator", &field_sep, "separator", 341 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
1652 "separator for columns, no spaces will be added between " 342 "separator for columns, no spaces will be added between "
1653 "columns '.' is reserved."), 343 "columns '.' is reserved."),
1654 OPT_END() 344 OPT_END()
1655}; 345};
1656 346
1657static void setup_sorting(void)
1658{
1659 char *tmp, *tok, *str = strdup(sort_order);
1660
1661 for (tok = strtok_r(str, ", ", &tmp);
1662 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1663 if (sort_dimension__add(tok) < 0) {
1664 error("Unknown --sort key: `%s'", tok);
1665 usage_with_options(report_usage, options);
1666 }
1667 }
1668
1669 free(str);
1670}
1671
1672static void setup_list(struct strlist **list, const char *list_str,
1673 struct sort_entry *se, const char *list_name,
1674 FILE *fp)
1675{
1676 if (list_str) {
1677 *list = strlist__new(true, list_str);
1678 if (!*list) {
1679 fprintf(stderr, "problems parsing %s list\n",
1680 list_name);
1681 exit(129);
1682 }
1683 if (strlist__nr_entries(*list) == 1) {
1684 fprintf(fp, "# %s: %s\n", list_name,
1685 strlist__entry(*list, 0)->s);
1686 se->elide = true;
1687 }
1688 }
1689}
1690
1691int cmd_report(int argc, const char **argv, const char *prefix __used) 347int cmd_report(int argc, const char **argv, const char *prefix __used)
1692{ 348{
1693 symbol__init(); 349 argc = parse_options(argc, argv, options, report_usage, 0);
1694 350
1695 page_size = getpagesize(); 351 setup_pager();
1696 352
1697 argc = parse_options(argc, argv, options, report_usage, 0); 353 if (symbol__init() < 0)
354 return -1;
1698 355
1699 setup_sorting(); 356 setup_sorting(report_usage, options);
1700 357
1701 if (parent_pattern != default_parent_pattern) { 358 if (parent_pattern != default_parent_pattern) {
1702 sort_dimension__add("parent"); 359 sort_dimension__add("parent");
1703 sort_parent.elide = 1; 360 sort_parent.elide = 1;
1704 } else 361 } else
1705 exclude_other = 0; 362 symbol_conf.exclude_other = false;
1706 363
1707 /* 364 /*
1708 * Any (unrecognized) arguments left? 365 * Any (unrecognized) arguments left?
@@ -1710,17 +367,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
1710 if (argc) 367 if (argc)
1711 usage_with_options(report_usage, options); 368 usage_with_options(report_usage, options);
1712 369
1713 setup_pager(); 370 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1714 371 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1715 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 372 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1716 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1717 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
1718
1719 if (field_sep && *field_sep == '.') {
1720 fputs("'.' is the only non valid --field-separator argument\n",
1721 stderr);
1722 exit(129);
1723 }
1724 373
1725 return __cmd_report(); 374 return __cmd_report();
1726} 375}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ce2d5be4f30e..80209df6cfe8 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -6,13 +6,13 @@
6#include "util/symbol.h" 6#include "util/symbol.h"
7#include "util/thread.h" 7#include "util/thread.h"
8#include "util/header.h" 8#include "util/header.h"
9#include "util/session.h"
9 10
10#include "util/parse-options.h" 11#include "util/parse-options.h"
11#include "util/trace-event.h" 12#include "util/trace-event.h"
12 13
13#include "util/debug.h" 14#include "util/debug.h"
14 15
15#include <sys/types.h>
16#include <sys/prctl.h> 16#include <sys/prctl.h>
17 17
18#include <semaphore.h> 18#include <semaphore.h>
@@ -20,26 +20,15 @@
20#include <math.h> 20#include <math.h>
21 21
22static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31
32static struct perf_header *header;
33static u64 sample_type;
34 23
35static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
37 26
27static int profile_cpu = -1;
28
38#define PR_SET_NAME 15 /* Set process name */ 29#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096 30#define MAX_CPUS 4096
40 31
41#define BUG_ON(x) assert(!(x))
42
43static u64 run_measurement_overhead; 32static u64 run_measurement_overhead;
44static u64 sleep_measurement_overhead; 33static u64 sleep_measurement_overhead;
45 34
@@ -74,6 +63,7 @@ enum sched_event_type {
74 SCHED_EVENT_RUN, 63 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP, 64 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP, 65 SCHED_EVENT_WAKEUP,
66 SCHED_EVENT_MIGRATION,
77}; 67};
78 68
79struct sched_atom { 69struct sched_atom {
@@ -147,6 +137,7 @@ struct work_atoms {
147 struct thread *thread; 137 struct thread *thread;
148 struct rb_node node; 138 struct rb_node node;
149 u64 max_lat; 139 u64 max_lat;
140 u64 max_lat_at;
150 u64 total_lat; 141 u64 total_lat;
151 u64 nb_atoms; 142 u64 nb_atoms;
152 u64 total_runtime; 143 u64 total_runtime;
@@ -226,7 +217,7 @@ static void calibrate_sleep_measurement_overhead(void)
226static struct sched_atom * 217static struct sched_atom *
227get_new_event(struct task_desc *task, u64 timestamp) 218get_new_event(struct task_desc *task, u64 timestamp)
228{ 219{
229 struct sched_atom *event = calloc(1, sizeof(*event)); 220 struct sched_atom *event = zalloc(sizeof(*event));
230 unsigned long idx = task->nr_events; 221 unsigned long idx = task->nr_events;
231 size_t size; 222 size_t size;
232 223
@@ -294,7 +285,7 @@ add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
294 return; 285 return;
295 } 286 }
296 287
297 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem)); 288 wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
298 sem_init(wakee_event->wait_sem, 0, 0); 289 sem_init(wakee_event->wait_sem, 0, 0);
299 wakee_event->specific_wait = 1; 290 wakee_event->specific_wait = 1;
300 event->wait_sem = wakee_event->wait_sem; 291 event->wait_sem = wakee_event->wait_sem;
@@ -324,7 +315,7 @@ static struct task_desc *register_pid(unsigned long pid, const char *comm)
324 if (task) 315 if (task)
325 return task; 316 return task;
326 317
327 task = calloc(1, sizeof(*task)); 318 task = zalloc(sizeof(*task));
328 task->pid = pid; 319 task->pid = pid;
329 task->nr = nr_tasks; 320 task->nr = nr_tasks;
330 strcpy(task->comm, comm); 321 strcpy(task->comm, comm);
@@ -398,6 +389,8 @@ process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
398 ret = sem_post(atom->wait_sem); 389 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret); 390 BUG_ON(ret);
400 break; 391 break;
392 case SCHED_EVENT_MIGRATION:
393 break;
401 default: 394 default:
402 BUG_ON(1); 395 BUG_ON(1);
403 } 396 }
@@ -418,34 +411,33 @@ static u64 get_cpu_usage_nsec_parent(void)
418 return sum; 411 return sum;
419} 412}
420 413
421static u64 get_cpu_usage_nsec_self(void) 414static int self_open_counters(void)
422{ 415{
423 char filename [] = "/proc/1234567890/sched"; 416 struct perf_event_attr attr;
424 unsigned long msecs, nsecs; 417 int fd;
425 char *line = NULL;
426 u64 total = 0;
427 size_t len = 0;
428 ssize_t chars;
429 FILE *file;
430 int ret;
431 418
432 sprintf(filename, "/proc/%d/sched", getpid()); 419 memset(&attr, 0, sizeof(attr));
433 file = fopen(filename, "r");
434 BUG_ON(!file);
435 420
436 while ((chars = getline(&line, &len, file)) != -1) { 421 attr.type = PERF_TYPE_SOFTWARE;
437 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n", 422 attr.config = PERF_COUNT_SW_TASK_CLOCK;
438 &msecs, &nsecs); 423
439 if (ret == 2) { 424 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
440 total = msecs*1e6 + nsecs;
441 break;
442 }
443 }
444 if (line)
445 free(line);
446 fclose(file);
447 425
448 return total; 426 if (fd < 0)
427 die("Error: sys_perf_event_open() syscall returned"
428 "with %d (%s)\n", fd, strerror(errno));
429 return fd;
430}
431
432static u64 get_cpu_usage_nsec_self(int fd)
433{
434 u64 runtime;
435 int ret;
436
437 ret = read(fd, &runtime, sizeof(runtime));
438 BUG_ON(ret != sizeof(runtime));
439
440 return runtime;
449} 441}
450 442
451static void *thread_func(void *ctx) 443static void *thread_func(void *ctx)
@@ -454,9 +446,11 @@ static void *thread_func(void *ctx)
454 u64 cpu_usage_0, cpu_usage_1; 446 u64 cpu_usage_0, cpu_usage_1;
455 unsigned long i, ret; 447 unsigned long i, ret;
456 char comm2[22]; 448 char comm2[22];
449 int fd;
457 450
458 sprintf(comm2, ":%s", this_task->comm); 451 sprintf(comm2, ":%s", this_task->comm);
459 prctl(PR_SET_NAME, comm2); 452 prctl(PR_SET_NAME, comm2);
453 fd = self_open_counters();
460 454
461again: 455again:
462 ret = sem_post(&this_task->ready_for_work); 456 ret = sem_post(&this_task->ready_for_work);
@@ -466,16 +460,15 @@ again:
466 ret = pthread_mutex_unlock(&start_work_mutex); 460 ret = pthread_mutex_unlock(&start_work_mutex);
467 BUG_ON(ret); 461 BUG_ON(ret);
468 462
469 cpu_usage_0 = get_cpu_usage_nsec_self(); 463 cpu_usage_0 = get_cpu_usage_nsec_self(fd);
470 464
471 for (i = 0; i < this_task->nr_events; i++) { 465 for (i = 0; i < this_task->nr_events; i++) {
472 this_task->curr_event = i; 466 this_task->curr_event = i;
473 process_sched_event(this_task, this_task->atoms[i]); 467 process_sched_event(this_task, this_task->atoms[i]);
474 } 468 }
475 469
476 cpu_usage_1 = get_cpu_usage_nsec_self(); 470 cpu_usage_1 = get_cpu_usage_nsec_self(fd);
477 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0; 471 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
478
479 ret = sem_post(&this_task->work_done_sem); 472 ret = sem_post(&this_task->work_done_sem);
480 BUG_ON(ret); 473 BUG_ON(ret);
481 474
@@ -632,34 +625,6 @@ static void test_calibrations(void)
632 printf("the sleep test took %Ld nsecs\n", T1-T0); 625 printf("the sleep test took %Ld nsecs\n", T1-T0);
633} 626}
634 627
635static int
636process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{
638 struct thread *thread;
639
640 thread = threads__findnew(event->comm.pid, &threads, &last_match);
641
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head),
644 (void *)(long)(event->header.size),
645 event->comm.comm, event->comm.pid);
646
647 if (thread == NULL ||
648 thread__set_comm(thread, event->comm.comm)) {
649 dump_printf("problem processing perf_event_comm, skipping event.\n");
650 return -1;
651 }
652 total_comm++;
653
654 return 0;
655}
656
657
658struct raw_event_sample {
659 u32 size;
660 char data[0];
661};
662
663#define FILL_FIELD(ptr, field, event, data) \ 628#define FILL_FIELD(ptr, field, event, data) \
664 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data) 629 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
665 630
@@ -745,20 +710,39 @@ struct trace_fork_event {
745 u32 child_pid; 710 u32 child_pid;
746}; 711};
747 712
713struct trace_migrate_task_event {
714 u32 size;
715
716 u16 common_type;
717 u8 common_flags;
718 u8 common_preempt_count;
719 u32 common_pid;
720 u32 common_tgid;
721
722 char comm[16];
723 u32 pid;
724
725 u32 prio;
726 u32 cpu;
727};
728
748struct trace_sched_handler { 729struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
750 struct event *, 732 struct event *,
751 int cpu, 733 int cpu,
752 u64 timestamp, 734 u64 timestamp,
753 struct thread *thread); 735 struct thread *thread);
754 736
755 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
756 struct event *, 739 struct event *,
757 int cpu, 740 int cpu,
758 u64 timestamp, 741 u64 timestamp,
759 struct thread *thread); 742 struct thread *thread);
760 743
761 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
762 struct event *, 746 struct event *,
763 int cpu, 747 int cpu,
764 u64 timestamp, 748 u64 timestamp,
@@ -769,11 +753,19 @@ struct trace_sched_handler {
769 int cpu, 753 int cpu,
770 u64 timestamp, 754 u64 timestamp,
771 struct thread *thread); 755 struct thread *thread);
756
757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
759 struct event *,
760 int cpu,
761 u64 timestamp,
762 struct thread *thread);
772}; 763};
773 764
774 765
775static void 766static void
776replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
777 struct event *event, 769 struct event *event,
778 int cpu __used, 770 int cpu __used,
779 u64 timestamp __used, 771 u64 timestamp __used,
@@ -800,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
800 792
801static void 793static void
802replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
803 struct event *event, 796 struct event *event,
804 int cpu, 797 int cpu,
805 u64 timestamp, 798 u64 timestamp,
@@ -941,9 +934,7 @@ __thread_latency_insert(struct rb_root *root, struct work_atoms *data,
941 934
942static void thread_atoms_insert(struct thread *thread) 935static void thread_atoms_insert(struct thread *thread)
943{ 936{
944 struct work_atoms *atoms; 937 struct work_atoms *atoms = zalloc(sizeof(*atoms));
945
946 atoms = calloc(sizeof(*atoms), 1);
947 if (!atoms) 938 if (!atoms)
948 die("No memory"); 939 die("No memory");
949 940
@@ -975,9 +966,7 @@ add_sched_out_event(struct work_atoms *atoms,
975 char run_state, 966 char run_state,
976 u64 timestamp) 967 u64 timestamp)
977{ 968{
978 struct work_atom *atom; 969 struct work_atom *atom = zalloc(sizeof(*atom));
979
980 atom = calloc(sizeof(*atom), 1);
981 if (!atom) 970 if (!atom)
982 die("Non memory"); 971 die("Non memory");
983 972
@@ -1028,13 +1017,16 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1028 1017
1029 delta = atom->sched_in_time - atom->wake_up_time; 1018 delta = atom->sched_in_time - atom->wake_up_time;
1030 atoms->total_lat += delta; 1019 atoms->total_lat += delta;
1031 if (delta > atoms->max_lat) 1020 if (delta > atoms->max_lat) {
1032 atoms->max_lat = delta; 1021 atoms->max_lat = delta;
1022 atoms->max_lat_at = timestamp;
1023 }
1033 atoms->nb_atoms++; 1024 atoms->nb_atoms++;
1034} 1025}
1035 1026
1036static void 1027static void
1037latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1038 struct event *event __used, 1030 struct event *event __used,
1039 int cpu, 1031 int cpu,
1040 u64 timestamp, 1032 u64 timestamp,
@@ -1058,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1058 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1059 1051
1060 1052
1061 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1062 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1063 1055
1064 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1065 if (!out_events) { 1057 if (!out_events) {
@@ -1087,18 +1079,16 @@ latency_switch_event(struct trace_switch_event *switch_event,
1087 1079
1088static void 1080static void
1089latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1090 struct event *event __used, 1083 struct event *event __used,
1091 int cpu, 1084 int cpu,
1092 u64 timestamp, 1085 u64 timestamp,
1093 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1094{ 1087{
1095 struct work_atoms *atoms; 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1096 struct thread *thread; 1089 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1097 1090
1098 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1099
1100 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1101 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1102 if (!atoms) { 1092 if (!atoms) {
1103 thread_atoms_insert(thread); 1093 thread_atoms_insert(thread);
1104 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1094 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
@@ -1112,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1112 1102
1113static void 1103static void
1114latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1115 struct event *__event __used, 1106 struct event *__event __used,
1116 int cpu __used, 1107 int cpu __used,
1117 u64 timestamp, 1108 u64 timestamp,
@@ -1125,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1125 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1126 return; 1117 return;
1127 1118
1128 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1129 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1130 if (!atoms) { 1121 if (!atoms) {
1131 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1139,7 +1130,12 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1139 1130
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1131 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141 1132
1142 if (atom->state != THREAD_SLEEPING) 1133 /*
1134 * You WILL be missing events if you've recorded only
1135 * one CPU, or are only looking at only one, so don't
1136 * make useless noise.
1137 */
1138 if (profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++; 1139 nr_state_machine_bugs++;
1144 1140
1145 nr_timestamps++; 1141 nr_timestamps++;
@@ -1152,11 +1148,52 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1152 atom->wake_up_time = timestamp; 1148 atom->wake_up_time = timestamp;
1153} 1149}
1154 1150
1151static void
1152latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1153 struct perf_session *session,
1154 struct event *__event __used,
1155 int cpu __used,
1156 u64 timestamp,
1157 struct thread *thread __used)
1158{
1159 struct work_atoms *atoms;
1160 struct work_atom *atom;
1161 struct thread *migrant;
1162
1163 /*
1164 * Only need to worry about migration when profiling one CPU.
1165 */
1166 if (profile_cpu == -1)
1167 return;
1168
1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1171 if (!atoms) {
1172 thread_atoms_insert(migrant);
1173 register_pid(migrant->pid, migrant->comm);
1174 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1175 if (!atoms)
1176 die("migration-event: Internal tree error");
1177 add_sched_out_event(atoms, 'R', timestamp);
1178 }
1179
1180 BUG_ON(list_empty(&atoms->work_list));
1181
1182 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1183 atom->sched_in_time = atom->sched_out_time = atom->wake_up_time = timestamp;
1184
1185 nr_timestamps++;
1186
1187 if (atom->sched_out_time > timestamp)
1188 nr_unordered_timestamps++;
1189}
1190
1155static struct trace_sched_handler lat_ops = { 1191static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event, 1192 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event, 1193 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event, 1194 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event, 1195 .fork_event = latency_fork_event,
1196 .migrate_task_event = latency_migrate_task_event,
1160}; 1197};
1161 1198
1162static void output_lat_thread(struct work_atoms *work_list) 1199static void output_lat_thread(struct work_atoms *work_list)
@@ -1183,10 +1220,11 @@ static void output_lat_thread(struct work_atoms *work_list)
1183 1220
1184 avg = work_list->total_lat / work_list->nb_atoms; 1221 avg = work_list->total_lat / work_list->nb_atoms;
1185 1222
1186 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n", 1223 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
1187 (double)work_list->total_runtime / 1e6, 1224 (double)work_list->total_runtime / 1e6,
1188 work_list->nb_atoms, (double)avg / 1e6, 1225 work_list->nb_atoms, (double)avg / 1e6,
1189 (double)work_list->max_lat / 1e6); 1226 (double)work_list->max_lat / 1e6,
1227 (double)work_list->max_lat_at / 1e9);
1190} 1228}
1191 1229
1192static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1230static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
@@ -1323,7 +1361,7 @@ static void sort_lat(void)
1323static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1324 1362
1325static void 1363static void
1326process_sched_wakeup_event(struct raw_event_sample *raw, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1327 struct event *event, 1365 struct event *event,
1328 int cpu __used, 1366 int cpu __used,
1329 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1331,16 +1369,17 @@ process_sched_wakeup_event(struct raw_event_sample *raw,
1331{ 1369{
1332 struct trace_wakeup_event wakeup_event; 1370 struct trace_wakeup_event wakeup_event;
1333 1371
1334 FILL_COMMON_FIELDS(wakeup_event, event, raw->data); 1372 FILL_COMMON_FIELDS(wakeup_event, event, data);
1335 1373
1336 FILL_ARRAY(wakeup_event, comm, event, raw->data); 1374 FILL_ARRAY(wakeup_event, comm, event, data);
1337 FILL_FIELD(wakeup_event, pid, event, raw->data); 1375 FILL_FIELD(wakeup_event, pid, event, data);
1338 FILL_FIELD(wakeup_event, prio, event, raw->data); 1376 FILL_FIELD(wakeup_event, prio, event, data);
1339 FILL_FIELD(wakeup_event, success, event, raw->data); 1377 FILL_FIELD(wakeup_event, success, event, data);
1340 FILL_FIELD(wakeup_event, cpu, event, raw->data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1341 1379
1342 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1343 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1344} 1383}
1345 1384
1346/* 1385/*
@@ -1358,6 +1397,7 @@ static char next_shortname2 = '0';
1358 1397
1359static void 1398static void
1360map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1361 struct event *event __used, 1401 struct event *event __used,
1362 int this_cpu, 1402 int this_cpu,
1363 u64 timestamp, 1403 u64 timestamp,
@@ -1385,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1385 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1386 1426
1387 1427
1388 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1389 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1390 1430
1391 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1392 1432
@@ -1436,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1436 1476
1437 1477
1438static void 1478static void
1439process_sched_switch_event(struct raw_event_sample *raw, 1479process_sched_switch_event(void *data, struct perf_session *session,
1440 struct event *event, 1480 struct event *event,
1441 int this_cpu, 1481 int this_cpu,
1442 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1444,15 +1484,15 @@ process_sched_switch_event(struct raw_event_sample *raw,
1444{ 1484{
1445 struct trace_switch_event switch_event; 1485 struct trace_switch_event switch_event;
1446 1486
1447 FILL_COMMON_FIELDS(switch_event, event, raw->data); 1487 FILL_COMMON_FIELDS(switch_event, event, data);
1448 1488
1449 FILL_ARRAY(switch_event, prev_comm, event, raw->data); 1489 FILL_ARRAY(switch_event, prev_comm, event, data);
1450 FILL_FIELD(switch_event, prev_pid, event, raw->data); 1490 FILL_FIELD(switch_event, prev_pid, event, data);
1451 FILL_FIELD(switch_event, prev_prio, event, raw->data); 1491 FILL_FIELD(switch_event, prev_prio, event, data);
1452 FILL_FIELD(switch_event, prev_state, event, raw->data); 1492 FILL_FIELD(switch_event, prev_state, event, data);
1453 FILL_ARRAY(switch_event, next_comm, event, raw->data); 1493 FILL_ARRAY(switch_event, next_comm, event, data);
1454 FILL_FIELD(switch_event, next_pid, event, raw->data); 1494 FILL_FIELD(switch_event, next_pid, event, data);
1455 FILL_FIELD(switch_event, next_prio, event, raw->data); 1495 FILL_FIELD(switch_event, next_prio, event, data);
1456 1496
1457 if (curr_pid[this_cpu] != (u32)-1) { 1497 if (curr_pid[this_cpu] != (u32)-1) {
1458 /* 1498 /*
@@ -1463,13 +1503,14 @@ process_sched_switch_event(struct raw_event_sample *raw,
1463 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1464 } 1504 }
1465 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1466 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread); 1506 trace_handler->switch_event(&switch_event, session, event,
1507 this_cpu, timestamp, thread);
1467 1508
1468 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1469} 1510}
1470 1511
1471static void 1512static void
1472process_sched_runtime_event(struct raw_event_sample *raw, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1473 struct event *event, 1514 struct event *event,
1474 int cpu __used, 1515 int cpu __used,
1475 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1477,17 +1518,17 @@ process_sched_runtime_event(struct raw_event_sample *raw,
1477{ 1518{
1478 struct trace_runtime_event runtime_event; 1519 struct trace_runtime_event runtime_event;
1479 1520
1480 FILL_ARRAY(runtime_event, comm, event, raw->data); 1521 FILL_ARRAY(runtime_event, comm, event, data);
1481 FILL_FIELD(runtime_event, pid, event, raw->data); 1522 FILL_FIELD(runtime_event, pid, event, data);
1482 FILL_FIELD(runtime_event, runtime, event, raw->data); 1523 FILL_FIELD(runtime_event, runtime, event, data);
1483 FILL_FIELD(runtime_event, vruntime, event, raw->data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1484 1525
1485 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1486 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1487} 1528}
1488 1529
1489static void 1530static void
1490process_sched_fork_event(struct raw_event_sample *raw, 1531process_sched_fork_event(void *data,
1491 struct event *event, 1532 struct event *event,
1492 int cpu __used, 1533 int cpu __used,
1493 u64 timestamp __used, 1534 u64 timestamp __used,
@@ -1495,15 +1536,16 @@ process_sched_fork_event(struct raw_event_sample *raw,
1495{ 1536{
1496 struct trace_fork_event fork_event; 1537 struct trace_fork_event fork_event;
1497 1538
1498 FILL_COMMON_FIELDS(fork_event, event, raw->data); 1539 FILL_COMMON_FIELDS(fork_event, event, data);
1499 1540
1500 FILL_ARRAY(fork_event, parent_comm, event, raw->data); 1541 FILL_ARRAY(fork_event, parent_comm, event, data);
1501 FILL_FIELD(fork_event, parent_pid, event, raw->data); 1542 FILL_FIELD(fork_event, parent_pid, event, data);
1502 FILL_ARRAY(fork_event, child_comm, event, raw->data); 1543 FILL_ARRAY(fork_event, child_comm, event, data);
1503 FILL_FIELD(fork_event, child_pid, event, raw->data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1504 1545
1505 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1506 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1507} 1549}
1508 1550
1509static void 1551static void
@@ -1517,233 +1559,129 @@ process_sched_exit_event(struct event *event,
1517} 1559}
1518 1560
1519static void 1561static void
1520process_raw_event(event_t *raw_event __used, void *more_data, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1521 int cpu, u64 timestamp, struct thread *thread) 1563 struct event *event,
1564 int cpu __used,
1565 u64 timestamp __used,
1566 struct thread *thread __used)
1567{
1568 struct trace_migrate_task_event migrate_task_event;
1569
1570 FILL_COMMON_FIELDS(migrate_task_event, event, data);
1571
1572 FILL_ARRAY(migrate_task_event, comm, event, data);
1573 FILL_FIELD(migrate_task_event, pid, event, data);
1574 FILL_FIELD(migrate_task_event, prio, event, data);
1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1576
1577 if (trace_handler->migrate_task_event)
1578 trace_handler->migrate_task_event(&migrate_task_event, session,
1579 event, cpu, timestamp, thread);
1580}
1581
1582static void
1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1522{ 1585{
1523 struct raw_event_sample *raw = more_data;
1524 struct event *event; 1586 struct event *event;
1525 int type; 1587 int type;
1526 1588
1527 type = trace_parse_common_type(raw->data); 1589
1590 type = trace_parse_common_type(data);
1528 event = trace_find_event(type); 1591 event = trace_find_event(type);
1529 1592
1530 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1531 process_sched_switch_event(raw, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1532 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1533 process_sched_runtime_event(raw, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1534 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1535 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1536 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1537 process_sched_wakeup_event(raw, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1538 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1605 if (!strcmp(event->name, "sched_migrate_task"))
1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1542} 1607}
1543 1608
1544static int 1609static int process_sample_event(event_t *event, struct perf_session *session)
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{ 1610{
1547 char level; 1611 struct sample_data data;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread; 1612 struct thread *thread;
1551 u64 ip = event->ip.ip;
1552 u64 timestamp = -1;
1553 u32 cpu = -1;
1554 u64 period = 1;
1555 void *more_data = event->ip.__more_data;
1556 int cpumode;
1557
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559
1560 if (sample_type & PERF_SAMPLE_TIME) {
1561 timestamp = *(u64 *)more_data;
1562 more_data += sizeof(u64);
1563 }
1564 1613
1565 if (sample_type & PERF_SAMPLE_CPU) { 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1566 cpu = *(u32 *)more_data; 1615 return 0;
1567 more_data += sizeof(u32);
1568 more_data += sizeof(u32); /* reserved */
1569 }
1570 1616
1571 if (sample_type & PERF_SAMPLE_PERIOD) { 1617 memset(&data, 0, sizeof(data));
1572 period = *(u64 *)more_data; 1618 data.time = -1;
1573 more_data += sizeof(u64); 1619 data.cpu = -1;
1574 } 1620 data.period = -1;
1575 1621
1576 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 1622 event__parse_sample(event, session->sample_type, &data);
1577 (void *)(offset + head),
1578 (void *)(long)(event->header.size),
1579 event->header.misc,
1580 event->ip.pid, event->ip.tid,
1581 (void *)(long)ip,
1582 (long long)period);
1583 1623
1584 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1625 event->header.misc,
1626 data.pid, data.tid,
1627 (void *)(long)data.ip,
1628 (long long)data.period);
1585 1629
1630 thread = perf_session__findnew(session, data.pid);
1586 if (thread == NULL) { 1631 if (thread == NULL) {
1587 eprintf("problem processing %d event, skipping it.\n", 1632 pr_debug("problem processing %d event, skipping it.\n",
1588 event->header.type); 1633 event->header.type);
1589 return -1; 1634 return -1;
1590 } 1635 }
1591 1636
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1637 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 1638
1613 dump_printf(" ...... dso: [hypervisor]\n"); 1639 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1614 } 1640 return 0;
1615 1641
1616 if (sample_type & PERF_SAMPLE_RAW) 1642 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618 1643
1619 return 0; 1644 return 0;
1620} 1645}
1621 1646
1622static int 1647static int process_lost_event(event_t *event __used,
1623process_event(event_t *event, unsigned long offset, unsigned long head) 1648 struct perf_session *session __used)
1624{ 1649{
1625 trace_event(event); 1650 nr_lost_chunks++;
1626 1651 nr_lost_events += event->lost.lost;
1627 nr_events++;
1628 switch (event->header.type) {
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635 1652
1636 case PERF_RECORD_COMM: 1653 return 0;
1637 return process_comm_event(event, offset, head); 1654}
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641
1642 case PERF_RECORD_SAMPLE:
1643 return process_sample_event(event, offset, head);
1644 1655
1645 case PERF_RECORD_MAX: 1656static int sample_type_check(struct perf_session *session __used)
1646 default: 1657{
1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1659 fprintf(stderr,
1660 "No trace sample to read. Did you call perf record "
1661 "without -R?");
1647 return -1; 1662 return -1;
1648 } 1663 }
1649 1664
1650 return 0; 1665 return 0;
1651} 1666}
1652 1667
1668static struct perf_event_ops event_ops = {
1669 .process_sample_event = process_sample_event,
1670 .process_comm_event = event__process_comm,
1671 .process_lost_event = process_lost_event,
1672 .sample_type_check = sample_type_check,
1673};
1674
1653static int read_events(void) 1675static int read_events(void)
1654{ 1676{
1655 int ret, rc = EXIT_FAILURE; 1677 int err;
1656 unsigned long offset = 0; 1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1657 unsigned long head = 0; 1679 if (session == NULL)
1658 struct stat perf_stat; 1680 return -ENOMEM;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match);
1665
1666 input = open(input_name, O_RDONLY);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721
1722 size = event->header.size;
1723
1724
1725 if (!size || process_event(event, offset, head) < 0) {
1726
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745 1681
1746 return rc; 1682 err = perf_session__process_events(session, &event_ops);
1683 perf_session__delete(session);
1684 return err;
1747} 1685}
1748 1686
1749static void print_bad_events(void) 1687static void print_bad_events(void)
@@ -1784,9 +1722,9 @@ static void __cmd_lat(void)
1784 read_events(); 1722 read_events();
1785 sort_lat(); 1723 sort_lat();
1786 1724
1787 printf("\n -----------------------------------------------------------------------------------------\n"); 1725 printf("\n ---------------------------------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n"); 1726 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n"); 1727 printf(" ---------------------------------------------------------------------------------------------------------------\n");
1790 1728
1791 next = rb_first(&sorted_atom_root); 1729 next = rb_first(&sorted_atom_root);
1792 1730
@@ -1883,6 +1821,8 @@ static const struct option latency_options[] = {
1883 "sort by key(s): runtime, switch, avg, max"), 1821 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose, 1822 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"), 1823 "be more verbose (show symbol address, etc)"),
1824 OPT_INTEGER('C', "CPU", &profile_cpu,
1825 "CPU to profile on"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1826 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"), 1827 "dump raw trace in ASCII"),
1888 OPT_END() 1828 OPT_END()
@@ -1960,14 +1900,18 @@ static int __cmd_record(int argc, const char **argv)
1960 1900
1961int cmd_sched(int argc, const char **argv, const char *prefix __used) 1901int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{ 1902{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage, 1903 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION); 1904 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc) 1905 if (!argc)
1969 usage_with_options(sched_usage, sched_options); 1906 usage_with_options(sched_usage, sched_options);
1970 1907
1908 /*
1909 * Aliased to 'perf trace' for now:
1910 */
1911 if (!strcmp(argv[0], "trace"))
1912 return cmd_trace(argc, argv, prefix);
1913
1914 symbol__init();
1971 if (!strncmp(argv[0], "rec", 3)) { 1915 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv); 1916 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) { 1917 } else if (!strncmp(argv[0], "lat", 3)) {
@@ -1991,11 +1935,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1991 usage_with_options(replay_usage, replay_options); 1935 usage_with_options(replay_usage, replay_options);
1992 } 1936 }
1993 __cmd_replay(); 1937 __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 { 1938 } else {
2000 usage_with_options(sched_usage, sched_options); 1939 usage_with_options(sched_usage, sched_options);
2001 } 1940 }
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..a589a43112d6 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -29,16 +29,13 @@
29#include "util/header.h" 29#include "util/header.h"
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h"
33#include "util/session.h"
32#include "util/svghelper.h" 34#include "util/svghelper.h"
33 35
34static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
35static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
36 38
37
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type;
41
42static unsigned int numcpus; 39static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */ 40static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */ 41static u64 max_freq; /* Highest CPU frequency seen */
@@ -49,8 +46,6 @@ static u64 first_time, last_time;
49static int power_only; 46static int power_only;
50 47
51 48
52static struct perf_header *header;
53
54struct per_pid; 49struct per_pid;
55struct per_pidcomm; 50struct per_pidcomm;
56 51
@@ -153,6 +148,17 @@ static struct wake_event *wake_events;
153 148
154struct sample_wrapper *all_samples; 149struct sample_wrapper *all_samples;
155 150
151
152struct process_filter;
153struct process_filter {
154 char *name;
155 int pid;
156 struct process_filter *next;
157};
158
159static struct process_filter *process_filter;
160
161
156static struct per_pid *find_create_pid(int pid) 162static struct per_pid *find_create_pid(int pid)
157{ 163{
158 struct per_pid *cursor = all_data; 164 struct per_pid *cursor = all_data;
@@ -272,33 +278,30 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 278static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 279static u64 cpus_pstate_state[MAX_CPUS];
274 280
275static int 281static int process_comm_event(event_t *event, struct perf_session *session __used)
276process_comm_event(event_t *event)
277{ 282{
278 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.pid, event->comm.comm);
279 return 0; 284 return 0;
280} 285}
281static int 286
282process_fork_event(event_t *event) 287static int process_fork_event(event_t *event, struct perf_session *session __used)
283{ 288{
284 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
285 return 0; 290 return 0;
286} 291}
287 292
288static int 293static int process_exit_event(event_t *event, struct perf_session *session __used)
289process_exit_event(event_t *event)
290{ 294{
291 pid_exit(event->fork.pid, event->fork.time); 295 pid_exit(event->fork.pid, event->fork.time);
292 return 0; 296 return 0;
293} 297}
294 298
295struct trace_entry { 299struct trace_entry {
296 u32 size;
297 unsigned short type; 300 unsigned short type;
298 unsigned char flags; 301 unsigned char flags;
299 unsigned char preempt_count; 302 unsigned char preempt_count;
300 int pid; 303 int pid;
301 int tgid; 304 int lock_depth;
302}; 305};
303 306
304struct power_entry { 307struct power_entry {
@@ -472,46 +475,24 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
472} 475}
473 476
474 477
475static int 478static int process_sample_event(event_t *event, struct perf_session *session)
476process_sample_event(event_t *event)
477{ 479{
478 int cursor = 0; 480 struct sample_data data;
479 u64 addr = 0;
480 u64 stamp = 0;
481 u32 cpu = 0;
482 u32 pid = 0;
483 struct trace_entry *te; 481 struct trace_entry *te;
484 482
485 if (sample_type & PERF_SAMPLE_IP) 483 memset(&data, 0, sizeof(data));
486 cursor++;
487
488 if (sample_type & PERF_SAMPLE_TID) {
489 pid = event->sample.array[cursor]>>32;
490 cursor++;
491 }
492 if (sample_type & PERF_SAMPLE_TIME) {
493 stamp = event->sample.array[cursor++];
494 484
495 if (!first_time || first_time > stamp) 485 event__parse_sample(event, session->sample_type, &data);
496 first_time = stamp;
497 if (last_time < stamp)
498 last_time = stamp;
499 486
487 if (session->sample_type & PERF_SAMPLE_TIME) {
488 if (!first_time || first_time > data.time)
489 first_time = data.time;
490 if (last_time < data.time)
491 last_time = data.time;
500 } 492 }
501 if (sample_type & PERF_SAMPLE_ADDR)
502 addr = event->sample.array[cursor++];
503 if (sample_type & PERF_SAMPLE_ID)
504 cursor++;
505 if (sample_type & PERF_SAMPLE_STREAM_ID)
506 cursor++;
507 if (sample_type & PERF_SAMPLE_CPU)
508 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
509 if (sample_type & PERF_SAMPLE_PERIOD)
510 cursor++;
511
512 te = (void *)&event->sample.array[cursor];
513 493
514 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) { 494 te = (void *)data.raw_data;
495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
515 char *event_str; 496 char *event_str;
516 struct power_entry *pe; 497 struct power_entry *pe;
517 498
@@ -523,19 +504,19 @@ process_sample_event(event_t *event)
523 return 0; 504 return 0;
524 505
525 if (strcmp(event_str, "power:power_start") == 0) 506 if (strcmp(event_str, "power:power_start") == 0)
526 c_state_start(cpu, stamp, pe->value); 507 c_state_start(data.cpu, data.time, pe->value);
527 508
528 if (strcmp(event_str, "power:power_end") == 0) 509 if (strcmp(event_str, "power:power_end") == 0)
529 c_state_end(cpu, stamp); 510 c_state_end(data.cpu, data.time);
530 511
531 if (strcmp(event_str, "power:power_frequency") == 0) 512 if (strcmp(event_str, "power:power_frequency") == 0)
532 p_state_change(cpu, stamp, pe->value); 513 p_state_change(data.cpu, data.time, pe->value);
533 514
534 if (strcmp(event_str, "sched:sched_wakeup") == 0) 515 if (strcmp(event_str, "sched:sched_wakeup") == 0)
535 sched_wakeup(cpu, stamp, pid, te); 516 sched_wakeup(data.cpu, data.time, data.pid, te);
536 517
537 if (strcmp(event_str, "sched:sched_switch") == 0) 518 if (strcmp(event_str, "sched:sched_switch") == 0)
538 sched_switch(cpu, stamp, te); 519 sched_switch(data.cpu, data.time, te);
539 } 520 }
540 return 0; 521 return 0;
541} 522}
@@ -588,16 +569,16 @@ static void end_sample_processing(void)
588 } 569 }
589} 570}
590 571
591static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
592{ 573{
593 int cursor; 574 int cursor;
594 575
595 cursor = 0; 576 cursor = 0;
596 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
597 cursor++; 578 cursor++;
598 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
599 cursor++; 580 cursor++;
600 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
601 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
602 return 0; 583 return 0;
603} 584}
@@ -607,8 +588,7 @@ static u64 sample_time(event_t *event)
607 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
608 * The order will get flipped later. 589 * The order will get flipped later.
609 */ 590 */
610static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
611queue_sample_event(event_t *event)
612{ 592{
613 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
614 int size; 594 int size;
@@ -622,7 +602,7 @@ queue_sample_event(event_t *event)
622 memset(copy, 0, size); 602 memset(copy, 0, size);
623 603
624 copy->next = NULL; 604 copy->next = NULL;
625 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
626 606
627 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
628 608
@@ -763,11 +743,11 @@ static void draw_wakeups(void)
763 c = p->all; 743 c = p->all;
764 while (c) { 744 while (c) {
765 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) { 745 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
766 if (p->pid == we->waker) { 746 if (p->pid == we->waker && !from) {
767 from = c->Y; 747 from = c->Y;
768 task_from = strdup(c->comm); 748 task_from = strdup(c->comm);
769 } 749 }
770 if (p->pid == we->wakee) { 750 if (p->pid == we->wakee && !to) {
771 to = c->Y; 751 to = c->Y;
772 task_to = strdup(c->comm); 752 task_to = strdup(c->comm);
773 } 753 }
@@ -882,12 +862,89 @@ static void draw_process_bars(void)
882 } 862 }
883} 863}
884 864
865static void add_process_filter(const char *string)
866{
867 struct process_filter *filt;
868 int pid;
869
870 pid = strtoull(string, NULL, 10);
871 filt = malloc(sizeof(struct process_filter));
872 if (!filt)
873 return;
874
875 filt->name = strdup(string);
876 filt->pid = pid;
877 filt->next = process_filter;
878
879 process_filter = filt;
880}
881
882static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
883{
884 struct process_filter *filt;
885 if (!process_filter)
886 return 1;
887
888 filt = process_filter;
889 while (filt) {
890 if (filt->pid && p->pid == filt->pid)
891 return 1;
892 if (strcmp(filt->name, c->comm) == 0)
893 return 1;
894 filt = filt->next;
895 }
896 return 0;
897}
898
899static int determine_display_tasks_filtered(void)
900{
901 struct per_pid *p;
902 struct per_pidcomm *c;
903 int count = 0;
904
905 p = all_data;
906 while (p) {
907 p->display = 0;
908 if (p->start_time == 1)
909 p->start_time = first_time;
910
911 /* no exit marker, task kept running to the end */
912 if (p->end_time == 0)
913 p->end_time = last_time;
914
915 c = p->all;
916
917 while (c) {
918 c->display = 0;
919
920 if (c->start_time == 1)
921 c->start_time = first_time;
922
923 if (passes_filter(p, c)) {
924 c->display = 1;
925 p->display = 1;
926 count++;
927 }
928
929 if (c->end_time == 0)
930 c->end_time = last_time;
931
932 c = c->next;
933 }
934 p = p->next;
935 }
936 return count;
937}
938
885static int determine_display_tasks(u64 threshold) 939static int determine_display_tasks(u64 threshold)
886{ 940{
887 struct per_pid *p; 941 struct per_pid *p;
888 struct per_pidcomm *c; 942 struct per_pidcomm *c;
889 int count = 0; 943 int count = 0;
890 944
945 if (process_filter)
946 return determine_display_tasks_filtered();
947
891 p = all_data; 948 p = all_data;
892 while (p) { 949 while (p) {
893 p->display = 0; 950 p->display = 0;
@@ -957,37 +1014,7 @@ static void write_svg_file(const char *filename)
957 svg_close(); 1014 svg_close();
958} 1015}
959 1016
960static int 1017static void process_samples(struct perf_session *session)
961process_event(event_t *event)
962{
963
964 switch (event->header.type) {
965
966 case PERF_RECORD_COMM:
967 return process_comm_event(event);
968 case PERF_RECORD_FORK:
969 return process_fork_event(event);
970 case PERF_RECORD_EXIT:
971 return process_exit_event(event);
972 case PERF_RECORD_SAMPLE:
973 return queue_sample_event(event);
974
975 /*
976 * We dont process them right now but they are fine:
977 */
978 case PERF_RECORD_MMAP:
979 case PERF_RECORD_THROTTLE:
980 case PERF_RECORD_UNTHROTTLE:
981 return 0;
982
983 default:
984 return -1;
985 }
986
987 return 0;
988}
989
990static void process_samples(void)
991{ 1018{
992 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
993 event_t *event; 1020 event_t *event;
@@ -998,113 +1025,42 @@ static void process_samples(void)
998 while (cursor) { 1025 while (cursor) {
999 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1000 cursor = cursor->next; 1027 cursor = cursor->next;
1001 process_sample_event(event); 1028 process_sample_event(event, session);
1002 } 1029 }
1003} 1030}
1004 1031
1005 1032static int sample_type_check(struct perf_session *session)
1006static int __cmd_timechart(void)
1007{ 1033{
1008 int ret, rc = EXIT_FAILURE; 1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1009 unsigned long offset = 0; 1035 fprintf(stderr, "No trace samples found in the file.\n"
1010 unsigned long head, shift; 1036 "Have you used 'perf timechart record' to record it?\n");
1011 struct stat statbuf; 1037 return -1;
1012 event_t *event;
1013 uint32_t size;
1014 char *buf;
1015 int input;
1016
1017 input = open(input_name, O_RDONLY);
1018 if (input < 0) {
1019 fprintf(stderr, " failed to open file: %s", input_name);
1020 if (!strcmp(input_name, "perf.data"))
1021 fprintf(stderr, " (try 'perf record' first)");
1022 fprintf(stderr, "\n");
1023 exit(-1);
1024 }
1025
1026 ret = fstat(input, &statbuf);
1027 if (ret < 0) {
1028 perror("failed to stat file");
1029 exit(-1);
1030 }
1031
1032 if (!statbuf.st_size) {
1033 fprintf(stderr, "zero-sized file, nothing to do!\n");
1034 exit(0);
1035 }
1036
1037 header = perf_header__read(input);
1038 head = header->data_offset;
1039
1040 sample_type = perf_header__sample_type(header);
1041
1042 shift = page_size * (head / page_size);
1043 offset += shift;
1044 head -= shift;
1045
1046remap:
1047 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1048 MAP_SHARED, input, offset);
1049 if (buf == MAP_FAILED) {
1050 perror("failed to mmap file");
1051 exit(-1);
1052 }
1053
1054more:
1055 event = (event_t *)(buf + head);
1056
1057 size = event->header.size;
1058 if (!size)
1059 size = 8;
1060
1061 if (head + event->header.size >= page_size * mmap_window) {
1062 int ret2;
1063
1064 shift = page_size * (head / page_size);
1065
1066 ret2 = munmap(buf, page_size * mmap_window);
1067 assert(ret2 == 0);
1068
1069 offset += shift;
1070 head -= shift;
1071 goto remap;
1072 }
1073
1074 size = event->header.size;
1075
1076 if (!size || process_event(event) < 0) {
1077
1078 printf("%p [%p]: skipping unknown header type: %d\n",
1079 (void *)(offset + head),
1080 (void *)(long)(event->header.size),
1081 event->header.type);
1082
1083 /*
1084 * assume we lost track of the stream, check alignment, and
1085 * increment a single u64 in the hope to catch on again 'soon'.
1086 */
1087
1088 if (unlikely(head & 7))
1089 head &= ~7ULL;
1090
1091 size = 8;
1092 } 1038 }
1093 1039
1094 head += size; 1040 return 0;
1041}
1095 1042
1096 if (offset + head >= header->data_offset + header->data_size) 1043static struct perf_event_ops event_ops = {
1097 goto done; 1044 .process_comm_event = process_comm_event,
1045 .process_fork_event = process_fork_event,
1046 .process_exit_event = process_exit_event,
1047 .process_sample_event = queue_sample_event,
1048 .sample_type_check = sample_type_check,
1049};
1098 1050
1099 if (offset + head < (unsigned long)statbuf.st_size) 1051static int __cmd_timechart(void)
1100 goto more; 1052{
1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1054 int ret;
1101 1055
1102done: 1056 if (session == NULL)
1103 rc = EXIT_SUCCESS; 1057 return -ENOMEM;
1104 close(input);
1105 1058
1059 ret = perf_session__process_events(session, &event_ops);
1060 if (ret)
1061 goto out_delete;
1106 1062
1107 process_samples(); 1063 process_samples(session);
1108 1064
1109 end_sample_processing(); 1065 end_sample_processing();
1110 1066
@@ -1112,9 +1068,11 @@ done:
1112 1068
1113 write_svg_file(output_name); 1069 write_svg_file(output_name);
1114 1070
1115 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name); 1071 pr_info("Written %2.1f seconds of trace to %s.\n",
1116 1072 (last_time - first_time) / 1000000000.0, output_name);
1117 return rc; 1073out_delete:
1074 perf_session__delete(session);
1075 return ret;
1118} 1076}
1119 1077
1120static const char * const timechart_usage[] = { 1078static const char * const timechart_usage[] = {
@@ -1153,6 +1111,14 @@ static int __cmd_record(int argc, const char **argv)
1153 return cmd_record(i, rec_argv, NULL); 1111 return cmd_record(i, rec_argv, NULL);
1154} 1112}
1155 1113
1114static int
1115parse_process(const struct option *opt __used, const char *arg, int __used unset)
1116{
1117 if (arg)
1118 add_process_filter(arg);
1119 return 0;
1120}
1121
1156static const struct option options[] = { 1122static const struct option options[] = {
1157 OPT_STRING('i', "input", &input_name, "file", 1123 OPT_STRING('i', "input", &input_name, "file",
1158 "input file name"), 1124 "input file name"),
@@ -1160,21 +1126,22 @@ static const struct option options[] = {
1160 "output file name"), 1126 "output file name"),
1161 OPT_INTEGER('w', "width", &svg_page_width, 1127 OPT_INTEGER('w', "width", &svg_page_width,
1162 "page width"), 1128 "page width"),
1163 OPT_BOOLEAN('p', "power-only", &power_only, 1129 OPT_BOOLEAN('P', "power-only", &power_only,
1164 "output power data only"), 1130 "output power data only"),
1131 OPT_CALLBACK('p', "process", NULL, "process",
1132 "process selector. Pass a pid or process name.",
1133 parse_process),
1165 OPT_END() 1134 OPT_END()
1166}; 1135};
1167 1136
1168 1137
1169int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1138int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1170{ 1139{
1171 symbol__init();
1172
1173 page_size = getpagesize();
1174
1175 argc = parse_options(argc, argv, options, timechart_usage, 1140 argc = parse_options(argc, argv, options, timechart_usage,
1176 PARSE_OPT_STOP_AT_NON_OPTION); 1141 PARSE_OPT_STOP_AT_NON_OPTION);
1177 1142
1143 symbol__init();
1144
1178 if (argc && !strncmp(argv[0], "rec", 3)) 1145 if (argc && !strncmp(argv[0], "rec", 3))
1179 return __cmd_record(argc, argv); 1146 return __cmd_record(argc, argv);
1180 else if (argc) 1147 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e23bc74e734f..ddc584b64871 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,8 +20,10 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/symbol.h"
24#include "util/color.h" 23#include "util/color.h"
24#include "util/session.h"
25#include "util/symbol.h"
26#include "util/thread.h"
25#include "util/util.h" 27#include "util/util.h"
26#include <linux/rbtree.h> 28#include <linux/rbtree.h>
27#include "util/parse-options.h" 29#include "util/parse-options.h"
@@ -54,26 +56,30 @@
54 56
55static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 57static int fd[MAX_NR_CPUS][MAX_COUNTERS];
56 58
57static int system_wide = 0; 59static int system_wide = 0;
58 60
59static int default_interval = 100000; 61static int default_interval = 0;
60 62
61static int count_filter = 5; 63static int count_filter = 5;
62static int print_entries = 15; 64static int print_entries;
63 65
64static int target_pid = -1; 66static int target_pid = -1;
65static int inherit = 0; 67static int inherit = 0;
66static int profile_cpu = -1; 68static int profile_cpu = -1;
67static int nr_cpus = 0; 69static int nr_cpus = 0;
68static unsigned int realtime_prio = 0; 70static unsigned int realtime_prio = 0;
69static int group = 0; 71static int group = 0;
70static unsigned int page_size; 72static unsigned int page_size;
71static unsigned int mmap_pages = 16; 73static unsigned int mmap_pages = 16;
72static int freq = 0; 74static int freq = 1000; /* 1 KHz */
73 75
74static int delay_secs = 2; 76static int delay_secs = 2;
75static int zero; 77static int zero = 0;
76static int dump_symtab; 78static int dump_symtab = 0;
79
80static bool hide_kernel_symbols = false;
81static bool hide_user_symbols = false;
82static struct winsize winsize;
77 83
78/* 84/*
79 * Source 85 * Source
@@ -86,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 191
145 start = sym->obj_start; 192 if (source->lines) {
146 if (!start) 193 pthread_mutex_lock(&source->lock);
147 start = sym->start; 194 goto out_assign;
148
149 if (module) {
150 section = module->sections->find_section(module->sections, ".text");
151 if (section)
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,66 @@ 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,
863 * Binary search in the histogram table and record the hit: 930 struct perf_session *session, int counter)
864 */
865static void record_ip(u64 ip, int counter)
866{ 931{
867 struct symbol *sym = dso__find_symbol(kernel_dso, ip); 932 u64 ip = self->ip.ip;
868 933 struct sym_entry *syme;
869 if (sym != NULL) { 934 struct addr_location al;
870 struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
871 936
872 if (!syme->skip) { 937 switch (origin) {
873 syme->count[counter]++; 938 case PERF_RECORD_MISC_USER:
874 record_precise_ip(syme, counter, ip); 939 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; 940 return;
880 } 941 break;
942 case PERF_RECORD_MISC_KERNEL:
943 if (hide_kernel_symbols)
944 return;
945 break;
946 default:
947 return;
881 } 948 }
882 949
883 samples--; 950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
951 al.sym == NULL || al.filtered)
952 return;
953
954 syme = symbol__priv(al.sym);
955 if (!syme->skip) {
956 syme->count[counter]++;
957 syme->origin = origin;
958 record_precise_ip(syme, counter, ip);
959 pthread_mutex_lock(&active_symbols_lock);
960 if (list_empty(&syme->node) || !syme->node.next)
961 __list_insert_active_sym(syme);
962 pthread_mutex_unlock(&active_symbols_lock);
963 if (origin == PERF_RECORD_MISC_USER)
964 ++userspace_samples;
965 ++samples;
966 }
884} 967}
885 968
886static void process_event(u64 ip, int counter, int user) 969static int event__process(event_t *event, struct perf_session *session)
887{ 970{
888 samples++; 971 switch (event->header.type) {
889 972 case PERF_RECORD_COMM:
890 if (user) { 973 event__process_comm(event, session);
891 userspace_samples++; 974 break;
892 return; 975 case PERF_RECORD_MMAP:
976 event__process_mmap(event, session);
977 break;
978 default:
979 break;
893 } 980 }
894 981
895 record_ip(ip, counter); 982 return 0;
896} 983}
897 984
898struct mmap_data { 985struct mmap_data {
@@ -913,17 +1000,14 @@ static unsigned int mmap_read_head(struct mmap_data *md)
913 return head; 1000 return head;
914} 1001}
915 1002
916struct timeval last_read, this_read; 1003static void perf_session__mmap_read_counter(struct perf_session *self,
917 1004 struct mmap_data *md)
918static void mmap_read_counter(struct mmap_data *md)
919{ 1005{
920 unsigned int head = mmap_read_head(md); 1006 unsigned int head = mmap_read_head(md);
921 unsigned int old = md->prev; 1007 unsigned int old = md->prev;
922 unsigned char *data = md->base + page_size; 1008 unsigned char *data = md->base + page_size;
923 int diff; 1009 int diff;
924 1010
925 gettimeofday(&this_read, NULL);
926
927 /* 1011 /*
928 * If we're further behind than half the buffer, there's a chance 1012 * 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. 1013 * the writer will bite our tail and mess up the samples under us.
@@ -934,14 +1018,7 @@ static void mmap_read_counter(struct mmap_data *md)
934 */ 1018 */
935 diff = head - old; 1019 diff = head - old;
936 if (diff > md->mask / 2 || diff < 0) { 1020 if (diff > md->mask / 2 || diff < 0) {
937 struct timeval iv; 1021 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 1022
946 /* 1023 /*
947 * head points to a known good entry, start there. 1024 * head points to a known good entry, start there.
@@ -949,8 +1026,6 @@ static void mmap_read_counter(struct mmap_data *md)
949 old = head; 1026 old = head;
950 } 1027 }
951 1028
952 last_read = this_read;
953
954 for (; old != head;) { 1029 for (; old != head;) {
955 event_t *event = (event_t *)&data[old & md->mask]; 1030 event_t *event = (event_t *)&data[old & md->mask];
956 1031
@@ -978,13 +1053,11 @@ static void mmap_read_counter(struct mmap_data *md)
978 event = &event_copy; 1053 event = &event_copy;
979 } 1054 }
980 1055
1056 if (event->header.type == PERF_RECORD_SAMPLE)
1057 event__process_sample(event, self, md->counter);
1058 else
1059 event__process(event, self);
981 old += size; 1060 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 } 1061 }
989 1062
990 md->prev = old; 1063 md->prev = old;
@@ -993,13 +1066,13 @@ static void mmap_read_counter(struct mmap_data *md)
993static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1066static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
994static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1067static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
995 1068
996static void mmap_read(void) 1069static void perf_session__mmap_read(struct perf_session *self)
997{ 1070{
998 int i, counter; 1071 int i, counter;
999 1072
1000 for (i = 0; i < nr_cpus; i++) { 1073 for (i = 0; i < nr_cpus; i++) {
1001 for (counter = 0; counter < nr_counters; counter++) 1074 for (counter = 0; counter < nr_counters; counter++)
1002 mmap_read_counter(&mmap_array[i][counter]); 1075 perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
1003 } 1076 }
1004} 1077}
1005 1078
@@ -1018,8 +1091,15 @@ static void start_counter(int i, int counter)
1018 attr = attrs + counter; 1091 attr = attrs + counter;
1019 1092
1020 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1093 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1021 attr->freq = freq; 1094
1095 if (freq) {
1096 attr->sample_type |= PERF_SAMPLE_PERIOD;
1097 attr->freq = 1;
1098 attr->sample_freq = freq;
1099 }
1100
1022 attr->inherit = (cpu < 0) && inherit; 1101 attr->inherit = (cpu < 0) && inherit;
1102 attr->mmap = 1;
1023 1103
1024try_again: 1104try_again:
1025 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1105 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
@@ -1077,6 +1157,18 @@ static int __cmd_top(void)
1077 pthread_t thread; 1157 pthread_t thread;
1078 int i, counter; 1158 int i, counter;
1079 int ret; 1159 int ret;
1160 /*
1161 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1162 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1163 */
1164 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
1165 if (session == NULL)
1166 return -ENOMEM;
1167
1168 if (target_pid != -1)
1169 event__synthesize_thread(target_pid, event__process, session);
1170 else
1171 event__synthesize_threads(event__process, session);
1080 1172
1081 for (i = 0; i < nr_cpus; i++) { 1173 for (i = 0; i < nr_cpus; i++) {
1082 group_fd = -1; 1174 group_fd = -1;
@@ -1087,7 +1179,7 @@ static int __cmd_top(void)
1087 /* Wait for a minimal set of events before starting the snapshot */ 1179 /* Wait for a minimal set of events before starting the snapshot */
1088 poll(event_array, nr_poll, 100); 1180 poll(event_array, nr_poll, 100);
1089 1181
1090 mmap_read(); 1182 perf_session__mmap_read(session);
1091 1183
1092 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1184 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1093 printf("Could not create display thread.\n"); 1185 printf("Could not create display thread.\n");
@@ -1107,7 +1199,7 @@ static int __cmd_top(void)
1107 while (1) { 1199 while (1) {
1108 int hits = samples; 1200 int hits = samples;
1109 1201
1110 mmap_read(); 1202 perf_session__mmap_read(session);
1111 1203
1112 if (hits == samples) 1204 if (hits == samples)
1113 ret = poll(event_array, nr_poll, 100); 1205 ret = poll(event_array, nr_poll, 100);
@@ -1133,7 +1225,10 @@ static const struct option options[] = {
1133 "system-wide collection from all CPUs"), 1225 "system-wide collection from all CPUs"),
1134 OPT_INTEGER('C', "CPU", &profile_cpu, 1226 OPT_INTEGER('C', "CPU", &profile_cpu,
1135 "CPU to profile on"), 1227 "CPU to profile on"),
1136 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"), 1228 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1229 "file", "vmlinux pathname"),
1230 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1231 "hide kernel symbols"),
1137 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1232 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1138 "number of mmap data pages"), 1233 "number of mmap data pages"),
1139 OPT_INTEGER('r', "realtime", &realtime_prio, 1234 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -1156,6 +1251,8 @@ static const struct option options[] = {
1156 "profile at this frequency"), 1251 "profile at this frequency"),
1157 OPT_INTEGER('E', "entries", &print_entries, 1252 OPT_INTEGER('E', "entries", &print_entries,
1158 "display this many functions"), 1253 "display this many functions"),
1254 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1255 "hide user symbols"),
1159 OPT_BOOLEAN('v', "verbose", &verbose, 1256 OPT_BOOLEAN('v', "verbose", &verbose,
1160 "be more verbose (show counter open errors, etc)"), 1257 "be more verbose (show counter open errors, etc)"),
1161 OPT_END() 1258 OPT_END()
@@ -1165,19 +1262,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1165{ 1262{
1166 int counter; 1263 int counter;
1167 1264
1168 symbol__init();
1169
1170 page_size = sysconf(_SC_PAGE_SIZE); 1265 page_size = sysconf(_SC_PAGE_SIZE);
1171 1266
1172 argc = parse_options(argc, argv, options, top_usage, 0); 1267 argc = parse_options(argc, argv, options, top_usage, 0);
1173 if (argc) 1268 if (argc)
1174 usage_with_options(top_usage, options); 1269 usage_with_options(top_usage, options);
1175 1270
1176 if (freq) {
1177 default_interval = freq;
1178 freq = 1;
1179 }
1180
1181 /* CPU and PID are mutually exclusive */ 1271 /* CPU and PID are mutually exclusive */
1182 if (target_pid != -1 && profile_cpu != -1) { 1272 if (target_pid != -1 && profile_cpu != -1) {
1183 printf("WARNING: PID switch overriding CPU\n"); 1273 printf("WARNING: PID switch overriding CPU\n");
@@ -1188,13 +1278,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1188 if (!nr_counters) 1278 if (!nr_counters)
1189 nr_counters = 1; 1279 nr_counters = 1;
1190 1280
1281 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1282 (nr_counters + 1) * sizeof(unsigned long));
1283 if (symbol_conf.vmlinux_name == NULL)
1284 symbol_conf.try_vmlinux_path = true;
1285 if (symbol__init() < 0)
1286 return -1;
1287
1191 if (delay_secs < 1) 1288 if (delay_secs < 1)
1192 delay_secs = 1; 1289 delay_secs = 1;
1193 1290
1194 parse_symbols();
1195 parse_source(sym_filter_entry); 1291 parse_source(sym_filter_entry);
1196 1292
1197 /* 1293 /*
1294 * User specified count overrides default frequency.
1295 */
1296 if (default_interval)
1297 freq = 0;
1298 else if (freq) {
1299 default_interval = freq;
1300 } else {
1301 fprintf(stderr, "frequency and count are zero, aborting\n");
1302 exit(EXIT_FAILURE);
1303 }
1304
1305 /*
1198 * Fill in the ones not specifically initialized via -c: 1306 * Fill in the ones not specifically initialized via -c:
1199 */ 1307 */
1200 for (counter = 0; counter < nr_counters; counter++) { 1308 for (counter = 0; counter < nr_counters; counter++) {
@@ -1211,5 +1319,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1211 if (target_pid != -1 || profile_cpu != -1) 1319 if (target_pid != -1 || profile_cpu != -1)
1212 nr_cpus = 1; 1320 nr_cpus = 1;
1213 1321
1322 get_term_dimensions(&winsize);
1323 if (print_entries == 0) {
1324 update_print_entries(&winsize);
1325 signal(SIGWINCH, sig_winch_handler);
1326 }
1327
1214 return __cmd_top(); 1328 return __cmd_top();
1215} 1329}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0c5e4f72f2ba..e2285e28720f 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -5,6 +5,53 @@
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"
11
12static char const *script_name;
13static char const *generate_script_lang;
14
15static int default_start_script(const char *script __unused,
16 int argc __unused,
17 const char **argv __unused)
18{
19 return 0;
20}
21
22static int default_stop_script(void)
23{
24 return 0;
25}
26
27static int default_generate_script(const char *outfile __unused)
28{
29 return 0;
30}
31
32static struct scripting_ops default_scripting_ops = {
33 .start_script = default_start_script,
34 .stop_script = default_stop_script,
35 .process_event = print_event,
36 .generate_script = default_generate_script,
37};
38
39static struct scripting_ops *scripting_ops;
40
41static void setup_scripting(void)
42{
43 /* make sure PERF_EXEC_PATH is set for scripts */
44 perf_set_argv_exec_path(perf_exec_path());
45
46 setup_perl_scripting();
47
48 scripting_ops = &default_scripting_ops;
49}
50
51static int cleanup_scripting(void)
52{
53 return scripting_ops->stop_script();
54}
8 55
9#include "util/parse-options.h" 56#include "util/parse-options.h"
10 57
@@ -12,249 +59,457 @@
12#include "util/debug.h" 59#include "util/debug.h"
13 60
14#include "util/trace-event.h" 61#include "util/trace-event.h"
62#include "util/exec_cmd.h"
15 63
16static char const *input_name = "perf.data"; 64static char const *input_name = "perf.data";
17static int input;
18static unsigned long page_size;
19static unsigned long mmap_window = 32;
20 65
21static unsigned long total = 0; 66static int process_sample_event(event_t *event, struct perf_session *session)
22static unsigned long total_comm = 0; 67{
68 struct sample_data data;
69 struct thread *thread;
23 70
24static struct rb_root threads; 71 memset(&data, 0, sizeof(data));
25static struct thread *last_match; 72 data.time = -1;
73 data.cpu = -1;
74 data.period = 1;
26 75
27static struct perf_header *header; 76 event__parse_sample(event, session->sample_type, &data);
28static u64 sample_type;
29 77
78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
79 event->header.misc,
80 data.pid, data.tid,
81 (void *)(long)data.ip,
82 (long long)data.period);
30 83
31static int 84 thread = perf_session__findnew(session, event->ip.pid);
32process_comm_event(event_t *event, unsigned long offset, unsigned long head) 85 if (thread == NULL) {
33{ 86 pr_debug("problem processing %d event, skipping it.\n",
34 struct thread *thread; 87 event->header.type);
88 return -1;
89 }
35 90
36 thread = threads__findnew(event->comm.pid, &threads, &last_match); 91 if (session->sample_type & PERF_SAMPLE_RAW) {
92 /*
93 * FIXME: better resolve from pid from the struct trace_entry
94 * field, although it should be the same than this perf
95 * event pid
96 */
97 scripting_ops->process_event(data.cpu, data.raw_data,
98 data.raw_size,
99 data.time, thread->comm);
100 }
37 101
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 102 session->events_stats.total += data.period;
39 (void *)(offset + head), 103 return 0;
40 (void *)(long)(event->header.size), 104}
41 event->comm.comm, event->comm.pid);
42 105
43 if (thread == NULL || 106static int sample_type_check(struct perf_session *session)
44 thread__set_comm(thread, event->comm.comm)) { 107{
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
109 fprintf(stderr,
110 "No trace sample to read. Did you call perf record "
111 "without -R?");
46 return -1; 112 return -1;
47 } 113 }
48 total_comm++;
49 114
50 return 0; 115 return 0;
51} 116}
52 117
53static int 118static struct perf_event_ops event_ops = {
54process_sample_event(event_t *event, unsigned long offset, unsigned long head) 119 .process_sample_event = process_sample_event,
120 .process_comm_event = event__process_comm,
121 .sample_type_check = sample_type_check,
122};
123
124static int __cmd_trace(struct perf_session *session)
55{ 125{
56 char level; 126 return perf_session__process_events(session, &event_ops);
57 int show = 0; 127}
58 struct dso *dso = NULL;
59 struct thread *thread;
60 u64 ip = event->ip.ip;
61 u64 timestamp = -1;
62 u32 cpu = -1;
63 u64 period = 1;
64 void *more_data = event->ip.__more_data;
65 int cpumode;
66
67 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68
69 if (sample_type & PERF_SAMPLE_TIME) {
70 timestamp = *(u64 *)more_data;
71 more_data += sizeof(u64);
72 }
73 128
74 if (sample_type & PERF_SAMPLE_CPU) { 129struct script_spec {
75 cpu = *(u32 *)more_data; 130 struct list_head node;
76 more_data += sizeof(u32); 131 struct scripting_ops *ops;
77 more_data += sizeof(u32); /* reserved */ 132 char spec[0];
78 } 133};
134
135LIST_HEAD(script_specs);
79 136
80 if (sample_type & PERF_SAMPLE_PERIOD) { 137static struct script_spec *script_spec__new(const char *spec,
81 period = *(u64 *)more_data; 138 struct scripting_ops *ops)
82 more_data += sizeof(u64); 139{
140 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
141
142 if (s != NULL) {
143 strcpy(s->spec, spec);
144 s->ops = ops;
83 } 145 }
84 146
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 147 return s;
86 (void *)(offset + head), 148}
87 (void *)(long)(event->header.size),
88 event->header.misc,
89 event->ip.pid, event->ip.tid,
90 (void *)(long)ip,
91 (long long)period);
92 149
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 150static void script_spec__delete(struct script_spec *s)
151{
152 free(s->spec);
153 free(s);
154}
94 155
95 if (thread == NULL) { 156static void script_spec__add(struct script_spec *s)
96 eprintf("problem processing %d event, skipping it.\n", 157{
97 event->header.type); 158 list_add_tail(&s->node, &script_specs);
98 return -1; 159}
99 }
100 160
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 161static struct script_spec *script_spec__find(const char *spec)
162{
163 struct script_spec *s;
102 164
103 if (cpumode == PERF_RECORD_MISC_KERNEL) { 165 list_for_each_entry(s, &script_specs, node)
104 show = SHOW_KERNEL; 166 if (strcasecmp(s->spec, spec) == 0)
105 level = 'k'; 167 return s;
168 return NULL;
169}
106 170
107 dso = kernel_dso; 171static struct script_spec *script_spec__findnew(const char *spec,
172 struct scripting_ops *ops)
173{
174 struct script_spec *s = script_spec__find(spec);
108 175
109 dump_printf(" ...... dso: %s\n", dso->name); 176 if (s)
177 return s;
110 178
111 } else if (cpumode == PERF_RECORD_MISC_USER) { 179 s = script_spec__new(spec, ops);
180 if (!s)
181 goto out_delete_spec;
112 182
113 show = SHOW_USER; 183 script_spec__add(s);
114 level = '.';
115 184
116 } else { 185 return s;
117 show = SHOW_HV;
118 level = 'H';
119 186
120 dso = hypervisor_dso; 187out_delete_spec:
188 script_spec__delete(s);
121 189
122 dump_printf(" ...... dso: [hypervisor]\n"); 190 return NULL;
123 } 191}
124 192
125 if (sample_type & PERF_SAMPLE_RAW) { 193int script_spec_register(const char *spec, struct scripting_ops *ops)
126 struct { 194{
127 u32 size; 195 struct script_spec *s;
128 char data[0];
129 } *raw = more_data;
130 196
131 /* 197 s = script_spec__find(spec);
132 * FIXME: better resolve from pid from the struct trace_entry 198 if (s)
133 * field, although it should be the same than this perf 199 return -1;
134 * event pid 200
135 */ 201 s = script_spec__findnew(spec, ops);
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm); 202 if (!s)
137 } 203 return -1;
138 total += period;
139 204
140 return 0; 205 return 0;
141} 206}
142 207
143static int 208static struct scripting_ops *script_spec__lookup(const char *spec)
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{ 209{
146 trace_event(event); 210 struct script_spec *s = script_spec__find(spec);
211 if (!s)
212 return NULL;
147 213
148 switch (event->header.type) { 214 return s->ops;
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST: 215}
150 return 0;
151 216
152 case PERF_RECORD_COMM: 217static void list_available_languages(void)
153 return process_comm_event(event, offset, head); 218{
219 struct script_spec *s;
154 220
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ: 221 fprintf(stderr, "\n");
156 return 0; 222 fprintf(stderr, "Scripting language extensions (used in "
223 "perf trace -s [spec:]script.[spec]):\n\n");
157 224
158 case PERF_RECORD_SAMPLE: 225 list_for_each_entry(s, &script_specs, node)
159 return process_sample_event(event, offset, head); 226 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
160 227
161 case PERF_RECORD_MAX: 228 fprintf(stderr, "\n");
162 default: 229}
163 return -1; 230
231static int parse_scriptname(const struct option *opt __used,
232 const char *str, int unset __used)
233{
234 char spec[PATH_MAX];
235 const char *script, *ext;
236 int len;
237
238 if (strcmp(str, "list") == 0) {
239 list_available_languages();
240 return 0;
241 }
242
243 script = strchr(str, ':');
244 if (script) {
245 len = script - str;
246 if (len >= PATH_MAX) {
247 fprintf(stderr, "invalid language specifier");
248 return -1;
249 }
250 strncpy(spec, str, len);
251 spec[len] = '\0';
252 scripting_ops = script_spec__lookup(spec);
253 if (!scripting_ops) {
254 fprintf(stderr, "invalid language specifier");
255 return -1;
256 }
257 script++;
258 } else {
259 script = str;
260 ext = strchr(script, '.');
261 if (!ext) {
262 fprintf(stderr, "invalid script extension");
263 return -1;
264 }
265 scripting_ops = script_spec__lookup(++ext);
266 if (!scripting_ops) {
267 fprintf(stderr, "invalid script extension");
268 return -1;
269 }
164 } 270 }
165 271
272 script_name = strdup(script);
273
166 return 0; 274 return 0;
167} 275}
168 276
169static int __cmd_trace(void) 277#define for_each_lang(scripts_dir, lang_dirent, lang_next) \
278 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
279 lang_next) \
280 if (lang_dirent.d_type == DT_DIR && \
281 (strcmp(lang_dirent.d_name, ".")) && \
282 (strcmp(lang_dirent.d_name, "..")))
283
284#define for_each_script(lang_dir, script_dirent, script_next) \
285 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
286 script_next) \
287 if (script_dirent.d_type != DT_DIR)
288
289
290#define RECORD_SUFFIX "-record"
291#define REPORT_SUFFIX "-report"
292
293struct script_desc {
294 struct list_head node;
295 char *name;
296 char *half_liner;
297 char *args;
298};
299
300LIST_HEAD(script_descs);
301
302static struct script_desc *script_desc__new(const char *name)
170{ 303{
171 int ret, rc = EXIT_FAILURE; 304 struct script_desc *s = zalloc(sizeof(*s));
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187 305
188 ret = fstat(input, &perf_stat); 306 if (s != NULL)
189 if (ret < 0) { 307 s->name = strdup(name);
190 perror("failed to stat file");
191 exit(-1);
192 }
193 308
194 if (!perf_stat.st_size) { 309 return s;
195 fprintf(stderr, "zero-sized file, nothing to do!\n"); 310}
196 exit(0); 311
197 } 312static void script_desc__delete(struct script_desc *s)
198 header = perf_header__read(input); 313{
199 head = header->data_offset; 314 free(s->name);
200 sample_type = perf_header__sample_type(header); 315 free(s);
316}
317
318static void script_desc__add(struct script_desc *s)
319{
320 list_add_tail(&s->node, &script_descs);
321}
322
323static struct script_desc *script_desc__find(const char *name)
324{
325 struct script_desc *s;
326
327 list_for_each_entry(s, &script_descs, node)
328 if (strcasecmp(s->name, name) == 0)
329 return s;
330 return NULL;
331}
332
333static struct script_desc *script_desc__findnew(const char *name)
334{
335 struct script_desc *s = script_desc__find(name);
336
337 if (s)
338 return s;
339
340 s = script_desc__new(name);
341 if (!s)
342 goto out_delete_desc;
343
344 script_desc__add(s);
201 345
202 if (!(sample_type & PERF_SAMPLE_RAW)) 346 return s;
203 die("No trace sample to read. Did you call perf record "
204 "without -R?");
205 347
206 if (load_kernel() < 0) { 348out_delete_desc:
207 perror("failed to load kernel symbols"); 349 script_desc__delete(s);
208 return EXIT_FAILURE; 350
351 return NULL;
352}
353
354static char *ends_with(char *str, const char *suffix)
355{
356 size_t suffix_len = strlen(suffix);
357 char *p = str;
358
359 if (strlen(str) > suffix_len) {
360 p = str + strlen(str) - suffix_len;
361 if (!strncmp(p, suffix, suffix_len))
362 return p;
209 } 363 }
210 364
211remap: 365 return NULL;
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, 366}
213 MAP_SHARED, input, offset); 367
214 if (buf == MAP_FAILED) { 368static char *ltrim(char *str)
215 perror("failed to mmap file"); 369{
216 exit(-1); 370 int len = strlen(str);
371
372 while (len && isspace(*str)) {
373 len--;
374 str++;
217 } 375 }
218 376
219more: 377 return str;
220 event = (event_t *)(buf + head); 378}
221 379
222 if (head + event->header.size >= page_size * mmap_window) { 380static int read_script_info(struct script_desc *desc, const char *filename)
223 unsigned long shift = page_size * (head / page_size); 381{
224 int res; 382 char line[BUFSIZ], *p;
383 FILE *fp;
225 384
226 res = munmap(buf, page_size * mmap_window); 385 fp = fopen(filename, "r");
227 assert(res == 0); 386 if (!fp)
387 return -1;
228 388
229 offset += shift; 389 while (fgets(line, sizeof(line), fp)) {
230 head -= shift; 390 p = ltrim(line);
231 goto remap; 391 if (strlen(p) == 0)
392 continue;
393 if (*p != '#')
394 continue;
395 p++;
396 if (strlen(p) && *p == '!')
397 continue;
398
399 p = ltrim(p);
400 if (strlen(p) && p[strlen(p) - 1] == '\n')
401 p[strlen(p) - 1] = '\0';
402
403 if (!strncmp(p, "description:", strlen("description:"))) {
404 p += strlen("description:");
405 desc->half_liner = strdup(ltrim(p));
406 continue;
407 }
408
409 if (!strncmp(p, "args:", strlen("args:"))) {
410 p += strlen("args:");
411 desc->args = strdup(ltrim(p));
412 continue;
413 }
232 } 414 }
233 415
234 size = event->header.size; 416 fclose(fp);
235 417
236 if (!size || process_event(event, offset, head) < 0) { 418 return 0;
237 419}
238 /*
239 * assume we lost track of the stream, check alignment, and
240 * increment a single u64 in the hope to catch on again 'soon'.
241 */
242 420
243 if (unlikely(head & 7)) 421static int list_available_scripts(const struct option *opt __used,
244 head &= ~7ULL; 422 const char *s __used, int unset __used)
423{
424 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
425 char scripts_path[MAXPATHLEN];
426 DIR *scripts_dir, *lang_dir;
427 char script_path[MAXPATHLEN];
428 char lang_path[MAXPATHLEN];
429 struct script_desc *desc;
430 char first_half[BUFSIZ];
431 char *script_root;
432 char *str;
433
434 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
435
436 scripts_dir = opendir(scripts_path);
437 if (!scripts_dir)
438 return -1;
245 439
246 size = 8; 440 for_each_lang(scripts_dir, lang_dirent, lang_next) {
441 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
442 lang_dirent.d_name);
443 lang_dir = opendir(lang_path);
444 if (!lang_dir)
445 continue;
446
447 for_each_script(lang_dir, script_dirent, script_next) {
448 script_root = strdup(script_dirent.d_name);
449 str = ends_with(script_root, REPORT_SUFFIX);
450 if (str) {
451 *str = '\0';
452 desc = script_desc__findnew(script_root);
453 snprintf(script_path, MAXPATHLEN, "%s/%s",
454 lang_path, script_dirent.d_name);
455 read_script_info(desc, script_path);
456 }
457 free(script_root);
458 }
247 } 459 }
248 460
249 head += size; 461 fprintf(stdout, "List of available trace scripts:\n");
462 list_for_each_entry(desc, &script_descs, node) {
463 sprintf(first_half, "%s %s", desc->name,
464 desc->args ? desc->args : "");
465 fprintf(stdout, " %-36s %s\n", first_half,
466 desc->half_liner ? desc->half_liner : "");
467 }
250 468
251 if (offset + head < (unsigned long)perf_stat.st_size) 469 exit(0);
252 goto more; 470}
253 471
254 rc = EXIT_SUCCESS; 472static char *get_script_path(const char *script_root, const char *suffix)
255 close(input); 473{
474 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
475 char scripts_path[MAXPATHLEN];
476 char script_path[MAXPATHLEN];
477 DIR *scripts_dir, *lang_dir;
478 char lang_path[MAXPATHLEN];
479 char *str, *__script_root;
480 char *path = NULL;
481
482 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
483
484 scripts_dir = opendir(scripts_path);
485 if (!scripts_dir)
486 return NULL;
487
488 for_each_lang(scripts_dir, lang_dirent, lang_next) {
489 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
490 lang_dirent.d_name);
491 lang_dir = opendir(lang_path);
492 if (!lang_dir)
493 continue;
494
495 for_each_script(lang_dir, script_dirent, script_next) {
496 __script_root = strdup(script_dirent.d_name);
497 str = ends_with(__script_root, suffix);
498 if (str) {
499 *str = '\0';
500 if (strcmp(__script_root, script_root))
501 continue;
502 snprintf(script_path, MAXPATHLEN, "%s/%s",
503 lang_path, script_dirent.d_name);
504 path = strdup(script_path);
505 free(__script_root);
506 break;
507 }
508 free(__script_root);
509 }
510 }
256 511
257 return rc; 512 return path;
258} 513}
259 514
260static const char * const annotate_usage[] = { 515static const char * const annotate_usage[] = {
@@ -267,25 +522,117 @@ static const struct option options[] = {
267 "dump raw trace in ASCII"), 522 "dump raw trace in ASCII"),
268 OPT_BOOLEAN('v', "verbose", &verbose, 523 OPT_BOOLEAN('v', "verbose", &verbose,
269 "be more verbose (show symbol address, etc)"), 524 "be more verbose (show symbol address, etc)"),
525 OPT_BOOLEAN('L', "Latency", &latency_format,
526 "show latency attributes (irqs/preemption disabled, etc)"),
527 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
528 list_available_scripts),
529 OPT_CALLBACK('s', "script", NULL, "name",
530 "script file name (lang:script name, script name, or *)",
531 parse_scriptname),
532 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
533 "generate perf-trace.xx script in specified language"),
534
270 OPT_END() 535 OPT_END()
271}; 536};
272 537
273int cmd_trace(int argc, const char **argv, const char *prefix __used) 538int cmd_trace(int argc, const char **argv, const char *prefix __used)
274{ 539{
275 symbol__init(); 540 struct perf_session *session;
276 page_size = getpagesize(); 541 const char *suffix = NULL;
542 const char **__argv;
543 char *script_path;
544 int i, err;
545
546 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
547 if (argc < 3) {
548 fprintf(stderr,
549 "Please specify a record script\n");
550 return -1;
551 }
552 suffix = RECORD_SUFFIX;
553 }
277 554
278 argc = parse_options(argc, argv, options, annotate_usage, 0); 555 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
279 if (argc) { 556 if (argc < 3) {
280 /* 557 fprintf(stderr,
281 * Special case: if there's an argument left then assume tha 558 "Please specify a report script\n");
282 * it's a symbol filter: 559 return -1;
283 */ 560 }
284 if (argc > 1) 561 suffix = REPORT_SUFFIX;
285 usage_with_options(annotate_usage, options);
286 } 562 }
287 563
564 if (suffix) {
565 script_path = get_script_path(argv[2], suffix);
566 if (!script_path) {
567 fprintf(stderr, "script not found\n");
568 return -1;
569 }
570
571 __argv = malloc((argc + 1) * sizeof(const char *));
572 __argv[0] = "/bin/sh";
573 __argv[1] = script_path;
574 for (i = 3; i < argc; i++)
575 __argv[i - 1] = argv[i];
576 __argv[argc - 1] = NULL;
577
578 execvp("/bin/sh", (char **)__argv);
579 exit(-1);
580 }
581
582 setup_scripting();
583
584 argc = parse_options(argc, argv, options, annotate_usage,
585 PARSE_OPT_STOP_AT_NON_OPTION);
586
587 if (symbol__init() < 0)
588 return -1;
288 setup_pager(); 589 setup_pager();
289 590
290 return __cmd_trace(); 591 session = perf_session__new(input_name, O_RDONLY, 0);
592 if (session == NULL)
593 return -ENOMEM;
594
595 if (generate_script_lang) {
596 struct stat perf_stat;
597
598 int input = open(input_name, O_RDONLY);
599 if (input < 0) {
600 perror("failed to open file");
601 exit(-1);
602 }
603
604 err = fstat(input, &perf_stat);
605 if (err < 0) {
606 perror("failed to stat file");
607 exit(-1);
608 }
609
610 if (!perf_stat.st_size) {
611 fprintf(stderr, "zero-sized file, nothing to do!\n");
612 exit(0);
613 }
614
615 scripting_ops = script_spec__lookup(generate_script_lang);
616 if (!scripting_ops) {
617 fprintf(stderr, "invalid language specifier");
618 return -1;
619 }
620
621 perf_header__read(&session->header, input);
622 err = scripting_ops->generate_script("perf-trace");
623 goto out;
624 }
625
626 if (script_name) {
627 err = scripting_ops->start_script(script_name, argc, argv);
628 if (err)
629 goto out;
630 }
631
632 err = __cmd_trace(session);
633
634 perf_session__delete(session);
635 cleanup_scripting();
636out:
637 return err;
291} 638}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index e11d8d231c3b..18035b1f16c7 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -15,6 +15,9 @@ 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);
20extern int cmd_diff(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 21extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix); 22extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix); 23extern int cmd_list(int argc, const char **argv, const char *prefix);
@@ -25,5 +28,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); 28extern int cmd_top(int argc, const char **argv, const char *prefix);
26extern int cmd_trace(int argc, const char **argv, const char *prefix); 29extern int cmd_trace(int argc, const char **argv, const char *prefix);
27extern int cmd_version(int argc, const char **argv, const char *prefix); 30extern int cmd_version(int argc, const char **argv, const char *prefix);
31extern int cmd_probe(int argc, const char **argv, const char *prefix);
32extern int cmd_kmem(int argc, const char **argv, const char *prefix);
28 33
29#endif 34#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00326e230d87..71dc7c3fe7b2 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,6 +3,9 @@
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
8perf-diff mainporcelain common
6perf-list mainporcelain common 9perf-list mainporcelain common
7perf-sched mainporcelain common 10perf-sched mainporcelain common
8perf-record mainporcelain common 11perf-record mainporcelain common
@@ -11,3 +14,5 @@ perf-stat mainporcelain common
11perf-timechart mainporcelain common 14perf-timechart mainporcelain common
12perf-top mainporcelain common 15perf-top mainporcelain common
13perf-trace mainporcelain common 16perf-trace mainporcelain common
17perf-probe mainporcelain common
18perf-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..873e55fab375 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,22 @@ 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 { "diff", cmd_diff, 0 },
289 { "record", cmd_record, 0 }, 290 { "help", cmd_help, 0 },
290 { "report", cmd_report, 0 }, 291 { "list", cmd_list, 0 },
291 { "stat", cmd_stat, 0 }, 292 { "record", cmd_record, 0 },
292 { "timechart", cmd_timechart, 0 }, 293 { "report", cmd_report, 0 },
293 { "top", cmd_top, 0 }, 294 { "bench", cmd_bench, 0 },
294 { "annotate", cmd_annotate, 0 }, 295 { "stat", cmd_stat, 0 },
295 { "version", cmd_version, 0 }, 296 { "timechart", cmd_timechart, 0 },
296 { "trace", cmd_trace, 0 }, 297 { "top", cmd_top, 0 },
297 { "sched", cmd_sched, 0 }, 298 { "annotate", cmd_annotate, 0 },
299 { "version", cmd_version, 0 },
300 { "trace", cmd_trace, 0 },
301 { "sched", cmd_sched, 0 },
302 { "probe", cmd_probe, 0 },
303 { "kmem", cmd_kmem, 0 },
298 }; 304 };
299 unsigned int i; 305 unsigned int i;
300 static const char ext[] = STRIP_EXTENSION; 306 static const char ext[] = STRIP_EXTENSION;
@@ -382,45 +388,12 @@ static int run_argv(int *argcp, const char ***argv)
382/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 388/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
383static void get_debugfs_mntpt(void) 389static void get_debugfs_mntpt(void)
384{ 390{
385 FILE *file; 391 const char *path = debugfs_find_mountpoint();
386 char fs_type[100];
387 char debugfs[MAXPATHLEN];
388 392
389 /* 393 if (path)
390 * try the standard location 394 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
391 */ 395 else
392 if (valid_debugfs_mount("/sys/kernel/debug/") == 0) { 396 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} 397}
425 398
426int main(int argc, const char **argv) 399int 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..7fc4a033dd49
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2# description: useless but exhaustive test script
3perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
new file mode 100644
index 000000000000..b25056ebf963
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
new file mode 100644
index 000000000000..eddb9ccce6a5
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -0,0 +1,7 @@
1#!/bin/bash
2# description: r/w activity for a program, by file
3# args: <comm>
4perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1
5
6
7
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
new file mode 100644
index 000000000000..8903979c5b6c
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
new file mode 100644
index 000000000000..7f44c25cc857
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2# description: system-wide r/w activity
3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
new file mode 100644
index 000000000000..6abedda911a4
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -0,0 +1,6 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup
3
4
5
6
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
new file mode 100644
index 000000000000..fce3adcb3249
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -0,0 +1,6 @@
1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency
3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
new file mode 100644
index 000000000000..fce6637b19ba
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
new file mode 100644
index 000000000000..71cfbd182fb9
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -0,0 +1,7 @@
1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
4
5
6
7
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
new file mode 100644
index 000000000000..4e7dc0a407a5
--- /dev/null
+++ b/tools/perf/scripts/perl/check-perf-trace.pl
@@ -0,0 +1,106 @@
1# perf trace event handlers, generated by perf trace -g perl
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, perl scripting support should be ok.
9
10use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
11use lib "./Perf-Trace-Util/lib";
12use Perf::Trace::Core;
13use Perf::Trace::Context;
14use Perf::Trace::Util;
15
16sub trace_begin
17{
18 print "trace_begin\n";
19}
20
21sub trace_end
22{
23 print "trace_end\n";
24
25 print_unhandled();
26}
27
28sub irq::softirq_entry
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $vec) = @_;
33
34 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
35 $common_pid, $common_comm);
36
37 print_uncommon($context);
38
39 printf("vec=%s\n",
40 symbol_str("irq::softirq_entry", "vec", $vec));
41}
42
43sub kmem::kmalloc
44{
45 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
46 $common_pid, $common_comm,
47 $call_site, $ptr, $bytes_req, $bytes_alloc,
48 $gfp_flags) = @_;
49
50 print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
51 $common_pid, $common_comm);
52
53 print_uncommon($context);
54
55 printf("call_site=%p, ptr=%p, bytes_req=%u, bytes_alloc=%u, ".
56 "gfp_flags=%s\n",
57 $call_site, $ptr, $bytes_req, $bytes_alloc,
58
59 flag_str("kmem::kmalloc", "gfp_flags", $gfp_flags));
60}
61
62# print trace fields not included in handler args
63sub print_uncommon
64{
65 my ($context) = @_;
66
67 printf("common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, ",
68 common_pc($context), trace_flag_str(common_flags($context)),
69 common_lock_depth($context));
70
71}
72
73my %unhandled;
74
75sub print_unhandled
76{
77 if ((scalar keys %unhandled) == 0) {
78 return;
79 }
80
81 print "\nunhandled events:\n\n";
82
83 printf("%-40s %10s\n", "event", "count");
84 printf("%-40s %10s\n", "----------------------------------------",
85 "-----------");
86
87 foreach my $event_name (keys %unhandled) {
88 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
89 }
90}
91
92sub trace_unhandled
93{
94 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
95 $common_pid, $common_comm) = @_;
96
97 $unhandled{$event_name}++;
98}
99
100sub print_header
101{
102 my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;
103
104 printf("%-20s %5u %05u.%09u %8u %-20s ",
105 $event_name, $cpu, $secs, $nsecs, $pid, $comm);
106}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
new file mode 100644
index 000000000000..2a39097687b9
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -0,0 +1,106 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for files read/written to for a given program
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my $usage = "perf trace -s rw-by-file.pl <comm>\n";
22
23my $for_comm = shift or die $usage;
24
25my %reads;
26my %writes;
27
28sub syscalls::sys_enter_read
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
32
33 if ($common_comm eq $for_comm) {
34 $reads{$fd}{bytes_requested} += $count;
35 $reads{$fd}{total_reads}++;
36 }
37}
38
39sub syscalls::sys_enter_write
40{
41 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
42 $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
43
44 if ($common_comm eq $for_comm) {
45 $writes{$fd}{bytes_written} += $count;
46 $writes{$fd}{total_writes}++;
47 }
48}
49
50sub trace_end
51{
52 printf("file read counts for $for_comm:\n\n");
53
54 printf("%6s %10s %10s\n", "fd", "# reads", "bytes_requested");
55 printf("%6s %10s %10s\n", "------", "----------", "-----------");
56
57 foreach my $fd (sort {$reads{$b}{bytes_requested} <=>
58 $reads{$a}{bytes_requested}} keys %reads) {
59 my $total_reads = $reads{$fd}{total_reads};
60 my $bytes_requested = $reads{$fd}{bytes_requested};
61 printf("%6u %10u %10u\n", $fd, $total_reads, $bytes_requested);
62 }
63
64 printf("\nfile write counts for $for_comm:\n\n");
65
66 printf("%6s %10s %10s\n", "fd", "# writes", "bytes_written");
67 printf("%6s %10s %10s\n", "------", "----------", "-----------");
68
69 foreach my $fd (sort {$writes{$b}{bytes_written} <=>
70 $writes{$a}{bytes_written}} keys %writes) {
71 my $total_writes = $writes{$fd}{total_writes};
72 my $bytes_written = $writes{$fd}{bytes_written};
73 printf("%6u %10u %10u\n", $fd, $total_writes, $bytes_written);
74 }
75
76 print_unhandled();
77}
78
79my %unhandled;
80
81sub print_unhandled
82{
83 if ((scalar keys %unhandled) == 0) {
84 return;
85 }
86
87 print "\nunhandled events:\n\n";
88
89 printf("%-40s %10s\n", "event", "count");
90 printf("%-40s %10s\n", "----------------------------------------",
91 "-----------");
92
93 foreach my $event_name (keys %unhandled) {
94 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
95 }
96}
97
98sub trace_unhandled
99{
100 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
101 $common_pid, $common_comm) = @_;
102
103 $unhandled{$event_name}++;
104}
105
106
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
new file mode 100644
index 000000000000..da601fae1a00
--- /dev/null
+++ b/tools/perf/scripts/perl/rw-by-pid.pl
@@ -0,0 +1,170 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display r/w activity for all processes
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %reads;
22my %writes;
23
24sub syscalls::sys_exit_read
25{
26 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
27 $common_pid, $common_comm,
28 $nr, $ret) = @_;
29
30 if ($ret > 0) {
31 $reads{$common_pid}{bytes_read} += $ret;
32 } else {
33 if (!defined ($reads{$common_pid}{bytes_read})) {
34 $reads{$common_pid}{bytes_read} = 0;
35 }
36 $reads{$common_pid}{errors}{$ret}++;
37 }
38}
39
40sub syscalls::sys_enter_read
41{
42 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
43 $common_pid, $common_comm,
44 $nr, $fd, $buf, $count) = @_;
45
46 $reads{$common_pid}{bytes_requested} += $count;
47 $reads{$common_pid}{total_reads}++;
48 $reads{$common_pid}{comm} = $common_comm;
49}
50
51sub syscalls::sys_exit_write
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $nr, $ret) = @_;
56
57 if ($ret <= 0) {
58 $writes{$common_pid}{errors}{$ret}++;
59 }
60}
61
62sub syscalls::sys_enter_write
63{
64 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
65 $common_pid, $common_comm,
66 $nr, $fd, $buf, $count) = @_;
67
68 $writes{$common_pid}{bytes_written} += $count;
69 $writes{$common_pid}{total_writes}++;
70 $writes{$common_pid}{comm} = $common_comm;
71}
72
73sub trace_end
74{
75 printf("read counts by pid:\n\n");
76
77 printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
78 "# reads", "bytes_requested", "bytes_read");
79 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
80 "-----------", "----------", "----------");
81
82 foreach my $pid (sort {$reads{$b}{bytes_read} <=>
83 $reads{$a}{bytes_read}} keys %reads) {
84 my $comm = $reads{$pid}{comm};
85 my $total_reads = $reads{$pid}{total_reads};
86 my $bytes_requested = $reads{$pid}{bytes_requested};
87 my $bytes_read = $reads{$pid}{bytes_read};
88
89 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
90 $total_reads, $bytes_requested, $bytes_read);
91 }
92
93 printf("\nfailed reads by pid:\n\n");
94
95 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
96 printf("%6s %20s %6s %10s\n", "------", "--------------------",
97 "------", "----------");
98
99 foreach my $pid (keys %reads) {
100 my $comm = $reads{$pid}{comm};
101 foreach my $err (sort {$reads{$b}{comm} cmp $reads{$a}{comm}}
102 keys %{$reads{$pid}{errors}}) {
103 my $errors = $reads{$pid}{errors}{$err};
104
105 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
106 }
107 }
108
109 printf("\nwrite counts by pid:\n\n");
110
111 printf("%6s %20s %10s %10s\n", "pid", "comm",
112 "# writes", "bytes_written");
113 printf("%6s %-20s %10s %10s\n", "------", "--------------------",
114 "-----------", "----------");
115
116 foreach my $pid (sort {$writes{$b}{bytes_written} <=>
117 $writes{$a}{bytes_written}} keys %writes) {
118 my $comm = $writes{$pid}{comm};
119 my $total_writes = $writes{$pid}{total_writes};
120 my $bytes_written = $writes{$pid}{bytes_written};
121
122 printf("%6s %-20s %10s %10s\n", $pid, $comm,
123 $total_writes, $bytes_written);
124 }
125
126 printf("\nfailed writes by pid:\n\n");
127
128 printf("%6s %20s %6s %10s\n", "pid", "comm", "error #", "# errors");
129 printf("%6s %20s %6s %10s\n", "------", "--------------------",
130 "------", "----------");
131
132 foreach my $pid (keys %writes) {
133 my $comm = $writes{$pid}{comm};
134 foreach my $err (sort {$writes{$b}{comm} cmp $writes{$a}{comm}}
135 keys %{$writes{$pid}{errors}}) {
136 my $errors = $writes{$pid}{errors}{$err};
137
138 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors);
139 }
140 }
141
142 print_unhandled();
143}
144
145my %unhandled;
146
147sub print_unhandled
148{
149 if ((scalar keys %unhandled) == 0) {
150 return;
151 }
152
153 print "\nunhandled events:\n\n";
154
155 printf("%-40s %10s\n", "event", "count");
156 printf("%-40s %10s\n", "----------------------------------------",
157 "-----------");
158
159 foreach my $event_name (keys %unhandled) {
160 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
161 }
162}
163
164sub trace_unhandled
165{
166 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
167 $common_pid, $common_comm) = @_;
168
169 $unhandled{$event_name}++;
170}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
new file mode 100644
index 000000000000..ed58ef284e23
--- /dev/null
+++ b/tools/perf/scripts/perl/wakeup-latency.pl
@@ -0,0 +1,103 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Display avg/min/max wakeup latency
6
7# The common_* event handler fields are the most useful fields common to
8# all events. They don't necessarily correspond to the 'common_*' fields
9# in the status files. Those fields not available as handler params can
10# be retrieved via script functions of the form get_common_*().
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my %last_wakeup;
22
23my $max_wakeup_latency;
24my $min_wakeup_latency;
25my $total_wakeup_latency;
26my $total_wakeups;
27
28sub sched::sched_switch
29{
30 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
31 $common_pid, $common_comm,
32 $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
33 $next_prio) = @_;
34
35 my $wakeup_ts = $last_wakeup{$common_cpu}{ts};
36 if ($wakeup_ts) {
37 my $switch_ts = nsecs($common_secs, $common_nsecs);
38 my $wakeup_latency = $switch_ts - $wakeup_ts;
39 if ($wakeup_latency > $max_wakeup_latency) {
40 $max_wakeup_latency = $wakeup_latency;
41 }
42 if ($wakeup_latency < $min_wakeup_latency) {
43 $min_wakeup_latency = $wakeup_latency;
44 }
45 $total_wakeup_latency += $wakeup_latency;
46 $total_wakeups++;
47 }
48 $last_wakeup{$common_cpu}{ts} = 0;
49}
50
51sub sched::sched_wakeup
52{
53 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
54 $common_pid, $common_comm,
55 $comm, $pid, $prio, $success, $target_cpu) = @_;
56
57 $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
58}
59
60sub trace_begin
61{
62 $min_wakeup_latency = 1000000000;
63 $max_wakeup_latency = 0;
64}
65
66sub trace_end
67{
68 printf("wakeup_latency stats:\n\n");
69 print "total_wakeups: $total_wakeups\n";
70 printf("avg_wakeup_latency (ns): %u\n",
71 avg($total_wakeup_latency, $total_wakeups));
72 printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
73 printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
74
75 print_unhandled();
76}
77
78my %unhandled;
79
80sub print_unhandled
81{
82 if ((scalar keys %unhandled) == 0) {
83 return;
84 }
85
86 print "\nunhandled events:\n\n";
87
88 printf("%-40s %10s\n", "event", "count");
89 printf("%-40s %10s\n", "----------------------------------------",
90 "-----------");
91
92 foreach my $event_name (keys %unhandled) {
93 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
94 }
95}
96
97sub trace_unhandled
98{
99 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
100 $common_pid, $common_comm) = @_;
101
102 $unhandled{$event_name}++;
103}
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
new file mode 100644
index 000000000000..511302c8a494
--- /dev/null
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -0,0 +1,129 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'};
75 my $exe = $$wqhash{'executed'};
76 my $comm = $$wqhash{'comm'};
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'};
91 my $destroyed = $$wqhash{'destroyed'};
92 my $comm = $$wqhash{'comm'};
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/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..b557b836de3d
--- /dev/null
+++ b/tools/perf/util/data_map.c
@@ -0,0 +1,252 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
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..bb0fd6da2d56
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,456 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "session.h"
5#include "sort.h"
6#include "string.h"
7#include "strlist.h"
8#include "thread.h"
9
10static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
14{
15 event_t ev;
16 char filename[PATH_MAX];
17 char bf[BUFSIZ];
18 FILE *fp;
19 size_t size = 0;
20 DIR *tasks;
21 struct dirent dirent, *next;
22 pid_t tgid = 0;
23
24 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
25
26 fp = fopen(filename, "r");
27 if (fp == NULL) {
28out_race:
29 /*
30 * We raced with a task exiting - just return:
31 */
32 pr_debug("couldn't open %s\n", filename);
33 return 0;
34 }
35
36 memset(&ev.comm, 0, sizeof(ev.comm));
37 while (!ev.comm.comm[0] || !ev.comm.pid) {
38 if (fgets(bf, sizeof(bf), fp) == NULL)
39 goto out_failure;
40
41 if (memcmp(bf, "Name:", 5) == 0) {
42 char *name = bf + 5;
43 while (*name && isspace(*name))
44 ++name;
45 size = strlen(name) - 1;
46 memcpy(ev.comm.comm, name, size++);
47 } else if (memcmp(bf, "Tgid:", 5) == 0) {
48 char *tgids = bf + 5;
49 while (*tgids && isspace(*tgids))
50 ++tgids;
51 tgid = ev.comm.pid = atoi(tgids);
52 }
53 }
54
55 ev.comm.header.type = PERF_RECORD_COMM;
56 size = ALIGN(size, sizeof(u64));
57 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
58
59 if (!full) {
60 ev.comm.tid = pid;
61
62 process(&ev, session);
63 goto out_fclose;
64 }
65
66 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
67
68 tasks = opendir(filename);
69 if (tasks == NULL)
70 goto out_race;
71
72 while (!readdir_r(tasks, &dirent, &next) && next) {
73 char *end;
74 pid = strtol(dirent.d_name, &end, 10);
75 if (*end)
76 continue;
77
78 ev.comm.tid = pid;
79
80 process(&ev, session);
81 }
82 closedir(tasks);
83
84out_fclose:
85 fclose(fp);
86 return tgid;
87
88out_failure:
89 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
90 return -1;
91}
92
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
97{
98 char filename[PATH_MAX];
99 FILE *fp;
100
101 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
102
103 fp = fopen(filename, "r");
104 if (fp == NULL) {
105 /*
106 * We raced with a task exiting - just return:
107 */
108 pr_debug("couldn't open %s\n", filename);
109 return -1;
110 }
111
112 while (1) {
113 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP },
116 };
117 int n;
118 size_t size;
119 if (fgets(bf, sizeof(bf), fp) == NULL)
120 break;
121
122 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
123 n = hex2u64(pbf, &ev.mmap.start);
124 if (n < 0)
125 continue;
126 pbf += n + 1;
127 n = hex2u64(pbf, &ev.mmap.len);
128 if (n < 0)
129 continue;
130 pbf += n + 3;
131 if (*pbf == 'x') { /* vm_exec */
132 char *execname = strchr(bf, '/');
133
134 /* Catch VDSO */
135 if (execname == NULL)
136 execname = strstr(bf, "[vdso]");
137
138 if (execname == NULL)
139 continue;
140
141 size = strlen(execname);
142 execname[size - 1] = '\0'; /* Remove \n */
143 memcpy(ev.mmap.filename, execname, size);
144 size = ALIGN(size, sizeof(u64));
145 ev.mmap.len -= ev.mmap.start;
146 ev.mmap.header.size = (sizeof(ev.mmap) -
147 (sizeof(ev.mmap.filename) - size));
148 ev.mmap.pid = tgid;
149 ev.mmap.tid = pid;
150
151 process(&ev, session);
152 }
153 }
154
155 fclose(fp);
156 return 0;
157}
158
159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
163{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
165 if (tgid == -1)
166 return -1;
167 return event__synthesize_mmap_events(pid, tgid, process, session);
168}
169
170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
173{
174 DIR *proc;
175 struct dirent dirent, *next;
176
177 proc = opendir("/proc");
178
179 while (!readdir_r(proc, &dirent, &next) && next) {
180 char *end;
181 pid_t pid = strtol(dirent.d_name, &end, 10);
182
183 if (*end) /* only interested in proper numerical dirents */
184 continue;
185
186 event__synthesize_thread(pid, process, session);
187 }
188
189 closedir(proc);
190}
191
192static void thread__comm_adjust(struct thread *self)
193{
194 char *comm = self->comm;
195
196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
200
201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
209{
210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
214
215 thread__comm_adjust(self);
216
217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
221{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
223
224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
225
226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
228 return -1;
229 }
230
231 return 0;
232}
233
234int event__process_lost(event_t *self, struct perf_session *session)
235{
236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
237 session->events_stats.lost += self->lost.lost;
238 return 0;
239}
240
241int event__process_mmap(event_t *self, struct perf_session *session)
242{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
245 session->cwd, session->cwdlen);
246
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
248 self->mmap.pid, self->mmap.tid,
249 (void *)(long)self->mmap.start,
250 (void *)(long)self->mmap.len,
251 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename);
253
254 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
256 else
257 thread__insert_map(thread, map);
258
259 return 0;
260}
261
262int event__process_task(event_t *self, struct perf_session *session)
263{
264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
266
267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
268 self->fork.ppid, self->fork.ptid);
269 /*
270 * A thread clone will have the same PID for both parent and child.
271 */
272 if (thread == parent)
273 return 0;
274
275 if (self->header.type == PERF_RECORD_EXIT)
276 return 0;
277
278 if (thread == NULL || parent == NULL ||
279 thread__fork(thread, parent) < 0) {
280 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
281 return -1;
282 }
283
284 return 0;
285}
286
287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
289 enum map_type type, u64 addr,
290 struct addr_location *al,
291 symbol_filter_t filter)
292{
293 struct map_groups *mg = &self->mg;
294
295 al->thread = self;
296 al->addr = addr;
297
298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
299 al->level = 'k';
300 mg = &session->kmaps;
301 } else if (cpumode & PERF_RECORD_MISC_USER)
302 al->level = '.';
303 else {
304 al->level = 'H';
305 al->map = NULL;
306 al->sym = NULL;
307 return;
308 }
309try_again:
310 al->map = map_groups__find(mg, type, al->addr);
311 if (al->map == NULL) {
312 /*
313 * If this is outside of all known maps, and is a negative
314 * address, try to look it up in the kernel dso, as it might be
315 * a vsyscall or vdso (which executes in user-mode).
316 *
317 * XXX This is nasty, we should have a symbol list in the
318 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list.
320 */
321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
322 mg = &session->kmaps;
323 goto try_again;
324 }
325 al->sym = NULL;
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
329 }
330}
331
332static void dso__calc_col_width(struct dso *self)
333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
347{
348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
350
351 if (thread == NULL)
352 return -1;
353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
359
360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
361 self->ip.ip, al, filter);
362 dump_printf(" ...... dso: %s\n",
363 al->map ? al->map->dso->long_name :
364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
388 return 0;
389}
390
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
392{
393 u64 *array = event->sample.array;
394
395 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip;
397 array++;
398 }
399
400 if (type & PERF_SAMPLE_TID) {
401 u32 *p = (u32 *)array;
402 data->pid = p[0];
403 data->tid = p[1];
404 array++;
405 }
406
407 if (type & PERF_SAMPLE_TIME) {
408 data->time = *array;
409 array++;
410 }
411
412 if (type & PERF_SAMPLE_ADDR) {
413 data->addr = *array;
414 array++;
415 }
416
417 if (type & PERF_SAMPLE_ID) {
418 data->id = *array;
419 array++;
420 }
421
422 if (type & PERF_SAMPLE_STREAM_ID) {
423 data->stream_id = *array;
424 array++;
425 }
426
427 if (type & PERF_SAMPLE_CPU) {
428 u32 *p = (u32 *)array;
429 data->cpu = *p;
430 array++;
431 }
432
433 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array;
435 array++;
436 }
437
438 if (type & PERF_SAMPLE_READ) {
439 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
440 return -1;
441 }
442
443 if (type & PERF_SAMPLE_CALLCHAIN) {
444 data->callchain = (struct ip_callchain *)array;
445 array += 1 + data->callchain->nr;
446 }
447
448 if (type & PERF_SAMPLE_RAW) {
449 u32 *p = (u32 *)array;
450 data->raw_size = *p;
451 p++;
452 data->raw_data = p;
453 }
454
455 return 0;
456}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 2c9c26d6ded0..690a96d0467c 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 u64 total;
99 u64 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,57 @@ 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);
103 152
104#endif 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event,
170 struct perf_session *session),
171 struct perf_session *session);
172
173int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session);
175int event__process_mmap(event_t *self, struct perf_session *session);
176int event__process_task(event_t *self, struct perf_session *session);
177
178struct addr_location;
179int event__preprocess_sample(const event_t *self, struct perf_session *session,
180 struct addr_location *al, symbol_filter_t filter);
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
182
183#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..8a0bca55106f 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 "session.h"
12#include "symbol.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..e8daf5ca6fd2
--- /dev/null
+++ b/tools/perf/util/hist.c
@@ -0,0 +1,662 @@
1#include "hist.h"
2#include "session.h"
3#include "sort.h"
4#include <math.h>
5
6struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5
9};
10
11/*
12 * histogram, sorted on item, collects counts
13 */
14
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
16 struct addr_location *al,
17 struct symbol *sym_parent,
18 u64 count, bool *hit)
19{
20 struct rb_node **p = &self->hists.rb_node;
21 struct rb_node *parent = NULL;
22 struct hist_entry *he;
23 struct hist_entry entry = {
24 .thread = al->thread,
25 .map = al->map,
26 .sym = al->sym,
27 .ip = al->addr,
28 .level = al->level,
29 .count = count,
30 .parent = sym_parent,
31 };
32 int cmp;
33
34 while (*p != NULL) {
35 parent = *p;
36 he = rb_entry(parent, struct hist_entry, rb_node);
37
38 cmp = hist_entry__cmp(&entry, he);
39
40 if (!cmp) {
41 *hit = true;
42 return he;
43 }
44
45 if (cmp < 0)
46 p = &(*p)->rb_left;
47 else
48 p = &(*p)->rb_right;
49 }
50
51 he = malloc(sizeof(*he));
52 if (!he)
53 return NULL;
54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, &self->hists);
57 *hit = false;
58 return he;
59}
60
61int64_t
62hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
63{
64 struct sort_entry *se;
65 int64_t cmp = 0;
66
67 list_for_each_entry(se, &hist_entry__sort_list, list) {
68 cmp = se->cmp(left, right);
69 if (cmp)
70 break;
71 }
72
73 return cmp;
74}
75
76int64_t
77hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
78{
79 struct sort_entry *se;
80 int64_t cmp = 0;
81
82 list_for_each_entry(se, &hist_entry__sort_list, list) {
83 int64_t (*f)(struct hist_entry *, struct hist_entry *);
84
85 f = se->collapse ?: se->cmp;
86
87 cmp = f(left, right);
88 if (cmp)
89 break;
90 }
91
92 return cmp;
93}
94
95void hist_entry__free(struct hist_entry *he)
96{
97 free(he);
98}
99
100/*
101 * collapse the histogram
102 */
103
104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
105{
106 struct rb_node **p = &root->rb_node;
107 struct rb_node *parent = NULL;
108 struct hist_entry *iter;
109 int64_t cmp;
110
111 while (*p != NULL) {
112 parent = *p;
113 iter = rb_entry(parent, struct hist_entry, rb_node);
114
115 cmp = hist_entry__collapse(iter, he);
116
117 if (!cmp) {
118 iter->count += he->count;
119 hist_entry__free(he);
120 return;
121 }
122
123 if (cmp < 0)
124 p = &(*p)->rb_left;
125 else
126 p = &(*p)->rb_right;
127 }
128
129 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root);
131}
132
133void perf_session__collapse_resort(struct perf_session *self)
134{
135 struct rb_root tmp;
136 struct rb_node *next;
137 struct hist_entry *n;
138
139 if (!sort__need_collapse)
140 return;
141
142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
145 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node);
148
149 rb_erase(&n->rb_node, &self->hists);
150 collapse__insert_entry(&tmp, n);
151 }
152
153 self->hists = tmp;
154}
155
156/*
157 * reverse the map, sort on count.
158 */
159
160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
163{
164 struct rb_node **p = &root->rb_node;
165 struct rb_node *parent = NULL;
166 struct hist_entry *iter;
167
168 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain,
170 min_callchain_hits, &callchain_param);
171
172 while (*p != NULL) {
173 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node);
175
176 if (he->count > iter->count)
177 p = &(*p)->rb_left;
178 else
179 p = &(*p)->rb_right;
180 }
181
182 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root);
184}
185
186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
187{
188 struct rb_root tmp;
189 struct rb_node *next;
190 struct hist_entry *n;
191 u64 min_callchain_hits;
192
193 min_callchain_hits =
194 total_samples * (callchain_param.min_percent / 100);
195
196 tmp = RB_ROOT;
197 next = rb_first(&self->hists);
198
199 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node);
202
203 rb_erase(&n->rb_node, &self->hists);
204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line seperator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session->events_stats.total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
new file mode 100644
index 000000000000..e5f99b24048b
--- /dev/null
+++ b/tools/perf/util/hist.h
@@ -0,0 +1,27 @@
1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H
3
4#include <linux/types.h>
5#include "callchain.h"
6
7extern struct callchain_param callchain_param;
8
9struct perf_session;
10struct hist_entry;
11struct addr_location;
12struct symbol;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
20void hist_entry__free(struct hist_entry *);
21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/asm/asm-offsets.h b/tools/perf/util/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/asm-offsets.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
new file mode 100644
index 000000000000..58e9817ffae0
--- /dev/null
+++ b/tools/perf/util/include/asm/bitops.h
@@ -0,0 +1,18 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/bug.h b/tools/perf/util/include/asm/bug.h
new file mode 100644
index 000000000000..7fcc6810adc2
--- /dev/null
+++ b/tools/perf/util/include/asm/bug.h
@@ -0,0 +1,22 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H
3
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5
6#define WARN(condition, format...) ({ \
7 int __ret_warn_on = !!(condition); \
8 if (unlikely(__ret_warn_on)) \
9 __WARN_printf(format); \
10 unlikely(__ret_warn_on); \
11})
12
13#define WARN_ONCE(condition, format...) ({ \
14 static int __warned; \
15 int __ret_warn_once = !!(condition); \
16 \
17 if (unlikely(__ret_warn_once)) \
18 if (WARN(!__warned, format)) \
19 __warned = 1; \
20 unlikely(__ret_warn_once); \
21})
22#endif
diff --git a/tools/perf/util/include/asm/byteorder.h b/tools/perf/util/include/asm/byteorder.h
new file mode 100644
index 000000000000..b722abe3a626
--- /dev/null
+++ b/tools/perf/util/include/asm/byteorder.h
@@ -0,0 +1,2 @@
1#include <asm/types.h>
2#include "../../../../include/linux/swab.h"
diff --git a/tools/perf/util/include/asm/swab.h b/tools/perf/util/include/asm/swab.h
new file mode 100644
index 000000000000..ed538942523d
--- /dev/null
+++ b/tools/perf/util/include/asm/swab.h
@@ -0,0 +1 @@
/* stub */
diff --git a/tools/perf/util/include/asm/uaccess.h b/tools/perf/util/include/asm/uaccess.h
new file mode 100644
index 000000000000..d0f72b8fcc35
--- /dev/null
+++ b/tools/perf/util/include/asm/uaccess.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_ASM_UACCESS_H_
2#define _PERF_ASM_UACCESS_H_
3
4#define __get_user(src, dest) \
5({ \
6 (src) = *dest; \
7 0; \
8})
9
10#define get_user __get_user
11
12#define access_ok(type, addr, size) 1
13
14#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
new file mode 100644
index 000000000000..94507639a8c4
--- /dev/null
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -0,0 +1,3 @@
1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
new file mode 100644
index 000000000000..8d63116e9435
--- /dev/null
+++ b/tools/perf/util/include/linux/bitops.h
@@ -0,0 +1,29 @@
1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_
3
4#define __KERNEL__
5
6#define CONFIG_GENERIC_FIND_NEXT_BIT
7#define CONFIG_GENERIC_FIND_FIRST_BIT
8#include "../../../../include/linux/bitops.h"
9
10#undef __KERNEL__
11
12static inline void set_bit(int nr, unsigned long *addr)
13{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15}
16
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{
19 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21}
22
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned
24 long size, unsigned long offset);
25
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned
27 long size, unsigned long offset);
28
29#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
new file mode 100644
index 000000000000..dfb0713ed47f
--- /dev/null
+++ b/tools/perf/util/include/linux/compiler.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_
3
4#ifndef __always_inline
5#define __always_inline inline
6#endif
7#define __user
8#define __attribute_const__
9
10#endif
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
new file mode 100644
index 000000000000..a53d4ee1e0b7
--- /dev/null
+++ b/tools/perf/util/include/linux/ctype.h
@@ -0,0 +1 @@
#include "../util.h"
diff --git a/tools/perf/util/include/linux/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..c4d55a0da2ea 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,99 @@ 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
107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter)
109{
110 const char *name = self->dso->long_name;
111 int nr;
112
113 if (dso__loaded(self->dso, self->type))
114 return 0;
115
116 nr = dso__load(self->dso, self, session, filter);
117 if (nr < 0) {
118 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
120
121 build_id__sprintf(self->dso->build_id,
122 sizeof(self->dso->build_id),
123 sbuild_id);
124 pr_warning("%s with build id %s not found",
125 name, sbuild_id);
126 } else
127 pr_warning("Failed to open %s", name);
128
129 pr_warning(", continuing without symbols\n");
130 return -1;
131 } else if (nr == 0) {
132 const size_t len = strlen(name);
133 const size_t real_len = len - sizeof(DSO__DELETED);
134
135 if (len > sizeof(DSO__DELETED) &&
136 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
137 pr_warning("%.*s was updated, restart the long "
138 "running apps that use it!\n",
139 (int)real_len, name);
140 } else {
141 pr_warning("no symbols found in %s, maybe install "
142 "a debug package?\n", name);
143 }
144
145 return -1;
146 }
147
148 return 0;
149}
150
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
152 u64 addr, symbol_filter_t filter)
153{
154 if (map__load(self, session, filter) < 0)
155 return NULL;
156
157 return dso__find_symbol(self->dso, self->type, addr);
158}
159
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter)
163{
164 if (map__load(self, session, filter) < 0)
165 return NULL;
166
167 if (!dso__sorted_by_name(self->dso, self->type))
168 dso__sort_by_name(self->dso, self->type);
169
170 return dso__find_symbol_by_name(self->dso, self->type, name);
171}
172
67struct map *map__clone(struct map *self) 173struct map *map__clone(struct map *self)
68{ 174{
69 struct map *map = malloc(sizeof(*self)); 175 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..29465d440043
--- /dev/null
+++ b/tools/perf/util/probe-event.c
@@ -0,0 +1,677 @@
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/* Check the name is good for event/group */
66static bool check_event_name(const char *name)
67{
68 if (!isalpha(*name) && *name != '_')
69 return false;
70 while (*++name != '\0') {
71 if (!isalpha(*name) && !isdigit(*name) && *name != '_')
72 return false;
73 }
74 return true;
75}
76
77/* Parse probepoint definition. */
78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
79{
80 char *ptr, *tmp;
81 char c, nc = 0;
82 /*
83 * <Syntax>
84 * perf probe [EVENT=]SRC:LN
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
86 *
87 * TODO:Group name support
88 */
89
90 ptr = strchr(arg, '=');
91 if (ptr) { /* Event name */
92 *ptr = '\0';
93 tmp = ptr + 1;
94 ptr = strchr(arg, ':');
95 if (ptr) /* Group name is not supported yet. */
96 semantic_error("Group name is not supported yet.");
97 if (!check_event_name(arg))
98 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg);
100 pp->event = strdup(arg);
101 arg = tmp;
102 }
103
104 ptr = strpbrk(arg, ":+@%");
105 if (ptr) {
106 nc = *ptr;
107 *ptr++ = '\0';
108 }
109
110 /* Check arg is function or file and copy it */
111 if (strchr(arg, '.')) /* File */
112 pp->file = strdup(arg);
113 else /* Function */
114 pp->function = strdup(arg);
115 DIE_IF(pp->file == NULL && pp->function == NULL);
116
117 /* Parse other options */
118 while (ptr) {
119 arg = ptr;
120 c = nc;
121 ptr = strpbrk(arg, ":+@%");
122 if (ptr) {
123 nc = *ptr;
124 *ptr++ = '\0';
125 }
126 switch (c) {
127 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0')
130 semantic_error("There is non-digit charactor"
131 " in line number.");
132 break;
133 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0')
136 semantic_error("There is non-digit charactor"
137 " in offset.");
138 break;
139 case '@': /* File name */
140 if (pp->file)
141 semantic_error("SRC@SRC is not allowed.");
142 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL);
144 if (ptr)
145 semantic_error("@SRC must be the last "
146 "option.");
147 break;
148 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) {
150 pp->retprobe = 1;
151 } else /* Others not supported yet */
152 semantic_error("%%%s is not supported.", arg);
153 break;
154 default:
155 DIE_IF("Program has a bug.");
156 break;
157 }
158 }
159
160 /* Exclusion check */
161 if (pp->line && pp->offset)
162 semantic_error("Offset can't be used with line number.");
163
164 if (!pp->line && pp->file && !pp->function)
165 semantic_error("File always requires line number.");
166
167 if (pp->offset && !pp->function)
168 semantic_error("Offset requires an entry function.");
169
170 if (pp->retprobe && !pp->function)
171 semantic_error("Return probe requires an entry function.");
172
173 if ((pp->offset || pp->line) && pp->retprobe)
174 semantic_error("Offset/Line can't be used with return probe.");
175
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
178}
179
180/* Parse perf-probe event definition */
181void parse_perf_probe_event(const char *str, struct probe_point *pp,
182 bool *need_dwarf)
183{
184 char **argv;
185 int argc, i;
186
187 *need_dwarf = false;
188
189 argv = argv_split(str, &argc);
190 if (!argv)
191 die("argv_split failed.");
192 if (argc > MAX_PROBE_ARGS + 1)
193 semantic_error("Too many arguments");
194
195 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp);
197 if (pp->file || pp->line)
198 *need_dwarf = true;
199
200 /* Copy arguments and ensure return probe has no C argument */
201 pp->nr_args = argc - 1;
202 pp->args = zalloc(sizeof(char *) * pp->nr_args);
203 for (i = 0; i < pp->nr_args; i++) {
204 pp->args[i] = strdup(argv[i + 1]);
205 if (!pp->args[i])
206 die("Failed to copy argument.");
207 if (is_c_varname(pp->args[i])) {
208 if (pp->retprobe)
209 semantic_error("You can't specify local"
210 " variable for kretprobe");
211 *need_dwarf = true;
212 }
213 }
214
215 argv_free(argv);
216}
217
218/* Parse kprobe_events event into struct probe_point */
219void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
220{
221 char pr;
222 char *p;
223 int ret, i, argc;
224 char **argv;
225
226 pr_debug("Parsing kprobe_events: %s\n", str);
227 argv = argv_split(str, &argc);
228 if (!argv)
229 die("argv_split failed.");
230 if (argc < 2)
231 semantic_error("Too less arguments.");
232
233 /* Scan event and group name. */
234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
235 &pr, (float *)(void *)&pp->group,
236 (float *)(void *)&pp->event);
237 if (ret != 3)
238 semantic_error("Failed to parse event name: %s", argv[0]);
239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
240
241 pp->retprobe = (pr == 'r');
242
243 /* Scan function name and offset */
244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
245 &pp->offset);
246 if (ret == 1)
247 pp->offset = 0;
248
249 /* kprobe_events doesn't have this information */
250 pp->line = 0;
251 pp->file = NULL;
252
253 pp->nr_args = argc - 2;
254 pp->args = zalloc(sizeof(char *) * pp->nr_args);
255 for (i = 0; i < pp->nr_args; i++) {
256 p = strchr(argv[i + 2], '=');
257 if (p) /* We don't need which register is assigned. */
258 *p = '\0';
259 pp->args[i] = strdup(argv[i + 2]);
260 if (!pp->args[i])
261 die("Failed to copy argument.");
262 }
263
264 argv_free(argv);
265}
266
267/* Synthesize only probe point (not argument) */
268int synthesize_perf_probe_point(struct probe_point *pp)
269{
270 char *buf;
271 char offs[64] = "", line[64] = "";
272 int ret;
273
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
275 if (!buf)
276 die("Failed to allocate memory by zalloc.");
277 if (pp->offset) {
278 ret = e_snprintf(offs, 64, "+%d", pp->offset);
279 if (ret <= 0)
280 goto error;
281 }
282 if (pp->line) {
283 ret = e_snprintf(line, 64, ":%d", pp->line);
284 if (ret <= 0)
285 goto error;
286 }
287
288 if (pp->function)
289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
290 offs, pp->retprobe ? "%return" : "", line);
291 else
292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
293 if (ret <= 0) {
294error:
295 free(pp->probes[0]);
296 pp->probes[0] = NULL;
297 }
298 return ret;
299}
300
301int synthesize_perf_probe_event(struct probe_point *pp)
302{
303 char *buf;
304 int i, len, ret;
305
306 len = synthesize_perf_probe_point(pp);
307 if (len < 0)
308 return 0;
309
310 buf = pp->probes[0];
311 for (i = 0; i < pp->nr_args; i++) {
312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
313 pp->args[i]);
314 if (ret <= 0)
315 goto error;
316 len += ret;
317 }
318 pp->found = 1;
319
320 return pp->found;
321error:
322 free(pp->probes[0]);
323 pp->probes[0] = NULL;
324
325 return ret;
326}
327
328int synthesize_trace_kprobe_event(struct probe_point *pp)
329{
330 char *buf;
331 int i, len, ret;
332
333 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
334 if (!buf)
335 die("Failed to allocate memory by zalloc.");
336 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
337 if (ret <= 0)
338 goto error;
339 len = ret;
340
341 for (i = 0; i < pp->nr_args; i++) {
342 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
343 pp->args[i]);
344 if (ret <= 0)
345 goto error;
346 len += ret;
347 }
348 pp->found = 1;
349
350 return pp->found;
351error:
352 free(pp->probes[0]);
353 pp->probes[0] = NULL;
354
355 return ret;
356}
357
358static int open_kprobe_events(int flags, int mode)
359{
360 char buf[PATH_MAX];
361 int ret;
362
363 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
364 if (ret < 0)
365 die("Failed to make kprobe_events path.");
366
367 ret = open(buf, flags, mode);
368 if (ret < 0) {
369 if (errno == ENOENT)
370 die("kprobe_events file does not exist -"
371 " please rebuild with CONFIG_KPROBE_TRACER.");
372 else
373 die("Could not open kprobe_events file: %s",
374 strerror(errno));
375 }
376 return ret;
377}
378
379/* Get raw string list of current kprobe_events */
380static struct strlist *get_trace_kprobe_event_rawlist(int fd)
381{
382 int ret, idx;
383 FILE *fp;
384 char buf[MAX_CMDLEN];
385 char *p;
386 struct strlist *sl;
387
388 sl = strlist__new(true, NULL);
389
390 fp = fdopen(dup(fd), "r");
391 while (!feof(fp)) {
392 p = fgets(buf, MAX_CMDLEN, fp);
393 if (!p)
394 break;
395
396 idx = strlen(p) - 1;
397 if (p[idx] == '\n')
398 p[idx] = '\0';
399 ret = strlist__add(sl, buf);
400 if (ret < 0)
401 die("strlist__add failed: %s", strerror(-ret));
402 }
403 fclose(fp);
404
405 return sl;
406}
407
408/* Free and zero clear probe_point */
409static void clear_probe_point(struct probe_point *pp)
410{
411 int i;
412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
417 if (pp->function)
418 free(pp->function);
419 if (pp->file)
420 free(pp->file);
421 for (i = 0; i < pp->nr_args; i++)
422 free(pp->args[i]);
423 if (pp->args)
424 free(pp->args);
425 for (i = 0; i < pp->found; i++)
426 free(pp->probes[i]);
427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place,
432 struct probe_point *pp)
433{
434 int i, ret;
435 char buf[128];
436
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
438 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret));
440 printf(" %-40s (on %s", buf, place);
441
442 if (pp->nr_args > 0) {
443 printf(" with");
444 for (i = 0; i < pp->nr_args; i++)
445 printf(" %s", pp->args[i]);
446 }
447 printf(")\n");
448}
449
450/* List up current perf-probe events */
451void show_perf_probe_events(void)
452{
453 int fd;
454 struct probe_point pp;
455 struct strlist *rawlist;
456 struct str_node *ent;
457
458 fd = open_kprobe_events(O_RDONLY, 0);
459 rawlist = get_trace_kprobe_event_rawlist(fd);
460 close(fd);
461
462 strlist__for_each(ent, rawlist) {
463 parse_trace_kprobe_event(ent->s, &pp);
464 /* Synthesize only event probe point */
465 synthesize_perf_probe_point(&pp);
466 /* Show an event */
467 show_perf_probe_event(pp.event, pp.probes[0], &pp);
468 clear_probe_point(&pp);
469 }
470
471 strlist__delete(rawlist);
472}
473
474/* Get current perf-probe event names */
475static struct strlist *get_perf_event_names(int fd, bool include_group)
476{
477 char buf[128];
478 struct strlist *sl, *rawlist;
479 struct str_node *ent;
480 struct probe_point pp;
481
482 memset(&pp, 0, sizeof(pp));
483 rawlist = get_trace_kprobe_event_rawlist(fd);
484
485 sl = strlist__new(true, NULL);
486 strlist__for_each(ent, rawlist) {
487 parse_trace_kprobe_event(ent->s, &pp);
488 if (include_group) {
489 if (e_snprintf(buf, 128, "%s:%s", pp.group,
490 pp.event) < 0)
491 die("Failed to copy group:event name.");
492 strlist__add(sl, buf);
493 } else
494 strlist__add(sl, pp.event);
495 clear_probe_point(&pp);
496 }
497
498 strlist__delete(rawlist);
499
500 return sl;
501}
502
503static void write_trace_kprobe_event(int fd, const char *buf)
504{
505 int ret;
506
507 pr_debug("Writing event: %s\n", buf);
508 ret = write(fd, buf, strlen(buf));
509 if (ret <= 0)
510 die("Failed to write event: %s", strerror(errno));
511}
512
513static void get_new_event_name(char *buf, size_t len, const char *base,
514 struct strlist *namelist, bool allow_suffix)
515{
516 int i, ret;
517
518 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0)
521 die("snprintf() failed: %s", strerror(-ret));
522 if (!strlist__has_entry(namelist, buf))
523 return;
524
525 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event.");
529 }
530
531 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) {
533 ret = e_snprintf(buf, len, "%s_%d", base, i);
534 if (ret < 0)
535 die("snprintf() failed: %s", strerror(-ret));
536 if (!strlist__has_entry(namelist, buf))
537 break;
538 }
539 if (i == MAX_EVENT_INDEX)
540 die("Too many events are on the same function.");
541}
542
543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
544 bool force_add)
545{
546 int i, j, fd;
547 struct probe_point *pp;
548 char buf[MAX_CMDLEN];
549 char event[64];
550 struct strlist *namelist;
551 bool allow_suffix;
552
553 fd = open_kprobe_events(O_RDWR, O_APPEND);
554 /* Get current event names */
555 namelist = get_perf_event_names(fd, false);
556
557 for (j = 0; j < nr_probes; j++) {
558 pp = probes + j;
559 if (!pp->event)
560 pp->event = strdup(pp->function);
561 if (!pp->group)
562 pp->group = strdup(PERFPROBE_GROUP);
563 DIE_IF(!pp->event || !pp->group);
564 /* If force_add is true, suffix search is allowed */
565 allow_suffix = force_add;
566 for (i = 0; i < pp->found; i++) {
567 /* Get an unused new event name */
568 get_new_event_name(event, 64, pp->event, namelist,
569 allow_suffix);
570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
571 pp->retprobe ? 'r' : 'p',
572 pp->group, event,
573 pp->probes[i]);
574 write_trace_kprobe_event(fd, buf);
575 printf("Added new event:\n");
576 /* Get the first parameter (probe-point) */
577 sscanf(pp->probes[i], "%s", buf);
578 show_perf_probe_event(event, buf, pp);
579 /* Add added event name to namelist */
580 strlist__add(namelist, event);
581 /*
582 * Probes after the first probe which comes from same
583 * user input are always allowed to add suffix, because
584 * there might be several addresses corresponding to
585 * one code line.
586 */
587 allow_suffix = true;
588 }
589 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593
594 strlist__delete(namelist);
595 close(fd);
596}
597
598static void __del_trace_kprobe_event(int fd, struct str_node *ent)
599{
600 char *p;
601 char buf[128];
602
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':');
607 if (!p)
608 die("Internal error: %s should have ':' but not.", ent->s);
609 *p = '/';
610
611 write_trace_kprobe_event(fd, buf);
612 printf("Remove event: %s\n", ent->s);
613}
614
615static void del_trace_kprobe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist)
617{
618 char buf[128];
619 struct str_node *ent, *n;
620 int found = 0;
621
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
623 die("Failed to copy event.");
624
625 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) {
628 found++;
629 __del_trace_kprobe_event(fd, ent);
630 strlist__remove(namelist, ent);
631 }
632 } else {
633 ent = strlist__find(namelist, buf);
634 if (ent) {
635 found++;
636 __del_trace_kprobe_event(fd, ent);
637 strlist__remove(namelist, ent);
638 }
639 }
640 if (found == 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
642}
643
644void del_trace_kprobe_events(struct strlist *dellist)
645{
646 int fd;
647 const char *group, *event;
648 char *p, *str;
649 struct str_node *ent;
650 struct strlist *namelist;
651
652 fd = open_kprobe_events(O_RDWR, O_APPEND);
653 /* Get current event names */
654 namelist = get_perf_event_names(fd, true);
655
656 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s);
658 if (!str)
659 die("Failed to copy event.");
660 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':');
662 if (p) {
663 group = str;
664 *p = '\0';
665 event = p + 1;
666 } else {
667 group = "*";
668 event = str;
669 }
670 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist);
672 free(str);
673 }
674 strlist__delete(namelist);
675 close(fd);
676}
677
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
new file mode 100644
index 000000000000..7f1d499118c0
--- /dev/null
+++ b/tools/perf/util/probe-event.h
@@ -0,0 +1,22 @@
1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H
3
4#include <stdbool.h>
5#include "probe-finder.h"
6#include "strlist.h"
7
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
11extern int synthesize_perf_probe_event(struct probe_point *pp);
12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void);
18
19/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024
21
22#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..4b852c0d16a5
--- /dev/null
+++ b/tools/perf/util/probe-finder.c
@@ -0,0 +1,730 @@
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 return -ENOENT;
692
693 pp->found = 0;
694 while (++cu_number) {
695 /* Search CU (Compilation Unit) */
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
697 &addr_size, &next_cuh, &__dw_error);
698 DIE_IF(ret == DW_DLV_ERROR);
699 if (ret == DW_DLV_NO_ENTRY)
700 break;
701
702 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
704 DIE_IF(ret != DW_DLV_OK);
705
706 /* Check if target file is included. */
707 if (pp->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file);
709
710 if (!pp->file || pf.fno) {
711 /* Save CU base address (for frame_base) */
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
713 DIE_IF(ret == DW_DLV_ERROR);
714 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0;
716 if (pp->function)
717 find_by_func(&pf);
718 else {
719 pf.lno = pp->line;
720 find_by_line(&pf);
721 }
722 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
724 }
725 ret = dwarf_finish(__dw_debug, &__dw_error);
726 DIE_IF(ret != DW_DLV_OK);
727
728 return pp->found;
729}
730
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
new file mode 100644
index 000000000000..a4086aaddb73
--- /dev/null
+++ b/tools/perf/util/probe-finder.h
@@ -0,0 +1,65 @@
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 char *event; /* Event name */
16 char *group; /* Event group */
17
18 /* Inputs */
19 char *file; /* File name */
20 int line; /* Line number */
21
22 char *function; /* Function name */
23 int offset; /* Offset bytes */
24
25 int nr_args; /* Number of arguments */
26 char **args; /* Arguments */
27
28 int retprobe; /* Return probe */
29
30 /* Output */
31 int found; /* Number of found probe points */
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33};
34
35#ifndef NO_LIBDWARF
36extern int find_probepoint(int fd, struct probe_point *pp);
37
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42
43#include <dwarf.h>
44#include <libdwarf.h>
45
46struct probe_finder {
47 struct probe_point *pp; /* Target probe point */
48
49 /* For function searching */
50 Dwarf_Addr addr; /* Address */
51 Dwarf_Unsigned fno; /* File number */
52 Dwarf_Unsigned lno; /* Line number */
53 Dwarf_Off inl_offs; /* Inline offset */
54 Dwarf_Die cu_die; /* Current CU */
55
56 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */
59 const char *var; /* Current variable name */
60 char *buf; /* Current output buffer */
61 int len; /* Length of output buffer */
62};
63#endif /* NO_LIBDWARF */
64
65#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..ce3a6c8abe76
--- /dev/null
+++ b/tools/perf/util/session.c
@@ -0,0 +1,150 @@
1#include <linux/kernel.h>
2
3#include <unistd.h>
4#include <sys/types.h>
5
6#include "session.h"
7#include "sort.h"
8#include "util.h"
9
10static int perf_session__open(struct perf_session *self, bool force)
11{
12 struct stat input_stat;
13
14 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename);
17 if (!strcmp(self->filename, "perf.data"))
18 pr_err(" (try 'perf record' first)");
19 pr_err("\n");
20 return -errno;
21 }
22
23 if (fstat(self->fd, &input_stat) < 0)
24 goto out_close;
25
26 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
27 pr_err("file %s not owned by current user or root\n",
28 self->filename);
29 goto out_close;
30 }
31
32 if (!input_stat.st_size) {
33 pr_info("zero-sized file (%s), nothing to do!\n",
34 self->filename);
35 goto out_close;
36 }
37
38 if (perf_header__read(&self->header, self->fd) < 0) {
39 pr_err("incompatible file format");
40 goto out_close;
41 }
42
43 self->size = input_stat.st_size;
44 return 0;
45
46out_close:
47 close(self->fd);
48 self->fd = -1;
49 return -1;
50}
51
52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
53{
54 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len);
56
57 if (self == NULL)
58 goto out;
59
60 if (perf_header__init(&self->header) < 0)
61 goto out_free;
62
63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
73
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
75 goto out_delete;
76out:
77 return self;
78out_free:
79 free(self);
80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
84}
85
86void perf_session__delete(struct perf_session *self)
87{
88 perf_header__exit(&self->header);
89 close(self->fd);
90 free(self->cwd);
91 free(self);
92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
new file mode 100644
index 000000000000..32eaa1bada06
--- /dev/null
+++ b/tools/perf/util/session.h
@@ -0,0 +1,61 @@
1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H
3
4#include "event.h"
5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
13
14struct perf_session {
15 struct perf_header header;
16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
25 int fd;
26 int cwdlen;
27 char *cwd;
28 char filename[0];
29};
30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
49void perf_session__delete(struct perf_session *self);
50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
61#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 618083bce0c6..1a53c11265fd 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -1,5 +1,5 @@
1#ifndef SIGCHAIN_H 1#ifndef __PERF_SIGCHAIN_H
2#define SIGCHAIN_H 2#define __PERF_SIGCHAIN_H
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
@@ -8,4 +8,4 @@ int sigchain_pop(int sig);
8 8
9void sigchain_push_common(sigchain_fun f); 9void sigchain_push_common(sigchain_fun f);
10 10
11#endif /* SIGCHAIN_H */ 11#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
new file mode 100644
index 000000000000..cb0f327de9e8
--- /dev/null
+++ b/tools/perf/util/sort.c
@@ -0,0 +1,316 @@
1#include "sort.h"
2
3regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order;
8int sort__need_collapse = 0;
9int sort__has_parent = 0;
10
11enum sort_type sort__first_dimension;
12
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep;
18
19LIST_HEAD(hist_entry__sort_list);
20
21struct sort_entry sort_thread = {
22 .header = "Command: Pid",
23 .cmp = sort__thread_cmp,
24 .print = sort__thread_print,
25 .width = &threads__col_width,
26};
27
28struct sort_entry sort_comm = {
29 .header = "Command",
30 .cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse,
32 .print = sort__comm_print,
33 .width = &comms__col_width,
34};
35
36struct sort_entry sort_dso = {
37 .header = "Shared Object",
38 .cmp = sort__dso_cmp,
39 .print = sort__dso_print,
40 .width = &dsos__col_width,
41};
42
43struct sort_entry sort_sym = {
44 .header = "Symbol",
45 .cmp = sort__sym_cmp,
46 .print = sort__sym_print,
47};
48
49struct sort_entry sort_parent = {
50 .header = "Parent symbol",
51 .cmp = sort__parent_cmp,
52 .print = sort__parent_print,
53 .width = &parent_symbol__col_width,
54};
55
56struct sort_dimension {
57 const char *name;
58 struct sort_entry *entry;
59 int taken;
60};
61
62static struct sort_dimension sort_dimensions[] = {
63 { .name = "pid", .entry = &sort_thread, },
64 { .name = "comm", .entry = &sort_comm, },
65 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, },
68};
69
70int64_t cmp_null(void *l, void *r)
71{
72 if (!l && !r)
73 return 0;
74 else if (!l)
75 return -1;
76 else
77 return 1;
78}
79
80/* --sort pid */
81
82int64_t
83sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
84{
85 return right->thread->pid - left->thread->pid;
86}
87
88int repsep_fprintf(FILE *fp, const char *fmt, ...)
89{
90 int n;
91 va_list ap;
92
93 va_start(ap, fmt);
94 if (!field_sep)
95 n = vfprintf(fp, fmt, ap);
96 else {
97 char *bf = NULL;
98 n = vasprintf(&bf, fmt, ap);
99 if (n > 0) {
100 char *sep = bf;
101
102 while (1) {
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 }
109 fputs(bf, fp);
110 free(bf);
111 }
112 va_end(ap);
113 return n;
114}
115
116size_t
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
118{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6,
120 self->thread->comm ?: "", self->thread->pid);
121}
122
123size_t
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
125{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
127}
128
129/* --sort dso */
130
131int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{
134 struct dso *dso_l = left->map ? left->map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL;
136 const char *dso_name_l, *dso_name_r;
137
138 if (!dso_l || !dso_r)
139 return cmp_null(dso_l, dso_r);
140
141 if (verbose) {
142 dso_name_l = dso_l->long_name;
143 dso_name_r = dso_r->long_name;
144 } else {
145 dso_name_l = dso_l->short_name;
146 dso_name_r = dso_r->short_name;
147 }
148
149 return strcmp(dso_name_l, dso_name_r);
150}
151
152size_t
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
154{
155 if (self->map && self->map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name :
157 self->map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name);
159 }
160
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
162}
163
164/* --sort symbol */
165
166int64_t
167sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{
169 u64 ip_l, ip_r;
170
171 if (left->sym == right->sym)
172 return 0;
173
174 ip_l = left->sym ? left->sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip;
176
177 return (int64_t)(ip_r - ip_l);
178}
179
180
181size_t
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{
184 size_t ret = 0;
185
186 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
189 }
190
191 ret += repsep_fprintf(fp, "[%c] ", self->level);
192 if (self->sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name);
194 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
196
197 return ret;
198}
199
200/* --sort comm */
201
202int64_t
203sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
204{
205 return right->thread->pid - left->thread->pid;
206}
207
208int64_t
209sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
210{
211 char *comm_l = left->thread->comm;
212 char *comm_r = right->thread->comm;
213
214 if (!comm_l || !comm_r)
215 return cmp_null(comm_l, comm_r);
216
217 return strcmp(comm_l, comm_r);
218}
219
220/* --sort parent */
221
222int64_t
223sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
224{
225 struct symbol *sym_l = left->parent;
226 struct symbol *sym_r = right->parent;
227
228 if (!sym_l || !sym_r)
229 return cmp_null(sym_l, sym_r);
230
231 return strcmp(sym_l->name, sym_r->name);
232}
233
234size_t
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
236{
237 return repsep_fprintf(fp, "%-*s", width,
238 self->parent ? self->parent->name : "[other]");
239}
240
241int sort_dimension__add(const char *tok)
242{
243 unsigned int i;
244
245 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
246 struct sort_dimension *sd = &sort_dimensions[i];
247
248 if (sd->taken)
249 continue;
250
251 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue;
253
254 if (sd->entry->collapse)
255 sort__need_collapse = 1;
256
257 if (sd->entry == &sort_parent) {
258 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
259 if (ret) {
260 char err[BUFSIZ];
261
262 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s",
264 parent_pattern, err);
265 exit(-1);
266 }
267 sort__has_parent = 1;
268 }
269
270 if (list_empty(&hist_entry__sort_list)) {
271 if (!strcmp(sd->name, "pid"))
272 sort__first_dimension = SORT_PID;
273 else if (!strcmp(sd->name, "comm"))
274 sort__first_dimension = SORT_COMM;
275 else if (!strcmp(sd->name, "dso"))
276 sort__first_dimension = SORT_DSO;
277 else if (!strcmp(sd->name, "symbol"))
278 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT;
281 }
282
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
284 sd->taken = 1;
285
286 return 0;
287 }
288
289 return -ESRCH;
290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
new file mode 100644
index 000000000000..753f9ea99fb0
--- /dev/null
+++ b/tools/perf/util/sort.h
@@ -0,0 +1,107 @@
1#ifndef __PERF_SORT_H
2#define __PERF_SORT_H
3#include "../builtin.h"
4
5#include "util.h"
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23
24#include "thread.h"
25#include "sort.h"
26
27extern regex_t parent_regex;
28extern char *sort_order;
29extern char default_parent_pattern[];
30extern char *parent_pattern;
31extern char default_sort_order[];
32extern int sort__need_collapse;
33extern int sort__has_parent;
34extern char *field_sep;
35extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension;
43
44struct hist_entry {
45 struct rb_node rb_node;
46 u64 count;
47 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip;
51 char level;
52 struct symbol *parent;
53 struct callchain_node callchain;
54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
59};
60
61enum sort_type {
62 SORT_PID,
63 SORT_COMM,
64 SORT_DSO,
65 SORT_SYM,
66 SORT_PARENT
67};
68
69/*
70 * configurable sorting bits
71 */
72
73struct sort_entry {
74 struct list_head list;
75
76 const char *header;
77
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
81 unsigned int *width;
82 bool elide;
83};
84
85extern struct sort_entry sort_thread;
86extern struct list_head hist_entry__sort_list;
87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
93extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
94extern size_t sort__sym_print(FILE *, struct hist_entry *, unsigned int __used);
95extern int64_t cmp_null(void *, void *);
96extern int64_t sort__thread_cmp(struct hist_entry *, struct hist_entry *);
97extern int64_t sort__comm_cmp(struct hist_entry *, struct hist_entry *);
98extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
99extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
100extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
106
107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index d2aa86c014c1..a3d121d6c83e 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -1,5 +1,5 @@
1#ifndef STRBUF_H 1#ifndef __PERF_STRBUF_H
2#define STRBUF_H 2#define __PERF_STRBUF_H
3 3
4/* 4/*
5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary 5 * Strbuf's can be use in many ways: as a byte array, or to store arbitrary
@@ -134,4 +134,4 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co
134extern int strbuf_branchname(struct strbuf *sb, const char *name); 134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); 135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 136
137#endif /* STRBUF_H */ 137#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c93eca9a7be3..5352d7dccc61 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,221 @@ int hex2u64(const char *ptr, u64 *long_val)
32 33
33 return p - ptr; 34 return p - ptr;
34} 35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46
47#define K 1024LL
48/*
49 * perf_atoll()
50 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
51 * and return its numeric value
52 */
53s64 perf_atoll(const char *str)
54{
55 unsigned int i;
56 s64 length = -1, unit = 1;
57
58 if (!isdigit(str[0]))
59 goto out_err;
60
61 for (i = 1; i < strlen(str); i++) {
62 switch (str[i]) {
63 case 'B':
64 case 'b':
65 break;
66 case 'K':
67 if (str[i + 1] != 'B')
68 goto out_err;
69 else
70 goto kilo;
71 case 'k':
72 if (str[i + 1] != 'b')
73 goto out_err;
74kilo:
75 unit = K;
76 break;
77 case 'M':
78 if (str[i + 1] != 'B')
79 goto out_err;
80 else
81 goto mega;
82 case 'm':
83 if (str[i + 1] != 'b')
84 goto out_err;
85mega:
86 unit = K * K;
87 break;
88 case 'G':
89 if (str[i + 1] != 'B')
90 goto out_err;
91 else
92 goto giga;
93 case 'g':
94 if (str[i + 1] != 'b')
95 goto out_err;
96giga:
97 unit = K * K * K;
98 break;
99 case 'T':
100 if (str[i + 1] != 'B')
101 goto out_err;
102 else
103 goto tera;
104 case 't':
105 if (str[i + 1] != 'b')
106 goto out_err;
107tera:
108 unit = K * K * K * K;
109 break;
110 case '\0': /* only specified figures */
111 unit = 1;
112 break;
113 default:
114 if (!isdigit(str[i]))
115 goto out_err;
116 break;
117 }
118 }
119
120 length = atoll(str) * unit;
121 goto out;
122
123out_err:
124 length = -1;
125out:
126 return length;
127}
128
129/*
130 * Helper function for splitting a string into an argv-like array.
131 * originaly copied from lib/argv_split.c
132 */
133static const char *skip_sep(const char *cp)
134{
135 while (*cp && isspace(*cp))
136 cp++;
137
138 return cp;
139}
140
141static const char *skip_arg(const char *cp)
142{
143 while (*cp && !isspace(*cp))
144 cp++;
145
146 return cp;
147}
148
149static int count_argc(const char *str)
150{
151 int count = 0;
152
153 while (*str) {
154 str = skip_sep(str);
155 if (*str) {
156 count++;
157 str = skip_arg(str);
158 }
159 }
160
161 return count;
162}
163
164/**
165 * argv_free - free an argv
166 * @argv - the argument vector to be freed
167 *
168 * Frees an argv and the strings it points to.
169 */
170void argv_free(char **argv)
171{
172 char **p;
173 for (p = argv; *p; p++)
174 free(*p);
175
176 free(argv);
177}
178
179/**
180 * argv_split - split a string at whitespace, returning an argv
181 * @str: the string to be split
182 * @argcp: returned argument count
183 *
184 * Returns an array of pointers to strings which are split out from
185 * @str. This is performed by strictly splitting on white-space; no
186 * quote processing is performed. Multiple whitespace characters are
187 * considered to be a single argument separator. The returned array
188 * is always NULL-terminated. Returns NULL on memory allocation
189 * failure.
190 */
191char **argv_split(const char *str, int *argcp)
192{
193 int argc = count_argc(str);
194 char **argv = zalloc(sizeof(*argv) * (argc+1));
195 char **argvp;
196
197 if (argv == NULL)
198 goto out;
199
200 if (argcp)
201 *argcp = argc;
202
203 argvp = argv;
204
205 while (*str) {
206 str = skip_sep(str);
207
208 if (*str) {
209 const char *p = str;
210 char *t;
211
212 str = skip_arg(str);
213
214 t = strndup(p, str-p);
215 if (t == NULL)
216 goto fail;
217 *argvp++ = t;
218 }
219 }
220 *argvp = NULL;
221
222out:
223 return argv;
224
225fail:
226 argv_free(argv);
227 return NULL;
228}
229
230/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bf39dfadfd24..02ede58c54b4 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,11 +1,17 @@
1#ifndef _PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define _PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
7 13
8#define _STR(x) #x 14#define _STR(x) #x
9#define STR(x) _STR(x) 15#define STR(x) _STR(x)
10 16
11#endif 17#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 921818e44a54..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -1,5 +1,5 @@
1#ifndef STRLIST_H_ 1#ifndef __PERF_STRLIST_H
2#define STRLIST_H_ 2#define __PERF_STRLIST_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <stdbool.h> 5#include <stdbool.h>
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* STRLIST_H_ */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index cd93195aedb3..e0781989cc31 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,5 +1,5 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_ 1#ifndef __PERF_SVGHELPER_H
2#define _INCLUDE_GUARD_SVG_HELPER_ 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include "types.h"
5 5
@@ -25,4 +25,4 @@ extern void svg_close(void);
25 25
26extern int svg_page_width; 26extern int svg_page_width;
27 27
28#endif 28#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 226f44a2357d..ab92763edb03 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,15 +1,23 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
7#include "thread.h"
5 8
6#include "debug.h" 9#include "debug.h"
7 10
11#include <asm/bug.h>
8#include <libelf.h> 12#include <libelf.h>
9#include <gelf.h> 13#include <gelf.h>
10#include <elf.h> 14#include <elf.h>
15#include <limits.h>
16#include <sys/utsname.h>
11 17
12const char *sym_hist_filter; 18#ifndef NT_GNU_BUILD_ID
19#define NT_GNU_BUILD_ID 3
20#endif
13 21
14enum dso_origin { 22enum dso_origin {
15 DSO__ORIG_KERNEL = 0, 23 DSO__ORIG_KERNEL = 0,
@@ -18,94 +26,206 @@ enum dso_origin {
18 DSO__ORIG_UBUNTU, 26 DSO__ORIG_UBUNTU,
19 DSO__ORIG_BUILDID, 27 DSO__ORIG_BUILDID,
20 DSO__ORIG_DSO, 28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
21 DSO__ORIG_NOT_FOUND, 30 DSO__ORIG_NOT_FOUND,
22}; 31};
23 32
24static struct symbol *symbol__new(u64 start, u64 len, 33static void dsos__add(struct list_head *head, struct dso *dso);
25 const char *name, unsigned int priv_size, 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
26 u64 obj_start, int v) 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct perf_session *session, symbol_filter_t filter);
37static int vmlinux_path__nr_entries;
38static char **vmlinux_path;
39
40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
42 .use_modules = true,
43 .try_vmlinux_path = true,
44};
45
46bool dso__loaded(const struct dso *self, enum map_type type)
27{ 47{
28 size_t namelen = strlen(name) + 1; 48 return self->loaded & (1 << type);
29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 49}
30 50
31 if (!self) 51bool dso__sorted_by_name(const struct dso *self, enum map_type type)
32 return NULL; 52{
53 return self->sorted_by_name & (1 << type);
54}
55
56static void dso__set_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{
63 self->sorted_by_name |= (1 << type);
64}
65
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{
68 switch (map_type) {
69 case MAP__FUNCTION:
70 return symbol_type == 'T' || symbol_type == 'W';
71 case MAP__VARIABLE:
72 return symbol_type == 'D' || symbol_type == 'd';
73 default:
74 return false;
75 }
76}
77
78static void symbols__fixup_end(struct rb_root *self)
79{
80 struct rb_node *nd, *prevnd = rb_first(self);
81 struct symbol *curr, *prev;
82
83 if (prevnd == NULL)
84 return;
85
86 curr = rb_entry(prevnd, struct symbol, rb_node);
87
88 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
89 prev = curr;
90 curr = rb_entry(nd, struct symbol, rb_node);
91
92 if (prev->end == prev->start)
93 prev->end = curr->start - 1;
94 }
95
96 /* Last entry */
97 if (curr->end == curr->start)
98 curr->end = roundup(curr->start, 4096);
99}
33 100
34 if (v >= 2) 101static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 102{
36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 103 struct map *prev, *curr;
104 struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
37 105
38 self->obj_start= obj_start; 106 if (prevnd == NULL)
39 self->hist = NULL; 107 return;
40 self->hist_sum = 0;
41 108
42 if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 109 curr = rb_entry(prevnd, struct map, rb_node);
43 self->hist = calloc(sizeof(u64), len);
44 110
45 if (priv_size) { 111 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
46 memset(self, 0, priv_size); 112 prev = curr;
47 self = ((void *)self) + priv_size; 113 curr = rb_entry(nd, struct map, rb_node);
114 prev->end = curr->start - 1;
48 } 115 }
116
117 /*
118 * We still haven't the actual symbols, so guess the
119 * last map final address.
120 */
121 curr->end = ~0UL;
122}
123
124static void map_groups__fixup_end(struct map_groups *self)
125{
126 int i;
127 for (i = 0; i < MAP__NR_TYPES; ++i)
128 __map_groups__fixup_end(self, i);
129}
130
131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
132{
133 size_t namelen = strlen(name) + 1;
134 struct symbol *self = zalloc(symbol_conf.priv_size +
135 sizeof(*self) + namelen);
136 if (self == NULL)
137 return NULL;
138
139 if (symbol_conf.priv_size)
140 self = ((void *)self) + symbol_conf.priv_size;
141
49 self->start = start; 142 self->start = start;
50 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
144
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146
51 memcpy(self->name, name, namelen); 147 memcpy(self->name, name, namelen);
52 148
53 return self; 149 return self;
54} 150}
55 151
56static void symbol__delete(struct symbol *self, unsigned int priv_size) 152static void symbol__delete(struct symbol *self)
57{ 153{
58 free(((void *)self) - priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
59} 155}
60 156
61static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
62{ 158{
63 if (!self->module) 159 return fprintf(fp, " %llx-%llx %s\n",
64 return fprintf(fp, " %llx-%llx %s\n",
65 self->start, self->end, self->name); 160 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} 161}
70 162
71struct dso *dso__new(const char *name, unsigned int sym_priv_size) 163static void dso__set_long_name(struct dso *self, char *name)
164{
165 if (name == NULL)
166 return;
167 self->long_name = name;
168 self->long_name_len = strlen(name);
169}
170
171static void dso__set_basename(struct dso *self)
172{
173 self->short_name = basename(self->long_name);
174}
175
176struct dso *dso__new(const char *name)
72{ 177{
73 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
74 179
75 if (self != NULL) { 180 if (self != NULL) {
181 int i;
76 strcpy(self->name, name); 182 strcpy(self->name, name);
77 self->syms = RB_ROOT; 183 dso__set_long_name(self, self->name);
78 self->sym_priv_size = sym_priv_size; 184 self->short_name = self->name;
79 self->find_symbol = dso__find_symbol; 185 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
80 self->slen_calculated = 0; 187 self->slen_calculated = 0;
81 self->origin = DSO__ORIG_NOT_FOUND; 188 self->origin = DSO__ORIG_NOT_FOUND;
189 self->loaded = 0;
190 self->sorted_by_name = 0;
191 self->has_build_id = 0;
82 } 192 }
83 193
84 return self; 194 return self;
85} 195}
86 196
87static void dso__delete_symbols(struct dso *self) 197static void symbols__delete(struct rb_root *self)
88{ 198{
89 struct symbol *pos; 199 struct symbol *pos;
90 struct rb_node *next = rb_first(&self->syms); 200 struct rb_node *next = rb_first(self);
91 201
92 while (next) { 202 while (next) {
93 pos = rb_entry(next, struct symbol, rb_node); 203 pos = rb_entry(next, struct symbol, rb_node);
94 next = rb_next(&pos->rb_node); 204 next = rb_next(&pos->rb_node);
95 rb_erase(&pos->rb_node, &self->syms); 205 rb_erase(&pos->rb_node, self);
96 symbol__delete(pos, self->sym_priv_size); 206 symbol__delete(pos);
97 } 207 }
98} 208}
99 209
100void dso__delete(struct dso *self) 210void dso__delete(struct dso *self)
101{ 211{
102 dso__delete_symbols(self); 212 int i;
213 for (i = 0; i < MAP__NR_TYPES; ++i)
214 symbols__delete(&self->symbols[i]);
215 if (self->long_name != self->name)
216 free(self->long_name);
103 free(self); 217 free(self);
104} 218}
105 219
106static void dso__insert_symbol(struct dso *self, struct symbol *sym) 220void dso__set_build_id(struct dso *self, void *build_id)
107{ 221{
108 struct rb_node **p = &self->syms.rb_node; 222 memcpy(self->build_id, build_id, sizeof(self->build_id));
223 self->has_build_id = 1;
224}
225
226static void symbols__insert(struct rb_root *self, struct symbol *sym)
227{
228 struct rb_node **p = &self->rb_node;
109 struct rb_node *parent = NULL; 229 struct rb_node *parent = NULL;
110 const u64 ip = sym->start; 230 const u64 ip = sym->start;
111 struct symbol *s; 231 struct symbol *s;
@@ -119,17 +239,17 @@ static void dso__insert_symbol(struct dso *self, struct symbol *sym)
119 p = &(*p)->rb_right; 239 p = &(*p)->rb_right;
120 } 240 }
121 rb_link_node(&sym->rb_node, parent, p); 241 rb_link_node(&sym->rb_node, parent, p);
122 rb_insert_color(&sym->rb_node, &self->syms); 242 rb_insert_color(&sym->rb_node, self);
123} 243}
124 244
125struct symbol *dso__find_symbol(struct dso *self, u64 ip) 245static struct symbol *symbols__find(struct rb_root *self, u64 ip)
126{ 246{
127 struct rb_node *n; 247 struct rb_node *n;
128 248
129 if (self == NULL) 249 if (self == NULL)
130 return NULL; 250 return NULL;
131 251
132 n = self->syms.rb_node; 252 n = self->rb_node;
133 253
134 while (n) { 254 while (n) {
135 struct symbol *s = rb_entry(n, struct symbol, rb_node); 255 struct symbol *s = rb_entry(n, struct symbol, rb_node);
@@ -145,12 +265,116 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
145 return NULL; 265 return NULL;
146} 266}
147 267
148size_t dso__fprintf(struct dso *self, FILE *fp) 268struct symbol_name_rb_node {
269 struct rb_node rb_node;
270 struct symbol sym;
271};
272
273static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
149{ 274{
150 size_t ret = fprintf(fp, "dso: %s\n", self->name); 275 struct rb_node **p = &self->rb_node;
276 struct rb_node *parent = NULL;
277 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
151 278
279 while (*p != NULL) {
280 parent = *p;
281 s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
282 if (strcmp(sym->name, s->sym.name) < 0)
283 p = &(*p)->rb_left;
284 else
285 p = &(*p)->rb_right;
286 }
287 rb_link_node(&symn->rb_node, parent, p);
288 rb_insert_color(&symn->rb_node, self);
289}
290
291static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
292{
152 struct rb_node *nd; 293 struct rb_node *nd;
153 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 294
295 for (nd = rb_first(source); nd; nd = rb_next(nd)) {
296 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
297 symbols__insert_by_name(self, pos);
298 }
299}
300
301static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
302{
303 struct rb_node *n;
304
305 if (self == NULL)
306 return NULL;
307
308 n = self->rb_node;
309
310 while (n) {
311 struct symbol_name_rb_node *s;
312 int cmp;
313
314 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
315 cmp = strcmp(name, s->sym.name);
316
317 if (cmp < 0)
318 n = n->rb_left;
319 else if (cmp > 0)
320 n = n->rb_right;
321 else
322 return &s->sym;
323 }
324
325 return NULL;
326}
327
328struct symbol *dso__find_symbol(struct dso *self,
329 enum map_type type, u64 addr)
330{
331 return symbols__find(&self->symbols[type], addr);
332}
333
334struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
335 const char *name)
336{
337 return symbols__find_by_name(&self->symbol_names[type], name);
338}
339
340void dso__sort_by_name(struct dso *self, enum map_type type)
341{
342 dso__set_sorted_by_name(self, type);
343 return symbols__sort_by_name(&self->symbol_names[type],
344 &self->symbols[type]);
345}
346
347int build_id__sprintf(u8 *self, int len, char *bf)
348{
349 char *bid = bf;
350 u8 *raw = self;
351 int i;
352
353 for (i = 0; i < len; ++i) {
354 sprintf(bid, "%02x", *raw);
355 ++raw;
356 bid += 2;
357 }
358
359 return raw - self;
360}
361
362size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
363{
364 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
365
366 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
367 return fprintf(fp, "%s", sbuild_id);
368}
369
370size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
371{
372 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374
375 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
154 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 378 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
155 ret += symbol__fprintf(pos, fp); 379 ret += symbol__fprintf(pos, fp);
156 } 380 }
@@ -158,13 +382,17 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
158 return ret; 382 return ret;
159} 383}
160 384
161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 385/*
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
387 * so that we can in the next step set the symbol ->end address and then
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
162{ 391{
163 struct rb_node *nd, *prevnd;
164 char *line = NULL; 392 char *line = NULL;
165 size_t n; 393 size_t n;
394 struct rb_root *root = &self->symbols[map->type];
166 FILE *file = fopen("/proc/kallsyms", "r"); 395 FILE *file = fopen("/proc/kallsyms", "r");
167 int count = 0;
168 396
169 if (file == NULL) 397 if (file == NULL)
170 goto out_failure; 398 goto out_failure;
@@ -174,6 +402,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
174 struct symbol *sym; 402 struct symbol *sym;
175 int line_len, len; 403 int line_len, len;
176 char symbol_type; 404 char symbol_type;
405 char *symbol_name;
177 406
178 line_len = getline(&line, &n, file); 407 line_len = getline(&line, &n, file);
179 if (line_len < 0) 408 if (line_len < 0)
@@ -191,49 +420,28 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
191 continue; 420 continue;
192 421
193 symbol_type = toupper(line[len]); 422 symbol_type = toupper(line[len]);
194 /* 423 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; 424 continue;
425
426 symbol_name = line + len + 2;
199 /* 427 /*
200 * Well fix up the end later, when we have all sorted. 428 * Will fix up the end later, when we have all symbols sorted.
201 */ 429 */
202 sym = symbol__new(start, 0xdead, line + len + 2, 430 sym = symbol__new(start, 0, symbol_name);
203 self->sym_priv_size, 0, v);
204 431
205 if (sym == NULL) 432 if (sym == NULL)
206 goto out_delete_line; 433 goto out_delete_line;
207 434 /*
208 if (filter && filter(self, sym)) 435 * We will pass the symbols to the filter later, in
209 symbol__delete(sym, self->sym_priv_size); 436 * map__split_kallsyms, when we have split the maps per module
210 else { 437 */
211 dso__insert_symbol(self, sym); 438 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 } 439 }
232 440
233 free(line); 441 free(line);
234 fclose(file); 442 fclose(file);
235 443
236 return count; 444 return 0;
237 445
238out_delete_line: 446out_delete_line:
239 free(line); 447 free(line);
@@ -241,14 +449,107 @@ out_failure:
241 return -1; 449 return -1;
242} 450}
243 451
244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 452/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have.
456 */
457static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter)
459{
460 struct map *curr_map = map;
461 struct symbol *pos;
462 int count = 0;
463 struct rb_root *root = &self->symbols[map->type];
464 struct rb_node *next = rb_first(root);
465 int kernel_range = 0;
466
467 while (next) {
468 char *module;
469
470 pos = rb_entry(next, struct symbol, rb_node);
471 next = rb_next(&pos->rb_node);
472
473 module = strchr(pos->name, '\t');
474 if (module) {
475 if (!symbol_conf.use_modules)
476 goto discard_symbol;
477
478 *module++ = '\0';
479
480 if (strcmp(self->name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
482 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} "
484 "inconsistency!\n");
485 return -1;
486 }
487 }
488 /*
489 * So that we look just like we get from .ko files,
490 * i.e. not prelinked, relative to map->start.
491 */
492 pos->start = curr_map->map_ip(curr_map, pos->start);
493 pos->end = curr_map->map_ip(curr_map, pos->end);
494 } else if (curr_map != map) {
495 char dso_name[PATH_MAX];
496 struct dso *dso;
497
498 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
499 kernel_range++);
500
501 dso = dso__new(dso_name);
502 if (dso == NULL)
503 return -1;
504
505 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) {
507 dso__delete(dso);
508 return -1;
509 }
510
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map);
513 ++kernel_range;
514 }
515
516 if (filter && filter(curr_map, pos)) {
517discard_symbol: rb_erase(&pos->rb_node, root);
518 symbol__delete(pos);
519 } else {
520 if (curr_map != map) {
521 rb_erase(&pos->rb_node, root);
522 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
523 }
524 count++;
525 }
526 }
527
528 return count;
529}
530
531
532static int dso__load_kallsyms(struct dso *self, struct map *map,
533 struct perf_session *session, symbol_filter_t filter)
534{
535 if (dso__load_all_kallsyms(self, map) < 0)
536 return -1;
537
538 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL;
540
541 return dso__split_kallsyms(self, map, session, filter);
542}
543
544static int dso__load_perf_map(struct dso *self, struct map *map,
545 symbol_filter_t filter)
245{ 546{
246 char *line = NULL; 547 char *line = NULL;
247 size_t n; 548 size_t n;
248 FILE *file; 549 FILE *file;
249 int nr_syms = 0; 550 int nr_syms = 0;
250 551
251 file = fopen(self->name, "r"); 552 file = fopen(self->long_name, "r");
252 if (file == NULL) 553 if (file == NULL)
253 goto out_failure; 554 goto out_failure;
254 555
@@ -278,16 +579,15 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
278 if (len + 2 >= line_len) 579 if (len + 2 >= line_len)
279 continue; 580 continue;
280 581
281 sym = symbol__new(start, size, line + len, 582 sym = symbol__new(start, size, line + len);
282 self->sym_priv_size, start, v);
283 583
284 if (sym == NULL) 584 if (sym == NULL)
285 goto out_delete_line; 585 goto out_delete_line;
286 586
287 if (filter && filter(self, sym)) 587 if (filter && filter(map, sym))
288 symbol__delete(sym, self->sym_priv_size); 588 symbol__delete(sym);
289 else { 589 else {
290 dso__insert_symbol(self, sym); 590 symbols__insert(&self->symbols[map->type], sym);
291 nr_syms++; 591 nr_syms++;
292 } 592 }
293 } 593 }
@@ -327,6 +627,13 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
327 sym->st_shndx != SHN_UNDEF; 627 sym->st_shndx != SHN_UNDEF;
328} 628}
329 629
630static inline bool elf_sym__is_object(const GElf_Sym *sym)
631{
632 return elf_sym__type(sym) == STT_OBJECT &&
633 sym->st_name != 0 &&
634 sym->st_shndx != SHN_UNDEF;
635}
636
330static inline int elf_sym__is_label(const GElf_Sym *sym) 637static inline int elf_sym__is_label(const GElf_Sym *sym)
331{ 638{
332 return elf_sym__type(sym) == STT_NOTYPE && 639 return elf_sym__type(sym) == STT_NOTYPE &&
@@ -347,6 +654,12 @@ static inline int elf_sec__is_text(const GElf_Shdr *shdr,
347 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 654 return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
348} 655}
349 656
657static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
658 const Elf_Data *secstrs)
659{
660 return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
661}
662
350static inline const char *elf_sym__name(const GElf_Sym *sym, 663static inline const char *elf_sym__name(const GElf_Sym *sym,
351 const Elf_Data *symstrs) 664 const Elf_Data *symstrs)
352{ 665{
@@ -393,7 +706,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 706 * 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). 707 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395 */ 708 */
396static int dso__synthesize_plt_symbols(struct dso *self, int v) 709static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
710 symbol_filter_t filter)
397{ 711{
398 uint32_t nr_rel_entries, idx; 712 uint32_t nr_rel_entries, idx;
399 GElf_Sym sym; 713 GElf_Sym sym;
@@ -409,7 +723,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
409 Elf *elf; 723 Elf *elf;
410 int nr = 0, symidx, fd, err = 0; 724 int nr = 0, symidx, fd, err = 0;
411 725
412 fd = open(self->name, O_RDONLY); 726 fd = open(self->long_name, O_RDONLY);
413 if (fd < 0) 727 if (fd < 0)
414 goto out; 728 goto out;
415 729
@@ -477,12 +791,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
477 "%s@plt", elf_sym__name(&sym, symstrs)); 791 "%s@plt", elf_sym__name(&sym, symstrs));
478 792
479 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 793 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
480 sympltname, self->sym_priv_size, 0, v); 794 sympltname);
481 if (!f) 795 if (!f)
482 goto out_elf_end; 796 goto out_elf_end;
483 797
484 dso__insert_symbol(self, f); 798 if (filter && filter(map, f))
485 ++nr; 799 symbol__delete(f);
800 else {
801 symbols__insert(&self->symbols[map->type], f);
802 ++nr;
803 }
486 } 804 }
487 } else if (shdr_rel_plt.sh_type == SHT_REL) { 805 } else if (shdr_rel_plt.sh_type == SHT_REL) {
488 GElf_Rel pos_mem, *pos; 806 GElf_Rel pos_mem, *pos;
@@ -495,12 +813,16 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
495 "%s@plt", elf_sym__name(&sym, symstrs)); 813 "%s@plt", elf_sym__name(&sym, symstrs));
496 814
497 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 815 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
498 sympltname, self->sym_priv_size, 0, v); 816 sympltname);
499 if (!f) 817 if (!f)
500 goto out_elf_end; 818 goto out_elf_end;
501 819
502 dso__insert_symbol(self, f); 820 if (filter && filter(map, f))
503 ++nr; 821 symbol__delete(f);
822 else {
823 symbols__insert(&self->symbols[map->type], f);
824 ++nr;
825 }
504 } 826 }
505 } 827 }
506 828
@@ -513,14 +835,42 @@ out_close:
513 if (err == 0) 835 if (err == 0)
514 return nr; 836 return nr;
515out: 837out:
516 fprintf(stderr, "%s: problems reading %s PLT info.\n", 838 pr_warning("%s: problems reading %s PLT info.\n",
517 __func__, self->name); 839 __func__, self->long_name);
518 return 0; 840 return 0;
519} 841}
520 842
521static int dso__load_sym(struct dso *self, int fd, const char *name, 843static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
522 symbol_filter_t filter, int v, struct module *mod)
523{ 844{
845 switch (type) {
846 case MAP__FUNCTION:
847 return elf_sym__is_function(self);
848 case MAP__VARIABLE:
849 return elf_sym__is_object(self);
850 default:
851 return false;
852 }
853}
854
855static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
856{
857 switch (type) {
858 case MAP__FUNCTION:
859 return elf_sec__is_text(self, secstrs);
860 case MAP__VARIABLE:
861 return elf_sec__is_data(self, secstrs);
862 default:
863 return false;
864 }
865}
866
867static int dso__load_sym(struct dso *self, struct map *map,
868 struct perf_session *session, const char *name, int fd,
869 symbol_filter_t filter, int kernel, int kmodule)
870{
871 struct map *curr_map = map;
872 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
524 Elf_Data *symstrs, *secstrs; 874 Elf_Data *symstrs, *secstrs;
525 uint32_t nr_syms; 875 uint32_t nr_syms;
526 int err = -1; 876 int err = -1;
@@ -531,19 +881,16 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
531 GElf_Sym sym; 881 GElf_Sym sym;
532 Elf_Scn *sec, *sec_strndx; 882 Elf_Scn *sec, *sec_strndx;
533 Elf *elf; 883 Elf *elf;
534 int nr = 0, kernel = !strcmp("[kernel]", self->name); 884 int nr = 0;
535 885
536 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 886 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
537 if (elf == NULL) { 887 if (elf == NULL) {
538 if (v) 888 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; 889 goto out_close;
542 } 890 }
543 891
544 if (gelf_getehdr(elf, &ehdr) == NULL) { 892 if (gelf_getehdr(elf, &ehdr) == NULL) {
545 if (v) 893 pr_err("%s: cannot get elf header.\n", __func__);
546 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
547 goto out_elf_end; 894 goto out_elf_end;
548 } 895 }
549 896
@@ -587,13 +934,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) { 934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
588 struct symbol *f; 935 struct symbol *f;
589 const char *elf_name; 936 const char *elf_name;
590 char *demangled; 937 char *demangled = NULL;
591 u64 obj_start;
592 struct section *section = NULL;
593 int is_label = elf_sym__is_label(&sym); 938 int is_label = elf_sym__is_label(&sym);
594 const char *section_name; 939 const char *section_name;
595 940
596 if (!is_label && !elf_sym__is_function(&sym)) 941 if (!is_label && !elf_sym__is_a(&sym, map->type))
597 continue; 942 continue;
598 943
599 sec = elf_getscn(elf, sym.st_shndx); 944 sec = elf_getscn(elf, sym.st_shndx);
@@ -602,55 +947,88 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
602 947
603 gelf_getshdr(sec, &shdr); 948 gelf_getshdr(sec, &shdr);
604 949
605 if (is_label && !elf_sec__is_text(&shdr, secstrs)) 950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
606 continue; 951 continue;
607 952
953 elf_name = elf_sym__name(&sym, symstrs);
608 section_name = elf_sec__name(&shdr, secstrs); 954 section_name = elf_sec__name(&shdr, secstrs);
609 obj_start = sym.st_value;
610 955
611 if (self->adjust_symbols) { 956 if (kernel || kmodule) {
612 if (v >= 2) 957 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 958
616 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 959 if (strcmp(section_name,
617 } 960 curr_dso->short_name + dso_name_len) == 0)
961 goto new_symbol;
618 962
619 if (mod) { 963 if (strcmp(section_name, ".text") == 0) {
620 section = mod->sections->find_section(mod->sections, section_name); 964 curr_map = map;
621 if (section) 965 curr_dso = self;
622 sym.st_value += section->vma; 966 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 } 967 }
968
969 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name);
971
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
973 if (curr_map == NULL) {
974 u64 start = sym.st_value;
975
976 if (kmodule)
977 start += map->start + shdr.sh_offset;
978
979 curr_dso = dso__new(dso_name);
980 if (curr_dso == NULL)
981 goto out_elf_end;
982 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION);
984 if (curr_map == NULL) {
985 dso__delete(curr_dso);
986 goto out_elf_end;
987 }
988 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL;
991 map_groups__insert(&session->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso);
993 } else
994 curr_dso = curr_map->dso;
995
996 goto new_symbol;
997 }
998
999 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
628 } 1004 }
629 /* 1005 /*
630 * We need to figure out if the object was created from C++ sources 1006 * 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 1007 * DWARF DW_compile_unit has this, but we don't always have access
632 * to it... 1008 * to it...
633 */ 1009 */
634 elf_name = elf_sym__name(&sym, symstrs);
635 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 1010 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
636 if (demangled != NULL) 1011 if (demangled != NULL)
637 elf_name = demangled; 1012 elf_name = demangled;
638 1013new_symbol:
639 f = symbol__new(sym.st_value, sym.st_size, elf_name, 1014 f = symbol__new(sym.st_value, sym.st_size, elf_name);
640 self->sym_priv_size, obj_start, v);
641 free(demangled); 1015 free(demangled);
642 if (!f) 1016 if (!f)
643 goto out_elf_end; 1017 goto out_elf_end;
644 1018
645 if (filter && filter(self, f)) 1019 if (filter && filter(curr_map, f))
646 symbol__delete(f, self->sym_priv_size); 1020 symbol__delete(f);
647 else { 1021 else {
648 f->module = mod; 1022 symbols__insert(&curr_dso->symbols[curr_map->type], f);
649 dso__insert_symbol(self, f);
650 nr++; 1023 nr++;
651 } 1024 }
652 } 1025 }
653 1026
1027 /*
1028 * For misannotated, zeroed, ASM function sizes.
1029 */
1030 if (nr > 0)
1031 symbols__fixup_end(&self->symbols[map->type]);
654 err = nr; 1032 err = nr;
655out_elf_end: 1033out_elf_end:
656 elf_end(elf); 1034 elf_end(elf);
@@ -658,63 +1036,154 @@ out_close:
658 return err; 1036 return err;
659} 1037}
660 1038
661#define BUILD_ID_SIZE 128 1039static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1040{
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042}
662 1043
663static char *dso__read_build_id(struct dso *self, int v) 1044static bool __dsos__read_build_ids(struct list_head *head)
664{ 1045{
665 int i; 1046 bool have_build_id = false;
1047 struct dso *pos;
1048
1049 list_for_each_entry(pos, head, node)
1050 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true;
1053 pos->has_build_id = true;
1054 }
1055
1056 return have_build_id;
1057}
1058
1059bool dsos__read_build_ids(void)
1060{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
1064}
1065
1066/*
1067 * Align offset to 4 bytes as needed for note name and descriptor data.
1068 */
1069#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1070
1071int filename__read_build_id(const char *filename, void *bf, size_t size)
1072{
1073 int fd, err = -1;
666 GElf_Ehdr ehdr; 1074 GElf_Ehdr ehdr;
667 GElf_Shdr shdr; 1075 GElf_Shdr shdr;
668 Elf_Data *build_id_data; 1076 Elf_Data *data;
669 Elf_Scn *sec; 1077 Elf_Scn *sec;
670 char *build_id = NULL, *bid; 1078 Elf_Kind ek;
671 unsigned char *raw; 1079 void *ptr;
672 Elf *elf; 1080 Elf *elf;
673 int fd = open(self->name, O_RDONLY);
674 1081
1082 if (size < BUILD_ID_SIZE)
1083 goto out;
1084
1085 fd = open(filename, O_RDONLY);
675 if (fd < 0) 1086 if (fd < 0)
676 goto out; 1087 goto out;
677 1088
678 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1089 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
679 if (elf == NULL) { 1090 if (elf == NULL) {
680 if (v) 1091 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; 1092 goto out_close;
684 } 1093 }
685 1094
1095 ek = elf_kind(elf);
1096 if (ek != ELF_K_ELF)
1097 goto out_elf_end;
1098
686 if (gelf_getehdr(elf, &ehdr) == NULL) { 1099 if (gelf_getehdr(elf, &ehdr) == NULL) {
687 if (v) 1100 pr_err("%s: cannot get elf header.\n", __func__);
688 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
689 goto out_elf_end; 1101 goto out_elf_end;
690 } 1102 }
691 1103
692 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 1104 sec = elf_section_by_name(elf, &ehdr, &shdr,
693 if (sec == NULL) 1105 ".note.gnu.build-id", NULL);
694 goto out_elf_end; 1106 if (sec == NULL) {
1107 sec = elf_section_by_name(elf, &ehdr, &shdr,
1108 ".notes", NULL);
1109 if (sec == NULL)
1110 goto out_elf_end;
1111 }
695 1112
696 build_id_data = elf_getdata(sec, NULL); 1113 data = elf_getdata(sec, NULL);
697 if (build_id_data == NULL) 1114 if (data == NULL)
698 goto out_elf_end;
699 build_id = malloc(BUILD_ID_SIZE);
700 if (build_id == NULL)
701 goto out_elf_end; 1115 goto out_elf_end;
702 raw = build_id_data->d_buf + 16;
703 bid = build_id;
704 1116
705 for (i = 0; i < 20; ++i) { 1117 ptr = data->d_buf;
706 sprintf(bid, "%02x", *raw); 1118 while (ptr < (data->d_buf + data->d_size)) {
707 ++raw; 1119 GElf_Nhdr *nhdr = ptr;
708 bid += 2; 1120 int namesz = NOTE_ALIGN(nhdr->n_namesz),
1121 descsz = NOTE_ALIGN(nhdr->n_descsz);
1122 const char *name;
1123
1124 ptr += sizeof(*nhdr);
1125 name = ptr;
1126 ptr += namesz;
1127 if (nhdr->n_type == NT_GNU_BUILD_ID &&
1128 nhdr->n_namesz == sizeof("GNU")) {
1129 if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1130 memcpy(bf, ptr, BUILD_ID_SIZE);
1131 err = BUILD_ID_SIZE;
1132 break;
1133 }
1134 }
1135 ptr += descsz;
709 } 1136 }
710 if (v >= 2)
711 printf("%s(%s): %s\n", __func__, self->name, build_id);
712out_elf_end: 1137out_elf_end:
713 elf_end(elf); 1138 elf_end(elf);
714out_close: 1139out_close:
715 close(fd); 1140 close(fd);
716out: 1141out:
717 return build_id; 1142 return err;
1143}
1144
1145int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1146{
1147 int fd, err = -1;
1148
1149 if (size < BUILD_ID_SIZE)
1150 goto out;
1151
1152 fd = open(filename, O_RDONLY);
1153 if (fd < 0)
1154 goto out;
1155
1156 while (1) {
1157 char bf[BUFSIZ];
1158 GElf_Nhdr nhdr;
1159 int namesz, descsz;
1160
1161 if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1162 break;
1163
1164 namesz = NOTE_ALIGN(nhdr.n_namesz);
1165 descsz = NOTE_ALIGN(nhdr.n_descsz);
1166 if (nhdr.n_type == NT_GNU_BUILD_ID &&
1167 nhdr.n_namesz == sizeof("GNU")) {
1168 if (read(fd, bf, namesz) != namesz)
1169 break;
1170 if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1171 if (read(fd, build_id,
1172 BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1173 err = 0;
1174 break;
1175 }
1176 } else if (read(fd, bf, descsz) != descsz)
1177 break;
1178 } else {
1179 int n = namesz + descsz;
1180 if (read(fd, bf, n) != n)
1181 break;
1182 }
1183 }
1184 close(fd);
1185out:
1186 return err;
718} 1187}
719 1188
720char dso__symtab_origin(const struct dso *self) 1189char dso__symtab_origin(const struct dso *self)
@@ -726,6 +1195,7 @@ char dso__symtab_origin(const struct dso *self)
726 [DSO__ORIG_UBUNTU] = 'u', 1195 [DSO__ORIG_UBUNTU] = 'u',
727 [DSO__ORIG_BUILDID] = 'b', 1196 [DSO__ORIG_BUILDID] = 'b',
728 [DSO__ORIG_DSO] = 'd', 1197 [DSO__ORIG_DSO] = 'd',
1198 [DSO__ORIG_KMODULE] = 'K',
729 }; 1199 };
730 1200
731 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1201 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -733,20 +1203,28 @@ char dso__symtab_origin(const struct dso *self)
733 return origin[self->origin]; 1203 return origin[self->origin];
734} 1204}
735 1205
736int dso__load(struct dso *self, symbol_filter_t filter, int v) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
737{ 1208{
738 int size = PATH_MAX; 1209 int size = PATH_MAX;
739 char *name = malloc(size), *build_id = NULL; 1210 char *name;
1211 u8 build_id[BUILD_ID_SIZE];
740 int ret = -1; 1212 int ret = -1;
741 int fd; 1213 int fd;
742 1214
1215 dso__set_loaded(self, map->type);
1216
1217 if (self->kernel)
1218 return dso__load_kernel_sym(self, map, session, filter);
1219
1220 name = malloc(size);
743 if (!name) 1221 if (!name)
744 return -1; 1222 return -1;
745 1223
746 self->adjust_symbols = 0; 1224 self->adjust_symbols = 0;
747 1225
748 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 1226 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
749 ret = dso__load_perf_map(self, filter, v); 1227 ret = dso__load_perf_map(self, map, filter);
750 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 1228 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
751 DSO__ORIG_NOT_FOUND; 1229 DSO__ORIG_NOT_FOUND;
752 return ret; 1230 return ret;
@@ -759,34 +1237,50 @@ more:
759 self->origin++; 1237 self->origin++;
760 switch (self->origin) { 1238 switch (self->origin) {
761 case DSO__ORIG_FEDORA: 1239 case DSO__ORIG_FEDORA:
762 snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 1240 snprintf(name, size, "/usr/lib/debug%s.debug",
1241 self->long_name);
763 break; 1242 break;
764 case DSO__ORIG_UBUNTU: 1243 case DSO__ORIG_UBUNTU:
765 snprintf(name, size, "/usr/lib/debug%s", self->name); 1244 snprintf(name, size, "/usr/lib/debug%s",
1245 self->long_name);
766 break; 1246 break;
767 case DSO__ORIG_BUILDID: 1247 case DSO__ORIG_BUILDID:
768 build_id = dso__read_build_id(self, v); 1248 if (filename__read_build_id(self->long_name, build_id,
769 if (build_id != NULL) { 1249 sizeof(build_id))) {
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1251
1252 build_id__sprintf(build_id, sizeof(build_id),
1253 build_id_hex);
770 snprintf(name, size, 1254 snprintf(name, size,
771 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1255 "/usr/lib/debug/.build-id/%.2s/%s.debug",
772 build_id, build_id + 2); 1256 build_id_hex, build_id_hex + 2);
773 free(build_id); 1257 if (self->has_build_id)
1258 goto compare_build_id;
774 break; 1259 break;
775 } 1260 }
776 self->origin++; 1261 self->origin++;
777 /* Fall thru */ 1262 /* Fall thru */
778 case DSO__ORIG_DSO: 1263 case DSO__ORIG_DSO:
779 snprintf(name, size, "%s", self->name); 1264 snprintf(name, size, "%s", self->long_name);
780 break; 1265 break;
781 1266
782 default: 1267 default:
783 goto out; 1268 goto out;
784 } 1269 }
785 1270
1271 if (self->has_build_id) {
1272 if (filename__read_build_id(name, build_id,
1273 sizeof(build_id)) < 0)
1274 goto more;
1275compare_build_id:
1276 if (!dso__build_id_equal(self, build_id))
1277 goto more;
1278 }
1279
786 fd = open(name, O_RDONLY); 1280 fd = open(name, O_RDONLY);
787 } while (fd < 0); 1281 } while (fd < 0);
788 1282
789 ret = dso__load_sym(self, fd, name, filter, v, NULL); 1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
790 close(fd); 1284 close(fd);
791 1285
792 /* 1286 /*
@@ -796,7 +1290,7 @@ more:
796 goto more; 1290 goto more;
797 1291
798 if (ret > 0) { 1292 if (ret > 0) {
799 int nr_plt = dso__synthesize_plt_symbols(self, v); 1293 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
800 if (nr_plt > 0) 1294 if (nr_plt > 0)
801 ret += nr_plt; 1295 ret += nr_plt;
802 } 1296 }
@@ -807,151 +1301,281 @@ out:
807 return ret; 1301 return ret;
808} 1302}
809 1303
810static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 1304struct map *map_groups__find_by_name(struct map_groups *self,
811 symbol_filter_t filter, int v) 1305 enum map_type type, const char *name)
812{ 1306{
813 struct module *mod = mod_dso__find_module(mods, name); 1307 struct rb_node *nd;
814 int err = 0, fd;
815 1308
816 if (mod == NULL || !mod->active) 1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
817 return err; 1310 struct map *map = rb_entry(nd, struct map, rb_node);
818 1311
819 fd = open(mod->path, O_RDONLY); 1312 if (map->dso && strcmp(map->dso->name, name) == 0)
1313 return map;
1314 }
820 1315
821 if (fd < 0) 1316 return NULL;
822 return err; 1317}
823 1318
824 err = dso__load_sym(self, fd, name, filter, v, mod); 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
825 close(fd); 1320{
1321 struct dirent *dent;
1322 DIR *dir = opendir(dirname);
826 1323
827 return err; 1324 if (!dir) {
1325 pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1326 return -1;
1327 }
1328
1329 while ((dent = readdir(dir)) != NULL) {
1330 char path[PATH_MAX];
1331
1332 if (dent->d_type == DT_DIR) {
1333 if (!strcmp(dent->d_name, ".") ||
1334 !strcmp(dent->d_name, ".."))
1335 continue;
1336
1337 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1340 goto failure;
1341 } else {
1342 char *dot = strrchr(dent->d_name, '.'),
1343 dso_name[PATH_MAX];
1344 struct map *map;
1345 char *long_name;
1346
1347 if (dot == NULL || strcmp(dot, ".ko"))
1348 continue;
1349 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1350 (int)(dot - dent->d_name), dent->d_name);
1351
1352 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1354 if (map == NULL)
1355 continue;
1356
1357 snprintf(path, sizeof(path), "%s/%s",
1358 dirname, dent->d_name);
1359
1360 long_name = strdup(path);
1361 if (long_name == NULL)
1362 goto failure;
1363 dso__set_long_name(map->dso, long_name);
1364 }
1365 }
1366
1367 return 0;
1368failure:
1369 closedir(dir);
1370 return -1;
828} 1371}
829 1372
830int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 1373static int perf_session__set_modules_path(struct perf_session *self)
831{ 1374{
832 struct mod_dso *mods = mod_dso__new_dso("modules"); 1375 struct utsname uts;
833 struct module *pos; 1376 char modules_path[PATH_MAX];
834 struct rb_node *next;
835 int err, count = 0;
836 1377
837 err = mod_dso__load_modules(mods); 1378 if (uname(&uts) < 0)
1379 return -1;
838 1380
839 if (err <= 0) 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
840 return err; 1382 uts.release);
841 1383
842 /* 1384 return perf_session__set_modules_path_dir(self, modules_path);
843 * Iterate over modules, and load active symbols. 1385}
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 1386
853 next = rb_next(&pos->rb_node); 1387/*
854 count += err; 1388 * Constructor variant for modules (where we know from /proc/modules where
855 } 1389 * they are loaded) and for vmlinux, where only after we load all the
1390 * symbols we'll know where it starts and ends.
1391 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{
1394 struct map *self = malloc(sizeof(*self));
856 1395
857 if (err < 0) { 1396 if (self != NULL) {
858 mod_dso__delete_modules(mods); 1397 /*
859 mod_dso__delete_self(mods); 1398 * ->end will be filled after we load all the symbols
860 return err; 1399 */
1400 map__init(self, type, start, 0, 0, dso);
861 } 1401 }
862 1402
863 return count; 1403 return self;
864} 1404}
865 1405
866static inline void dso__fill_symbol_holes(struct dso *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
867{ 1407{
868 struct symbol *prev = NULL; 1408 char *line = NULL;
869 struct rb_node *nd; 1409 size_t n;
1410 FILE *file = fopen("/proc/modules", "r");
1411 struct map *map;
870 1412
871 for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 1413 if (file == NULL)
872 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 1414 return -1;
873 1415
874 if (prev) { 1416 while (!feof(file)) {
875 u64 hole = 0; 1417 char name[PATH_MAX];
876 int alias = pos->start == prev->start; 1418 u64 start;
1419 struct dso *dso;
1420 char *sep;
1421 int line_len;
877 1422
878 if (!alias) 1423 line_len = getline(&line, &n, file);
879 hole = prev->start - pos->end - 1; 1424 if (line_len < 0)
1425 break;
880 1426
881 if (hole || alias) { 1427 if (!line)
882 if (alias) 1428 goto out_failure;
883 pos->end = prev->end; 1429
884 else if (hole) 1430 line[--line_len] = '\0'; /* \n */
885 pos->end = prev->start - 1; 1431
886 } 1432 sep = strrchr(line, 'x');
1433 if (sep == NULL)
1434 continue;
1435
1436 hex2u64(sep + 1, &start);
1437
1438 sep = strchr(line, ' ');
1439 if (sep == NULL)
1440 continue;
1441
1442 *sep = '\0';
1443
1444 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name);
1446
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line;
887 } 1454 }
888 prev = pos; 1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
889 } 1465 }
1466
1467 free(line);
1468 fclose(file);
1469
1470 return perf_session__set_modules_path(self);
1471
1472out_delete_line:
1473 free(line);
1474out_failure:
1475 return -1;
890} 1476}
891 1477
892static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
893 symbol_filter_t filter, int v) 1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter)
894{ 1481{
895 int err, fd = open(vmlinux, O_RDONLY); 1482 int err = -1, fd;
896 1483
897 if (fd < 0) 1484 if (self->has_build_id) {
898 return -1; 1485 u8 build_id[BUILD_ID_SIZE];
899 1486
900 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 1487 if (filename__read_build_id(vmlinux, build_id,
1488 sizeof(build_id)) < 0) {
1489 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1490 return -1;
1491 }
1492 if (!dso__build_id_equal(self, build_id)) {
1493 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1494 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1495
1496 build_id__sprintf(self->build_id,
1497 sizeof(self->build_id),
1498 expected_build_id);
1499 build_id__sprintf(build_id, sizeof(build_id),
1500 vmlinux_build_id);
1501 pr_debug("build_id in %s is %s while expected is %s, "
1502 "ignoring it\n", vmlinux, vmlinux_build_id,
1503 expected_build_id);
1504 return -1;
1505 }
1506 }
901 1507
902 if (err > 0) 1508 fd = open(vmlinux, O_RDONLY);
903 dso__fill_symbol_holes(self); 1509 if (fd < 0)
1510 return -1;
904 1511
1512 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
905 close(fd); 1514 close(fd);
906 1515
907 return err; 1516 return err;
908} 1517}
909 1518
910int dso__load_kernel(struct dso *self, const char *vmlinux, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
911 symbol_filter_t filter, int v, int use_modules) 1520 struct perf_session *session, symbol_filter_t filter)
912{ 1521{
913 int err = -1; 1522 int err;
914 1523 bool is_kallsyms;
915 if (vmlinux) { 1524
916 err = dso__load_vmlinux(self, vmlinux, filter, v); 1525 if (vmlinux_path != NULL) {
917 if (err > 0 && use_modules) { 1526 int i;
918 int syms = dso__load_modules(self, filter, v); 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
919 1528 vmlinux_path__nr_entries);
920 if (syms < 0) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
921 fprintf(stderr, "dso__load_modules failed!\n"); 1530 err = dso__load_vmlinux(self, map, session,
922 return syms; 1531 vmlinux_path[i], filter);
1532 if (err > 0) {
1533 pr_debug("Using %s for symbols\n",
1534 vmlinux_path[i]);
1535 dso__set_long_name(self,
1536 strdup(vmlinux_path[i]));
1537 goto out_fixup;
923 } 1538 }
924 err += syms;
925 } 1539 }
926 } 1540 }
927 1541
928 if (err <= 0) 1542 is_kallsyms = self->long_name[0] == '[';
929 err = dso__load_kallsyms(self, filter, v); 1543 if (is_kallsyms)
1544 goto do_kallsyms;
930 1545
931 if (err > 0) 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
932 self->origin = DSO__ORIG_KERNEL; 1547 if (err <= 0) {
1548 pr_info("The file %s cannot be used, "
1549 "trying to use /proc/kallsyms...", self->long_name);
1550do_kallsyms:
1551 err = dso__load_kallsyms(self, map, session, filter);
1552 if (err > 0 && !is_kallsyms)
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1554 }
1555
1556 if (err > 0) {
1557out_fixup:
1558 map__fixup_start(map);
1559 map__fixup_end(map);
1560 }
933 1561
934 return err; 1562 return err;
935} 1563}
936 1564
937LIST_HEAD(dsos); 1565LIST_HEAD(dsos__user);
938struct dso *kernel_dso; 1566LIST_HEAD(dsos__kernel);
939struct dso *vdso; 1567struct dso *vdso;
940struct dso *hypervisor_dso;
941 1568
942const char *vmlinux_name = "vmlinux"; 1569static void dsos__add(struct list_head *head, struct dso *dso)
943int modules;
944
945static void dsos__add(struct dso *dso)
946{ 1570{
947 list_add_tail(&dso->node, &dsos); 1571 list_add_tail(&dso->node, head);
948} 1572}
949 1573
950static struct dso *dsos__find(const char *name) 1574static struct dso *dsos__find(struct list_head *head, const char *name)
951{ 1575{
952 struct dso *pos; 1576 struct dso *pos;
953 1577
954 list_for_each_entry(pos, &dsos, node) 1578 list_for_each_entry(pos, head, node)
955 if (strcmp(pos->name, name) == 0) 1579 if (strcmp(pos->name, name) == 0)
956 return pos; 1580 return pos;
957 return NULL; 1581 return NULL;
@@ -959,79 +1583,227 @@ static struct dso *dsos__find(const char *name)
959 1583
960struct dso *dsos__findnew(const char *name) 1584struct dso *dsos__findnew(const char *name)
961{ 1585{
962 struct dso *dso = dsos__find(name); 1586 struct dso *dso = dsos__find(&dsos__user, name);
963 int nr;
964
965 if (dso)
966 return dso;
967
968 dso = dso__new(name, 0);
969 if (!dso)
970 goto out_delete_dso;
971 1587
972 nr = dso__load(dso, NULL, verbose); 1588 if (!dso) {
973 if (nr < 0) { 1589 dso = dso__new(name);
974 eprintf("Failed to open: %s\n", name); 1590 if (dso != NULL) {
975 goto out_delete_dso; 1591 dsos__add(&dsos__user, dso);
1592 dso__set_basename(dso);
1593 }
976 } 1594 }
977 if (!nr)
978 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979
980 dsos__add(dso);
981 1595
982 return dso; 1596 return dso;
1597}
983 1598
984out_delete_dso: 1599static void __dsos__fprintf(struct list_head *head, FILE *fp)
985 dso__delete(dso); 1600{
986 return NULL; 1601 struct dso *pos;
1602
1603 list_for_each_entry(pos, head, node) {
1604 int i;
1605 for (i = 0; i < MAP__NR_TYPES; ++i)
1606 dso__fprintf(pos, i, fp);
1607 }
987} 1608}
988 1609
989void dsos__fprintf(FILE *fp) 1610void dsos__fprintf(FILE *fp)
990{ 1611{
1612 __dsos__fprintf(&dsos__kernel, fp);
1613 __dsos__fprintf(&dsos__user, fp);
1614}
1615
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
1617{
991 struct dso *pos; 1618 struct dso *pos;
1619 size_t ret = 0;
992 1620
993 list_for_each_entry(pos, &dsos, node) 1621 list_for_each_entry(pos, head, node) {
994 dso__fprintf(pos, fp); 1622 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name);
1624 }
1625 return ret;
995} 1626}
996 1627
997static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 1628size_t dsos__fprintf_buildid(FILE *fp)
998{ 1629{
999 return dso__find_symbol(dso, ip); 1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1631 __dsos__fprintf_buildid(&dsos__user, fp));
1000} 1632}
1001 1633
1002int load_kernel(void) 1634static struct dso *dsos__create_kernel( const char *vmlinux)
1003{ 1635{
1004 int err; 1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1637
1638 if (kernel == NULL)
1639 return NULL;
1640
1641 kernel->short_name = "[kernel]";
1642 kernel->kernel = 1;
1643
1644 vdso = dso__new("[vdso]");
1645 if (vdso == NULL)
1646 goto out_delete_kernel_dso;
1647 dso__set_loaded(vdso, MAP__FUNCTION);
1648
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
1650 sizeof(kernel->build_id)) == 0)
1651 kernel->has_build_id = true;
1652
1653 dsos__add(&dsos__kernel, kernel);
1654 dsos__add(&dsos__user, vdso);
1005 1655
1006 kernel_dso = dso__new("[kernel]", 0); 1656 return kernel;
1007 if (!kernel_dso) 1657
1658out_delete_kernel_dso:
1659 dso__delete(kernel);
1660 return NULL;
1661}
1662
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux)
1664{
1665 struct map *functions, *variables;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667
1668 if (kernel == NULL)
1008 return -1; 1669 return -1;
1009 1670
1010 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1671 functions = map__new2(0, kernel, MAP__FUNCTION);
1011 if (err <= 0) { 1672 if (functions == NULL)
1012 dso__delete(kernel_dso); 1673 return -1;
1013 kernel_dso = NULL;
1014 } else
1015 dsos__add(kernel_dso);
1016 1674
1017 vdso = dso__new("[vdso]", 0); 1675 variables = map__new2(0, kernel, MAP__VARIABLE);
1018 if (!vdso) 1676 if (variables == NULL) {
1677 map__delete(functions);
1019 return -1; 1678 return -1;
1679 }
1020 1680
1021 vdso->find_symbol = vdso__find_symbol; 1681 functions->map_ip = functions->unmap_ip =
1682 variables->map_ip = variables->unmap_ip = identity__map_ip;
1683 map_groups__insert(self, functions);
1684 map_groups__insert(self, variables);
1022 1685
1023 dsos__add(vdso); 1686 return 0;
1687}
1688
1689static void vmlinux_path__exit(void)
1690{
1691 while (--vmlinux_path__nr_entries >= 0) {
1692 free(vmlinux_path[vmlinux_path__nr_entries]);
1693 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1694 }
1024 1695
1025 hypervisor_dso = dso__new("[hypervisor]", 0); 1696 free(vmlinux_path);
1026 if (!hypervisor_dso) 1697 vmlinux_path = NULL;
1698}
1699
1700static int vmlinux_path__init(void)
1701{
1702 struct utsname uts;
1703 char bf[PATH_MAX];
1704
1705 if (uname(&uts) < 0)
1027 return -1; 1706 return -1;
1028 dsos__add(hypervisor_dso);
1029 1707
1030 return err; 1708 vmlinux_path = malloc(sizeof(char *) * 5);
1709 if (vmlinux_path == NULL)
1710 return -1;
1711
1712 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1713 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1714 goto out_fail;
1715 ++vmlinux_path__nr_entries;
1716 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1717 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1718 goto out_fail;
1719 ++vmlinux_path__nr_entries;
1720 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1721 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1722 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1723 goto out_fail;
1724 ++vmlinux_path__nr_entries;
1725 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1726 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1727 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1728 goto out_fail;
1729 ++vmlinux_path__nr_entries;
1730 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1731 uts.release);
1732 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1733 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1734 goto out_fail;
1735 ++vmlinux_path__nr_entries;
1736
1737 return 0;
1738
1739out_fail:
1740 vmlinux_path__exit();
1741 return -1;
1031} 1742}
1032 1743
1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1746{
1747 if (list_str == NULL)
1748 return 0;
1033 1749
1034void symbol__init(void) 1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1757
1758int symbol__init(void)
1035{ 1759{
1036 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1761 if (symbol_conf.sort_by_name)
1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1763 sizeof(struct symbol));
1764
1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1766 return -1;
1767
1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1769 pr_err("'.' is the only non valid --field-separator argument\n");
1770 return -1;
1771 }
1772
1773 if (setup_list(&symbol_conf.dso_list,
1774 symbol_conf.dso_list_str, "dso") < 0)
1775 return -1;
1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1804 /*
1805 * Now that we have all the maps created, just set the ->end of them:
1806 */
1807 map_groups__fixup_end(&self->kmaps);
1808 return 0;
1037} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 829da9edba64..8aded2356f79 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,96 @@ 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 strlist;
53
54struct symbol_conf {
55 unsigned short priv_size;
56 bool try_vmlinux_path,
57 use_modules,
58 sort_by_name,
59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
71};
72
73extern struct symbol_conf symbol_conf;
74
75static inline void *symbol__priv(struct symbol *self)
76{
77 return ((void *)self) - symbol_conf.priv_size;
78}
79
80struct addr_location {
81 struct thread *thread;
82 struct map *map;
83 struct symbol *sym;
84 u64 addr;
85 char level;
86 bool filtered;
87};
88
57struct dso { 89struct dso {
58 struct list_head node; 90 struct list_head node;
59 struct rb_root syms; 91 struct rb_root symbols[MAP__NR_TYPES];
60 struct symbol *(*find_symbol)(struct dso *, u64 ip); 92 struct rb_root symbol_names[MAP__NR_TYPES];
61 unsigned int sym_priv_size; 93 u8 adjust_symbols:1;
62 unsigned char adjust_symbols; 94 u8 slen_calculated:1;
63 unsigned char slen_calculated; 95 u8 has_build_id:1;
96 u8 kernel:1;
64 unsigned char origin; 97 unsigned char origin;
98 u8 sorted_by_name;
99 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name;
103 char *long_name;
65 char name[0]; 104 char name[0];
66}; 105};
67 106
68extern const char *sym_hist_filter; 107struct 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); 108void dso__delete(struct dso *self);
74 109
75static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) 110bool dso__loaded(const struct dso *self, enum map_type type);
76{ 111bool dso__sorted_by_name(const struct dso *self, enum map_type type);
77 return ((void *)sym) - self->sym_priv_size; 112
78} 113void dso__sort_by_name(struct dso *self, enum map_type type);
79 114
80struct symbol *dso__find_symbol(struct dso *self, u64 ip); 115struct perf_session;
81 116
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); 117struct dso *dsos__findnew(const char *name);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
87void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp);
88 122
89size_t dso__fprintf(struct dso *self, FILE *fp); 123size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
90char dso__symtab_origin(const struct dso *self); 125char dso__symtab_origin(const struct dso *self);
126void dso__set_build_id(struct dso *self, void *build_id);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name);
91 130
92int load_kernel(void); 131int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void);
134int build_id__sprintf(u8 *self, int len, char *bf);
93 135
94void symbol__init(void); 136int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self);
95 138
96extern struct list_head dsos; 139extern struct list_head dsos__user, dsos__kernel;
97extern struct dso *kernel_dso;
98extern struct dso *vdso; 140extern struct dso *vdso;
99extern struct dso *hypervisor_dso; 141#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..4a08dcf50b68 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,20 +2,30 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
10void map_groups__init(struct map_groups *self)
11{
12 int i;
13 for (i = 0; i < MAP__NR_TYPES; ++i) {
14 self->maps[i] = RB_ROOT;
15 INIT_LIST_HEAD(&self->removed_maps[i]);
16 }
17}
18
9static struct thread *thread__new(pid_t pid) 19static struct thread *thread__new(pid_t pid)
10{ 20{
11 struct thread *self = calloc(1, sizeof(*self)); 21 struct thread *self = zalloc(sizeof(*self));
12 22
13 if (self != NULL) { 23 if (self != NULL) {
24 map_groups__init(&self->mg);
14 self->pid = pid; 25 self->pid = pid;
15 self->comm = malloc(32); 26 self->comm = malloc(32);
16 if (self->comm) 27 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid); 28 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 } 29 }
20 30
21 return self; 31 return self;
@@ -29,21 +39,90 @@ int thread__set_comm(struct thread *self, const char *comm)
29 return self->comm ? 0 : -ENOMEM; 39 return self->comm ? 0 : -ENOMEM;
30} 40}
31 41
32static size_t thread__fprintf(struct thread *self, FILE *fp) 42int thread__comm_len(struct thread *self)
43{
44 if (!self->comm_len) {
45 if (!self->comm)
46 return 0;
47 self->comm_len = strlen(self->comm);
48 }
49
50 return self->comm_len;
51}
52
53static const char *map_type__name[MAP__NR_TYPES] = {
54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp)
60{
61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
62 struct rb_node *nd;
63
64 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
65 struct map *pos = rb_entry(nd, struct map, rb_node);
66 printed += fprintf(fp, "Map:");
67 printed += map__fprintf(pos, fp);
68 if (verbose > 1) {
69 printed += dso__fprintf(pos->dso, type, fp);
70 printed += fprintf(fp, "--\n");
71 }
72 }
73
74 return printed;
75}
76
77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
78{
79 size_t printed = 0, i;
80 for (i = 0; i < MAP__NR_TYPES; ++i)
81 printed += __map_groups__fprintf_maps(self, i, fp);
82 return printed;
83}
84
85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
86 enum map_type type, FILE *fp)
33{ 87{
34 struct map *pos; 88 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); 89 size_t printed = 0;
90
91 list_for_each_entry(pos, &self->removed_maps[type], node) {
92 printed += fprintf(fp, "Map:");
93 printed += map__fprintf(pos, fp);
94 if (verbose > 1) {
95 printed += dso__fprintf(pos->dso, type, fp);
96 printed += fprintf(fp, "--\n");
97 }
98 }
99 return printed;
100}
36 101
37 list_for_each_entry(pos, &self->maps, node) 102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
38 ret += map__fprintf(pos, fp); 103{
104 size_t printed = 0, i;
105 for (i = 0; i < MAP__NR_TYPES; ++i)
106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
107 return printed;
108}
39 109
40 return ret; 110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
111{
112 size_t printed = map_groups__fprintf_maps(self, fp);
113 printed += fprintf(fp, "Removed maps:\n");
114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp)
118{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp);
41} 121}
42 122
43struct thread * 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{ 124{
46 struct rb_node **p = &threads->rb_node; 125 struct rb_node **p = &self->threads.rb_node;
47 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
48 struct thread *th; 127 struct thread *th;
49 128
@@ -52,15 +131,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 131 * so most of the time we dont have to look up
53 * the full rbtree: 132 * the full rbtree:
54 */ 133 */
55 if (*last_match && (*last_match)->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
56 return *last_match; 135 return self->last_match;
57 136
58 while (*p != NULL) { 137 while (*p != NULL) {
59 parent = *p; 138 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
61 140
62 if (th->pid == pid) { 141 if (th->pid == pid) {
63 *last_match = th; 142 self->last_match = th;
64 return th; 143 return th;
65 } 144 }
66 145
@@ -73,99 +152,127 @@ threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
73 th = thread__new(pid); 152 th = thread__new(pid);
74 if (th != NULL) { 153 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads); 155 rb_insert_color(&th->rb_node, &self->threads);
77 *last_match = th; 156 self->last_match = th;
78 } 157 }
79 158
80 return th; 159 return th;
81} 160}
82 161
83struct thread * 162static void map_groups__remove_overlappings(struct map_groups *self,
84register_idle_thread(struct rb_root *threads, struct thread **last_match) 163 struct map *map)
85{ 164{
86 struct thread *thread = threads__findnew(0, threads, last_match); 165 struct rb_root *root = &self->maps[map->type];
166 struct rb_node *next = rb_first(root);
87 167
88 if (!thread || thread__set_comm(thread, "swapper")) { 168 while (next) {
89 fprintf(stderr, "problem inserting idle task.\n"); 169 struct map *pos = rb_entry(next, struct map, rb_node);
90 exit(-1); 170 next = rb_next(&pos->rb_node);
91 } 171
172 if (!map__overlap(pos, map))
173 continue;
92 174
93 return thread; 175 if (verbose >= 2) {
176 fputs("overlapping maps:\n", stderr);
177 map__fprintf(map, stderr);
178 map__fprintf(pos, stderr);
179 }
180
181 rb_erase(&pos->rb_node, root);
182 /*
183 * We may have references to this map, for instance in some
184 * hist_entry instances, so just move them to a separate
185 * list.
186 */
187 list_add_tail(&pos->node, &self->removed_maps[map->type]);
188 }
94} 189}
95 190
96void thread__insert_map(struct thread *self, struct map *map) 191void maps__insert(struct rb_root *maps, struct map *map)
97{ 192{
98 struct map *pos, *tmp; 193 struct rb_node **p = &maps->rb_node;
99 194 struct rb_node *parent = NULL;
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) { 195 const u64 ip = map->start;
101 if (map__overlap(pos, map)) { 196 struct map *m;
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107 197
108 if (map->start <= pos->start && map->end > pos->start) 198 while (*p != NULL) {
109 pos->start = map->end; 199 parent = *p;
200 m = rb_entry(parent, struct map, rb_node);
201 if (ip < m->start)
202 p = &(*p)->rb_left;
203 else
204 p = &(*p)->rb_right;
205 }
110 206
111 if (map->end >= pos->end && map->start < pos->end) 207 rb_link_node(&map->rb_node, parent, p);
112 pos->end = map->start; 208 rb_insert_color(&map->rb_node, maps);
209}
113 210
114 if (verbose >= 2) { 211struct map *maps__find(struct rb_root *maps, u64 ip)
115 printf("after collision:\n"); 212{
116 map__fprintf(pos, stdout); 213 struct rb_node **p = &maps->rb_node;
117 } 214 struct rb_node *parent = NULL;
215 struct map *m;
118 216
119 if (pos->start >= pos->end) { 217 while (*p != NULL) {
120 list_del_init(&pos->node); 218 parent = *p;
121 free(pos); 219 m = rb_entry(parent, struct map, rb_node);
122 } 220 if (ip < m->start)
123 } 221 p = &(*p)->rb_left;
222 else if (ip > m->end)
223 p = &(*p)->rb_right;
224 else
225 return m;
124 } 226 }
125 227
126 list_add_tail(&map->node, &self->maps); 228 return NULL;
127} 229}
128 230
129int thread__fork(struct thread *self, struct thread *parent) 231void thread__insert_map(struct thread *self, struct map *map)
130{ 232{
131 struct map *map; 233 map_groups__remove_overlappings(&self->mg, map);
132 234 map_groups__insert(&self->mg, map);
133 if (self->comm) 235}
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138 236
139 list_for_each_entry(map, &parent->maps, node) { 237/*
238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
242{
243 struct rb_node *nd;
244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
245 struct map *map = rb_entry(nd, struct map, rb_node);
140 struct map *new = map__clone(map); 246 struct map *new = map__clone(map);
141 if (!new) 247 if (new == NULL)
142 return -ENOMEM; 248 return -ENOMEM;
143 thread__insert_map(self, new); 249 map_groups__insert(self, new);
144 } 250 }
145
146 return 0; 251 return 0;
147} 252}
148 253
149struct map *thread__find_map(struct thread *self, u64 ip) 254int thread__fork(struct thread *self, struct thread *parent)
150{ 255{
151 struct map *pos; 256 int i;
152 257
153 if (self == NULL) 258 if (self->comm)
154 return NULL; 259 free(self->comm);
155 260 self->comm = strdup(parent->comm);
156 list_for_each_entry(pos, &self->maps, node) 261 if (!self->comm)
157 if (ip >= pos->start && ip <= pos->end) 262 return -ENOMEM;
158 return pos;
159 263
160 return NULL; 264 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
266 return -ENOMEM;
267 return 0;
161} 268}
162 269
163size_t threads__fprintf(FILE *fp, struct rb_root *threads) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
164{ 271{
165 size_t ret = 0; 272 size_t ret = 0;
166 struct rb_node *nd; 273 struct rb_node *nd;
167 274
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170 277
171 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -173,3 +280,16 @@ size_t threads__fprintf(FILE *fp, struct rb_root *threads)
173 280
174 return ret; 281 return ret;
175} 282}
283
284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
288{
289 struct map *map = map_groups__find(self, type, addr);
290
291 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
293
294 return NULL;
295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 32aea3c1c2ad..c206f72c8881 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};
12
6struct thread { 13struct thread {
7 struct rb_node rb_node; 14 struct rb_node rb_node;
8 struct list_head maps; 15 struct map_groups mg;
9 pid_t pid; 16 pid_t pid;
10 char shortname[3]; 17 char shortname[3];
11 char *comm; 18 char *comm;
19 int comm_len;
12}; 20};
13 21
22void map_groups__init(struct map_groups *self);
14int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
15struct thread * 24int thread__comm_len(struct thread *self);
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match); 25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map); 26void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
30
31void maps__insert(struct rb_root *maps, struct map *map);
32struct map *maps__find(struct rb_root *maps, u64 addr);
33
34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
40 enum map_type type, u64 addr)
41{
42 return maps__find(&self->maps[type], addr);
43}
44
45static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr)
47{
48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49}
50
51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr,
54 struct addr_location *al,
55 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
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, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
64{
65 return map_groups__find_symbol(self, session, 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..6d6d76b8a21e
--- /dev/null
+++ b/tools/perf/util/trace-event-perl.c
@@ -0,0 +1,661 @@
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 __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, int argc, const char **argv)
363{
364 const char **command_line;
365 int i, err = 0;
366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
372
373 my_perl = perl_alloc();
374 perl_construct(my_perl);
375
376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
377 (char **)NULL)) {
378 err = -1;
379 goto error;
380 }
381
382 if (perl_run(my_perl)) {
383 err = -1;
384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
391
392 run_start_sub();
393
394 free(command_line);
395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
402}
403
404/*
405 * Stop trace script
406 */
407static int perl_stop_script(void)
408{
409 dSP; /* access to Perl stack */
410 PUSHMARK(SP);
411
412 if (get_cv("main::trace_end", 0))
413 call_pv("main::trace_end", G_DISCARD | G_NOARGS);
414
415 perl_destruct(my_perl);
416 perl_free(my_perl);
417
418 fprintf(stderr, "\nperf trace Perl script stopped\n");
419
420 return 0;
421}
422
423static int perl_generate_script(const char *outfile)
424{
425 struct event *event = NULL;
426 struct format_field *f;
427 char fname[PATH_MAX];
428 int not_first, count;
429 FILE *ofp;
430
431 sprintf(fname, "%s.pl", outfile);
432 ofp = fopen(fname, "w");
433 if (ofp == NULL) {
434 fprintf(stderr, "couldn't open %s\n", fname);
435 return -1;
436 }
437
438 fprintf(ofp, "# perf trace event handlers, "
439 "generated by perf trace -g perl\n");
440
441 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
442 " License version 2\n\n");
443
444 fprintf(ofp, "# The common_* event handler fields are the most useful "
445 "fields common to\n");
446
447 fprintf(ofp, "# all events. They don't necessarily correspond to "
448 "the 'common_*' fields\n");
449
450 fprintf(ofp, "# in the format files. Those fields not available as "
451 "handler params can\n");
452
453 fprintf(ofp, "# be retrieved using Perl functions of the form "
454 "common_*($context).\n");
455
456 fprintf(ofp, "# See Context.pm for the list of available "
457 "functions.\n\n");
458
459 fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
460 "Perf-Trace-Util/lib\";\n");
461
462 fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
463 fprintf(ofp, "use Perf::Trace::Core;\n");
464 fprintf(ofp, "use Perf::Trace::Context;\n");
465 fprintf(ofp, "use Perf::Trace::Util;\n\n");
466
467 fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
468 fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
469
470 while ((event = trace_find_next_event(event))) {
471 fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
472 fprintf(ofp, "\tmy (");
473
474 fprintf(ofp, "$event_name, ");
475 fprintf(ofp, "$context, ");
476 fprintf(ofp, "$common_cpu, ");
477 fprintf(ofp, "$common_secs, ");
478 fprintf(ofp, "$common_nsecs,\n");
479 fprintf(ofp, "\t $common_pid, ");
480 fprintf(ofp, "$common_comm,\n\t ");
481
482 not_first = 0;
483 count = 0;
484
485 for (f = event->format.fields; f; f = f->next) {
486 if (not_first++)
487 fprintf(ofp, ", ");
488 if (++count % 5 == 0)
489 fprintf(ofp, "\n\t ");
490
491 fprintf(ofp, "$%s", f->name);
492 }
493 fprintf(ofp, ") = @_;\n\n");
494
495 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
496 "$common_secs, $common_nsecs,\n\t "
497 "$common_pid, $common_comm);\n\n");
498
499 fprintf(ofp, "\tprintf(\"");
500
501 not_first = 0;
502 count = 0;
503
504 for (f = event->format.fields; f; f = f->next) {
505 if (not_first++)
506 fprintf(ofp, ", ");
507 if (count && count % 4 == 0) {
508 fprintf(ofp, "\".\n\t \"");
509 }
510 count++;
511
512 fprintf(ofp, "%s=", f->name);
513 if (f->flags & FIELD_IS_STRING ||
514 f->flags & FIELD_IS_FLAG ||
515 f->flags & FIELD_IS_SYMBOLIC)
516 fprintf(ofp, "%%s");
517 else if (f->flags & FIELD_IS_SIGNED)
518 fprintf(ofp, "%%d");
519 else
520 fprintf(ofp, "%%u");
521 }
522
523 fprintf(ofp, "\\n\",\n\t ");
524
525 not_first = 0;
526 count = 0;
527
528 for (f = event->format.fields; f; f = f->next) {
529 if (not_first++)
530 fprintf(ofp, ", ");
531
532 if (++count % 5 == 0)
533 fprintf(ofp, "\n\t ");
534
535 if (f->flags & FIELD_IS_FLAG) {
536 if ((count - 1) % 5 != 0) {
537 fprintf(ofp, "\n\t ");
538 count = 4;
539 }
540 fprintf(ofp, "flag_str(\"");
541 fprintf(ofp, "%s::%s\", ", event->system,
542 event->name);
543 fprintf(ofp, "\"%s\", $%s)", f->name,
544 f->name);
545 } else if (f->flags & FIELD_IS_SYMBOLIC) {
546 if ((count - 1) % 5 != 0) {
547 fprintf(ofp, "\n\t ");
548 count = 4;
549 }
550 fprintf(ofp, "symbol_str(\"");
551 fprintf(ofp, "%s::%s\", ", event->system,
552 event->name);
553 fprintf(ofp, "\"%s\", $%s)", f->name,
554 f->name);
555 } else
556 fprintf(ofp, "$%s", f->name);
557 }
558
559 fprintf(ofp, ");\n");
560 fprintf(ofp, "}\n\n");
561 }
562
563 fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "
564 "$common_cpu, $common_secs, $common_nsecs,\n\t "
565 "$common_pid, $common_comm) = @_;\n\n");
566
567 fprintf(ofp, "\tprint_header($event_name, $common_cpu, "
568 "$common_secs, $common_nsecs,\n\t $common_pid, "
569 "$common_comm);\n}\n\n");
570
571 fprintf(ofp, "sub print_header\n{\n"
572 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
573 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
574 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
575
576 fclose(ofp);
577
578 fprintf(stderr, "generated Perl script: %s\n", fname);
579
580 return 0;
581}
582
583struct scripting_ops perl_scripting_ops = {
584 .name = "Perl",
585 .start_script = perl_start_script,
586 .stop_script = perl_stop_script,
587 .process_event = perl_process_event,
588 .generate_script = perl_generate_script,
589};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
661#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..6ad405620c9b 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 *script, int argc, const char **argv);
274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm);
277 int (*generate_script) (const char *outfile);
278};
279
280int script_spec_register(const char *spec, struct scripting_ops *ops);
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}