aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-annotate.txt4
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt2
-rw-r--r--tools/perf/Documentation/perf-evlist.txt2
-rw-r--r--tools/perf/Documentation/perf-kmem.txt2
-rw-r--r--tools/perf/Documentation/perf-lock.txt2
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perf-report.txt11
-rw-r--r--tools/perf/Documentation/perf-sched.txt2
-rw-r--r--tools/perf/Documentation/perf-script.txt9
-rw-r--r--tools/perf/Documentation/perf-test.txt8
-rw-r--r--tools/perf/Documentation/perf-timechart.txt2
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c3
-rw-r--r--tools/perf/builtin-annotate.c132
-rw-r--r--tools/perf/builtin-buildid-list.c53
-rw-r--r--tools/perf/builtin-diff.c21
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-inject.c118
-rw-r--r--tools/perf/builtin-kmem.c16
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-lock.c12
-rw-r--r--tools/perf/builtin-probe.c1
-rw-r--r--tools/perf/builtin-record.c603
-rw-r--r--tools/perf/builtin-report.c236
-rw-r--r--tools/perf/builtin-sched.c200
-rw-r--r--tools/perf/builtin-script.c130
-rw-r--r--tools/perf/builtin-stat.c134
-rw-r--r--tools/perf/builtin-test.c545
-rw-r--r--tools/perf/builtin-timechart.c38
-rw-r--r--tools/perf/builtin-top.c558
-rw-r--r--tools/perf/perf.c33
-rw-r--r--tools/perf/perf.h24
-rw-r--r--tools/perf/util/annotate.c8
-rw-r--r--tools/perf/util/annotate.h5
-rw-r--r--tools/perf/util/build-id.c26
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.h3
-rw-r--r--tools/perf/util/cgroup.c15
-rw-r--r--tools/perf/util/config.c5
-rw-r--r--tools/perf/util/debugfs.c35
-rw-r--r--tools/perf/util/debugfs.h31
-rw-r--r--tools/perf/util/event.c360
-rw-r--r--tools/perf/util/event.h68
-rw-r--r--tools/perf/util/evlist.c299
-rw-r--r--tools/perf/util/evlist.h43
-rw-r--r--tools/perf/util/evsel.c154
-rw-r--r--tools/perf/util/evsel.h8
-rw-r--r--tools/perf/util/header.c741
-rw-r--r--tools/perf/util/header.h51
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/include/linux/bitops.h118
-rw-r--r--tools/perf/util/map.c4
-rw-r--r--tools/perf/util/map.h19
-rw-r--r--tools/perf/util/parse-events.c30
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/probe-finder.h1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c75
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c4
-rw-r--r--tools/perf/util/session.c342
-rw-r--r--tools/perf/util/session.h72
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/thread.c6
-rw-r--r--tools/perf/util/thread.h14
-rw-r--r--tools/perf/util/tool.h50
-rw-r--r--tools/perf/util/top.h20
-rw-r--r--tools/perf/util/trace-event-info.c28
-rw-r--r--tools/perf/util/trace-event-scripting.c2
-rw-r--r--tools/perf/util/trace-event.h8
-rw-r--r--tools/perf/util/ui/browsers/annotate.c16
-rw-r--r--tools/perf/util/ui/browsers/hists.c2
-rw-r--r--tools/perf/util/ui/progress.c3
-rw-r--r--tools/perf/util/usage.c5
-rw-r--r--tools/perf/util/util.h11
-rw-r--r--tools/perf/util/values.c1
76 files changed, 3449 insertions, 2163 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index fe6762ed56bd..c89f9e1453f7 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -22,7 +22,7 @@ OPTIONS
22------- 22-------
23-i:: 23-i::
24--input=:: 24--input=::
25 Input file name. (default: perf.data) 25 Input file name. (default: perf.data unless stdin is a fifo)
26 26
27-d:: 27-d::
28--dsos=<dso[,dso...]>:: 28--dsos=<dso[,dso...]>::
@@ -66,7 +66,7 @@ OPTIONS
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69-c:: 69-C::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 71 be provided as a comma-separated list with no space: 0,1. Ranges of
72 CPUs are specified with -: 0-2. Default is to report samples on all 72 CPUs are specified with -: 0-2. Default is to report samples on all
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index cc22325ffd1b..25c52efcc7f0 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -26,7 +26,7 @@ OPTIONS
26 Show only DSOs with hits. 26 Show only DSOs with hits.
27-i:: 27-i::
28--input=:: 28--input=::
29 Input file name. (default: perf.data) 29 Input file name. (default: perf.data unless stdin is a fifo)
30-f:: 30-f::
31--force:: 31--force::
32 Don't do ownership validation. 32 Don't do ownership validation.
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 0cada9e053dc..0507ec7bad71 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -18,7 +18,7 @@ OPTIONS
18------- 18-------
19-i:: 19-i::
20--input=:: 20--input=::
21 Input file name. (default: perf.data) 21 Input file name. (default: perf.data unless stdin is a fifo)
22 22
23SEE ALSO 23SEE ALSO
24-------- 24--------
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index a52fcde894c7..7c8fbbf3f61c 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -23,7 +23,7 @@ OPTIONS
23------- 23-------
24-i <file>:: 24-i <file>::
25--input=<file>:: 25--input=<file>::
26 Select the input file (default: perf.data) 26 Select the input file (default: perf.data unless stdin is a fifo)
27 27
28--caller:: 28--caller::
29 Show per-callsite statistics 29 Show per-callsite statistics
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
index 4a26a2f3a6a3..d6b2a4f2108b 100644
--- a/tools/perf/Documentation/perf-lock.txt
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -29,7 +29,7 @@ COMMON OPTIONS
29 29
30-i:: 30-i::
31--input=<file>:: 31--input=<file>::
32 Input file name. 32 Input file name. (default: perf.data unless stdin is a fifo)
33 33
34-v:: 34-v::
35--verbose:: 35--verbose::
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 5a520f825295..2937f7e14bb7 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -89,7 +89,7 @@ OPTIONS
89 89
90-m:: 90-m::
91--mmap-pages=:: 91--mmap-pages=::
92 Number of mmap data pages. 92 Number of mmap data pages. Must be a power of two.
93 93
94-g:: 94-g::
95--call-graph:: 95--call-graph::
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 212f24d672e1..9b430e98712e 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -19,7 +19,7 @@ OPTIONS
19------- 19-------
20-i:: 20-i::
21--input=:: 21--input=::
22 Input file name. (default: perf.data) 22 Input file name. (default: perf.data unless stdin is a fifo)
23 23
24-v:: 24-v::
25--verbose:: 25--verbose::
@@ -39,7 +39,7 @@ OPTIONS
39-T:: 39-T::
40--threads:: 40--threads::
41 Show per-thread event counters 41 Show per-thread event counters
42-C:: 42-c::
43--comms=:: 43--comms=::
44 Only consider symbols in these comms. CSV that understands 44 Only consider symbols in these comms. CSV that understands
45 file://filename entries. 45 file://filename entries.
@@ -80,9 +80,10 @@ OPTIONS
80--dump-raw-trace:: 80--dump-raw-trace::
81 Dump raw trace in ASCII. 81 Dump raw trace in ASCII.
82 82
83-g [type,min,order]:: 83-g [type,min[,limit],order]::
84--call-graph:: 84--call-graph::
85 Display call chains using type, min percent threshold and order. 85 Display call chains using type, min percent threshold, optional print
86 limit and order.
86 type can be either: 87 type can be either:
87 - flat: single column, linear exposure of call chains. 88 - flat: single column, linear exposure of call chains.
88 - graph: use a graph tree, displaying absolute overhead rates. 89 - graph: use a graph tree, displaying absolute overhead rates.
@@ -128,7 +129,7 @@ OPTIONS
128--symfs=<directory>:: 129--symfs=<directory>::
129 Look for files with symbols relative to this directory. 130 Look for files with symbols relative to this directory.
130 131
131-c:: 132-C::
132--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 133--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
133 be provided as a comma-separated list with no space: 0,1. Ranges of 134 be provided as a comma-separated list with no space: 0,1. Ranges of
134 CPUs are specified with -: 0-2. Default is to report samples on all 135 CPUs are specified with -: 0-2. Default is to report samples on all
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 5b212b57f70b..8ff4df956951 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -40,7 +40,7 @@ OPTIONS
40------- 40-------
41-i:: 41-i::
42--input=<file>:: 42--input=<file>::
43 Input file name. (default: perf.data) 43 Input file name. (default: perf.data unless stdin is a fifo)
44 44
45-v:: 45-v::
46--verbose:: 46--verbose::
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index dec87ecb530e..2f6cef43da25 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -106,7 +106,7 @@ OPTIONS
106 106
107-i:: 107-i::
108--input=:: 108--input=::
109 Input file name. 109 Input file name. (default: perf.data unless stdin is a fifo)
110 110
111-d:: 111-d::
112--debug-mode:: 112--debug-mode::
@@ -182,12 +182,17 @@ OPTIONS
182--hide-call-graph:: 182--hide-call-graph::
183 When printing symbols do not display call chain. 183 When printing symbols do not display call chain.
184 184
185-c:: 185-C::
186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 186--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
187 be provided as a comma-separated list with no space: 0,1. Ranges of 187 be provided as a comma-separated list with no space: 0,1. Ranges of
188 CPUs are specified with -: 0-2. Default is to report samples on all 188 CPUs are specified with -: 0-2. Default is to report samples on all
189 CPUs. 189 CPUs.
190 190
191-c::
192--comms=::
193 Only display events for these comms. CSV that understands
194 file://filename entries.
195
191-I:: 196-I::
192--show-info:: 197--show-info::
193 Display extended information about the perf.data file. This adds 198 Display extended information about the perf.data file. This adds
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 2c3b462f64b0..b24ac40fcd58 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -8,13 +8,19 @@ perf-test - Runs sanity tests.
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf test <options>' 11'perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]'
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command does assorted sanity tests, initially through linked routines but 15This command does assorted sanity tests, initially through linked routines but
16also will look for a directory with more tests in the form of scripts. 16also will look for a directory with more tests in the form of scripts.
17 17
18To get a list of available tests use 'perf test list', specifying a test name
19fragment will show all tests that have it.
20
21To run just specific tests, inform test name fragments or the numbers obtained
22from 'perf test list'.
23
18OPTIONS 24OPTIONS
19------- 25-------
20-v:: 26-v::
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index d7b79e2ba2ad..1632b0efc757 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -27,7 +27,7 @@ OPTIONS
27 Select the output file (default: output.svg) 27 Select the output file (default: output.svg)
28-i:: 28-i::
29--input=:: 29--input=::
30 Select the input file (default: perf.data) 30 Select the input file (default: perf.data unless stdin is a fifo)
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)
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b98e3075646b..ac86d67b636e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -278,6 +278,7 @@ LIB_H += util/strbuf.h
278LIB_H += util/strlist.h 278LIB_H += util/strlist.h
279LIB_H += util/strfilter.h 279LIB_H += util/strfilter.h
280LIB_H += util/svghelper.h 280LIB_H += util/svghelper.h
281LIB_H += util/tool.h
281LIB_H += util/run-command.h 282LIB_H += util/run-command.h
282LIB_H += util/sigchain.h 283LIB_H += util/sigchain.h
283LIB_H += util/symbol.h 284LIB_H += util/symbol.h
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 48ae0c5e3f73..7cdd61d0e27c 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -9,7 +9,10 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <stdlib.h>
13#ifndef __UCLIBC__
12#include <libio.h> 14#include <libio.h>
15#endif
13#include <dwarf-regs.h> 16#include <dwarf-regs.h>
14 17
15 18
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 46b4c24f338e..214ba7f9f577 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -27,32 +27,32 @@
27#include "util/sort.h" 27#include "util/sort.h"
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h"
30 31
31#include <linux/bitmap.h> 32#include <linux/bitmap.h>
32 33
33static char const *input_name = "perf.data"; 34struct perf_annotate {
34 35 struct perf_tool tool;
35static bool force, use_tui, use_stdio; 36 char const *input_name;
36 37 bool force, use_tui, use_stdio;
37static bool full_paths; 38 bool full_paths;
38 39 bool print_line;
39static bool print_line; 40 const char *sym_hist_filter;
40 41 const char *cpu_list;
41static const char *sym_hist_filter; 42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
42 43};
43static const char *cpu_list;
44static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
45 44
46static int perf_evlist__add_sample(struct perf_evlist *evlist, 45static int perf_evsel__add_sample(struct perf_evsel *evsel,
47 struct perf_sample *sample, 46 struct perf_sample *sample,
48 struct perf_evsel *evsel, 47 struct addr_location *al,
49 struct addr_location *al) 48 struct perf_annotate *ann)
50{ 49{
51 struct hist_entry *he; 50 struct hist_entry *he;
52 int ret; 51 int ret;
53 52
54 if (sym_hist_filter != NULL && 53 if (ann->sym_hist_filter != NULL &&
55 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { 54 (al->sym == NULL ||
55 strcmp(ann->sym_hist_filter, al->sym->name) != 0)) {
56 /* We're only interested in a symbol named sym_hist_filter */ 56 /* We're only interested in a symbol named sym_hist_filter */
57 if (al->sym != NULL) { 57 if (al->sym != NULL) {
58 rb_erase(&al->sym->rb_node, 58 rb_erase(&al->sym->rb_node,
@@ -69,8 +69,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
69 ret = 0; 69 ret = 0;
70 if (he->ms.sym != NULL) { 70 if (he->ms.sym != NULL) {
71 struct annotation *notes = symbol__annotation(he->ms.sym); 71 struct annotation *notes = symbol__annotation(he->ms.sym);
72 if (notes->src == NULL && 72 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
73 symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
74 return -ENOMEM; 73 return -ENOMEM;
75 74
76 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 75 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -81,25 +80,26 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist,
81 return ret; 80 return ret;
82} 81}
83 82
84static int process_sample_event(union perf_event *event, 83static int process_sample_event(struct perf_tool *tool,
84 union perf_event *event,
85 struct perf_sample *sample, 85 struct perf_sample *sample,
86 struct perf_evsel *evsel, 86 struct perf_evsel *evsel,
87 struct perf_session *session) 87 struct machine *machine)
88{ 88{
89 struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
89 struct addr_location al; 90 struct addr_location al;
90 91
91 if (perf_event__preprocess_sample(event, session, &al, sample, 92 if (perf_event__preprocess_sample(event, machine, &al, sample,
92 symbol__annotate_init) < 0) { 93 symbol__annotate_init) < 0) {
93 pr_warning("problem processing %d event, skipping it.\n", 94 pr_warning("problem processing %d event, skipping it.\n",
94 event->header.type); 95 event->header.type);
95 return -1; 96 return -1;
96 } 97 }
97 98
98 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 99 if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
99 return 0; 100 return 0;
100 101
101 if (!al.filtered && 102 if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) {
102 perf_evlist__add_sample(session->evlist, sample, evsel, &al)) {
103 pr_warning("problem incrementing symbol count, " 103 pr_warning("problem incrementing symbol count, "
104 "skipping event\n"); 104 "skipping event\n");
105 return -1; 105 return -1;
@@ -108,14 +108,15 @@ static int process_sample_event(union perf_event *event,
108 return 0; 108 return 0;
109} 109}
110 110
111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) 111static int hist_entry__tty_annotate(struct hist_entry *he, int evidx,
112 struct perf_annotate *ann)
112{ 113{
113 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 114 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
114 print_line, full_paths, 0, 0); 115 ann->print_line, ann->full_paths, 0, 0);
115} 116}
116 117
117static void hists__find_annotations(struct hists *self, int evidx, 118static void hists__find_annotations(struct hists *self, int evidx,
118 int nr_events) 119 struct perf_annotate *ann)
119{ 120{
120 struct rb_node *nd = rb_first(&self->entries), *next; 121 struct rb_node *nd = rb_first(&self->entries), *next;
121 int key = K_RIGHT; 122 int key = K_RIGHT;
@@ -138,8 +139,7 @@ find_next:
138 } 139 }
139 140
140 if (use_browser > 0) { 141 if (use_browser > 0) {
141 key = hist_entry__tui_annotate(he, evidx, nr_events, 142 key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0);
142 NULL, NULL, 0);
143 switch (key) { 143 switch (key) {
144 case K_RIGHT: 144 case K_RIGHT:
145 next = rb_next(nd); 145 next = rb_next(nd);
@@ -154,7 +154,7 @@ find_next:
154 if (next != NULL) 154 if (next != NULL)
155 nd = next; 155 nd = next;
156 } else { 156 } else {
157 hist_entry__tty_annotate(he, evidx); 157 hist_entry__tty_annotate(he, evidx, ann);
158 nd = rb_next(nd); 158 nd = rb_next(nd);
159 /* 159 /*
160 * Since we have a hist_entry per IP for the same 160 * Since we have a hist_entry per IP for the same
@@ -167,33 +167,26 @@ find_next:
167 } 167 }
168} 168}
169 169
170static struct perf_event_ops event_ops = { 170static int __cmd_annotate(struct perf_annotate *ann)
171 .sample = process_sample_event,
172 .mmap = perf_event__process_mmap,
173 .comm = perf_event__process_comm,
174 .fork = perf_event__process_task,
175 .ordered_samples = true,
176 .ordering_requires_timestamps = true,
177};
178
179static int __cmd_annotate(void)
180{ 171{
181 int ret; 172 int ret;
182 struct perf_session *session; 173 struct perf_session *session;
183 struct perf_evsel *pos; 174 struct perf_evsel *pos;
184 u64 total_nr_samples; 175 u64 total_nr_samples;
185 176
186 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 177 session = perf_session__new(ann->input_name, O_RDONLY,
178 ann->force, false, &ann->tool);
187 if (session == NULL) 179 if (session == NULL)
188 return -ENOMEM; 180 return -ENOMEM;
189 181
190 if (cpu_list) { 182 if (ann->cpu_list) {
191 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 183 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
184 ann->cpu_bitmap);
192 if (ret) 185 if (ret)
193 goto out_delete; 186 goto out_delete;
194 } 187 }
195 188
196 ret = perf_session__process_events(session, &event_ops); 189 ret = perf_session__process_events(session, &ann->tool);
197 if (ret) 190 if (ret)
198 goto out_delete; 191 goto out_delete;
199 192
@@ -217,13 +210,12 @@ static int __cmd_annotate(void)
217 total_nr_samples += nr_samples; 210 total_nr_samples += nr_samples;
218 hists__collapse_resort(hists); 211 hists__collapse_resort(hists);
219 hists__output_resort(hists); 212 hists__output_resort(hists);
220 hists__find_annotations(hists, pos->idx, 213 hists__find_annotations(hists, pos->idx, ann);
221 session->evlist->nr_entries);
222 } 214 }
223 } 215 }
224 216
225 if (total_nr_samples == 0) { 217 if (total_nr_samples == 0) {
226 ui__warning("The %s file has no samples!\n", input_name); 218 ui__warning("The %s file has no samples!\n", session->filename);
227 goto out_delete; 219 goto out_delete;
228 } 220 }
229out_delete: 221out_delete:
@@ -247,29 +239,41 @@ static const char * const annotate_usage[] = {
247 NULL 239 NULL
248}; 240};
249 241
250static const struct option options[] = { 242int cmd_annotate(int argc, const char **argv, const char *prefix __used)
251 OPT_STRING('i', "input", &input_name, "file", 243{
244 struct perf_annotate annotate = {
245 .tool = {
246 .sample = process_sample_event,
247 .mmap = perf_event__process_mmap,
248 .comm = perf_event__process_comm,
249 .fork = perf_event__process_task,
250 .ordered_samples = true,
251 .ordering_requires_timestamps = true,
252 },
253 };
254 const struct option options[] = {
255 OPT_STRING('i', "input", &annotate.input_name, "file",
252 "input file name"), 256 "input file name"),
253 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 257 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
254 "only consider symbols in these dsos"), 258 "only consider symbols in these dsos"),
255 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 259 OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol",
256 "symbol to annotate"), 260 "symbol to annotate"),
257 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 261 OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"),
258 OPT_INCR('v', "verbose", &verbose, 262 OPT_INCR('v', "verbose", &verbose,
259 "be more verbose (show symbol address, etc)"), 263 "be more verbose (show symbol address, etc)"),
260 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 264 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
261 "dump raw trace in ASCII"), 265 "dump raw trace in ASCII"),
262 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 266 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
263 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 267 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
264 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 268 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
265 "file", "vmlinux pathname"), 269 "file", "vmlinux pathname"),
266 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 270 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
267 "load module symbols - WARNING: use only with -k and LIVE kernel"), 271 "load module symbols - WARNING: use only with -k and LIVE kernel"),
268 OPT_BOOLEAN('l', "print-line", &print_line, 272 OPT_BOOLEAN('l', "print-line", &annotate.print_line,
269 "print matching source lines (may be slow)"), 273 "print matching source lines (may be slow)"),
270 OPT_BOOLEAN('P', "full-paths", &full_paths, 274 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
271 "Don't shorten the displayed pathnames"), 275 "Don't shorten the displayed pathnames"),
272 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 276 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
273 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 277 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
274 "Look for files with symbols relative to this directory"), 278 "Look for files with symbols relative to this directory"),
275 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, 279 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
@@ -279,15 +283,13 @@ static const struct option options[] = {
279 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 283 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
280 "Specify disassembler style (e.g. -M intel for intel syntax)"), 284 "Specify disassembler style (e.g. -M intel for intel syntax)"),
281 OPT_END() 285 OPT_END()
282}; 286 };
283 287
284int cmd_annotate(int argc, const char **argv, const char *prefix __used)
285{
286 argc = parse_options(argc, argv, options, annotate_usage, 0); 288 argc = parse_options(argc, argv, options, annotate_usage, 0);
287 289
288 if (use_stdio) 290 if (annotate.use_stdio)
289 use_browser = 0; 291 use_browser = 0;
290 else if (use_tui) 292 else if (annotate.use_tui)
291 use_browser = 1; 293 use_browser = 1;
292 294
293 setup_browser(true); 295 setup_browser(true);
@@ -308,7 +310,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
308 if (argc > 1) 310 if (argc > 1)
309 usage_with_options(annotate_usage, options); 311 usage_with_options(annotate_usage, options);
310 312
311 sym_hist_filter = argv[0]; 313 annotate.sym_hist_filter = argv[0];
312 } 314 }
313 315
314 if (field_sep && *field_sep == '.') { 316 if (field_sep && *field_sep == '.') {
@@ -316,5 +318,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
316 return -1; 318 return -1;
317 } 319 }
318 320
319 return __cmd_annotate(); 321 return __cmd_annotate(&annotate);
320} 322}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index cb690a65bf02..52480467e9ff 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -18,7 +18,7 @@
18 18
19#include <libelf.h> 19#include <libelf.h>
20 20
21static char const *input_name = "perf.data"; 21static const char *input_name;
22static bool force; 22static bool force;
23static bool show_kernel; 23static bool show_kernel;
24static bool with_hits; 24static bool with_hits;
@@ -39,24 +39,6 @@ static const struct option options[] = {
39 OPT_END() 39 OPT_END()
40}; 40};
41 41
42static int perf_session__list_build_ids(void)
43{
44 struct perf_session *session;
45
46 session = perf_session__new(input_name, O_RDONLY, force, false,
47 &build_id__mark_dso_hit_ops);
48 if (session == NULL)
49 return -1;
50
51 if (with_hits)
52 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
53
54 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
55
56 perf_session__delete(session);
57 return 0;
58}
59
60static int sysfs__fprintf_build_id(FILE *fp) 42static int sysfs__fprintf_build_id(FILE *fp)
61{ 43{
62 u8 kallsyms_build_id[BUILD_ID_SIZE]; 44 u8 kallsyms_build_id[BUILD_ID_SIZE];
@@ -85,17 +67,36 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
85 return fprintf(fp, "%s\n", sbuild_id); 67 return fprintf(fp, "%s\n", sbuild_id);
86} 68}
87 69
88static int __cmd_buildid_list(void) 70static int perf_session__list_build_ids(void)
89{ 71{
90 if (show_kernel) 72 struct perf_session *session;
91 return sysfs__fprintf_build_id(stdout);
92 73
93 elf_version(EV_CURRENT); 74 elf_version(EV_CURRENT);
75
76 session = perf_session__new(input_name, O_RDONLY, force, false,
77 &build_id__mark_dso_hit_ops);
78 if (session == NULL)
79 return -1;
80
94 /* 81 /*
95 * See if this is an ELF file first: 82 * See if this is an ELF file first:
96 */ 83 */
97 if (filename__fprintf_build_id(input_name, stdout)) 84 if (filename__fprintf_build_id(session->filename, stdout))
98 return 0; 85 goto out;
86
87 if (with_hits)
88 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
89
90 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
91out:
92 perf_session__delete(session);
93 return 0;
94}
95
96static int __cmd_buildid_list(void)
97{
98 if (show_kernel)
99 return sysfs__fprintf_build_id(stdout);
99 100
100 return perf_session__list_build_ids(); 101 return perf_session__list_build_ids();
101} 102}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b39f3a1ee7dc..4f19513d7dda 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -9,7 +9,9 @@
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/event.h" 10#include "util/event.h"
11#include "util/hist.h" 11#include "util/hist.h"
12#include "util/evsel.h"
12#include "util/session.h" 13#include "util/session.h"
14#include "util/tool.h"
13#include "util/sort.h" 15#include "util/sort.h"
14#include "util/symbol.h" 16#include "util/symbol.h"
15#include "util/util.h" 17#include "util/util.h"
@@ -30,14 +32,15 @@ static int hists__add_entry(struct hists *self,
30 return -ENOMEM; 32 return -ENOMEM;
31} 33}
32 34
33static int diff__process_sample_event(union perf_event *event, 35static int diff__process_sample_event(struct perf_tool *tool __used,
36 union perf_event *event,
34 struct perf_sample *sample, 37 struct perf_sample *sample,
35 struct perf_evsel *evsel __used, 38 struct perf_evsel *evsel __used,
36 struct perf_session *session) 39 struct machine *machine)
37{ 40{
38 struct addr_location al; 41 struct addr_location al;
39 42
40 if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { 43 if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
41 pr_warning("problem processing %d event, skipping it.\n", 44 pr_warning("problem processing %d event, skipping it.\n",
42 event->header.type); 45 event->header.type);
43 return -1; 46 return -1;
@@ -46,16 +49,16 @@ static int diff__process_sample_event(union perf_event *event,
46 if (al.filtered || al.sym == NULL) 49 if (al.filtered || al.sym == NULL)
47 return 0; 50 return 0;
48 51
49 if (hists__add_entry(&session->hists, &al, sample->period)) { 52 if (hists__add_entry(&evsel->hists, &al, sample->period)) {
50 pr_warning("problem incrementing symbol period, skipping event\n"); 53 pr_warning("problem incrementing symbol period, skipping event\n");
51 return -1; 54 return -1;
52 } 55 }
53 56
54 session->hists.stats.total_period += sample->period; 57 evsel->hists.stats.total_period += sample->period;
55 return 0; 58 return 0;
56} 59}
57 60
58static struct perf_event_ops event_ops = { 61static struct perf_tool perf_diff = {
59 .sample = diff__process_sample_event, 62 .sample = diff__process_sample_event,
60 .mmap = perf_event__process_mmap, 63 .mmap = perf_event__process_mmap,
61 .comm = perf_event__process_comm, 64 .comm = perf_event__process_comm,
@@ -145,13 +148,13 @@ static int __cmd_diff(void)
145 int ret, i; 148 int ret, i;
146 struct perf_session *session[2]; 149 struct perf_session *session[2];
147 150
148 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops); 151 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff);
149 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops); 152 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff);
150 if (session[0] == NULL || session[1] == NULL) 153 if (session[0] == NULL || session[1] == NULL)
151 return -ENOMEM; 154 return -ENOMEM;
152 155
153 for (i = 0; i < 2; ++i) { 156 for (i = 0; i < 2; ++i) {
154 ret = perf_session__process_events(session[i], &event_ops); 157 ret = perf_session__process_events(session[i], &perf_diff);
155 if (ret) 158 if (ret)
156 goto out_delete; 159 goto out_delete;
157 } 160 }
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 4c5e9e04a41f..26760322c4f4 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,7 +15,7 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18static char const *input_name = "perf.data"; 18static const char *input_name;
19 19
20static int __cmd_evlist(void) 20static int __cmd_evlist(void)
21{ 21{
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 8dfc12bb119b..09c106193e65 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -9,6 +9,7 @@
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h"
12#include "util/debug.h" 13#include "util/debug.h"
13 14
14#include "util/parse-options.h" 15#include "util/parse-options.h"
@@ -16,8 +17,9 @@
16static char const *input_name = "-"; 17static char const *input_name = "-";
17static bool inject_build_ids; 18static bool inject_build_ids;
18 19
19static int perf_event__repipe_synth(union perf_event *event, 20static int perf_event__repipe_synth(struct perf_tool *tool __used,
20 struct perf_session *session __used) 21 union perf_event *event,
22 struct machine *machine __used)
21{ 23{
22 uint32_t size; 24 uint32_t size;
23 void *buf = event; 25 void *buf = event;
@@ -36,41 +38,70 @@ static int perf_event__repipe_synth(union perf_event *event,
36 return 0; 38 return 0;
37} 39}
38 40
39static int perf_event__repipe(union perf_event *event, 41static int perf_event__repipe_op2_synth(struct perf_tool *tool,
42 union perf_event *event,
43 struct perf_session *session __used)
44{
45 return perf_event__repipe_synth(tool, event, NULL);
46}
47
48static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
49 union perf_event *event)
50{
51 return perf_event__repipe_synth(tool, event, NULL);
52}
53
54static int perf_event__repipe_tracing_data_synth(union perf_event *event,
55 struct perf_session *session __used)
56{
57 return perf_event__repipe_synth(NULL, event, NULL);
58}
59
60static int perf_event__repipe_attr(union perf_event *event,
61 struct perf_evlist **pevlist __used)
62{
63 return perf_event__repipe_synth(NULL, event, NULL);
64}
65
66static int perf_event__repipe(struct perf_tool *tool,
67 union perf_event *event,
40 struct perf_sample *sample __used, 68 struct perf_sample *sample __used,
41 struct perf_session *session) 69 struct machine *machine)
42{ 70{
43 return perf_event__repipe_synth(event, session); 71 return perf_event__repipe_synth(tool, event, machine);
44} 72}
45 73
46static int perf_event__repipe_sample(union perf_event *event, 74static int perf_event__repipe_sample(struct perf_tool *tool,
75 union perf_event *event,
47 struct perf_sample *sample __used, 76 struct perf_sample *sample __used,
48 struct perf_evsel *evsel __used, 77 struct perf_evsel *evsel __used,
49 struct perf_session *session) 78 struct machine *machine)
50{ 79{
51 return perf_event__repipe_synth(event, session); 80 return perf_event__repipe_synth(tool, event, machine);
52} 81}
53 82
54static int perf_event__repipe_mmap(union perf_event *event, 83static int perf_event__repipe_mmap(struct perf_tool *tool,
84 union perf_event *event,
55 struct perf_sample *sample, 85 struct perf_sample *sample,
56 struct perf_session *session) 86 struct machine *machine)
57{ 87{
58 int err; 88 int err;
59 89
60 err = perf_event__process_mmap(event, sample, session); 90 err = perf_event__process_mmap(tool, event, sample, machine);
61 perf_event__repipe(event, sample, session); 91 perf_event__repipe(tool, event, sample, machine);
62 92
63 return err; 93 return err;
64} 94}
65 95
66static int perf_event__repipe_task(union perf_event *event, 96static int perf_event__repipe_task(struct perf_tool *tool,
97 union perf_event *event,
67 struct perf_sample *sample, 98 struct perf_sample *sample,
68 struct perf_session *session) 99 struct machine *machine)
69{ 100{
70 int err; 101 int err;
71 102
72 err = perf_event__process_task(event, sample, session); 103 err = perf_event__process_task(tool, event, sample, machine);
73 perf_event__repipe(event, sample, session); 104 perf_event__repipe(tool, event, sample, machine);
74 105
75 return err; 106 return err;
76} 107}
@@ -80,7 +111,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event,
80{ 111{
81 int err; 112 int err;
82 113
83 perf_event__repipe_synth(event, session); 114 perf_event__repipe_synth(NULL, event, NULL);
84 err = perf_event__process_tracing_data(event, session); 115 err = perf_event__process_tracing_data(event, session);
85 116
86 return err; 117 return err;
@@ -100,10 +131,10 @@ static int dso__read_build_id(struct dso *self)
100 return -1; 131 return -1;
101} 132}
102 133
103static int dso__inject_build_id(struct dso *self, struct perf_session *session) 134static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
135 struct machine *machine)
104{ 136{
105 u16 misc = PERF_RECORD_MISC_USER; 137 u16 misc = PERF_RECORD_MISC_USER;
106 struct machine *machine;
107 int err; 138 int err;
108 139
109 if (dso__read_build_id(self) < 0) { 140 if (dso__read_build_id(self) < 0) {
@@ -111,17 +142,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
111 return -1; 142 return -1;
112 } 143 }
113 144
114 machine = perf_session__find_host_machine(session);
115 if (machine == NULL) {
116 pr_err("Can't find machine for session\n");
117 return -1;
118 }
119
120 if (self->kernel) 145 if (self->kernel)
121 misc = PERF_RECORD_MISC_KERNEL; 146 misc = PERF_RECORD_MISC_KERNEL;
122 147
123 err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, 148 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
124 machine, session); 149 machine);
125 if (err) { 150 if (err) {
126 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 151 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
127 return -1; 152 return -1;
@@ -130,10 +155,11 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
130 return 0; 155 return 0;
131} 156}
132 157
133static int perf_event__inject_buildid(union perf_event *event, 158static int perf_event__inject_buildid(struct perf_tool *tool,
159 union perf_event *event,
134 struct perf_sample *sample, 160 struct perf_sample *sample,
135 struct perf_evsel *evsel __used, 161 struct perf_evsel *evsel __used,
136 struct perf_session *session) 162 struct machine *machine)
137{ 163{
138 struct addr_location al; 164 struct addr_location al;
139 struct thread *thread; 165 struct thread *thread;
@@ -141,21 +167,21 @@ static int perf_event__inject_buildid(union perf_event *event,
141 167
142 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 168 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
143 169
144 thread = perf_session__findnew(session, event->ip.pid); 170 thread = machine__findnew_thread(machine, event->ip.pid);
145 if (thread == NULL) { 171 if (thread == NULL) {
146 pr_err("problem processing %d event, skipping it.\n", 172 pr_err("problem processing %d event, skipping it.\n",
147 event->header.type); 173 event->header.type);
148 goto repipe; 174 goto repipe;
149 } 175 }
150 176
151 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 177 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
152 event->ip.pid, event->ip.ip, &al); 178 event->ip.ip, &al);
153 179
154 if (al.map != NULL) { 180 if (al.map != NULL) {
155 if (!al.map->dso->hit) { 181 if (!al.map->dso->hit) {
156 al.map->dso->hit = 1; 182 al.map->dso->hit = 1;
157 if (map__load(al.map, NULL) >= 0) { 183 if (map__load(al.map, NULL) >= 0) {
158 dso__inject_build_id(al.map->dso, session); 184 dso__inject_build_id(al.map->dso, tool, machine);
159 /* 185 /*
160 * If this fails, too bad, let the other side 186 * If this fails, too bad, let the other side
161 * account this as unresolved. 187 * account this as unresolved.
@@ -168,24 +194,24 @@ static int perf_event__inject_buildid(union perf_event *event,
168 } 194 }
169 195
170repipe: 196repipe:
171 perf_event__repipe(event, sample, session); 197 perf_event__repipe(tool, event, sample, machine);
172 return 0; 198 return 0;
173} 199}
174 200
175struct perf_event_ops inject_ops = { 201struct perf_tool perf_inject = {
176 .sample = perf_event__repipe_sample, 202 .sample = perf_event__repipe_sample,
177 .mmap = perf_event__repipe, 203 .mmap = perf_event__repipe,
178 .comm = perf_event__repipe, 204 .comm = perf_event__repipe,
179 .fork = perf_event__repipe, 205 .fork = perf_event__repipe,
180 .exit = perf_event__repipe, 206 .exit = perf_event__repipe,
181 .lost = perf_event__repipe, 207 .lost = perf_event__repipe,
182 .read = perf_event__repipe, 208 .read = perf_event__repipe_sample,
183 .throttle = perf_event__repipe, 209 .throttle = perf_event__repipe,
184 .unthrottle = perf_event__repipe, 210 .unthrottle = perf_event__repipe,
185 .attr = perf_event__repipe_synth, 211 .attr = perf_event__repipe_attr,
186 .event_type = perf_event__repipe_synth, 212 .event_type = perf_event__repipe_event_type_synth,
187 .tracing_data = perf_event__repipe_synth, 213 .tracing_data = perf_event__repipe_tracing_data_synth,
188 .build_id = perf_event__repipe_synth, 214 .build_id = perf_event__repipe_op2_synth,
189}; 215};
190 216
191extern volatile int session_done; 217extern volatile int session_done;
@@ -203,17 +229,17 @@ static int __cmd_inject(void)
203 signal(SIGINT, sig_handler); 229 signal(SIGINT, sig_handler);
204 230
205 if (inject_build_ids) { 231 if (inject_build_ids) {
206 inject_ops.sample = perf_event__inject_buildid; 232 perf_inject.sample = perf_event__inject_buildid;
207 inject_ops.mmap = perf_event__repipe_mmap; 233 perf_inject.mmap = perf_event__repipe_mmap;
208 inject_ops.fork = perf_event__repipe_task; 234 perf_inject.fork = perf_event__repipe_task;
209 inject_ops.tracing_data = perf_event__repipe_tracing_data; 235 perf_inject.tracing_data = perf_event__repipe_tracing_data;
210 } 236 }
211 237
212 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); 238 session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject);
213 if (session == NULL) 239 if (session == NULL)
214 return -ENOMEM; 240 return -ENOMEM;
215 241
216 ret = perf_session__process_events(session, &inject_ops); 242 ret = perf_session__process_events(session, &perf_inject);
217 243
218 perf_session__delete(session); 244 perf_session__delete(session);
219 245
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963df105..fe1ad8f21961 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -7,6 +7,7 @@
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#include "util/session.h"
10#include "util/tool.h"
10 11
11#include "util/parse-options.h" 12#include "util/parse-options.h"
12#include "util/trace-event.h" 13#include "util/trace-event.h"
@@ -18,7 +19,7 @@
18struct alloc_stat; 19struct alloc_stat;
19typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 20typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
20 21
21static char const *input_name = "perf.data"; 22static const char *input_name;
22 23
23static int alloc_flag; 24static int alloc_flag;
24static int caller_flag; 25static int caller_flag;
@@ -303,12 +304,13 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
303 } 304 }
304} 305}
305 306
306static int process_sample_event(union perf_event *event, 307static int process_sample_event(struct perf_tool *tool __used,
308 union perf_event *event,
307 struct perf_sample *sample, 309 struct perf_sample *sample,
308 struct perf_evsel *evsel __used, 310 struct perf_evsel *evsel __used,
309 struct perf_session *session) 311 struct machine *machine)
310{ 312{
311 struct thread *thread = perf_session__findnew(session, event->ip.pid); 313 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
312 314
313 if (thread == NULL) { 315 if (thread == NULL) {
314 pr_debug("problem processing %d event, skipping it.\n", 316 pr_debug("problem processing %d event, skipping it.\n",
@@ -324,7 +326,7 @@ static int process_sample_event(union perf_event *event,
324 return 0; 326 return 0;
325} 327}
326 328
327static struct perf_event_ops event_ops = { 329static struct perf_tool perf_kmem = {
328 .sample = process_sample_event, 330 .sample = process_sample_event,
329 .comm = perf_event__process_comm, 331 .comm = perf_event__process_comm,
330 .ordered_samples = true, 332 .ordered_samples = true,
@@ -483,7 +485,7 @@ static int __cmd_kmem(void)
483{ 485{
484 int err = -EINVAL; 486 int err = -EINVAL;
485 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 487 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
486 0, false, &event_ops); 488 0, false, &perf_kmem);
487 if (session == NULL) 489 if (session == NULL)
488 return -ENOMEM; 490 return -ENOMEM;
489 491
@@ -494,7 +496,7 @@ static int __cmd_kmem(void)
494 goto out_delete; 496 goto out_delete;
495 497
496 setup_pager(); 498 setup_pager();
497 err = perf_session__process_events(session, &event_ops); 499 err = perf_session__process_events(session, &perf_kmem);
498 if (err != 0) 500 if (err != 0)
499 goto out_delete; 501 goto out_delete;
500 sort_result(); 502 sort_result();
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 34d1e853829d..032324a76b87 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -38,7 +38,7 @@ static const struct option kvm_options[] = {
38 OPT_BOOLEAN(0, "guest", &perf_guest, 38 OPT_BOOLEAN(0, "guest", &perf_guest,
39 "Collect guest os data"), 39 "Collect guest os data"),
40 OPT_BOOLEAN(0, "host", &perf_host, 40 OPT_BOOLEAN(0, "host", &perf_host,
41 "Collect guest os data"), 41 "Collect host os data"),
42 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", 42 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
43 "guest mount directory under which every guest os" 43 "guest mount directory under which every guest os"
44 " instance has a subdir"), 44 " instance has a subdir"),
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 899080ace267..2296c391d0f5 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -12,6 +12,7 @@
12 12
13#include "util/debug.h" 13#include "util/debug.h"
14#include "util/session.h" 14#include "util/session.h"
15#include "util/tool.h"
15 16
16#include <sys/types.h> 17#include <sys/types.h>
17#include <sys/prctl.h> 18#include <sys/prctl.h>
@@ -325,7 +326,7 @@ alloc_failed:
325 die("memory allocation failed\n"); 326 die("memory allocation failed\n");
326} 327}
327 328
328static char const *input_name = "perf.data"; 329static const char *input_name;
329 330
330struct raw_event_sample { 331struct raw_event_sample {
331 u32 size; 332 u32 size;
@@ -845,12 +846,13 @@ static void dump_info(void)
845 die("Unknown type of information\n"); 846 die("Unknown type of information\n");
846} 847}
847 848
848static int process_sample_event(union perf_event *event, 849static int process_sample_event(struct perf_tool *tool __used,
850 union perf_event *event,
849 struct perf_sample *sample, 851 struct perf_sample *sample,
850 struct perf_evsel *evsel __used, 852 struct perf_evsel *evsel __used,
851 struct perf_session *s) 853 struct machine *machine)
852{ 854{
853 struct thread *thread = perf_session__findnew(s, sample->tid); 855 struct thread *thread = machine__findnew_thread(machine, sample->tid);
854 856
855 if (thread == NULL) { 857 if (thread == NULL) {
856 pr_debug("problem processing %d event, skipping it.\n", 858 pr_debug("problem processing %d event, skipping it.\n",
@@ -863,7 +865,7 @@ static int process_sample_event(union perf_event *event,
863 return 0; 865 return 0;
864} 866}
865 867
866static struct perf_event_ops eops = { 868static struct perf_tool eops = {
867 .sample = process_sample_event, 869 .sample = process_sample_event,
868 .comm = perf_event__process_comm, 870 .comm = perf_event__process_comm,
869 .ordered_samples = true, 871 .ordered_samples = true,
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 710ae3d0a489..59d43abfbfec 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -46,7 +46,6 @@
46 46
47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" 47#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
48#define DEFAULT_FUNC_FILTER "!_*" 48#define DEFAULT_FUNC_FILTER "!_*"
49#define MAX_PATH_LEN 256
50 49
51/* Session management structure */ 50/* Session management structure */
52static struct { 51static struct {
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6ab58cc99d53..0abfb18b911f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -22,6 +22,7 @@
22#include "util/evsel.h" 22#include "util/evsel.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/session.h" 24#include "util/session.h"
25#include "util/tool.h"
25#include "util/symbol.h" 26#include "util/symbol.h"
26#include "util/cpumap.h" 27#include "util/cpumap.h"
27#include "util/thread_map.h" 28#include "util/thread_map.h"
@@ -35,55 +36,36 @@ enum write_mode_t {
35 WRITE_APPEND 36 WRITE_APPEND
36}; 37};
37 38
38static u64 user_interval = ULLONG_MAX; 39struct perf_record {
39static u64 default_interval = 0; 40 struct perf_tool tool;
40 41 struct perf_record_opts opts;
41static unsigned int page_size; 42 u64 bytes_written;
42static unsigned int mmap_pages = UINT_MAX; 43 const char *output_name;
43static unsigned int user_freq = UINT_MAX; 44 struct perf_evlist *evlist;
44static int freq = 1000; 45 struct perf_session *session;
45static int output; 46 const char *progname;
46static int pipe_output = 0; 47 int output;
47static const char *output_name = NULL; 48 unsigned int page_size;
48static bool group = false; 49 int realtime_prio;
49static int realtime_prio = 0; 50 enum write_mode_t write_mode;
50static bool nodelay = false; 51 bool no_buildid;
51static bool raw_samples = false; 52 bool no_buildid_cache;
52static bool sample_id_all_avail = true; 53 bool force;
53static bool system_wide = false; 54 bool file_new;
54static pid_t target_pid = -1; 55 bool append_file;
55static pid_t target_tid = -1; 56 long samples;
56static pid_t child_pid = -1; 57 off_t post_processing_offset;
57static bool no_inherit = false; 58};
58static enum write_mode_t write_mode = WRITE_FORCE; 59
59static bool call_graph = false; 60static void advance_output(struct perf_record *rec, size_t size)
60static bool inherit_stat = false;
61static bool no_samples = false;
62static bool sample_address = false;
63static bool sample_time = false;
64static bool no_buildid = false;
65static bool no_buildid_cache = false;
66static struct perf_evlist *evsel_list;
67
68static long samples = 0;
69static u64 bytes_written = 0;
70
71static int file_new = 1;
72static off_t post_processing_offset;
73
74static struct perf_session *session;
75static const char *cpu_list;
76static const char *progname;
77
78static void advance_output(size_t size)
79{ 61{
80 bytes_written += size; 62 rec->bytes_written += size;
81} 63}
82 64
83static void write_output(void *buf, size_t size) 65static void write_output(struct perf_record *rec, void *buf, size_t size)
84{ 66{
85 while (size) { 67 while (size) {
86 int ret = write(output, buf, size); 68 int ret = write(rec->output, buf, size);
87 69
88 if (ret < 0) 70 if (ret < 0)
89 die("failed to write"); 71 die("failed to write");
@@ -91,30 +73,33 @@ static void write_output(void *buf, size_t size)
91 size -= ret; 73 size -= ret;
92 buf += ret; 74 buf += ret;
93 75
94 bytes_written += ret; 76 rec->bytes_written += ret;
95 } 77 }
96} 78}
97 79
98static int process_synthesized_event(union perf_event *event, 80static int process_synthesized_event(struct perf_tool *tool,
81 union perf_event *event,
99 struct perf_sample *sample __used, 82 struct perf_sample *sample __used,
100 struct perf_session *self __used) 83 struct machine *machine __used)
101{ 84{
102 write_output(event, event->header.size); 85 struct perf_record *rec = container_of(tool, struct perf_record, tool);
86 write_output(rec, event, event->header.size);
103 return 0; 87 return 0;
104} 88}
105 89
106static void mmap_read(struct perf_mmap *md) 90static void perf_record__mmap_read(struct perf_record *rec,
91 struct perf_mmap *md)
107{ 92{
108 unsigned int head = perf_mmap__read_head(md); 93 unsigned int head = perf_mmap__read_head(md);
109 unsigned int old = md->prev; 94 unsigned int old = md->prev;
110 unsigned char *data = md->base + page_size; 95 unsigned char *data = md->base + rec->page_size;
111 unsigned long size; 96 unsigned long size;
112 void *buf; 97 void *buf;
113 98
114 if (old == head) 99 if (old == head)
115 return; 100 return;
116 101
117 samples++; 102 rec->samples++;
118 103
119 size = head - old; 104 size = head - old;
120 105
@@ -123,14 +108,14 @@ static void mmap_read(struct perf_mmap *md)
123 size = md->mask + 1 - (old & md->mask); 108 size = md->mask + 1 - (old & md->mask);
124 old += size; 109 old += size;
125 110
126 write_output(buf, size); 111 write_output(rec, buf, size);
127 } 112 }
128 113
129 buf = &data[old & md->mask]; 114 buf = &data[old & md->mask];
130 size = head - old; 115 size = head - old;
131 old += size; 116 old += size;
132 117
133 write_output(buf, size); 118 write_output(rec, buf, size);
134 119
135 md->prev = old; 120 md->prev = old;
136 perf_mmap__write_tail(md, old); 121 perf_mmap__write_tail(md, old);
@@ -149,17 +134,18 @@ static void sig_handler(int sig)
149 signr = sig; 134 signr = sig;
150} 135}
151 136
152static void sig_atexit(void) 137static void perf_record__sig_exit(int exit_status __used, void *arg)
153{ 138{
139 struct perf_record *rec = arg;
154 int status; 140 int status;
155 141
156 if (child_pid > 0) { 142 if (rec->evlist->workload.pid > 0) {
157 if (!child_finished) 143 if (!child_finished)
158 kill(child_pid, SIGTERM); 144 kill(rec->evlist->workload.pid, SIGTERM);
159 145
160 wait(&status); 146 wait(&status);
161 if (WIFSIGNALED(status)) 147 if (WIFSIGNALED(status))
162 psignal(WTERMSIG(status), progname); 148 psignal(WTERMSIG(status), rec->progname);
163 } 149 }
164 150
165 if (signr == -1 || signr == SIGUSR1) 151 if (signr == -1 || signr == SIGUSR1)
@@ -169,78 +155,6 @@ static void sig_atexit(void)
169 kill(getpid(), signr); 155 kill(getpid(), signr);
170} 156}
171 157
172static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist)
173{
174 struct perf_event_attr *attr = &evsel->attr;
175 int track = !evsel->idx; /* only the first counter needs these */
176
177 attr->disabled = 1;
178 attr->inherit = !no_inherit;
179 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
180 PERF_FORMAT_TOTAL_TIME_RUNNING |
181 PERF_FORMAT_ID;
182
183 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
184
185 if (evlist->nr_entries > 1)
186 attr->sample_type |= PERF_SAMPLE_ID;
187
188 /*
189 * We default some events to a 1 default interval. But keep
190 * it a weak assumption overridable by the user.
191 */
192 if (!attr->sample_period || (user_freq != UINT_MAX &&
193 user_interval != ULLONG_MAX)) {
194 if (freq) {
195 attr->sample_type |= PERF_SAMPLE_PERIOD;
196 attr->freq = 1;
197 attr->sample_freq = freq;
198 } else {
199 attr->sample_period = default_interval;
200 }
201 }
202
203 if (no_samples)
204 attr->sample_freq = 0;
205
206 if (inherit_stat)
207 attr->inherit_stat = 1;
208
209 if (sample_address) {
210 attr->sample_type |= PERF_SAMPLE_ADDR;
211 attr->mmap_data = track;
212 }
213
214 if (call_graph)
215 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
216
217 if (system_wide)
218 attr->sample_type |= PERF_SAMPLE_CPU;
219
220 if (sample_id_all_avail &&
221 (sample_time || system_wide || !no_inherit || cpu_list))
222 attr->sample_type |= PERF_SAMPLE_TIME;
223
224 if (raw_samples) {
225 attr->sample_type |= PERF_SAMPLE_TIME;
226 attr->sample_type |= PERF_SAMPLE_RAW;
227 attr->sample_type |= PERF_SAMPLE_CPU;
228 }
229
230 if (nodelay) {
231 attr->watermark = 0;
232 attr->wakeup_events = 1;
233 }
234
235 attr->mmap = track;
236 attr->comm = track;
237
238 if (target_pid == -1 && target_tid == -1 && !system_wide) {
239 attr->disabled = 1;
240 attr->enable_on_exec = 1;
241 }
242}
243
244static bool perf_evlist__equal(struct perf_evlist *evlist, 158static bool perf_evlist__equal(struct perf_evlist *evlist,
245 struct perf_evlist *other) 159 struct perf_evlist *other)
246{ 160{
@@ -260,15 +174,17 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
260 return true; 174 return true;
261} 175}
262 176
263static void open_counters(struct perf_evlist *evlist) 177static void perf_record__open(struct perf_record *rec)
264{ 178{
265 struct perf_evsel *pos, *first; 179 struct perf_evsel *pos, *first;
266 180 struct perf_evlist *evlist = rec->evlist;
267 if (evlist->cpus->map[0] < 0) 181 struct perf_session *session = rec->session;
268 no_inherit = true; 182 struct perf_record_opts *opts = &rec->opts;
269 183
270 first = list_entry(evlist->entries.next, struct perf_evsel, node); 184 first = list_entry(evlist->entries.next, struct perf_evsel, node);
271 185
186 perf_evlist__config_attrs(evlist, opts);
187
272 list_for_each_entry(pos, &evlist->entries, node) { 188 list_for_each_entry(pos, &evlist->entries, node) {
273 struct perf_event_attr *attr = &pos->attr; 189 struct perf_event_attr *attr = &pos->attr;
274 struct xyarray *group_fd = NULL; 190 struct xyarray *group_fd = NULL;
@@ -286,29 +202,27 @@ static void open_counters(struct perf_evlist *evlist)
286 */ 202 */
287 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; 203 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
288 204
289 if (group && pos != first) 205 if (opts->group && pos != first)
290 group_fd = first->fd; 206 group_fd = first->fd;
291
292 config_attr(pos, evlist);
293retry_sample_id: 207retry_sample_id:
294 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 208 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
295try_again: 209try_again:
296 if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, 210 if (perf_evsel__open(pos, evlist->cpus, evlist->threads,
297 group_fd) < 0) { 211 opts->group, group_fd) < 0) {
298 int err = errno; 212 int err = errno;
299 213
300 if (err == EPERM || err == EACCES) { 214 if (err == EPERM || err == EACCES) {
301 ui__error_paranoid(); 215 ui__error_paranoid();
302 exit(EXIT_FAILURE); 216 exit(EXIT_FAILURE);
303 } else if (err == ENODEV && cpu_list) { 217 } else if (err == ENODEV && opts->cpu_list) {
304 die("No such device - did you specify" 218 die("No such device - did you specify"
305 " an out-of-range profile CPU?\n"); 219 " an out-of-range profile CPU?\n");
306 } else if (err == EINVAL && sample_id_all_avail) { 220 } else if (err == EINVAL && opts->sample_id_all_avail) {
307 /* 221 /*
308 * Old kernel, no attr->sample_id_type_all field 222 * Old kernel, no attr->sample_id_type_all field
309 */ 223 */
310 sample_id_all_avail = false; 224 opts->sample_id_all_avail = false;
311 if (!sample_time && !raw_samples && !time_needed) 225 if (!opts->sample_time && !opts->raw_samples && !time_needed)
312 attr->sample_type &= ~PERF_SAMPLE_TIME; 226 attr->sample_type &= ~PERF_SAMPLE_TIME;
313 227
314 goto retry_sample_id; 228 goto retry_sample_id;
@@ -358,10 +272,20 @@ try_again:
358 exit(-1); 272 exit(-1);
359 } 273 }
360 274
361 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) 275 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
276 if (errno == EPERM)
277 die("Permission error mapping pages.\n"
278 "Consider increasing "
279 "/proc/sys/kernel/perf_event_mlock_kb,\n"
280 "or try again with a smaller value of -m/--mmap_pages.\n"
281 "(current value: %d)\n", opts->mmap_pages);
282 else if (!is_power_of_2(opts->mmap_pages))
283 die("--mmap_pages/-m value must be a power of two.");
284
362 die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 285 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
286 }
363 287
364 if (file_new) 288 if (rec->file_new)
365 session->evlist = evlist; 289 session->evlist = evlist;
366 else { 290 else {
367 if (!perf_evlist__equal(session->evlist, evlist)) { 291 if (!perf_evlist__equal(session->evlist, evlist)) {
@@ -373,29 +297,32 @@ try_again:
373 perf_session__update_sample_type(session); 297 perf_session__update_sample_type(session);
374} 298}
375 299
376static int process_buildids(void) 300static int process_buildids(struct perf_record *rec)
377{ 301{
378 u64 size = lseek(output, 0, SEEK_CUR); 302 u64 size = lseek(rec->output, 0, SEEK_CUR);
379 303
380 if (size == 0) 304 if (size == 0)
381 return 0; 305 return 0;
382 306
383 session->fd = output; 307 rec->session->fd = rec->output;
384 return __perf_session__process_events(session, post_processing_offset, 308 return __perf_session__process_events(rec->session, rec->post_processing_offset,
385 size - post_processing_offset, 309 size - rec->post_processing_offset,
386 size, &build_id__mark_dso_hit_ops); 310 size, &build_id__mark_dso_hit_ops);
387} 311}
388 312
389static void atexit_header(void) 313static void perf_record__exit(int status __used, void *arg)
390{ 314{
391 if (!pipe_output) { 315 struct perf_record *rec = arg;
392 session->header.data_size += bytes_written; 316
393 317 if (!rec->opts.pipe_output) {
394 if (!no_buildid) 318 rec->session->header.data_size += rec->bytes_written;
395 process_buildids(); 319
396 perf_session__write_header(session, evsel_list, output, true); 320 if (!rec->no_buildid)
397 perf_session__delete(session); 321 process_buildids(rec);
398 perf_evlist__delete(evsel_list); 322 perf_session__write_header(rec->session, rec->evlist,
323 rec->output, true);
324 perf_session__delete(rec->session);
325 perf_evlist__delete(rec->evlist);
399 symbol__exit(); 326 symbol__exit();
400 } 327 }
401} 328}
@@ -403,7 +330,7 @@ static void atexit_header(void)
403static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 330static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
404{ 331{
405 int err; 332 int err;
406 struct perf_session *psession = data; 333 struct perf_tool *tool = data;
407 334
408 if (machine__is_host(machine)) 335 if (machine__is_host(machine))
409 return; 336 return;
@@ -416,8 +343,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
416 *method is used to avoid symbol missing when the first addr is 343 *method is used to avoid symbol missing when the first addr is
417 *in module instead of in guest kernel. 344 *in module instead of in guest kernel.
418 */ 345 */
419 err = perf_event__synthesize_modules(process_synthesized_event, 346 err = perf_event__synthesize_modules(tool, process_synthesized_event,
420 psession, machine); 347 machine);
421 if (err < 0) 348 if (err < 0)
422 pr_err("Couldn't record guest kernel [%d]'s reference" 349 pr_err("Couldn't record guest kernel [%d]'s reference"
423 " relocation symbol.\n", machine->pid); 350 " relocation symbol.\n", machine->pid);
@@ -426,12 +353,11 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
426 * We use _stext for guest kernel because guest kernel's /proc/kallsyms 353 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
427 * have no _text sometimes. 354 * have no _text sometimes.
428 */ 355 */
429 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 356 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
430 psession, machine, "_text"); 357 machine, "_text");
431 if (err < 0) 358 if (err < 0)
432 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 359 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
433 psession, machine, 360 machine, "_stext");
434 "_stext");
435 if (err < 0) 361 if (err < 0)
436 pr_err("Couldn't record guest kernel [%d]'s reference" 362 pr_err("Couldn't record guest kernel [%d]'s reference"
437 " relocation symbol.\n", machine->pid); 363 " relocation symbol.\n", machine->pid);
@@ -442,73 +368,71 @@ static struct perf_event_header finished_round_event = {
442 .type = PERF_RECORD_FINISHED_ROUND, 368 .type = PERF_RECORD_FINISHED_ROUND,
443}; 369};
444 370
445static void mmap_read_all(void) 371static void perf_record__mmap_read_all(struct perf_record *rec)
446{ 372{
447 int i; 373 int i;
448 374
449 for (i = 0; i < evsel_list->nr_mmaps; i++) { 375 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
450 if (evsel_list->mmap[i].base) 376 if (rec->evlist->mmap[i].base)
451 mmap_read(&evsel_list->mmap[i]); 377 perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
452 } 378 }
453 379
454 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) 380 if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
455 write_output(&finished_round_event, sizeof(finished_round_event)); 381 write_output(rec, &finished_round_event, sizeof(finished_round_event));
456} 382}
457 383
458static int __cmd_record(int argc, const char **argv) 384static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
459{ 385{
460 struct stat st; 386 struct stat st;
461 int flags; 387 int flags;
462 int err; 388 int err, output;
463 unsigned long waking = 0; 389 unsigned long waking = 0;
464 int child_ready_pipe[2], go_pipe[2];
465 const bool forks = argc > 0; 390 const bool forks = argc > 0;
466 char buf;
467 struct machine *machine; 391 struct machine *machine;
392 struct perf_tool *tool = &rec->tool;
393 struct perf_record_opts *opts = &rec->opts;
394 struct perf_evlist *evsel_list = rec->evlist;
395 const char *output_name = rec->output_name;
396 struct perf_session *session;
468 397
469 progname = argv[0]; 398 rec->progname = argv[0];
470 399
471 page_size = sysconf(_SC_PAGE_SIZE); 400 rec->page_size = sysconf(_SC_PAGE_SIZE);
472 401
473 atexit(sig_atexit); 402 on_exit(perf_record__sig_exit, rec);
474 signal(SIGCHLD, sig_handler); 403 signal(SIGCHLD, sig_handler);
475 signal(SIGINT, sig_handler); 404 signal(SIGINT, sig_handler);
476 signal(SIGUSR1, sig_handler); 405 signal(SIGUSR1, sig_handler);
477 406
478 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
479 perror("failed to create pipes");
480 exit(-1);
481 }
482
483 if (!output_name) { 407 if (!output_name) {
484 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) 408 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
485 pipe_output = 1; 409 opts->pipe_output = true;
486 else 410 else
487 output_name = "perf.data"; 411 rec->output_name = output_name = "perf.data";
488 } 412 }
489 if (output_name) { 413 if (output_name) {
490 if (!strcmp(output_name, "-")) 414 if (!strcmp(output_name, "-"))
491 pipe_output = 1; 415 opts->pipe_output = true;
492 else if (!stat(output_name, &st) && st.st_size) { 416 else if (!stat(output_name, &st) && st.st_size) {
493 if (write_mode == WRITE_FORCE) { 417 if (rec->write_mode == WRITE_FORCE) {
494 char oldname[PATH_MAX]; 418 char oldname[PATH_MAX];
495 snprintf(oldname, sizeof(oldname), "%s.old", 419 snprintf(oldname, sizeof(oldname), "%s.old",
496 output_name); 420 output_name);
497 unlink(oldname); 421 unlink(oldname);
498 rename(output_name, oldname); 422 rename(output_name, oldname);
499 } 423 }
500 } else if (write_mode == WRITE_APPEND) { 424 } else if (rec->write_mode == WRITE_APPEND) {
501 write_mode = WRITE_FORCE; 425 rec->write_mode = WRITE_FORCE;
502 } 426 }
503 } 427 }
504 428
505 flags = O_CREAT|O_RDWR; 429 flags = O_CREAT|O_RDWR;
506 if (write_mode == WRITE_APPEND) 430 if (rec->write_mode == WRITE_APPEND)
507 file_new = 0; 431 rec->file_new = 0;
508 else 432 else
509 flags |= O_TRUNC; 433 flags |= O_TRUNC;
510 434
511 if (pipe_output) 435 if (opts->pipe_output)
512 output = STDOUT_FILENO; 436 output = STDOUT_FILENO;
513 else 437 else
514 output = open(output_name, flags, S_IRUSR | S_IWUSR); 438 output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -517,17 +441,21 @@ static int __cmd_record(int argc, const char **argv)
517 exit(-1); 441 exit(-1);
518 } 442 }
519 443
444 rec->output = output;
445
520 session = perf_session__new(output_name, O_WRONLY, 446 session = perf_session__new(output_name, O_WRONLY,
521 write_mode == WRITE_FORCE, false, NULL); 447 rec->write_mode == WRITE_FORCE, false, NULL);
522 if (session == NULL) { 448 if (session == NULL) {
523 pr_err("Not enough memory for reading perf file header\n"); 449 pr_err("Not enough memory for reading perf file header\n");
524 return -1; 450 return -1;
525 } 451 }
526 452
527 if (!no_buildid) 453 rec->session = session;
454
455 if (!rec->no_buildid)
528 perf_header__set_feat(&session->header, HEADER_BUILD_ID); 456 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
529 457
530 if (!file_new) { 458 if (!rec->file_new) {
531 err = perf_session__read_header(session, output); 459 err = perf_session__read_header(session, output);
532 if (err < 0) 460 if (err < 0)
533 goto out_delete_session; 461 goto out_delete_session;
@@ -549,94 +477,57 @@ static int __cmd_record(int argc, const char **argv)
549 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY); 477 perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY);
550 perf_header__set_feat(&session->header, HEADER_CPUID); 478 perf_header__set_feat(&session->header, HEADER_CPUID);
551 479
552 /* 512 kiB: default amount of unprivileged mlocked memory */
553 if (mmap_pages == UINT_MAX)
554 mmap_pages = (512 * 1024) / page_size;
555
556 if (forks) { 480 if (forks) {
557 child_pid = fork(); 481 err = perf_evlist__prepare_workload(evsel_list, opts, argv);
558 if (child_pid < 0) { 482 if (err < 0) {
559 perror("failed to fork"); 483 pr_err("Couldn't run the workload!\n");
560 exit(-1); 484 goto out_delete_session;
561 }
562
563 if (!child_pid) {
564 if (pipe_output)
565 dup2(2, 1);
566 close(child_ready_pipe[0]);
567 close(go_pipe[1]);
568 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
569
570 /*
571 * Do a dummy execvp to get the PLT entry resolved,
572 * so we avoid the resolver overhead on the real
573 * execvp call.
574 */
575 execvp("", (char **)argv);
576
577 /*
578 * Tell the parent we're ready to go
579 */
580 close(child_ready_pipe[1]);
581
582 /*
583 * Wait until the parent tells us to go.
584 */
585 if (read(go_pipe[0], &buf, 1) == -1)
586 perror("unable to read pipe");
587
588 execvp(argv[0], (char **)argv);
589
590 perror(argv[0]);
591 kill(getppid(), SIGUSR1);
592 exit(-1);
593 }
594
595 if (!system_wide && target_tid == -1 && target_pid == -1)
596 evsel_list->threads->map[0] = child_pid;
597
598 close(child_ready_pipe[1]);
599 close(go_pipe[0]);
600 /*
601 * wait for child to settle
602 */
603 if (read(child_ready_pipe[0], &buf, 1) == -1) {
604 perror("unable to read pipe");
605 exit(-1);
606 } 485 }
607 close(child_ready_pipe[0]);
608 } 486 }
609 487
610 open_counters(evsel_list); 488 perf_record__open(rec);
611 489
612 /* 490 /*
613 * perf_session__delete(session) will be called at atexit_header() 491 * perf_session__delete(session) will be called at perf_record__exit()
614 */ 492 */
615 atexit(atexit_header); 493 on_exit(perf_record__exit, rec);
616 494
617 if (pipe_output) { 495 if (opts->pipe_output) {
618 err = perf_header__write_pipe(output); 496 err = perf_header__write_pipe(output);
619 if (err < 0) 497 if (err < 0)
620 return err; 498 return err;
621 } else if (file_new) { 499 } else if (rec->file_new) {
622 err = perf_session__write_header(session, evsel_list, 500 err = perf_session__write_header(session, evsel_list,
623 output, false); 501 output, false);
624 if (err < 0) 502 if (err < 0)
625 return err; 503 return err;
626 } 504 }
627 505
628 post_processing_offset = lseek(output, 0, SEEK_CUR); 506 if (!!rec->no_buildid
507 && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) {
508 pr_err("Couldn't generating buildids. "
509 "Use --no-buildid to profile anyway.\n");
510 return -1;
511 }
629 512
630 if (pipe_output) { 513 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
631 err = perf_session__synthesize_attrs(session, 514
632 process_synthesized_event); 515 machine = perf_session__find_host_machine(session);
516 if (!machine) {
517 pr_err("Couldn't find native kernel information.\n");
518 return -1;
519 }
520
521 if (opts->pipe_output) {
522 err = perf_event__synthesize_attrs(tool, session,
523 process_synthesized_event);
633 if (err < 0) { 524 if (err < 0) {
634 pr_err("Couldn't synthesize attrs.\n"); 525 pr_err("Couldn't synthesize attrs.\n");
635 return err; 526 return err;
636 } 527 }
637 528
638 err = perf_event__synthesize_event_types(process_synthesized_event, 529 err = perf_event__synthesize_event_types(tool, process_synthesized_event,
639 session); 530 machine);
640 if (err < 0) { 531 if (err < 0) {
641 pr_err("Couldn't synthesize event_types.\n"); 532 pr_err("Couldn't synthesize event_types.\n");
642 return err; 533 return err;
@@ -651,56 +542,49 @@ static int __cmd_record(int argc, const char **argv)
651 * return this more properly and also 542 * return this more properly and also
652 * propagate errors that now are calling die() 543 * propagate errors that now are calling die()
653 */ 544 */
654 err = perf_event__synthesize_tracing_data(output, evsel_list, 545 err = perf_event__synthesize_tracing_data(tool, output, evsel_list,
655 process_synthesized_event, 546 process_synthesized_event);
656 session);
657 if (err <= 0) { 547 if (err <= 0) {
658 pr_err("Couldn't record tracing data.\n"); 548 pr_err("Couldn't record tracing data.\n");
659 return err; 549 return err;
660 } 550 }
661 advance_output(err); 551 advance_output(rec, err);
662 } 552 }
663 } 553 }
664 554
665 machine = perf_session__find_host_machine(session); 555 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
666 if (!machine) { 556 machine, "_text");
667 pr_err("Couldn't find native kernel information.\n");
668 return -1;
669 }
670
671 err = perf_event__synthesize_kernel_mmap(process_synthesized_event,
672 session, machine, "_text");
673 if (err < 0) 557 if (err < 0)
674 err = perf_event__synthesize_kernel_mmap(process_synthesized_event, 558 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
675 session, machine, "_stext"); 559 machine, "_stext");
676 if (err < 0) 560 if (err < 0)
677 pr_err("Couldn't record kernel reference relocation symbol\n" 561 pr_err("Couldn't record kernel reference relocation symbol\n"
678 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 562 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
679 "Check /proc/kallsyms permission or run as root.\n"); 563 "Check /proc/kallsyms permission or run as root.\n");
680 564
681 err = perf_event__synthesize_modules(process_synthesized_event, 565 err = perf_event__synthesize_modules(tool, process_synthesized_event,
682 session, machine); 566 machine);
683 if (err < 0) 567 if (err < 0)
684 pr_err("Couldn't record kernel module information.\n" 568 pr_err("Couldn't record kernel module information.\n"
685 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 569 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
686 "Check /proc/modules permission or run as root.\n"); 570 "Check /proc/modules permission or run as root.\n");
687 571
688 if (perf_guest) 572 if (perf_guest)
689 perf_session__process_machines(session, 573 perf_session__process_machines(session, tool,
690 perf_event__synthesize_guest_os); 574 perf_event__synthesize_guest_os);
691 575
692 if (!system_wide) 576 if (!opts->system_wide)
693 perf_event__synthesize_thread_map(evsel_list->threads, 577 perf_event__synthesize_thread_map(tool, evsel_list->threads,
694 process_synthesized_event, 578 process_synthesized_event,
695 session); 579 machine);
696 else 580 else
697 perf_event__synthesize_threads(process_synthesized_event, 581 perf_event__synthesize_threads(tool, process_synthesized_event,
698 session); 582 machine);
699 583
700 if (realtime_prio) { 584 if (rec->realtime_prio) {
701 struct sched_param param; 585 struct sched_param param;
702 586
703 param.sched_priority = realtime_prio; 587 param.sched_priority = rec->realtime_prio;
704 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 588 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
705 pr_err("Could not set realtime priority.\n"); 589 pr_err("Could not set realtime priority.\n");
706 exit(-1); 590 exit(-1);
@@ -713,14 +597,14 @@ static int __cmd_record(int argc, const char **argv)
713 * Let the child rip 597 * Let the child rip
714 */ 598 */
715 if (forks) 599 if (forks)
716 close(go_pipe[1]); 600 perf_evlist__start_workload(evsel_list);
717 601
718 for (;;) { 602 for (;;) {
719 int hits = samples; 603 int hits = rec->samples;
720 604
721 mmap_read_all(); 605 perf_record__mmap_read_all(rec);
722 606
723 if (hits == samples) { 607 if (hits == rec->samples) {
724 if (done) 608 if (done)
725 break; 609 break;
726 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 610 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1);
@@ -741,9 +625,9 @@ static int __cmd_record(int argc, const char **argv)
741 */ 625 */
742 fprintf(stderr, 626 fprintf(stderr,
743 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 627 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
744 (double)bytes_written / 1024.0 / 1024.0, 628 (double)rec->bytes_written / 1024.0 / 1024.0,
745 output_name, 629 output_name,
746 bytes_written / 24); 630 rec->bytes_written / 24);
747 631
748 return 0; 632 return 0;
749 633
@@ -758,58 +642,89 @@ static const char * const record_usage[] = {
758 NULL 642 NULL
759}; 643};
760 644
761static bool force, append_file; 645/*
646 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new
647 * because we need to have access to it in perf_record__exit, that is called
648 * after cmd_record() exits, but since record_options need to be accessible to
649 * builtin-script, leave it here.
650 *
651 * At least we don't ouch it in all the other functions here directly.
652 *
653 * Just say no to tons of global variables, sigh.
654 */
655static struct perf_record record = {
656 .opts = {
657 .target_pid = -1,
658 .target_tid = -1,
659 .mmap_pages = UINT_MAX,
660 .user_freq = UINT_MAX,
661 .user_interval = ULLONG_MAX,
662 .freq = 1000,
663 .sample_id_all_avail = true,
664 },
665 .write_mode = WRITE_FORCE,
666 .file_new = true,
667};
762 668
669/*
670 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
671 * with it and switch to use the library functions in perf_evlist that came
672 * from builtin-record.c, i.e. use perf_record_opts,
673 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
674 * using pipes, etc.
675 */
763const struct option record_options[] = { 676const struct option record_options[] = {
764 OPT_CALLBACK('e', "event", &evsel_list, "event", 677 OPT_CALLBACK('e', "event", &record.evlist, "event",
765 "event selector. use 'perf list' to list available events", 678 "event selector. use 'perf list' to list available events",
766 parse_events_option), 679 parse_events_option),
767 OPT_CALLBACK(0, "filter", &evsel_list, "filter", 680 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
768 "event filter", parse_filter), 681 "event filter", parse_filter),
769 OPT_INTEGER('p', "pid", &target_pid, 682 OPT_INTEGER('p', "pid", &record.opts.target_pid,
770 "record events on existing process id"), 683 "record events on existing process id"),
771 OPT_INTEGER('t', "tid", &target_tid, 684 OPT_INTEGER('t', "tid", &record.opts.target_tid,
772 "record events on existing thread id"), 685 "record events on existing thread id"),
773 OPT_INTEGER('r', "realtime", &realtime_prio, 686 OPT_INTEGER('r', "realtime", &record.realtime_prio,
774 "collect data with this RT SCHED_FIFO priority"), 687 "collect data with this RT SCHED_FIFO priority"),
775 OPT_BOOLEAN('D', "no-delay", &nodelay, 688 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay,
776 "collect data without buffering"), 689 "collect data without buffering"),
777 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 690 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
778 "collect raw sample records from all opened counters"), 691 "collect raw sample records from all opened counters"),
779 OPT_BOOLEAN('a', "all-cpus", &system_wide, 692 OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
780 "system-wide collection from all CPUs"), 693 "system-wide collection from all CPUs"),
781 OPT_BOOLEAN('A', "append", &append_file, 694 OPT_BOOLEAN('A', "append", &record.append_file,
782 "append to the output file to do incremental profiling"), 695 "append to the output file to do incremental profiling"),
783 OPT_STRING('C', "cpu", &cpu_list, "cpu", 696 OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
784 "list of cpus to monitor"), 697 "list of cpus to monitor"),
785 OPT_BOOLEAN('f', "force", &force, 698 OPT_BOOLEAN('f', "force", &record.force,
786 "overwrite existing data file (deprecated)"), 699 "overwrite existing data file (deprecated)"),
787 OPT_U64('c', "count", &user_interval, "event period to sample"), 700 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
788 OPT_STRING('o', "output", &output_name, "file", 701 OPT_STRING('o', "output", &record.output_name, "file",
789 "output file name"), 702 "output file name"),
790 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 703 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
791 "child tasks do not inherit counters"), 704 "child tasks do not inherit counters"),
792 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), 705 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
793 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 706 OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages,
794 OPT_BOOLEAN(0, "group", &group, 707 "number of mmap data pages"),
708 OPT_BOOLEAN(0, "group", &record.opts.group,
795 "put the counters into a counter group"), 709 "put the counters into a counter group"),
796 OPT_BOOLEAN('g', "call-graph", &call_graph, 710 OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph,
797 "do call-graph (stack chain/backtrace) recording"), 711 "do call-graph (stack chain/backtrace) recording"),
798 OPT_INCR('v', "verbose", &verbose, 712 OPT_INCR('v', "verbose", &verbose,
799 "be more verbose (show counter open errors, etc)"), 713 "be more verbose (show counter open errors, etc)"),
800 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 714 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
801 OPT_BOOLEAN('s', "stat", &inherit_stat, 715 OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat,
802 "per thread counts"), 716 "per thread counts"),
803 OPT_BOOLEAN('d', "data", &sample_address, 717 OPT_BOOLEAN('d', "data", &record.opts.sample_address,
804 "Sample addresses"), 718 "Sample addresses"),
805 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), 719 OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"),
806 OPT_BOOLEAN('n', "no-samples", &no_samples, 720 OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"),
721 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
807 "don't sample"), 722 "don't sample"),
808 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, 723 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache,
809 "do not update the buildid cache"), 724 "do not update the buildid cache"),
810 OPT_BOOLEAN('B', "no-buildid", &no_buildid, 725 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid,
811 "do not collect buildids in perf.data"), 726 "do not collect buildids in perf.data"),
812 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 727 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
813 "monitor event in cgroup name only", 728 "monitor event in cgroup name only",
814 parse_cgroups), 729 parse_cgroups),
815 OPT_END() 730 OPT_END()
@@ -819,6 +734,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
819{ 734{
820 int err = -ENOMEM; 735 int err = -ENOMEM;
821 struct perf_evsel *pos; 736 struct perf_evsel *pos;
737 struct perf_evlist *evsel_list;
738 struct perf_record *rec = &record;
822 739
823 perf_header__set_cmdline(argc, argv); 740 perf_header__set_cmdline(argc, argv);
824 741
@@ -826,23 +743,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
826 if (evsel_list == NULL) 743 if (evsel_list == NULL)
827 return -ENOMEM; 744 return -ENOMEM;
828 745
746 rec->evlist = evsel_list;
747
829 argc = parse_options(argc, argv, record_options, record_usage, 748 argc = parse_options(argc, argv, record_options, record_usage,
830 PARSE_OPT_STOP_AT_NON_OPTION); 749 PARSE_OPT_STOP_AT_NON_OPTION);
831 if (!argc && target_pid == -1 && target_tid == -1 && 750 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
832 !system_wide && !cpu_list) 751 !rec->opts.system_wide && !rec->opts.cpu_list)
833 usage_with_options(record_usage, record_options); 752 usage_with_options(record_usage, record_options);
834 753
835 if (force && append_file) { 754 if (rec->force && rec->append_file) {
836 fprintf(stderr, "Can't overwrite and append at the same time." 755 fprintf(stderr, "Can't overwrite and append at the same time."
837 " You need to choose between -f and -A"); 756 " You need to choose between -f and -A");
838 usage_with_options(record_usage, record_options); 757 usage_with_options(record_usage, record_options);
839 } else if (append_file) { 758 } else if (rec->append_file) {
840 write_mode = WRITE_APPEND; 759 rec->write_mode = WRITE_APPEND;
841 } else { 760 } else {
842 write_mode = WRITE_FORCE; 761 rec->write_mode = WRITE_FORCE;
843 } 762 }
844 763
845 if (nr_cgroups && !system_wide) { 764 if (nr_cgroups && !rec->opts.system_wide) {
846 fprintf(stderr, "cgroup monitoring only available in" 765 fprintf(stderr, "cgroup monitoring only available in"
847 " system-wide mode\n"); 766 " system-wide mode\n");
848 usage_with_options(record_usage, record_options); 767 usage_with_options(record_usage, record_options);
@@ -860,7 +779,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
860"If some relocation was applied (e.g. kexec) symbols may be misresolved\n" 779"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
861"even with a suitable vmlinux or kallsyms file.\n\n"); 780"even with a suitable vmlinux or kallsyms file.\n\n");
862 781
863 if (no_buildid_cache || no_buildid) 782 if (rec->no_buildid_cache || rec->no_buildid)
864 disable_buildid_cache(); 783 disable_buildid_cache();
865 784
866 if (evsel_list->nr_entries == 0 && 785 if (evsel_list->nr_entries == 0 &&
@@ -869,43 +788,37 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
869 goto out_symbol_exit; 788 goto out_symbol_exit;
870 } 789 }
871 790
872 if (target_pid != -1) 791 if (rec->opts.target_pid != -1)
873 target_tid = target_pid; 792 rec->opts.target_tid = rec->opts.target_pid;
874 793
875 if (perf_evlist__create_maps(evsel_list, target_pid, 794 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
876 target_tid, cpu_list) < 0) 795 rec->opts.target_tid, rec->opts.cpu_list) < 0)
877 usage_with_options(record_usage, record_options); 796 usage_with_options(record_usage, record_options);
878 797
879 list_for_each_entry(pos, &evsel_list->entries, node) { 798 list_for_each_entry(pos, &evsel_list->entries, node) {
880 if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr,
881 evsel_list->threads->nr) < 0)
882 goto out_free_fd;
883 if (perf_header__push_event(pos->attr.config, event_name(pos))) 799 if (perf_header__push_event(pos->attr.config, event_name(pos)))
884 goto out_free_fd; 800 goto out_free_fd;
885 } 801 }
886 802
887 if (perf_evlist__alloc_pollfd(evsel_list) < 0) 803 if (rec->opts.user_interval != ULLONG_MAX)
888 goto out_free_fd; 804 rec->opts.default_interval = rec->opts.user_interval;
889 805 if (rec->opts.user_freq != UINT_MAX)
890 if (user_interval != ULLONG_MAX) 806 rec->opts.freq = rec->opts.user_freq;
891 default_interval = user_interval;
892 if (user_freq != UINT_MAX)
893 freq = user_freq;
894 807
895 /* 808 /*
896 * User specified count overrides default frequency. 809 * User specified count overrides default frequency.
897 */ 810 */
898 if (default_interval) 811 if (rec->opts.default_interval)
899 freq = 0; 812 rec->opts.freq = 0;
900 else if (freq) { 813 else if (rec->opts.freq) {
901 default_interval = freq; 814 rec->opts.default_interval = rec->opts.freq;
902 } else { 815 } else {
903 fprintf(stderr, "frequency and count are zero, aborting\n"); 816 fprintf(stderr, "frequency and count are zero, aborting\n");
904 err = -EINVAL; 817 err = -EINVAL;
905 goto out_free_fd; 818 goto out_free_fd;
906 } 819 }
907 820
908 err = __cmd_record(argc, argv); 821 err = __cmd_record(&record, argc, argv);
909out_free_fd: 822out_free_fd:
910 perf_evlist__delete_maps(evsel_list); 823 perf_evlist__delete_maps(evsel_list);
911out_symbol_exit: 824out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 4d7c8340c326..25d34d483e49 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -25,6 +25,7 @@
25#include "util/evsel.h" 25#include "util/evsel.h"
26#include "util/header.h" 26#include "util/header.h"
27#include "util/session.h" 27#include "util/session.h"
28#include "util/tool.h"
28 29
29#include "util/parse-options.h" 30#include "util/parse-options.h"
30#include "util/parse-events.h" 31#include "util/parse-events.h"
@@ -35,38 +36,35 @@
35 36
36#include <linux/bitmap.h> 37#include <linux/bitmap.h>
37 38
38static char const *input_name = "perf.data"; 39struct perf_report {
39 40 struct perf_tool tool;
40static bool force, use_tui, use_stdio; 41 struct perf_session *session;
41static bool hide_unresolved; 42 char const *input_name;
42static bool dont_use_callchains; 43 bool force, use_tui, use_stdio;
43static bool show_full_info; 44 bool hide_unresolved;
44 45 bool dont_use_callchains;
45static bool show_threads; 46 bool show_full_info;
46static struct perf_read_values show_threads_values; 47 bool show_threads;
47 48 bool inverted_callchain;
48static const char default_pretty_printing_style[] = "normal"; 49 struct perf_read_values show_threads_values;
49static const char *pretty_printing_style = default_pretty_printing_style; 50 const char *pretty_printing_style;
50 51 symbol_filter_t annotate_init;
51static char callchain_default_opt[] = "fractal,0.5,callee"; 52 const char *cpu_list;
52static bool inverted_callchain; 53 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
53static symbol_filter_t annotate_init; 54};
54
55static const char *cpu_list;
56static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
57 55
58static int perf_session__add_hist_entry(struct perf_session *session, 56static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
59 struct addr_location *al, 57 struct addr_location *al,
60 struct perf_sample *sample, 58 struct perf_sample *sample,
61 struct perf_evsel *evsel) 59 struct machine *machine)
62{ 60{
63 struct symbol *parent = NULL; 61 struct symbol *parent = NULL;
64 int err = 0; 62 int err = 0;
65 struct hist_entry *he; 63 struct hist_entry *he;
66 64
67 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 65 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
68 err = perf_session__resolve_callchain(session, al->thread, 66 err = machine__resolve_callchain(machine, evsel, al->thread,
69 sample->callchain, &parent); 67 sample->callchain, &parent);
70 if (err) 68 if (err)
71 return err; 69 return err;
72 } 70 }
@@ -76,7 +74,8 @@ static int perf_session__add_hist_entry(struct perf_session *session,
76 return -ENOMEM; 74 return -ENOMEM;
77 75
78 if (symbol_conf.use_callchain) { 76 if (symbol_conf.use_callchain) {
79 err = callchain_append(he->callchain, &session->callchain_cursor, 77 err = callchain_append(he->callchain,
78 &evsel->hists.callchain_cursor,
80 sample->period); 79 sample->period);
81 if (err) 80 if (err)
82 return err; 81 return err;
@@ -92,8 +91,7 @@ static int perf_session__add_hist_entry(struct perf_session *session,
92 assert(evsel != NULL); 91 assert(evsel != NULL);
93 92
94 err = -ENOMEM; 93 err = -ENOMEM;
95 if (notes->src == NULL && 94 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
96 symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
97 goto out; 95 goto out;
98 96
99 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 97 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
@@ -106,30 +104,32 @@ out:
106} 104}
107 105
108 106
109static int process_sample_event(union perf_event *event, 107static int process_sample_event(struct perf_tool *tool,
108 union perf_event *event,
110 struct perf_sample *sample, 109 struct perf_sample *sample,
111 struct perf_evsel *evsel, 110 struct perf_evsel *evsel,
112 struct perf_session *session) 111 struct machine *machine)
113{ 112{
113 struct perf_report *rep = container_of(tool, struct perf_report, tool);
114 struct addr_location al; 114 struct addr_location al;
115 115
116 if (perf_event__preprocess_sample(event, session, &al, sample, 116 if (perf_event__preprocess_sample(event, machine, &al, sample,
117 annotate_init) < 0) { 117 rep->annotate_init) < 0) {
118 fprintf(stderr, "problem processing %d event, skipping it.\n", 118 fprintf(stderr, "problem processing %d event, skipping it.\n",
119 event->header.type); 119 event->header.type);
120 return -1; 120 return -1;
121 } 121 }
122 122
123 if (al.filtered || (hide_unresolved && al.sym == NULL)) 123 if (al.filtered || (rep->hide_unresolved && al.sym == NULL))
124 return 0; 124 return 0;
125 125
126 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 126 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
127 return 0; 127 return 0;
128 128
129 if (al.map != NULL) 129 if (al.map != NULL)
130 al.map->dso->hit = 1; 130 al.map->dso->hit = 1;
131 131
132 if (perf_session__add_hist_entry(session, &al, sample, evsel)) { 132 if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
133 pr_debug("problem incrementing symbol period, skipping event\n"); 133 pr_debug("problem incrementing symbol period, skipping event\n");
134 return -1; 134 return -1;
135 } 135 }
@@ -137,15 +137,17 @@ static int process_sample_event(union perf_event *event,
137 return 0; 137 return 0;
138} 138}
139 139
140static int process_read_event(union perf_event *event, 140static int process_read_event(struct perf_tool *tool,
141 union perf_event *event,
141 struct perf_sample *sample __used, 142 struct perf_sample *sample __used,
142 struct perf_session *session) 143 struct perf_evsel *evsel,
144 struct machine *machine __used)
143{ 145{
144 struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, 146 struct perf_report *rep = container_of(tool, struct perf_report, tool);
145 event->read.id); 147
146 if (show_threads) { 148 if (rep->show_threads) {
147 const char *name = evsel ? event_name(evsel) : "unknown"; 149 const char *name = evsel ? event_name(evsel) : "unknown";
148 perf_read_values_add_value(&show_threads_values, 150 perf_read_values_add_value(&rep->show_threads_values,
149 event->read.pid, event->read.tid, 151 event->read.pid, event->read.tid,
150 event->read.id, 152 event->read.id,
151 name, 153 name,
@@ -159,8 +161,10 @@ static int process_read_event(union perf_event *event,
159 return 0; 161 return 0;
160} 162}
161 163
162static int perf_session__setup_sample_type(struct perf_session *self) 164static int perf_report__setup_sample_type(struct perf_report *rep)
163{ 165{
166 struct perf_session *self = rep->session;
167
164 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { 168 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
165 if (sort__has_parent) { 169 if (sort__has_parent) {
166 ui__warning("Selected --sort parent, but no " 170 ui__warning("Selected --sort parent, but no "
@@ -173,7 +177,8 @@ static int perf_session__setup_sample_type(struct perf_session *self)
173 "you call 'perf record' without -g?\n"); 177 "you call 'perf record' without -g?\n");
174 return -1; 178 return -1;
175 } 179 }
176 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && 180 } else if (!rep->dont_use_callchains &&
181 callchain_param.mode != CHAIN_NONE &&
177 !symbol_conf.use_callchain) { 182 !symbol_conf.use_callchain) {
178 symbol_conf.use_callchain = true; 183 symbol_conf.use_callchain = true;
179 if (callchain_register_param(&callchain_param) < 0) { 184 if (callchain_register_param(&callchain_param) < 0) {
@@ -186,22 +191,6 @@ static int perf_session__setup_sample_type(struct perf_session *self)
186 return 0; 191 return 0;
187} 192}
188 193
189static struct perf_event_ops event_ops = {
190 .sample = process_sample_event,
191 .mmap = perf_event__process_mmap,
192 .comm = perf_event__process_comm,
193 .exit = perf_event__process_task,
194 .fork = perf_event__process_task,
195 .lost = perf_event__process_lost,
196 .read = process_read_event,
197 .attr = perf_event__process_attr,
198 .event_type = perf_event__process_event_type,
199 .tracing_data = perf_event__process_tracing_data,
200 .build_id = perf_event__process_build_id,
201 .ordered_samples = true,
202 .ordering_requires_timestamps = true,
203};
204
205extern volatile int session_done; 194extern volatile int session_done;
206 195
207static void sig_handler(int sig __used) 196static void sig_handler(int sig __used)
@@ -224,6 +213,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
224} 213}
225 214
226static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 215static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
216 struct perf_report *rep,
227 const char *help) 217 const char *help)
228{ 218{
229 struct perf_evsel *pos; 219 struct perf_evsel *pos;
@@ -241,18 +231,18 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
241 parent_pattern == default_parent_pattern) { 231 parent_pattern == default_parent_pattern) {
242 fprintf(stdout, "#\n# (%s)\n#\n", help); 232 fprintf(stdout, "#\n# (%s)\n#\n", help);
243 233
244 if (show_threads) { 234 if (rep->show_threads) {
245 bool style = !strcmp(pretty_printing_style, "raw"); 235 bool style = !strcmp(rep->pretty_printing_style, "raw");
246 perf_read_values_display(stdout, &show_threads_values, 236 perf_read_values_display(stdout, &rep->show_threads_values,
247 style); 237 style);
248 perf_read_values_destroy(&show_threads_values); 238 perf_read_values_destroy(&rep->show_threads_values);
249 } 239 }
250 } 240 }
251 241
252 return 0; 242 return 0;
253} 243}
254 244
255static int __cmd_report(void) 245static int __cmd_report(struct perf_report *rep)
256{ 246{
257 int ret = -EINVAL; 247 int ret = -EINVAL;
258 u64 nr_samples; 248 u64 nr_samples;
@@ -264,27 +254,31 @@ static int __cmd_report(void)
264 254
265 signal(SIGINT, sig_handler); 255 signal(SIGINT, sig_handler);
266 256
267 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); 257 session = perf_session__new(rep->input_name, O_RDONLY,
258 rep->force, false, &rep->tool);
268 if (session == NULL) 259 if (session == NULL)
269 return -ENOMEM; 260 return -ENOMEM;
270 261
271 if (cpu_list) { 262 rep->session = session;
272 ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); 263
264 if (rep->cpu_list) {
265 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
266 rep->cpu_bitmap);
273 if (ret) 267 if (ret)
274 goto out_delete; 268 goto out_delete;
275 } 269 }
276 270
277 if (use_browser <= 0) 271 if (use_browser <= 0)
278 perf_session__fprintf_info(session, stdout, show_full_info); 272 perf_session__fprintf_info(session, stdout, rep->show_full_info);
279 273
280 if (show_threads) 274 if (rep->show_threads)
281 perf_read_values_init(&show_threads_values); 275 perf_read_values_init(&rep->show_threads_values);
282 276
283 ret = perf_session__setup_sample_type(session); 277 ret = perf_report__setup_sample_type(rep);
284 if (ret) 278 if (ret)
285 goto out_delete; 279 goto out_delete;
286 280
287 ret = perf_session__process_events(session, &event_ops); 281 ret = perf_session__process_events(session, &rep->tool);
288 if (ret) 282 if (ret)
289 goto out_delete; 283 goto out_delete;
290 284
@@ -327,7 +321,7 @@ static int __cmd_report(void)
327 } 321 }
328 322
329 if (nr_samples == 0) { 323 if (nr_samples == 0) {
330 ui__warning("The %s file has no samples!\n", input_name); 324 ui__warning("The %s file has no samples!\n", session->filename);
331 goto out_delete; 325 goto out_delete;
332 } 326 }
333 327
@@ -335,7 +329,7 @@ static int __cmd_report(void)
335 perf_evlist__tui_browse_hists(session->evlist, help, 329 perf_evlist__tui_browse_hists(session->evlist, help,
336 NULL, NULL, 0); 330 NULL, NULL, 0);
337 } else 331 } else
338 perf_evlist__tty_browse_hists(session->evlist, help); 332 perf_evlist__tty_browse_hists(session->evlist, rep, help);
339 333
340out_delete: 334out_delete:
341 /* 335 /*
@@ -354,9 +348,9 @@ out_delete:
354} 348}
355 349
356static int 350static int
357parse_callchain_opt(const struct option *opt __used, const char *arg, 351parse_callchain_opt(const struct option *opt, const char *arg, int unset)
358 int unset)
359{ 352{
353 struct perf_report *rep = (struct perf_report *)opt->value;
360 char *tok, *tok2; 354 char *tok, *tok2;
361 char *endptr; 355 char *endptr;
362 356
@@ -364,7 +358,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
364 * --no-call-graph 358 * --no-call-graph
365 */ 359 */
366 if (unset) { 360 if (unset) {
367 dont_use_callchains = true; 361 rep->dont_use_callchains = true;
368 return 0; 362 return 0;
369 } 363 }
370 364
@@ -412,7 +406,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
412 goto setup; 406 goto setup;
413 407
414 if (tok2[0] != 'c') { 408 if (tok2[0] != 'c') {
415 callchain_param.print_limit = strtod(tok2, &endptr); 409 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
416 tok2 = strtok(NULL, ","); 410 tok2 = strtok(NULL, ",");
417 if (!tok2) 411 if (!tok2)
418 goto setup; 412 goto setup;
@@ -433,13 +427,34 @@ setup:
433 return 0; 427 return 0;
434} 428}
435 429
436static const char * const report_usage[] = { 430int cmd_report(int argc, const char **argv, const char *prefix __used)
437 "perf report [<options>] <command>", 431{
438 NULL 432 struct stat st;
439}; 433 char callchain_default_opt[] = "fractal,0.5,callee";
440 434 const char * const report_usage[] = {
441static const struct option options[] = { 435 "perf report [<options>]",
442 OPT_STRING('i', "input", &input_name, "file", 436 NULL
437 };
438 struct perf_report report = {
439 .tool = {
440 .sample = process_sample_event,
441 .mmap = perf_event__process_mmap,
442 .comm = perf_event__process_comm,
443 .exit = perf_event__process_task,
444 .fork = perf_event__process_task,
445 .lost = perf_event__process_lost,
446 .read = process_read_event,
447 .attr = perf_event__process_attr,
448 .event_type = perf_event__process_event_type,
449 .tracing_data = perf_event__process_tracing_data,
450 .build_id = perf_event__process_build_id,
451 .ordered_samples = true,
452 .ordering_requires_timestamps = true,
453 },
454 .pretty_printing_style = "normal",
455 };
456 const struct option options[] = {
457 OPT_STRING('i', "input", &report.input_name, "file",
443 "input file name"), 458 "input file name"),
444 OPT_INCR('v', "verbose", &verbose, 459 OPT_INCR('v', "verbose", &verbose,
445 "be more verbose (show symbol address, etc)"), 460 "be more verbose (show symbol address, etc)"),
@@ -449,17 +464,18 @@ static const struct option options[] = {
449 "file", "vmlinux pathname"), 464 "file", "vmlinux pathname"),
450 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 465 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
451 "file", "kallsyms pathname"), 466 "file", "kallsyms pathname"),
452 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 467 OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
453 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 468 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
454 "load module symbols - WARNING: use only with -k and LIVE kernel"), 469 "load module symbols - WARNING: use only with -k and LIVE kernel"),
455 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 470 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
456 "Show a column with the number of samples"), 471 "Show a column with the number of samples"),
457 OPT_BOOLEAN('T', "threads", &show_threads, 472 OPT_BOOLEAN('T', "threads", &report.show_threads,
458 "Show per-thread event counters"), 473 "Show per-thread event counters"),
459 OPT_STRING(0, "pretty", &pretty_printing_style, "key", 474 OPT_STRING(0, "pretty", &report.pretty_printing_style, "key",
460 "pretty printing style key: normal raw"), 475 "pretty printing style key: normal raw"),
461 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 476 OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"),
462 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 477 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
478 "Use the stdio interface"),
463 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 479 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
464 "sort by key(s): pid, comm, dso, symbol, parent"), 480 "sort by key(s): pid, comm, dso, symbol, parent"),
465 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 481 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -468,13 +484,14 @@ static const struct option options[] = {
468 "regex filter to identify parent, see: '--sort parent'"), 484 "regex filter to identify parent, see: '--sort parent'"),
469 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 485 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
470 "Only display entries with parent-match"), 486 "Only display entries with parent-match"),
471 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", 487 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
472 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " 488 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. "
473 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), 489 "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
474 OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"), 490 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
491 "alias for inverted call graph"),
475 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 492 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
476 "only consider symbols in these dsos"), 493 "only consider symbols in these dsos"),
477 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 494 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
478 "only consider symbols in these comms"), 495 "only consider symbols in these comms"),
479 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 496 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
480 "only consider these symbols"), 497 "only consider these symbols"),
@@ -484,12 +501,13 @@ static const struct option options[] = {
484 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 501 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
485 "separator for columns, no spaces will be added between " 502 "separator for columns, no spaces will be added between "
486 "columns '.' is reserved."), 503 "columns '.' is reserved."),
487 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, 504 OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
488 "Only display entries resolved to a symbol"), 505 "Only display entries resolved to a symbol"),
489 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 506 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
490 "Look for files with symbols relative to this directory"), 507 "Look for files with symbols relative to this directory"),
491 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 508 OPT_STRING('C', "cpu", &report.cpu_list, "cpu",
492 OPT_BOOLEAN('I', "show-info", &show_full_info, 509 "list of cpus to profile"),
510 OPT_BOOLEAN('I', "show-info", &report.show_full_info,
493 "Display extended information about perf.data file"), 511 "Display extended information about perf.data file"),
494 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, 512 OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
495 "Interleave source code with assembly code (default)"), 513 "Interleave source code with assembly code (default)"),
@@ -500,24 +518,30 @@ static const struct option options[] = {
500 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 518 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
501 "Show a column with the sum of periods"), 519 "Show a column with the sum of periods"),
502 OPT_END() 520 OPT_END()
503}; 521 };
504 522
505int cmd_report(int argc, const char **argv, const char *prefix __used)
506{
507 argc = parse_options(argc, argv, options, report_usage, 0); 523 argc = parse_options(argc, argv, options, report_usage, 0);
508 524
509 if (use_stdio) 525 if (report.use_stdio)
510 use_browser = 0; 526 use_browser = 0;
511 else if (use_tui) 527 else if (report.use_tui)
512 use_browser = 1; 528 use_browser = 1;
513 529
514 if (inverted_callchain) 530 if (report.inverted_callchain)
515 callchain_param.order = ORDER_CALLER; 531 callchain_param.order = ORDER_CALLER;
516 532
517 if (strcmp(input_name, "-") != 0) 533 if (!report.input_name || !strlen(report.input_name)) {
534 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
535 report.input_name = "-";
536 else
537 report.input_name = "perf.data";
538 }
539
540 if (strcmp(report.input_name, "-") != 0)
518 setup_browser(true); 541 setup_browser(true);
519 else 542 else
520 use_browser = 0; 543 use_browser = 0;
544
521 /* 545 /*
522 * Only in the newt browser we are doing integrated annotation, 546 * Only in the newt browser we are doing integrated annotation,
523 * so don't allocate extra space that won't be used in the stdio 547 * so don't allocate extra space that won't be used in the stdio
@@ -525,7 +549,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
525 */ 549 */
526 if (use_browser > 0) { 550 if (use_browser > 0) {
527 symbol_conf.priv_size = sizeof(struct annotation); 551 symbol_conf.priv_size = sizeof(struct annotation);
528 annotate_init = symbol__annotate_init; 552 report.annotate_init = symbol__annotate_init;
529 /* 553 /*
530 * For searching by name on the "Browse map details". 554 * For searching by name on the "Browse map details".
531 * providing it only in verbose mode not to bloat too 555 * providing it only in verbose mode not to bloat too
@@ -572,5 +596,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
572 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); 596 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
573 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 597 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
574 598
575 return __cmd_report(); 599 return __cmd_report(&report);
576} 600}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 5177964943e7..fb8b5f83b4a0 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -2,11 +2,14 @@
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/util.h" 4#include "util/util.h"
5#include "util/evlist.h"
5#include "util/cache.h" 6#include "util/cache.h"
7#include "util/evsel.h"
6#include "util/symbol.h" 8#include "util/symbol.h"
7#include "util/thread.h" 9#include "util/thread.h"
8#include "util/header.h" 10#include "util/header.h"
9#include "util/session.h" 11#include "util/session.h"
12#include "util/tool.h"
10 13
11#include "util/parse-options.h" 14#include "util/parse-options.h"
12#include "util/trace-event.h" 15#include "util/trace-event.h"
@@ -19,7 +22,7 @@
19#include <pthread.h> 22#include <pthread.h>
20#include <math.h> 23#include <math.h>
21 24
22static char const *input_name = "perf.data"; 25static const char *input_name;
23 26
24static char default_sort_order[] = "avg, max, switch, runtime"; 27static char default_sort_order[] = "avg, max, switch, runtime";
25static const char *sort_order = default_sort_order; 28static const char *sort_order = default_sort_order;
@@ -723,21 +726,21 @@ struct trace_migrate_task_event {
723 726
724struct trace_sched_handler { 727struct trace_sched_handler {
725 void (*switch_event)(struct trace_switch_event *, 728 void (*switch_event)(struct trace_switch_event *,
726 struct perf_session *, 729 struct machine *,
727 struct event *, 730 struct event *,
728 int cpu, 731 int cpu,
729 u64 timestamp, 732 u64 timestamp,
730 struct thread *thread); 733 struct thread *thread);
731 734
732 void (*runtime_event)(struct trace_runtime_event *, 735 void (*runtime_event)(struct trace_runtime_event *,
733 struct perf_session *, 736 struct machine *,
734 struct event *, 737 struct event *,
735 int cpu, 738 int cpu,
736 u64 timestamp, 739 u64 timestamp,
737 struct thread *thread); 740 struct thread *thread);
738 741
739 void (*wakeup_event)(struct trace_wakeup_event *, 742 void (*wakeup_event)(struct trace_wakeup_event *,
740 struct perf_session *, 743 struct machine *,
741 struct event *, 744 struct event *,
742 int cpu, 745 int cpu,
743 u64 timestamp, 746 u64 timestamp,
@@ -750,7 +753,7 @@ struct trace_sched_handler {
750 struct thread *thread); 753 struct thread *thread);
751 754
752 void (*migrate_task_event)(struct trace_migrate_task_event *, 755 void (*migrate_task_event)(struct trace_migrate_task_event *,
753 struct perf_session *session, 756 struct machine *machine,
754 struct event *, 757 struct event *,
755 int cpu, 758 int cpu,
756 u64 timestamp, 759 u64 timestamp,
@@ -760,7 +763,7 @@ struct trace_sched_handler {
760 763
761static void 764static void
762replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 765replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
763 struct perf_session *session __used, 766 struct machine *machine __used,
764 struct event *event, 767 struct event *event,
765 int cpu __used, 768 int cpu __used,
766 u64 timestamp __used, 769 u64 timestamp __used,
@@ -787,7 +790,7 @@ static u64 cpu_last_switched[MAX_CPUS];
787 790
788static void 791static void
789replay_switch_event(struct trace_switch_event *switch_event, 792replay_switch_event(struct trace_switch_event *switch_event,
790 struct perf_session *session __used, 793 struct machine *machine __used,
791 struct event *event, 794 struct event *event,
792 int cpu, 795 int cpu,
793 u64 timestamp, 796 u64 timestamp,
@@ -1021,7 +1024,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1021 1024
1022static void 1025static void
1023latency_switch_event(struct trace_switch_event *switch_event, 1026latency_switch_event(struct trace_switch_event *switch_event,
1024 struct perf_session *session, 1027 struct machine *machine,
1025 struct event *event __used, 1028 struct event *event __used,
1026 int cpu, 1029 int cpu,
1027 u64 timestamp, 1030 u64 timestamp,
@@ -1045,8 +1048,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1045 die("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1048 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1046 1049
1047 1050
1048 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1051 sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
1049 sched_in = perf_session__findnew(session, switch_event->next_pid); 1052 sched_in = machine__findnew_thread(machine, switch_event->next_pid);
1050 1053
1051 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1054 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1052 if (!out_events) { 1055 if (!out_events) {
@@ -1074,13 +1077,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1074 1077
1075static void 1078static void
1076latency_runtime_event(struct trace_runtime_event *runtime_event, 1079latency_runtime_event(struct trace_runtime_event *runtime_event,
1077 struct perf_session *session, 1080 struct machine *machine,
1078 struct event *event __used, 1081 struct event *event __used,
1079 int cpu, 1082 int cpu,
1080 u64 timestamp, 1083 u64 timestamp,
1081 struct thread *this_thread __used) 1084 struct thread *this_thread __used)
1082{ 1085{
1083 struct thread *thread = perf_session__findnew(session, runtime_event->pid); 1086 struct thread *thread = machine__findnew_thread(machine, runtime_event->pid);
1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1087 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1085 1088
1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1089 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,7 +1100,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1097 1100
1098static void 1101static void
1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1102latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1100 struct perf_session *session, 1103 struct machine *machine,
1101 struct event *__event __used, 1104 struct event *__event __used,
1102 int cpu __used, 1105 int cpu __used,
1103 u64 timestamp, 1106 u64 timestamp,
@@ -1111,7 +1114,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1111 if (!wakeup_event->success) 1114 if (!wakeup_event->success)
1112 return; 1115 return;
1113 1116
1114 wakee = perf_session__findnew(session, wakeup_event->pid); 1117 wakee = machine__findnew_thread(machine, wakeup_event->pid);
1115 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1118 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1116 if (!atoms) { 1119 if (!atoms) {
1117 thread_atoms_insert(wakee); 1120 thread_atoms_insert(wakee);
@@ -1145,7 +1148,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1145 1148
1146static void 1149static void
1147latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1150latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1148 struct perf_session *session, 1151 struct machine *machine,
1149 struct event *__event __used, 1152 struct event *__event __used,
1150 int cpu __used, 1153 int cpu __used,
1151 u64 timestamp, 1154 u64 timestamp,
@@ -1161,7 +1164,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1161 if (profile_cpu == -1) 1164 if (profile_cpu == -1)
1162 return; 1165 return;
1163 1166
1164 migrant = perf_session__findnew(session, migrate_task_event->pid); 1167 migrant = machine__findnew_thread(machine, migrate_task_event->pid);
1165 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1168 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1166 if (!atoms) { 1169 if (!atoms) {
1167 thread_atoms_insert(migrant); 1170 thread_atoms_insert(migrant);
@@ -1356,12 +1359,13 @@ static void sort_lat(void)
1356static struct trace_sched_handler *trace_handler; 1359static struct trace_sched_handler *trace_handler;
1357 1360
1358static void 1361static void
1359process_sched_wakeup_event(void *data, struct perf_session *session, 1362process_sched_wakeup_event(struct perf_tool *tool __used,
1360 struct event *event, 1363 struct event *event,
1361 int cpu __used, 1364 struct perf_sample *sample,
1362 u64 timestamp __used, 1365 struct machine *machine,
1363 struct thread *thread __used) 1366 struct thread *thread)
1364{ 1367{
1368 void *data = sample->raw_data;
1365 struct trace_wakeup_event wakeup_event; 1369 struct trace_wakeup_event wakeup_event;
1366 1370
1367 FILL_COMMON_FIELDS(wakeup_event, event, data); 1371 FILL_COMMON_FIELDS(wakeup_event, event, data);
@@ -1373,8 +1377,8 @@ process_sched_wakeup_event(void *data, struct perf_session *session,
1373 FILL_FIELD(wakeup_event, cpu, event, data); 1377 FILL_FIELD(wakeup_event, cpu, event, data);
1374 1378
1375 if (trace_handler->wakeup_event) 1379 if (trace_handler->wakeup_event)
1376 trace_handler->wakeup_event(&wakeup_event, session, event, 1380 trace_handler->wakeup_event(&wakeup_event, machine, event,
1377 cpu, timestamp, thread); 1381 sample->cpu, sample->time, thread);
1378} 1382}
1379 1383
1380/* 1384/*
@@ -1392,7 +1396,7 @@ static char next_shortname2 = '0';
1392 1396
1393static void 1397static void
1394map_switch_event(struct trace_switch_event *switch_event, 1398map_switch_event(struct trace_switch_event *switch_event,
1395 struct perf_session *session, 1399 struct machine *machine,
1396 struct event *event __used, 1400 struct event *event __used,
1397 int this_cpu, 1401 int this_cpu,
1398 u64 timestamp, 1402 u64 timestamp,
@@ -1420,8 +1424,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1420 die("hm, delta: %" PRIu64 " < 0 ?\n", delta); 1424 die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
1421 1425
1422 1426
1423 sched_out = perf_session__findnew(session, switch_event->prev_pid); 1427 sched_out = machine__findnew_thread(machine, switch_event->prev_pid);
1424 sched_in = perf_session__findnew(session, switch_event->next_pid); 1428 sched_in = machine__findnew_thread(machine, switch_event->next_pid);
1425 1429
1426 curr_thread[this_cpu] = sched_in; 1430 curr_thread[this_cpu] = sched_in;
1427 1431
@@ -1469,14 +1473,15 @@ map_switch_event(struct trace_switch_event *switch_event,
1469 } 1473 }
1470} 1474}
1471 1475
1472
1473static void 1476static void
1474process_sched_switch_event(void *data, struct perf_session *session, 1477process_sched_switch_event(struct perf_tool *tool __used,
1475 struct event *event, 1478 struct event *event,
1476 int this_cpu, 1479 struct perf_sample *sample,
1477 u64 timestamp __used, 1480 struct machine *machine,
1478 struct thread *thread __used) 1481 struct thread *thread)
1479{ 1482{
1483 int this_cpu = sample->cpu;
1484 void *data = sample->raw_data;
1480 struct trace_switch_event switch_event; 1485 struct trace_switch_event switch_event;
1481 1486
1482 FILL_COMMON_FIELDS(switch_event, event, data); 1487 FILL_COMMON_FIELDS(switch_event, event, data);
@@ -1498,19 +1503,20 @@ process_sched_switch_event(void *data, struct perf_session *session,
1498 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1499 } 1504 }
1500 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1501 trace_handler->switch_event(&switch_event, session, event, 1506 trace_handler->switch_event(&switch_event, machine, event,
1502 this_cpu, timestamp, thread); 1507 this_cpu, sample->time, thread);
1503 1508
1504 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1505} 1510}
1506 1511
1507static void 1512static void
1508process_sched_runtime_event(void *data, struct perf_session *session, 1513process_sched_runtime_event(struct perf_tool *tool __used,
1509 struct event *event, 1514 struct event *event,
1510 int cpu __used, 1515 struct perf_sample *sample,
1511 u64 timestamp __used, 1516 struct machine *machine,
1512 struct thread *thread __used) 1517 struct thread *thread)
1513{ 1518{
1519 void *data = sample->raw_data;
1514 struct trace_runtime_event runtime_event; 1520 struct trace_runtime_event runtime_event;
1515 1521
1516 FILL_ARRAY(runtime_event, comm, event, data); 1522 FILL_ARRAY(runtime_event, comm, event, data);
@@ -1519,16 +1525,18 @@ process_sched_runtime_event(void *data, struct perf_session *session,
1519 FILL_FIELD(runtime_event, vruntime, event, data); 1525 FILL_FIELD(runtime_event, vruntime, event, data);
1520 1526
1521 if (trace_handler->runtime_event) 1527 if (trace_handler->runtime_event)
1522 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread); 1528 trace_handler->runtime_event(&runtime_event, machine, event,
1529 sample->cpu, sample->time, thread);
1523} 1530}
1524 1531
1525static void 1532static void
1526process_sched_fork_event(void *data, 1533process_sched_fork_event(struct perf_tool *tool __used,
1527 struct event *event, 1534 struct event *event,
1528 int cpu __used, 1535 struct perf_sample *sample,
1529 u64 timestamp __used, 1536 struct machine *machine __used,
1530 struct thread *thread __used) 1537 struct thread *thread)
1531{ 1538{
1539 void *data = sample->raw_data;
1532 struct trace_fork_event fork_event; 1540 struct trace_fork_event fork_event;
1533 1541
1534 FILL_COMMON_FIELDS(fork_event, event, data); 1542 FILL_COMMON_FIELDS(fork_event, event, data);
@@ -1540,13 +1548,14 @@ process_sched_fork_event(void *data,
1540 1548
1541 if (trace_handler->fork_event) 1549 if (trace_handler->fork_event)
1542 trace_handler->fork_event(&fork_event, event, 1550 trace_handler->fork_event(&fork_event, event,
1543 cpu, timestamp, thread); 1551 sample->cpu, sample->time, thread);
1544} 1552}
1545 1553
1546static void 1554static void
1547process_sched_exit_event(struct event *event, 1555process_sched_exit_event(struct perf_tool *tool __used,
1548 int cpu __used, 1556 struct event *event,
1549 u64 timestamp __used, 1557 struct perf_sample *sample __used,
1558 struct machine *machine __used,
1550 struct thread *thread __used) 1559 struct thread *thread __used)
1551{ 1560{
1552 if (verbose) 1561 if (verbose)
@@ -1554,12 +1563,13 @@ process_sched_exit_event(struct event *event,
1554} 1563}
1555 1564
1556static void 1565static void
1557process_sched_migrate_task_event(void *data, struct perf_session *session, 1566process_sched_migrate_task_event(struct perf_tool *tool __used,
1558 struct event *event, 1567 struct event *event,
1559 int cpu __used, 1568 struct perf_sample *sample,
1560 u64 timestamp __used, 1569 struct machine *machine,
1561 struct thread *thread __used) 1570 struct thread *thread)
1562{ 1571{
1572 void *data = sample->raw_data;
1563 struct trace_migrate_task_event migrate_task_event; 1573 struct trace_migrate_task_event migrate_task_event;
1564 1574
1565 FILL_COMMON_FIELDS(migrate_task_event, event, data); 1575 FILL_COMMON_FIELDS(migrate_task_event, event, data);
@@ -1570,67 +1580,47 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
1570 FILL_FIELD(migrate_task_event, cpu, event, data); 1580 FILL_FIELD(migrate_task_event, cpu, event, data);
1571 1581
1572 if (trace_handler->migrate_task_event) 1582 if (trace_handler->migrate_task_event)
1573 trace_handler->migrate_task_event(&migrate_task_event, session, 1583 trace_handler->migrate_task_event(&migrate_task_event, machine,
1574 event, cpu, timestamp, thread); 1584 event, sample->cpu,
1585 sample->time, thread);
1575} 1586}
1576 1587
1577static void process_raw_event(union perf_event *raw_event __used, 1588typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event,
1578 struct perf_session *session, void *data, int cpu, 1589 struct perf_sample *sample,
1579 u64 timestamp, struct thread *thread) 1590 struct machine *machine,
1580{ 1591 struct thread *thread);
1581 struct event *event;
1582 int type;
1583
1584
1585 type = trace_parse_common_type(data);
1586 event = trace_find_event(type);
1587
1588 if (!strcmp(event->name, "sched_switch"))
1589 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1590 if (!strcmp(event->name, "sched_stat_runtime"))
1591 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1592 if (!strcmp(event->name, "sched_wakeup"))
1593 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1594 if (!strcmp(event->name, "sched_wakeup_new"))
1595 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1596 if (!strcmp(event->name, "sched_process_fork"))
1597 process_sched_fork_event(data, event, cpu, timestamp, thread);
1598 if (!strcmp(event->name, "sched_process_exit"))
1599 process_sched_exit_event(event, cpu, timestamp, thread);
1600 if (!strcmp(event->name, "sched_migrate_task"))
1601 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1602}
1603 1592
1604static int process_sample_event(union perf_event *event, 1593static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
1605 struct perf_sample *sample, 1594 union perf_event *event __used,
1606 struct perf_evsel *evsel __used, 1595 struct perf_sample *sample,
1607 struct perf_session *session) 1596 struct perf_evsel *evsel,
1597 struct machine *machine)
1608{ 1598{
1609 struct thread *thread; 1599 struct thread *thread = machine__findnew_thread(machine, sample->pid);
1610
1611 if (!(session->sample_type & PERF_SAMPLE_RAW))
1612 return 0;
1613 1600
1614 thread = perf_session__findnew(session, sample->pid);
1615 if (thread == NULL) { 1601 if (thread == NULL) {
1616 pr_debug("problem processing %d event, skipping it.\n", 1602 pr_debug("problem processing %s event, skipping it.\n",
1617 event->header.type); 1603 evsel->name);
1618 return -1; 1604 return -1;
1619 } 1605 }
1620 1606
1621 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1607 evsel->hists.stats.total_period += sample->period;
1608 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
1622 1609
1623 if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) 1610 if (evsel->handler.func != NULL) {
1624 return 0; 1611 tracepoint_handler f = evsel->handler.func;
1625 1612
1626 process_raw_event(event, session, sample->raw_data, sample->cpu, 1613 if (evsel->handler.data == NULL)
1627 sample->time, thread); 1614 evsel->handler.data = trace_find_event(evsel->attr.config);
1615
1616 f(tool, evsel->handler.data, sample, machine, thread);
1617 }
1628 1618
1629 return 0; 1619 return 0;
1630} 1620}
1631 1621
1632static struct perf_event_ops event_ops = { 1622static struct perf_tool perf_sched = {
1633 .sample = process_sample_event, 1623 .sample = perf_sched__process_tracepoint_sample,
1634 .comm = perf_event__process_comm, 1624 .comm = perf_event__process_comm,
1635 .lost = perf_event__process_lost, 1625 .lost = perf_event__process_lost,
1636 .fork = perf_event__process_task, 1626 .fork = perf_event__process_task,
@@ -1640,13 +1630,25 @@ static struct perf_event_ops event_ops = {
1640static void read_events(bool destroy, struct perf_session **psession) 1630static void read_events(bool destroy, struct perf_session **psession)
1641{ 1631{
1642 int err = -EINVAL; 1632 int err = -EINVAL;
1633 const struct perf_evsel_str_handler handlers[] = {
1634 { "sched:sched_switch", process_sched_switch_event, },
1635 { "sched:sched_stat_runtime", process_sched_runtime_event, },
1636 { "sched:sched_wakeup", process_sched_wakeup_event, },
1637 { "sched:sched_wakeup_new", process_sched_wakeup_event, },
1638 { "sched:sched_process_fork", process_sched_fork_event, },
1639 { "sched:sched_process_exit", process_sched_exit_event, },
1640 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1641 };
1643 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 1642 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1644 0, false, &event_ops); 1643 0, false, &perf_sched);
1645 if (session == NULL) 1644 if (session == NULL)
1646 die("No Memory"); 1645 die("No Memory");
1647 1646
1647 err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers);
1648 assert(err == 0);
1649
1648 if (perf_session__has_traces(session, "record -R")) { 1650 if (perf_session__has_traces(session, "record -R")) {
1649 err = perf_session__process_events(session, &event_ops); 1651 err = perf_session__process_events(session, &perf_sched);
1650 if (err) 1652 if (err)
1651 die("Failed to process events, error %d", err); 1653 die("Failed to process events, error %d", err);
1652 1654
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 2f62a2952269..fd1909afcfd6 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -7,6 +7,7 @@
7#include "util/header.h" 7#include "util/header.h"
8#include "util/parse-options.h" 8#include "util/parse-options.h"
9#include "util/session.h" 9#include "util/session.h"
10#include "util/tool.h"
10#include "util/symbol.h" 11#include "util/symbol.h"
11#include "util/thread.h" 12#include "util/thread.h"
12#include "util/trace-event.h" 13#include "util/trace-event.h"
@@ -23,6 +24,7 @@ static u64 nr_unordered;
23extern const struct option record_options[]; 24extern const struct option record_options[];
24static bool no_callchain; 25static bool no_callchain;
25static bool show_full_info; 26static bool show_full_info;
27static bool system_wide;
26static const char *cpu_list; 28static const char *cpu_list;
27static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 29static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
28 30
@@ -315,7 +317,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
315 317
316static void print_sample_addr(union perf_event *event, 318static void print_sample_addr(union perf_event *event,
317 struct perf_sample *sample, 319 struct perf_sample *sample,
318 struct perf_session *session, 320 struct machine *machine,
319 struct thread *thread, 321 struct thread *thread,
320 struct perf_event_attr *attr) 322 struct perf_event_attr *attr)
321{ 323{
@@ -328,11 +330,11 @@ static void print_sample_addr(union perf_event *event,
328 if (!sample_addr_correlates_sym(attr)) 330 if (!sample_addr_correlates_sym(attr))
329 return; 331 return;
330 332
331 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 333 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
332 event->ip.pid, sample->addr, &al); 334 sample->addr, &al);
333 if (!al.map) 335 if (!al.map)
334 thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, 336 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
335 event->ip.pid, sample->addr, &al); 337 sample->addr, &al);
336 338
337 al.cpu = sample->cpu; 339 al.cpu = sample->cpu;
338 al.sym = NULL; 340 al.sym = NULL;
@@ -362,7 +364,7 @@ static void print_sample_addr(union perf_event *event,
362static void process_event(union perf_event *event __unused, 364static void process_event(union perf_event *event __unused,
363 struct perf_sample *sample, 365 struct perf_sample *sample,
364 struct perf_evsel *evsel, 366 struct perf_evsel *evsel,
365 struct perf_session *session, 367 struct machine *machine,
366 struct thread *thread) 368 struct thread *thread)
367{ 369{
368 struct perf_event_attr *attr = &evsel->attr; 370 struct perf_event_attr *attr = &evsel->attr;
@@ -377,15 +379,15 @@ static void process_event(union perf_event *event __unused,
377 sample->raw_size); 379 sample->raw_size);
378 380
379 if (PRINT_FIELD(ADDR)) 381 if (PRINT_FIELD(ADDR))
380 print_sample_addr(event, sample, session, thread, attr); 382 print_sample_addr(event, sample, machine, thread, attr);
381 383
382 if (PRINT_FIELD(IP)) { 384 if (PRINT_FIELD(IP)) {
383 if (!symbol_conf.use_callchain) 385 if (!symbol_conf.use_callchain)
384 printf(" "); 386 printf(" ");
385 else 387 else
386 printf("\n"); 388 printf("\n");
387 perf_session__print_ip(event, sample, session, 389 perf_event__print_ip(event, sample, machine, evsel,
388 PRINT_FIELD(SYM), PRINT_FIELD(DSO)); 390 PRINT_FIELD(SYM), PRINT_FIELD(DSO));
389 } 391 }
390 392
391 printf("\n"); 393 printf("\n");
@@ -432,14 +434,16 @@ static int cleanup_scripting(void)
432 return scripting_ops->stop_script(); 434 return scripting_ops->stop_script();
433} 435}
434 436
435static char const *input_name = "perf.data"; 437static const char *input_name;
436 438
437static int process_sample_event(union perf_event *event, 439static int process_sample_event(struct perf_tool *tool __used,
440 union perf_event *event,
438 struct perf_sample *sample, 441 struct perf_sample *sample,
439 struct perf_evsel *evsel, 442 struct perf_evsel *evsel,
440 struct perf_session *session) 443 struct machine *machine)
441{ 444{
442 struct thread *thread = perf_session__findnew(session, event->ip.pid); 445 struct addr_location al;
446 struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
443 447
444 if (thread == NULL) { 448 if (thread == NULL) {
445 pr_debug("problem processing %d event, skipping it.\n", 449 pr_debug("problem processing %d event, skipping it.\n",
@@ -458,16 +462,25 @@ static int process_sample_event(union perf_event *event,
458 return 0; 462 return 0;
459 } 463 }
460 464
465 if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) {
466 pr_err("problem processing %d event, skipping it.\n",
467 event->header.type);
468 return -1;
469 }
470
471 if (al.filtered)
472 return 0;
473
461 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 474 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
462 return 0; 475 return 0;
463 476
464 scripting_ops->process_event(event, sample, evsel, session, thread); 477 scripting_ops->process_event(event, sample, evsel, machine, thread);
465 478
466 session->hists.stats.total_period += sample->period; 479 evsel->hists.stats.total_period += sample->period;
467 return 0; 480 return 0;
468} 481}
469 482
470static struct perf_event_ops event_ops = { 483static struct perf_tool perf_script = {
471 .sample = process_sample_event, 484 .sample = process_sample_event,
472 .mmap = perf_event__process_mmap, 485 .mmap = perf_event__process_mmap,
473 .comm = perf_event__process_comm, 486 .comm = perf_event__process_comm,
@@ -494,7 +507,7 @@ static int __cmd_script(struct perf_session *session)
494 507
495 signal(SIGINT, sig_handler); 508 signal(SIGINT, sig_handler);
496 509
497 ret = perf_session__process_events(session, &event_ops); 510 ret = perf_session__process_events(session, &perf_script);
498 511
499 if (debug_mode) 512 if (debug_mode)
500 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); 513 pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -523,12 +536,6 @@ static struct script_spec *script_spec__new(const char *spec,
523 return s; 536 return s;
524} 537}
525 538
526static void script_spec__delete(struct script_spec *s)
527{
528 free(s->spec);
529 free(s);
530}
531
532static void script_spec__add(struct script_spec *s) 539static void script_spec__add(struct script_spec *s)
533{ 540{
534 list_add_tail(&s->node, &script_specs); 541 list_add_tail(&s->node, &script_specs);
@@ -554,16 +561,11 @@ static struct script_spec *script_spec__findnew(const char *spec,
554 561
555 s = script_spec__new(spec, ops); 562 s = script_spec__new(spec, ops);
556 if (!s) 563 if (!s)
557 goto out_delete_spec; 564 return NULL;
558 565
559 script_spec__add(s); 566 script_spec__add(s);
560 567
561 return s; 568 return s;
562
563out_delete_spec:
564 script_spec__delete(s);
565
566 return NULL;
567} 569}
568 570
569int script_spec_register(const char *spec, struct scripting_ops *ops) 571int script_spec_register(const char *spec, struct scripting_ops *ops)
@@ -681,7 +683,8 @@ static int parse_output_fields(const struct option *opt __used,
681 type = PERF_TYPE_RAW; 683 type = PERF_TYPE_RAW;
682 else { 684 else {
683 fprintf(stderr, "Invalid event type in field string.\n"); 685 fprintf(stderr, "Invalid event type in field string.\n");
684 return -EINVAL; 686 rc = -EINVAL;
687 goto out;
685 } 688 }
686 689
687 if (output[type].user_set) 690 if (output[type].user_set)
@@ -923,6 +926,24 @@ static int read_script_info(struct script_desc *desc, const char *filename)
923 return 0; 926 return 0;
924} 927}
925 928
929static char *get_script_root(struct dirent *script_dirent, const char *suffix)
930{
931 char *script_root, *str;
932
933 script_root = strdup(script_dirent->d_name);
934 if (!script_root)
935 return NULL;
936
937 str = (char *)ends_with(script_root, suffix);
938 if (!str) {
939 free(script_root);
940 return NULL;
941 }
942
943 *str = '\0';
944 return script_root;
945}
946
926static int list_available_scripts(const struct option *opt __used, 947static int list_available_scripts(const struct option *opt __used,
927 const char *s __used, int unset __used) 948 const char *s __used, int unset __used)
928{ 949{
@@ -934,7 +955,6 @@ static int list_available_scripts(const struct option *opt __used,
934 struct script_desc *desc; 955 struct script_desc *desc;
935 char first_half[BUFSIZ]; 956 char first_half[BUFSIZ];
936 char *script_root; 957 char *script_root;
937 char *str;
938 958
939 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 959 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
940 960
@@ -950,16 +970,14 @@ static int list_available_scripts(const struct option *opt __used,
950 continue; 970 continue;
951 971
952 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 972 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
953 script_root = strdup(script_dirent.d_name); 973 script_root = get_script_root(&script_dirent, REPORT_SUFFIX);
954 str = (char *)ends_with(script_root, REPORT_SUFFIX); 974 if (script_root) {
955 if (str) {
956 *str = '\0';
957 desc = script_desc__findnew(script_root); 975 desc = script_desc__findnew(script_root);
958 snprintf(script_path, MAXPATHLEN, "%s/%s", 976 snprintf(script_path, MAXPATHLEN, "%s/%s",
959 lang_path, script_dirent.d_name); 977 lang_path, script_dirent.d_name);
960 read_script_info(desc, script_path); 978 read_script_info(desc, script_path);
979 free(script_root);
961 } 980 }
962 free(script_root);
963 } 981 }
964 } 982 }
965 983
@@ -981,8 +999,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
981 char script_path[MAXPATHLEN]; 999 char script_path[MAXPATHLEN];
982 DIR *scripts_dir, *lang_dir; 1000 DIR *scripts_dir, *lang_dir;
983 char lang_path[MAXPATHLEN]; 1001 char lang_path[MAXPATHLEN];
984 char *str, *__script_root; 1002 char *__script_root;
985 char *path = NULL;
986 1003
987 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1004 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
988 1005
@@ -998,23 +1015,18 @@ static char *get_script_path(const char *script_root, const char *suffix)
998 continue; 1015 continue;
999 1016
1000 for_each_script(lang_path, lang_dir, script_dirent, script_next) { 1017 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
1001 __script_root = strdup(script_dirent.d_name); 1018 __script_root = get_script_root(&script_dirent, suffix);
1002 str = (char *)ends_with(__script_root, suffix); 1019 if (__script_root && !strcmp(script_root, __script_root)) {
1003 if (str) { 1020 free(__script_root);
1004 *str = '\0';
1005 if (strcmp(__script_root, script_root))
1006 continue;
1007 snprintf(script_path, MAXPATHLEN, "%s/%s", 1021 snprintf(script_path, MAXPATHLEN, "%s/%s",
1008 lang_path, script_dirent.d_name); 1022 lang_path, script_dirent.d_name);
1009 path = strdup(script_path); 1023 return strdup(script_path);
1010 free(__script_root);
1011 break;
1012 } 1024 }
1013 free(__script_root); 1025 free(__script_root);
1014 } 1026 }
1015 } 1027 }
1016 1028
1017 return path; 1029 return NULL;
1018} 1030}
1019 1031
1020static bool is_top_script(const char *script_path) 1032static bool is_top_script(const char *script_path)
@@ -1083,7 +1095,11 @@ static const struct option options[] = {
1083 OPT_CALLBACK('f', "fields", NULL, "str", 1095 OPT_CALLBACK('f', "fields", NULL, "str",
1084 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", 1096 "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
1085 parse_output_fields), 1097 parse_output_fields),
1086 OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), 1098 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1099 "system-wide collection from all CPUs"),
1100 OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1101 OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1102 "only display events for these comms"),
1087 OPT_BOOLEAN('I', "show-info", &show_full_info, 1103 OPT_BOOLEAN('I', "show-info", &show_full_info,
1088 "display extended information from perf.data file"), 1104 "display extended information from perf.data file"),
1089 OPT_END() 1105 OPT_END()
@@ -1110,7 +1126,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1110 struct perf_session *session; 1126 struct perf_session *session;
1111 char *script_path = NULL; 1127 char *script_path = NULL;
1112 const char **__argv; 1128 const char **__argv;
1113 bool system_wide;
1114 int i, j, err; 1129 int i, j, err;
1115 1130
1116 setup_scripting(); 1131 setup_scripting();
@@ -1178,15 +1193,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1178 } 1193 }
1179 1194
1180 if (!pid) { 1195 if (!pid) {
1181 system_wide = true;
1182 j = 0; 1196 j = 0;
1183 1197
1184 dup2(live_pipe[1], 1); 1198 dup2(live_pipe[1], 1);
1185 close(live_pipe[0]); 1199 close(live_pipe[0]);
1186 1200
1187 if (!is_top_script(argv[0])) 1201 if (is_top_script(argv[0])) {
1202 system_wide = true;
1203 } else if (!system_wide) {
1188 system_wide = !have_cmd(argc - rep_args, 1204 system_wide = !have_cmd(argc - rep_args,
1189 &argv[rep_args]); 1205 &argv[rep_args]);
1206 }
1190 1207
1191 __argv = malloc((argc + 6) * sizeof(const char *)); 1208 __argv = malloc((argc + 6) * sizeof(const char *));
1192 if (!__argv) 1209 if (!__argv)
@@ -1234,10 +1251,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1234 script_path = rep_script_path; 1251 script_path = rep_script_path;
1235 1252
1236 if (script_path) { 1253 if (script_path) {
1237 system_wide = false;
1238 j = 0; 1254 j = 0;
1239 1255
1240 if (rec_script_path) 1256 if (!rec_script_path)
1257 system_wide = false;
1258 else if (!system_wide)
1241 system_wide = !have_cmd(argc - 1, &argv[1]); 1259 system_wide = !have_cmd(argc - 1, &argv[1]);
1242 1260
1243 __argv = malloc((argc + 2) * sizeof(const char *)); 1261 __argv = malloc((argc + 2) * sizeof(const char *));
@@ -1261,7 +1279,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1261 if (!script_name) 1279 if (!script_name)
1262 setup_pager(); 1280 setup_pager();
1263 1281
1264 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); 1282 session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script);
1265 if (session == NULL) 1283 if (session == NULL)
1266 return -ENOMEM; 1284 return -ENOMEM;
1267 1285
@@ -1287,7 +1305,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
1287 return -1; 1305 return -1;
1288 } 1306 }
1289 1307
1290 input = open(input_name, O_RDONLY); 1308 input = open(session->filename, O_RDONLY); /* input_name */
1291 if (input < 0) { 1309 if (input < 0) {
1292 perror("failed to open file"); 1310 perror("failed to open file");
1293 exit(-1); 1311 exit(-1);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 955930e0a5c3..f5d2a63eba66 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -578,6 +578,33 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
578 avg / avg_stats(&walltime_nsecs_stats)); 578 avg / avg_stats(&walltime_nsecs_stats));
579} 579}
580 580
581/* used for get_ratio_color() */
582enum grc_type {
583 GRC_STALLED_CYCLES_FE,
584 GRC_STALLED_CYCLES_BE,
585 GRC_CACHE_MISSES,
586 GRC_MAX_NR
587};
588
589static const char *get_ratio_color(enum grc_type type, double ratio)
590{
591 static const double grc_table[GRC_MAX_NR][3] = {
592 [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
593 [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
594 [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 },
595 };
596 const char *color = PERF_COLOR_NORMAL;
597
598 if (ratio > grc_table[type][0])
599 color = PERF_COLOR_RED;
600 else if (ratio > grc_table[type][1])
601 color = PERF_COLOR_MAGENTA;
602 else if (ratio > grc_table[type][2])
603 color = PERF_COLOR_YELLOW;
604
605 return color;
606}
607
581static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 608static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
582{ 609{
583 double total, ratio = 0.0; 610 double total, ratio = 0.0;
@@ -588,13 +615,7 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
588 if (total) 615 if (total)
589 ratio = avg / total * 100.0; 616 ratio = avg / total * 100.0;
590 617
591 color = PERF_COLOR_NORMAL; 618 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
592 if (ratio > 50.0)
593 color = PERF_COLOR_RED;
594 else if (ratio > 30.0)
595 color = PERF_COLOR_MAGENTA;
596 else if (ratio > 10.0)
597 color = PERF_COLOR_YELLOW;
598 619
599 fprintf(output, " # "); 620 fprintf(output, " # ");
600 color_fprintf(output, color, "%6.2f%%", ratio); 621 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -611,13 +632,7 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
611 if (total) 632 if (total)
612 ratio = avg / total * 100.0; 633 ratio = avg / total * 100.0;
613 634
614 color = PERF_COLOR_NORMAL; 635 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
615 if (ratio > 75.0)
616 color = PERF_COLOR_RED;
617 else if (ratio > 50.0)
618 color = PERF_COLOR_MAGENTA;
619 else if (ratio > 20.0)
620 color = PERF_COLOR_YELLOW;
621 636
622 fprintf(output, " # "); 637 fprintf(output, " # ");
623 color_fprintf(output, color, "%6.2f%%", ratio); 638 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -634,13 +649,7 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
634 if (total) 649 if (total)
635 ratio = avg / total * 100.0; 650 ratio = avg / total * 100.0;
636 651
637 color = PERF_COLOR_NORMAL; 652 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
638 if (ratio > 20.0)
639 color = PERF_COLOR_RED;
640 else if (ratio > 10.0)
641 color = PERF_COLOR_MAGENTA;
642 else if (ratio > 5.0)
643 color = PERF_COLOR_YELLOW;
644 653
645 fprintf(output, " # "); 654 fprintf(output, " # ");
646 color_fprintf(output, color, "%6.2f%%", ratio); 655 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -657,13 +666,7 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
657 if (total) 666 if (total)
658 ratio = avg / total * 100.0; 667 ratio = avg / total * 100.0;
659 668
660 color = PERF_COLOR_NORMAL; 669 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
661 if (ratio > 20.0)
662 color = PERF_COLOR_RED;
663 else if (ratio > 10.0)
664 color = PERF_COLOR_MAGENTA;
665 else if (ratio > 5.0)
666 color = PERF_COLOR_YELLOW;
667 670
668 fprintf(output, " # "); 671 fprintf(output, " # ");
669 color_fprintf(output, color, "%6.2f%%", ratio); 672 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -680,13 +683,7 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
680 if (total) 683 if (total)
681 ratio = avg / total * 100.0; 684 ratio = avg / total * 100.0;
682 685
683 color = PERF_COLOR_NORMAL; 686 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
684 if (ratio > 20.0)
685 color = PERF_COLOR_RED;
686 else if (ratio > 10.0)
687 color = PERF_COLOR_MAGENTA;
688 else if (ratio > 5.0)
689 color = PERF_COLOR_YELLOW;
690 687
691 fprintf(output, " # "); 688 fprintf(output, " # ");
692 color_fprintf(output, color, "%6.2f%%", ratio); 689 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -703,13 +700,7 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
703 if (total) 700 if (total)
704 ratio = avg / total * 100.0; 701 ratio = avg / total * 100.0;
705 702
706 color = PERF_COLOR_NORMAL; 703 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
707 if (ratio > 20.0)
708 color = PERF_COLOR_RED;
709 else if (ratio > 10.0)
710 color = PERF_COLOR_MAGENTA;
711 else if (ratio > 5.0)
712 color = PERF_COLOR_YELLOW;
713 704
714 fprintf(output, " # "); 705 fprintf(output, " # ");
715 color_fprintf(output, color, "%6.2f%%", ratio); 706 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -726,13 +717,7 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
726 if (total) 717 if (total)
727 ratio = avg / total * 100.0; 718 ratio = avg / total * 100.0;
728 719
729 color = PERF_COLOR_NORMAL; 720 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
730 if (ratio > 20.0)
731 color = PERF_COLOR_RED;
732 else if (ratio > 10.0)
733 color = PERF_COLOR_MAGENTA;
734 else if (ratio > 5.0)
735 color = PERF_COLOR_YELLOW;
736 721
737 fprintf(output, " # "); 722 fprintf(output, " # ");
738 color_fprintf(output, color, "%6.2f%%", ratio); 723 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -749,13 +734,7 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
749 if (total) 734 if (total)
750 ratio = avg / total * 100.0; 735 ratio = avg / total * 100.0;
751 736
752 color = PERF_COLOR_NORMAL; 737 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
753 if (ratio > 20.0)
754 color = PERF_COLOR_RED;
755 else if (ratio > 10.0)
756 color = PERF_COLOR_MAGENTA;
757 else if (ratio > 5.0)
758 color = PERF_COLOR_YELLOW;
759 738
760 fprintf(output, " # "); 739 fprintf(output, " # ");
761 color_fprintf(output, color, "%6.2f%%", ratio); 740 color_fprintf(output, color, "%6.2f%%", ratio);
@@ -1108,22 +1087,13 @@ static const struct option options[] = {
1108 */ 1087 */
1109static int add_default_attributes(void) 1088static int add_default_attributes(void)
1110{ 1089{
1111 struct perf_evsel *pos;
1112 size_t attr_nr = 0;
1113 size_t c;
1114
1115 /* Set attrs if no event is selected and !null_run: */ 1090 /* Set attrs if no event is selected and !null_run: */
1116 if (null_run) 1091 if (null_run)
1117 return 0; 1092 return 0;
1118 1093
1119 if (!evsel_list->nr_entries) { 1094 if (!evsel_list->nr_entries) {
1120 for (c = 0; c < ARRAY_SIZE(default_attrs); c++) { 1095 if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0)
1121 pos = perf_evsel__new(default_attrs + c, c + attr_nr); 1096 return -1;
1122 if (pos == NULL)
1123 return -1;
1124 perf_evlist__add(evsel_list, pos);
1125 }
1126 attr_nr += c;
1127 } 1097 }
1128 1098
1129 /* Detailed events get appended to the event list: */ 1099 /* Detailed events get appended to the event list: */
@@ -1132,38 +1102,21 @@ static int add_default_attributes(void)
1132 return 0; 1102 return 0;
1133 1103
1134 /* Append detailed run extra attributes: */ 1104 /* Append detailed run extra attributes: */
1135 for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) { 1105 if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0)
1136 pos = perf_evsel__new(detailed_attrs + c, c + attr_nr); 1106 return -1;
1137 if (pos == NULL)
1138 return -1;
1139 perf_evlist__add(evsel_list, pos);
1140 }
1141 attr_nr += c;
1142 1107
1143 if (detailed_run < 2) 1108 if (detailed_run < 2)
1144 return 0; 1109 return 0;
1145 1110
1146 /* Append very detailed run extra attributes: */ 1111 /* Append very detailed run extra attributes: */
1147 for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) { 1112 if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0)
1148 pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr); 1113 return -1;
1149 if (pos == NULL)
1150 return -1;
1151 perf_evlist__add(evsel_list, pos);
1152 }
1153 1114
1154 if (detailed_run < 3) 1115 if (detailed_run < 3)
1155 return 0; 1116 return 0;
1156 1117
1157 /* Append very, very detailed run extra attributes: */ 1118 /* Append very, very detailed run extra attributes: */
1158 for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) { 1119 return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs);
1159 pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
1160 if (pos == NULL)
1161 return -1;
1162 perf_evlist__add(evsel_list, pos);
1163 }
1164
1165
1166 return 0;
1167} 1120}
1168 1121
1169int cmd_stat(int argc, const char **argv, const char *prefix __used) 1122int cmd_stat(int argc, const char **argv, const char *prefix __used)
@@ -1267,8 +1220,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1267 1220
1268 list_for_each_entry(pos, &evsel_list->entries, node) { 1221 list_for_each_entry(pos, &evsel_list->entries, node) {
1269 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1222 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
1270 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 || 1223 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
1271 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
1272 goto out_free_fd; 1224 goto out_free_fd;
1273 } 1225 }
1274 1226
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 831d1baeac37..2b9a7f497a20 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -7,6 +7,7 @@
7 7
8#include "util/cache.h" 8#include "util/cache.h"
9#include "util/debug.h" 9#include "util/debug.h"
10#include "util/debugfs.h"
10#include "util/evlist.h" 11#include "util/evlist.h"
11#include "util/parse-options.h" 12#include "util/parse-options.h"
12#include "util/parse-events.h" 13#include "util/parse-events.h"
@@ -14,8 +15,6 @@
14#include "util/thread_map.h" 15#include "util/thread_map.h"
15#include "../../include/linux/hw_breakpoint.h" 16#include "../../include/linux/hw_breakpoint.h"
16 17
17static long page_size;
18
19static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) 18static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
20{ 19{
21 bool *visited = symbol__priv(sym); 20 bool *visited = symbol__priv(sym);
@@ -31,6 +30,7 @@ static int test__vmlinux_matches_kallsyms(void)
31 struct map *kallsyms_map, *vmlinux_map; 30 struct map *kallsyms_map, *vmlinux_map;
32 struct machine kallsyms, vmlinux; 31 struct machine kallsyms, vmlinux;
33 enum map_type type = MAP__FUNCTION; 32 enum map_type type = MAP__FUNCTION;
33 long page_size = sysconf(_SC_PAGE_SIZE);
34 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; 34 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
35 35
36 /* 36 /*
@@ -247,7 +247,7 @@ static int trace_event__id(const char *evname)
247 247
248 if (asprintf(&filename, 248 if (asprintf(&filename,
249 "%s/syscalls/%s/id", 249 "%s/syscalls/%s/id",
250 debugfs_path, evname) < 0) 250 tracing_events_path, evname) < 0)
251 return -1; 251 return -1;
252 252
253 fd = open(filename, O_RDONLY); 253 fd = open(filename, O_RDONLY);
@@ -603,7 +603,7 @@ out_free_threads:
603 603
604#define TEST_ASSERT_VAL(text, cond) \ 604#define TEST_ASSERT_VAL(text, cond) \
605do { \ 605do { \
606 if (!cond) { \ 606 if (!(cond)) { \
607 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ 607 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
608 return -1; \ 608 return -1; \
609 } \ 609 } \
@@ -759,6 +759,103 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
759 return 0; 759 return 0;
760} 760}
761 761
762static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
763{
764 struct perf_evsel *evsel = list_entry(evlist->entries.next,
765 struct perf_evsel, node);
766
767 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
768 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
769 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
770 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
771
772 return test__checkevent_tracepoint(evlist);
773}
774
775static int
776test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
777{
778 struct perf_evsel *evsel;
779
780 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
781
782 list_for_each_entry(evsel, &evlist->entries, node) {
783 TEST_ASSERT_VAL("wrong exclude_user",
784 !evsel->attr.exclude_user);
785 TEST_ASSERT_VAL("wrong exclude_kernel",
786 evsel->attr.exclude_kernel);
787 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
788 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
789 }
790
791 return test__checkevent_tracepoint_multi(evlist);
792}
793
794static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
795{
796 struct perf_evsel *evsel = list_entry(evlist->entries.next,
797 struct perf_evsel, node);
798
799 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
800 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
801 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
802 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
803
804 return test__checkevent_raw(evlist);
805}
806
807static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
808{
809 struct perf_evsel *evsel = list_entry(evlist->entries.next,
810 struct perf_evsel, node);
811
812 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
813 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
814 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
815 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
816
817 return test__checkevent_numeric(evlist);
818}
819
820static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
821{
822 struct perf_evsel *evsel = list_entry(evlist->entries.next,
823 struct perf_evsel, node);
824
825 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
826 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
827 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
828 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
829
830 return test__checkevent_symbolic_name(evlist);
831}
832
833static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
834{
835 struct perf_evsel *evsel = list_entry(evlist->entries.next,
836 struct perf_evsel, node);
837
838 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
839 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
840 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
841 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
842
843 return test__checkevent_symbolic_alias(evlist);
844}
845
846static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
847{
848 struct perf_evsel *evsel = list_entry(evlist->entries.next,
849 struct perf_evsel, node);
850
851 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
852 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
853 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
854 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
855
856 return test__checkevent_genhw(evlist);
857}
858
762static struct test__event_st { 859static struct test__event_st {
763 const char *name; 860 const char *name;
764 __u32 type; 861 __u32 type;
@@ -808,6 +905,34 @@ static struct test__event_st {
808 .name = "mem:0:w", 905 .name = "mem:0:w",
809 .check = test__checkevent_breakpoint_w, 906 .check = test__checkevent_breakpoint_w,
810 }, 907 },
908 {
909 .name = "syscalls:sys_enter_open:k",
910 .check = test__checkevent_tracepoint_modifier,
911 },
912 {
913 .name = "syscalls:*:u",
914 .check = test__checkevent_tracepoint_multi_modifier,
915 },
916 {
917 .name = "r1:kp",
918 .check = test__checkevent_raw_modifier,
919 },
920 {
921 .name = "1:1:hp",
922 .check = test__checkevent_numeric_modifier,
923 },
924 {
925 .name = "instructions:h",
926 .check = test__checkevent_symbolic_name_modifier,
927 },
928 {
929 .name = "faults:u",
930 .check = test__checkevent_symbolic_alias_modifier,
931 },
932 {
933 .name = "L1-dcache-load-miss:kp",
934 .check = test__checkevent_genhw_modifier,
935 },
811}; 936};
812 937
813#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) 938#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
@@ -841,6 +966,336 @@ static int test__parse_events(void)
841 966
842 return ret; 967 return ret;
843} 968}
969
970static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
971 size_t *sizep)
972{
973 cpu_set_t *mask;
974 size_t size;
975 int i, cpu = -1, nrcpus = 1024;
976realloc:
977 mask = CPU_ALLOC(nrcpus);
978 size = CPU_ALLOC_SIZE(nrcpus);
979 CPU_ZERO_S(size, mask);
980
981 if (sched_getaffinity(pid, size, mask) == -1) {
982 CPU_FREE(mask);
983 if (errno == EINVAL && nrcpus < (1024 << 8)) {
984 nrcpus = nrcpus << 2;
985 goto realloc;
986 }
987 perror("sched_getaffinity");
988 return -1;
989 }
990
991 for (i = 0; i < nrcpus; i++) {
992 if (CPU_ISSET_S(i, size, mask)) {
993 if (cpu == -1) {
994 cpu = i;
995 *maskp = mask;
996 *sizep = size;
997 } else
998 CPU_CLR_S(i, size, mask);
999 }
1000 }
1001
1002 if (cpu == -1)
1003 CPU_FREE(mask);
1004
1005 return cpu;
1006}
1007
1008static int test__PERF_RECORD(void)
1009{
1010 struct perf_record_opts opts = {
1011 .target_pid = -1,
1012 .target_tid = -1,
1013 .no_delay = true,
1014 .freq = 10,
1015 .mmap_pages = 256,
1016 .sample_id_all_avail = true,
1017 };
1018 cpu_set_t *cpu_mask = NULL;
1019 size_t cpu_mask_size = 0;
1020 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1021 struct perf_evsel *evsel;
1022 struct perf_sample sample;
1023 const char *cmd = "sleep";
1024 const char *argv[] = { cmd, "1", NULL, };
1025 char *bname;
1026 u64 sample_type, prev_time = 0;
1027 bool found_cmd_mmap = false,
1028 found_libc_mmap = false,
1029 found_vdso_mmap = false,
1030 found_ld_mmap = false;
1031 int err = -1, errs = 0, i, wakeups = 0, sample_size;
1032 u32 cpu;
1033 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
1034
1035 if (evlist == NULL || argv == NULL) {
1036 pr_debug("Not enough memory to create evlist\n");
1037 goto out;
1038 }
1039
1040 /*
1041 * We need at least one evsel in the evlist, use the default
1042 * one: "cycles".
1043 */
1044 err = perf_evlist__add_default(evlist);
1045 if (err < 0) {
1046 pr_debug("Not enough memory to create evsel\n");
1047 goto out_delete_evlist;
1048 }
1049
1050 /*
1051 * Create maps of threads and cpus to monitor. In this case
1052 * we start with all threads and cpus (-1, -1) but then in
1053 * perf_evlist__prepare_workload we'll fill in the only thread
1054 * we're monitoring, the one forked there.
1055 */
1056 err = perf_evlist__create_maps(evlist, opts.target_pid,
1057 opts.target_tid, opts.cpu_list);
1058 if (err < 0) {
1059 pr_debug("Not enough memory to create thread/cpu maps\n");
1060 goto out_delete_evlist;
1061 }
1062
1063 /*
1064 * Prepare the workload in argv[] to run, it'll fork it, and then wait
1065 * for perf_evlist__start_workload() to exec it. This is done this way
1066 * so that we have time to open the evlist (calling sys_perf_event_open
1067 * on all the fds) and then mmap them.
1068 */
1069 err = perf_evlist__prepare_workload(evlist, &opts, argv);
1070 if (err < 0) {
1071 pr_debug("Couldn't run the workload!\n");
1072 goto out_delete_evlist;
1073 }
1074
1075 /*
1076 * Config the evsels, setting attr->comm on the first one, etc.
1077 */
1078 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
1079 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
1080 evsel->attr.sample_type |= PERF_SAMPLE_TID;
1081 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
1082 perf_evlist__config_attrs(evlist, &opts);
1083
1084 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask,
1085 &cpu_mask_size);
1086 if (err < 0) {
1087 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
1088 goto out_delete_evlist;
1089 }
1090
1091 cpu = err;
1092
1093 /*
1094 * So that we can check perf_sample.cpu on all the samples.
1095 */
1096 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) {
1097 pr_debug("sched_setaffinity: %s\n", strerror(errno));
1098 goto out_free_cpu_mask;
1099 }
1100
1101 /*
1102 * Call sys_perf_event_open on all the fds on all the evsels,
1103 * grouping them if asked to.
1104 */
1105 err = perf_evlist__open(evlist, opts.group);
1106 if (err < 0) {
1107 pr_debug("perf_evlist__open: %s\n", strerror(errno));
1108 goto out_delete_evlist;
1109 }
1110
1111 /*
1112 * mmap the first fd on a given CPU and ask for events for the other
1113 * fds in the same CPU to be injected in the same mmap ring buffer
1114 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
1115 */
1116 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
1117 if (err < 0) {
1118 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
1119 goto out_delete_evlist;
1120 }
1121
1122 /*
1123 * We'll need these two to parse the PERF_SAMPLE_* fields in each
1124 * event.
1125 */
1126 sample_type = perf_evlist__sample_type(evlist);
1127 sample_size = __perf_evsel__sample_size(sample_type);
1128
1129 /*
1130 * Now that all is properly set up, enable the events, they will
1131 * count just on workload.pid, which will start...
1132 */
1133 perf_evlist__enable(evlist);
1134
1135 /*
1136 * Now!
1137 */
1138 perf_evlist__start_workload(evlist);
1139
1140 while (1) {
1141 int before = total_events;
1142
1143 for (i = 0; i < evlist->nr_mmaps; i++) {
1144 union perf_event *event;
1145
1146 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1147 const u32 type = event->header.type;
1148 const char *name = perf_event__name(type);
1149
1150 ++total_events;
1151 if (type < PERF_RECORD_MAX)
1152 nr_events[type]++;
1153
1154 err = perf_event__parse_sample(event, sample_type,
1155 sample_size, true,
1156 &sample, false);
1157 if (err < 0) {
1158 if (verbose)
1159 perf_event__fprintf(event, stderr);
1160 pr_debug("Couldn't parse sample\n");
1161 goto out_err;
1162 }
1163
1164 if (verbose) {
1165 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
1166 perf_event__fprintf(event, stderr);
1167 }
1168
1169 if (prev_time > sample.time) {
1170 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
1171 name, prev_time, sample.time);
1172 ++errs;
1173 }
1174
1175 prev_time = sample.time;
1176
1177 if (sample.cpu != cpu) {
1178 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
1179 name, cpu, sample.cpu);
1180 ++errs;
1181 }
1182
1183 if ((pid_t)sample.pid != evlist->workload.pid) {
1184 pr_debug("%s with unexpected pid, expected %d, got %d\n",
1185 name, evlist->workload.pid, sample.pid);
1186 ++errs;
1187 }
1188
1189 if ((pid_t)sample.tid != evlist->workload.pid) {
1190 pr_debug("%s with unexpected tid, expected %d, got %d\n",
1191 name, evlist->workload.pid, sample.tid);
1192 ++errs;
1193 }
1194
1195 if ((type == PERF_RECORD_COMM ||
1196 type == PERF_RECORD_MMAP ||
1197 type == PERF_RECORD_FORK ||
1198 type == PERF_RECORD_EXIT) &&
1199 (pid_t)event->comm.pid != evlist->workload.pid) {
1200 pr_debug("%s with unexpected pid/tid\n", name);
1201 ++errs;
1202 }
1203
1204 if ((type == PERF_RECORD_COMM ||
1205 type == PERF_RECORD_MMAP) &&
1206 event->comm.pid != event->comm.tid) {
1207 pr_debug("%s with different pid/tid!\n", name);
1208 ++errs;
1209 }
1210
1211 switch (type) {
1212 case PERF_RECORD_COMM:
1213 if (strcmp(event->comm.comm, cmd)) {
1214 pr_debug("%s with unexpected comm!\n", name);
1215 ++errs;
1216 }
1217 break;
1218 case PERF_RECORD_EXIT:
1219 goto found_exit;
1220 case PERF_RECORD_MMAP:
1221 bname = strrchr(event->mmap.filename, '/');
1222 if (bname != NULL) {
1223 if (!found_cmd_mmap)
1224 found_cmd_mmap = !strcmp(bname + 1, cmd);
1225 if (!found_libc_mmap)
1226 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
1227 if (!found_ld_mmap)
1228 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
1229 } else if (!found_vdso_mmap)
1230 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
1231 break;
1232
1233 case PERF_RECORD_SAMPLE:
1234 /* Just ignore samples for now */
1235 break;
1236 default:
1237 pr_debug("Unexpected perf_event->header.type %d!\n",
1238 type);
1239 ++errs;
1240 }
1241 }
1242 }
1243
1244 /*
1245 * We don't use poll here because at least at 3.1 times the
1246 * PERF_RECORD_{!SAMPLE} events don't honour
1247 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
1248 */
1249 if (total_events == before && false)
1250 poll(evlist->pollfd, evlist->nr_fds, -1);
1251
1252 sleep(1);
1253 if (++wakeups > 5) {
1254 pr_debug("No PERF_RECORD_EXIT event!\n");
1255 break;
1256 }
1257 }
1258
1259found_exit:
1260 if (nr_events[PERF_RECORD_COMM] > 1) {
1261 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
1262 ++errs;
1263 }
1264
1265 if (nr_events[PERF_RECORD_COMM] == 0) {
1266 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
1267 ++errs;
1268 }
1269
1270 if (!found_cmd_mmap) {
1271 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
1272 ++errs;
1273 }
1274
1275 if (!found_libc_mmap) {
1276 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
1277 ++errs;
1278 }
1279
1280 if (!found_ld_mmap) {
1281 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
1282 ++errs;
1283 }
1284
1285 if (!found_vdso_mmap) {
1286 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
1287 ++errs;
1288 }
1289out_err:
1290 perf_evlist__munmap(evlist);
1291out_free_cpu_mask:
1292 CPU_FREE(cpu_mask);
1293out_delete_evlist:
1294 perf_evlist__delete(evlist);
1295out:
1296 return (err < 0 || errs > 0) ? -1 : 0;
1297}
1298
844static struct test { 1299static struct test {
845 const char *desc; 1300 const char *desc;
846 int (*func)(void); 1301 int (*func)(void);
@@ -866,45 +1321,89 @@ static struct test {
866 .func = test__parse_events, 1321 .func = test__parse_events,
867 }, 1322 },
868 { 1323 {
1324 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1325 .func = test__PERF_RECORD,
1326 },
1327 {
869 .func = NULL, 1328 .func = NULL,
870 }, 1329 },
871}; 1330};
872 1331
873static int __cmd_test(void) 1332static bool perf_test__matches(int curr, int argc, const char *argv[])
874{ 1333{
875 int i = 0; 1334 int i;
1335
1336 if (argc == 0)
1337 return true;
876 1338
877 page_size = sysconf(_SC_PAGE_SIZE); 1339 for (i = 0; i < argc; ++i) {
1340 char *end;
1341 long nr = strtoul(argv[i], &end, 10);
1342
1343 if (*end == '\0') {
1344 if (nr == curr + 1)
1345 return true;
1346 continue;
1347 }
1348
1349 if (strstr(tests[curr].desc, argv[i]))
1350 return true;
1351 }
1352
1353 return false;
1354}
1355
1356static int __cmd_test(int argc, const char *argv[])
1357{
1358 int i = 0;
878 1359
879 while (tests[i].func) { 1360 while (tests[i].func) {
880 int err; 1361 int curr = i++, err;
881 pr_info("%2d: %s:", i + 1, tests[i].desc); 1362
1363 if (!perf_test__matches(curr, argc, argv))
1364 continue;
1365
1366 pr_info("%2d: %s:", i, tests[curr].desc);
882 pr_debug("\n--- start ---\n"); 1367 pr_debug("\n--- start ---\n");
883 err = tests[i].func(); 1368 err = tests[curr].func();
884 pr_debug("---- end ----\n%s:", tests[i].desc); 1369 pr_debug("---- end ----\n%s:", tests[curr].desc);
885 pr_info(" %s\n", err ? "FAILED!\n" : "Ok"); 1370 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
886 ++i;
887 } 1371 }
888 1372
889 return 0; 1373 return 0;
890} 1374}
891 1375
892static const char * const test_usage[] = { 1376static int perf_test__list(int argc, const char **argv)
893 "perf test [<options>]", 1377{
894 NULL, 1378 int i = 0;
895}; 1379
1380 while (tests[i].func) {
1381 int curr = i++;
896 1382
897static const struct option test_options[] = { 1383 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
1384 continue;
1385
1386 pr_info("%2d: %s\n", i, tests[curr].desc);
1387 }
1388
1389 return 0;
1390}
1391
1392int cmd_test(int argc, const char **argv, const char *prefix __used)
1393{
1394 const char * const test_usage[] = {
1395 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
1396 NULL,
1397 };
1398 const struct option test_options[] = {
898 OPT_INTEGER('v', "verbose", &verbose, 1399 OPT_INTEGER('v', "verbose", &verbose,
899 "be more verbose (show symbol address, etc)"), 1400 "be more verbose (show symbol address, etc)"),
900 OPT_END() 1401 OPT_END()
901}; 1402 };
902 1403
903int cmd_test(int argc, const char **argv, const char *prefix __used)
904{
905 argc = parse_options(argc, argv, test_options, test_usage, 0); 1404 argc = parse_options(argc, argv, test_options, test_usage, 0);
906 if (argc) 1405 if (argc >= 1 && !strcmp(argv[0], "list"))
907 usage_with_options(test_usage, test_options); 1406 return perf_test__list(argc, argv);
908 1407
909 symbol_conf.priv_size = sizeof(int); 1408 symbol_conf.priv_size = sizeof(int);
910 symbol_conf.sort_by_name = true; 1409 symbol_conf.sort_by_name = true;
@@ -915,5 +1414,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
915 1414
916 setup_pager(); 1415 setup_pager();
917 1416
918 return __cmd_test(); 1417 return __cmd_test(argc, argv);
919} 1418}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index aa26f4d66d10..3b75b2e21ea5 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -19,6 +19,7 @@
19#include "util/color.h" 19#include "util/color.h"
20#include <linux/list.h> 20#include <linux/list.h>
21#include "util/cache.h" 21#include "util/cache.h"
22#include "util/evsel.h"
22#include <linux/rbtree.h> 23#include <linux/rbtree.h>
23#include "util/symbol.h" 24#include "util/symbol.h"
24#include "util/callchain.h" 25#include "util/callchain.h"
@@ -31,13 +32,14 @@
31#include "util/event.h" 32#include "util/event.h"
32#include "util/session.h" 33#include "util/session.h"
33#include "util/svghelper.h" 34#include "util/svghelper.h"
35#include "util/tool.h"
34 36
35#define SUPPORT_OLD_POWER_EVENTS 1 37#define SUPPORT_OLD_POWER_EVENTS 1
36#define PWR_EVENT_EXIT -1 38#define PWR_EVENT_EXIT -1
37 39
38 40
39static char const *input_name = "perf.data"; 41static const char *input_name;
40static char const *output_name = "output.svg"; 42static const char *output_name = "output.svg";
41 43
42static unsigned int numcpus; 44static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */ 45static u64 min_freq; /* Lowest CPU frequency seen */
@@ -273,25 +275,28 @@ static int cpus_cstate_state[MAX_CPUS];
273static u64 cpus_pstate_start_times[MAX_CPUS]; 275static u64 cpus_pstate_start_times[MAX_CPUS];
274static u64 cpus_pstate_state[MAX_CPUS]; 276static u64 cpus_pstate_state[MAX_CPUS];
275 277
276static int process_comm_event(union perf_event *event, 278static int process_comm_event(struct perf_tool *tool __used,
279 union perf_event *event,
277 struct perf_sample *sample __used, 280 struct perf_sample *sample __used,
278 struct perf_session *session __used) 281 struct machine *machine __used)
279{ 282{
280 pid_set_comm(event->comm.tid, event->comm.comm); 283 pid_set_comm(event->comm.tid, event->comm.comm);
281 return 0; 284 return 0;
282} 285}
283 286
284static int process_fork_event(union perf_event *event, 287static int process_fork_event(struct perf_tool *tool __used,
288 union perf_event *event,
285 struct perf_sample *sample __used, 289 struct perf_sample *sample __used,
286 struct perf_session *session __used) 290 struct machine *machine __used)
287{ 291{
288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 292 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
289 return 0; 293 return 0;
290} 294}
291 295
292static int process_exit_event(union perf_event *event, 296static int process_exit_event(struct perf_tool *tool __used,
297 union perf_event *event,
293 struct perf_sample *sample __used, 298 struct perf_sample *sample __used,
294 struct perf_session *session __used) 299 struct machine *machine __used)
295{ 300{
296 pid_exit(event->fork.pid, event->fork.time); 301 pid_exit(event->fork.pid, event->fork.time);
297 return 0; 302 return 0;
@@ -486,14 +491,15 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
486} 491}
487 492
488 493
489static int process_sample_event(union perf_event *event __used, 494static int process_sample_event(struct perf_tool *tool __used,
495 union perf_event *event __used,
490 struct perf_sample *sample, 496 struct perf_sample *sample,
491 struct perf_evsel *evsel __used, 497 struct perf_evsel *evsel,
492 struct perf_session *session) 498 struct machine *machine __used)
493{ 499{
494 struct trace_entry *te; 500 struct trace_entry *te;
495 501
496 if (session->sample_type & PERF_SAMPLE_TIME) { 502 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
497 if (!first_time || first_time > sample->time) 503 if (!first_time || first_time > sample->time)
498 first_time = sample->time; 504 first_time = sample->time;
499 if (last_time < sample->time) 505 if (last_time < sample->time)
@@ -501,7 +507,7 @@ static int process_sample_event(union perf_event *event __used,
501 } 507 }
502 508
503 te = (void *)sample->raw_data; 509 te = (void *)sample->raw_data;
504 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { 510 if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
505 char *event_str; 511 char *event_str;
506#ifdef SUPPORT_OLD_POWER_EVENTS 512#ifdef SUPPORT_OLD_POWER_EVENTS
507 struct power_entry_old *peo; 513 struct power_entry_old *peo;
@@ -974,7 +980,7 @@ static void write_svg_file(const char *filename)
974 svg_close(); 980 svg_close();
975} 981}
976 982
977static struct perf_event_ops event_ops = { 983static struct perf_tool perf_timechart = {
978 .comm = process_comm_event, 984 .comm = process_comm_event,
979 .fork = process_fork_event, 985 .fork = process_fork_event,
980 .exit = process_exit_event, 986 .exit = process_exit_event,
@@ -985,7 +991,7 @@ static struct perf_event_ops event_ops = {
985static int __cmd_timechart(void) 991static int __cmd_timechart(void)
986{ 992{
987 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 993 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
988 0, false, &event_ops); 994 0, false, &perf_timechart);
989 int ret = -EINVAL; 995 int ret = -EINVAL;
990 996
991 if (session == NULL) 997 if (session == NULL)
@@ -994,7 +1000,7 @@ static int __cmd_timechart(void)
994 if (!perf_session__has_traces(session, "timechart record")) 1000 if (!perf_session__has_traces(session, "timechart record"))
995 goto out_delete; 1001 goto out_delete;
996 1002
997 ret = perf_session__process_events(session, &event_ops); 1003 ret = perf_session__process_events(session, &perf_timechart);
998 if (ret) 1004 if (ret)
999 goto out_delete; 1005 goto out_delete;
1000 1006
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9cdedb58134..4f81eeb99875 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -64,44 +64,6 @@
64#include <linux/unistd.h> 64#include <linux/unistd.h>
65#include <linux/types.h> 65#include <linux/types.h>
66 66
67static struct perf_top top = {
68 .count_filter = 5,
69 .delay_secs = 2,
70 .target_pid = -1,
71 .target_tid = -1,
72 .freq = 1000, /* 1 KHz */
73};
74
75static bool system_wide = false;
76
77static bool use_tui, use_stdio;
78
79static bool sort_has_symbols;
80
81static bool dont_use_callchains;
82static char callchain_default_opt[] = "fractal,0.5,callee";
83
84
85static int default_interval = 0;
86
87static bool kptr_restrict_warned;
88static bool vmlinux_warned;
89static bool inherit = false;
90static int realtime_prio = 0;
91static bool group = false;
92static bool sample_id_all_avail = true;
93static unsigned int mmap_pages = 128;
94
95static bool dump_symtab = false;
96
97static struct winsize winsize;
98
99static const char *sym_filter = NULL;
100static int sym_pcnt_filter = 5;
101
102/*
103 * Source functions
104 */
105 67
106void get_term_dimensions(struct winsize *ws) 68void get_term_dimensions(struct winsize *ws)
107{ 69{
@@ -125,21 +87,23 @@ void get_term_dimensions(struct winsize *ws)
125 ws->ws_col = 80; 87 ws->ws_col = 80;
126} 88}
127 89
128static void update_print_entries(struct winsize *ws) 90static void perf_top__update_print_entries(struct perf_top *top)
129{ 91{
130 top.print_entries = ws->ws_row; 92 top->print_entries = top->winsize.ws_row;
131 93
132 if (top.print_entries > 9) 94 if (top->print_entries > 9)
133 top.print_entries -= 9; 95 top->print_entries -= 9;
134} 96}
135 97
136static void sig_winch_handler(int sig __used) 98static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg)
137{ 99{
138 get_term_dimensions(&winsize); 100 struct perf_top *top = arg;
139 update_print_entries(&winsize); 101
102 get_term_dimensions(&top->winsize);
103 perf_top__update_print_entries(top);
140} 104}
141 105
142static int parse_source(struct hist_entry *he) 106static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
143{ 107{
144 struct symbol *sym; 108 struct symbol *sym;
145 struct annotation *notes; 109 struct annotation *notes;
@@ -170,7 +134,7 @@ static int parse_source(struct hist_entry *he)
170 134
171 pthread_mutex_lock(&notes->lock); 135 pthread_mutex_lock(&notes->lock);
172 136
173 if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { 137 if (symbol__alloc_hist(sym) < 0) {
174 pthread_mutex_unlock(&notes->lock); 138 pthread_mutex_unlock(&notes->lock);
175 pr_err("Not enough memory for annotating '%s' symbol!\n", 139 pr_err("Not enough memory for annotating '%s' symbol!\n",
176 sym->name); 140 sym->name);
@@ -181,7 +145,7 @@ static int parse_source(struct hist_entry *he)
181 err = symbol__annotate(sym, map, 0); 145 err = symbol__annotate(sym, map, 0);
182 if (err == 0) { 146 if (err == 0) {
183out_assign: 147out_assign:
184 top.sym_filter_entry = he; 148 top->sym_filter_entry = he;
185 } 149 }
186 150
187 pthread_mutex_unlock(&notes->lock); 151 pthread_mutex_unlock(&notes->lock);
@@ -194,14 +158,16 @@ static void __zero_source_counters(struct hist_entry *he)
194 symbol__annotate_zero_histograms(sym); 158 symbol__annotate_zero_histograms(sym);
195} 159}
196 160
197static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) 161static void perf_top__record_precise_ip(struct perf_top *top,
162 struct hist_entry *he,
163 int counter, u64 ip)
198{ 164{
199 struct annotation *notes; 165 struct annotation *notes;
200 struct symbol *sym; 166 struct symbol *sym;
201 167
202 if (he == NULL || he->ms.sym == NULL || 168 if (he == NULL || he->ms.sym == NULL ||
203 ((top.sym_filter_entry == NULL || 169 ((top->sym_filter_entry == NULL ||
204 top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) 170 top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
205 return; 171 return;
206 172
207 sym = he->ms.sym; 173 sym = he->ms.sym;
@@ -210,8 +176,7 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
210 if (pthread_mutex_trylock(&notes->lock)) 176 if (pthread_mutex_trylock(&notes->lock))
211 return; 177 return;
212 178
213 if (notes->src == NULL && 179 if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
214 symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) {
215 pthread_mutex_unlock(&notes->lock); 180 pthread_mutex_unlock(&notes->lock);
216 pr_err("Not enough memory for annotating '%s' symbol!\n", 181 pr_err("Not enough memory for annotating '%s' symbol!\n",
217 sym->name); 182 sym->name);
@@ -225,8 +190,9 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip)
225 pthread_mutex_unlock(&notes->lock); 190 pthread_mutex_unlock(&notes->lock);
226} 191}
227 192
228static void show_details(struct hist_entry *he) 193static void perf_top__show_details(struct perf_top *top)
229{ 194{
195 struct hist_entry *he = top->sym_filter_entry;
230 struct annotation *notes; 196 struct annotation *notes;
231 struct symbol *symbol; 197 struct symbol *symbol;
232 int more; 198 int more;
@@ -242,15 +208,15 @@ static void show_details(struct hist_entry *he)
242 if (notes->src == NULL) 208 if (notes->src == NULL)
243 goto out_unlock; 209 goto out_unlock;
244 210
245 printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); 211 printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
246 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 212 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
247 213
248 more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, 214 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
249 0, sym_pcnt_filter, top.print_entries, 4); 215 0, top->sym_pcnt_filter, top->print_entries, 4);
250 if (top.zero) 216 if (top->zero)
251 symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); 217 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
252 else 218 else
253 symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); 219 symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx);
254 if (more != 0) 220 if (more != 0)
255 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 221 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
256out_unlock: 222out_unlock:
@@ -259,11 +225,9 @@ out_unlock:
259 225
260static const char CONSOLE_CLEAR[] = ""; 226static const char CONSOLE_CLEAR[] = "";
261 227
262static struct hist_entry * 228static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
263 perf_session__add_hist_entry(struct perf_session *session, 229 struct addr_location *al,
264 struct addr_location *al, 230 struct perf_sample *sample)
265 struct perf_sample *sample,
266 struct perf_evsel *evsel)
267{ 231{
268 struct hist_entry *he; 232 struct hist_entry *he;
269 233
@@ -271,50 +235,51 @@ static struct hist_entry *
271 if (he == NULL) 235 if (he == NULL)
272 return NULL; 236 return NULL;
273 237
274 session->hists.stats.total_period += sample->period; 238 evsel->hists.stats.total_period += sample->period;
275 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 239 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
276 return he; 240 return he;
277} 241}
278 242
279static void print_sym_table(void) 243static void perf_top__print_sym_table(struct perf_top *top)
280{ 244{
281 char bf[160]; 245 char bf[160];
282 int printed = 0; 246 int printed = 0;
283 const int win_width = winsize.ws_col - 1; 247 const int win_width = top->winsize.ws_col - 1;
284 248
285 puts(CONSOLE_CLEAR); 249 puts(CONSOLE_CLEAR);
286 250
287 perf_top__header_snprintf(&top, bf, sizeof(bf)); 251 perf_top__header_snprintf(top, bf, sizeof(bf));
288 printf("%s\n", bf); 252 printf("%s\n", bf);
289 253
290 perf_top__reset_sample_counters(&top); 254 perf_top__reset_sample_counters(top);
291 255
292 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 256 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
293 257
294 if (top.sym_evsel->hists.stats.nr_lost_warned != 258 if (top->sym_evsel->hists.stats.nr_lost_warned !=
295 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { 259 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
296 top.sym_evsel->hists.stats.nr_lost_warned = 260 top->sym_evsel->hists.stats.nr_lost_warned =
297 top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 261 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
298 color_fprintf(stdout, PERF_COLOR_RED, 262 color_fprintf(stdout, PERF_COLOR_RED,
299 "WARNING: LOST %d chunks, Check IO/CPU overload", 263 "WARNING: LOST %d chunks, Check IO/CPU overload",
300 top.sym_evsel->hists.stats.nr_lost_warned); 264 top->sym_evsel->hists.stats.nr_lost_warned);
301 ++printed; 265 ++printed;
302 } 266 }
303 267
304 if (top.sym_filter_entry) { 268 if (top->sym_filter_entry) {
305 show_details(top.sym_filter_entry); 269 perf_top__show_details(top);
306 return; 270 return;
307 } 271 }
308 272
309 hists__collapse_resort_threaded(&top.sym_evsel->hists); 273 hists__collapse_resort_threaded(&top->sym_evsel->hists);
310 hists__output_resort_threaded(&top.sym_evsel->hists); 274 hists__output_resort_threaded(&top->sym_evsel->hists);
311 hists__decay_entries_threaded(&top.sym_evsel->hists, 275 hists__decay_entries_threaded(&top->sym_evsel->hists,
312 top.hide_user_symbols, 276 top->hide_user_symbols,
313 top.hide_kernel_symbols); 277 top->hide_kernel_symbols);
314 hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); 278 hists__output_recalc_col_len(&top->sym_evsel->hists,
279 top->winsize.ws_row - 3);
315 putchar('\n'); 280 putchar('\n');
316 hists__fprintf(&top.sym_evsel->hists, NULL, false, false, 281 hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
317 winsize.ws_row - 4 - printed, win_width, stdout); 282 top->winsize.ws_row - 4 - printed, win_width, stdout);
318} 283}
319 284
320static void prompt_integer(int *target, const char *msg) 285static void prompt_integer(int *target, const char *msg)
@@ -352,17 +317,17 @@ static void prompt_percent(int *target, const char *msg)
352 *target = tmp; 317 *target = tmp;
353} 318}
354 319
355static void prompt_symbol(struct hist_entry **target, const char *msg) 320static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
356{ 321{
357 char *buf = malloc(0), *p; 322 char *buf = malloc(0), *p;
358 struct hist_entry *syme = *target, *n, *found = NULL; 323 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
359 struct rb_node *next; 324 struct rb_node *next;
360 size_t dummy = 0; 325 size_t dummy = 0;
361 326
362 /* zero counters of active symbol */ 327 /* zero counters of active symbol */
363 if (syme) { 328 if (syme) {
364 __zero_source_counters(syme); 329 __zero_source_counters(syme);
365 *target = NULL; 330 top->sym_filter_entry = NULL;
366 } 331 }
367 332
368 fprintf(stdout, "\n%s: ", msg); 333 fprintf(stdout, "\n%s: ", msg);
@@ -373,7 +338,7 @@ static void prompt_symbol(struct hist_entry **target, const char *msg)
373 if (p) 338 if (p)
374 *p = 0; 339 *p = 0;
375 340
376 next = rb_first(&top.sym_evsel->hists.entries); 341 next = rb_first(&top->sym_evsel->hists.entries);
377 while (next) { 342 while (next) {
378 n = rb_entry(next, struct hist_entry, rb_node); 343 n = rb_entry(next, struct hist_entry, rb_node);
379 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 344 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
@@ -386,47 +351,46 @@ static void prompt_symbol(struct hist_entry **target, const char *msg)
386 if (!found) { 351 if (!found) {
387 fprintf(stderr, "Sorry, %s is not active.\n", buf); 352 fprintf(stderr, "Sorry, %s is not active.\n", buf);
388 sleep(1); 353 sleep(1);
389 return;
390 } else 354 } else
391 parse_source(found); 355 perf_top__parse_source(top, found);
392 356
393out_free: 357out_free:
394 free(buf); 358 free(buf);
395} 359}
396 360
397static void print_mapped_keys(void) 361static void perf_top__print_mapped_keys(struct perf_top *top)
398{ 362{
399 char *name = NULL; 363 char *name = NULL;
400 364
401 if (top.sym_filter_entry) { 365 if (top->sym_filter_entry) {
402 struct symbol *sym = top.sym_filter_entry->ms.sym; 366 struct symbol *sym = top->sym_filter_entry->ms.sym;
403 name = sym->name; 367 name = sym->name;
404 } 368 }
405 369
406 fprintf(stdout, "\nMapped keys:\n"); 370 fprintf(stdout, "\nMapped keys:\n");
407 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); 371 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs);
408 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); 372 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries);
409 373
410 if (top.evlist->nr_entries > 1) 374 if (top->evlist->nr_entries > 1)
411 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); 375 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel));
412 376
413 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); 377 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
414 378
415 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 379 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter);
416 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 380 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
417 fprintf(stdout, "\t[S] stop annotation.\n"); 381 fprintf(stdout, "\t[S] stop annotation.\n");
418 382
419 fprintf(stdout, 383 fprintf(stdout,
420 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 384 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
421 top.hide_kernel_symbols ? "yes" : "no"); 385 top->hide_kernel_symbols ? "yes" : "no");
422 fprintf(stdout, 386 fprintf(stdout,
423 "\t[U] hide user symbols. \t(%s)\n", 387 "\t[U] hide user symbols. \t(%s)\n",
424 top.hide_user_symbols ? "yes" : "no"); 388 top->hide_user_symbols ? "yes" : "no");
425 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); 389 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0);
426 fprintf(stdout, "\t[qQ] quit.\n"); 390 fprintf(stdout, "\t[qQ] quit.\n");
427} 391}
428 392
429static int key_mapped(int c) 393static int perf_top__key_mapped(struct perf_top *top, int c)
430{ 394{
431 switch (c) { 395 switch (c) {
432 case 'd': 396 case 'd':
@@ -442,7 +406,7 @@ static int key_mapped(int c)
442 case 'S': 406 case 'S':
443 return 1; 407 return 1;
444 case 'E': 408 case 'E':
445 return top.evlist->nr_entries > 1 ? 1 : 0; 409 return top->evlist->nr_entries > 1 ? 1 : 0;
446 default: 410 default:
447 break; 411 break;
448 } 412 }
@@ -450,13 +414,13 @@ static int key_mapped(int c)
450 return 0; 414 return 0;
451} 415}
452 416
453static void handle_keypress(int c) 417static void perf_top__handle_keypress(struct perf_top *top, int c)
454{ 418{
455 if (!key_mapped(c)) { 419 if (!perf_top__key_mapped(top, c)) {
456 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 420 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
457 struct termios tc, save; 421 struct termios tc, save;
458 422
459 print_mapped_keys(); 423 perf_top__print_mapped_keys(top);
460 fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 424 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
461 fflush(stdout); 425 fflush(stdout);
462 426
@@ -471,81 +435,86 @@ static void handle_keypress(int c)
471 c = getc(stdin); 435 c = getc(stdin);
472 436
473 tcsetattr(0, TCSAFLUSH, &save); 437 tcsetattr(0, TCSAFLUSH, &save);
474 if (!key_mapped(c)) 438 if (!perf_top__key_mapped(top, c))
475 return; 439 return;
476 } 440 }
477 441
478 switch (c) { 442 switch (c) {
479 case 'd': 443 case 'd':
480 prompt_integer(&top.delay_secs, "Enter display delay"); 444 prompt_integer(&top->delay_secs, "Enter display delay");
481 if (top.delay_secs < 1) 445 if (top->delay_secs < 1)
482 top.delay_secs = 1; 446 top->delay_secs = 1;
483 break; 447 break;
484 case 'e': 448 case 'e':
485 prompt_integer(&top.print_entries, "Enter display entries (lines)"); 449 prompt_integer(&top->print_entries, "Enter display entries (lines)");
486 if (top.print_entries == 0) { 450 if (top->print_entries == 0) {
487 sig_winch_handler(SIGWINCH); 451 struct sigaction act = {
488 signal(SIGWINCH, sig_winch_handler); 452 .sa_sigaction = perf_top__sig_winch,
453 .sa_flags = SA_SIGINFO,
454 };
455 perf_top__sig_winch(SIGWINCH, NULL, top);
456 sigaction(SIGWINCH, &act, NULL);
489 } else 457 } else
490 signal(SIGWINCH, SIG_DFL); 458 signal(SIGWINCH, SIG_DFL);
491 break; 459 break;
492 case 'E': 460 case 'E':
493 if (top.evlist->nr_entries > 1) { 461 if (top->evlist->nr_entries > 1) {
494 /* Select 0 as the default event: */ 462 /* Select 0 as the default event: */
495 int counter = 0; 463 int counter = 0;
496 464
497 fprintf(stderr, "\nAvailable events:"); 465 fprintf(stderr, "\nAvailable events:");
498 466
499 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) 467 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
500 fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); 468 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
501 469
502 prompt_integer(&counter, "Enter details event counter"); 470 prompt_integer(&counter, "Enter details event counter");
503 471
504 if (counter >= top.evlist->nr_entries) { 472 if (counter >= top->evlist->nr_entries) {
505 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 473 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
506 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); 474 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
507 sleep(1); 475 sleep(1);
508 break; 476 break;
509 } 477 }
510 list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) 478 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
511 if (top.sym_evsel->idx == counter) 479 if (top->sym_evsel->idx == counter)
512 break; 480 break;
513 } else 481 } else
514 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 482 top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
515 break; 483 break;
516 case 'f': 484 case 'f':
517 prompt_integer(&top.count_filter, "Enter display event count filter"); 485 prompt_integer(&top->count_filter, "Enter display event count filter");
518 break; 486 break;
519 case 'F': 487 case 'F':
520 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 488 prompt_percent(&top->sym_pcnt_filter,
489 "Enter details display event filter (percent)");
521 break; 490 break;
522 case 'K': 491 case 'K':
523 top.hide_kernel_symbols = !top.hide_kernel_symbols; 492 top->hide_kernel_symbols = !top->hide_kernel_symbols;
524 break; 493 break;
525 case 'q': 494 case 'q':
526 case 'Q': 495 case 'Q':
527 printf("exiting.\n"); 496 printf("exiting.\n");
528 if (dump_symtab) 497 if (top->dump_symtab)
529 perf_session__fprintf_dsos(top.session, stderr); 498 perf_session__fprintf_dsos(top->session, stderr);
530 exit(0); 499 exit(0);
531 case 's': 500 case 's':
532 prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); 501 perf_top__prompt_symbol(top, "Enter details symbol");
533 break; 502 break;
534 case 'S': 503 case 'S':
535 if (!top.sym_filter_entry) 504 if (!top->sym_filter_entry)
536 break; 505 break;
537 else { 506 else {
538 struct hist_entry *syme = top.sym_filter_entry; 507 struct hist_entry *syme = top->sym_filter_entry;
539 508
540 top.sym_filter_entry = NULL; 509 top->sym_filter_entry = NULL;
541 __zero_source_counters(syme); 510 __zero_source_counters(syme);
542 } 511 }
543 break; 512 break;
544 case 'U': 513 case 'U':
545 top.hide_user_symbols = !top.hide_user_symbols; 514 top->hide_user_symbols = !top->hide_user_symbols;
546 break; 515 break;
547 case 'z': 516 case 'z':
548 top.zero = !top.zero; 517 top->zero = !top->zero;
549 break; 518 break;
550 default: 519 default:
551 break; 520 break;
@@ -563,28 +532,30 @@ static void perf_top__sort_new_samples(void *arg)
563 hists__collapse_resort_threaded(&t->sym_evsel->hists); 532 hists__collapse_resort_threaded(&t->sym_evsel->hists);
564 hists__output_resort_threaded(&t->sym_evsel->hists); 533 hists__output_resort_threaded(&t->sym_evsel->hists);
565 hists__decay_entries_threaded(&t->sym_evsel->hists, 534 hists__decay_entries_threaded(&t->sym_evsel->hists,
566 top.hide_user_symbols, 535 t->hide_user_symbols,
567 top.hide_kernel_symbols); 536 t->hide_kernel_symbols);
568} 537}
569 538
570static void *display_thread_tui(void *arg __used) 539static void *display_thread_tui(void *arg)
571{ 540{
541 struct perf_top *top = arg;
572 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 542 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
573 543
574 perf_top__sort_new_samples(&top); 544 perf_top__sort_new_samples(top);
575 perf_evlist__tui_browse_hists(top.evlist, help, 545 perf_evlist__tui_browse_hists(top->evlist, help,
576 perf_top__sort_new_samples, 546 perf_top__sort_new_samples,
577 &top, top.delay_secs); 547 top, top->delay_secs);
578 548
579 exit_browser(0); 549 exit_browser(0);
580 exit(0); 550 exit(0);
581 return NULL; 551 return NULL;
582} 552}
583 553
584static void *display_thread(void *arg __used) 554static void *display_thread(void *arg)
585{ 555{
586 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 556 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
587 struct termios tc, save; 557 struct termios tc, save;
558 struct perf_top *top = arg;
588 int delay_msecs, c; 559 int delay_msecs, c;
589 560
590 tcgetattr(0, &save); 561 tcgetattr(0, &save);
@@ -595,13 +566,13 @@ static void *display_thread(void *arg __used)
595 566
596 pthread__unblock_sigwinch(); 567 pthread__unblock_sigwinch();
597repeat: 568repeat:
598 delay_msecs = top.delay_secs * 1000; 569 delay_msecs = top->delay_secs * 1000;
599 tcsetattr(0, TCSANOW, &tc); 570 tcsetattr(0, TCSANOW, &tc);
600 /* trash return*/ 571 /* trash return*/
601 getc(stdin); 572 getc(stdin);
602 573
603 while (1) { 574 while (1) {
604 print_sym_table(); 575 perf_top__print_sym_table(top);
605 /* 576 /*
606 * Either timeout expired or we got an EINTR due to SIGWINCH, 577 * Either timeout expired or we got an EINTR due to SIGWINCH,
607 * refresh screen in both cases. 578 * refresh screen in both cases.
@@ -621,7 +592,7 @@ process_hotkey:
621 c = getc(stdin); 592 c = getc(stdin);
622 tcsetattr(0, TCSAFLUSH, &save); 593 tcsetattr(0, TCSAFLUSH, &save);
623 594
624 handle_keypress(c); 595 perf_top__handle_keypress(top, c);
625 goto repeat; 596 goto repeat;
626 597
627 return NULL; 598 return NULL;
@@ -673,47 +644,17 @@ static int symbol_filter(struct map *map __used, struct symbol *sym)
673 return 0; 644 return 0;
674} 645}
675 646
676static void perf_event__process_sample(const union perf_event *event, 647static void perf_event__process_sample(struct perf_tool *tool,
648 const union perf_event *event,
677 struct perf_evsel *evsel, 649 struct perf_evsel *evsel,
678 struct perf_sample *sample, 650 struct perf_sample *sample,
679 struct perf_session *session) 651 struct machine *machine)
680{ 652{
653 struct perf_top *top = container_of(tool, struct perf_top, tool);
681 struct symbol *parent = NULL; 654 struct symbol *parent = NULL;
682 u64 ip = event->ip.ip; 655 u64 ip = event->ip.ip;
683 struct addr_location al; 656 struct addr_location al;
684 struct machine *machine;
685 int err; 657 int err;
686 u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
687
688 ++top.samples;
689
690 switch (origin) {
691 case PERF_RECORD_MISC_USER:
692 ++top.us_samples;
693 if (top.hide_user_symbols)
694 return;
695 machine = perf_session__find_host_machine(session);
696 break;
697 case PERF_RECORD_MISC_KERNEL:
698 ++top.kernel_samples;
699 if (top.hide_kernel_symbols)
700 return;
701 machine = perf_session__find_host_machine(session);
702 break;
703 case PERF_RECORD_MISC_GUEST_KERNEL:
704 ++top.guest_kernel_samples;
705 machine = perf_session__find_machine(session, event->ip.pid);
706 break;
707 case PERF_RECORD_MISC_GUEST_USER:
708 ++top.guest_us_samples;
709 /*
710 * TODO: we don't process guest user from host side
711 * except simple counting.
712 */
713 return;
714 default:
715 return;
716 }
717 658
718 if (!machine && perf_guest) { 659 if (!machine && perf_guest) {
719 pr_err("Can't find guest [%d]'s kernel information\n", 660 pr_err("Can't find guest [%d]'s kernel information\n",
@@ -722,14 +663,14 @@ static void perf_event__process_sample(const union perf_event *event,
722 } 663 }
723 664
724 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 665 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
725 top.exact_samples++; 666 top->exact_samples++;
726 667
727 if (perf_event__preprocess_sample(event, session, &al, sample, 668 if (perf_event__preprocess_sample(event, machine, &al, sample,
728 symbol_filter) < 0 || 669 symbol_filter) < 0 ||
729 al.filtered) 670 al.filtered)
730 return; 671 return;
731 672
732 if (!kptr_restrict_warned && 673 if (!top->kptr_restrict_warned &&
733 symbol_conf.kptr_restrict && 674 symbol_conf.kptr_restrict &&
734 al.cpumode == PERF_RECORD_MISC_KERNEL) { 675 al.cpumode == PERF_RECORD_MISC_KERNEL) {
735 ui__warning( 676 ui__warning(
@@ -740,7 +681,7 @@ static void perf_event__process_sample(const union perf_event *event,
740 " modules" : ""); 681 " modules" : "");
741 if (use_browser <= 0) 682 if (use_browser <= 0)
742 sleep(5); 683 sleep(5);
743 kptr_restrict_warned = true; 684 top->kptr_restrict_warned = true;
744 } 685 }
745 686
746 if (al.sym == NULL) { 687 if (al.sym == NULL) {
@@ -756,7 +697,7 @@ static void perf_event__process_sample(const union perf_event *event,
756 * --hide-kernel-symbols, even if the user specifies an 697 * --hide-kernel-symbols, even if the user specifies an
757 * invalid --vmlinux ;-) 698 * invalid --vmlinux ;-)
758 */ 699 */
759 if (!kptr_restrict_warned && !vmlinux_warned && 700 if (!top->kptr_restrict_warned && !top->vmlinux_warned &&
760 al.map == machine->vmlinux_maps[MAP__FUNCTION] && 701 al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
761 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 702 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
762 if (symbol_conf.vmlinux_name) { 703 if (symbol_conf.vmlinux_name) {
@@ -769,7 +710,7 @@ static void perf_event__process_sample(const union perf_event *event,
769 710
770 if (use_browser <= 0) 711 if (use_browser <= 0)
771 sleep(5); 712 sleep(5);
772 vmlinux_warned = true; 713 top->vmlinux_warned = true;
773 } 714 }
774 } 715 }
775 716
@@ -778,70 +719,109 @@ static void perf_event__process_sample(const union perf_event *event,
778 719
779 if ((sort__has_parent || symbol_conf.use_callchain) && 720 if ((sort__has_parent || symbol_conf.use_callchain) &&
780 sample->callchain) { 721 sample->callchain) {
781 err = perf_session__resolve_callchain(session, al.thread, 722 err = machine__resolve_callchain(machine, evsel, al.thread,
782 sample->callchain, &parent); 723 sample->callchain, &parent);
783 if (err) 724 if (err)
784 return; 725 return;
785 } 726 }
786 727
787 he = perf_session__add_hist_entry(session, &al, sample, evsel); 728 he = perf_evsel__add_hist_entry(evsel, &al, sample);
788 if (he == NULL) { 729 if (he == NULL) {
789 pr_err("Problem incrementing symbol period, skipping event\n"); 730 pr_err("Problem incrementing symbol period, skipping event\n");
790 return; 731 return;
791 } 732 }
792 733
793 if (symbol_conf.use_callchain) { 734 if (symbol_conf.use_callchain) {
794 err = callchain_append(he->callchain, &session->callchain_cursor, 735 err = callchain_append(he->callchain, &evsel->hists.callchain_cursor,
795 sample->period); 736 sample->period);
796 if (err) 737 if (err)
797 return; 738 return;
798 } 739 }
799 740
800 if (sort_has_symbols) 741 if (top->sort_has_symbols)
801 record_precise_ip(he, evsel->idx, ip); 742 perf_top__record_precise_ip(top, he, evsel->idx, ip);
802 } 743 }
803 744
804 return; 745 return;
805} 746}
806 747
807static void perf_session__mmap_read_idx(struct perf_session *self, int idx) 748static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
808{ 749{
809 struct perf_sample sample; 750 struct perf_sample sample;
810 struct perf_evsel *evsel; 751 struct perf_evsel *evsel;
752 struct perf_session *session = top->session;
811 union perf_event *event; 753 union perf_event *event;
754 struct machine *machine;
755 u8 origin;
812 int ret; 756 int ret;
813 757
814 while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { 758 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
815 ret = perf_session__parse_sample(self, event, &sample); 759 ret = perf_session__parse_sample(session, event, &sample);
816 if (ret) { 760 if (ret) {
817 pr_err("Can't parse sample, err = %d\n", ret); 761 pr_err("Can't parse sample, err = %d\n", ret);
818 continue; 762 continue;
819 } 763 }
820 764
821 evsel = perf_evlist__id2evsel(self->evlist, sample.id); 765 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
822 assert(evsel != NULL); 766 assert(evsel != NULL);
823 767
768 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
769
824 if (event->header.type == PERF_RECORD_SAMPLE) 770 if (event->header.type == PERF_RECORD_SAMPLE)
825 perf_event__process_sample(event, evsel, &sample, self); 771 ++top->samples;
826 else if (event->header.type < PERF_RECORD_MAX) { 772
773 switch (origin) {
774 case PERF_RECORD_MISC_USER:
775 ++top->us_samples;
776 if (top->hide_user_symbols)
777 continue;
778 machine = perf_session__find_host_machine(session);
779 break;
780 case PERF_RECORD_MISC_KERNEL:
781 ++top->kernel_samples;
782 if (top->hide_kernel_symbols)
783 continue;
784 machine = perf_session__find_host_machine(session);
785 break;
786 case PERF_RECORD_MISC_GUEST_KERNEL:
787 ++top->guest_kernel_samples;
788 machine = perf_session__find_machine(session, event->ip.pid);
789 break;
790 case PERF_RECORD_MISC_GUEST_USER:
791 ++top->guest_us_samples;
792 /*
793 * TODO: we don't process guest user from host side
794 * except simple counting.
795 */
796 /* Fall thru */
797 default:
798 continue;
799 }
800
801
802 if (event->header.type == PERF_RECORD_SAMPLE) {
803 perf_event__process_sample(&top->tool, event, evsel,
804 &sample, machine);
805 } else if (event->header.type < PERF_RECORD_MAX) {
827 hists__inc_nr_events(&evsel->hists, event->header.type); 806 hists__inc_nr_events(&evsel->hists, event->header.type);
828 perf_event__process(event, &sample, self); 807 perf_event__process(&top->tool, event, &sample, machine);
829 } else 808 } else
830 ++self->hists.stats.nr_unknown_events; 809 ++session->hists.stats.nr_unknown_events;
831 } 810 }
832} 811}
833 812
834static void perf_session__mmap_read(struct perf_session *self) 813static void perf_top__mmap_read(struct perf_top *top)
835{ 814{
836 int i; 815 int i;
837 816
838 for (i = 0; i < top.evlist->nr_mmaps; i++) 817 for (i = 0; i < top->evlist->nr_mmaps; i++)
839 perf_session__mmap_read_idx(self, i); 818 perf_top__mmap_read_idx(top, i);
840} 819}
841 820
842static void start_counters(struct perf_evlist *evlist) 821static void perf_top__start_counters(struct perf_top *top)
843{ 822{
844 struct perf_evsel *counter, *first; 823 struct perf_evsel *counter, *first;
824 struct perf_evlist *evlist = top->evlist;
845 825
846 first = list_entry(evlist->entries.next, struct perf_evsel, node); 826 first = list_entry(evlist->entries.next, struct perf_evsel, node);
847 827
@@ -849,15 +829,15 @@ static void start_counters(struct perf_evlist *evlist)
849 struct perf_event_attr *attr = &counter->attr; 829 struct perf_event_attr *attr = &counter->attr;
850 struct xyarray *group_fd = NULL; 830 struct xyarray *group_fd = NULL;
851 831
852 if (group && counter != first) 832 if (top->group && counter != first)
853 group_fd = first->fd; 833 group_fd = first->fd;
854 834
855 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 835 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
856 836
857 if (top.freq) { 837 if (top->freq) {
858 attr->sample_type |= PERF_SAMPLE_PERIOD; 838 attr->sample_type |= PERF_SAMPLE_PERIOD;
859 attr->freq = 1; 839 attr->freq = 1;
860 attr->sample_freq = top.freq; 840 attr->sample_freq = top->freq;
861 } 841 }
862 842
863 if (evlist->nr_entries > 1) { 843 if (evlist->nr_entries > 1) {
@@ -870,23 +850,23 @@ static void start_counters(struct perf_evlist *evlist)
870 850
871 attr->mmap = 1; 851 attr->mmap = 1;
872 attr->comm = 1; 852 attr->comm = 1;
873 attr->inherit = inherit; 853 attr->inherit = top->inherit;
874retry_sample_id: 854retry_sample_id:
875 attr->sample_id_all = sample_id_all_avail ? 1 : 0; 855 attr->sample_id_all = top->sample_id_all_avail ? 1 : 0;
876try_again: 856try_again:
877 if (perf_evsel__open(counter, top.evlist->cpus, 857 if (perf_evsel__open(counter, top->evlist->cpus,
878 top.evlist->threads, group, 858 top->evlist->threads, top->group,
879 group_fd) < 0) { 859 group_fd) < 0) {
880 int err = errno; 860 int err = errno;
881 861
882 if (err == EPERM || err == EACCES) { 862 if (err == EPERM || err == EACCES) {
883 ui__error_paranoid(); 863 ui__error_paranoid();
884 goto out_err; 864 goto out_err;
885 } else if (err == EINVAL && sample_id_all_avail) { 865 } else if (err == EINVAL && top->sample_id_all_avail) {
886 /* 866 /*
887 * Old kernel, no attr->sample_id_type_all field 867 * Old kernel, no attr->sample_id_type_all field
888 */ 868 */
889 sample_id_all_avail = false; 869 top->sample_id_all_avail = false;
890 goto retry_sample_id; 870 goto retry_sample_id;
891 } 871 }
892 /* 872 /*
@@ -920,7 +900,7 @@ try_again:
920 } 900 }
921 } 901 }
922 902
923 if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { 903 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
924 ui__warning("Failed to mmap with %d (%s)\n", 904 ui__warning("Failed to mmap with %d (%s)\n",
925 errno, strerror(errno)); 905 errno, strerror(errno));
926 goto out_err; 906 goto out_err;
@@ -933,14 +913,14 @@ out_err:
933 exit(0); 913 exit(0);
934} 914}
935 915
936static int setup_sample_type(void) 916static int perf_top__setup_sample_type(struct perf_top *top)
937{ 917{
938 if (!sort_has_symbols) { 918 if (!top->sort_has_symbols) {
939 if (symbol_conf.use_callchain) { 919 if (symbol_conf.use_callchain) {
940 ui__warning("Selected -g but \"sym\" not present in --sort/-s."); 920 ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
941 return -EINVAL; 921 return -EINVAL;
942 } 922 }
943 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 923 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
944 if (callchain_register_param(&callchain_param) < 0) { 924 if (callchain_register_param(&callchain_param) < 0) {
945 ui__warning("Can't register callchain params.\n"); 925 ui__warning("Can't register callchain params.\n");
946 return -EINVAL; 926 return -EINVAL;
@@ -950,7 +930,7 @@ static int setup_sample_type(void)
950 return 0; 930 return 0;
951} 931}
952 932
953static int __cmd_top(void) 933static int __cmd_top(struct perf_top *top)
954{ 934{
955 pthread_t thread; 935 pthread_t thread;
956 int ret; 936 int ret;
@@ -958,39 +938,40 @@ static int __cmd_top(void)
958 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 938 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
959 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 939 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
960 */ 940 */
961 top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); 941 top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
962 if (top.session == NULL) 942 if (top->session == NULL)
963 return -ENOMEM; 943 return -ENOMEM;
964 944
965 ret = setup_sample_type(); 945 ret = perf_top__setup_sample_type(top);
966 if (ret) 946 if (ret)
967 goto out_delete; 947 goto out_delete;
968 948
969 if (top.target_tid != -1) 949 if (top->target_tid != -1)
970 perf_event__synthesize_thread_map(top.evlist->threads, 950 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
971 perf_event__process, top.session); 951 perf_event__process,
952 &top->session->host_machine);
972 else 953 else
973 perf_event__synthesize_threads(perf_event__process, top.session); 954 perf_event__synthesize_threads(&top->tool, perf_event__process,
974 955 &top->session->host_machine);
975 start_counters(top.evlist); 956 perf_top__start_counters(top);
976 top.session->evlist = top.evlist; 957 top->session->evlist = top->evlist;
977 perf_session__update_sample_type(top.session); 958 perf_session__update_sample_type(top->session);
978 959
979 /* Wait for a minimal set of events before starting the snapshot */ 960 /* Wait for a minimal set of events before starting the snapshot */
980 poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 961 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
981 962
982 perf_session__mmap_read(top.session); 963 perf_top__mmap_read(top);
983 964
984 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 965 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
985 display_thread), NULL)) { 966 display_thread), top)) {
986 printf("Could not create display thread.\n"); 967 printf("Could not create display thread.\n");
987 exit(-1); 968 exit(-1);
988 } 969 }
989 970
990 if (realtime_prio) { 971 if (top->realtime_prio) {
991 struct sched_param param; 972 struct sched_param param;
992 973
993 param.sched_priority = realtime_prio; 974 param.sched_priority = top->realtime_prio;
994 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 975 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
995 printf("Could not set realtime priority.\n"); 976 printf("Could not set realtime priority.\n");
996 exit(-1); 977 exit(-1);
@@ -998,25 +979,25 @@ static int __cmd_top(void)
998 } 979 }
999 980
1000 while (1) { 981 while (1) {
1001 u64 hits = top.samples; 982 u64 hits = top->samples;
1002 983
1003 perf_session__mmap_read(top.session); 984 perf_top__mmap_read(top);
1004 985
1005 if (hits == top.samples) 986 if (hits == top->samples)
1006 ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); 987 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1007 } 988 }
1008 989
1009out_delete: 990out_delete:
1010 perf_session__delete(top.session); 991 perf_session__delete(top->session);
1011 top.session = NULL; 992 top->session = NULL;
1012 993
1013 return 0; 994 return 0;
1014} 995}
1015 996
1016static int 997static int
1017parse_callchain_opt(const struct option *opt __used, const char *arg, 998parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1018 int unset)
1019{ 999{
1000 struct perf_top *top = (struct perf_top *)opt->value;
1020 char *tok, *tok2; 1001 char *tok, *tok2;
1021 char *endptr; 1002 char *endptr;
1022 1003
@@ -1024,7 +1005,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1024 * --no-call-graph 1005 * --no-call-graph
1025 */ 1006 */
1026 if (unset) { 1007 if (unset) {
1027 dont_use_callchains = true; 1008 top->dont_use_callchains = true;
1028 return 0; 1009 return 0;
1029 } 1010 }
1030 1011
@@ -1052,9 +1033,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
1052 symbol_conf.use_callchain = false; 1033 symbol_conf.use_callchain = false;
1053 1034
1054 return 0; 1035 return 0;
1055 } 1036 } else
1056
1057 else
1058 return -1; 1037 return -1;
1059 1038
1060 /* get the min percentage */ 1039 /* get the min percentage */
@@ -1098,17 +1077,32 @@ static const char * const top_usage[] = {
1098 NULL 1077 NULL
1099}; 1078};
1100 1079
1101static const struct option options[] = { 1080int cmd_top(int argc, const char **argv, const char *prefix __used)
1081{
1082 struct perf_evsel *pos;
1083 int status = -ENOMEM;
1084 struct perf_top top = {
1085 .count_filter = 5,
1086 .delay_secs = 2,
1087 .target_pid = -1,
1088 .target_tid = -1,
1089 .freq = 1000, /* 1 KHz */
1090 .sample_id_all_avail = true,
1091 .mmap_pages = 128,
1092 .sym_pcnt_filter = 5,
1093 };
1094 char callchain_default_opt[] = "fractal,0.5,callee";
1095 const struct option options[] = {
1102 OPT_CALLBACK('e', "event", &top.evlist, "event", 1096 OPT_CALLBACK('e', "event", &top.evlist, "event",
1103 "event selector. use 'perf list' to list available events", 1097 "event selector. use 'perf list' to list available events",
1104 parse_events_option), 1098 parse_events_option),
1105 OPT_INTEGER('c', "count", &default_interval, 1099 OPT_INTEGER('c', "count", &top.default_interval,
1106 "event period to sample"), 1100 "event period to sample"),
1107 OPT_INTEGER('p', "pid", &top.target_pid, 1101 OPT_INTEGER('p', "pid", &top.target_pid,
1108 "profile events on existing process id"), 1102 "profile events on existing process id"),
1109 OPT_INTEGER('t', "tid", &top.target_tid, 1103 OPT_INTEGER('t', "tid", &top.target_tid,
1110 "profile events on existing thread id"), 1104 "profile events on existing thread id"),
1111 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1105 OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1112 "system-wide collection from all CPUs"), 1106 "system-wide collection from all CPUs"),
1113 OPT_STRING('C', "cpu", &top.cpu_list, "cpu", 1107 OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1114 "list of cpus to monitor"), 1108 "list of cpus to monitor"),
@@ -1116,20 +1110,20 @@ static const struct option options[] = {
1116 "file", "vmlinux pathname"), 1110 "file", "vmlinux pathname"),
1117 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1111 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1118 "hide kernel symbols"), 1112 "hide kernel symbols"),
1119 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 1113 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"),
1120 OPT_INTEGER('r', "realtime", &realtime_prio, 1114 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1121 "collect data with this RT SCHED_FIFO priority"), 1115 "collect data with this RT SCHED_FIFO priority"),
1122 OPT_INTEGER('d', "delay", &top.delay_secs, 1116 OPT_INTEGER('d', "delay", &top.delay_secs,
1123 "number of seconds to delay between refreshes"), 1117 "number of seconds to delay between refreshes"),
1124 OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 1118 OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab,
1125 "dump the symbol table used for profiling"), 1119 "dump the symbol table used for profiling"),
1126 OPT_INTEGER('f', "count-filter", &top.count_filter, 1120 OPT_INTEGER('f', "count-filter", &top.count_filter,
1127 "only display functions with more events than this"), 1121 "only display functions with more events than this"),
1128 OPT_BOOLEAN('g', "group", &group, 1122 OPT_BOOLEAN('g', "group", &top.group,
1129 "put the counters into a counter group"), 1123 "put the counters into a counter group"),
1130 OPT_BOOLEAN('i', "inherit", &inherit, 1124 OPT_BOOLEAN('i', "inherit", &top.inherit,
1131 "child tasks inherit counters"), 1125 "child tasks inherit counters"),
1132 OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", 1126 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1133 "symbol to annotate"), 1127 "symbol to annotate"),
1134 OPT_BOOLEAN('z', "zero", &top.zero, 1128 OPT_BOOLEAN('z', "zero", &top.zero,
1135 "zero history across updates"), 1129 "zero history across updates"),
@@ -1139,15 +1133,15 @@ static const struct option options[] = {
1139 "display this many functions"), 1133 "display this many functions"),
1140 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1134 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1141 "hide user symbols"), 1135 "hide user symbols"),
1142 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), 1136 OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"),
1143 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), 1137 OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"),
1144 OPT_INCR('v', "verbose", &verbose, 1138 OPT_INCR('v', "verbose", &verbose,
1145 "be more verbose (show counter open errors, etc)"), 1139 "be more verbose (show counter open errors, etc)"),
1146 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1140 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1147 "sort by key(s): pid, comm, dso, symbol, parent"), 1141 "sort by key(s): pid, comm, dso, symbol, parent"),
1148 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1142 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1149 "Show a column with the number of samples"), 1143 "Show a column with the number of samples"),
1150 OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", 1144 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
1151 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " 1145 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1152 "Default: fractal,0.5,callee", &parse_callchain_opt, 1146 "Default: fractal,0.5,callee", &parse_callchain_opt,
1153 callchain_default_opt), 1147 callchain_default_opt),
@@ -1166,12 +1160,7 @@ static const struct option options[] = {
1166 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1160 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1167 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1161 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1168 OPT_END() 1162 OPT_END()
1169}; 1163 };
1170
1171int cmd_top(int argc, const char **argv, const char *prefix __used)
1172{
1173 struct perf_evsel *pos;
1174 int status = -ENOMEM;
1175 1164
1176 top.evlist = perf_evlist__new(NULL, NULL); 1165 top.evlist = perf_evlist__new(NULL, NULL);
1177 if (top.evlist == NULL) 1166 if (top.evlist == NULL)
@@ -1188,9 +1177,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1188 1177
1189 setup_sorting(top_usage, options); 1178 setup_sorting(top_usage, options);
1190 1179
1191 if (use_stdio) 1180 if (top.use_stdio)
1192 use_browser = 0; 1181 use_browser = 0;
1193 else if (use_tui) 1182 else if (top.use_tui)
1194 use_browser = 1; 1183 use_browser = 1;
1195 1184
1196 setup_browser(false); 1185 setup_browser(false);
@@ -1215,38 +1204,31 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1215 return -ENOMEM; 1204 return -ENOMEM;
1216 } 1205 }
1217 1206
1207 symbol_conf.nr_events = top.evlist->nr_entries;
1208
1218 if (top.delay_secs < 1) 1209 if (top.delay_secs < 1)
1219 top.delay_secs = 1; 1210 top.delay_secs = 1;
1220 1211
1221 /* 1212 /*
1222 * User specified count overrides default frequency. 1213 * User specified count overrides default frequency.
1223 */ 1214 */
1224 if (default_interval) 1215 if (top.default_interval)
1225 top.freq = 0; 1216 top.freq = 0;
1226 else if (top.freq) { 1217 else if (top.freq) {
1227 default_interval = top.freq; 1218 top.default_interval = top.freq;
1228 } else { 1219 } else {
1229 fprintf(stderr, "frequency and count are zero, aborting\n"); 1220 fprintf(stderr, "frequency and count are zero, aborting\n");
1230 exit(EXIT_FAILURE); 1221 exit(EXIT_FAILURE);
1231 } 1222 }
1232 1223
1233 list_for_each_entry(pos, &top.evlist->entries, node) { 1224 list_for_each_entry(pos, &top.evlist->entries, node) {
1234 if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr,
1235 top.evlist->threads->nr) < 0)
1236 goto out_free_fd;
1237 /* 1225 /*
1238 * Fill in the ones not specifically initialized via -c: 1226 * Fill in the ones not specifically initialized via -c:
1239 */ 1227 */
1240 if (pos->attr.sample_period) 1228 if (!pos->attr.sample_period)
1241 continue; 1229 pos->attr.sample_period = top.default_interval;
1242
1243 pos->attr.sample_period = default_interval;
1244 } 1230 }
1245 1231
1246 if (perf_evlist__alloc_pollfd(top.evlist) < 0 ||
1247 perf_evlist__alloc_mmap(top.evlist) < 0)
1248 goto out_free_fd;
1249
1250 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); 1232 top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1251 1233
1252 symbol_conf.priv_size = sizeof(struct annotation); 1234 symbol_conf.priv_size = sizeof(struct annotation);
@@ -1263,16 +1245,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1263 * Avoid annotation data structures overhead when symbols aren't on the 1245 * Avoid annotation data structures overhead when symbols aren't on the
1264 * sort list. 1246 * sort list.
1265 */ 1247 */
1266 sort_has_symbols = sort_sym.list.next != NULL; 1248 top.sort_has_symbols = sort_sym.list.next != NULL;
1267 1249
1268 get_term_dimensions(&winsize); 1250 get_term_dimensions(&top.winsize);
1269 if (top.print_entries == 0) { 1251 if (top.print_entries == 0) {
1270 update_print_entries(&winsize); 1252 struct sigaction act = {
1271 signal(SIGWINCH, sig_winch_handler); 1253 .sa_sigaction = perf_top__sig_winch,
1254 .sa_flags = SA_SIGINFO,
1255 };
1256 perf_top__update_print_entries(&top);
1257 sigaction(SIGWINCH, &act, NULL);
1272 } 1258 }
1273 1259
1274 status = __cmd_top(); 1260 status = __cmd_top(&top);
1275out_free_fd: 1261
1276 perf_evlist__delete(top.evlist); 1262 perf_evlist__delete(top.evlist);
1277 1263
1278 return status; 1264 return status;
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 73d0cac8b67e..2b2e225a4d4c 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -29,8 +29,6 @@ struct pager_config {
29 int val; 29 int val;
30}; 30};
31 31
32static char debugfs_mntpt[MAXPATHLEN];
33
34static int pager_command_config(const char *var, const char *value, void *data) 32static int pager_command_config(const char *var, const char *value, void *data)
35{ 33{
36 struct pager_config *c = data; 34 struct pager_config *c = data;
@@ -81,15 +79,6 @@ static void commit_pager_choice(void)
81 } 79 }
82} 80}
83 81
84static void set_debugfs_path(void)
85{
86 char *path;
87
88 path = getenv(PERF_DEBUGFS_ENVIRONMENT);
89 snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt,
90 "tracing/events");
91}
92
93static int handle_options(const char ***argv, int *argc, int *envchanged) 82static int handle_options(const char ***argv, int *argc, int *envchanged)
94{ 83{
95 int handled = 0; 84 int handled = 0;
@@ -161,15 +150,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
161 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 150 fprintf(stderr, "No directory given for --debugfs-dir.\n");
162 usage(perf_usage_string); 151 usage(perf_usage_string);
163 } 152 }
164 strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN); 153 debugfs_set_path((*argv)[1]);
165 debugfs_mntpt[MAXPATHLEN - 1] = '\0';
166 if (envchanged) 154 if (envchanged)
167 *envchanged = 1; 155 *envchanged = 1;
168 (*argv)++; 156 (*argv)++;
169 (*argc)--; 157 (*argc)--;
170 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 158 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
171 strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN); 159 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
172 debugfs_mntpt[MAXPATHLEN - 1] = '\0'; 160 fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
173 if (envchanged) 161 if (envchanged)
174 *envchanged = 1; 162 *envchanged = 1;
175 } else { 163 } else {
@@ -281,7 +269,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
281 if (use_pager == -1 && p->option & USE_PAGER) 269 if (use_pager == -1 && p->option & USE_PAGER)
282 use_pager = 1; 270 use_pager = 1;
283 commit_pager_choice(); 271 commit_pager_choice();
284 set_debugfs_path();
285 272
286 status = p->fn(argc, argv, prefix); 273 status = p->fn(argc, argv, prefix);
287 exit_browser(status); 274 exit_browser(status);
@@ -416,17 +403,6 @@ static int run_argv(int *argcp, const char ***argv)
416 return done_alias; 403 return done_alias;
417} 404}
418 405
419/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
420static void get_debugfs_mntpt(void)
421{
422 const char *path = debugfs_mount(NULL);
423
424 if (path)
425 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
426 else
427 debugfs_mntpt[0] = '\0';
428}
429
430static void pthread__block_sigwinch(void) 406static void pthread__block_sigwinch(void)
431{ 407{
432 sigset_t set; 408 sigset_t set;
@@ -453,7 +429,7 @@ int main(int argc, const char **argv)
453 if (!cmd) 429 if (!cmd)
454 cmd = "perf-help"; 430 cmd = "perf-help";
455 /* get debugfs mount point from /proc/mounts */ 431 /* get debugfs mount point from /proc/mounts */
456 get_debugfs_mntpt(); 432 debugfs_mount(NULL);
457 /* 433 /*
458 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 434 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
459 * 435 *
@@ -476,7 +452,6 @@ int main(int argc, const char **argv)
476 argc--; 452 argc--;
477 handle_options(&argv, &argc, NULL); 453 handle_options(&argv, &argc, NULL);
478 commit_pager_choice(); 454 commit_pager_choice();
479 set_debugfs_path();
480 set_buildid_dir(); 455 set_buildid_dir();
481 456
482 if (argc > 0) { 457 if (argc > 0) {
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 914c895510f7..64f8bee31ced 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -185,4 +185,28 @@ extern const char perf_version_string[];
185 185
186void pthread__unblock_sigwinch(void); 186void pthread__unblock_sigwinch(void);
187 187
188struct perf_record_opts {
189 pid_t target_pid;
190 pid_t target_tid;
191 bool call_graph;
192 bool group;
193 bool inherit_stat;
194 bool no_delay;
195 bool no_inherit;
196 bool no_samples;
197 bool pipe_output;
198 bool raw_samples;
199 bool sample_address;
200 bool sample_time;
201 bool sample_id_all_avail;
202 bool system_wide;
203 bool period;
204 unsigned int freq;
205 unsigned int mmap_pages;
206 unsigned int user_freq;
207 u64 default_interval;
208 u64 user_interval;
209 const char *cpu_list;
210};
211
188#endif 212#endif
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 119e996035c8..011ed2676604 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -25,17 +25,17 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
25 return 0; 25 return 0;
26} 26}
27 27
28int symbol__alloc_hist(struct symbol *sym, int nevents) 28int symbol__alloc_hist(struct symbol *sym)
29{ 29{
30 struct annotation *notes = symbol__annotation(sym); 30 struct annotation *notes = symbol__annotation(sym);
31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + 31 size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
32 (sym->end - sym->start) * sizeof(u64)); 32 (sym->end - sym->start) * sizeof(u64));
33 33
34 notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); 34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 if (notes->src == NULL) 35 if (notes->src == NULL)
36 return -1; 36 return -1;
37 notes->src->sizeof_sym_hist = sizeof_sym_hist; 37 notes->src->sizeof_sym_hist = sizeof_sym_hist;
38 notes->src->nr_histograms = nevents; 38 notes->src->nr_histograms = symbol_conf.nr_events;
39 INIT_LIST_HEAD(&notes->src->source); 39 INIT_LIST_HEAD(&notes->src->source);
40 return 0; 40 return 0;
41} 41}
@@ -334,7 +334,7 @@ fallback:
334 disassembler_style ? "-M " : "", 334 disassembler_style ? "-M " : "",
335 disassembler_style ? disassembler_style : "", 335 disassembler_style ? disassembler_style : "",
336 map__rip_2objdump(map, sym->start), 336 map__rip_2objdump(map, sym->start),
337 map__rip_2objdump(map, sym->end), 337 map__rip_2objdump(map, sym->end+1),
338 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", 338 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
339 symbol_conf.annotate_src ? "-S" : "", 339 symbol_conf.annotate_src ? "-S" : "",
340 symfs_filename, filename); 340 symfs_filename, filename);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index d9072523d342..efa5dc82bfae 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -72,7 +72,7 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
72 72
73int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 73int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
74 int evidx, u64 addr); 74 int evidx, u64 addr);
75int symbol__alloc_hist(struct symbol *sym, int nevents); 75int symbol__alloc_hist(struct symbol *sym);
76void symbol__annotate_zero_histograms(struct symbol *sym); 76void symbol__annotate_zero_histograms(struct symbol *sym);
77 77
78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 78int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
@@ -99,8 +99,7 @@ static inline int symbol__tui_annotate(struct symbol *sym __used,
99} 99}
100#else 100#else
101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 101int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
102 int nr_events, void(*timer)(void *arg), void *arg, 102 void(*timer)(void *arg), void *arg, int delay_secs);
103 int delay_secs);
104#endif 103#endif
105 104
106extern const char *disassembler_style; 105extern const char *disassembler_style;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a91cd99f26ea..dff9c7a725f4 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -13,15 +13,18 @@
13#include "symbol.h" 13#include "symbol.h"
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include "debug.h" 15#include "debug.h"
16#include "session.h"
17#include "tool.h"
16 18
17static int build_id__mark_dso_hit(union perf_event *event, 19static int build_id__mark_dso_hit(struct perf_tool *tool __used,
20 union perf_event *event,
18 struct perf_sample *sample __used, 21 struct perf_sample *sample __used,
19 struct perf_evsel *evsel __used, 22 struct perf_evsel *evsel __used,
20 struct perf_session *session) 23 struct machine *machine)
21{ 24{
22 struct addr_location al; 25 struct addr_location al;
23 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
24 struct thread *thread = perf_session__findnew(session, event->ip.pid); 27 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
25 28
26 if (thread == NULL) { 29 if (thread == NULL) {
27 pr_err("problem processing %d event, skipping it.\n", 30 pr_err("problem processing %d event, skipping it.\n",
@@ -29,8 +32,8 @@ static int build_id__mark_dso_hit(union perf_event *event,
29 return -1; 32 return -1;
30 } 33 }
31 34
32 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 35 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
33 event->ip.pid, event->ip.ip, &al); 36 event->ip.ip, &al);
34 37
35 if (al.map != NULL) 38 if (al.map != NULL)
36 al.map->dso->hit = 1; 39 al.map->dso->hit = 1;
@@ -38,25 +41,26 @@ static int build_id__mark_dso_hit(union perf_event *event,
38 return 0; 41 return 0;
39} 42}
40 43
41static int perf_event__exit_del_thread(union perf_event *event, 44static int perf_event__exit_del_thread(struct perf_tool *tool __used,
45 union perf_event *event,
42 struct perf_sample *sample __used, 46 struct perf_sample *sample __used,
43 struct perf_session *session) 47 struct machine *machine)
44{ 48{
45 struct thread *thread = perf_session__findnew(session, event->fork.tid); 49 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
46 50
47 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 51 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
48 event->fork.ppid, event->fork.ptid); 52 event->fork.ppid, event->fork.ptid);
49 53
50 if (thread) { 54 if (thread) {
51 rb_erase(&thread->rb_node, &session->threads); 55 rb_erase(&thread->rb_node, &machine->threads);
52 session->last_match = NULL; 56 machine->last_match = NULL;
53 thread__delete(thread); 57 thread__delete(thread);
54 } 58 }
55 59
56 return 0; 60 return 0;
57} 61}
58 62
59struct perf_event_ops build_id__mark_dso_hit_ops = { 63struct perf_tool build_id__mark_dso_hit_ops = {
60 .sample = build_id__mark_dso_hit, 64 .sample = build_id__mark_dso_hit,
61 .mmap = perf_event__process_mmap, 65 .mmap = perf_event__process_mmap,
62 .fork = perf_event__process_task, 66 .fork = perf_event__process_task,
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 5dafb00eaa06..a993ba87d996 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -3,7 +3,7 @@
3 3
4#include "session.h" 4#include "session.h"
5 5
6extern struct perf_event_ops build_id__mark_dso_hit_ops; 6extern struct perf_tool build_id__mark_dso_hit_ops;
7 7
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 8char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9 9
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 9b4ff16cac96..7f9c0f1ae3a9 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -101,6 +101,9 @@ int callchain_append(struct callchain_root *root,
101int callchain_merge(struct callchain_cursor *cursor, 101int callchain_merge(struct callchain_cursor *cursor,
102 struct callchain_root *dst, struct callchain_root *src); 102 struct callchain_root *dst, struct callchain_root *src);
103 103
104struct ip_callchain;
105union perf_event;
106
104bool ip_callchain__valid(struct ip_callchain *chain, 107bool ip_callchain__valid(struct ip_callchain *chain,
105 const union perf_event *event); 108 const union perf_event *event);
106/* 109/*
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 96bee5c46008..dbe2f16b1a1a 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -3,7 +3,6 @@
3#include "parse-options.h" 3#include "parse-options.h"
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "debugfs.h" /* MAX_PATH, STR() */
7#include "evlist.h" 6#include "evlist.h"
8 7
9int nr_cgroups; 8int nr_cgroups;
@@ -12,7 +11,7 @@ static int
12cgroupfs_find_mountpoint(char *buf, size_t maxlen) 11cgroupfs_find_mountpoint(char *buf, size_t maxlen)
13{ 12{
14 FILE *fp; 13 FILE *fp;
15 char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; 14 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
16 char *token, *saved_ptr = NULL; 15 char *token, *saved_ptr = NULL;
17 int found = 0; 16 int found = 0;
18 17
@@ -25,8 +24,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
25 * and inspect every cgroupfs mount point to find one that has 24 * and inspect every cgroupfs mount point to find one that has
26 * perf_event subsystem 25 * perf_event subsystem
27 */ 26 */
28 while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %" 27 while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
29 STR(MAX_PATH)"s %*d %*d\n", 28 STR(PATH_MAX)"s %*d %*d\n",
30 mountpoint, type, tokens) == 3) { 29 mountpoint, type, tokens) == 3) {
31 30
32 if (!strcmp(type, "cgroup")) { 31 if (!strcmp(type, "cgroup")) {
@@ -57,15 +56,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
57 56
58static int open_cgroup(char *name) 57static int open_cgroup(char *name)
59{ 58{
60 char path[MAX_PATH+1]; 59 char path[PATH_MAX + 1];
61 char mnt[MAX_PATH+1]; 60 char mnt[PATH_MAX + 1];
62 int fd; 61 int fd;
63 62
64 63
65 if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1)) 64 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
66 return -1; 65 return -1;
67 66
68 snprintf(path, MAX_PATH, "%s/%s", mnt, name); 67 snprintf(path, PATH_MAX, "%s/%s", mnt, name);
69 68
70 fd = open(path, O_RDONLY); 69 fd = open(path, O_RDONLY);
71 if (fd == -1) 70 if (fd == -1)
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 80d9598db31a..0deac6a14b65 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -1,5 +1,8 @@
1/* 1/*
2 * GIT - The information manager from hell 2 * config.c
3 *
4 * Helper functions for parsing config items.
5 * Originally copied from GIT source.
3 * 6 *
4 * Copyright (C) Linus Torvalds, 2005 7 * Copyright (C) Linus Torvalds, 2005
5 * Copyright (C) Johannes Schindelin, 2005 8 * Copyright (C) Johannes Schindelin, 2005
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index a88fefc0cc0a..ffc35e748e89 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -2,8 +2,12 @@
2#include "debugfs.h" 2#include "debugfs.h"
3#include "cache.h" 3#include "cache.h"
4 4
5#include <linux/kernel.h>
6#include <sys/mount.h>
7
5static int debugfs_premounted; 8static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1]; 9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
7 11
8static const char *debugfs_known_mountpoints[] = { 12static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/", 13 "/sys/kernel/debug/",
@@ -62,11 +66,9 @@ const char *debugfs_find_mountpoint(void)
62 /* give up and parse /proc/mounts */ 66 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r"); 67 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL) 68 if (fp == NULL)
65 die("Can't open /proc/mounts for read"); 69 return NULL;
66 70
67 while (fscanf(fp, "%*s %" 71 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) { 72 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0) 73 if (strcmp(type, "debugfs") == 0)
72 break; 74 break;
@@ -106,6 +108,12 @@ int debugfs_valid_entry(const char *path)
106 return 0; 108 return 0;
107} 109}
108 110
111static void debugfs_set_tracing_events_path(const char *mountpoint)
112{
113 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
114 mountpoint, "tracing/events");
115}
116
109/* mount the debugfs somewhere if it's not mounted */ 117/* mount the debugfs somewhere if it's not mounted */
110 118
111char *debugfs_mount(const char *mountpoint) 119char *debugfs_mount(const char *mountpoint)
@@ -113,7 +121,7 @@ char *debugfs_mount(const char *mountpoint)
113 /* see if it's already mounted */ 121 /* see if it's already mounted */
114 if (debugfs_find_mountpoint()) { 122 if (debugfs_find_mountpoint()) {
115 debugfs_premounted = 1; 123 debugfs_premounted = 1;
116 return debugfs_mountpoint; 124 goto out;
117 } 125 }
118 126
119 /* if not mounted and no argument */ 127 /* if not mounted and no argument */
@@ -129,12 +137,19 @@ char *debugfs_mount(const char *mountpoint)
129 return NULL; 137 return NULL;
130 138
131 /* save the mountpoint */ 139 /* save the mountpoint */
132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1; 140 debugfs_found = 1;
134 141 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
142out:
143 debugfs_set_tracing_events_path(debugfs_mountpoint);
135 return debugfs_mountpoint; 144 return debugfs_mountpoint;
136} 145}
137 146
147void debugfs_set_path(const char *mountpoint)
148{
149 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
150 debugfs_set_tracing_events_path(mountpoint);
151}
152
138/* umount the debugfs */ 153/* umount the debugfs */
139 154
140int debugfs_umount(void) 155int debugfs_umount(void)
@@ -158,7 +173,7 @@ int debugfs_umount(void)
158 173
159int debugfs_write(const char *entry, const char *value) 174int debugfs_write(const char *entry, const char *value)
160{ 175{
161 char path[MAX_PATH+1]; 176 char path[PATH_MAX + 1];
162 int ret, count; 177 int ret, count;
163 int fd; 178 int fd;
164 179
@@ -203,7 +218,7 @@ int debugfs_write(const char *entry, const char *value)
203 */ 218 */
204int debugfs_read(const char *entry, char *buffer, size_t size) 219int debugfs_read(const char *entry, char *buffer, size_t size)
205{ 220{
206 char path[MAX_PATH+1]; 221 char path[PATH_MAX + 1];
207 int ret; 222 int ret;
208 int fd; 223 int fd;
209 224
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 83a02879745f..4a878f735eb0 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -1,25 +1,18 @@
1#ifndef __DEBUGFS_H__ 1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__ 2#define __DEBUGFS_H__
3 3
4#include <sys/mount.h> 4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs);
6int debugfs_valid_entry(const char *path);
7char *debugfs_mount(const char *mountpoint);
8int debugfs_umount(void);
9void debugfs_set_path(const char *mountpoint);
10int debugfs_write(const char *entry, const char *value);
11int debugfs_read(const char *entry, char *buffer, size_t size);
12void debugfs_force_cleanup(void);
13int debugfs_make_path(const char *element, char *buffer, int size);
5 14
6#ifndef MAX_PATH 15extern char debugfs_mountpoint[];
7# define MAX_PATH 256 16extern char tracing_events_path[];
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 char *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 17
25#endif /* __DEBUGFS_H__ */ 18#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 437f8ca679a0..73ddaf06b8e7 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,7 +1,6 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h" 4#include "sort.h"
6#include "string.h" 5#include "string.h"
7#include "strlist.h" 6#include "strlist.h"
@@ -44,36 +43,27 @@ static struct perf_sample synth_sample = {
44 .period = 1, 43 .period = 1,
45}; 44};
46 45
47static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, 46static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
48 int full, perf_event__handler_t process,
49 struct perf_session *session)
50{ 47{
51 char filename[PATH_MAX]; 48 char filename[PATH_MAX];
52 char bf[BUFSIZ]; 49 char bf[BUFSIZ];
53 FILE *fp; 50 FILE *fp;
54 size_t size = 0; 51 size_t size = 0;
55 DIR *tasks; 52 pid_t tgid = -1;
56 struct dirent dirent, *next;
57 pid_t tgid = 0;
58 53
59 snprintf(filename, sizeof(filename), "/proc/%d/status", pid); 54 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
60 55
61 fp = fopen(filename, "r"); 56 fp = fopen(filename, "r");
62 if (fp == NULL) { 57 if (fp == NULL) {
63out_race:
64 /*
65 * We raced with a task exiting - just return:
66 */
67 pr_debug("couldn't open %s\n", filename); 58 pr_debug("couldn't open %s\n", filename);
68 return 0; 59 return 0;
69 } 60 }
70 61
71 memset(&event->comm, 0, sizeof(event->comm)); 62 while (!comm[0] || (tgid < 0)) {
72
73 while (!event->comm.comm[0] || !event->comm.pid) {
74 if (fgets(bf, sizeof(bf), fp) == NULL) { 63 if (fgets(bf, sizeof(bf), fp) == NULL) {
75 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); 64 pr_warning("couldn't get COMM and pgid, malformed %s\n",
76 goto out; 65 filename);
66 break;
77 } 67 }
78 68
79 if (memcmp(bf, "Name:", 5) == 0) { 69 if (memcmp(bf, "Name:", 5) == 0) {
@@ -81,33 +71,65 @@ out_race:
81 while (*name && isspace(*name)) 71 while (*name && isspace(*name))
82 ++name; 72 ++name;
83 size = strlen(name) - 1; 73 size = strlen(name) - 1;
84 memcpy(event->comm.comm, name, size++); 74 if (size >= len)
75 size = len - 1;
76 memcpy(comm, name, size);
77
85 } else if (memcmp(bf, "Tgid:", 5) == 0) { 78 } else if (memcmp(bf, "Tgid:", 5) == 0) {
86 char *tgids = bf + 5; 79 char *tgids = bf + 5;
87 while (*tgids && isspace(*tgids)) 80 while (*tgids && isspace(*tgids))
88 ++tgids; 81 ++tgids;
89 tgid = event->comm.pid = atoi(tgids); 82 tgid = atoi(tgids);
90 } 83 }
91 } 84 }
92 85
86 fclose(fp);
87
88 return tgid;
89}
90
91static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
92 union perf_event *event, pid_t pid,
93 int full,
94 perf_event__handler_t process,
95 struct machine *machine)
96{
97 char filename[PATH_MAX];
98 size_t size;
99 DIR *tasks;
100 struct dirent dirent, *next;
101 pid_t tgid;
102
103 memset(&event->comm, 0, sizeof(event->comm));
104
105 tgid = perf_event__get_comm_tgid(pid, event->comm.comm,
106 sizeof(event->comm.comm));
107 if (tgid < 0)
108 goto out;
109
110 event->comm.pid = tgid;
93 event->comm.header.type = PERF_RECORD_COMM; 111 event->comm.header.type = PERF_RECORD_COMM;
112
113 size = strlen(event->comm.comm) + 1;
94 size = ALIGN(size, sizeof(u64)); 114 size = ALIGN(size, sizeof(u64));
95 memset(event->comm.comm + size, 0, session->id_hdr_size); 115 memset(event->comm.comm + size, 0, machine->id_hdr_size);
96 event->comm.header.size = (sizeof(event->comm) - 116 event->comm.header.size = (sizeof(event->comm) -
97 (sizeof(event->comm.comm) - size) + 117 (sizeof(event->comm.comm) - size) +
98 session->id_hdr_size); 118 machine->id_hdr_size);
99 if (!full) { 119 if (!full) {
100 event->comm.tid = pid; 120 event->comm.tid = pid;
101 121
102 process(event, &synth_sample, session); 122 process(tool, event, &synth_sample, machine);
103 goto out; 123 goto out;
104 } 124 }
105 125
106 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 126 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
107 127
108 tasks = opendir(filename); 128 tasks = opendir(filename);
109 if (tasks == NULL) 129 if (tasks == NULL) {
110 goto out_race; 130 pr_debug("couldn't open %s\n", filename);
131 return 0;
132 }
111 133
112 while (!readdir_r(tasks, &dirent, &next) && next) { 134 while (!readdir_r(tasks, &dirent, &next) && next) {
113 char *end; 135 char *end;
@@ -115,22 +137,32 @@ out_race:
115 if (*end) 137 if (*end)
116 continue; 138 continue;
117 139
140 /* already have tgid; jut want to update the comm */
141 (void) perf_event__get_comm_tgid(pid, event->comm.comm,
142 sizeof(event->comm.comm));
143
144 size = strlen(event->comm.comm) + 1;
145 size = ALIGN(size, sizeof(u64));
146 memset(event->comm.comm + size, 0, machine->id_hdr_size);
147 event->comm.header.size = (sizeof(event->comm) -
148 (sizeof(event->comm.comm) - size) +
149 machine->id_hdr_size);
150
118 event->comm.tid = pid; 151 event->comm.tid = pid;
119 152
120 process(event, &synth_sample, session); 153 process(tool, event, &synth_sample, machine);
121 } 154 }
122 155
123 closedir(tasks); 156 closedir(tasks);
124out: 157out:
125 fclose(fp);
126
127 return tgid; 158 return tgid;
128} 159}
129 160
130static int perf_event__synthesize_mmap_events(union perf_event *event, 161static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
162 union perf_event *event,
131 pid_t pid, pid_t tgid, 163 pid_t pid, pid_t tgid,
132 perf_event__handler_t process, 164 perf_event__handler_t process,
133 struct perf_session *session) 165 struct machine *machine)
134{ 166{
135 char filename[PATH_MAX]; 167 char filename[PATH_MAX];
136 FILE *fp; 168 FILE *fp;
@@ -193,12 +225,12 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
193 event->mmap.len -= event->mmap.start; 225 event->mmap.len -= event->mmap.start;
194 event->mmap.header.size = (sizeof(event->mmap) - 226 event->mmap.header.size = (sizeof(event->mmap) -
195 (sizeof(event->mmap.filename) - size)); 227 (sizeof(event->mmap.filename) - size));
196 memset(event->mmap.filename + size, 0, session->id_hdr_size); 228 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
197 event->mmap.header.size += session->id_hdr_size; 229 event->mmap.header.size += machine->id_hdr_size;
198 event->mmap.pid = tgid; 230 event->mmap.pid = tgid;
199 event->mmap.tid = pid; 231 event->mmap.tid = pid;
200 232
201 process(event, &synth_sample, session); 233 process(tool, event, &synth_sample, machine);
202 } 234 }
203 } 235 }
204 236
@@ -206,14 +238,14 @@ static int perf_event__synthesize_mmap_events(union perf_event *event,
206 return 0; 238 return 0;
207} 239}
208 240
209int perf_event__synthesize_modules(perf_event__handler_t process, 241int perf_event__synthesize_modules(struct perf_tool *tool,
210 struct perf_session *session, 242 perf_event__handler_t process,
211 struct machine *machine) 243 struct machine *machine)
212{ 244{
213 struct rb_node *nd; 245 struct rb_node *nd;
214 struct map_groups *kmaps = &machine->kmaps; 246 struct map_groups *kmaps = &machine->kmaps;
215 union perf_event *event = zalloc((sizeof(event->mmap) + 247 union perf_event *event = zalloc((sizeof(event->mmap) +
216 session->id_hdr_size)); 248 machine->id_hdr_size));
217 if (event == NULL) { 249 if (event == NULL) {
218 pr_debug("Not enough memory synthesizing mmap event " 250 pr_debug("Not enough memory synthesizing mmap event "
219 "for kernel modules\n"); 251 "for kernel modules\n");
@@ -243,15 +275,15 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
243 event->mmap.header.type = PERF_RECORD_MMAP; 275 event->mmap.header.type = PERF_RECORD_MMAP;
244 event->mmap.header.size = (sizeof(event->mmap) - 276 event->mmap.header.size = (sizeof(event->mmap) -
245 (sizeof(event->mmap.filename) - size)); 277 (sizeof(event->mmap.filename) - size));
246 memset(event->mmap.filename + size, 0, session->id_hdr_size); 278 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
247 event->mmap.header.size += session->id_hdr_size; 279 event->mmap.header.size += machine->id_hdr_size;
248 event->mmap.start = pos->start; 280 event->mmap.start = pos->start;
249 event->mmap.len = pos->end - pos->start; 281 event->mmap.len = pos->end - pos->start;
250 event->mmap.pid = machine->pid; 282 event->mmap.pid = machine->pid;
251 283
252 memcpy(event->mmap.filename, pos->dso->long_name, 284 memcpy(event->mmap.filename, pos->dso->long_name,
253 pos->dso->long_name_len + 1); 285 pos->dso->long_name_len + 1);
254 process(event, &synth_sample, session); 286 process(tool, event, &synth_sample, machine);
255 } 287 }
256 288
257 free(event); 289 free(event);
@@ -260,40 +292,69 @@ int perf_event__synthesize_modules(perf_event__handler_t process,
260 292
261static int __event__synthesize_thread(union perf_event *comm_event, 293static int __event__synthesize_thread(union perf_event *comm_event,
262 union perf_event *mmap_event, 294 union perf_event *mmap_event,
263 pid_t pid, perf_event__handler_t process, 295 pid_t pid, int full,
264 struct perf_session *session) 296 perf_event__handler_t process,
297 struct perf_tool *tool,
298 struct machine *machine)
265{ 299{
266 pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, 300 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
267 session); 301 process, machine);
268 if (tgid == -1) 302 if (tgid == -1)
269 return -1; 303 return -1;
270 return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, 304 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
271 process, session); 305 process, machine);
272} 306}
273 307
274int perf_event__synthesize_thread_map(struct thread_map *threads, 308int perf_event__synthesize_thread_map(struct perf_tool *tool,
309 struct thread_map *threads,
275 perf_event__handler_t process, 310 perf_event__handler_t process,
276 struct perf_session *session) 311 struct machine *machine)
277{ 312{
278 union perf_event *comm_event, *mmap_event; 313 union perf_event *comm_event, *mmap_event;
279 int err = -1, thread; 314 int err = -1, thread, j;
280 315
281 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 316 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
282 if (comm_event == NULL) 317 if (comm_event == NULL)
283 goto out; 318 goto out;
284 319
285 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); 320 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
286 if (mmap_event == NULL) 321 if (mmap_event == NULL)
287 goto out_free_comm; 322 goto out_free_comm;
288 323
289 err = 0; 324 err = 0;
290 for (thread = 0; thread < threads->nr; ++thread) { 325 for (thread = 0; thread < threads->nr; ++thread) {
291 if (__event__synthesize_thread(comm_event, mmap_event, 326 if (__event__synthesize_thread(comm_event, mmap_event,
292 threads->map[thread], 327 threads->map[thread], 0,
293 process, session)) { 328 process, tool, machine)) {
294 err = -1; 329 err = -1;
295 break; 330 break;
296 } 331 }
332
333 /*
334 * comm.pid is set to thread group id by
335 * perf_event__synthesize_comm
336 */
337 if ((int) comm_event->comm.pid != threads->map[thread]) {
338 bool need_leader = true;
339
340 /* is thread group leader in thread_map? */
341 for (j = 0; j < threads->nr; ++j) {
342 if ((int) comm_event->comm.pid == threads->map[j]) {
343 need_leader = false;
344 break;
345 }
346 }
347
348 /* if not, generate events for it */
349 if (need_leader &&
350 __event__synthesize_thread(comm_event,
351 mmap_event,
352 comm_event->comm.pid, 0,
353 process, tool, machine)) {
354 err = -1;
355 break;
356 }
357 }
297 } 358 }
298 free(mmap_event); 359 free(mmap_event);
299out_free_comm: 360out_free_comm:
@@ -302,19 +363,20 @@ out:
302 return err; 363 return err;
303} 364}
304 365
305int perf_event__synthesize_threads(perf_event__handler_t process, 366int perf_event__synthesize_threads(struct perf_tool *tool,
306 struct perf_session *session) 367 perf_event__handler_t process,
368 struct machine *machine)
307{ 369{
308 DIR *proc; 370 DIR *proc;
309 struct dirent dirent, *next; 371 struct dirent dirent, *next;
310 union perf_event *comm_event, *mmap_event; 372 union perf_event *comm_event, *mmap_event;
311 int err = -1; 373 int err = -1;
312 374
313 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); 375 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
314 if (comm_event == NULL) 376 if (comm_event == NULL)
315 goto out; 377 goto out;
316 378
317 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); 379 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
318 if (mmap_event == NULL) 380 if (mmap_event == NULL)
319 goto out_free_comm; 381 goto out_free_comm;
320 382
@@ -329,8 +391,8 @@ int perf_event__synthesize_threads(perf_event__handler_t process,
329 if (*end) /* only interested in proper numerical dirents */ 391 if (*end) /* only interested in proper numerical dirents */
330 continue; 392 continue;
331 393
332 __event__synthesize_thread(comm_event, mmap_event, pid, 394 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
333 process, session); 395 process, tool, machine);
334 } 396 }
335 397
336 closedir(proc); 398 closedir(proc);
@@ -365,8 +427,8 @@ static int find_symbol_cb(void *arg, const char *name, char type,
365 return 1; 427 return 1;
366} 428}
367 429
368int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 430int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
369 struct perf_session *session, 431 perf_event__handler_t process,
370 struct machine *machine, 432 struct machine *machine,
371 const char *symbol_name) 433 const char *symbol_name)
372{ 434{
@@ -383,7 +445,7 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
383 */ 445 */
384 struct process_symbol_args args = { .name = symbol_name, }; 446 struct process_symbol_args args = { .name = symbol_name, };
385 union perf_event *event = zalloc((sizeof(event->mmap) + 447 union perf_event *event = zalloc((sizeof(event->mmap) +
386 session->id_hdr_size)); 448 machine->id_hdr_size));
387 if (event == NULL) { 449 if (event == NULL) {
388 pr_debug("Not enough memory synthesizing mmap event " 450 pr_debug("Not enough memory synthesizing mmap event "
389 "for kernel modules\n"); 451 "for kernel modules\n");
@@ -417,25 +479,32 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process,
417 size = ALIGN(size, sizeof(u64)); 479 size = ALIGN(size, sizeof(u64));
418 event->mmap.header.type = PERF_RECORD_MMAP; 480 event->mmap.header.type = PERF_RECORD_MMAP;
419 event->mmap.header.size = (sizeof(event->mmap) - 481 event->mmap.header.size = (sizeof(event->mmap) -
420 (sizeof(event->mmap.filename) - size) + session->id_hdr_size); 482 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
421 event->mmap.pgoff = args.start; 483 event->mmap.pgoff = args.start;
422 event->mmap.start = map->start; 484 event->mmap.start = map->start;
423 event->mmap.len = map->end - event->mmap.start; 485 event->mmap.len = map->end - event->mmap.start;
424 event->mmap.pid = machine->pid; 486 event->mmap.pid = machine->pid;
425 487
426 err = process(event, &synth_sample, session); 488 err = process(tool, event, &synth_sample, machine);
427 free(event); 489 free(event);
428 490
429 return err; 491 return err;
430} 492}
431 493
432int perf_event__process_comm(union perf_event *event, 494size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
495{
496 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
497}
498
499int perf_event__process_comm(struct perf_tool *tool __used,
500 union perf_event *event,
433 struct perf_sample *sample __used, 501 struct perf_sample *sample __used,
434 struct perf_session *session) 502 struct machine *machine)
435{ 503{
436 struct thread *thread = perf_session__findnew(session, event->comm.tid); 504 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
437 505
438 dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); 506 if (dump_trace)
507 perf_event__fprintf_comm(event, stdout);
439 508
440 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { 509 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
441 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 510 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
@@ -445,13 +514,13 @@ int perf_event__process_comm(union perf_event *event,
445 return 0; 514 return 0;
446} 515}
447 516
448int perf_event__process_lost(union perf_event *event, 517int perf_event__process_lost(struct perf_tool *tool __used,
518 union perf_event *event,
449 struct perf_sample *sample __used, 519 struct perf_sample *sample __used,
450 struct perf_session *session) 520 struct machine *machine __used)
451{ 521{
452 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 522 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
453 event->lost.id, event->lost.lost); 523 event->lost.id, event->lost.lost);
454 session->hists.stats.total_lost += event->lost.lost;
455 return 0; 524 return 0;
456} 525}
457 526
@@ -468,21 +537,15 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event,
468 maps[MAP__FUNCTION]->end = ~0ULL; 537 maps[MAP__FUNCTION]->end = ~0ULL;
469} 538}
470 539
471static int perf_event__process_kernel_mmap(union perf_event *event, 540static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
472 struct perf_session *session) 541 union perf_event *event,
542 struct machine *machine)
473{ 543{
474 struct map *map; 544 struct map *map;
475 char kmmap_prefix[PATH_MAX]; 545 char kmmap_prefix[PATH_MAX];
476 struct machine *machine;
477 enum dso_kernel_type kernel_type; 546 enum dso_kernel_type kernel_type;
478 bool is_kernel_mmap; 547 bool is_kernel_mmap;
479 548
480 machine = perf_session__findnew_machine(session, event->mmap.pid);
481 if (!machine) {
482 pr_err("Can't find id %d's machine\n", event->mmap.pid);
483 goto out_problem;
484 }
485
486 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); 549 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
487 if (machine__is_host(machine)) 550 if (machine__is_host(machine))
488 kernel_type = DSO_TYPE_KERNEL; 551 kernel_type = DSO_TYPE_KERNEL;
@@ -549,9 +612,9 @@ static int perf_event__process_kernel_mmap(union perf_event *event,
549 * time /proc/sys/kernel/kptr_restrict was non zero. 612 * time /proc/sys/kernel/kptr_restrict was non zero.
550 */ 613 */
551 if (event->mmap.pgoff != 0) { 614 if (event->mmap.pgoff != 0) {
552 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, 615 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
553 symbol_name, 616 symbol_name,
554 event->mmap.pgoff); 617 event->mmap.pgoff);
555 } 618 }
556 619
557 if (machine__is_default_guest(machine)) { 620 if (machine__is_default_guest(machine)) {
@@ -567,32 +630,35 @@ out_problem:
567 return -1; 630 return -1;
568} 631}
569 632
570int perf_event__process_mmap(union perf_event *event, 633size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
634{
635 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
636 event->mmap.pid, event->mmap.tid, event->mmap.start,
637 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
638}
639
640int perf_event__process_mmap(struct perf_tool *tool,
641 union perf_event *event,
571 struct perf_sample *sample __used, 642 struct perf_sample *sample __used,
572 struct perf_session *session) 643 struct machine *machine)
573{ 644{
574 struct machine *machine;
575 struct thread *thread; 645 struct thread *thread;
576 struct map *map; 646 struct map *map;
577 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 647 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
578 int ret = 0; 648 int ret = 0;
579 649
580 dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 650 if (dump_trace)
581 event->mmap.pid, event->mmap.tid, event->mmap.start, 651 perf_event__fprintf_mmap(event, stdout);
582 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
583 652
584 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 653 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
585 cpumode == PERF_RECORD_MISC_KERNEL) { 654 cpumode == PERF_RECORD_MISC_KERNEL) {
586 ret = perf_event__process_kernel_mmap(event, session); 655 ret = perf_event__process_kernel_mmap(tool, event, machine);
587 if (ret < 0) 656 if (ret < 0)
588 goto out_problem; 657 goto out_problem;
589 return 0; 658 return 0;
590 } 659 }
591 660
592 machine = perf_session__find_host_machine(session); 661 thread = machine__findnew_thread(machine, event->mmap.pid);
593 if (machine == NULL)
594 goto out_problem;
595 thread = perf_session__findnew(session, event->mmap.pid);
596 if (thread == NULL) 662 if (thread == NULL)
597 goto out_problem; 663 goto out_problem;
598 map = map__new(&machine->user_dsos, event->mmap.start, 664 map = map__new(&machine->user_dsos, event->mmap.start,
@@ -610,18 +676,26 @@ out_problem:
610 return 0; 676 return 0;
611} 677}
612 678
613int perf_event__process_task(union perf_event *event, 679size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
680{
681 return fprintf(fp, "(%d:%d):(%d:%d)\n",
682 event->fork.pid, event->fork.tid,
683 event->fork.ppid, event->fork.ptid);
684}
685
686int perf_event__process_task(struct perf_tool *tool __used,
687 union perf_event *event,
614 struct perf_sample *sample __used, 688 struct perf_sample *sample __used,
615 struct perf_session *session) 689 struct machine *machine)
616{ 690{
617 struct thread *thread = perf_session__findnew(session, event->fork.tid); 691 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
618 struct thread *parent = perf_session__findnew(session, event->fork.ptid); 692 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
619 693
620 dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, 694 if (dump_trace)
621 event->fork.ppid, event->fork.ptid); 695 perf_event__fprintf_task(event, stdout);
622 696
623 if (event->header.type == PERF_RECORD_EXIT) { 697 if (event->header.type == PERF_RECORD_EXIT) {
624 perf_session__remove_thread(session, thread); 698 machine__remove_thread(machine, thread);
625 return 0; 699 return 0;
626 } 700 }
627 701
@@ -634,22 +708,45 @@ int perf_event__process_task(union perf_event *event,
634 return 0; 708 return 0;
635} 709}
636 710
637int perf_event__process(union perf_event *event, struct perf_sample *sample, 711size_t perf_event__fprintf(union perf_event *event, FILE *fp)
638 struct perf_session *session) 712{
713 size_t ret = fprintf(fp, "PERF_RECORD_%s",
714 perf_event__name(event->header.type));
715
716 switch (event->header.type) {
717 case PERF_RECORD_COMM:
718 ret += perf_event__fprintf_comm(event, fp);
719 break;
720 case PERF_RECORD_FORK:
721 case PERF_RECORD_EXIT:
722 ret += perf_event__fprintf_task(event, fp);
723 break;
724 case PERF_RECORD_MMAP:
725 ret += perf_event__fprintf_mmap(event, fp);
726 break;
727 default:
728 ret += fprintf(fp, "\n");
729 }
730
731 return ret;
732}
733
734int perf_event__process(struct perf_tool *tool, union perf_event *event,
735 struct perf_sample *sample, struct machine *machine)
639{ 736{
640 switch (event->header.type) { 737 switch (event->header.type) {
641 case PERF_RECORD_COMM: 738 case PERF_RECORD_COMM:
642 perf_event__process_comm(event, sample, session); 739 perf_event__process_comm(tool, event, sample, machine);
643 break; 740 break;
644 case PERF_RECORD_MMAP: 741 case PERF_RECORD_MMAP:
645 perf_event__process_mmap(event, sample, session); 742 perf_event__process_mmap(tool, event, sample, machine);
646 break; 743 break;
647 case PERF_RECORD_FORK: 744 case PERF_RECORD_FORK:
648 case PERF_RECORD_EXIT: 745 case PERF_RECORD_EXIT:
649 perf_event__process_task(event, sample, session); 746 perf_event__process_task(tool, event, sample, machine);
650 break; 747 break;
651 case PERF_RECORD_LOST: 748 case PERF_RECORD_LOST:
652 perf_event__process_lost(event, sample, session); 749 perf_event__process_lost(tool, event, sample, machine);
653 default: 750 default:
654 break; 751 break;
655 } 752 }
@@ -658,36 +755,29 @@ int perf_event__process(union perf_event *event, struct perf_sample *sample,
658} 755}
659 756
660void thread__find_addr_map(struct thread *self, 757void thread__find_addr_map(struct thread *self,
661 struct perf_session *session, u8 cpumode, 758 struct machine *machine, u8 cpumode,
662 enum map_type type, pid_t pid, u64 addr, 759 enum map_type type, u64 addr,
663 struct addr_location *al) 760 struct addr_location *al)
664{ 761{
665 struct map_groups *mg = &self->mg; 762 struct map_groups *mg = &self->mg;
666 struct machine *machine = NULL;
667 763
668 al->thread = self; 764 al->thread = self;
669 al->addr = addr; 765 al->addr = addr;
670 al->cpumode = cpumode; 766 al->cpumode = cpumode;
671 al->filtered = false; 767 al->filtered = false;
672 768
769 if (machine == NULL) {
770 al->map = NULL;
771 return;
772 }
773
673 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 774 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
674 al->level = 'k'; 775 al->level = 'k';
675 machine = perf_session__find_host_machine(session);
676 if (machine == NULL) {
677 al->map = NULL;
678 return;
679 }
680 mg = &machine->kmaps; 776 mg = &machine->kmaps;
681 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 777 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
682 al->level = '.'; 778 al->level = '.';
683 machine = perf_session__find_host_machine(session);
684 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 779 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
685 al->level = 'g'; 780 al->level = 'g';
686 machine = perf_session__find_machine(session, pid);
687 if (machine == NULL) {
688 al->map = NULL;
689 return;
690 }
691 mg = &machine->kmaps; 781 mg = &machine->kmaps;
692 } else { 782 } else {
693 /* 783 /*
@@ -733,13 +823,12 @@ try_again:
733 al->addr = al->map->map_ip(al->map, al->addr); 823 al->addr = al->map->map_ip(al->map, al->addr);
734} 824}
735 825
736void thread__find_addr_location(struct thread *self, 826void thread__find_addr_location(struct thread *thread, struct machine *machine,
737 struct perf_session *session, u8 cpumode, 827 u8 cpumode, enum map_type type, u64 addr,
738 enum map_type type, pid_t pid, u64 addr,
739 struct addr_location *al, 828 struct addr_location *al,
740 symbol_filter_t filter) 829 symbol_filter_t filter)
741{ 830{
742 thread__find_addr_map(self, session, cpumode, type, pid, addr, al); 831 thread__find_addr_map(thread, machine, cpumode, type, addr, al);
743 if (al->map != NULL) 832 if (al->map != NULL)
744 al->sym = map__find_symbol(al->map, al->addr, filter); 833 al->sym = map__find_symbol(al->map, al->addr, filter);
745 else 834 else
@@ -747,13 +836,13 @@ void thread__find_addr_location(struct thread *self,
747} 836}
748 837
749int perf_event__preprocess_sample(const union perf_event *event, 838int perf_event__preprocess_sample(const union perf_event *event,
750 struct perf_session *session, 839 struct machine *machine,
751 struct addr_location *al, 840 struct addr_location *al,
752 struct perf_sample *sample, 841 struct perf_sample *sample,
753 symbol_filter_t filter) 842 symbol_filter_t filter)
754{ 843{
755 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 844 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
756 struct thread *thread = perf_session__findnew(session, event->ip.pid); 845 struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
757 846
758 if (thread == NULL) 847 if (thread == NULL)
759 return -1; 848 return -1;
@@ -764,18 +853,18 @@ int perf_event__preprocess_sample(const union perf_event *event,
764 853
765 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 854 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
766 /* 855 /*
767 * Have we already created the kernel maps for the host machine? 856 * Have we already created the kernel maps for this machine?
768 * 857 *
769 * This should have happened earlier, when we processed the kernel MMAP 858 * This should have happened earlier, when we processed the kernel MMAP
770 * events, but for older perf.data files there was no such thing, so do 859 * events, but for older perf.data files there was no such thing, so do
771 * it now. 860 * it now.
772 */ 861 */
773 if (cpumode == PERF_RECORD_MISC_KERNEL && 862 if (cpumode == PERF_RECORD_MISC_KERNEL &&
774 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL) 863 machine->vmlinux_maps[MAP__FUNCTION] == NULL)
775 machine__create_kernel_maps(&session->host_machine); 864 machine__create_kernel_maps(machine);
776 865
777 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 866 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
778 event->ip.pid, event->ip.ip, al); 867 event->ip.ip, al);
779 dump_printf(" ...... dso: %s\n", 868 dump_printf(" ...... dso: %s\n",
780 al->map ? al->map->dso->long_name : 869 al->map ? al->map->dso->long_name :
781 al->level == 'H' ? "[hypervisor]" : "<not found>"); 870 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -783,13 +872,14 @@ int perf_event__preprocess_sample(const union perf_event *event,
783 al->cpu = sample->cpu; 872 al->cpu = sample->cpu;
784 873
785 if (al->map) { 874 if (al->map) {
875 struct dso *dso = al->map->dso;
876
786 if (symbol_conf.dso_list && 877 if (symbol_conf.dso_list &&
787 (!al->map || !al->map->dso || 878 (!dso || !(strlist__has_entry(symbol_conf.dso_list,
788 !(strlist__has_entry(symbol_conf.dso_list, 879 dso->short_name) ||
789 al->map->dso->short_name) || 880 (dso->short_name != dso->long_name &&
790 (al->map->dso->short_name != al->map->dso->long_name && 881 strlist__has_entry(symbol_conf.dso_list,
791 strlist__has_entry(symbol_conf.dso_list, 882 dso->long_name)))))
792 al->map->dso->long_name)))))
793 goto out_filtered; 883 goto out_filtered;
794 884
795 al->sym = map__find_symbol(al->map, al->addr, filter); 885 al->sym = map__find_symbol(al->map, al->addr, filter);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 357a85b85248..cbdeaad9c5e5 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -2,6 +2,7 @@
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h> 4#include <limits.h>
5#include <stdio.h>
5 6
6#include "../perf.h" 7#include "../perf.h"
7#include "map.h" 8#include "map.h"
@@ -141,43 +142,54 @@ union perf_event {
141 142
142void perf_event__print_totals(void); 143void perf_event__print_totals(void);
143 144
144struct perf_session; 145struct perf_tool;
145struct thread_map; 146struct thread_map;
146 147
147typedef int (*perf_event__handler_synth_t)(union perf_event *event, 148typedef int (*perf_event__handler_t)(struct perf_tool *tool,
148 struct perf_session *session); 149 union perf_event *event,
149typedef int (*perf_event__handler_t)(union perf_event *event,
150 struct perf_sample *sample, 150 struct perf_sample *sample,
151 struct perf_session *session); 151 struct machine *machine);
152 152
153int perf_event__synthesize_thread_map(struct thread_map *threads, 153int perf_event__synthesize_thread_map(struct perf_tool *tool,
154 struct thread_map *threads,
154 perf_event__handler_t process, 155 perf_event__handler_t process,
155 struct perf_session *session); 156 struct machine *machine);
156int perf_event__synthesize_threads(perf_event__handler_t process, 157int perf_event__synthesize_threads(struct perf_tool *tool,
157 struct perf_session *session); 158 perf_event__handler_t process,
158int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, 159 struct machine *machine);
159 struct perf_session *session, 160int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
161 perf_event__handler_t process,
160 struct machine *machine, 162 struct machine *machine,
161 const char *symbol_name); 163 const char *symbol_name);
162 164
163int perf_event__synthesize_modules(perf_event__handler_t process, 165int perf_event__synthesize_modules(struct perf_tool *tool,
164 struct perf_session *session, 166 perf_event__handler_t process,
165 struct machine *machine); 167 struct machine *machine);
166 168
167int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, 169int perf_event__process_comm(struct perf_tool *tool,
168 struct perf_session *session); 170 union perf_event *event,
169int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, 171 struct perf_sample *sample,
170 struct perf_session *session); 172 struct machine *machine);
171int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, 173int perf_event__process_lost(struct perf_tool *tool,
172 struct perf_session *session); 174 union perf_event *event,
173int perf_event__process_task(union perf_event *event, struct perf_sample *sample, 175 struct perf_sample *sample,
174 struct perf_session *session); 176 struct machine *machine);
175int perf_event__process(union perf_event *event, struct perf_sample *sample, 177int perf_event__process_mmap(struct perf_tool *tool,
176 struct perf_session *session); 178 union perf_event *event,
179 struct perf_sample *sample,
180 struct machine *machine);
181int perf_event__process_task(struct perf_tool *tool,
182 union perf_event *event,
183 struct perf_sample *sample,
184 struct machine *machine);
185int perf_event__process(struct perf_tool *tool,
186 union perf_event *event,
187 struct perf_sample *sample,
188 struct machine *machine);
177 189
178struct addr_location; 190struct addr_location;
179int perf_event__preprocess_sample(const union perf_event *self, 191int perf_event__preprocess_sample(const union perf_event *self,
180 struct perf_session *session, 192 struct machine *machine,
181 struct addr_location *al, 193 struct addr_location *al,
182 struct perf_sample *sample, 194 struct perf_sample *sample,
183 symbol_filter_t filter); 195 symbol_filter_t filter);
@@ -187,5 +199,13 @@ const char *perf_event__name(unsigned int id);
187int perf_event__parse_sample(const union perf_event *event, u64 type, 199int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all, 200 int sample_size, bool sample_id_all,
189 struct perf_sample *sample, bool swapped); 201 struct perf_sample *sample, bool swapped);
202int perf_event__synthesize_sample(union perf_event *event, u64 type,
203 const struct perf_sample *sample,
204 bool swapped);
205
206size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
207size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
208size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
209size_t perf_event__fprintf(union perf_event *event, FILE *fp);
190 210
191#endif /* __PERF_RECORD_H */ 211#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index fbb4b4ab9cc6..fa1837088ca8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -6,12 +6,16 @@
6 * 6 *
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9#include "util.h"
10#include "debugfs.h"
9#include <poll.h> 11#include <poll.h>
10#include "cpumap.h" 12#include "cpumap.h"
11#include "thread_map.h" 13#include "thread_map.h"
12#include "evlist.h" 14#include "evlist.h"
13#include "evsel.h" 15#include "evsel.h"
14#include "util.h" 16#include <unistd.h>
17
18#include "parse-events.h"
15 19
16#include <sys/mman.h> 20#include <sys/mman.h>
17 21
@@ -30,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
30 INIT_HLIST_HEAD(&evlist->heads[i]); 34 INIT_HLIST_HEAD(&evlist->heads[i]);
31 INIT_LIST_HEAD(&evlist->entries); 35 INIT_LIST_HEAD(&evlist->entries);
32 perf_evlist__set_maps(evlist, cpus, threads); 36 perf_evlist__set_maps(evlist, cpus, threads);
37 evlist->workload.pid = -1;
33} 38}
34 39
35struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 40struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -43,6 +48,22 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
43 return evlist; 48 return evlist;
44} 49}
45 50
51void perf_evlist__config_attrs(struct perf_evlist *evlist,
52 struct perf_record_opts *opts)
53{
54 struct perf_evsel *evsel;
55
56 if (evlist->cpus->map[0] < 0)
57 opts->no_inherit = true;
58
59 list_for_each_entry(evsel, &evlist->entries, node) {
60 perf_evsel__config(evsel, opts);
61
62 if (evlist->nr_entries > 1)
63 evsel->attr.sample_type |= PERF_SAMPLE_ID;
64 }
65}
66
46static void perf_evlist__purge(struct perf_evlist *evlist) 67static void perf_evlist__purge(struct perf_evlist *evlist)
47{ 68{
48 struct perf_evsel *pos, *n; 69 struct perf_evsel *pos, *n;
@@ -76,6 +97,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
76 ++evlist->nr_entries; 97 ++evlist->nr_entries;
77} 98}
78 99
100static void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
101 struct list_head *list,
102 int nr_entries)
103{
104 list_splice_tail(list, &evlist->entries);
105 evlist->nr_entries += nr_entries;
106}
107
79int perf_evlist__add_default(struct perf_evlist *evlist) 108int perf_evlist__add_default(struct perf_evlist *evlist)
80{ 109{
81 struct perf_event_attr attr = { 110 struct perf_event_attr attr = {
@@ -100,6 +129,126 @@ error:
100 return -ENOMEM; 129 return -ENOMEM;
101} 130}
102 131
132int perf_evlist__add_attrs(struct perf_evlist *evlist,
133 struct perf_event_attr *attrs, size_t nr_attrs)
134{
135 struct perf_evsel *evsel, *n;
136 LIST_HEAD(head);
137 size_t i;
138
139 for (i = 0; i < nr_attrs; i++) {
140 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i);
141 if (evsel == NULL)
142 goto out_delete_partial_list;
143 list_add_tail(&evsel->node, &head);
144 }
145
146 perf_evlist__splice_list_tail(evlist, &head, nr_attrs);
147
148 return 0;
149
150out_delete_partial_list:
151 list_for_each_entry_safe(evsel, n, &head, node)
152 perf_evsel__delete(evsel);
153 return -1;
154}
155
156static int trace_event__id(const char *evname)
157{
158 char *filename, *colon;
159 int err = -1, fd;
160
161 if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0)
162 return -1;
163
164 colon = strrchr(filename, ':');
165 if (colon != NULL)
166 *colon = '/';
167
168 fd = open(filename, O_RDONLY);
169 if (fd >= 0) {
170 char id[16];
171 if (read(fd, id, sizeof(id)) > 0)
172 err = atoi(id);
173 close(fd);
174 }
175
176 free(filename);
177 return err;
178}
179
180int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
181 const char *tracepoints[],
182 size_t nr_tracepoints)
183{
184 int err;
185 size_t i;
186 struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs));
187
188 if (attrs == NULL)
189 return -1;
190
191 for (i = 0; i < nr_tracepoints; i++) {
192 err = trace_event__id(tracepoints[i]);
193
194 if (err < 0)
195 goto out_free_attrs;
196
197 attrs[i].type = PERF_TYPE_TRACEPOINT;
198 attrs[i].config = err;
199 attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
200 PERF_SAMPLE_CPU);
201 attrs[i].sample_period = 1;
202 }
203
204 err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints);
205out_free_attrs:
206 free(attrs);
207 return err;
208}
209
210static struct perf_evsel *
211 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
212{
213 struct perf_evsel *evsel;
214
215 list_for_each_entry(evsel, &evlist->entries, node) {
216 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
217 (int)evsel->attr.config == id)
218 return evsel;
219 }
220
221 return NULL;
222}
223
224int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
225 const struct perf_evsel_str_handler *assocs,
226 size_t nr_assocs)
227{
228 struct perf_evsel *evsel;
229 int err;
230 size_t i;
231
232 for (i = 0; i < nr_assocs; i++) {
233 err = trace_event__id(assocs[i].name);
234 if (err < 0)
235 goto out;
236
237 evsel = perf_evlist__find_tracepoint_by_id(evlist, err);
238 if (evsel == NULL)
239 continue;
240
241 err = -EEXIST;
242 if (evsel->handler.func != NULL)
243 goto out;
244 evsel->handler.func = assocs[i].handler;
245 }
246
247 err = 0;
248out:
249 return err;
250}
251
103void perf_evlist__disable(struct perf_evlist *evlist) 252void perf_evlist__disable(struct perf_evlist *evlist)
104{ 253{
105 int cpu, thread; 254 int cpu, thread;
@@ -126,7 +275,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
126 } 275 }
127} 276}
128 277
129int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 278static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
130{ 279{
131 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; 280 int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
132 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 281 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
@@ -282,7 +431,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
282 evlist->mmap = NULL; 431 evlist->mmap = NULL;
283} 432}
284 433
285int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 434static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
286{ 435{
287 evlist->nr_mmaps = evlist->cpus->nr; 436 evlist->nr_mmaps = evlist->cpus->nr;
288 if (evlist->cpus->map[0] == -1) 437 if (evlist->cpus->map[0] == -1)
@@ -298,8 +447,10 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
298 evlist->mmap[idx].mask = mask; 447 evlist->mmap[idx].mask = mask;
299 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 448 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
300 MAP_SHARED, fd, 0); 449 MAP_SHARED, fd, 0);
301 if (evlist->mmap[idx].base == MAP_FAILED) 450 if (evlist->mmap[idx].base == MAP_FAILED) {
451 evlist->mmap[idx].base = NULL;
302 return -1; 452 return -1;
453 }
303 454
304 perf_evlist__add_pollfd(evlist, fd); 455 perf_evlist__add_pollfd(evlist, fd);
305 return 0; 456 return 0;
@@ -400,14 +551,22 @@ out_unmap:
400 * 551 *
401 * Using perf_evlist__read_on_cpu does this automatically. 552 * Using perf_evlist__read_on_cpu does this automatically.
402 */ 553 */
403int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) 554int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
555 bool overwrite)
404{ 556{
405 unsigned int page_size = sysconf(_SC_PAGE_SIZE); 557 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
406 int mask = pages * page_size - 1;
407 struct perf_evsel *evsel; 558 struct perf_evsel *evsel;
408 const struct cpu_map *cpus = evlist->cpus; 559 const struct cpu_map *cpus = evlist->cpus;
409 const struct thread_map *threads = evlist->threads; 560 const struct thread_map *threads = evlist->threads;
410 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); 561 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
562
563 /* 512 kiB: default amount of unprivileged mlocked memory */
564 if (pages == UINT_MAX)
565 pages = (512 * 1024) / page_size;
566 else if (!is_power_of_2(pages))
567 return -EINVAL;
568
569 mask = pages * page_size - 1;
411 570
412 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 571 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
413 return -ENOMEM; 572 return -ENOMEM;
@@ -512,6 +671,38 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
512 return first->attr.sample_type; 671 return first->attr.sample_type;
513} 672}
514 673
674u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist)
675{
676 struct perf_evsel *first;
677 struct perf_sample *data;
678 u64 sample_type;
679 u16 size = 0;
680
681 first = list_entry(evlist->entries.next, struct perf_evsel, node);
682
683 if (!first->attr.sample_id_all)
684 goto out;
685
686 sample_type = first->attr.sample_type;
687
688 if (sample_type & PERF_SAMPLE_TID)
689 size += sizeof(data->tid) * 2;
690
691 if (sample_type & PERF_SAMPLE_TIME)
692 size += sizeof(data->time);
693
694 if (sample_type & PERF_SAMPLE_ID)
695 size += sizeof(data->id);
696
697 if (sample_type & PERF_SAMPLE_STREAM_ID)
698 size += sizeof(data->stream_id);
699
700 if (sample_type & PERF_SAMPLE_CPU)
701 size += sizeof(data->cpu) * 2;
702out:
703 return size;
704}
705
515bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) 706bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
516{ 707{
517 struct perf_evsel *pos, *first; 708 struct perf_evsel *pos, *first;
@@ -569,3 +760,97 @@ out_err:
569 760
570 return err; 761 return err;
571} 762}
763
764int perf_evlist__prepare_workload(struct perf_evlist *evlist,
765 struct perf_record_opts *opts,
766 const char *argv[])
767{
768 int child_ready_pipe[2], go_pipe[2];
769 char bf;
770
771 if (pipe(child_ready_pipe) < 0) {
772 perror("failed to create 'ready' pipe");
773 return -1;
774 }
775
776 if (pipe(go_pipe) < 0) {
777 perror("failed to create 'go' pipe");
778 goto out_close_ready_pipe;
779 }
780
781 evlist->workload.pid = fork();
782 if (evlist->workload.pid < 0) {
783 perror("failed to fork");
784 goto out_close_pipes;
785 }
786
787 if (!evlist->workload.pid) {
788 if (opts->pipe_output)
789 dup2(2, 1);
790
791 close(child_ready_pipe[0]);
792 close(go_pipe[1]);
793 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
794
795 /*
796 * Do a dummy execvp to get the PLT entry resolved,
797 * so we avoid the resolver overhead on the real
798 * execvp call.
799 */
800 execvp("", (char **)argv);
801
802 /*
803 * Tell the parent we're ready to go
804 */
805 close(child_ready_pipe[1]);
806
807 /*
808 * Wait until the parent tells us to go.
809 */
810 if (read(go_pipe[0], &bf, 1) == -1)
811 perror("unable to read pipe");
812
813 execvp(argv[0], (char **)argv);
814
815 perror(argv[0]);
816 kill(getppid(), SIGUSR1);
817 exit(-1);
818 }
819
820 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
821 evlist->threads->map[0] = evlist->workload.pid;
822
823 close(child_ready_pipe[1]);
824 close(go_pipe[0]);
825 /*
826 * wait for child to settle
827 */
828 if (read(child_ready_pipe[0], &bf, 1) == -1) {
829 perror("unable to read pipe");
830 goto out_close_pipes;
831 }
832
833 evlist->workload.cork_fd = go_pipe[1];
834 close(child_ready_pipe[0]);
835 return 0;
836
837out_close_pipes:
838 close(go_pipe[0]);
839 close(go_pipe[1]);
840out_close_ready_pipe:
841 close(child_ready_pipe[0]);
842 close(child_ready_pipe[1]);
843 return -1;
844}
845
846int perf_evlist__start_workload(struct perf_evlist *evlist)
847{
848 if (evlist->workload.cork_fd > 0) {
849 /*
850 * Remove the cork, let it rip!
851 */
852 return close(evlist->workload.cork_fd);
853 }
854
855 return 0;
856}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 1779ffef7828..8922aeed0467 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -2,12 +2,16 @@
2#define __PERF_EVLIST_H 1 2#define __PERF_EVLIST_H 1
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <stdio.h>
5#include "../perf.h" 6#include "../perf.h"
6#include "event.h" 7#include "event.h"
8#include "util.h"
9#include <unistd.h>
7 10
8struct pollfd; 11struct pollfd;
9struct thread_map; 12struct thread_map;
10struct cpu_map; 13struct cpu_map;
14struct perf_record_opts;
11 15
12#define PERF_EVLIST__HLIST_BITS 8 16#define PERF_EVLIST__HLIST_BITS 8
13#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 17#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -19,6 +23,10 @@ struct perf_evlist {
19 int nr_fds; 23 int nr_fds;
20 int nr_mmaps; 24 int nr_mmaps;
21 int mmap_len; 25 int mmap_len;
26 struct {
27 int cork_fd;
28 pid_t pid;
29 } workload;
22 bool overwrite; 30 bool overwrite;
23 union perf_event event_copy; 31 union perf_event event_copy;
24 struct perf_mmap *mmap; 32 struct perf_mmap *mmap;
@@ -28,6 +36,11 @@ struct perf_evlist {
28 struct perf_evsel *selected; 36 struct perf_evsel *selected;
29}; 37};
30 38
39struct perf_evsel_str_handler {
40 const char *name;
41 void *handler;
42};
43
31struct perf_evsel; 44struct perf_evsel;
32 45
33struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 46struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -39,11 +52,26 @@ void perf_evlist__delete(struct perf_evlist *evlist);
39 52
40void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); 53void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
41int perf_evlist__add_default(struct perf_evlist *evlist); 54int perf_evlist__add_default(struct perf_evlist *evlist);
55int perf_evlist__add_attrs(struct perf_evlist *evlist,
56 struct perf_event_attr *attrs, size_t nr_attrs);
57int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
58 const char *tracepoints[], size_t nr_tracepoints);
59int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
60 const struct perf_evsel_str_handler *assocs,
61 size_t nr_assocs);
62
63#define perf_evlist__add_attrs_array(evlist, array) \
64 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array))
65
66#define perf_evlist__add_tracepoints_array(evlist, array) \
67 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
68
69#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
70 perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
42 71
43void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 72void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
44 int cpu, int thread, u64 id); 73 int cpu, int thread, u64 id);
45 74
46int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
47void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 75void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
48 76
49struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); 77struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
@@ -52,8 +80,16 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
52 80
53int perf_evlist__open(struct perf_evlist *evlist, bool group); 81int perf_evlist__open(struct perf_evlist *evlist, bool group);
54 82
55int perf_evlist__alloc_mmap(struct perf_evlist *evlist); 83void perf_evlist__config_attrs(struct perf_evlist *evlist,
56int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); 84 struct perf_record_opts *opts);
85
86int perf_evlist__prepare_workload(struct perf_evlist *evlist,
87 struct perf_record_opts *opts,
88 const char *argv[]);
89int perf_evlist__start_workload(struct perf_evlist *evlist);
90
91int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
92 bool overwrite);
57void perf_evlist__munmap(struct perf_evlist *evlist); 93void perf_evlist__munmap(struct perf_evlist *evlist);
58 94
59void perf_evlist__disable(struct perf_evlist *evlist); 95void perf_evlist__disable(struct perf_evlist *evlist);
@@ -77,6 +113,7 @@ int perf_evlist__set_filters(struct perf_evlist *evlist);
77 113
78u64 perf_evlist__sample_type(const struct perf_evlist *evlist); 114u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
79bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); 115bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
116u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
80 117
81bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); 118bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
82bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); 119bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d7915d4e77cb..667f3b78bb2c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -63,6 +63,79 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 63 return evsel;
64} 64}
65 65
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
67{
68 struct perf_event_attr *attr = &evsel->attr;
69 int track = !evsel->idx; /* only the first counter needs these */
70
71 attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0;
72 attr->inherit = !opts->no_inherit;
73 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
74 PERF_FORMAT_TOTAL_TIME_RUNNING |
75 PERF_FORMAT_ID;
76
77 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
78
79 /*
80 * We default some events to a 1 default interval. But keep
81 * it a weak assumption overridable by the user.
82 */
83 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
84 opts->user_interval != ULLONG_MAX)) {
85 if (opts->freq) {
86 attr->sample_type |= PERF_SAMPLE_PERIOD;
87 attr->freq = 1;
88 attr->sample_freq = opts->freq;
89 } else {
90 attr->sample_period = opts->default_interval;
91 }
92 }
93
94 if (opts->no_samples)
95 attr->sample_freq = 0;
96
97 if (opts->inherit_stat)
98 attr->inherit_stat = 1;
99
100 if (opts->sample_address) {
101 attr->sample_type |= PERF_SAMPLE_ADDR;
102 attr->mmap_data = track;
103 }
104
105 if (opts->call_graph)
106 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
107
108 if (opts->system_wide)
109 attr->sample_type |= PERF_SAMPLE_CPU;
110
111 if (opts->period)
112 attr->sample_type |= PERF_SAMPLE_PERIOD;
113
114 if (opts->sample_id_all_avail &&
115 (opts->sample_time || opts->system_wide ||
116 !opts->no_inherit || opts->cpu_list))
117 attr->sample_type |= PERF_SAMPLE_TIME;
118
119 if (opts->raw_samples) {
120 attr->sample_type |= PERF_SAMPLE_TIME;
121 attr->sample_type |= PERF_SAMPLE_RAW;
122 attr->sample_type |= PERF_SAMPLE_CPU;
123 }
124
125 if (opts->no_delay) {
126 attr->watermark = 0;
127 attr->wakeup_events = 1;
128 }
129
130 attr->mmap = track;
131 attr->comm = track;
132
133 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) {
134 attr->disabled = 1;
135 attr->enable_on_exec = 1;
136 }
137}
138
66int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 139int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
67{ 140{
68 int cpu, thread; 141 int cpu, thread;
@@ -387,7 +460,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
387 u32 val32[2]; 460 u32 val32[2];
388 } u; 461 } u;
389 462
390 463 memset(data, 0, sizeof(*data));
391 data->cpu = data->pid = data->tid = -1; 464 data->cpu = data->pid = data->tid = -1;
392 data->stream_id = data->id = data->time = -1ULL; 465 data->stream_id = data->id = data->time = -1ULL;
393 466
@@ -504,3 +577,82 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
504 577
505 return 0; 578 return 0;
506} 579}
580
581int perf_event__synthesize_sample(union perf_event *event, u64 type,
582 const struct perf_sample *sample,
583 bool swapped)
584{
585 u64 *array;
586
587 /*
588 * used for cross-endian analysis. See git commit 65014ab3
589 * for why this goofiness is needed.
590 */
591 union {
592 u64 val64;
593 u32 val32[2];
594 } u;
595
596 array = event->sample.array;
597
598 if (type & PERF_SAMPLE_IP) {
599 event->ip.ip = sample->ip;
600 array++;
601 }
602
603 if (type & PERF_SAMPLE_TID) {
604 u.val32[0] = sample->pid;
605 u.val32[1] = sample->tid;
606 if (swapped) {
607 /*
608 * Inverse of what is done in perf_event__parse_sample
609 */
610 u.val32[0] = bswap_32(u.val32[0]);
611 u.val32[1] = bswap_32(u.val32[1]);
612 u.val64 = bswap_64(u.val64);
613 }
614
615 *array = u.val64;
616 array++;
617 }
618
619 if (type & PERF_SAMPLE_TIME) {
620 *array = sample->time;
621 array++;
622 }
623
624 if (type & PERF_SAMPLE_ADDR) {
625 *array = sample->addr;
626 array++;
627 }
628
629 if (type & PERF_SAMPLE_ID) {
630 *array = sample->id;
631 array++;
632 }
633
634 if (type & PERF_SAMPLE_STREAM_ID) {
635 *array = sample->stream_id;
636 array++;
637 }
638
639 if (type & PERF_SAMPLE_CPU) {
640 u.val32[0] = sample->cpu;
641 if (swapped) {
642 /*
643 * Inverse of what is done in perf_event__parse_sample
644 */
645 u.val32[0] = bswap_32(u.val32[0]);
646 u.val64 = bswap_64(u.val64);
647 }
648 *array = u.val64;
649 array++;
650 }
651
652 if (type & PERF_SAMPLE_PERIOD) {
653 *array = sample->period;
654 array++;
655 }
656
657 return 0;
658}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index b1d15e6f7ae3..326b8e4d5035 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -61,12 +61,17 @@ struct perf_evsel {
61 off_t id_offset; 61 off_t id_offset;
62 }; 62 };
63 struct cgroup_sel *cgrp; 63 struct cgroup_sel *cgrp;
64 struct {
65 void *func;
66 void *data;
67 } handler;
64 bool supported; 68 bool supported;
65}; 69};
66 70
67struct cpu_map; 71struct cpu_map;
68struct thread_map; 72struct thread_map;
69struct perf_evlist; 73struct perf_evlist;
74struct perf_record_opts;
70 75
71struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 76struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
72void perf_evsel__init(struct perf_evsel *evsel, 77void perf_evsel__init(struct perf_evsel *evsel,
@@ -74,6 +79,9 @@ void perf_evsel__init(struct perf_evsel *evsel,
74void perf_evsel__exit(struct perf_evsel *evsel); 79void perf_evsel__exit(struct perf_evsel *evsel);
75void perf_evsel__delete(struct perf_evsel *evsel); 80void perf_evsel__delete(struct perf_evsel *evsel);
76 81
82void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts);
84
77int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 85int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
78int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 86int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
79int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 87int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 33c17a2b2a81..3e7e0b09c12c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,6 +8,7 @@
8#include <stdlib.h> 8#include <stdlib.h>
9#include <linux/list.h> 9#include <linux/list.h>
10#include <linux/kernel.h> 10#include <linux/kernel.h>
11#include <linux/bitops.h>
11#include <sys/utsname.h> 12#include <sys/utsname.h>
12 13
13#include "evlist.h" 14#include "evlist.h"
@@ -28,9 +29,6 @@ static struct perf_trace_event_type *events;
28static u32 header_argc; 29static u32 header_argc;
29static const char **header_argv; 30static const char **header_argv;
30 31
31static int dsos__write_buildid_table(struct perf_header *header, int fd);
32static int perf_session__cache_build_ids(struct perf_session *session);
33
34int perf_header__push_event(u64 id, const char *name) 32int perf_header__push_event(u64 id, const char *name)
35{ 33{
36 if (strlen(name) > MAX_EVENT_NAME) 34 if (strlen(name) > MAX_EVENT_NAME)
@@ -187,6 +185,252 @@ perf_header__set_cmdline(int argc, const char **argv)
187 return 0; 185 return 0;
188} 186}
189 187
188#define dsos__for_each_with_build_id(pos, head) \
189 list_for_each_entry(pos, head, node) \
190 if (!pos->has_build_id) \
191 continue; \
192 else
193
194static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
195 u16 misc, int fd)
196{
197 struct dso *pos;
198
199 dsos__for_each_with_build_id(pos, head) {
200 int err;
201 struct build_id_event b;
202 size_t len;
203
204 if (!pos->hit)
205 continue;
206 len = pos->long_name_len + 1;
207 len = ALIGN(len, NAME_ALIGN);
208 memset(&b, 0, sizeof(b));
209 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
210 b.pid = pid;
211 b.header.misc = misc;
212 b.header.size = sizeof(b) + len;
213 err = do_write(fd, &b, sizeof(b));
214 if (err < 0)
215 return err;
216 err = write_padded(fd, pos->long_name,
217 pos->long_name_len + 1, len);
218 if (err < 0)
219 return err;
220 }
221
222 return 0;
223}
224
225static int machine__write_buildid_table(struct machine *machine, int fd)
226{
227 int err;
228 u16 kmisc = PERF_RECORD_MISC_KERNEL,
229 umisc = PERF_RECORD_MISC_USER;
230
231 if (!machine__is_host(machine)) {
232 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
233 umisc = PERF_RECORD_MISC_GUEST_USER;
234 }
235
236 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
237 kmisc, fd);
238 if (err == 0)
239 err = __dsos__write_buildid_table(&machine->user_dsos,
240 machine->pid, umisc, fd);
241 return err;
242}
243
244static int dsos__write_buildid_table(struct perf_header *header, int fd)
245{
246 struct perf_session *session = container_of(header,
247 struct perf_session, header);
248 struct rb_node *nd;
249 int err = machine__write_buildid_table(&session->host_machine, fd);
250
251 if (err)
252 return err;
253
254 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
255 struct machine *pos = rb_entry(nd, struct machine, rb_node);
256 err = machine__write_buildid_table(pos, fd);
257 if (err)
258 break;
259 }
260 return err;
261}
262
263int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
264 const char *name, bool is_kallsyms)
265{
266 const size_t size = PATH_MAX;
267 char *realname, *filename = zalloc(size),
268 *linkname = zalloc(size), *targetname;
269 int len, err = -1;
270
271 if (is_kallsyms) {
272 if (symbol_conf.kptr_restrict) {
273 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
274 return 0;
275 }
276 realname = (char *)name;
277 } else
278 realname = realpath(name, NULL);
279
280 if (realname == NULL || filename == NULL || linkname == NULL)
281 goto out_free;
282
283 len = snprintf(filename, size, "%s%s%s",
284 debugdir, is_kallsyms ? "/" : "", realname);
285 if (mkdir_p(filename, 0755))
286 goto out_free;
287
288 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
289
290 if (access(filename, F_OK)) {
291 if (is_kallsyms) {
292 if (copyfile("/proc/kallsyms", filename))
293 goto out_free;
294 } else if (link(realname, filename) && copyfile(name, filename))
295 goto out_free;
296 }
297
298 len = snprintf(linkname, size, "%s/.build-id/%.2s",
299 debugdir, sbuild_id);
300
301 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
302 goto out_free;
303
304 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
305 targetname = filename + strlen(debugdir) - 5;
306 memcpy(targetname, "../..", 5);
307
308 if (symlink(targetname, linkname) == 0)
309 err = 0;
310out_free:
311 if (!is_kallsyms)
312 free(realname);
313 free(filename);
314 free(linkname);
315 return err;
316}
317
318static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
319 const char *name, const char *debugdir,
320 bool is_kallsyms)
321{
322 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
323
324 build_id__sprintf(build_id, build_id_size, sbuild_id);
325
326 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
327}
328
329int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
330{
331 const size_t size = PATH_MAX;
332 char *filename = zalloc(size),
333 *linkname = zalloc(size);
334 int err = -1;
335
336 if (filename == NULL || linkname == NULL)
337 goto out_free;
338
339 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
340 debugdir, sbuild_id, sbuild_id + 2);
341
342 if (access(linkname, F_OK))
343 goto out_free;
344
345 if (readlink(linkname, filename, size - 1) < 0)
346 goto out_free;
347
348 if (unlink(linkname))
349 goto out_free;
350
351 /*
352 * Since the link is relative, we must make it absolute:
353 */
354 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
355 debugdir, sbuild_id, filename);
356
357 if (unlink(linkname))
358 goto out_free;
359
360 err = 0;
361out_free:
362 free(filename);
363 free(linkname);
364 return err;
365}
366
367static int dso__cache_build_id(struct dso *dso, const char *debugdir)
368{
369 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
370
371 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
372 dso->long_name, debugdir, is_kallsyms);
373}
374
375static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
376{
377 struct dso *pos;
378 int err = 0;
379
380 dsos__for_each_with_build_id(pos, head)
381 if (dso__cache_build_id(pos, debugdir))
382 err = -1;
383
384 return err;
385}
386
387static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
388{
389 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
390 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
391 return ret;
392}
393
394static int perf_session__cache_build_ids(struct perf_session *session)
395{
396 struct rb_node *nd;
397 int ret;
398 char debugdir[PATH_MAX];
399
400 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
401
402 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
403 return -1;
404
405 ret = machine__cache_build_ids(&session->host_machine, debugdir);
406
407 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
408 struct machine *pos = rb_entry(nd, struct machine, rb_node);
409 ret |= machine__cache_build_ids(pos, debugdir);
410 }
411 return ret ? -1 : 0;
412}
413
414static bool machine__read_build_ids(struct machine *machine, bool with_hits)
415{
416 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
417 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
418 return ret;
419}
420
421static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
422{
423 struct rb_node *nd;
424 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
425
426 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
427 struct machine *pos = rb_entry(nd, struct machine, rb_node);
428 ret |= machine__read_build_ids(pos, with_hits);
429 }
430
431 return ret;
432}
433
190static int write_trace_info(int fd, struct perf_header *h __used, 434static int write_trace_info(int fd, struct perf_header *h __used,
191 struct perf_evlist *evlist) 435 struct perf_evlist *evlist)
192{ 436{
@@ -202,6 +446,9 @@ static int write_build_id(int fd, struct perf_header *h,
202 446
203 session = container_of(h, struct perf_session, header); 447 session = container_of(h, struct perf_session, header);
204 448
449 if (!perf_session__read_build_ids(session, true))
450 return -1;
451
205 err = dsos__write_buildid_table(h, fd); 452 err = dsos__write_buildid_table(h, fd);
206 if (err < 0) { 453 if (err < 0) {
207 pr_debug("failed to write buildid table\n"); 454 pr_debug("failed to write buildid table\n");
@@ -1065,26 +1312,30 @@ struct feature_ops {
1065 bool full_only; 1312 bool full_only;
1066}; 1313};
1067 1314
1068#define FEAT_OPA(n, w, p) \ 1315#define FEAT_OPA(n, func) \
1069 [n] = { .name = #n, .write = w, .print = p } 1316 [n] = { .name = #n, .write = write_##func, .print = print_##func }
1070#define FEAT_OPF(n, w, p) \ 1317#define FEAT_OPF(n, func) \
1071 [n] = { .name = #n, .write = w, .print = p, .full_only = true } 1318 [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true }
1319
1320/* feature_ops not implemented: */
1321#define print_trace_info NULL
1322#define print_build_id NULL
1072 1323
1073static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1324static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1074 FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL), 1325 FEAT_OPA(HEADER_TRACE_INFO, trace_info),
1075 FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL), 1326 FEAT_OPA(HEADER_BUILD_ID, build_id),
1076 FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname), 1327 FEAT_OPA(HEADER_HOSTNAME, hostname),
1077 FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease), 1328 FEAT_OPA(HEADER_OSRELEASE, osrelease),
1078 FEAT_OPA(HEADER_VERSION, write_version, print_version), 1329 FEAT_OPA(HEADER_VERSION, version),
1079 FEAT_OPA(HEADER_ARCH, write_arch, print_arch), 1330 FEAT_OPA(HEADER_ARCH, arch),
1080 FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus), 1331 FEAT_OPA(HEADER_NRCPUS, nrcpus),
1081 FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc), 1332 FEAT_OPA(HEADER_CPUDESC, cpudesc),
1082 FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid), 1333 FEAT_OPA(HEADER_CPUID, cpuid),
1083 FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem), 1334 FEAT_OPA(HEADER_TOTAL_MEM, total_mem),
1084 FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc), 1335 FEAT_OPA(HEADER_EVENT_DESC, event_desc),
1085 FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline), 1336 FEAT_OPA(HEADER_CMDLINE, cmdline),
1086 FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology), 1337 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
1087 FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology), 1338 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1088}; 1339};
1089 1340
1090struct header_print_data { 1341struct header_print_data {
@@ -1103,9 +1354,9 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section,
1103 "%d, continuing...\n", section->offset, feat); 1354 "%d, continuing...\n", section->offset, feat);
1104 return 0; 1355 return 0;
1105 } 1356 }
1106 if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { 1357 if (feat >= HEADER_LAST_FEATURE) {
1107 pr_warning("unknown feature %d\n", feat); 1358 pr_warning("unknown feature %d\n", feat);
1108 return -1; 1359 return 0;
1109 } 1360 }
1110 if (!feat_ops[feat].print) 1361 if (!feat_ops[feat].print)
1111 return 0; 1362 return 0;
@@ -1132,252 +1383,6 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
1132 return 0; 1383 return 0;
1133} 1384}
1134 1385
1135#define dsos__for_each_with_build_id(pos, head) \
1136 list_for_each_entry(pos, head, node) \
1137 if (!pos->has_build_id) \
1138 continue; \
1139 else
1140
1141static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
1142 u16 misc, int fd)
1143{
1144 struct dso *pos;
1145
1146 dsos__for_each_with_build_id(pos, head) {
1147 int err;
1148 struct build_id_event b;
1149 size_t len;
1150
1151 if (!pos->hit)
1152 continue;
1153 len = pos->long_name_len + 1;
1154 len = ALIGN(len, NAME_ALIGN);
1155 memset(&b, 0, sizeof(b));
1156 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
1157 b.pid = pid;
1158 b.header.misc = misc;
1159 b.header.size = sizeof(b) + len;
1160 err = do_write(fd, &b, sizeof(b));
1161 if (err < 0)
1162 return err;
1163 err = write_padded(fd, pos->long_name,
1164 pos->long_name_len + 1, len);
1165 if (err < 0)
1166 return err;
1167 }
1168
1169 return 0;
1170}
1171
1172static int machine__write_buildid_table(struct machine *machine, int fd)
1173{
1174 int err;
1175 u16 kmisc = PERF_RECORD_MISC_KERNEL,
1176 umisc = PERF_RECORD_MISC_USER;
1177
1178 if (!machine__is_host(machine)) {
1179 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
1180 umisc = PERF_RECORD_MISC_GUEST_USER;
1181 }
1182
1183 err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid,
1184 kmisc, fd);
1185 if (err == 0)
1186 err = __dsos__write_buildid_table(&machine->user_dsos,
1187 machine->pid, umisc, fd);
1188 return err;
1189}
1190
1191static int dsos__write_buildid_table(struct perf_header *header, int fd)
1192{
1193 struct perf_session *session = container_of(header,
1194 struct perf_session, header);
1195 struct rb_node *nd;
1196 int err = machine__write_buildid_table(&session->host_machine, fd);
1197
1198 if (err)
1199 return err;
1200
1201 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
1202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1203 err = machine__write_buildid_table(pos, fd);
1204 if (err)
1205 break;
1206 }
1207 return err;
1208}
1209
1210int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
1211 const char *name, bool is_kallsyms)
1212{
1213 const size_t size = PATH_MAX;
1214 char *realname, *filename = zalloc(size),
1215 *linkname = zalloc(size), *targetname;
1216 int len, err = -1;
1217
1218 if (is_kallsyms) {
1219 if (symbol_conf.kptr_restrict) {
1220 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
1221 return 0;
1222 }
1223 realname = (char *)name;
1224 } else
1225 realname = realpath(name, NULL);
1226
1227 if (realname == NULL || filename == NULL || linkname == NULL)
1228 goto out_free;
1229
1230 len = snprintf(filename, size, "%s%s%s",
1231 debugdir, is_kallsyms ? "/" : "", realname);
1232 if (mkdir_p(filename, 0755))
1233 goto out_free;
1234
1235 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
1236
1237 if (access(filename, F_OK)) {
1238 if (is_kallsyms) {
1239 if (copyfile("/proc/kallsyms", filename))
1240 goto out_free;
1241 } else if (link(realname, filename) && copyfile(name, filename))
1242 goto out_free;
1243 }
1244
1245 len = snprintf(linkname, size, "%s/.build-id/%.2s",
1246 debugdir, sbuild_id);
1247
1248 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
1249 goto out_free;
1250
1251 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
1252 targetname = filename + strlen(debugdir) - 5;
1253 memcpy(targetname, "../..", 5);
1254
1255 if (symlink(targetname, linkname) == 0)
1256 err = 0;
1257out_free:
1258 if (!is_kallsyms)
1259 free(realname);
1260 free(filename);
1261 free(linkname);
1262 return err;
1263}
1264
1265static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
1266 const char *name, const char *debugdir,
1267 bool is_kallsyms)
1268{
1269 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1270
1271 build_id__sprintf(build_id, build_id_size, sbuild_id);
1272
1273 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
1274}
1275
1276int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
1277{
1278 const size_t size = PATH_MAX;
1279 char *filename = zalloc(size),
1280 *linkname = zalloc(size);
1281 int err = -1;
1282
1283 if (filename == NULL || linkname == NULL)
1284 goto out_free;
1285
1286 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
1287 debugdir, sbuild_id, sbuild_id + 2);
1288
1289 if (access(linkname, F_OK))
1290 goto out_free;
1291
1292 if (readlink(linkname, filename, size - 1) < 0)
1293 goto out_free;
1294
1295 if (unlink(linkname))
1296 goto out_free;
1297
1298 /*
1299 * Since the link is relative, we must make it absolute:
1300 */
1301 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
1302 debugdir, sbuild_id, filename);
1303
1304 if (unlink(linkname))
1305 goto out_free;
1306
1307 err = 0;
1308out_free:
1309 free(filename);
1310 free(linkname);
1311 return err;
1312}
1313
1314static int dso__cache_build_id(struct dso *dso, const char *debugdir)
1315{
1316 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
1317
1318 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id),
1319 dso->long_name, debugdir, is_kallsyms);
1320}
1321
1322static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
1323{
1324 struct dso *pos;
1325 int err = 0;
1326
1327 dsos__for_each_with_build_id(pos, head)
1328 if (dso__cache_build_id(pos, debugdir))
1329 err = -1;
1330
1331 return err;
1332}
1333
1334static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
1335{
1336 int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir);
1337 ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir);
1338 return ret;
1339}
1340
1341static int perf_session__cache_build_ids(struct perf_session *session)
1342{
1343 struct rb_node *nd;
1344 int ret;
1345 char debugdir[PATH_MAX];
1346
1347 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
1348
1349 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
1350 return -1;
1351
1352 ret = machine__cache_build_ids(&session->host_machine, debugdir);
1353
1354 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
1355 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1356 ret |= machine__cache_build_ids(pos, debugdir);
1357 }
1358 return ret ? -1 : 0;
1359}
1360
1361static bool machine__read_build_ids(struct machine *machine, bool with_hits)
1362{
1363 bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits);
1364 ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits);
1365 return ret;
1366}
1367
1368static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
1369{
1370 struct rb_node *nd;
1371 bool ret = machine__read_build_ids(&session->host_machine, with_hits);
1372
1373 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
1374 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1375 ret |= machine__read_build_ids(pos, with_hits);
1376 }
1377
1378 return ret;
1379}
1380
1381static int do_write_feat(int fd, struct perf_header *h, int type, 1386static int do_write_feat(int fd, struct perf_header *h, int type,
1382 struct perf_file_section **p, 1387 struct perf_file_section **p,
1383 struct perf_evlist *evlist) 1388 struct perf_evlist *evlist)
@@ -1386,6 +1391,8 @@ static int do_write_feat(int fd, struct perf_header *h, int type,
1386 int ret = 0; 1391 int ret = 0;
1387 1392
1388 if (perf_header__has_feat(h, type)) { 1393 if (perf_header__has_feat(h, type)) {
1394 if (!feat_ops[type].write)
1395 return -1;
1389 1396
1390 (*p)->offset = lseek(fd, 0, SEEK_CUR); 1397 (*p)->offset = lseek(fd, 0, SEEK_CUR);
1391 1398
@@ -1408,18 +1415,12 @@ static int perf_header__adds_write(struct perf_header *header,
1408 struct perf_evlist *evlist, int fd) 1415 struct perf_evlist *evlist, int fd)
1409{ 1416{
1410 int nr_sections; 1417 int nr_sections;
1411 struct perf_session *session;
1412 struct perf_file_section *feat_sec, *p; 1418 struct perf_file_section *feat_sec, *p;
1413 int sec_size; 1419 int sec_size;
1414 u64 sec_start; 1420 u64 sec_start;
1421 int feat;
1415 int err; 1422 int err;
1416 1423
1417 session = container_of(header, struct perf_session, header);
1418
1419 if (perf_header__has_feat(header, HEADER_BUILD_ID &&
1420 !perf_session__read_build_ids(session, true)))
1421 perf_header__clear_feat(header, HEADER_BUILD_ID);
1422
1423 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 1424 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
1424 if (!nr_sections) 1425 if (!nr_sections)
1425 return 0; 1426 return 0;
@@ -1433,64 +1434,11 @@ static int perf_header__adds_write(struct perf_header *header,
1433 sec_start = header->data_offset + header->data_size; 1434 sec_start = header->data_offset + header->data_size;
1434 lseek(fd, sec_start + sec_size, SEEK_SET); 1435 lseek(fd, sec_start + sec_size, SEEK_SET);
1435 1436
1436 err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); 1437 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
1437 if (err) 1438 if (do_write_feat(fd, header, feat, &p, evlist))
1438 goto out_free; 1439 perf_header__clear_feat(header, feat);
1439
1440 err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist);
1441 if (err) {
1442 perf_header__clear_feat(header, HEADER_BUILD_ID);
1443 goto out_free;
1444 } 1440 }
1445 1441
1446 err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist);
1447 if (err)
1448 perf_header__clear_feat(header, HEADER_HOSTNAME);
1449
1450 err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist);
1451 if (err)
1452 perf_header__clear_feat(header, HEADER_OSRELEASE);
1453
1454 err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist);
1455 if (err)
1456 perf_header__clear_feat(header, HEADER_VERSION);
1457
1458 err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist);
1459 if (err)
1460 perf_header__clear_feat(header, HEADER_ARCH);
1461
1462 err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist);
1463 if (err)
1464 perf_header__clear_feat(header, HEADER_NRCPUS);
1465
1466 err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist);
1467 if (err)
1468 perf_header__clear_feat(header, HEADER_CPUDESC);
1469
1470 err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist);
1471 if (err)
1472 perf_header__clear_feat(header, HEADER_CPUID);
1473
1474 err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist);
1475 if (err)
1476 perf_header__clear_feat(header, HEADER_TOTAL_MEM);
1477
1478 err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist);
1479 if (err)
1480 perf_header__clear_feat(header, HEADER_CMDLINE);
1481
1482 err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist);
1483 if (err)
1484 perf_header__clear_feat(header, HEADER_EVENT_DESC);
1485
1486 err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist);
1487 if (err)
1488 perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY);
1489
1490 err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist);
1491 if (err)
1492 perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY);
1493
1494 lseek(fd, sec_start, SEEK_SET); 1442 lseek(fd, sec_start, SEEK_SET);
1495 /* 1443 /*
1496 * may write more than needed due to dropped feature, but 1444 * may write more than needed due to dropped feature, but
@@ -1499,7 +1447,6 @@ static int perf_header__adds_write(struct perf_header *header,
1499 err = do_write(fd, feat_sec, sec_size); 1447 err = do_write(fd, feat_sec, sec_size);
1500 if (err < 0) 1448 if (err < 0)
1501 pr_debug("failed to write feature section\n"); 1449 pr_debug("failed to write feature section\n");
1502out_free:
1503 free(feat_sec); 1450 free(feat_sec);
1504 return err; 1451 return err;
1505} 1452}
@@ -1637,20 +1584,20 @@ static int perf_header__getbuffer64(struct perf_header *header,
1637int perf_header__process_sections(struct perf_header *header, int fd, 1584int perf_header__process_sections(struct perf_header *header, int fd,
1638 void *data, 1585 void *data,
1639 int (*process)(struct perf_file_section *section, 1586 int (*process)(struct perf_file_section *section,
1640 struct perf_header *ph, 1587 struct perf_header *ph,
1641 int feat, int fd, void *data)) 1588 int feat, int fd, void *data))
1642{ 1589{
1643 struct perf_file_section *feat_sec; 1590 struct perf_file_section *feat_sec, *sec;
1644 int nr_sections; 1591 int nr_sections;
1645 int sec_size; 1592 int sec_size;
1646 int idx = 0; 1593 int feat;
1647 int err = -1, feat = 1; 1594 int err;
1648 1595
1649 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 1596 nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
1650 if (!nr_sections) 1597 if (!nr_sections)
1651 return 0; 1598 return 0;
1652 1599
1653 feat_sec = calloc(sizeof(*feat_sec), nr_sections); 1600 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections);
1654 if (!feat_sec) 1601 if (!feat_sec)
1655 return -1; 1602 return -1;
1656 1603
@@ -1658,20 +1605,16 @@ int perf_header__process_sections(struct perf_header *header, int fd,
1658 1605
1659 lseek(fd, header->data_offset + header->data_size, SEEK_SET); 1606 lseek(fd, header->data_offset + header->data_size, SEEK_SET);
1660 1607
1661 if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) 1608 err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
1609 if (err < 0)
1662 goto out_free; 1610 goto out_free;
1663 1611
1664 err = 0; 1612 for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) {
1665 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 1613 err = process(sec++, header, feat, fd, data);
1666 if (perf_header__has_feat(header, feat)) { 1614 if (err < 0)
1667 struct perf_file_section *sec = &feat_sec[idx++]; 1615 goto out_free;
1668
1669 err = process(sec, header, feat, fd, data);
1670 if (err < 0)
1671 break;
1672 }
1673 ++feat;
1674 } 1616 }
1617 err = 0;
1675out_free: 1618out_free:
1676 free(feat_sec); 1619 free(feat_sec);
1677 return err; 1620 return err;
@@ -1906,32 +1849,21 @@ static int perf_file_section__process(struct perf_file_section *section,
1906 return 0; 1849 return 0;
1907 } 1850 }
1908 1851
1852 if (feat >= HEADER_LAST_FEATURE) {
1853 pr_debug("unknown feature %d, continuing...\n", feat);
1854 return 0;
1855 }
1856
1909 switch (feat) { 1857 switch (feat) {
1910 case HEADER_TRACE_INFO: 1858 case HEADER_TRACE_INFO:
1911 trace_report(fd, false); 1859 trace_report(fd, false);
1912 break; 1860 break;
1913
1914 case HEADER_BUILD_ID: 1861 case HEADER_BUILD_ID:
1915 if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) 1862 if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
1916 pr_debug("Failed to read buildids, continuing...\n"); 1863 pr_debug("Failed to read buildids, continuing...\n");
1917 break; 1864 break;
1918
1919 case HEADER_HOSTNAME:
1920 case HEADER_OSRELEASE:
1921 case HEADER_VERSION:
1922 case HEADER_ARCH:
1923 case HEADER_NRCPUS:
1924 case HEADER_CPUDESC:
1925 case HEADER_CPUID:
1926 case HEADER_TOTAL_MEM:
1927 case HEADER_CMDLINE:
1928 case HEADER_EVENT_DESC:
1929 case HEADER_CPU_TOPOLOGY:
1930 case HEADER_NUMA_TOPOLOGY:
1931 break;
1932
1933 default: 1865 default:
1934 pr_debug("unknown feature %d, continuing...\n", feat); 1866 break;
1935 } 1867 }
1936 1868
1937 return 0; 1869 return 0;
@@ -2041,6 +1973,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
2041 lseek(fd, tmp, SEEK_SET); 1973 lseek(fd, tmp, SEEK_SET);
2042 } 1974 }
2043 1975
1976 symbol_conf.nr_events = nr_attrs;
1977
2044 if (f_header.event_types.size) { 1978 if (f_header.event_types.size) {
2045 lseek(fd, f_header.event_types.offset, SEEK_SET); 1979 lseek(fd, f_header.event_types.offset, SEEK_SET);
2046 events = malloc(f_header.event_types.size); 1980 events = malloc(f_header.event_types.size);
@@ -2068,9 +2002,9 @@ out_delete_evlist:
2068 return -ENOMEM; 2002 return -ENOMEM;
2069} 2003}
2070 2004
2071int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 2005int perf_event__synthesize_attr(struct perf_tool *tool,
2072 perf_event__handler_t process, 2006 struct perf_event_attr *attr, u16 ids, u64 *id,
2073 struct perf_session *session) 2007 perf_event__handler_t process)
2074{ 2008{
2075 union perf_event *ev; 2009 union perf_event *ev;
2076 size_t size; 2010 size_t size;
@@ -2092,22 +2026,23 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
2092 ev->attr.header.type = PERF_RECORD_HEADER_ATTR; 2026 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
2093 ev->attr.header.size = size; 2027 ev->attr.header.size = size;
2094 2028
2095 err = process(ev, NULL, session); 2029 err = process(tool, ev, NULL, NULL);
2096 2030
2097 free(ev); 2031 free(ev);
2098 2032
2099 return err; 2033 return err;
2100} 2034}
2101 2035
2102int perf_session__synthesize_attrs(struct perf_session *session, 2036int perf_event__synthesize_attrs(struct perf_tool *tool,
2037 struct perf_session *session,
2103 perf_event__handler_t process) 2038 perf_event__handler_t process)
2104{ 2039{
2105 struct perf_evsel *attr; 2040 struct perf_evsel *attr;
2106 int err = 0; 2041 int err = 0;
2107 2042
2108 list_for_each_entry(attr, &session->evlist->entries, node) { 2043 list_for_each_entry(attr, &session->evlist->entries, node) {
2109 err = perf_event__synthesize_attr(&attr->attr, attr->ids, 2044 err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids,
2110 attr->id, process, session); 2045 attr->id, process);
2111 if (err) { 2046 if (err) {
2112 pr_debug("failed to create perf header attribute\n"); 2047 pr_debug("failed to create perf header attribute\n");
2113 return err; 2048 return err;
@@ -2118,23 +2053,23 @@ int perf_session__synthesize_attrs(struct perf_session *session,
2118} 2053}
2119 2054
2120int perf_event__process_attr(union perf_event *event, 2055int perf_event__process_attr(union perf_event *event,
2121 struct perf_session *session) 2056 struct perf_evlist **pevlist)
2122{ 2057{
2123 unsigned int i, ids, n_ids; 2058 unsigned int i, ids, n_ids;
2124 struct perf_evsel *evsel; 2059 struct perf_evsel *evsel;
2060 struct perf_evlist *evlist = *pevlist;
2125 2061
2126 if (session->evlist == NULL) { 2062 if (evlist == NULL) {
2127 session->evlist = perf_evlist__new(NULL, NULL); 2063 *pevlist = evlist = perf_evlist__new(NULL, NULL);
2128 if (session->evlist == NULL) 2064 if (evlist == NULL)
2129 return -ENOMEM; 2065 return -ENOMEM;
2130 } 2066 }
2131 2067
2132 evsel = perf_evsel__new(&event->attr.attr, 2068 evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries);
2133 session->evlist->nr_entries);
2134 if (evsel == NULL) 2069 if (evsel == NULL)
2135 return -ENOMEM; 2070 return -ENOMEM;
2136 2071
2137 perf_evlist__add(session->evlist, evsel); 2072 perf_evlist__add(evlist, evsel);
2138 2073
2139 ids = event->header.size; 2074 ids = event->header.size;
2140 ids -= (void *)&event->attr.id - (void *)event; 2075 ids -= (void *)&event->attr.id - (void *)event;
@@ -2148,18 +2083,16 @@ int perf_event__process_attr(union perf_event *event,
2148 return -ENOMEM; 2083 return -ENOMEM;
2149 2084
2150 for (i = 0; i < n_ids; i++) { 2085 for (i = 0; i < n_ids; i++) {
2151 perf_evlist__id_add(session->evlist, evsel, 0, i, 2086 perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]);
2152 event->attr.id[i]);
2153 } 2087 }
2154 2088
2155 perf_session__update_sample_type(session);
2156
2157 return 0; 2089 return 0;
2158} 2090}
2159 2091
2160int perf_event__synthesize_event_type(u64 event_id, char *name, 2092int perf_event__synthesize_event_type(struct perf_tool *tool,
2093 u64 event_id, char *name,
2161 perf_event__handler_t process, 2094 perf_event__handler_t process,
2162 struct perf_session *session) 2095 struct machine *machine)
2163{ 2096{
2164 union perf_event ev; 2097 union perf_event ev;
2165 size_t size = 0; 2098 size_t size = 0;
@@ -2177,13 +2110,14 @@ int perf_event__synthesize_event_type(u64 event_id, char *name,
2177 ev.event_type.header.size = sizeof(ev.event_type) - 2110 ev.event_type.header.size = sizeof(ev.event_type) -
2178 (sizeof(ev.event_type.event_type.name) - size); 2111 (sizeof(ev.event_type.event_type.name) - size);
2179 2112
2180 err = process(&ev, NULL, session); 2113 err = process(tool, &ev, NULL, machine);
2181 2114
2182 return err; 2115 return err;
2183} 2116}
2184 2117
2185int perf_event__synthesize_event_types(perf_event__handler_t process, 2118int perf_event__synthesize_event_types(struct perf_tool *tool,
2186 struct perf_session *session) 2119 perf_event__handler_t process,
2120 struct machine *machine)
2187{ 2121{
2188 struct perf_trace_event_type *type; 2122 struct perf_trace_event_type *type;
2189 int i, err = 0; 2123 int i, err = 0;
@@ -2191,9 +2125,9 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2191 for (i = 0; i < event_count; i++) { 2125 for (i = 0; i < event_count; i++) {
2192 type = &events[i]; 2126 type = &events[i];
2193 2127
2194 err = perf_event__synthesize_event_type(type->event_id, 2128 err = perf_event__synthesize_event_type(tool, type->event_id,
2195 type->name, process, 2129 type->name, process,
2196 session); 2130 machine);
2197 if (err) { 2131 if (err) {
2198 pr_debug("failed to create perf header event type\n"); 2132 pr_debug("failed to create perf header event type\n");
2199 return err; 2133 return err;
@@ -2203,8 +2137,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process,
2203 return err; 2137 return err;
2204} 2138}
2205 2139
2206int perf_event__process_event_type(union perf_event *event, 2140int perf_event__process_event_type(struct perf_tool *tool __unused,
2207 struct perf_session *session __unused) 2141 union perf_event *event)
2208{ 2142{
2209 if (perf_header__push_event(event->event_type.event_type.event_id, 2143 if (perf_header__push_event(event->event_type.event_type.event_id,
2210 event->event_type.event_type.name) < 0) 2144 event->event_type.event_type.name) < 0)
@@ -2213,9 +2147,9 @@ int perf_event__process_event_type(union perf_event *event,
2213 return 0; 2147 return 0;
2214} 2148}
2215 2149
2216int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 2150int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
2217 perf_event__handler_t process, 2151 struct perf_evlist *evlist,
2218 struct perf_session *session __unused) 2152 perf_event__handler_t process)
2219{ 2153{
2220 union perf_event ev; 2154 union perf_event ev;
2221 struct tracing_data *tdata; 2155 struct tracing_data *tdata;
@@ -2246,7 +2180,7 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
2246 ev.tracing_data.header.size = sizeof(ev.tracing_data); 2180 ev.tracing_data.header.size = sizeof(ev.tracing_data);
2247 ev.tracing_data.size = aligned_size; 2181 ev.tracing_data.size = aligned_size;
2248 2182
2249 process(&ev, NULL, session); 2183 process(tool, &ev, NULL, NULL);
2250 2184
2251 /* 2185 /*
2252 * The put function will copy all the tracing data 2186 * The put function will copy all the tracing data
@@ -2288,10 +2222,10 @@ int perf_event__process_tracing_data(union perf_event *event,
2288 return size_read + padding; 2222 return size_read + padding;
2289} 2223}
2290 2224
2291int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 2225int perf_event__synthesize_build_id(struct perf_tool *tool,
2226 struct dso *pos, u16 misc,
2292 perf_event__handler_t process, 2227 perf_event__handler_t process,
2293 struct machine *machine, 2228 struct machine *machine)
2294 struct perf_session *session)
2295{ 2229{
2296 union perf_event ev; 2230 union perf_event ev;
2297 size_t len; 2231 size_t len;
@@ -2311,12 +2245,13 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
2311 ev.build_id.header.size = sizeof(ev.build_id) + len; 2245 ev.build_id.header.size = sizeof(ev.build_id) + len;
2312 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); 2246 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
2313 2247
2314 err = process(&ev, NULL, session); 2248 err = process(tool, &ev, NULL, machine);
2315 2249
2316 return err; 2250 return err;
2317} 2251}
2318 2252
2319int perf_event__process_build_id(union perf_event *event, 2253int perf_event__process_build_id(struct perf_tool *tool __used,
2254 union perf_event *event,
2320 struct perf_session *session) 2255 struct perf_session *session)
2321{ 2256{
2322 __event_process_build_id(&event->build_id, 2257 __event_process_build_id(&event->build_id,
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3d5a742f4a2a..ac4ec956024e 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -10,7 +10,8 @@
10#include <linux/bitmap.h> 10#include <linux/bitmap.h>
11 11
12enum { 12enum {
13 HEADER_TRACE_INFO = 1, 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_TRACE_INFO = 1,
14 HEADER_BUILD_ID, 15 HEADER_BUILD_ID,
15 16
16 HEADER_HOSTNAME, 17 HEADER_HOSTNAME,
@@ -27,10 +28,9 @@ enum {
27 HEADER_NUMA_TOPOLOGY, 28 HEADER_NUMA_TOPOLOGY,
28 29
29 HEADER_LAST_FEATURE, 30 HEADER_LAST_FEATURE,
31 HEADER_FEAT_BITS = 256,
30}; 32};
31 33
32#define HEADER_FEAT_BITS 256
33
34struct perf_file_section { 34struct perf_file_section {
35 u64 offset; 35 u64 offset;
36 u64 size; 36 u64 size;
@@ -68,6 +68,7 @@ struct perf_header {
68}; 68};
69 69
70struct perf_evlist; 70struct perf_evlist;
71struct perf_session;
71 72
72int perf_session__read_header(struct perf_session *session, int fd); 73int perf_session__read_header(struct perf_session *session, int fd);
73int perf_session__write_header(struct perf_session *session, 74int perf_session__write_header(struct perf_session *session,
@@ -96,32 +97,36 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
96 const char *name, bool is_kallsyms); 97 const char *name, bool is_kallsyms);
97int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); 98int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
98 99
99int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 100int perf_event__synthesize_attr(struct perf_tool *tool,
100 perf_event__handler_t process, 101 struct perf_event_attr *attr, u16 ids, u64 *id,
101 struct perf_session *session); 102 perf_event__handler_t process);
102int perf_session__synthesize_attrs(struct perf_session *session, 103int perf_event__synthesize_attrs(struct perf_tool *tool,
103 perf_event__handler_t process); 104 struct perf_session *session,
104int perf_event__process_attr(union perf_event *event, struct perf_session *session); 105 perf_event__handler_t process);
106int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
105 107
106int perf_event__synthesize_event_type(u64 event_id, char *name, 108int perf_event__synthesize_event_type(struct perf_tool *tool,
109 u64 event_id, char *name,
107 perf_event__handler_t process, 110 perf_event__handler_t process,
108 struct perf_session *session); 111 struct machine *machine);
109int perf_event__synthesize_event_types(perf_event__handler_t process, 112int perf_event__synthesize_event_types(struct perf_tool *tool,
110 struct perf_session *session); 113 perf_event__handler_t process,
111int perf_event__process_event_type(union perf_event *event, 114 struct machine *machine);
112 struct perf_session *session); 115int perf_event__process_event_type(struct perf_tool *tool,
113 116 union perf_event *event);
114int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, 117
115 perf_event__handler_t process, 118int perf_event__synthesize_tracing_data(struct perf_tool *tool,
116 struct perf_session *session); 119 int fd, struct perf_evlist *evlist,
120 perf_event__handler_t process);
117int perf_event__process_tracing_data(union perf_event *event, 121int perf_event__process_tracing_data(union perf_event *event,
118 struct perf_session *session); 122 struct perf_session *session);
119 123
120int perf_event__synthesize_build_id(struct dso *pos, u16 misc, 124int perf_event__synthesize_build_id(struct perf_tool *tool,
125 struct dso *pos, u16 misc,
121 perf_event__handler_t process, 126 perf_event__handler_t process,
122 struct machine *machine, 127 struct machine *machine);
123 struct perf_session *session); 128int perf_event__process_build_id(struct perf_tool *tool,
124int perf_event__process_build_id(union perf_event *event, 129 union perf_event *event,
125 struct perf_session *session); 130 struct perf_session *session);
126 131
127/* 132/*
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 89289c8e935e..ff6f9d56ea41 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -117,7 +117,6 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used,
117 117
118static inline int hist_entry__tui_annotate(struct hist_entry *self __used, 118static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
119 int evidx __used, 119 int evidx __used,
120 int nr_events __used,
121 void(*timer)(void *arg) __used, 120 void(*timer)(void *arg) __used,
122 void *arg __used, 121 void *arg __used,
123 int delay_secs __used) 122 int delay_secs __used)
@@ -128,7 +127,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
128#define K_RIGHT -2 127#define K_RIGHT -2
129#else 128#else
130#include "ui/keysyms.h" 129#include "ui/keysyms.h"
131int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, 130int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
132 void(*timer)(void *arg), void *arg, int delay_secs); 131 void(*timer)(void *arg), void *arg, int delay_secs);
133 132
134int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 133int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 305c8484f200..62cdee78db7b 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -9,6 +9,17 @@
9#define BITS_PER_BYTE 8 9#define BITS_PER_BYTE 8
10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
11 11
12#define for_each_set_bit(bit, addr, size) \
13 for ((bit) = find_first_bit((addr), (size)); \
14 (bit) < (size); \
15 (bit) = find_next_bit((addr), (size), (bit) + 1))
16
17/* same as for_each_set_bit() but use bit as value to start with */
18#define for_each_set_bit_cont(bit, addr, size) \
19 for ((bit) = find_next_bit((addr), (size), (bit)); \
20 (bit) < (size); \
21 (bit) = find_next_bit((addr), (size), (bit) + 1))
22
12static inline void set_bit(int nr, unsigned long *addr) 23static inline void set_bit(int nr, unsigned long *addr)
13{ 24{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); 25 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
@@ -30,4 +41,111 @@ static inline unsigned long hweight_long(unsigned long w)
30 return sizeof(w) == 4 ? hweight32(w) : hweight64(w); 41 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
31} 42}
32 43
44#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
45
46/**
47 * __ffs - find first bit in word.
48 * @word: The word to search
49 *
50 * Undefined if no bit exists, so code should check against 0 first.
51 */
52static __always_inline unsigned long __ffs(unsigned long word)
53{
54 int num = 0;
55
56#if BITS_PER_LONG == 64
57 if ((word & 0xffffffff) == 0) {
58 num += 32;
59 word >>= 32;
60 }
61#endif
62 if ((word & 0xffff) == 0) {
63 num += 16;
64 word >>= 16;
65 }
66 if ((word & 0xff) == 0) {
67 num += 8;
68 word >>= 8;
69 }
70 if ((word & 0xf) == 0) {
71 num += 4;
72 word >>= 4;
73 }
74 if ((word & 0x3) == 0) {
75 num += 2;
76 word >>= 2;
77 }
78 if ((word & 0x1) == 0)
79 num += 1;
80 return num;
81}
82
83/*
84 * Find the first set bit in a memory region.
85 */
86static inline unsigned long
87find_first_bit(const unsigned long *addr, unsigned long size)
88{
89 const unsigned long *p = addr;
90 unsigned long result = 0;
91 unsigned long tmp;
92
93 while (size & ~(BITS_PER_LONG-1)) {
94 if ((tmp = *(p++)))
95 goto found;
96 result += BITS_PER_LONG;
97 size -= BITS_PER_LONG;
98 }
99 if (!size)
100 return result;
101
102 tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
103 if (tmp == 0UL) /* Are any bits set? */
104 return result + size; /* Nope. */
105found:
106 return result + __ffs(tmp);
107}
108
109/*
110 * Find the next set bit in a memory region.
111 */
112static inline unsigned long
113find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
114{
115 const unsigned long *p = addr + BITOP_WORD(offset);
116 unsigned long result = offset & ~(BITS_PER_LONG-1);
117 unsigned long tmp;
118
119 if (offset >= size)
120 return size;
121 size -= result;
122 offset %= BITS_PER_LONG;
123 if (offset) {
124 tmp = *(p++);
125 tmp &= (~0UL << offset);
126 if (size < BITS_PER_LONG)
127 goto found_first;
128 if (tmp)
129 goto found_middle;
130 size -= BITS_PER_LONG;
131 result += BITS_PER_LONG;
132 }
133 while (size & ~(BITS_PER_LONG-1)) {
134 if ((tmp = *(p++)))
135 goto found_middle;
136 result += BITS_PER_LONG;
137 size -= BITS_PER_LONG;
138 }
139 if (!size)
140 return result;
141 tmp = *p;
142
143found_first:
144 tmp &= (~0UL >> (BITS_PER_LONG - size));
145 if (tmp == 0UL) /* Are any bits set? */
146 return result + size; /* Nope. */
147found_middle:
148 return result + __ffs(tmp);
149}
150
33#endif 151#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 78284b13e808..316aa0ab7122 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -562,6 +562,10 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
562 INIT_LIST_HEAD(&self->user_dsos); 562 INIT_LIST_HEAD(&self->user_dsos);
563 INIT_LIST_HEAD(&self->kernel_dsos); 563 INIT_LIST_HEAD(&self->kernel_dsos);
564 564
565 self->threads = RB_ROOT;
566 INIT_LIST_HEAD(&self->dead_threads);
567 self->last_match = NULL;
568
565 self->kmaps.machine = self; 569 self->kmaps.machine = self;
566 self->pid = pid; 570 self->pid = pid;
567 self->root_dir = strdup(root_dir); 571 self->root_dir = strdup(root_dir);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 890d85545d0f..2b8017f8a930 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -18,9 +18,11 @@ enum map_type {
18extern const char *map_type__name[MAP__NR_TYPES]; 18extern const char *map_type__name[MAP__NR_TYPES];
19 19
20struct dso; 20struct dso;
21struct ip_callchain;
21struct ref_reloc_sym; 22struct ref_reloc_sym;
22struct map_groups; 23struct map_groups;
23struct machine; 24struct machine;
25struct perf_evsel;
24 26
25struct map { 27struct map {
26 union { 28 union {
@@ -61,7 +63,11 @@ struct map_groups {
61struct machine { 63struct machine {
62 struct rb_node rb_node; 64 struct rb_node rb_node;
63 pid_t pid; 65 pid_t pid;
66 u16 id_hdr_size;
64 char *root_dir; 67 char *root_dir;
68 struct rb_root threads;
69 struct list_head dead_threads;
70 struct thread *last_match;
65 struct list_head user_dsos; 71 struct list_head user_dsos;
66 struct list_head kernel_dsos; 72 struct list_head kernel_dsos;
67 struct map_groups kmaps; 73 struct map_groups kmaps;
@@ -148,6 +154,13 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid);
148void machine__exit(struct machine *self); 154void machine__exit(struct machine *self);
149void machine__delete(struct machine *self); 155void machine__delete(struct machine *self);
150 156
157int machine__resolve_callchain(struct machine *machine,
158 struct perf_evsel *evsel, struct thread *thread,
159 struct ip_callchain *chain,
160 struct symbol **parent);
161int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
162 u64 addr);
163
151/* 164/*
152 * Default guest kernel is defined by parameter --guestkallsyms 165 * Default guest kernel is defined by parameter --guestkallsyms
153 * and --guestmodules 166 * and --guestmodules
@@ -190,6 +203,12 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
190 struct map **mapp, 203 struct map **mapp,
191 symbol_filter_t filter); 204 symbol_filter_t filter);
192 205
206
207struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
208void machine__remove_thread(struct machine *machine, struct thread *th);
209
210size_t machine__fprintf(struct machine *machine, FILE *fp);
211
193static inline 212static inline
194struct symbol *machine__find_kernel_symbol(struct machine *self, 213struct symbol *machine__find_kernel_symbol(struct machine *self,
195 enum map_type type, u64 addr, 214 enum map_type type, u64 addr,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 928918b796b2..531c283fc0c5 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -25,8 +25,6 @@ enum event_result {
25 EVT_HANDLED_ALL 25 EVT_HANDLED_ALL
26}; 26};
27 27
28char debugfs_path[MAXPATHLEN];
29
30#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 28#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
31#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 29#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
32 30
@@ -40,6 +38,7 @@ static struct event_symbol event_symbols[] = {
40 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, 38 { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
41 { CHW(BRANCH_MISSES), "branch-misses", "" }, 39 { CHW(BRANCH_MISSES), "branch-misses", "" },
42 { CHW(BUS_CYCLES), "bus-cycles", "" }, 40 { CHW(BUS_CYCLES), "bus-cycles", "" },
41 { CHW(REF_CPU_CYCLES), "ref-cycles", "" },
43 42
44 { CSW(CPU_CLOCK), "cpu-clock", "" }, 43 { CSW(CPU_CLOCK), "cpu-clock", "" },
45 { CSW(TASK_CLOCK), "task-clock", "" }, 44 { CSW(TASK_CLOCK), "task-clock", "" },
@@ -70,6 +69,7 @@ static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
70 "bus-cycles", 69 "bus-cycles",
71 "stalled-cycles-frontend", 70 "stalled-cycles-frontend",
72 "stalled-cycles-backend", 71 "stalled-cycles-backend",
72 "ref-cycles",
73}; 73};
74 74
75static const char *sw_event_names[PERF_COUNT_SW_MAX] = { 75static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
@@ -140,7 +140,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
140 char evt_path[MAXPATHLEN]; 140 char evt_path[MAXPATHLEN];
141 int fd; 141 int fd;
142 142
143 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 143 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
144 sys_dir->d_name, evt_dir->d_name); 144 sys_dir->d_name, evt_dir->d_name);
145 fd = open(evt_path, O_RDONLY); 145 fd = open(evt_path, O_RDONLY);
146 if (fd < 0) 146 if (fd < 0)
@@ -171,16 +171,16 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
171 char evt_path[MAXPATHLEN]; 171 char evt_path[MAXPATHLEN];
172 char dir_path[MAXPATHLEN]; 172 char dir_path[MAXPATHLEN];
173 173
174 if (debugfs_valid_mountpoint(debugfs_path)) 174 if (debugfs_valid_mountpoint(tracing_events_path))
175 return NULL; 175 return NULL;
176 176
177 sys_dir = opendir(debugfs_path); 177 sys_dir = opendir(tracing_events_path);
178 if (!sys_dir) 178 if (!sys_dir)
179 return NULL; 179 return NULL;
180 180
181 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 181 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
182 182
183 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 183 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
184 sys_dirent.d_name); 184 sys_dirent.d_name);
185 evt_dir = opendir(dir_path); 185 evt_dir = opendir(dir_path);
186 if (!evt_dir) 186 if (!evt_dir)
@@ -447,7 +447,7 @@ parse_single_tracepoint_event(char *sys_name,
447 u64 id; 447 u64 id;
448 int fd; 448 int fd;
449 449
450 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 450 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
451 sys_name, evt_name); 451 sys_name, evt_name);
452 452
453 fd = open(evt_path, O_RDONLY); 453 fd = open(evt_path, O_RDONLY);
@@ -485,7 +485,7 @@ parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name,
485 struct dirent *evt_ent; 485 struct dirent *evt_ent;
486 DIR *evt_dir; 486 DIR *evt_dir;
487 487
488 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); 488 snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name);
489 evt_dir = opendir(evt_path); 489 evt_dir = opendir(evt_path);
490 490
491 if (!evt_dir) { 491 if (!evt_dir) {
@@ -528,7 +528,7 @@ parse_tracepoint_event(struct perf_evlist *evlist, const char **strp,
528 char sys_name[MAX_EVENT_LENGTH]; 528 char sys_name[MAX_EVENT_LENGTH];
529 unsigned int sys_length, evt_length; 529 unsigned int sys_length, evt_length;
530 530
531 if (debugfs_valid_mountpoint(debugfs_path)) 531 if (debugfs_valid_mountpoint(tracing_events_path))
532 return 0; 532 return 0;
533 533
534 evt_name = strchr(*strp, ':'); 534 evt_name = strchr(*strp, ':');
@@ -920,10 +920,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
920 char evt_path[MAXPATHLEN]; 920 char evt_path[MAXPATHLEN];
921 char dir_path[MAXPATHLEN]; 921 char dir_path[MAXPATHLEN];
922 922
923 if (debugfs_valid_mountpoint(debugfs_path)) 923 if (debugfs_valid_mountpoint(tracing_events_path))
924 return; 924 return;
925 925
926 sys_dir = opendir(debugfs_path); 926 sys_dir = opendir(tracing_events_path);
927 if (!sys_dir) 927 if (!sys_dir)
928 return; 928 return;
929 929
@@ -932,7 +932,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
932 !strglobmatch(sys_dirent.d_name, subsys_glob)) 932 !strglobmatch(sys_dirent.d_name, subsys_glob))
933 continue; 933 continue;
934 934
935 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 935 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
936 sys_dirent.d_name); 936 sys_dirent.d_name);
937 evt_dir = opendir(dir_path); 937 evt_dir = opendir(dir_path);
938 if (!evt_dir) 938 if (!evt_dir)
@@ -964,16 +964,16 @@ int is_valid_tracepoint(const char *event_string)
964 char evt_path[MAXPATHLEN]; 964 char evt_path[MAXPATHLEN];
965 char dir_path[MAXPATHLEN]; 965 char dir_path[MAXPATHLEN];
966 966
967 if (debugfs_valid_mountpoint(debugfs_path)) 967 if (debugfs_valid_mountpoint(tracing_events_path))
968 return 0; 968 return 0;
969 969
970 sys_dir = opendir(debugfs_path); 970 sys_dir = opendir(tracing_events_path);
971 if (!sys_dir) 971 if (!sys_dir)
972 return 0; 972 return 0;
973 973
974 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 974 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
975 975
976 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, 976 snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path,
977 sys_dirent.d_name); 977 sys_dirent.d_name);
978 evt_dir = opendir(dir_path); 978 evt_dir = opendir(dir_path);
979 if (!evt_dir) 979 if (!evt_dir)
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2f8e375e038d..7e0cbe75d5f1 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -39,7 +39,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
39int print_hwcache_events(const char *event_glob); 39int print_hwcache_events(const char *event_glob);
40extern int is_valid_tracepoint(const char *event_string); 40extern int is_valid_tracepoint(const char *event_string);
41 41
42extern char debugfs_path[];
43extern int valid_debugfs_mount(const char *debugfs); 42extern int valid_debugfs_mount(const char *debugfs);
44 43
45#endif /* __PERF_PARSE_EVENTS_H */ 44#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 1132c8f0ce89..17e94d0c36f9 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -5,7 +5,6 @@
5#include "util.h" 5#include "util.h"
6#include "probe-event.h" 6#include "probe-event.h"
7 7
8#define MAX_PATH_LEN 256
9#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
10#define MAX_PROBES 128 9#define MAX_PROBES 128
11 10
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 74350ffb57fe..e30749e38a9b 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -27,7 +27,10 @@
27 27
28#include "../../perf.h" 28#include "../../perf.h"
29#include "../util.h" 29#include "../util.h"
30#include "../thread.h"
31#include "../event.h"
30#include "../trace-event.h" 32#include "../trace-event.h"
33#include "../evsel.h"
31 34
32#include <EXTERN.h> 35#include <EXTERN.h>
33#include <perl.h> 36#include <perl.h>
@@ -245,11 +248,11 @@ static inline struct event *find_cache_event(int type)
245 return event; 248 return event;
246} 249}
247 250
248static void perl_process_event(union perf_event *pevent __unused, 251static void perl_process_tracepoint(union perf_event *pevent __unused,
249 struct perf_sample *sample, 252 struct perf_sample *sample,
250 struct perf_evsel *evsel, 253 struct perf_evsel *evsel,
251 struct perf_session *session __unused, 254 struct machine *machine __unused,
252 struct thread *thread) 255 struct thread *thread)
253{ 256{
254 struct format_field *field; 257 struct format_field *field;
255 static char handler[256]; 258 static char handler[256];
@@ -265,6 +268,9 @@ static void perl_process_event(union perf_event *pevent __unused,
265 268
266 dSP; 269 dSP;
267 270
271 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
272 return;
273
268 type = trace_parse_common_type(data); 274 type = trace_parse_common_type(data);
269 275
270 event = find_cache_event(type); 276 event = find_cache_event(type);
@@ -332,6 +338,42 @@ static void perl_process_event(union perf_event *pevent __unused,
332 LEAVE; 338 LEAVE;
333} 339}
334 340
341static void perl_process_event_generic(union perf_event *pevent __unused,
342 struct perf_sample *sample,
343 struct perf_evsel *evsel __unused,
344 struct machine *machine __unused,
345 struct thread *thread __unused)
346{
347 dSP;
348
349 if (!get_cv("process_event", 0))
350 return;
351
352 ENTER;
353 SAVETMPS;
354 PUSHMARK(SP);
355 XPUSHs(sv_2mortal(newSVpvn((const char *)pevent, pevent->header.size)));
356 XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr))));
357 XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample))));
358 XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size)));
359 PUTBACK;
360 call_pv("process_event", G_SCALAR);
361 SPAGAIN;
362 PUTBACK;
363 FREETMPS;
364 LEAVE;
365}
366
367static void perl_process_event(union perf_event *pevent,
368 struct perf_sample *sample,
369 struct perf_evsel *evsel,
370 struct machine *machine,
371 struct thread *thread)
372{
373 perl_process_tracepoint(pevent, sample, evsel, machine, thread);
374 perl_process_event_generic(pevent, sample, evsel, machine, thread);
375}
376
335static void run_start_sub(void) 377static void run_start_sub(void)
336{ 378{
337 dSP; /* access to Perl stack */ 379 dSP; /* access to Perl stack */
@@ -553,7 +595,28 @@ static int perl_generate_script(const char *outfile)
553 fprintf(ofp, "sub print_header\n{\n" 595 fprintf(ofp, "sub print_header\n{\n"
554 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" 596 "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
555 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t " 597 "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t "
556 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}"); 598 "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n");
599
600 fprintf(ofp,
601 "\n# Packed byte string args of process_event():\n"
602 "#\n"
603 "# $event:\tunion perf_event\tutil/event.h\n"
604 "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n"
605 "# $sample:\tstruct perf_sample\tutil/event.h\n"
606 "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n"
607 "\n"
608 "sub process_event\n"
609 "{\n"
610 "\tmy ($event, $attr, $sample, $raw_data) = @_;\n"
611 "\n"
612 "\tmy @event\t= unpack(\"LSS\", $event);\n"
613 "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n"
614 "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n"
615 "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n"
616 "\n"
617 "\tuse Data::Dumper;\n"
618 "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n"
619 "}\n");
557 620
558 fclose(ofp); 621 fclose(ofp);
559 622
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 6ccf70e8d8f2..0b2a48783172 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -29,6 +29,8 @@
29 29
30#include "../../perf.h" 30#include "../../perf.h"
31#include "../util.h" 31#include "../util.h"
32#include "../event.h"
33#include "../thread.h"
32#include "../trace-event.h" 34#include "../trace-event.h"
33 35
34PyMODINIT_FUNC initperf_trace_context(void); 36PyMODINIT_FUNC initperf_trace_context(void);
@@ -207,7 +209,7 @@ static inline struct event *find_cache_event(int type)
207static void python_process_event(union perf_event *pevent __unused, 209static void python_process_event(union perf_event *pevent __unused,
208 struct perf_sample *sample, 210 struct perf_sample *sample,
209 struct perf_evsel *evsel __unused, 211 struct perf_evsel *evsel __unused,
210 struct perf_session *session __unused, 212 struct machine *machine __unused,
211 struct thread *thread) 213 struct thread *thread)
212{ 214{
213 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 215 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 0f4555ce9063..b5ca2558c7bb 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -10,6 +10,7 @@
10#include "evlist.h" 10#include "evlist.h"
11#include "evsel.h" 11#include "evsel.h"
12#include "session.h" 12#include "session.h"
13#include "tool.h"
13#include "sort.h" 14#include "sort.h"
14#include "util.h" 15#include "util.h"
15#include "cpumap.h" 16#include "cpumap.h"
@@ -78,39 +79,13 @@ out_close:
78 return -1; 79 return -1;
79} 80}
80 81
81static void perf_session__id_header_size(struct perf_session *session)
82{
83 struct perf_sample *data;
84 u64 sample_type = session->sample_type;
85 u16 size = 0;
86
87 if (!session->sample_id_all)
88 goto out;
89
90 if (sample_type & PERF_SAMPLE_TID)
91 size += sizeof(data->tid) * 2;
92
93 if (sample_type & PERF_SAMPLE_TIME)
94 size += sizeof(data->time);
95
96 if (sample_type & PERF_SAMPLE_ID)
97 size += sizeof(data->id);
98
99 if (sample_type & PERF_SAMPLE_STREAM_ID)
100 size += sizeof(data->stream_id);
101
102 if (sample_type & PERF_SAMPLE_CPU)
103 size += sizeof(data->cpu) * 2;
104out:
105 session->id_hdr_size = size;
106}
107
108void perf_session__update_sample_type(struct perf_session *self) 82void perf_session__update_sample_type(struct perf_session *self)
109{ 83{
110 self->sample_type = perf_evlist__sample_type(self->evlist); 84 self->sample_type = perf_evlist__sample_type(self->evlist);
111 self->sample_size = __perf_evsel__sample_size(self->sample_type); 85 self->sample_size = __perf_evsel__sample_size(self->sample_type);
112 self->sample_id_all = perf_evlist__sample_id_all(self->evlist); 86 self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
113 perf_session__id_header_size(self); 87 self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
88 self->host_machine.id_hdr_size = self->id_hdr_size;
114} 89}
115 90
116int perf_session__create_kernel_maps(struct perf_session *self) 91int perf_session__create_kernel_maps(struct perf_session *self)
@@ -130,18 +105,26 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
130 105
131struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
132 bool force, bool repipe, 107 bool force, bool repipe,
133 struct perf_event_ops *ops) 108 struct perf_tool *tool)
134{ 109{
135 size_t len = filename ? strlen(filename) + 1 : 0; 110 struct perf_session *self;
136 struct perf_session *self = zalloc(sizeof(*self) + len); 111 struct stat st;
112 size_t len;
113
114 if (!filename || !strlen(filename)) {
115 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
116 filename = "-";
117 else
118 filename = "perf.data";
119 }
120
121 len = strlen(filename);
122 self = zalloc(sizeof(*self) + len);
137 123
138 if (self == NULL) 124 if (self == NULL)
139 goto out; 125 goto out;
140 126
141 memcpy(self->filename, filename, len); 127 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads);
144 self->last_match = NULL;
145 /* 128 /*
146 * On 64bit we can mmap the data file in one go. No need for tiny mmap 129 * On 64bit we can mmap the data file in one go. No need for tiny mmap
147 * slices. On 32bit we use 32MB. 130 * slices. On 32bit we use 32MB.
@@ -171,10 +154,10 @@ struct perf_session *perf_session__new(const char *filename, int mode,
171 goto out_delete; 154 goto out_delete;
172 } 155 }
173 156
174 if (ops && ops->ordering_requires_timestamps && 157 if (tool && tool->ordering_requires_timestamps &&
175 ops->ordered_samples && !self->sample_id_all) { 158 tool->ordered_samples && !self->sample_id_all) {
176 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 159 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
177 ops->ordered_samples = false; 160 tool->ordered_samples = false;
178 } 161 }
179 162
180out: 163out:
@@ -184,17 +167,22 @@ out_delete:
184 return NULL; 167 return NULL;
185} 168}
186 169
187static void perf_session__delete_dead_threads(struct perf_session *self) 170static void machine__delete_dead_threads(struct machine *machine)
188{ 171{
189 struct thread *n, *t; 172 struct thread *n, *t;
190 173
191 list_for_each_entry_safe(t, n, &self->dead_threads, node) { 174 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
192 list_del(&t->node); 175 list_del(&t->node);
193 thread__delete(t); 176 thread__delete(t);
194 } 177 }
195} 178}
196 179
197static void perf_session__delete_threads(struct perf_session *self) 180static void perf_session__delete_dead_threads(struct perf_session *session)
181{
182 machine__delete_dead_threads(&session->host_machine);
183}
184
185static void machine__delete_threads(struct machine *self)
198{ 186{
199 struct rb_node *nd = rb_first(&self->threads); 187 struct rb_node *nd = rb_first(&self->threads);
200 188
@@ -207,6 +195,11 @@ static void perf_session__delete_threads(struct perf_session *self)
207 } 195 }
208} 196}
209 197
198static void perf_session__delete_threads(struct perf_session *session)
199{
200 machine__delete_threads(&session->host_machine);
201}
202
210void perf_session__delete(struct perf_session *self) 203void perf_session__delete(struct perf_session *self)
211{ 204{
212 perf_session__destroy_kernel_maps(self); 205 perf_session__destroy_kernel_maps(self);
@@ -217,7 +210,7 @@ void perf_session__delete(struct perf_session *self)
217 free(self); 210 free(self);
218} 211}
219 212
220void perf_session__remove_thread(struct perf_session *self, struct thread *th) 213void machine__remove_thread(struct machine *self, struct thread *th)
221{ 214{
222 self->last_match = NULL; 215 self->last_match = NULL;
223 rb_erase(&th->rb_node, &self->threads); 216 rb_erase(&th->rb_node, &self->threads);
@@ -236,16 +229,16 @@ static bool symbol__match_parent_regex(struct symbol *sym)
236 return 0; 229 return 0;
237} 230}
238 231
239int perf_session__resolve_callchain(struct perf_session *self, 232int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
240 struct thread *thread, 233 struct thread *thread,
241 struct ip_callchain *chain, 234 struct ip_callchain *chain,
242 struct symbol **parent) 235 struct symbol **parent)
243{ 236{
244 u8 cpumode = PERF_RECORD_MISC_USER; 237 u8 cpumode = PERF_RECORD_MISC_USER;
245 unsigned int i; 238 unsigned int i;
246 int err; 239 int err;
247 240
248 callchain_cursor_reset(&self->callchain_cursor); 241 callchain_cursor_reset(&evsel->hists.callchain_cursor);
249 242
250 for (i = 0; i < chain->nr; i++) { 243 for (i = 0; i < chain->nr; i++) {
251 u64 ip; 244 u64 ip;
@@ -272,7 +265,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
272 265
273 al.filtered = false; 266 al.filtered = false;
274 thread__find_addr_location(thread, self, cpumode, 267 thread__find_addr_location(thread, self, cpumode,
275 MAP__FUNCTION, thread->pid, ip, &al, NULL); 268 MAP__FUNCTION, ip, &al, NULL);
276 if (al.sym != NULL) { 269 if (al.sym != NULL) {
277 if (sort__has_parent && !*parent && 270 if (sort__has_parent && !*parent &&
278 symbol__match_parent_regex(al.sym)) 271 symbol__match_parent_regex(al.sym))
@@ -281,7 +274,7 @@ int perf_session__resolve_callchain(struct perf_session *self,
281 break; 274 break;
282 } 275 }
283 276
284 err = callchain_cursor_append(&self->callchain_cursor, 277 err = callchain_cursor_append(&evsel->hists.callchain_cursor,
285 ip, al.map, al.sym); 278 ip, al.map, al.sym);
286 if (err) 279 if (err)
287 return err; 280 return err;
@@ -290,75 +283,91 @@ int perf_session__resolve_callchain(struct perf_session *self,
290 return 0; 283 return 0;
291} 284}
292 285
293static int process_event_synth_stub(union perf_event *event __used, 286static int process_event_synth_tracing_data_stub(union perf_event *event __used,
294 struct perf_session *session __used) 287 struct perf_session *session __used)
288{
289 dump_printf(": unhandled!\n");
290 return 0;
291}
292
293static int process_event_synth_attr_stub(union perf_event *event __used,
294 struct perf_evlist **pevlist __used)
295{ 295{
296 dump_printf(": unhandled!\n"); 296 dump_printf(": unhandled!\n");
297 return 0; 297 return 0;
298} 298}
299 299
300static int process_event_sample_stub(union perf_event *event __used, 300static int process_event_sample_stub(struct perf_tool *tool __used,
301 union perf_event *event __used,
301 struct perf_sample *sample __used, 302 struct perf_sample *sample __used,
302 struct perf_evsel *evsel __used, 303 struct perf_evsel *evsel __used,
303 struct perf_session *session __used) 304 struct machine *machine __used)
304{ 305{
305 dump_printf(": unhandled!\n"); 306 dump_printf(": unhandled!\n");
306 return 0; 307 return 0;
307} 308}
308 309
309static int process_event_stub(union perf_event *event __used, 310static int process_event_stub(struct perf_tool *tool __used,
311 union perf_event *event __used,
310 struct perf_sample *sample __used, 312 struct perf_sample *sample __used,
311 struct perf_session *session __used) 313 struct machine *machine __used)
312{ 314{
313 dump_printf(": unhandled!\n"); 315 dump_printf(": unhandled!\n");
314 return 0; 316 return 0;
315} 317}
316 318
317static int process_finished_round_stub(union perf_event *event __used, 319static int process_finished_round_stub(struct perf_tool *tool __used,
318 struct perf_session *session __used, 320 union perf_event *event __used,
319 struct perf_event_ops *ops __used) 321 struct perf_session *perf_session __used)
320{ 322{
321 dump_printf(": unhandled!\n"); 323 dump_printf(": unhandled!\n");
322 return 0; 324 return 0;
323} 325}
324 326
325static int process_finished_round(union perf_event *event, 327static int process_event_type_stub(struct perf_tool *tool __used,
326 struct perf_session *session, 328 union perf_event *event __used)
327 struct perf_event_ops *ops); 329{
330 dump_printf(": unhandled!\n");
331 return 0;
332}
328 333
329static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 334static int process_finished_round(struct perf_tool *tool,
335 union perf_event *event,
336 struct perf_session *session);
337
338static void perf_tool__fill_defaults(struct perf_tool *tool)
330{ 339{
331 if (handler->sample == NULL) 340 if (tool->sample == NULL)
332 handler->sample = process_event_sample_stub; 341 tool->sample = process_event_sample_stub;
333 if (handler->mmap == NULL) 342 if (tool->mmap == NULL)
334 handler->mmap = process_event_stub; 343 tool->mmap = process_event_stub;
335 if (handler->comm == NULL) 344 if (tool->comm == NULL)
336 handler->comm = process_event_stub; 345 tool->comm = process_event_stub;
337 if (handler->fork == NULL) 346 if (tool->fork == NULL)
338 handler->fork = process_event_stub; 347 tool->fork = process_event_stub;
339 if (handler->exit == NULL) 348 if (tool->exit == NULL)
340 handler->exit = process_event_stub; 349 tool->exit = process_event_stub;
341 if (handler->lost == NULL) 350 if (tool->lost == NULL)
342 handler->lost = perf_event__process_lost; 351 tool->lost = perf_event__process_lost;
343 if (handler->read == NULL) 352 if (tool->read == NULL)
344 handler->read = process_event_stub; 353 tool->read = process_event_sample_stub;
345 if (handler->throttle == NULL) 354 if (tool->throttle == NULL)
346 handler->throttle = process_event_stub; 355 tool->throttle = process_event_stub;
347 if (handler->unthrottle == NULL) 356 if (tool->unthrottle == NULL)
348 handler->unthrottle = process_event_stub; 357 tool->unthrottle = process_event_stub;
349 if (handler->attr == NULL) 358 if (tool->attr == NULL)
350 handler->attr = process_event_synth_stub; 359 tool->attr = process_event_synth_attr_stub;
351 if (handler->event_type == NULL) 360 if (tool->event_type == NULL)
352 handler->event_type = process_event_synth_stub; 361 tool->event_type = process_event_type_stub;
353 if (handler->tracing_data == NULL) 362 if (tool->tracing_data == NULL)
354 handler->tracing_data = process_event_synth_stub; 363 tool->tracing_data = process_event_synth_tracing_data_stub;
355 if (handler->build_id == NULL) 364 if (tool->build_id == NULL)
356 handler->build_id = process_event_synth_stub; 365 tool->build_id = process_finished_round_stub;
357 if (handler->finished_round == NULL) { 366 if (tool->finished_round == NULL) {
358 if (handler->ordered_samples) 367 if (tool->ordered_samples)
359 handler->finished_round = process_finished_round; 368 tool->finished_round = process_finished_round;
360 else 369 else
361 handler->finished_round = process_finished_round_stub; 370 tool->finished_round = process_finished_round_stub;
362 } 371 }
363} 372}
364 373
@@ -490,11 +499,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
490static int perf_session_deliver_event(struct perf_session *session, 499static int perf_session_deliver_event(struct perf_session *session,
491 union perf_event *event, 500 union perf_event *event,
492 struct perf_sample *sample, 501 struct perf_sample *sample,
493 struct perf_event_ops *ops, 502 struct perf_tool *tool,
494 u64 file_offset); 503 u64 file_offset);
495 504
496static void flush_sample_queue(struct perf_session *s, 505static void flush_sample_queue(struct perf_session *s,
497 struct perf_event_ops *ops) 506 struct perf_tool *tool)
498{ 507{
499 struct ordered_samples *os = &s->ordered_samples; 508 struct ordered_samples *os = &s->ordered_samples;
500 struct list_head *head = &os->samples; 509 struct list_head *head = &os->samples;
@@ -505,7 +514,7 @@ static void flush_sample_queue(struct perf_session *s,
505 unsigned idx = 0, progress_next = os->nr_samples / 16; 514 unsigned idx = 0, progress_next = os->nr_samples / 16;
506 int ret; 515 int ret;
507 516
508 if (!ops->ordered_samples || !limit) 517 if (!tool->ordered_samples || !limit)
509 return; 518 return;
510 519
511 list_for_each_entry_safe(iter, tmp, head, list) { 520 list_for_each_entry_safe(iter, tmp, head, list) {
@@ -516,7 +525,7 @@ static void flush_sample_queue(struct perf_session *s,
516 if (ret) 525 if (ret)
517 pr_err("Can't parse sample, err = %d\n", ret); 526 pr_err("Can't parse sample, err = %d\n", ret);
518 else 527 else
519 perf_session_deliver_event(s, iter->event, &sample, ops, 528 perf_session_deliver_event(s, iter->event, &sample, tool,
520 iter->file_offset); 529 iter->file_offset);
521 530
522 os->last_flush = iter->timestamp; 531 os->last_flush = iter->timestamp;
@@ -578,11 +587,11 @@ static void flush_sample_queue(struct perf_session *s,
578 * Flush every events below timestamp 7 587 * Flush every events below timestamp 7
579 * etc... 588 * etc...
580 */ 589 */
581static int process_finished_round(union perf_event *event __used, 590static int process_finished_round(struct perf_tool *tool,
582 struct perf_session *session, 591 union perf_event *event __used,
583 struct perf_event_ops *ops) 592 struct perf_session *session)
584{ 593{
585 flush_sample_queue(session, ops); 594 flush_sample_queue(session, tool);
586 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; 595 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
587 596
588 return 0; 597 return 0;
@@ -737,13 +746,26 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
737 callchain__printf(sample); 746 callchain__printf(sample);
738} 747}
739 748
749static struct machine *
750 perf_session__find_machine_for_cpumode(struct perf_session *session,
751 union perf_event *event)
752{
753 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
754
755 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest)
756 return perf_session__find_machine(session, event->ip.pid);
757
758 return perf_session__find_host_machine(session);
759}
760
740static int perf_session_deliver_event(struct perf_session *session, 761static int perf_session_deliver_event(struct perf_session *session,
741 union perf_event *event, 762 union perf_event *event,
742 struct perf_sample *sample, 763 struct perf_sample *sample,
743 struct perf_event_ops *ops, 764 struct perf_tool *tool,
744 u64 file_offset) 765 u64 file_offset)
745{ 766{
746 struct perf_evsel *evsel; 767 struct perf_evsel *evsel;
768 struct machine *machine;
747 769
748 dump_event(session, event, file_offset, sample); 770 dump_event(session, event, file_offset, sample);
749 771
@@ -765,6 +787,8 @@ static int perf_session_deliver_event(struct perf_session *session,
765 hists__inc_nr_events(&evsel->hists, event->header.type); 787 hists__inc_nr_events(&evsel->hists, event->header.type);
766 } 788 }
767 789
790 machine = perf_session__find_machine_for_cpumode(session, event);
791
768 switch (event->header.type) { 792 switch (event->header.type) {
769 case PERF_RECORD_SAMPLE: 793 case PERF_RECORD_SAMPLE:
770 dump_sample(session, event, sample); 794 dump_sample(session, event, sample);
@@ -772,23 +796,25 @@ static int perf_session_deliver_event(struct perf_session *session,
772 ++session->hists.stats.nr_unknown_id; 796 ++session->hists.stats.nr_unknown_id;
773 return -1; 797 return -1;
774 } 798 }
775 return ops->sample(event, sample, evsel, session); 799 return tool->sample(tool, event, sample, evsel, machine);
776 case PERF_RECORD_MMAP: 800 case PERF_RECORD_MMAP:
777 return ops->mmap(event, sample, session); 801 return tool->mmap(tool, event, sample, machine);
778 case PERF_RECORD_COMM: 802 case PERF_RECORD_COMM:
779 return ops->comm(event, sample, session); 803 return tool->comm(tool, event, sample, machine);
780 case PERF_RECORD_FORK: 804 case PERF_RECORD_FORK:
781 return ops->fork(event, sample, session); 805 return tool->fork(tool, event, sample, machine);
782 case PERF_RECORD_EXIT: 806 case PERF_RECORD_EXIT:
783 return ops->exit(event, sample, session); 807 return tool->exit(tool, event, sample, machine);
784 case PERF_RECORD_LOST: 808 case PERF_RECORD_LOST:
785 return ops->lost(event, sample, session); 809 if (tool->lost == perf_event__process_lost)
810 session->hists.stats.total_lost += event->lost.lost;
811 return tool->lost(tool, event, sample, machine);
786 case PERF_RECORD_READ: 812 case PERF_RECORD_READ:
787 return ops->read(event, sample, session); 813 return tool->read(tool, event, sample, evsel, machine);
788 case PERF_RECORD_THROTTLE: 814 case PERF_RECORD_THROTTLE:
789 return ops->throttle(event, sample, session); 815 return tool->throttle(tool, event, sample, machine);
790 case PERF_RECORD_UNTHROTTLE: 816 case PERF_RECORD_UNTHROTTLE:
791 return ops->unthrottle(event, sample, session); 817 return tool->unthrottle(tool, event, sample, machine);
792 default: 818 default:
793 ++session->hists.stats.nr_unknown_events; 819 ++session->hists.stats.nr_unknown_events;
794 return -1; 820 return -1;
@@ -812,24 +838,29 @@ static int perf_session__preprocess_sample(struct perf_session *session,
812} 838}
813 839
814static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 840static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
815 struct perf_event_ops *ops, u64 file_offset) 841 struct perf_tool *tool, u64 file_offset)
816{ 842{
843 int err;
844
817 dump_event(session, event, file_offset, NULL); 845 dump_event(session, event, file_offset, NULL);
818 846
819 /* These events are processed right away */ 847 /* These events are processed right away */
820 switch (event->header.type) { 848 switch (event->header.type) {
821 case PERF_RECORD_HEADER_ATTR: 849 case PERF_RECORD_HEADER_ATTR:
822 return ops->attr(event, session); 850 err = tool->attr(event, &session->evlist);
851 if (err == 0)
852 perf_session__update_sample_type(session);
853 return err;
823 case PERF_RECORD_HEADER_EVENT_TYPE: 854 case PERF_RECORD_HEADER_EVENT_TYPE:
824 return ops->event_type(event, session); 855 return tool->event_type(tool, event);
825 case PERF_RECORD_HEADER_TRACING_DATA: 856 case PERF_RECORD_HEADER_TRACING_DATA:
826 /* setup for reading amidst mmap */ 857 /* setup for reading amidst mmap */
827 lseek(session->fd, file_offset, SEEK_SET); 858 lseek(session->fd, file_offset, SEEK_SET);
828 return ops->tracing_data(event, session); 859 return tool->tracing_data(event, session);
829 case PERF_RECORD_HEADER_BUILD_ID: 860 case PERF_RECORD_HEADER_BUILD_ID:
830 return ops->build_id(event, session); 861 return tool->build_id(tool, event, session);
831 case PERF_RECORD_FINISHED_ROUND: 862 case PERF_RECORD_FINISHED_ROUND:
832 return ops->finished_round(event, session, ops); 863 return tool->finished_round(tool, event, session);
833 default: 864 default:
834 return -EINVAL; 865 return -EINVAL;
835 } 866 }
@@ -837,7 +868,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
837 868
838static int perf_session__process_event(struct perf_session *session, 869static int perf_session__process_event(struct perf_session *session,
839 union perf_event *event, 870 union perf_event *event,
840 struct perf_event_ops *ops, 871 struct perf_tool *tool,
841 u64 file_offset) 872 u64 file_offset)
842{ 873{
843 struct perf_sample sample; 874 struct perf_sample sample;
@@ -853,7 +884,7 @@ static int perf_session__process_event(struct perf_session *session,
853 hists__inc_nr_events(&session->hists, event->header.type); 884 hists__inc_nr_events(&session->hists, event->header.type);
854 885
855 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 886 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
856 return perf_session__process_user_event(session, event, ops, file_offset); 887 return perf_session__process_user_event(session, event, tool, file_offset);
857 888
858 /* 889 /*
859 * For all kernel events we get the sample data 890 * For all kernel events we get the sample data
@@ -866,14 +897,14 @@ static int perf_session__process_event(struct perf_session *session,
866 if (perf_session__preprocess_sample(session, event, &sample)) 897 if (perf_session__preprocess_sample(session, event, &sample))
867 return 0; 898 return 0;
868 899
869 if (ops->ordered_samples) { 900 if (tool->ordered_samples) {
870 ret = perf_session_queue_event(session, event, &sample, 901 ret = perf_session_queue_event(session, event, &sample,
871 file_offset); 902 file_offset);
872 if (ret != -ETIME) 903 if (ret != -ETIME)
873 return ret; 904 return ret;
874 } 905 }
875 906
876 return perf_session_deliver_event(session, event, &sample, ops, 907 return perf_session_deliver_event(session, event, &sample, tool,
877 file_offset); 908 file_offset);
878} 909}
879 910
@@ -884,6 +915,11 @@ void perf_event_header__bswap(struct perf_event_header *self)
884 self->size = bswap_16(self->size); 915 self->size = bswap_16(self->size);
885} 916}
886 917
918struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
919{
920 return machine__findnew_thread(&session->host_machine, pid);
921}
922
887static struct thread *perf_session__register_idle_thread(struct perf_session *self) 923static struct thread *perf_session__register_idle_thread(struct perf_session *self)
888{ 924{
889 struct thread *thread = perf_session__findnew(self, 0); 925 struct thread *thread = perf_session__findnew(self, 0);
@@ -897,9 +933,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
897} 933}
898 934
899static void perf_session__warn_about_errors(const struct perf_session *session, 935static void perf_session__warn_about_errors(const struct perf_session *session,
900 const struct perf_event_ops *ops) 936 const struct perf_tool *tool)
901{ 937{
902 if (ops->lost == perf_event__process_lost && 938 if (tool->lost == perf_event__process_lost &&
903 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 939 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
904 ui__warning("Processed %d events and lost %d chunks!\n\n" 940 ui__warning("Processed %d events and lost %d chunks!\n\n"
905 "Check IO/CPU overload!\n\n", 941 "Check IO/CPU overload!\n\n",
@@ -934,7 +970,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
934volatile int session_done; 970volatile int session_done;
935 971
936static int __perf_session__process_pipe_events(struct perf_session *self, 972static int __perf_session__process_pipe_events(struct perf_session *self,
937 struct perf_event_ops *ops) 973 struct perf_tool *tool)
938{ 974{
939 union perf_event event; 975 union perf_event event;
940 uint32_t size; 976 uint32_t size;
@@ -943,7 +979,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
943 int err; 979 int err;
944 void *p; 980 void *p;
945 981
946 perf_event_ops__fill_defaults(ops); 982 perf_tool__fill_defaults(tool);
947 983
948 head = 0; 984 head = 0;
949more: 985more:
@@ -979,8 +1015,7 @@ more:
979 } 1015 }
980 } 1016 }
981 1017
982 if (size == 0 || 1018 if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {
983 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
984 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1019 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
985 head, event.header.size, event.header.type); 1020 head, event.header.size, event.header.type);
986 /* 1021 /*
@@ -1003,7 +1038,7 @@ more:
1003done: 1038done:
1004 err = 0; 1039 err = 0;
1005out_err: 1040out_err:
1006 perf_session__warn_about_errors(self, ops); 1041 perf_session__warn_about_errors(self, tool);
1007 perf_session_free_sample_buffers(self); 1042 perf_session_free_sample_buffers(self);
1008 return err; 1043 return err;
1009} 1044}
@@ -1034,7 +1069,7 @@ fetch_mmaped_event(struct perf_session *session,
1034 1069
1035int __perf_session__process_events(struct perf_session *session, 1070int __perf_session__process_events(struct perf_session *session,
1036 u64 data_offset, u64 data_size, 1071 u64 data_offset, u64 data_size,
1037 u64 file_size, struct perf_event_ops *ops) 1072 u64 file_size, struct perf_tool *tool)
1038{ 1073{
1039 u64 head, page_offset, file_offset, file_pos, progress_next; 1074 u64 head, page_offset, file_offset, file_pos, progress_next;
1040 int err, mmap_prot, mmap_flags, map_idx = 0; 1075 int err, mmap_prot, mmap_flags, map_idx = 0;
@@ -1043,7 +1078,7 @@ int __perf_session__process_events(struct perf_session *session,
1043 union perf_event *event; 1078 union perf_event *event;
1044 uint32_t size; 1079 uint32_t size;
1045 1080
1046 perf_event_ops__fill_defaults(ops); 1081 perf_tool__fill_defaults(tool);
1047 1082
1048 page_size = sysconf(_SC_PAGESIZE); 1083 page_size = sysconf(_SC_PAGESIZE);
1049 1084
@@ -1098,7 +1133,7 @@ more:
1098 size = event->header.size; 1133 size = event->header.size;
1099 1134
1100 if (size == 0 || 1135 if (size == 0 ||
1101 perf_session__process_event(session, event, ops, file_pos) < 0) { 1136 perf_session__process_event(session, event, tool, file_pos) < 0) {
1102 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1137 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
1103 file_offset + head, event->header.size, 1138 file_offset + head, event->header.size,
1104 event->header.type); 1139 event->header.type);
@@ -1127,15 +1162,15 @@ more:
1127 err = 0; 1162 err = 0;
1128 /* do the final flush for ordered samples */ 1163 /* do the final flush for ordered samples */
1129 session->ordered_samples.next_flush = ULLONG_MAX; 1164 session->ordered_samples.next_flush = ULLONG_MAX;
1130 flush_sample_queue(session, ops); 1165 flush_sample_queue(session, tool);
1131out_err: 1166out_err:
1132 perf_session__warn_about_errors(session, ops); 1167 perf_session__warn_about_errors(session, tool);
1133 perf_session_free_sample_buffers(session); 1168 perf_session_free_sample_buffers(session);
1134 return err; 1169 return err;
1135} 1170}
1136 1171
1137int perf_session__process_events(struct perf_session *self, 1172int perf_session__process_events(struct perf_session *self,
1138 struct perf_event_ops *ops) 1173 struct perf_tool *tool)
1139{ 1174{
1140 int err; 1175 int err;
1141 1176
@@ -1146,9 +1181,9 @@ int perf_session__process_events(struct perf_session *self,
1146 err = __perf_session__process_events(self, 1181 err = __perf_session__process_events(self,
1147 self->header.data_offset, 1182 self->header.data_offset,
1148 self->header.data_size, 1183 self->header.data_size,
1149 self->size, ops); 1184 self->size, tool);
1150 else 1185 else
1151 err = __perf_session__process_pipe_events(self, ops); 1186 err = __perf_session__process_pipe_events(self, tool);
1152 1187
1153 return err; 1188 return err;
1154} 1189}
@@ -1163,9 +1198,8 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg)
1163 return true; 1198 return true;
1164} 1199}
1165 1200
1166int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, 1201int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1167 const char *symbol_name, 1202 const char *symbol_name, u64 addr)
1168 u64 addr)
1169{ 1203{
1170 char *bracket; 1204 char *bracket;
1171 enum map_type i; 1205 enum map_type i;
@@ -1224,6 +1258,27 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1224 return ret; 1258 return ret;
1225} 1259}
1226 1260
1261size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1262{
1263 /*
1264 * FIXME: Here we have to actually print all the machines in this
1265 * session, not just the host...
1266 */
1267 return machine__fprintf(&session->host_machine, fp);
1268}
1269
1270void perf_session__remove_thread(struct perf_session *session,
1271 struct thread *th)
1272{
1273 /*
1274 * FIXME: This one makes no sense, we need to remove the thread from
1275 * the machine it belongs to, perf_session can have many machines, so
1276 * doing it always on ->host_machine is wrong. Fix when auditing all
1277 * the 'perf kvm' code.
1278 */
1279 machine__remove_thread(&session->host_machine, th);
1280}
1281
1227struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1282struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1228 unsigned int type) 1283 unsigned int type)
1229{ 1284{
@@ -1236,17 +1291,16 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1236 return NULL; 1291 return NULL;
1237} 1292}
1238 1293
1239void perf_session__print_ip(union perf_event *event, 1294void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1240 struct perf_sample *sample, 1295 struct machine *machine, struct perf_evsel *evsel,
1241 struct perf_session *session, 1296 int print_sym, int print_dso)
1242 int print_sym, int print_dso)
1243{ 1297{
1244 struct addr_location al; 1298 struct addr_location al;
1245 const char *symname, *dsoname; 1299 const char *symname, *dsoname;
1246 struct callchain_cursor *cursor = &session->callchain_cursor; 1300 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1247 struct callchain_cursor_node *node; 1301 struct callchain_cursor_node *node;
1248 1302
1249 if (perf_event__preprocess_sample(event, session, &al, sample, 1303 if (perf_event__preprocess_sample(event, machine, &al, sample,
1250 NULL) < 0) { 1304 NULL) < 0) {
1251 error("problem processing %d event, skipping it.\n", 1305 error("problem processing %d event, skipping it.\n",
1252 event->header.type); 1306 event->header.type);
@@ -1255,7 +1309,7 @@ void perf_session__print_ip(union perf_event *event,
1255 1309
1256 if (symbol_conf.use_callchain && sample->callchain) { 1310 if (symbol_conf.use_callchain && sample->callchain) {
1257 1311
1258 if (perf_session__resolve_callchain(session, al.thread, 1312 if (machine__resolve_callchain(machine, evsel, al.thread,
1259 sample->callchain, NULL) != 0) { 1313 sample->callchain, NULL) != 0) {
1260 if (verbose) 1314 if (verbose)
1261 error("Failed to resolve callchain. Skipping\n"); 1315 error("Failed to resolve callchain. Skipping\n");
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6e393c98eb34..37bc38381fb6 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,9 +30,6 @@ struct perf_session {
30 struct perf_header header; 30 struct perf_header header;
31 unsigned long size; 31 unsigned long size;
32 unsigned long mmap_window; 32 unsigned long mmap_window;
33 struct rb_root threads;
34 struct list_head dead_threads;
35 struct thread *last_match;
36 struct machine host_machine; 33 struct machine host_machine;
37 struct rb_root machines; 34 struct rb_root machines;
38 struct perf_evlist *evlist; 35 struct perf_evlist *evlist;
@@ -53,65 +50,31 @@ struct perf_session {
53 int cwdlen; 50 int cwdlen;
54 char *cwd; 51 char *cwd;
55 struct ordered_samples ordered_samples; 52 struct ordered_samples ordered_samples;
56 struct callchain_cursor callchain_cursor; 53 char filename[1];
57 char filename[0];
58}; 54};
59 55
60struct perf_evsel; 56struct perf_tool;
61struct perf_event_ops;
62
63typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample,
64 struct perf_evsel *evsel, struct perf_session *session);
65typedef int (*event_op)(union perf_event *self, struct perf_sample *sample,
66 struct perf_session *session);
67typedef int (*event_synth_op)(union perf_event *self,
68 struct perf_session *session);
69typedef int (*event_op2)(union perf_event *self, struct perf_session *session,
70 struct perf_event_ops *ops);
71
72struct perf_event_ops {
73 event_sample sample;
74 event_op mmap,
75 comm,
76 fork,
77 exit,
78 lost,
79 read,
80 throttle,
81 unthrottle;
82 event_synth_op attr,
83 event_type,
84 tracing_data,
85 build_id;
86 event_op2 finished_round;
87 bool ordered_samples;
88 bool ordering_requires_timestamps;
89};
90 57
91struct perf_session *perf_session__new(const char *filename, int mode, 58struct perf_session *perf_session__new(const char *filename, int mode,
92 bool force, bool repipe, 59 bool force, bool repipe,
93 struct perf_event_ops *ops); 60 struct perf_tool *tool);
94void perf_session__delete(struct perf_session *self); 61void perf_session__delete(struct perf_session *self);
95 62
96void perf_event_header__bswap(struct perf_event_header *self); 63void perf_event_header__bswap(struct perf_event_header *self);
97 64
98int __perf_session__process_events(struct perf_session *self, 65int __perf_session__process_events(struct perf_session *self,
99 u64 data_offset, u64 data_size, u64 size, 66 u64 data_offset, u64 data_size, u64 size,
100 struct perf_event_ops *ops); 67 struct perf_tool *tool);
101int perf_session__process_events(struct perf_session *self, 68int perf_session__process_events(struct perf_session *self,
102 struct perf_event_ops *event_ops); 69 struct perf_tool *tool);
103 70
104int perf_session__resolve_callchain(struct perf_session *self, 71int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
105 struct thread *thread, 72 struct thread *thread,
106 struct ip_callchain *chain, 73 struct ip_callchain *chain,
107 struct symbol **parent); 74 struct symbol **parent);
108 75
109bool perf_session__has_traces(struct perf_session *self, const char *msg); 76bool perf_session__has_traces(struct perf_session *self, const char *msg);
110 77
111int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
112 const char *symbol_name,
113 u64 addr);
114
115void mem_bswap_64(void *src, int byte_size); 78void mem_bswap_64(void *src, int byte_size);
116void perf_event__attr_swap(struct perf_event_attr *attr); 79void perf_event__attr_swap(struct perf_event_attr *attr);
117 80
@@ -144,12 +107,16 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p
144 107
145static inline 108static inline
146void perf_session__process_machines(struct perf_session *self, 109void perf_session__process_machines(struct perf_session *self,
110 struct perf_tool *tool,
147 machine__process_t process) 111 machine__process_t process)
148{ 112{
149 process(&self->host_machine, self); 113 process(&self->host_machine, tool);
150 return machines__process(&self->machines, process, self); 114 return machines__process(&self->machines, process, tool);
151} 115}
152 116
117struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
118size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
119
153size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 120size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
154 121
155size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 122size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
@@ -167,13 +134,20 @@ static inline int perf_session__parse_sample(struct perf_session *session,
167 session->header.needs_swap); 134 session->header.needs_swap);
168} 135}
169 136
137static inline int perf_session__synthesize_sample(struct perf_session *session,
138 union perf_event *event,
139 const struct perf_sample *sample)
140{
141 return perf_event__synthesize_sample(event, session->sample_type,
142 sample, session->header.needs_swap);
143}
144
170struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 145struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
171 unsigned int type); 146 unsigned int type);
172 147
173void perf_session__print_ip(union perf_event *event, 148void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
174 struct perf_sample *sample, 149 struct machine *machine, struct perf_evsel *evsel,
175 struct perf_session *session, 150 int print_sym, int print_dso);
176 int print_sym, int print_dso);
177 151
178int perf_session__cpu_bitmap(struct perf_session *session, 152int perf_session__cpu_bitmap(struct perf_session *session,
179 const char *cpu_list, unsigned long *cpu_bitmap); 153 const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 95d370074928..36d4c5619575 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -27,7 +27,8 @@ build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27perf = Extension('perf', 27perf = Extension('perf',
28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 28 sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', 29 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], 30 'util/util.c', 'util/xyarray.c', 'util/cgroup.c',
31 'util/debugfs.c'],
31 include_dirs = ['util/include'], 32 include_dirs = ['util/include'],
32 extra_compile_args = cflags, 33 extra_compile_args = cflags,
33 ) 34 )
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 632b50c7bc26..215d50f2042e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1757,7 +1757,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
1757 struct stat st; 1757 struct stat st;
1758 1758
1759 /*sshfs might return bad dent->d_type, so we have to stat*/ 1759 /*sshfs might return bad dent->d_type, so we have to stat*/
1760 sprintf(path, "%s/%s", dir_name, dent->d_name); 1760 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
1761 if (stat(path, &st)) 1761 if (stat(path, &st))
1762 continue; 1762 continue;
1763 1763
@@ -1766,8 +1766,6 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
1766 !strcmp(dent->d_name, "..")) 1766 !strcmp(dent->d_name, ".."))
1767 continue; 1767 continue;
1768 1768
1769 snprintf(path, sizeof(path), "%s/%s",
1770 dir_name, dent->d_name);
1771 ret = map_groups__set_modules_path_dir(mg, path); 1769 ret = map_groups__set_modules_path_dir(mg, path);
1772 if (ret < 0) 1770 if (ret < 0)
1773 goto out; 1771 goto out;
@@ -1788,9 +1786,6 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
1788 if (map == NULL) 1786 if (map == NULL)
1789 continue; 1787 continue;
1790 1788
1791 snprintf(path, sizeof(path), "%s/%s",
1792 dir_name, dent->d_name);
1793
1794 long_name = strdup(path); 1789 long_name = strdup(path);
1795 if (long_name == NULL) { 1790 if (long_name == NULL) {
1796 ret = -1; 1791 ret = -1;
@@ -2609,10 +2604,10 @@ int symbol__init(void)
2609 symbol_conf.initialized = true; 2604 symbol_conf.initialized = true;
2610 return 0; 2605 return 0;
2611 2606
2612out_free_dso_list:
2613 strlist__delete(symbol_conf.dso_list);
2614out_free_comm_list: 2607out_free_comm_list:
2615 strlist__delete(symbol_conf.comm_list); 2608 strlist__delete(symbol_conf.comm_list);
2609out_free_dso_list:
2610 strlist__delete(symbol_conf.dso_list);
2616 return -1; 2611 return -1;
2617} 2612}
2618 2613
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 29f8d742e92f..123c2e14353e 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -68,6 +68,7 @@ struct strlist;
68 68
69struct symbol_conf { 69struct symbol_conf {
70 unsigned short priv_size; 70 unsigned short priv_size;
71 unsigned short nr_events;
71 bool try_vmlinux_path, 72 bool try_vmlinux_path,
72 use_modules, 73 use_modules,
73 sort_by_name, 74 sort_by_name,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index d5d3b22250f3..fb4b7ea6752f 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -61,7 +61,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
61 map_groups__fprintf(&self->mg, verbose, fp); 61 map_groups__fprintf(&self->mg, verbose, fp);
62} 62}
63 63
64struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 64struct thread *machine__findnew_thread(struct machine *self, pid_t pid)
65{ 65{
66 struct rb_node **p = &self->threads.rb_node; 66 struct rb_node **p = &self->threads.rb_node;
67 struct rb_node *parent = NULL; 67 struct rb_node *parent = NULL;
@@ -125,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent)
125 return 0; 125 return 0;
126} 126}
127 127
128size_t perf_session__fprintf(struct perf_session *self, FILE *fp) 128size_t machine__fprintf(struct machine *machine, FILE *fp)
129{ 129{
130 size_t ret = 0; 130 size_t ret = 0;
131 struct rb_node *nd; 131 struct rb_node *nd;
132 132
133 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { 133 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
134 struct thread *pos = rb_entry(nd, struct thread, rb_node); 134 struct thread *pos = rb_entry(nd, struct thread, rb_node);
135 135
136 ret += thread__fprintf(pos, fp); 136 ret += thread__fprintf(pos, fp);
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index e5f2401c1b5e..70c2c13ff679 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -18,16 +18,14 @@ struct thread {
18 int comm_len; 18 int comm_len;
19}; 19};
20 20
21struct perf_session; 21struct machine;
22 22
23void thread__delete(struct thread *self); 23void thread__delete(struct thread *self);
24 24
25int thread__set_comm(struct thread *self, const char *comm); 25int thread__set_comm(struct thread *self, const char *comm);
26int thread__comm_len(struct thread *self); 26int thread__comm_len(struct thread *self);
27struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
28void thread__insert_map(struct thread *self, struct map *map); 27void thread__insert_map(struct thread *self, struct map *map);
29int thread__fork(struct thread *self, struct thread *parent); 28int thread__fork(struct thread *self, struct thread *parent);
30size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
31 29
32static inline struct map *thread__find_map(struct thread *self, 30static inline struct map *thread__find_map(struct thread *self,
33 enum map_type type, u64 addr) 31 enum map_type type, u64 addr)
@@ -35,14 +33,12 @@ static inline struct map *thread__find_map(struct thread *self,
35 return self ? map_groups__find(&self->mg, type, addr) : NULL; 33 return self ? map_groups__find(&self->mg, type, addr) : NULL;
36} 34}
37 35
38void thread__find_addr_map(struct thread *self, 36void thread__find_addr_map(struct thread *thread, struct machine *machine,
39 struct perf_session *session, u8 cpumode, 37 u8 cpumode, enum map_type type, u64 addr,
40 enum map_type type, pid_t pid, u64 addr,
41 struct addr_location *al); 38 struct addr_location *al);
42 39
43void thread__find_addr_location(struct thread *self, 40void thread__find_addr_location(struct thread *thread, struct machine *machine,
44 struct perf_session *session, u8 cpumode, 41 u8 cpumode, enum map_type type, u64 addr,
45 enum map_type type, pid_t pid, u64 addr,
46 struct addr_location *al, 42 struct addr_location *al,
47 symbol_filter_t filter); 43 symbol_filter_t filter);
48#endif /* __PERF_THREAD_H */ 44#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
new file mode 100644
index 000000000000..b0e1aadba8d5
--- /dev/null
+++ b/tools/perf/util/tool.h
@@ -0,0 +1,50 @@
1#ifndef __PERF_TOOL_H
2#define __PERF_TOOL_H
3
4#include <stdbool.h>
5
6struct perf_session;
7union perf_event;
8struct perf_evlist;
9struct perf_evsel;
10struct perf_sample;
11struct perf_tool;
12struct machine;
13
14typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event,
15 struct perf_sample *sample,
16 struct perf_evsel *evsel, struct machine *machine);
17
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
19 struct perf_sample *sample, struct machine *machine);
20
21typedef int (*event_attr_op)(union perf_event *event,
22 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
29 struct perf_session *session);
30
31struct perf_tool {
32 event_sample sample,
33 read;
34 event_op mmap,
35 comm,
36 fork,
37 exit,
38 lost,
39 throttle,
40 unthrottle;
41 event_attr_op attr;
42 event_synth_op tracing_data;
43 event_simple_op event_type;
44 event_op2 finished_round,
45 build_id;
46 bool ordered_samples;
47 bool ordering_requires_timestamps;
48};
49
50#endif /* __PERF_TOOL_H */
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 399650967958..a248f3c2c60d 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -1,15 +1,17 @@
1#ifndef __PERF_TOP_H 1#ifndef __PERF_TOP_H
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h"
4#include "types.h" 5#include "types.h"
5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h>
7 8
8struct perf_evlist; 9struct perf_evlist;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_session; 11struct perf_session;
11 12
12struct perf_top { 13struct perf_top {
14 struct perf_tool tool;
13 struct perf_evlist *evlist; 15 struct perf_evlist *evlist;
14 /* 16 /*
15 * Symbols will be added here in perf_event__process_sample and will 17 * Symbols will be added here in perf_event__process_sample and will
@@ -23,10 +25,26 @@ struct perf_top {
23 int freq; 25 int freq;
24 pid_t target_pid, target_tid; 26 pid_t target_pid, target_tid;
25 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool system_wide;
29 bool use_tui, use_stdio;
30 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned;
33 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_avail;
37 bool dump_symtab;
26 const char *cpu_list; 38 const char *cpu_list;
27 struct hist_entry *sym_filter_entry; 39 struct hist_entry *sym_filter_entry;
28 struct perf_evsel *sym_evsel; 40 struct perf_evsel *sym_evsel;
29 struct perf_session *session; 41 struct perf_session *session;
42 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio;
46 int sym_pcnt_filter;
47 const char *sym_filter;
30}; 48};
31 49
32size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index d2655f08bcc0..ac6830d8292b 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -18,7 +18,8 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _GNU_SOURCE 21#include <ctype.h>
22#include "util.h"
22#include <dirent.h> 23#include <dirent.h>
23#include <mntent.h> 24#include <mntent.h>
24#include <stdio.h> 25#include <stdio.h>
@@ -31,7 +32,6 @@
31#include <pthread.h> 32#include <pthread.h>
32#include <fcntl.h> 33#include <fcntl.h>
33#include <unistd.h> 34#include <unistd.h>
34#include <ctype.h>
35#include <errno.h> 35#include <errno.h>
36#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/list.h> 37#include <linux/list.h>
@@ -44,10 +44,6 @@
44 44
45#define VERSION "0.5" 45#define VERSION "0.5"
46 46
47#define _STR(x) #x
48#define STR(x) _STR(x)
49#define MAX_PATH 256
50
51#define TRACE_CTRL "tracing_on" 47#define TRACE_CTRL "tracing_on"
52#define TRACE "trace" 48#define TRACE "trace"
53#define AVAILABLE "available_tracers" 49#define AVAILABLE "available_tracers"
@@ -73,26 +69,6 @@ struct events {
73}; 69};
74 70
75 71
76
77static void die(const char *fmt, ...)
78{
79 va_list ap;
80 int ret = errno;
81
82 if (errno)
83 perror("perf");
84 else
85 ret = -1;
86
87 va_start(ap, fmt);
88 fprintf(stderr, " ");
89 vfprintf(stderr, fmt, ap);
90 va_end(ap);
91
92 fprintf(stderr, "\n");
93 exit(ret);
94}
95
96void *malloc_or_die(unsigned int size) 72void *malloc_or_die(unsigned int size)
97{ 73{
98 void *data; 74 void *data;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index c9dcbec7d800..a3fdf55f317b 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -39,7 +39,7 @@ static int stop_script_unsupported(void)
39static void process_event_unsupported(union perf_event *event __unused, 39static void process_event_unsupported(union perf_event *event __unused,
40 struct perf_sample *sample __unused, 40 struct perf_sample *sample __unused,
41 struct perf_evsel *evsel __unused, 41 struct perf_evsel *evsel __unused,
42 struct perf_session *session __unused, 42 struct machine *machine __unused,
43 struct thread *thread __unused) 43 struct thread *thread __unused)
44{ 44{
45} 45}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a84100817649..58ae14c5baac 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,7 +3,11 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h" 6
7struct machine;
8struct perf_sample;
9union perf_event;
10struct thread;
7 11
8#define __unused __attribute__((unused)) 12#define __unused __attribute__((unused))
9 13
@@ -292,7 +296,7 @@ struct scripting_ops {
292 void (*process_event) (union perf_event *event, 296 void (*process_event) (union perf_event *event,
293 struct perf_sample *sample, 297 struct perf_sample *sample,
294 struct perf_evsel *evsel, 298 struct perf_evsel *evsel,
295 struct perf_session *session, 299 struct machine *machine,
296 struct thread *thread); 300 struct thread *thread);
297 int (*generate_script) (const char *outfile); 301 int (*generate_script) (const char *outfile);
298}; 302};
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
index 0575905d1205..295a9c93f945 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -224,7 +224,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser)
224} 224}
225 225
226static int annotate_browser__run(struct annotate_browser *self, int evidx, 226static int annotate_browser__run(struct annotate_browser *self, int evidx,
227 int nr_events, void(*timer)(void *arg), 227 void(*timer)(void *arg),
228 void *arg, int delay_secs) 228 void *arg, int delay_secs)
229{ 229{
230 struct rb_node *nd = NULL; 230 struct rb_node *nd = NULL;
@@ -328,8 +328,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
328 notes = symbol__annotation(target); 328 notes = symbol__annotation(target);
329 pthread_mutex_lock(&notes->lock); 329 pthread_mutex_lock(&notes->lock);
330 330
331 if (notes->src == NULL && 331 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
332 symbol__alloc_hist(target, nr_events) < 0) {
333 pthread_mutex_unlock(&notes->lock); 332 pthread_mutex_unlock(&notes->lock);
334 ui__warning("Not enough memory for annotating '%s' symbol!\n", 333 ui__warning("Not enough memory for annotating '%s' symbol!\n",
335 target->name); 334 target->name);
@@ -337,7 +336,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
337 } 336 }
338 337
339 pthread_mutex_unlock(&notes->lock); 338 pthread_mutex_unlock(&notes->lock);
340 symbol__tui_annotate(target, ms->map, evidx, nr_events, 339 symbol__tui_annotate(target, ms->map, evidx,
341 timer, arg, delay_secs); 340 timer, arg, delay_secs);
342 } 341 }
343 continue; 342 continue;
@@ -358,15 +357,15 @@ out:
358 return key; 357 return key;
359} 358}
360 359
361int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, 360int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
362 void(*timer)(void *arg), void *arg, int delay_secs) 361 void(*timer)(void *arg), void *arg, int delay_secs)
363{ 362{
364 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, 363 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
365 timer, arg, delay_secs); 364 timer, arg, delay_secs);
366} 365}
367 366
368int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 367int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
369 int nr_events, void(*timer)(void *arg), void *arg, 368 void(*timer)(void *arg), void *arg,
370 int delay_secs) 369 int delay_secs)
371{ 370{
372 struct objdump_line *pos, *n; 371 struct objdump_line *pos, *n;
@@ -419,8 +418,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
419 browser.b.nr_entries = browser.nr_entries; 418 browser.b.nr_entries = browser.nr_entries;
420 browser.b.entries = &notes->src->source, 419 browser.b.entries = &notes->src->source,
421 browser.b.width += 18; /* Percentage */ 420 browser.b.width += 18; /* Percentage */
422 ret = annotate_browser__run(&browser, evidx, nr_events, 421 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
423 timer, arg, delay_secs);
424 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 422 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
425 list_del(&pos->node); 423 list_del(&pos->node);
426 objdump_line__free(pos); 424 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index d0c94b459685..1212a386a033 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -1020,7 +1020,7 @@ do_annotate:
1020 * Don't let this be freed, say, by hists__decay_entry. 1020 * Don't let this be freed, say, by hists__decay_entry.
1021 */ 1021 */
1022 he->used = true; 1022 he->used = true;
1023 err = hist_entry__tui_annotate(he, evsel->idx, nr_events, 1023 err = hist_entry__tui_annotate(he, evsel->idx,
1024 timer, arg, delay_secs); 1024 timer, arg, delay_secs);
1025 he->used = false; 1025 he->used = false;
1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 1026 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
index 295e366b6311..13aa64e50e11 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/util/ui/progress.c
@@ -14,6 +14,9 @@ void ui_progress__update(u64 curr, u64 total, const char *title)
14 if (use_browser <= 0) 14 if (use_browser <= 0)
15 return; 15 return;
16 16
17 if (total == 0)
18 return;
19
17 ui__refresh_dimensions(true); 20 ui__refresh_dimensions(true);
18 pthread_mutex_lock(&ui__lock); 21 pthread_mutex_lock(&ui__lock);
19 y = SLtt_Screen_Rows / 2 - 2; 22 y = SLtt_Screen_Rows / 2 - 2;
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index e16bf9a707e8..d76d1c0ff98f 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -1,5 +1,8 @@
1/* 1/*
2 * GIT - The information manager from hell 2 * usage.c
3 *
4 * Various reporting routines.
5 * Originally copied from GIT source.
3 * 6 *
4 * Copyright (C) Linus Torvalds, 2005 7 * Copyright (C) Linus Torvalds, 2005
5 */ 8 */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0128906bac88..37be34dff798 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -245,4 +245,15 @@ int readn(int fd, void *buf, size_t size);
245#define _STR(x) #x 245#define _STR(x) #x
246#define STR(x) _STR(x) 246#define STR(x) _STR(x)
247 247
248/*
249 * Determine whether some value is a power of two, where zero is
250 * *not* considered a power of two.
251 */
252
253static inline __attribute__((const))
254bool is_power_of_2(unsigned long n)
255{
256 return (n != 0 && ((n & (n - 1)) == 0));
257}
258
248#endif 259#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index bdd33470b235..697c8b4e59cc 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -32,6 +32,7 @@ void perf_read_values_destroy(struct perf_read_values *values)
32 32
33 for (i = 0; i < values->threads; i++) 33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]); 34 free(values->value[i]);
35 free(values->value);
35 free(values->pid); 36 free(values->pid);
36 free(values->tid); 37 free(values->tid);
37 free(values->counterrawid); 38 free(values->counterrawid);