aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Makefile.perf9
-rw-r--r--tools/perf/builtin-record.c11
-rw-r--r--tools/perf/config/Makefile15
-rw-r--r--tools/perf/config/feature-checks/Makefile8
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-zlib.c9
-rw-r--r--tools/perf/scripts/python/bin/export-to-postgresql-report15
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py98
-rw-r--r--tools/perf/util/build-id.c334
-rw-r--r--tools/perf/util/build-id.h11
-rw-r--r--tools/perf/util/db-export.c162
-rw-r--r--tools/perf/util/db-export.h21
-rw-r--r--tools/perf/util/dso.c71
-rw-r--r--tools/perf/util/dso.h7
-rw-r--r--tools/perf/util/event.h26
-rw-r--r--tools/perf/util/evsel.c2
-rw-r--r--tools/perf/util/header.c343
-rw-r--r--tools/perf/util/header.h8
-rw-r--r--tools/perf/util/include/linux/bitmap.h17
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/machine.c38
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c29
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c152
-rw-r--r--tools/perf/util/symbol-elf.c35
-rw-r--r--tools/perf/util/symbol.c19
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/thread-stack.c747
-rw-r--r--tools/perf/util/thread-stack.h111
-rw-r--r--tools/perf/util/thread.c3
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/util.h5
-rw-r--r--tools/perf/util/zlib.c78
32 files changed, 1966 insertions, 429 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 3caf7dab50e8..aecf61dcd754 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -66,6 +66,9 @@ include config/utilities.mak
66# 66#
67# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32 67# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
68# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode 68# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
69#
70# Define NO_ZLIB if you do not want to support compressed kernel modules
71
69 72
70ifeq ($(srctree),) 73ifeq ($(srctree),)
71srctree := $(patsubst %/,%,$(dir $(shell pwd))) 74srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -317,6 +320,7 @@ LIB_H += ui/util.h
317LIB_H += ui/ui.h 320LIB_H += ui/ui.h
318LIB_H += util/data.h 321LIB_H += util/data.h
319LIB_H += util/kvm-stat.h 322LIB_H += util/kvm-stat.h
323LIB_H += util/thread-stack.h
320 324
321LIB_OBJS += $(OUTPUT)util/abspath.o 325LIB_OBJS += $(OUTPUT)util/abspath.o
322LIB_OBJS += $(OUTPUT)util/alias.o 326LIB_OBJS += $(OUTPUT)util/alias.o
@@ -394,6 +398,7 @@ LIB_OBJS += $(OUTPUT)util/srcline.o
394LIB_OBJS += $(OUTPUT)util/data.o 398LIB_OBJS += $(OUTPUT)util/data.o
395LIB_OBJS += $(OUTPUT)util/tsc.o 399LIB_OBJS += $(OUTPUT)util/tsc.o
396LIB_OBJS += $(OUTPUT)util/cloexec.o 400LIB_OBJS += $(OUTPUT)util/cloexec.o
401LIB_OBJS += $(OUTPUT)util/thread-stack.o
397 402
398LIB_OBJS += $(OUTPUT)ui/setup.o 403LIB_OBJS += $(OUTPUT)ui/setup.o
399LIB_OBJS += $(OUTPUT)ui/helpline.o 404LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -582,6 +587,10 @@ ifndef NO_LIBNUMA
582 BUILTIN_OBJS += $(OUTPUT)bench/numa.o 587 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
583endif 588endif
584 589
590ifndef NO_ZLIB
591 LIB_OBJS += $(OUTPUT)util/zlib.o
592endif
593
585ifdef ASCIIDOC8 594ifdef ASCIIDOC8
586 export ASCIIDOC8 595 export ASCIIDOC8
587endif 596endif
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 5091a27e6d28..582c4da155ea 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
200 if (size == 0) 200 if (size == 0)
201 return 0; 201 return 0;
202 202
203 /*
204 * During this process, it'll load kernel map and replace the
205 * dso->long_name to a real pathname it found. In this case
206 * we prefer the vmlinux path like
207 * /lib/modules/3.16.4/build/vmlinux
208 *
209 * rather than build-id path (in debug directory).
210 * $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
211 */
212 symbol_conf.ignore_vmlinux_buildid = true;
213
203 return __perf_session__process_events(session, start, 214 return __perf_session__process_events(session, start,
204 size - start, 215 size - start,
205 size, &build_id__mark_dso_hit_ops); 216 size, &build_id__mark_dso_hit_ops);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 71264e41fa85..79f906c7124e 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS = \
200 libunwind \ 200 libunwind \
201 stackprotector-all \ 201 stackprotector-all \
202 timerfd \ 202 timerfd \
203 libdw-dwarf-unwind 203 libdw-dwarf-unwind \
204 zlib
204 205
205LIB_FEATURE_TESTS = \ 206LIB_FEATURE_TESTS = \
206 dwarf \ 207 dwarf \
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS = \
214 libpython \ 215 libpython \
215 libslang \ 216 libslang \
216 libunwind \ 217 libunwind \
217 libdw-dwarf-unwind 218 libdw-dwarf-unwind \
219 zlib
218 220
219VF_FEATURE_TESTS = \ 221VF_FEATURE_TESTS = \
220 backtrace \ 222 backtrace \
@@ -604,6 +606,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
604 CFLAGS += -DHAVE_LIBBFD_SUPPORT 606 CFLAGS += -DHAVE_LIBBFD_SUPPORT
605endif 607endif
606 608
609ifndef NO_ZLIB
610 ifeq ($(feature-zlib), 1)
611 CFLAGS += -DHAVE_ZLIB_SUPPORT
612 EXTLIBS += -lz
613 else
614 NO_ZLIB := 1
615 endif
616endif
617
607ifndef NO_BACKTRACE 618ifndef NO_BACKTRACE
608 ifeq ($(feature-backtrace), 1) 619 ifeq ($(feature-backtrace), 1)
609 CFLAGS += -DHAVE_BACKTRACE_SUPPORT 620 CFLAGS += -DHAVE_BACKTRACE_SUPPORT
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 7c68ec74a808..53f19b5dbc37 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -29,7 +29,8 @@ FILES= \
29 test-timerfd.bin \ 29 test-timerfd.bin \
30 test-libdw-dwarf-unwind.bin \ 30 test-libdw-dwarf-unwind.bin \
31 test-compile-32.bin \ 31 test-compile-32.bin \
32 test-compile-x32.bin 32 test-compile-x32.bin \
33 test-zlib.bin
33 34
34CC := $(CROSS_COMPILE)gcc -MD 35CC := $(CROSS_COMPILE)gcc -MD
35PKG_CONFIG := $(CROSS_COMPILE)pkg-config 36PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -41,7 +42,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
41############################### 42###############################
42 43
43test-all.bin: 44test-all.bin:
44 $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl 45 $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
45 46
46test-hello.bin: 47test-hello.bin:
47 $(BUILD) 48 $(BUILD)
@@ -139,6 +140,9 @@ test-compile-32.bin:
139test-compile-x32.bin: 140test-compile-x32.bin:
140 $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c 141 $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
141 142
143test-zlib.bin:
144 $(BUILD) -lz
145
142-include *.d 146-include *.d
143 147
144############################### 148###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index a7d022e161c0..652e0098eba6 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -93,6 +93,10 @@
93# include "test-sync-compare-and-swap.c" 93# include "test-sync-compare-and-swap.c"
94#undef main 94#undef main
95 95
96#define main main_test_zlib
97# include "test-zlib.c"
98#undef main
99
96int main(int argc, char *argv[]) 100int main(int argc, char *argv[])
97{ 101{
98 main_test_libpython(); 102 main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
116 main_test_stackprotector_all(); 120 main_test_stackprotector_all();
117 main_test_libdw_dwarf_unwind(); 121 main_test_libdw_dwarf_unwind();
118 main_test_sync_compare_and_swap(argc, argv); 122 main_test_sync_compare_and_swap(argc, argv);
123 main_test_zlib();
119 124
120 return 0; 125 return 0;
121} 126}
diff --git a/tools/perf/config/feature-checks/test-zlib.c b/tools/perf/config/feature-checks/test-zlib.c
new file mode 100644
index 000000000000..e111fff6240e
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-zlib.c
@@ -0,0 +1,9 @@
1#include <zlib.h>
2
3int main(void)
4{
5 z_stream zs;
6
7 inflateInit(&zs);
8 return 0;
9}
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-report b/tools/perf/scripts/python/bin/export-to-postgresql-report
index a8fdd15f85bf..cd335b6e2a01 100644
--- a/tools/perf/scripts/python/bin/export-to-postgresql-report
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-report
@@ -1,6 +1,6 @@
1#!/bin/bash 1#!/bin/bash
2# description: export perf data to a postgresql database 2# description: export perf data to a postgresql database
3# args: [database name] [columns] 3# args: [database name] [columns] [calls]
4n_args=0 4n_args=0
5for i in "$@" 5for i in "$@"
6do 6do
@@ -9,11 +9,16 @@ do
9 fi 9 fi
10 n_args=$(( $n_args + 1 )) 10 n_args=$(( $n_args + 1 ))
11done 11done
12if [ "$n_args" -gt 2 ] ; then 12if [ "$n_args" -gt 3 ] ; then
13 echo "usage: export-to-postgresql-report [database name] [columns]" 13 echo "usage: export-to-postgresql-report [database name] [columns] [calls]"
14 exit 14 exit
15fi 15fi
16if [ "$n_args" -gt 1 ] ; then 16if [ "$n_args" -gt 2 ] ; then
17 dbname=$1
18 columns=$2
19 calls=$3
20 shift 3
21elif [ "$n_args" -gt 1 ] ; then
17 dbname=$1 22 dbname=$1
18 columns=$2 23 columns=$2
19 shift 2 24 shift 2
@@ -21,4 +26,4 @@ elif [ "$n_args" -gt 0 ] ; then
21 dbname=$1 26 dbname=$1
22 shift 27 shift
23fi 28fi
24perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns 29perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns $calls
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index d8f6df0093d6..4cdafd880074 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -40,10 +40,12 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
40#from Core import * 40#from Core import *
41 41
42perf_db_export_mode = True 42perf_db_export_mode = True
43perf_db_export_calls = False
43 44
44def usage(): 45def usage():
45 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>]" 46 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]"
46 print >> sys.stderr, "where: columns 'all' or 'branches'" 47 print >> sys.stderr, "where: columns 'all' or 'branches'"
48 print >> sys.stderr, " calls 'calls' => create calls table"
47 raise Exception("Too few arguments") 49 raise Exception("Too few arguments")
48 50
49if (len(sys.argv) < 2): 51if (len(sys.argv) < 2):
@@ -61,6 +63,12 @@ if columns not in ("all", "branches"):
61 63
62branches = (columns == "branches") 64branches = (columns == "branches")
63 65
66if (len(sys.argv) >= 4):
67 if (sys.argv[3] == "calls"):
68 perf_db_export_calls = True
69 else:
70 usage()
71
64output_dir_name = os.getcwd() + "/" + dbname + "-perf-data" 72output_dir_name = os.getcwd() + "/" + dbname + "-perf-data"
65os.mkdir(output_dir_name) 73os.mkdir(output_dir_name)
66 74
@@ -123,6 +131,10 @@ do_query(query, 'CREATE TABLE symbols ('
123 'sym_end bigint,' 131 'sym_end bigint,'
124 'binding integer,' 132 'binding integer,'
125 'name varchar(2048))') 133 'name varchar(2048))')
134do_query(query, 'CREATE TABLE branch_types ('
135 'id integer NOT NULL,'
136 'name varchar(80))')
137
126if branches: 138if branches:
127 do_query(query, 'CREATE TABLE samples (' 139 do_query(query, 'CREATE TABLE samples ('
128 'id bigint NOT NULL,' 140 'id bigint NOT NULL,'
@@ -139,7 +151,9 @@ if branches:
139 'to_dso_id bigint,' 151 'to_dso_id bigint,'
140 'to_symbol_id bigint,' 152 'to_symbol_id bigint,'
141 'to_sym_offset bigint,' 153 'to_sym_offset bigint,'
142 'to_ip bigint)') 154 'to_ip bigint,'
155 'branch_type integer,'
156 'in_tx boolean)')
143else: 157else:
144 do_query(query, 'CREATE TABLE samples (' 158 do_query(query, 'CREATE TABLE samples ('
145 'id bigint NOT NULL,' 159 'id bigint NOT NULL,'
@@ -160,7 +174,28 @@ else:
160 'period bigint,' 174 'period bigint,'
161 'weight bigint,' 175 'weight bigint,'
162 'transaction bigint,' 176 'transaction bigint,'
163 'data_src bigint)') 177 'data_src bigint,'
178 'branch_type integer,'
179 'in_tx boolean)')
180
181if perf_db_export_calls:
182 do_query(query, 'CREATE TABLE call_paths ('
183 'id bigint NOT NULL,'
184 'parent_id bigint,'
185 'symbol_id bigint,'
186 'ip bigint)')
187 do_query(query, 'CREATE TABLE calls ('
188 'id bigint NOT NULL,'
189 'thread_id bigint,'
190 'comm_id bigint,'
191 'call_path_id bigint,'
192 'call_time bigint,'
193 'return_time bigint,'
194 'branch_count bigint,'
195 'call_id bigint,'
196 'return_id bigint,'
197 'parent_call_path_id bigint,'
198 'flags integer)')
164 199
165do_query(query, 'CREATE VIEW samples_view AS ' 200do_query(query, 'CREATE VIEW samples_view AS '
166 'SELECT ' 201 'SELECT '
@@ -178,7 +213,9 @@ do_query(query, 'CREATE VIEW samples_view AS '
178 'to_hex(to_ip) AS to_ip_hex,' 213 'to_hex(to_ip) AS to_ip_hex,'
179 '(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,' 214 '(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
180 'to_sym_offset,' 215 'to_sym_offset,'
181 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name' 216 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
217 '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
218 'in_tx'
182 ' FROM samples') 219 ' FROM samples')
183 220
184 221
@@ -234,7 +271,11 @@ comm_file = open_output_file("comm_table.bin")
234comm_thread_file = open_output_file("comm_thread_table.bin") 271comm_thread_file = open_output_file("comm_thread_table.bin")
235dso_file = open_output_file("dso_table.bin") 272dso_file = open_output_file("dso_table.bin")
236symbol_file = open_output_file("symbol_table.bin") 273symbol_file = open_output_file("symbol_table.bin")
274branch_type_file = open_output_file("branch_type_table.bin")
237sample_file = open_output_file("sample_table.bin") 275sample_file = open_output_file("sample_table.bin")
276if perf_db_export_calls:
277 call_path_file = open_output_file("call_path_table.bin")
278 call_file = open_output_file("call_table.bin")
238 279
239def trace_begin(): 280def trace_begin():
240 print datetime.datetime.today(), "Writing to intermediate files..." 281 print datetime.datetime.today(), "Writing to intermediate files..."
@@ -245,6 +286,9 @@ def trace_begin():
245 comm_table(0, "unknown") 286 comm_table(0, "unknown")
246 dso_table(0, 0, "unknown", "unknown", "") 287 dso_table(0, 0, "unknown", "unknown", "")
247 symbol_table(0, 0, 0, 0, 0, "unknown") 288 symbol_table(0, 0, 0, 0, 0, "unknown")
289 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
290 if perf_db_export_calls:
291 call_path_table(0, 0, 0, 0)
248 292
249unhandled_count = 0 293unhandled_count = 0
250 294
@@ -257,7 +301,11 @@ def trace_end():
257 copy_output_file(comm_thread_file, "comm_threads") 301 copy_output_file(comm_thread_file, "comm_threads")
258 copy_output_file(dso_file, "dsos") 302 copy_output_file(dso_file, "dsos")
259 copy_output_file(symbol_file, "symbols") 303 copy_output_file(symbol_file, "symbols")
304 copy_output_file(branch_type_file, "branch_types")
260 copy_output_file(sample_file, "samples") 305 copy_output_file(sample_file, "samples")
306 if perf_db_export_calls:
307 copy_output_file(call_path_file, "call_paths")
308 copy_output_file(call_file, "calls")
261 309
262 print datetime.datetime.today(), "Removing intermediate files..." 310 print datetime.datetime.today(), "Removing intermediate files..."
263 remove_output_file(evsel_file) 311 remove_output_file(evsel_file)
@@ -267,7 +315,11 @@ def trace_end():
267 remove_output_file(comm_thread_file) 315 remove_output_file(comm_thread_file)
268 remove_output_file(dso_file) 316 remove_output_file(dso_file)
269 remove_output_file(symbol_file) 317 remove_output_file(symbol_file)
318 remove_output_file(branch_type_file)
270 remove_output_file(sample_file) 319 remove_output_file(sample_file)
320 if perf_db_export_calls:
321 remove_output_file(call_path_file)
322 remove_output_file(call_file)
271 os.rmdir(output_dir_name) 323 os.rmdir(output_dir_name)
272 print datetime.datetime.today(), "Adding primary keys" 324 print datetime.datetime.today(), "Adding primary keys"
273 do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)') 325 do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
@@ -277,7 +329,11 @@ def trace_end():
277 do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)') 329 do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)')
278 do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)') 330 do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)')
279 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') 331 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
332 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
280 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') 333 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
334 if perf_db_export_calls:
335 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
336 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
281 337
282 print datetime.datetime.today(), "Adding foreign keys" 338 print datetime.datetime.today(), "Adding foreign keys"
283 do_query(query, 'ALTER TABLE threads ' 339 do_query(query, 'ALTER TABLE threads '
@@ -299,6 +355,18 @@ def trace_end():
299 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' 355 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
300 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' 356 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
301 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') 357 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
358 if perf_db_export_calls:
359 do_query(query, 'ALTER TABLE call_paths '
360 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
361 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)')
362 do_query(query, 'ALTER TABLE calls '
363 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
364 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
365 'ADD CONSTRAINT call_pathfk FOREIGN KEY (call_path_id) REFERENCES call_paths (id),'
366 'ADD CONSTRAINT callfk FOREIGN KEY (call_id) REFERENCES samples (id),'
367 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),'
368 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
369 do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
302 370
303 if (unhandled_count): 371 if (unhandled_count):
304 print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events" 372 print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
@@ -352,9 +420,25 @@ def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x
352 value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name) 420 value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name)
353 symbol_file.write(value) 421 symbol_file.write(value)
354 422
355def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, *x): 423def branch_type_table(branch_type, name, *x):
424 n = len(name)
425 fmt = "!hiii" + str(n) + "s"
426 value = struct.pack(fmt, 2, 4, branch_type, n, name)
427 branch_type_file.write(value)
428
429def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x):
356 if branches: 430 if branches:
357 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiq", 15, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip) 431 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx)
358 else: 432 else:
359 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiq", 19, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src) 433 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx)
360 sample_file.write(value) 434 sample_file.write(value)
435
436def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
437 fmt = "!hiqiqiqiq"
438 value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip)
439 call_path_file.write(value)
440
441def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, *x):
442 fmt = "!hiqiqiqiqiqiqiqiqiqiqii"
443 value = struct.pack(fmt, 11, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags)
444 call_file.write(value)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 2e7c68e39330..dd2a3e52ada1 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -15,6 +15,8 @@
15#include "debug.h" 15#include "debug.h"
16#include "session.h" 16#include "session.h"
17#include "tool.h" 17#include "tool.h"
18#include "header.h"
19#include "vdso.h"
18 20
19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 21int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 22 union perf_event *event,
@@ -105,3 +107,335 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
105 build_id_hex, build_id_hex + 2); 107 build_id_hex, build_id_hex + 2);
106 return bf; 108 return bf;
107} 109}
110
111#define dsos__for_each_with_build_id(pos, head) \
112 list_for_each_entry(pos, head, node) \
113 if (!pos->has_build_id) \
114 continue; \
115 else
116
117static int write_buildid(const char *name, size_t name_len, u8 *build_id,
118 pid_t pid, u16 misc, int fd)
119{
120 int err;
121 struct build_id_event b;
122 size_t len;
123
124 len = name_len + 1;
125 len = PERF_ALIGN(len, NAME_ALIGN);
126
127 memset(&b, 0, sizeof(b));
128 memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
129 b.pid = pid;
130 b.header.misc = misc;
131 b.header.size = sizeof(b) + len;
132
133 err = writen(fd, &b, sizeof(b));
134 if (err < 0)
135 return err;
136
137 return write_padded(fd, name, name_len + 1, len);
138}
139
140static int __dsos__write_buildid_table(struct list_head *head,
141 struct machine *machine,
142 pid_t pid, u16 misc, int fd)
143{
144 char nm[PATH_MAX];
145 struct dso *pos;
146
147 dsos__for_each_with_build_id(pos, head) {
148 int err;
149 const char *name;
150 size_t name_len;
151
152 if (!pos->hit)
153 continue;
154
155 if (dso__is_vdso(pos)) {
156 name = pos->short_name;
157 name_len = pos->short_name_len + 1;
158 } else if (dso__is_kcore(pos)) {
159 machine__mmap_name(machine, nm, sizeof(nm));
160 name = nm;
161 name_len = strlen(nm) + 1;
162 } else {
163 name = pos->long_name;
164 name_len = pos->long_name_len + 1;
165 }
166
167 err = write_buildid(name, name_len, pos->build_id,
168 pid, misc, fd);
169 if (err)
170 return err;
171 }
172
173 return 0;
174}
175
176static int machine__write_buildid_table(struct machine *machine, int fd)
177{
178 int err;
179 u16 kmisc = PERF_RECORD_MISC_KERNEL,
180 umisc = PERF_RECORD_MISC_USER;
181
182 if (!machine__is_host(machine)) {
183 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
184 umisc = PERF_RECORD_MISC_GUEST_USER;
185 }
186
187 err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
188 machine->pid, kmisc, fd);
189 if (err == 0)
190 err = __dsos__write_buildid_table(&machine->user_dsos.head,
191 machine, machine->pid, umisc,
192 fd);
193 return err;
194}
195
196int perf_session__write_buildid_table(struct perf_session *session, int fd)
197{
198 struct rb_node *nd;
199 int err = machine__write_buildid_table(&session->machines.host, fd);
200
201 if (err)
202 return err;
203
204 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
205 struct machine *pos = rb_entry(nd, struct machine, rb_node);
206 err = machine__write_buildid_table(pos, fd);
207 if (err)
208 break;
209 }
210 return err;
211}
212
213static int __dsos__hit_all(struct list_head *head)
214{
215 struct dso *pos;
216
217 list_for_each_entry(pos, head, node)
218 pos->hit = true;
219
220 return 0;
221}
222
223static int machine__hit_all_dsos(struct machine *machine)
224{
225 int err;
226
227 err = __dsos__hit_all(&machine->kernel_dsos.head);
228 if (err)
229 return err;
230
231 return __dsos__hit_all(&machine->user_dsos.head);
232}
233
234int dsos__hit_all(struct perf_session *session)
235{
236 struct rb_node *nd;
237 int err;
238
239 err = machine__hit_all_dsos(&session->machines.host);
240 if (err)
241 return err;
242
243 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
244 struct machine *pos = rb_entry(nd, struct machine, rb_node);
245
246 err = machine__hit_all_dsos(pos);
247 if (err)
248 return err;
249 }
250
251 return 0;
252}
253
254int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
255 const char *name, bool is_kallsyms, bool is_vdso)
256{
257 const size_t size = PATH_MAX;
258 char *realname, *filename = zalloc(size),
259 *linkname = zalloc(size), *targetname;
260 int len, err = -1;
261 bool slash = is_kallsyms || is_vdso;
262
263 if (is_kallsyms) {
264 if (symbol_conf.kptr_restrict) {
265 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
266 err = 0;
267 goto out_free;
268 }
269 realname = (char *) name;
270 } else
271 realname = realpath(name, NULL);
272
273 if (realname == NULL || filename == NULL || linkname == NULL)
274 goto out_free;
275
276 len = scnprintf(filename, size, "%s%s%s",
277 debugdir, slash ? "/" : "",
278 is_vdso ? DSO__NAME_VDSO : realname);
279 if (mkdir_p(filename, 0755))
280 goto out_free;
281
282 snprintf(filename + len, size - len, "/%s", sbuild_id);
283
284 if (access(filename, F_OK)) {
285 if (is_kallsyms) {
286 if (copyfile("/proc/kallsyms", filename))
287 goto out_free;
288 } else if (link(realname, filename) && copyfile(name, filename))
289 goto out_free;
290 }
291
292 len = scnprintf(linkname, size, "%s/.build-id/%.2s",
293 debugdir, sbuild_id);
294
295 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
296 goto out_free;
297
298 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
299 targetname = filename + strlen(debugdir) - 5;
300 memcpy(targetname, "../..", 5);
301
302 if (symlink(targetname, linkname) == 0)
303 err = 0;
304out_free:
305 if (!is_kallsyms)
306 free(realname);
307 free(filename);
308 free(linkname);
309 return err;
310}
311
312static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
313 const char *name, const char *debugdir,
314 bool is_kallsyms, bool is_vdso)
315{
316 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
317
318 build_id__sprintf(build_id, build_id_size, sbuild_id);
319
320 return build_id_cache__add_s(sbuild_id, debugdir, name,
321 is_kallsyms, is_vdso);
322}
323
324int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
325{
326 const size_t size = PATH_MAX;
327 char *filename = zalloc(size),
328 *linkname = zalloc(size);
329 int err = -1;
330
331 if (filename == NULL || linkname == NULL)
332 goto out_free;
333
334 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
335 debugdir, sbuild_id, sbuild_id + 2);
336
337 if (access(linkname, F_OK))
338 goto out_free;
339
340 if (readlink(linkname, filename, size - 1) < 0)
341 goto out_free;
342
343 if (unlink(linkname))
344 goto out_free;
345
346 /*
347 * Since the link is relative, we must make it absolute:
348 */
349 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
350 debugdir, sbuild_id, filename);
351
352 if (unlink(linkname))
353 goto out_free;
354
355 err = 0;
356out_free:
357 free(filename);
358 free(linkname);
359 return err;
360}
361
362static int dso__cache_build_id(struct dso *dso, struct machine *machine,
363 const char *debugdir)
364{
365 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
366 bool is_vdso = dso__is_vdso(dso);
367 const char *name = dso->long_name;
368 char nm[PATH_MAX];
369
370 if (dso__is_kcore(dso)) {
371 is_kallsyms = true;
372 machine__mmap_name(machine, nm, sizeof(nm));
373 name = nm;
374 }
375 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
376 debugdir, is_kallsyms, is_vdso);
377}
378
379static int __dsos__cache_build_ids(struct list_head *head,
380 struct machine *machine, const char *debugdir)
381{
382 struct dso *pos;
383 int err = 0;
384
385 dsos__for_each_with_build_id(pos, head)
386 if (dso__cache_build_id(pos, machine, debugdir))
387 err = -1;
388
389 return err;
390}
391
392static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
393{
394 int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
395 debugdir);
396 ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
397 debugdir);
398 return ret;
399}
400
401int perf_session__cache_build_ids(struct perf_session *session)
402{
403 struct rb_node *nd;
404 int ret;
405 char debugdir[PATH_MAX];
406
407 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
408
409 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
410 return -1;
411
412 ret = machine__cache_build_ids(&session->machines.host, debugdir);
413
414 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
415 struct machine *pos = rb_entry(nd, struct machine, rb_node);
416 ret |= machine__cache_build_ids(pos, debugdir);
417 }
418 return ret ? -1 : 0;
419}
420
421static bool machine__read_build_ids(struct machine *machine, bool with_hits)
422{
423 bool ret;
424
425 ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
426 ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
427 return ret;
428}
429
430bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
431{
432 struct rb_node *nd;
433 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
434
435 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
436 struct machine *pos = rb_entry(nd, struct machine, rb_node);
437 ret |= machine__read_build_ids(pos, with_hits);
438 }
439
440 return ret;
441}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index ae392561470b..666a3bd4f64e 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -15,4 +15,15 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel, 16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine); 17 struct machine *machine);
18
19int dsos__hit_all(struct perf_session *session);
20
21bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
22int perf_session__write_buildid_table(struct perf_session *session, int fd);
23int perf_session__cache_build_ids(struct perf_session *session);
24
25int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
26 const char *name, bool is_kallsyms, bool is_vdso);
27int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
28
18#endif 29#endif
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index be128b075a32..c81dae399763 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -21,16 +21,76 @@
21#include "comm.h" 21#include "comm.h"
22#include "symbol.h" 22#include "symbol.h"
23#include "event.h" 23#include "event.h"
24#include "util.h"
25#include "thread-stack.h"
24#include "db-export.h" 26#include "db-export.h"
25 27
28struct deferred_export {
29 struct list_head node;
30 struct comm *comm;
31};
32
33static int db_export__deferred(struct db_export *dbe)
34{
35 struct deferred_export *de;
36 int err;
37
38 while (!list_empty(&dbe->deferred)) {
39 de = list_entry(dbe->deferred.next, struct deferred_export,
40 node);
41 err = dbe->export_comm(dbe, de->comm);
42 list_del(&de->node);
43 free(de);
44 if (err)
45 return err;
46 }
47
48 return 0;
49}
50
51static void db_export__free_deferred(struct db_export *dbe)
52{
53 struct deferred_export *de;
54
55 while (!list_empty(&dbe->deferred)) {
56 de = list_entry(dbe->deferred.next, struct deferred_export,
57 node);
58 list_del(&de->node);
59 free(de);
60 }
61}
62
63static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
64{
65 struct deferred_export *de;
66
67 de = zalloc(sizeof(struct deferred_export));
68 if (!de)
69 return -ENOMEM;
70
71 de->comm = comm;
72 list_add_tail(&de->node, &dbe->deferred);
73
74 return 0;
75}
76
26int db_export__init(struct db_export *dbe) 77int db_export__init(struct db_export *dbe)
27{ 78{
28 memset(dbe, 0, sizeof(struct db_export)); 79 memset(dbe, 0, sizeof(struct db_export));
80 INIT_LIST_HEAD(&dbe->deferred);
29 return 0; 81 return 0;
30} 82}
31 83
32void db_export__exit(struct db_export *dbe __maybe_unused) 84int db_export__flush(struct db_export *dbe)
85{
86 return db_export__deferred(dbe);
87}
88
89void db_export__exit(struct db_export *dbe)
33{ 90{
91 db_export__free_deferred(dbe);
92 call_return_processor__free(dbe->crp);
93 dbe->crp = NULL;
34} 94}
35 95
36int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) 96int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
@@ -112,7 +172,10 @@ int db_export__comm(struct db_export *dbe, struct comm *comm,
112 comm->db_id = ++dbe->comm_last_db_id; 172 comm->db_id = ++dbe->comm_last_db_id;
113 173
114 if (dbe->export_comm) { 174 if (dbe->export_comm) {
115 err = dbe->export_comm(dbe, comm); 175 if (main_thread->comm_set)
176 err = dbe->export_comm(dbe, comm);
177 else
178 err = db_export__defer_comm(dbe, comm);
116 if (err) 179 if (err)
117 return err; 180 return err;
118 } 181 }
@@ -208,6 +271,15 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
208 return 0; 271 return 0;
209} 272}
210 273
274int db_export__branch_type(struct db_export *dbe, u32 branch_type,
275 const char *name)
276{
277 if (dbe->export_branch_type)
278 return dbe->export_branch_type(dbe, branch_type, name);
279
280 return 0;
281}
282
211int db_export__sample(struct db_export *dbe, union perf_event *event, 283int db_export__sample(struct db_export *dbe, union perf_event *event,
212 struct perf_sample *sample, struct perf_evsel *evsel, 284 struct perf_sample *sample, struct perf_evsel *evsel,
213 struct thread *thread, struct addr_location *al) 285 struct thread *thread, struct addr_location *al)
@@ -261,6 +333,13 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
261 &es.addr_sym_db_id, &es.addr_offset); 333 &es.addr_sym_db_id, &es.addr_offset);
262 if (err) 334 if (err)
263 return err; 335 return err;
336 if (dbe->crp) {
337 err = thread_stack__process(thread, comm, sample, al,
338 &addr_al, es.db_id,
339 dbe->crp);
340 if (err)
341 return err;
342 }
264 } 343 }
265 344
266 if (dbe->export_sample) 345 if (dbe->export_sample)
@@ -268,3 +347,82 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
268 347
269 return 0; 348 return 0;
270} 349}
350
351static struct {
352 u32 branch_type;
353 const char *name;
354} branch_types[] = {
355 {0, "no branch"},
356 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
357 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
358 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
359 {PERF_IP_FLAG_BRANCH, "unconditional jump"},
360 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
361 "software interrupt"},
362 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
363 "return from interrupt"},
364 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
365 "system call"},
366 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
367 "return from system call"},
368 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
369 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
370 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
371 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
372 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
373 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
374 {0, NULL}
375};
376
377int db_export__branch_types(struct db_export *dbe)
378{
379 int i, err = 0;
380
381 for (i = 0; branch_types[i].name ; i++) {
382 err = db_export__branch_type(dbe, branch_types[i].branch_type,
383 branch_types[i].name);
384 if (err)
385 break;
386 }
387 return err;
388}
389
390int db_export__call_path(struct db_export *dbe, struct call_path *cp)
391{
392 int err;
393
394 if (cp->db_id)
395 return 0;
396
397 if (cp->parent) {
398 err = db_export__call_path(dbe, cp->parent);
399 if (err)
400 return err;
401 }
402
403 cp->db_id = ++dbe->call_path_last_db_id;
404
405 if (dbe->export_call_path)
406 return dbe->export_call_path(dbe, cp);
407
408 return 0;
409}
410
411int db_export__call_return(struct db_export *dbe, struct call_return *cr)
412{
413 int err;
414
415 if (cr->db_id)
416 return 0;
417
418 err = db_export__call_path(dbe, cr->cp);
419 if (err)
420 return err;
421
422 cr->db_id = ++dbe->call_return_last_db_id;
423
424 if (dbe->export_call_return)
425 return dbe->export_call_return(dbe, cr);
426
427 return 0;
428}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index b3643e8e5750..adbd22d66798 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -17,6 +17,7 @@
17#define __PERF_DB_EXPORT_H 17#define __PERF_DB_EXPORT_H
18 18
19#include <linux/types.h> 19#include <linux/types.h>
20#include <linux/list.h>
20 21
21struct perf_evsel; 22struct perf_evsel;
22struct machine; 23struct machine;
@@ -25,6 +26,9 @@ struct comm;
25struct dso; 26struct dso;
26struct perf_sample; 27struct perf_sample;
27struct addr_location; 28struct addr_location;
29struct call_return_processor;
30struct call_path;
31struct call_return;
28 32
29struct export_sample { 33struct export_sample {
30 union perf_event *event; 34 union perf_event *event;
@@ -54,7 +58,13 @@ struct db_export {
54 struct machine *machine); 58 struct machine *machine);
55 int (*export_symbol)(struct db_export *dbe, struct symbol *sym, 59 int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
56 struct dso *dso); 60 struct dso *dso);
61 int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
62 const char *name);
57 int (*export_sample)(struct db_export *dbe, struct export_sample *es); 63 int (*export_sample)(struct db_export *dbe, struct export_sample *es);
64 int (*export_call_path)(struct db_export *dbe, struct call_path *cp);
65 int (*export_call_return)(struct db_export *dbe,
66 struct call_return *cr);
67 struct call_return_processor *crp;
58 u64 evsel_last_db_id; 68 u64 evsel_last_db_id;
59 u64 machine_last_db_id; 69 u64 machine_last_db_id;
60 u64 thread_last_db_id; 70 u64 thread_last_db_id;
@@ -63,9 +73,13 @@ struct db_export {
63 u64 dso_last_db_id; 73 u64 dso_last_db_id;
64 u64 symbol_last_db_id; 74 u64 symbol_last_db_id;
65 u64 sample_last_db_id; 75 u64 sample_last_db_id;
76 u64 call_path_last_db_id;
77 u64 call_return_last_db_id;
78 struct list_head deferred;
66}; 79};
67 80
68int db_export__init(struct db_export *dbe); 81int db_export__init(struct db_export *dbe);
82int db_export__flush(struct db_export *dbe);
69void db_export__exit(struct db_export *dbe); 83void db_export__exit(struct db_export *dbe);
70int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel); 84int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
71int db_export__machine(struct db_export *dbe, struct machine *machine); 85int db_export__machine(struct db_export *dbe, struct machine *machine);
@@ -79,8 +93,15 @@ int db_export__dso(struct db_export *dbe, struct dso *dso,
79 struct machine *machine); 93 struct machine *machine);
80int db_export__symbol(struct db_export *dbe, struct symbol *sym, 94int db_export__symbol(struct db_export *dbe, struct symbol *sym,
81 struct dso *dso); 95 struct dso *dso);
96int db_export__branch_type(struct db_export *dbe, u32 branch_type,
97 const char *name);
82int db_export__sample(struct db_export *dbe, union perf_event *event, 98int db_export__sample(struct db_export *dbe, union perf_event *event,
83 struct perf_sample *sample, struct perf_evsel *evsel, 99 struct perf_sample *sample, struct perf_evsel *evsel,
84 struct thread *thread, struct addr_location *al); 100 struct thread *thread, struct addr_location *al);
85 101
102int db_export__branch_types(struct db_export *dbe);
103
104int db_export__call_path(struct db_export *dbe, struct call_path *cp);
105int db_export__call_return(struct db_export *dbe, struct call_return *cr);
106
86#endif 107#endif
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 0247acfdfaca..45be944d450a 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
21 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', 21 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
22 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', 22 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
23 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', 23 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
24 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm',
24 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', 25 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
25 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', 26 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
27 [DSO_BINARY_TYPE__GUEST_KMODULE_COMP] = 'M',
26 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', 28 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
27 }; 29 };
28 30
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
112 break; 114 break;
113 115
114 case DSO_BINARY_TYPE__GUEST_KMODULE: 116 case DSO_BINARY_TYPE__GUEST_KMODULE:
117 case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
115 path__join3(filename, size, symbol_conf.symfs, 118 path__join3(filename, size, symbol_conf.symfs,
116 root_dir, dso->long_name); 119 root_dir, dso->long_name);
117 break; 120 break;
118 121
119 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 122 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
123 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
120 __symbol__join_symfs(filename, size, dso->long_name); 124 __symbol__join_symfs(filename, size, dso->long_name);
121 break; 125 break;
122 126
@@ -137,6 +141,73 @@ int dso__read_binary_type_filename(const struct dso *dso,
137 return ret; 141 return ret;
138} 142}
139 143
144static const struct {
145 const char *fmt;
146 int (*decompress)(const char *input, int output);
147} compressions[] = {
148#ifdef HAVE_ZLIB_SUPPORT
149 { "gz", gzip_decompress_to_file },
150#endif
151 { NULL, NULL },
152};
153
154bool is_supported_compression(const char *ext)
155{
156 unsigned i;
157
158 for (i = 0; compressions[i].fmt; i++) {
159 if (!strcmp(ext, compressions[i].fmt))
160 return true;
161 }
162 return false;
163}
164
165bool is_kmodule_extension(const char *ext)
166{
167 if (strncmp(ext, "ko", 2))
168 return false;
169
170 if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
171 return true;
172
173 return false;
174}
175
176bool is_kernel_module(const char *pathname, bool *compressed)
177{
178 const char *ext = strrchr(pathname, '.');
179
180 if (ext == NULL)
181 return false;
182
183 if (is_supported_compression(ext + 1)) {
184 if (compressed)
185 *compressed = true;
186 ext -= 3;
187 } else if (compressed)
188 *compressed = false;
189
190 return is_kmodule_extension(ext + 1);
191}
192
193bool decompress_to_file(const char *ext, const char *filename, int output_fd)
194{
195 unsigned i;
196
197 for (i = 0; compressions[i].fmt; i++) {
198 if (!strcmp(ext, compressions[i].fmt))
199 return !compressions[i].decompress(filename,
200 output_fd);
201 }
202 return false;
203}
204
205bool dso__needs_decompress(struct dso *dso)
206{
207 return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
208 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
209}
210
140/* 211/*
141 * Global list of open DSOs and the counter. 212 * Global list of open DSOs and the counter.
142 */ 213 */
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index a316e4af321f..3782c82c6e44 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -22,7 +22,9 @@ enum dso_binary_type {
22 DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 22 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
23 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 23 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
24 DSO_BINARY_TYPE__GUEST_KMODULE, 24 DSO_BINARY_TYPE__GUEST_KMODULE,
25 DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
25 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 26 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
27 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
26 DSO_BINARY_TYPE__KCORE, 28 DSO_BINARY_TYPE__KCORE,
27 DSO_BINARY_TYPE__GUEST_KCORE, 29 DSO_BINARY_TYPE__GUEST_KCORE,
28 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 30 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
185char dso__symtab_origin(const struct dso *dso); 187char dso__symtab_origin(const struct dso *dso);
186int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 188int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
187 char *root_dir, char *filename, size_t size); 189 char *root_dir, char *filename, size_t size);
190bool is_supported_compression(const char *ext);
191bool is_kmodule_extension(const char *ext);
192bool is_kernel_module(const char *pathname, bool *compressed);
193bool decompress_to_file(const char *ext, const char *filename, int output_fd);
194bool dso__needs_decompress(struct dso *dso);
188 195
189/* 196/*
190 * The dso__data_* external interface provides following functions: 197 * The dso__data_* external interface provides following functions:
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 8c7fe9d64e79..7be389735402 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -143,6 +143,32 @@ struct branch_stack {
143 struct branch_entry entries[0]; 143 struct branch_entry entries[0];
144}; 144};
145 145
146enum {
147 PERF_IP_FLAG_BRANCH = 1ULL << 0,
148 PERF_IP_FLAG_CALL = 1ULL << 1,
149 PERF_IP_FLAG_RETURN = 1ULL << 2,
150 PERF_IP_FLAG_CONDITIONAL = 1ULL << 3,
151 PERF_IP_FLAG_SYSCALLRET = 1ULL << 4,
152 PERF_IP_FLAG_ASYNC = 1ULL << 5,
153 PERF_IP_FLAG_INTERRUPT = 1ULL << 6,
154 PERF_IP_FLAG_TX_ABORT = 1ULL << 7,
155 PERF_IP_FLAG_TRACE_BEGIN = 1ULL << 8,
156 PERF_IP_FLAG_TRACE_END = 1ULL << 9,
157 PERF_IP_FLAG_IN_TX = 1ULL << 10,
158};
159
160#define PERF_BRANCH_MASK (\
161 PERF_IP_FLAG_BRANCH |\
162 PERF_IP_FLAG_CALL |\
163 PERF_IP_FLAG_RETURN |\
164 PERF_IP_FLAG_CONDITIONAL |\
165 PERF_IP_FLAG_SYSCALLRET |\
166 PERF_IP_FLAG_ASYNC |\
167 PERF_IP_FLAG_INTERRUPT |\
168 PERF_IP_FLAG_TX_ABORT |\
169 PERF_IP_FLAG_TRACE_BEGIN |\
170 PERF_IP_FLAG_TRACE_END)
171
146struct perf_sample { 172struct perf_sample {
147 u64 ip; 173 u64 ip;
148 u32 pid, tid; 174 u32 pid, tid;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2f9e68025ede..12b4396c7175 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -853,8 +853,6 @@ void perf_evsel__exit(struct perf_evsel *evsel)
853 perf_evsel__free_id(evsel); 853 perf_evsel__free_id(evsel);
854 close_cgroup(evsel->cgrp); 854 close_cgroup(evsel->cgrp);
855 zfree(&evsel->group_name); 855 zfree(&evsel->group_name);
856 if (evsel->tp_format)
857 pevent_free_format(evsel->tp_format);
858 zfree(&evsel->name); 856 zfree(&evsel->name);
859 perf_evsel__object.fini(evsel); 857 perf_evsel__object.fini(evsel);
860} 858}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 0ecf4a304cbc..76442caca37e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -79,10 +79,7 @@ static int do_write(int fd, const void *buf, size_t size)
79 return 0; 79 return 0;
80} 80}
81 81
82#define NAME_ALIGN 64 82int write_padded(int fd, const void *bf, size_t count, size_t count_aligned)
83
84static int write_padded(int fd, const void *bf, size_t count,
85 size_t count_aligned)
86{ 83{
87 static const char zero_buf[NAME_ALIGN]; 84 static const char zero_buf[NAME_ALIGN];
88 int err = do_write(fd, bf, count); 85 int err = do_write(fd, bf, count);
@@ -171,340 +168,6 @@ perf_header__set_cmdline(int argc, const char **argv)
171 return 0; 168 return 0;
172} 169}
173 170
174#define dsos__for_each_with_build_id(pos, head) \
175 list_for_each_entry(pos, head, node) \
176 if (!pos->has_build_id) \
177 continue; \
178 else
179
180static int write_buildid(const char *name, size_t name_len, u8 *build_id,
181 pid_t pid, u16 misc, int fd)
182{
183 int err;
184 struct build_id_event b;
185 size_t len;
186
187 len = name_len + 1;
188 len = PERF_ALIGN(len, NAME_ALIGN);
189
190 memset(&b, 0, sizeof(b));
191 memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
192 b.pid = pid;
193 b.header.misc = misc;
194 b.header.size = sizeof(b) + len;
195
196 err = do_write(fd, &b, sizeof(b));
197 if (err < 0)
198 return err;
199
200 return write_padded(fd, name, name_len + 1, len);
201}
202
203static int __dsos__hit_all(struct list_head *head)
204{
205 struct dso *pos;
206
207 list_for_each_entry(pos, head, node)
208 pos->hit = true;
209
210 return 0;
211}
212
213static int machine__hit_all_dsos(struct machine *machine)
214{
215 int err;
216
217 err = __dsos__hit_all(&machine->kernel_dsos.head);
218 if (err)
219 return err;
220
221 return __dsos__hit_all(&machine->user_dsos.head);
222}
223
224int dsos__hit_all(struct perf_session *session)
225{
226 struct rb_node *nd;
227 int err;
228
229 err = machine__hit_all_dsos(&session->machines.host);
230 if (err)
231 return err;
232
233 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
234 struct machine *pos = rb_entry(nd, struct machine, rb_node);
235
236 err = machine__hit_all_dsos(pos);
237 if (err)
238 return err;
239 }
240
241 return 0;
242}
243
244static int __dsos__write_buildid_table(struct list_head *head,
245 struct machine *machine,
246 pid_t pid, u16 misc, int fd)
247{
248 char nm[PATH_MAX];
249 struct dso *pos;
250
251 dsos__for_each_with_build_id(pos, head) {
252 int err;
253 const char *name;
254 size_t name_len;
255
256 if (!pos->hit)
257 continue;
258
259 if (dso__is_vdso(pos)) {
260 name = pos->short_name;
261 name_len = pos->short_name_len + 1;
262 } else if (dso__is_kcore(pos)) {
263 machine__mmap_name(machine, nm, sizeof(nm));
264 name = nm;
265 name_len = strlen(nm) + 1;
266 } else {
267 name = pos->long_name;
268 name_len = pos->long_name_len + 1;
269 }
270
271 err = write_buildid(name, name_len, pos->build_id,
272 pid, misc, fd);
273 if (err)
274 return err;
275 }
276
277 return 0;
278}
279
280static int machine__write_buildid_table(struct machine *machine, int fd)
281{
282 int err;
283 u16 kmisc = PERF_RECORD_MISC_KERNEL,
284 umisc = PERF_RECORD_MISC_USER;
285
286 if (!machine__is_host(machine)) {
287 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
288 umisc = PERF_RECORD_MISC_GUEST_USER;
289 }
290
291 err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
292 machine->pid, kmisc, fd);
293 if (err == 0)
294 err = __dsos__write_buildid_table(&machine->user_dsos.head,
295 machine, machine->pid, umisc,
296 fd);
297 return err;
298}
299
300static int dsos__write_buildid_table(struct perf_header *header, int fd)
301{
302 struct perf_session *session = container_of(header,
303 struct perf_session, header);
304 struct rb_node *nd;
305 int err = machine__write_buildid_table(&session->machines.host, fd);
306
307 if (err)
308 return err;
309
310 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
311 struct machine *pos = rb_entry(nd, struct machine, rb_node);
312 err = machine__write_buildid_table(pos, fd);
313 if (err)
314 break;
315 }
316 return err;
317}
318
319int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
320 const char *name, bool is_kallsyms, bool is_vdso)
321{
322 const size_t size = PATH_MAX;
323 char *realname, *filename = zalloc(size),
324 *linkname = zalloc(size), *targetname;
325 int len, err = -1;
326 bool slash = is_kallsyms || is_vdso;
327
328 if (is_kallsyms) {
329 if (symbol_conf.kptr_restrict) {
330 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
331 err = 0;
332 goto out_free;
333 }
334 realname = (char *) name;
335 } else
336 realname = realpath(name, NULL);
337
338 if (realname == NULL || filename == NULL || linkname == NULL)
339 goto out_free;
340
341 len = scnprintf(filename, size, "%s%s%s",
342 debugdir, slash ? "/" : "",
343 is_vdso ? DSO__NAME_VDSO : realname);
344 if (mkdir_p(filename, 0755))
345 goto out_free;
346
347 snprintf(filename + len, size - len, "/%s", sbuild_id);
348
349 if (access(filename, F_OK)) {
350 if (is_kallsyms) {
351 if (copyfile("/proc/kallsyms", filename))
352 goto out_free;
353 } else if (link(realname, filename) && copyfile(name, filename))
354 goto out_free;
355 }
356
357 len = scnprintf(linkname, size, "%s/.build-id/%.2s",
358 debugdir, sbuild_id);
359
360 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
361 goto out_free;
362
363 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
364 targetname = filename + strlen(debugdir) - 5;
365 memcpy(targetname, "../..", 5);
366
367 if (symlink(targetname, linkname) == 0)
368 err = 0;
369out_free:
370 if (!is_kallsyms)
371 free(realname);
372 free(filename);
373 free(linkname);
374 return err;
375}
376
377static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
378 const char *name, const char *debugdir,
379 bool is_kallsyms, bool is_vdso)
380{
381 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
382
383 build_id__sprintf(build_id, build_id_size, sbuild_id);
384
385 return build_id_cache__add_s(sbuild_id, debugdir, name,
386 is_kallsyms, is_vdso);
387}
388
389int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
390{
391 const size_t size = PATH_MAX;
392 char *filename = zalloc(size),
393 *linkname = zalloc(size);
394 int err = -1;
395
396 if (filename == NULL || linkname == NULL)
397 goto out_free;
398
399 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
400 debugdir, sbuild_id, sbuild_id + 2);
401
402 if (access(linkname, F_OK))
403 goto out_free;
404
405 if (readlink(linkname, filename, size - 1) < 0)
406 goto out_free;
407
408 if (unlink(linkname))
409 goto out_free;
410
411 /*
412 * Since the link is relative, we must make it absolute:
413 */
414 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
415 debugdir, sbuild_id, filename);
416
417 if (unlink(linkname))
418 goto out_free;
419
420 err = 0;
421out_free:
422 free(filename);
423 free(linkname);
424 return err;
425}
426
427static int dso__cache_build_id(struct dso *dso, struct machine *machine,
428 const char *debugdir)
429{
430 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
431 bool is_vdso = dso__is_vdso(dso);
432 const char *name = dso->long_name;
433 char nm[PATH_MAX];
434
435 if (dso__is_kcore(dso)) {
436 is_kallsyms = true;
437 machine__mmap_name(machine, nm, sizeof(nm));
438 name = nm;
439 }
440 return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
441 debugdir, is_kallsyms, is_vdso);
442}
443
444static int __dsos__cache_build_ids(struct list_head *head,
445 struct machine *machine, const char *debugdir)
446{
447 struct dso *pos;
448 int err = 0;
449
450 dsos__for_each_with_build_id(pos, head)
451 if (dso__cache_build_id(pos, machine, debugdir))
452 err = -1;
453
454 return err;
455}
456
457static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
458{
459 int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
460 debugdir);
461 ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
462 debugdir);
463 return ret;
464}
465
466static int perf_session__cache_build_ids(struct perf_session *session)
467{
468 struct rb_node *nd;
469 int ret;
470 char debugdir[PATH_MAX];
471
472 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
473
474 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
475 return -1;
476
477 ret = machine__cache_build_ids(&session->machines.host, debugdir);
478
479 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
480 struct machine *pos = rb_entry(nd, struct machine, rb_node);
481 ret |= machine__cache_build_ids(pos, debugdir);
482 }
483 return ret ? -1 : 0;
484}
485
486static bool machine__read_build_ids(struct machine *machine, bool with_hits)
487{
488 bool ret;
489
490 ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
491 ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
492 return ret;
493}
494
495static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
496{
497 struct rb_node *nd;
498 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
499
500 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
501 struct machine *pos = rb_entry(nd, struct machine, rb_node);
502 ret |= machine__read_build_ids(pos, with_hits);
503 }
504
505 return ret;
506}
507
508static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, 171static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
509 struct perf_evlist *evlist) 172 struct perf_evlist *evlist)
510{ 173{
@@ -523,7 +186,7 @@ static int write_build_id(int fd, struct perf_header *h,
523 if (!perf_session__read_build_ids(session, true)) 186 if (!perf_session__read_build_ids(session, true))
524 return -1; 187 return -1;
525 188
526 err = dsos__write_buildid_table(h, fd); 189 err = perf_session__write_buildid_table(session, fd);
527 if (err < 0) { 190 if (err < 0) {
528 pr_debug("failed to write buildid table\n"); 191 pr_debug("failed to write buildid table\n");
529 return err; 192 return err;
@@ -1606,7 +1269,7 @@ static int __event_process_build_id(struct build_id_event *bev,
1606 1269
1607 dso__set_build_id(dso, &bev->build_id); 1270 dso__set_build_id(dso, &bev->build_id);
1608 1271
1609 if (filename[0] == '[') 1272 if (!is_kernel_module(filename, NULL))
1610 dso->kernel = dso_type; 1273 dso->kernel = dso_type;
1611 1274
1612 build_id__sprintf(dso->build_id, sizeof(dso->build_id), 1275 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 8f5cbaea64a5..3bb90ac172a1 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -122,10 +122,6 @@ int perf_header__process_sections(struct perf_header *header, int fd,
122 122
123int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); 123int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
124 124
125int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
126 const char *name, bool is_kallsyms, bool is_vdso);
127int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
128
129int perf_event__synthesize_attr(struct perf_tool *tool, 125int perf_event__synthesize_attr(struct perf_tool *tool,
130 struct perf_event_attr *attr, u32 ids, u64 *id, 126 struct perf_event_attr *attr, u32 ids, u64 *id,
131 perf_event__handler_t process); 127 perf_event__handler_t process);
@@ -151,7 +147,9 @@ int perf_event__process_build_id(struct perf_tool *tool,
151 struct perf_session *session); 147 struct perf_session *session);
152bool is_perf_magic(u64 magic); 148bool is_perf_magic(u64 magic);
153 149
154int dsos__hit_all(struct perf_session *session); 150#define NAME_ALIGN 64
151
152int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
155 153
156/* 154/*
157 * arch specific callback 155 * arch specific callback
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 01ffd12dc791..40bd21488032 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -46,4 +46,21 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
46 __bitmap_or(dst, src1, src2, nbits); 46 __bitmap_or(dst, src1, src2, nbits);
47} 47}
48 48
49/**
50 * test_and_set_bit - Set a bit and return its old value
51 * @nr: Bit to set
52 * @addr: Address to count from
53 */
54static inline int test_and_set_bit(int nr, unsigned long *addr)
55{
56 unsigned long mask = BIT_MASK(nr);
57 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
58 unsigned long old;
59
60 old = *p;
61 *p = old | mask;
62
63 return (old & mask) != 0;
64}
65
49#endif /* _PERF_BITOPS_H */ 66#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index dadfa7e54287..c3294163de17 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,6 +15,8 @@
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) 15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) 16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) 17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
18#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
19#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
18 20
19#define for_each_set_bit(bit, addr, size) \ 21#define for_each_set_bit(bit, addr, size) \
20 for ((bit) = find_first_bit((addr), (size)); \ 22 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 51a630301afa..52e94902afb1 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
464{ 464{
465 struct map *map; 465 struct map *map;
466 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); 466 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
467 bool compressed;
467 468
468 if (dso == NULL) 469 if (dso == NULL)
469 return NULL; 470 return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
476 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; 477 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
477 else 478 else
478 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 479 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
480
481 /* _KMODULE_COMP should be next to _KMODULE */
482 if (is_kernel_module(filename, &compressed) && compressed)
483 dso->symtab_type++;
484
479 map_groups__insert(&machine->kmaps, map); 485 map_groups__insert(&machine->kmaps, map);
480 return map; 486 return map;
481} 487}
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
861 struct map *map; 867 struct map *map;
862 char *long_name; 868 char *long_name;
863 869
864 if (dot == NULL || strcmp(dot, ".ko")) 870 if (dot == NULL)
865 continue; 871 continue;
872
873 /* On some system, modules are compressed like .ko.gz */
874 if (is_supported_compression(dot + 1) &&
875 is_kmodule_extension(dot - 2))
876 dot -= 3;
877
866 snprintf(dso_name, sizeof(dso_name), "[%.*s]", 878 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
867 (int)(dot - dent->d_name), dent->d_name); 879 (int)(dot - dent->d_name), dent->d_name);
868 880
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1044 dot = strrchr(name, '.'); 1056 dot = strrchr(name, '.');
1045 if (dot == NULL) 1057 if (dot == NULL)
1046 goto out_problem; 1058 goto out_problem;
1059 /* On some system, modules are compressed like .ko.gz */
1060 if (is_supported_compression(dot + 1))
1061 dot -= 3;
1062 if (!is_kmodule_extension(dot + 1))
1063 goto out_problem;
1047 snprintf(short_module_name, sizeof(short_module_name), 1064 snprintf(short_module_name, sizeof(short_module_name),
1048 "[%.*s]", (int)(dot - name), name); 1065 "[%.*s]", (int)(dot - name), name);
1049 strxfrchar(short_module_name, '-', '_'); 1066 strxfrchar(short_module_name, '-', '_');
@@ -1068,8 +1085,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1068 * Should be there already, from the build-id table in 1085 * Should be there already, from the build-id table in
1069 * the header. 1086 * the header.
1070 */ 1087 */
1071 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos, 1088 struct dso *kernel = NULL;
1072 kmmap_prefix); 1089 struct dso *dso;
1090
1091 list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
1092 if (is_kernel_module(dso->long_name, NULL))
1093 continue;
1094
1095 kernel = dso;
1096 break;
1097 }
1098
1099 if (kernel == NULL)
1100 kernel = __dsos__findnew(&machine->kernel_dsos,
1101 kmmap_prefix);
1073 if (kernel == NULL) 1102 if (kernel == NULL)
1074 goto out_problem; 1103 goto out_problem;
1075 1104
@@ -1077,6 +1106,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1077 if (__machine__create_kernel_maps(machine, kernel) < 0) 1106 if (__machine__create_kernel_maps(machine, kernel) < 0)
1078 goto out_problem; 1107 goto out_problem;
1079 1108
1109 if (strstr(dso->long_name, "vmlinux"))
1110 dso__set_short_name(dso, "[kernel.vmlinux]", false);
1111
1080 machine__set_kernel_mmap_len(machine, event); 1112 machine__set_kernel_mmap_len(machine, event);
1081 1113
1082 /* 1114 /*
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 0a01bac4ce02..22ebc46226e7 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -24,6 +24,7 @@
24#include <string.h> 24#include <string.h>
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27#include <linux/bitmap.h>
27 28
28#include "../util.h" 29#include "../util.h"
29#include <EXTERN.h> 30#include <EXTERN.h>
@@ -57,7 +58,7 @@ INTERP my_perl;
57#define FTRACE_MAX_EVENT \ 58#define FTRACE_MAX_EVENT \
58 ((1 << (sizeof(unsigned short) * 8)) - 1) 59 ((1 << (sizeof(unsigned short) * 8)) - 1)
59 60
60struct event_format *events[FTRACE_MAX_EVENT]; 61static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
61 62
62extern struct scripting_context *scripting_context; 63extern struct scripting_context *scripting_context;
63 64
@@ -238,35 +239,15 @@ static void define_event_symbols(struct event_format *event,
238 define_event_symbols(event, ev_name, args->next); 239 define_event_symbols(event, ev_name, args->next);
239} 240}
240 241
241static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
242{
243 static char ev_name[256];
244 struct event_format *event;
245 int type = evsel->attr.config;
246
247 if (events[type])
248 return events[type];
249
250 events[type] = event = evsel->tp_format;
251 if (!event)
252 return NULL;
253
254 sprintf(ev_name, "%s::%s", event->system, event->name);
255
256 define_event_symbols(event, ev_name, event->print_fmt.args);
257
258 return event;
259}
260
261static void perl_process_tracepoint(struct perf_sample *sample, 242static void perl_process_tracepoint(struct perf_sample *sample,
262 struct perf_evsel *evsel, 243 struct perf_evsel *evsel,
263 struct thread *thread) 244 struct thread *thread)
264{ 245{
246 struct event_format *event = evsel->tp_format;
265 struct format_field *field; 247 struct format_field *field;
266 static char handler[256]; 248 static char handler[256];
267 unsigned long long val; 249 unsigned long long val;
268 unsigned long s, ns; 250 unsigned long s, ns;
269 struct event_format *event;
270 int pid; 251 int pid;
271 int cpu = sample->cpu; 252 int cpu = sample->cpu;
272 void *data = sample->raw_data; 253 void *data = sample->raw_data;
@@ -278,7 +259,6 @@ static void perl_process_tracepoint(struct perf_sample *sample,
278 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 259 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
279 return; 260 return;
280 261
281 event = find_cache_event(evsel);
282 if (!event) 262 if (!event)
283 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); 263 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
284 264
@@ -286,6 +266,9 @@ static void perl_process_tracepoint(struct perf_sample *sample,
286 266
287 sprintf(handler, "%s::%s", event->system, event->name); 267 sprintf(handler, "%s::%s", event->system, event->name);
288 268
269 if (!test_and_set_bit(event->id, events_defined))
270 define_event_symbols(event, handler, event->print_fmt.args);
271
289 s = nsecs / NSECS_PER_SEC; 272 s = nsecs / NSECS_PER_SEC;
290 ns = nsecs - s * NSECS_PER_SEC; 273 ns = nsecs - s * NSECS_PER_SEC;
291 274
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 2fd7ee8f18c7..d808a328f4dc 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -26,6 +26,7 @@
26#include <string.h> 26#include <string.h>
27#include <stdbool.h> 27#include <stdbool.h>
28#include <errno.h> 28#include <errno.h>
29#include <linux/bitmap.h>
29 30
30#include "../../perf.h" 31#include "../../perf.h"
31#include "../debug.h" 32#include "../debug.h"
@@ -37,6 +38,7 @@
37#include "../comm.h" 38#include "../comm.h"
38#include "../machine.h" 39#include "../machine.h"
39#include "../db-export.h" 40#include "../db-export.h"
41#include "../thread-stack.h"
40#include "../trace-event.h" 42#include "../trace-event.h"
41#include "../machine.h" 43#include "../machine.h"
42 44
@@ -45,7 +47,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
45#define FTRACE_MAX_EVENT \ 47#define FTRACE_MAX_EVENT \
46 ((1 << (sizeof(unsigned short) * 8)) - 1) 48 ((1 << (sizeof(unsigned short) * 8)) - 1)
47 49
48struct event_format *events[FTRACE_MAX_EVENT]; 50static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
49 51
50#define MAX_FIELDS 64 52#define MAX_FIELDS 64
51#define N_COMMON_FIELDS 7 53#define N_COMMON_FIELDS 7
@@ -66,7 +68,10 @@ struct tables {
66 PyObject *comm_thread_handler; 68 PyObject *comm_thread_handler;
67 PyObject *dso_handler; 69 PyObject *dso_handler;
68 PyObject *symbol_handler; 70 PyObject *symbol_handler;
71 PyObject *branch_type_handler;
69 PyObject *sample_handler; 72 PyObject *sample_handler;
73 PyObject *call_path_handler;
74 PyObject *call_return_handler;
70 bool db_export_mode; 75 bool db_export_mode;
71}; 76};
72 77
@@ -251,31 +256,6 @@ static void define_event_symbols(struct event_format *event,
251 define_event_symbols(event, ev_name, args->next); 256 define_event_symbols(event, ev_name, args->next);
252} 257}
253 258
254static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
255{
256 static char ev_name[256];
257 struct event_format *event;
258 int type = evsel->attr.config;
259
260 /*
261 * XXX: Do we really need to cache this since now we have evsel->tp_format
262 * cached already? Need to re-read this "cache" routine that as well calls
263 * define_event_symbols() :-\
264 */
265 if (events[type])
266 return events[type];
267
268 events[type] = event = evsel->tp_format;
269 if (!event)
270 return NULL;
271
272 sprintf(ev_name, "%s__%s", event->system, event->name);
273
274 define_event_symbols(event, ev_name, event->print_fmt.args);
275
276 return event;
277}
278
279static PyObject *get_field_numeric_entry(struct event_format *event, 259static PyObject *get_field_numeric_entry(struct event_format *event,
280 struct format_field *field, void *data) 260 struct format_field *field, void *data)
281{ 261{
@@ -399,12 +379,12 @@ static void python_process_tracepoint(struct perf_sample *sample,
399 struct thread *thread, 379 struct thread *thread,
400 struct addr_location *al) 380 struct addr_location *al)
401{ 381{
382 struct event_format *event = evsel->tp_format;
402 PyObject *handler, *context, *t, *obj, *callchain; 383 PyObject *handler, *context, *t, *obj, *callchain;
403 PyObject *dict = NULL; 384 PyObject *dict = NULL;
404 static char handler_name[256]; 385 static char handler_name[256];
405 struct format_field *field; 386 struct format_field *field;
406 unsigned long s, ns; 387 unsigned long s, ns;
407 struct event_format *event;
408 unsigned n = 0; 388 unsigned n = 0;
409 int pid; 389 int pid;
410 int cpu = sample->cpu; 390 int cpu = sample->cpu;
@@ -416,7 +396,6 @@ static void python_process_tracepoint(struct perf_sample *sample,
416 if (!t) 396 if (!t)
417 Py_FatalError("couldn't create Python tuple"); 397 Py_FatalError("couldn't create Python tuple");
418 398
419 event = find_cache_event(evsel);
420 if (!event) 399 if (!event)
421 die("ug! no event found for type %d", (int)evsel->attr.config); 400 die("ug! no event found for type %d", (int)evsel->attr.config);
422 401
@@ -424,6 +403,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
424 403
425 sprintf(handler_name, "%s__%s", event->system, event->name); 404 sprintf(handler_name, "%s__%s", event->system, event->name);
426 405
406 if (!test_and_set_bit(event->id, events_defined))
407 define_event_symbols(event, handler_name, event->print_fmt.args);
408
427 handler = get_handler(handler_name); 409 handler = get_handler(handler_name);
428 if (!handler) { 410 if (!handler) {
429 dict = PyDict_New(); 411 dict = PyDict_New();
@@ -664,13 +646,31 @@ static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
664 return 0; 646 return 0;
665} 647}
666 648
649static int python_export_branch_type(struct db_export *dbe, u32 branch_type,
650 const char *name)
651{
652 struct tables *tables = container_of(dbe, struct tables, dbe);
653 PyObject *t;
654
655 t = tuple_new(2);
656
657 tuple_set_s32(t, 0, branch_type);
658 tuple_set_string(t, 1, name);
659
660 call_object(tables->branch_type_handler, t, "branch_type_table");
661
662 Py_DECREF(t);
663
664 return 0;
665}
666
667static int python_export_sample(struct db_export *dbe, 667static int python_export_sample(struct db_export *dbe,
668 struct export_sample *es) 668 struct export_sample *es)
669{ 669{
670 struct tables *tables = container_of(dbe, struct tables, dbe); 670 struct tables *tables = container_of(dbe, struct tables, dbe);
671 PyObject *t; 671 PyObject *t;
672 672
673 t = tuple_new(19); 673 t = tuple_new(21);
674 674
675 tuple_set_u64(t, 0, es->db_id); 675 tuple_set_u64(t, 0, es->db_id);
676 tuple_set_u64(t, 1, es->evsel->db_id); 676 tuple_set_u64(t, 1, es->evsel->db_id);
@@ -691,6 +691,8 @@ static int python_export_sample(struct db_export *dbe,
691 tuple_set_u64(t, 16, es->sample->weight); 691 tuple_set_u64(t, 16, es->sample->weight);
692 tuple_set_u64(t, 17, es->sample->transaction); 692 tuple_set_u64(t, 17, es->sample->transaction);
693 tuple_set_u64(t, 18, es->sample->data_src); 693 tuple_set_u64(t, 18, es->sample->data_src);
694 tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
695 tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX));
694 696
695 call_object(tables->sample_handler, t, "sample_table"); 697 call_object(tables->sample_handler, t, "sample_table");
696 698
@@ -699,6 +701,64 @@ static int python_export_sample(struct db_export *dbe,
699 return 0; 701 return 0;
700} 702}
701 703
704static int python_export_call_path(struct db_export *dbe, struct call_path *cp)
705{
706 struct tables *tables = container_of(dbe, struct tables, dbe);
707 PyObject *t;
708 u64 parent_db_id, sym_db_id;
709
710 parent_db_id = cp->parent ? cp->parent->db_id : 0;
711 sym_db_id = cp->sym ? *(u64 *)symbol__priv(cp->sym) : 0;
712
713 t = tuple_new(4);
714
715 tuple_set_u64(t, 0, cp->db_id);
716 tuple_set_u64(t, 1, parent_db_id);
717 tuple_set_u64(t, 2, sym_db_id);
718 tuple_set_u64(t, 3, cp->ip);
719
720 call_object(tables->call_path_handler, t, "call_path_table");
721
722 Py_DECREF(t);
723
724 return 0;
725}
726
727static int python_export_call_return(struct db_export *dbe,
728 struct call_return *cr)
729{
730 struct tables *tables = container_of(dbe, struct tables, dbe);
731 u64 comm_db_id = cr->comm ? cr->comm->db_id : 0;
732 PyObject *t;
733
734 t = tuple_new(11);
735
736 tuple_set_u64(t, 0, cr->db_id);
737 tuple_set_u64(t, 1, cr->thread->db_id);
738 tuple_set_u64(t, 2, comm_db_id);
739 tuple_set_u64(t, 3, cr->cp->db_id);
740 tuple_set_u64(t, 4, cr->call_time);
741 tuple_set_u64(t, 5, cr->return_time);
742 tuple_set_u64(t, 6, cr->branch_count);
743 tuple_set_u64(t, 7, cr->call_ref);
744 tuple_set_u64(t, 8, cr->return_ref);
745 tuple_set_u64(t, 9, cr->cp->parent->db_id);
746 tuple_set_s32(t, 10, cr->flags);
747
748 call_object(tables->call_return_handler, t, "call_return_table");
749
750 Py_DECREF(t);
751
752 return 0;
753}
754
755static int python_process_call_return(struct call_return *cr, void *data)
756{
757 struct db_export *dbe = data;
758
759 return db_export__call_return(dbe, cr);
760}
761
702static void python_process_general_event(struct perf_sample *sample, 762static void python_process_general_event(struct perf_sample *sample,
703 struct perf_evsel *evsel, 763 struct perf_evsel *evsel,
704 struct thread *thread, 764 struct thread *thread,
@@ -831,7 +891,9 @@ error:
831static void set_table_handlers(struct tables *tables) 891static void set_table_handlers(struct tables *tables)
832{ 892{
833 const char *perf_db_export_mode = "perf_db_export_mode"; 893 const char *perf_db_export_mode = "perf_db_export_mode";
834 PyObject *db_export_mode; 894 const char *perf_db_export_calls = "perf_db_export_calls";
895 PyObject *db_export_mode, *db_export_calls;
896 bool export_calls = false;
835 int ret; 897 int ret;
836 898
837 memset(tables, 0, sizeof(struct tables)); 899 memset(tables, 0, sizeof(struct tables));
@@ -848,6 +910,23 @@ static void set_table_handlers(struct tables *tables)
848 if (!ret) 910 if (!ret)
849 return; 911 return;
850 912
913 tables->dbe.crp = NULL;
914 db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls);
915 if (db_export_calls) {
916 ret = PyObject_IsTrue(db_export_calls);
917 if (ret == -1)
918 handler_call_die(perf_db_export_calls);
919 export_calls = !!ret;
920 }
921
922 if (export_calls) {
923 tables->dbe.crp =
924 call_return_processor__new(python_process_call_return,
925 &tables->dbe);
926 if (!tables->dbe.crp)
927 Py_FatalError("failed to create calls processor");
928 }
929
851 tables->db_export_mode = true; 930 tables->db_export_mode = true;
852 /* 931 /*
853 * Reserve per symbol space for symbol->db_id via symbol__priv() 932 * Reserve per symbol space for symbol->db_id via symbol__priv()
@@ -861,7 +940,10 @@ static void set_table_handlers(struct tables *tables)
861 SET_TABLE_HANDLER(comm_thread); 940 SET_TABLE_HANDLER(comm_thread);
862 SET_TABLE_HANDLER(dso); 941 SET_TABLE_HANDLER(dso);
863 SET_TABLE_HANDLER(symbol); 942 SET_TABLE_HANDLER(symbol);
943 SET_TABLE_HANDLER(branch_type);
864 SET_TABLE_HANDLER(sample); 944 SET_TABLE_HANDLER(sample);
945 SET_TABLE_HANDLER(call_path);
946 SET_TABLE_HANDLER(call_return);
865} 947}
866 948
867/* 949/*
@@ -910,6 +992,12 @@ static int python_start_script(const char *script, int argc, const char **argv)
910 992
911 set_table_handlers(tables); 993 set_table_handlers(tables);
912 994
995 if (tables->db_export_mode) {
996 err = db_export__branch_types(&tables->dbe);
997 if (err)
998 goto error;
999 }
1000
913 return err; 1001 return err;
914error: 1002error:
915 Py_Finalize(); 1003 Py_Finalize();
@@ -920,7 +1008,9 @@ error:
920 1008
921static int python_flush_script(void) 1009static int python_flush_script(void)
922{ 1010{
923 return 0; 1011 struct tables *tables = &tables_global;
1012
1013 return db_export__flush(&tables->dbe);
924} 1014}
925 1015
926/* 1016/*
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 1e23a5bfb044..efc7eb6b8f0f 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
546 return 0; 546 return 0;
547} 547}
548 548
549static int decompress_kmodule(struct dso *dso, const char *name,
550 enum dso_binary_type type)
551{
552 int fd;
553 const char *ext = strrchr(name, '.');
554 char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
555
556 if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
557 type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
558 type != dso->symtab_type)
559 return -1;
560
561 if (!ext || !is_supported_compression(ext + 1))
562 return -1;
563
564 fd = mkstemp(tmpbuf);
565 if (fd < 0)
566 return -1;
567
568 if (!decompress_to_file(ext + 1, name, fd)) {
569 close(fd);
570 fd = -1;
571 }
572
573 unlink(tmpbuf);
574
575 return fd;
576}
577
549bool symsrc__possibly_runtime(struct symsrc *ss) 578bool symsrc__possibly_runtime(struct symsrc *ss)
550{ 579{
551 return ss->dynsym || ss->opdsec; 580 return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
571 Elf *elf; 600 Elf *elf;
572 int fd; 601 int fd;
573 602
574 fd = open(name, O_RDONLY); 603 if (dso__needs_decompress(dso))
604 fd = decompress_kmodule(dso, name, type);
605 else
606 fd = open(name, O_RDONLY);
607
575 if (fd < 0) 608 if (fd < 0)
576 return -1; 609 return -1;
577 610
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 078331140d8c..c24c5b83156c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
51 DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 51 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
52 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 52 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
53 DSO_BINARY_TYPE__GUEST_KMODULE, 53 DSO_BINARY_TYPE__GUEST_KMODULE,
54 DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
54 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 55 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
56 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
55 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 57 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
56 DSO_BINARY_TYPE__NOT_FOUND, 58 DSO_BINARY_TYPE__NOT_FOUND,
57}; 59};
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1300 return dso->kernel == DSO_TYPE_GUEST_KERNEL; 1302 return dso->kernel == DSO_TYPE_GUEST_KERNEL;
1301 1303
1302 case DSO_BINARY_TYPE__GUEST_KMODULE: 1304 case DSO_BINARY_TYPE__GUEST_KMODULE:
1305 case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
1303 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1306 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1307 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
1304 /* 1308 /*
1305 * kernel modules know their symtab type - it's set when 1309 * kernel modules know their symtab type - it's set when
1306 * creating a module dso in machine__new_module(). 1310 * creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1368 return -1; 1372 return -1;
1369 1373
1370 kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1374 kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
1371 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE; 1375 dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
1376 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
1377 dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
1372 1378
1373 /* 1379 /*
1374 * Iterate over candidate debug images. 1380 * Iterate over candidate debug images.
@@ -1505,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1505 symbol_filter_t filter) 1511 symbol_filter_t filter)
1506{ 1512{
1507 int i, err = 0; 1513 int i, err = 0;
1508 char *filename; 1514 char *filename = NULL;
1509 1515
1510 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1516 if (!symbol_conf.ignore_vmlinux_buildid)
1511 vmlinux_path__nr_entries + 1); 1517 filename = dso__build_id_filename(dso, NULL, 0);
1512
1513 filename = dso__build_id_filename(dso, NULL, 0);
1514 if (filename != NULL) { 1518 if (filename != NULL) {
1515 err = dso__load_vmlinux(dso, map, filename, true, filter); 1519 err = dso__load_vmlinux(dso, map, filename, true, filter);
1516 if (err > 0) 1520 if (err > 0)
@@ -1518,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1518 free(filename); 1522 free(filename);
1519 } 1523 }
1520 1524
1525 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1526 vmlinux_path__nr_entries + 1);
1527
1521 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1528 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1522 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); 1529 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1523 if (err > 0) 1530 if (err > 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index eb2c19bf8d90..ded3ca7266de 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -105,6 +105,7 @@ struct symbol_conf {
105 unsigned short nr_events; 105 unsigned short nr_events;
106 bool try_vmlinux_path, 106 bool try_vmlinux_path,
107 ignore_vmlinux, 107 ignore_vmlinux,
108 ignore_vmlinux_buildid,
108 show_kernel_path, 109 show_kernel_path,
109 use_modules, 110 use_modules,
110 sort_by_name, 111 sort_by_name,
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
new file mode 100644
index 000000000000..9ed59a452d1f
--- /dev/null
+++ b/tools/perf/util/thread-stack.c
@@ -0,0 +1,747 @@
1/*
2 * thread-stack.c: Synthesize a thread's stack using call / return events
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/rbtree.h>
17#include <linux/list.h>
18#include "thread.h"
19#include "event.h"
20#include "machine.h"
21#include "util.h"
22#include "debug.h"
23#include "symbol.h"
24#include "comm.h"
25#include "thread-stack.h"
26
27#define CALL_PATH_BLOCK_SHIFT 8
28#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
29#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
30
31struct call_path_block {
32 struct call_path cp[CALL_PATH_BLOCK_SIZE];
33 struct list_head node;
34};
35
36/**
37 * struct call_path_root - root of all call paths.
38 * @call_path: root call path
39 * @blocks: list of blocks to store call paths
40 * @next: next free space
41 * @sz: number of spaces
42 */
43struct call_path_root {
44 struct call_path call_path;
45 struct list_head blocks;
46 size_t next;
47 size_t sz;
48};
49
50/**
51 * struct call_return_processor - provides a call-back to consume call-return
52 * information.
53 * @cpr: call path root
54 * @process: call-back that accepts call/return information
55 * @data: anonymous data for call-back
56 */
57struct call_return_processor {
58 struct call_path_root *cpr;
59 int (*process)(struct call_return *cr, void *data);
60 void *data;
61};
62
63#define STACK_GROWTH 2048
64
65/**
66 * struct thread_stack_entry - thread stack entry.
67 * @ret_addr: return address
68 * @timestamp: timestamp (if known)
69 * @ref: external reference (e.g. db_id of sample)
70 * @branch_count: the branch count when the entry was created
71 * @cp: call path
72 * @no_call: a 'call' was not seen
73 */
74struct thread_stack_entry {
75 u64 ret_addr;
76 u64 timestamp;
77 u64 ref;
78 u64 branch_count;
79 struct call_path *cp;
80 bool no_call;
81};
82
83/**
84 * struct thread_stack - thread stack constructed from 'call' and 'return'
85 * branch samples.
86 * @stack: array that holds the stack
87 * @cnt: number of entries in the stack
88 * @sz: current maximum stack size
89 * @trace_nr: current trace number
90 * @branch_count: running branch count
91 * @kernel_start: kernel start address
92 * @last_time: last timestamp
93 * @crp: call/return processor
94 * @comm: current comm
95 */
96struct thread_stack {
97 struct thread_stack_entry *stack;
98 size_t cnt;
99 size_t sz;
100 u64 trace_nr;
101 u64 branch_count;
102 u64 kernel_start;
103 u64 last_time;
104 struct call_return_processor *crp;
105 struct comm *comm;
106};
107
108static int thread_stack__grow(struct thread_stack *ts)
109{
110 struct thread_stack_entry *new_stack;
111 size_t sz, new_sz;
112
113 new_sz = ts->sz + STACK_GROWTH;
114 sz = new_sz * sizeof(struct thread_stack_entry);
115
116 new_stack = realloc(ts->stack, sz);
117 if (!new_stack)
118 return -ENOMEM;
119
120 ts->stack = new_stack;
121 ts->sz = new_sz;
122
123 return 0;
124}
125
126static struct thread_stack *thread_stack__new(struct thread *thread,
127 struct call_return_processor *crp)
128{
129 struct thread_stack *ts;
130
131 ts = zalloc(sizeof(struct thread_stack));
132 if (!ts)
133 return NULL;
134
135 if (thread_stack__grow(ts)) {
136 free(ts);
137 return NULL;
138 }
139
140 if (thread->mg && thread->mg->machine)
141 ts->kernel_start = machine__kernel_start(thread->mg->machine);
142 else
143 ts->kernel_start = 1ULL << 63;
144 ts->crp = crp;
145
146 return ts;
147}
148
149static int thread_stack__push(struct thread_stack *ts, u64 ret_addr)
150{
151 int err = 0;
152
153 if (ts->cnt == ts->sz) {
154 err = thread_stack__grow(ts);
155 if (err) {
156 pr_warning("Out of memory: discarding thread stack\n");
157 ts->cnt = 0;
158 }
159 }
160
161 ts->stack[ts->cnt++].ret_addr = ret_addr;
162
163 return err;
164}
165
166static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
167{
168 size_t i;
169
170 /*
171 * In some cases there may be functions which are not seen to return.
172 * For example when setjmp / longjmp has been used. Or the perf context
173 * switch in the kernel which doesn't stop and start tracing in exactly
174 * the same code path. When that happens the return address will be
175 * further down the stack. If the return address is not found at all,
176 * we assume the opposite (i.e. this is a return for a call that wasn't
177 * seen for some reason) and leave the stack alone.
178 */
179 for (i = ts->cnt; i; ) {
180 if (ts->stack[--i].ret_addr == ret_addr) {
181 ts->cnt = i;
182 return;
183 }
184 }
185}
186
187static bool thread_stack__in_kernel(struct thread_stack *ts)
188{
189 if (!ts->cnt)
190 return false;
191
192 return ts->stack[ts->cnt - 1].cp->in_kernel;
193}
194
195static int thread_stack__call_return(struct thread *thread,
196 struct thread_stack *ts, size_t idx,
197 u64 timestamp, u64 ref, bool no_return)
198{
199 struct call_return_processor *crp = ts->crp;
200 struct thread_stack_entry *tse;
201 struct call_return cr = {
202 .thread = thread,
203 .comm = ts->comm,
204 .db_id = 0,
205 };
206
207 tse = &ts->stack[idx];
208 cr.cp = tse->cp;
209 cr.call_time = tse->timestamp;
210 cr.return_time = timestamp;
211 cr.branch_count = ts->branch_count - tse->branch_count;
212 cr.call_ref = tse->ref;
213 cr.return_ref = ref;
214 if (tse->no_call)
215 cr.flags |= CALL_RETURN_NO_CALL;
216 if (no_return)
217 cr.flags |= CALL_RETURN_NO_RETURN;
218
219 return crp->process(&cr, crp->data);
220}
221
222static int thread_stack__flush(struct thread *thread, struct thread_stack *ts)
223{
224 struct call_return_processor *crp = ts->crp;
225 int err;
226
227 if (!crp) {
228 ts->cnt = 0;
229 return 0;
230 }
231
232 while (ts->cnt) {
233 err = thread_stack__call_return(thread, ts, --ts->cnt,
234 ts->last_time, 0, true);
235 if (err) {
236 pr_err("Error flushing thread stack!\n");
237 ts->cnt = 0;
238 return err;
239 }
240 }
241
242 return 0;
243}
244
245int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
246 u64 to_ip, u16 insn_len, u64 trace_nr)
247{
248 if (!thread)
249 return -EINVAL;
250
251 if (!thread->ts) {
252 thread->ts = thread_stack__new(thread, NULL);
253 if (!thread->ts) {
254 pr_warning("Out of memory: no thread stack\n");
255 return -ENOMEM;
256 }
257 thread->ts->trace_nr = trace_nr;
258 }
259
260 /*
261 * When the trace is discontinuous, the trace_nr changes. In that case
262 * the stack might be completely invalid. Better to report nothing than
263 * to report something misleading, so flush the stack.
264 */
265 if (trace_nr != thread->ts->trace_nr) {
266 if (thread->ts->trace_nr)
267 thread_stack__flush(thread, thread->ts);
268 thread->ts->trace_nr = trace_nr;
269 }
270
271 /* Stop here if thread_stack__process() is in use */
272 if (thread->ts->crp)
273 return 0;
274
275 if (flags & PERF_IP_FLAG_CALL) {
276 u64 ret_addr;
277
278 if (!to_ip)
279 return 0;
280 ret_addr = from_ip + insn_len;
281 if (ret_addr == to_ip)
282 return 0; /* Zero-length calls are excluded */
283 return thread_stack__push(thread->ts, ret_addr);
284 } else if (flags & PERF_IP_FLAG_RETURN) {
285 if (!from_ip)
286 return 0;
287 thread_stack__pop(thread->ts, to_ip);
288 }
289
290 return 0;
291}
292
293void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
294{
295 if (!thread || !thread->ts)
296 return;
297
298 if (trace_nr != thread->ts->trace_nr) {
299 if (thread->ts->trace_nr)
300 thread_stack__flush(thread, thread->ts);
301 thread->ts->trace_nr = trace_nr;
302 }
303}
304
305void thread_stack__free(struct thread *thread)
306{
307 if (thread->ts) {
308 thread_stack__flush(thread, thread->ts);
309 zfree(&thread->ts->stack);
310 zfree(&thread->ts);
311 }
312}
313
314void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
315 size_t sz, u64 ip)
316{
317 size_t i;
318
319 if (!thread || !thread->ts)
320 chain->nr = 1;
321 else
322 chain->nr = min(sz, thread->ts->cnt + 1);
323
324 chain->ips[0] = ip;
325
326 for (i = 1; i < chain->nr; i++)
327 chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
328}
329
330static void call_path__init(struct call_path *cp, struct call_path *parent,
331 struct symbol *sym, u64 ip, bool in_kernel)
332{
333 cp->parent = parent;
334 cp->sym = sym;
335 cp->ip = sym ? 0 : ip;
336 cp->db_id = 0;
337 cp->in_kernel = in_kernel;
338 RB_CLEAR_NODE(&cp->rb_node);
339 cp->children = RB_ROOT;
340}
341
342static struct call_path_root *call_path_root__new(void)
343{
344 struct call_path_root *cpr;
345
346 cpr = zalloc(sizeof(struct call_path_root));
347 if (!cpr)
348 return NULL;
349 call_path__init(&cpr->call_path, NULL, NULL, 0, false);
350 INIT_LIST_HEAD(&cpr->blocks);
351 return cpr;
352}
353
354static void call_path_root__free(struct call_path_root *cpr)
355{
356 struct call_path_block *pos, *n;
357
358 list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
359 list_del(&pos->node);
360 free(pos);
361 }
362 free(cpr);
363}
364
365static struct call_path *call_path__new(struct call_path_root *cpr,
366 struct call_path *parent,
367 struct symbol *sym, u64 ip,
368 bool in_kernel)
369{
370 struct call_path_block *cpb;
371 struct call_path *cp;
372 size_t n;
373
374 if (cpr->next < cpr->sz) {
375 cpb = list_last_entry(&cpr->blocks, struct call_path_block,
376 node);
377 } else {
378 cpb = zalloc(sizeof(struct call_path_block));
379 if (!cpb)
380 return NULL;
381 list_add_tail(&cpb->node, &cpr->blocks);
382 cpr->sz += CALL_PATH_BLOCK_SIZE;
383 }
384
385 n = cpr->next++ & CALL_PATH_BLOCK_MASK;
386 cp = &cpb->cp[n];
387
388 call_path__init(cp, parent, sym, ip, in_kernel);
389
390 return cp;
391}
392
393static struct call_path *call_path__findnew(struct call_path_root *cpr,
394 struct call_path *parent,
395 struct symbol *sym, u64 ip, u64 ks)
396{
397 struct rb_node **p;
398 struct rb_node *node_parent = NULL;
399 struct call_path *cp;
400 bool in_kernel = ip >= ks;
401
402 if (sym)
403 ip = 0;
404
405 if (!parent)
406 return call_path__new(cpr, parent, sym, ip, in_kernel);
407
408 p = &parent->children.rb_node;
409 while (*p != NULL) {
410 node_parent = *p;
411 cp = rb_entry(node_parent, struct call_path, rb_node);
412
413 if (cp->sym == sym && cp->ip == ip)
414 return cp;
415
416 if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
417 p = &(*p)->rb_left;
418 else
419 p = &(*p)->rb_right;
420 }
421
422 cp = call_path__new(cpr, parent, sym, ip, in_kernel);
423 if (!cp)
424 return NULL;
425
426 rb_link_node(&cp->rb_node, node_parent, p);
427 rb_insert_color(&cp->rb_node, &parent->children);
428
429 return cp;
430}
431
432struct call_return_processor *
433call_return_processor__new(int (*process)(struct call_return *cr, void *data),
434 void *data)
435{
436 struct call_return_processor *crp;
437
438 crp = zalloc(sizeof(struct call_return_processor));
439 if (!crp)
440 return NULL;
441 crp->cpr = call_path_root__new();
442 if (!crp->cpr)
443 goto out_free;
444 crp->process = process;
445 crp->data = data;
446 return crp;
447
448out_free:
449 free(crp);
450 return NULL;
451}
452
453void call_return_processor__free(struct call_return_processor *crp)
454{
455 if (crp) {
456 call_path_root__free(crp->cpr);
457 free(crp);
458 }
459}
460
461static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
462 u64 timestamp, u64 ref, struct call_path *cp,
463 bool no_call)
464{
465 struct thread_stack_entry *tse;
466 int err;
467
468 if (ts->cnt == ts->sz) {
469 err = thread_stack__grow(ts);
470 if (err)
471 return err;
472 }
473
474 tse = &ts->stack[ts->cnt++];
475 tse->ret_addr = ret_addr;
476 tse->timestamp = timestamp;
477 tse->ref = ref;
478 tse->branch_count = ts->branch_count;
479 tse->cp = cp;
480 tse->no_call = no_call;
481
482 return 0;
483}
484
485static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
486 u64 ret_addr, u64 timestamp, u64 ref,
487 struct symbol *sym)
488{
489 int err;
490
491 if (!ts->cnt)
492 return 1;
493
494 if (ts->cnt == 1) {
495 struct thread_stack_entry *tse = &ts->stack[0];
496
497 if (tse->cp->sym == sym)
498 return thread_stack__call_return(thread, ts, --ts->cnt,
499 timestamp, ref, false);
500 }
501
502 if (ts->stack[ts->cnt - 1].ret_addr == ret_addr) {
503 return thread_stack__call_return(thread, ts, --ts->cnt,
504 timestamp, ref, false);
505 } else {
506 size_t i = ts->cnt - 1;
507
508 while (i--) {
509 if (ts->stack[i].ret_addr != ret_addr)
510 continue;
511 i += 1;
512 while (ts->cnt > i) {
513 err = thread_stack__call_return(thread, ts,
514 --ts->cnt,
515 timestamp, ref,
516 true);
517 if (err)
518 return err;
519 }
520 return thread_stack__call_return(thread, ts, --ts->cnt,
521 timestamp, ref, false);
522 }
523 }
524
525 return 1;
526}
527
528static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
529 struct perf_sample *sample,
530 struct addr_location *from_al,
531 struct addr_location *to_al, u64 ref)
532{
533 struct call_path_root *cpr = ts->crp->cpr;
534 struct call_path *cp;
535 struct symbol *sym;
536 u64 ip;
537
538 if (sample->ip) {
539 ip = sample->ip;
540 sym = from_al->sym;
541 } else if (sample->addr) {
542 ip = sample->addr;
543 sym = to_al->sym;
544 } else {
545 return 0;
546 }
547
548 cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
549 ts->kernel_start);
550 if (!cp)
551 return -ENOMEM;
552
553 return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
554 true);
555}
556
557static int thread_stack__no_call_return(struct thread *thread,
558 struct thread_stack *ts,
559 struct perf_sample *sample,
560 struct addr_location *from_al,
561 struct addr_location *to_al, u64 ref)
562{
563 struct call_path_root *cpr = ts->crp->cpr;
564 struct call_path *cp, *parent;
565 u64 ks = ts->kernel_start;
566 int err;
567
568 if (sample->ip >= ks && sample->addr < ks) {
569 /* Return to userspace, so pop all kernel addresses */
570 while (thread_stack__in_kernel(ts)) {
571 err = thread_stack__call_return(thread, ts, --ts->cnt,
572 sample->time, ref,
573 true);
574 if (err)
575 return err;
576 }
577
578 /* If the stack is empty, push the userspace address */
579 if (!ts->cnt) {
580 cp = call_path__findnew(cpr, &cpr->call_path,
581 to_al->sym, sample->addr,
582 ts->kernel_start);
583 if (!cp)
584 return -ENOMEM;
585 return thread_stack__push_cp(ts, 0, sample->time, ref,
586 cp, true);
587 }
588 } else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
589 /* Return to userspace, so pop all kernel addresses */
590 while (thread_stack__in_kernel(ts)) {
591 err = thread_stack__call_return(thread, ts, --ts->cnt,
592 sample->time, ref,
593 true);
594 if (err)
595 return err;
596 }
597 }
598
599 if (ts->cnt)
600 parent = ts->stack[ts->cnt - 1].cp;
601 else
602 parent = &cpr->call_path;
603
604 /* This 'return' had no 'call', so push and pop top of stack */
605 cp = call_path__findnew(cpr, parent, from_al->sym, sample->ip,
606 ts->kernel_start);
607 if (!cp)
608 return -ENOMEM;
609
610 err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
611 true);
612 if (err)
613 return err;
614
615 return thread_stack__pop_cp(thread, ts, sample->addr, sample->time, ref,
616 to_al->sym);
617}
618
619static int thread_stack__trace_begin(struct thread *thread,
620 struct thread_stack *ts, u64 timestamp,
621 u64 ref)
622{
623 struct thread_stack_entry *tse;
624 int err;
625
626 if (!ts->cnt)
627 return 0;
628
629 /* Pop trace end */
630 tse = &ts->stack[ts->cnt - 1];
631 if (tse->cp->sym == NULL && tse->cp->ip == 0) {
632 err = thread_stack__call_return(thread, ts, --ts->cnt,
633 timestamp, ref, false);
634 if (err)
635 return err;
636 }
637
638 return 0;
639}
640
641static int thread_stack__trace_end(struct thread_stack *ts,
642 struct perf_sample *sample, u64 ref)
643{
644 struct call_path_root *cpr = ts->crp->cpr;
645 struct call_path *cp;
646 u64 ret_addr;
647
648 /* No point having 'trace end' on the bottom of the stack */
649 if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
650 return 0;
651
652 cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
653 ts->kernel_start);
654 if (!cp)
655 return -ENOMEM;
656
657 ret_addr = sample->ip + sample->insn_len;
658
659 return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
660 false);
661}
662
663int thread_stack__process(struct thread *thread, struct comm *comm,
664 struct perf_sample *sample,
665 struct addr_location *from_al,
666 struct addr_location *to_al, u64 ref,
667 struct call_return_processor *crp)
668{
669 struct thread_stack *ts = thread->ts;
670 int err = 0;
671
672 if (ts) {
673 if (!ts->crp) {
674 /* Supersede thread_stack__event() */
675 thread_stack__free(thread);
676 thread->ts = thread_stack__new(thread, crp);
677 if (!thread->ts)
678 return -ENOMEM;
679 ts = thread->ts;
680 ts->comm = comm;
681 }
682 } else {
683 thread->ts = thread_stack__new(thread, crp);
684 if (!thread->ts)
685 return -ENOMEM;
686 ts = thread->ts;
687 ts->comm = comm;
688 }
689
690 /* Flush stack on exec */
691 if (ts->comm != comm && thread->pid_ == thread->tid) {
692 err = thread_stack__flush(thread, ts);
693 if (err)
694 return err;
695 ts->comm = comm;
696 }
697
698 /* If the stack is empty, put the current symbol on the stack */
699 if (!ts->cnt) {
700 err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
701 ref);
702 if (err)
703 return err;
704 }
705
706 ts->branch_count += 1;
707 ts->last_time = sample->time;
708
709 if (sample->flags & PERF_IP_FLAG_CALL) {
710 struct call_path_root *cpr = ts->crp->cpr;
711 struct call_path *cp;
712 u64 ret_addr;
713
714 if (!sample->ip || !sample->addr)
715 return 0;
716
717 ret_addr = sample->ip + sample->insn_len;
718 if (ret_addr == sample->addr)
719 return 0; /* Zero-length calls are excluded */
720
721 cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
722 to_al->sym, sample->addr,
723 ts->kernel_start);
724 if (!cp)
725 return -ENOMEM;
726 err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
727 cp, false);
728 } else if (sample->flags & PERF_IP_FLAG_RETURN) {
729 if (!sample->ip || !sample->addr)
730 return 0;
731
732 err = thread_stack__pop_cp(thread, ts, sample->addr,
733 sample->time, ref, from_al->sym);
734 if (err) {
735 if (err < 0)
736 return err;
737 err = thread_stack__no_call_return(thread, ts, sample,
738 from_al, to_al, ref);
739 }
740 } else if (sample->flags & PERF_IP_FLAG_TRACE_BEGIN) {
741 err = thread_stack__trace_begin(thread, ts, sample->time, ref);
742 } else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
743 err = thread_stack__trace_end(ts, sample, ref);
744 }
745
746 return err;
747}
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
new file mode 100644
index 000000000000..b843bbef8ba2
--- /dev/null
+++ b/tools/perf/util/thread-stack.h
@@ -0,0 +1,111 @@
1/*
2 * thread-stack.h: Synthesize a thread's stack using call / return events
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef __PERF_THREAD_STACK_H
17#define __PERF_THREAD_STACK_H
18
19#include <sys/types.h>
20
21#include <linux/types.h>
22#include <linux/rbtree.h>
23
24struct thread;
25struct comm;
26struct ip_callchain;
27struct symbol;
28struct dso;
29struct call_return_processor;
30struct comm;
31struct perf_sample;
32struct addr_location;
33
34/*
35 * Call/Return flags.
36 *
37 * CALL_RETURN_NO_CALL: 'return' but no matching 'call'
38 * CALL_RETURN_NO_RETURN: 'call' but no matching 'return'
39 */
40enum {
41 CALL_RETURN_NO_CALL = 1 << 0,
42 CALL_RETURN_NO_RETURN = 1 << 1,
43};
44
45/**
46 * struct call_return - paired call/return information.
47 * @thread: thread in which call/return occurred
48 * @comm: comm in which call/return occurred
49 * @cp: call path
50 * @call_time: timestamp of call (if known)
51 * @return_time: timestamp of return (if known)
52 * @branch_count: number of branches seen between call and return
53 * @call_ref: external reference to 'call' sample (e.g. db_id)
54 * @return_ref: external reference to 'return' sample (e.g. db_id)
55 * @db_id: id used for db-export
56 * @flags: Call/Return flags
57 */
58struct call_return {
59 struct thread *thread;
60 struct comm *comm;
61 struct call_path *cp;
62 u64 call_time;
63 u64 return_time;
64 u64 branch_count;
65 u64 call_ref;
66 u64 return_ref;
67 u64 db_id;
68 u32 flags;
69};
70
71/**
72 * struct call_path - node in list of calls leading to a function call.
73 * @parent: call path to the parent function call
74 * @sym: symbol of function called
75 * @ip: only if sym is null, the ip of the function
76 * @db_id: id used for db-export
77 * @in_kernel: whether function is a in the kernel
78 * @rb_node: node in parent's tree of called functions
79 * @children: tree of call paths of functions called
80 *
81 * In combination with the call_return structure, the call_path structure
82 * defines a context-sensitve call-graph.
83 */
84struct call_path {
85 struct call_path *parent;
86 struct symbol *sym;
87 u64 ip;
88 u64 db_id;
89 bool in_kernel;
90 struct rb_node rb_node;
91 struct rb_root children;
92};
93
94int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
95 u64 to_ip, u16 insn_len, u64 trace_nr);
96void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
97void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
98 size_t sz, u64 ip);
99void thread_stack__free(struct thread *thread);
100
101struct call_return_processor *
102call_return_processor__new(int (*process)(struct call_return *cr, void *data),
103 void *data);
104void call_return_processor__free(struct call_return_processor *crp);
105int thread_stack__process(struct thread *thread, struct comm *comm,
106 struct perf_sample *sample,
107 struct addr_location *from_al,
108 struct addr_location *to_al, u64 ref,
109 struct call_return_processor *crp);
110
111#endif
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index bf5bf858b7f6..a2157f0ef1df 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -4,6 +4,7 @@
4#include <string.h> 4#include <string.h>
5#include "session.h" 5#include "session.h"
6#include "thread.h" 6#include "thread.h"
7#include "thread-stack.h"
7#include "util.h" 8#include "util.h"
8#include "debug.h" 9#include "debug.h"
9#include "comm.h" 10#include "comm.h"
@@ -66,6 +67,8 @@ void thread__delete(struct thread *thread)
66{ 67{
67 struct comm *comm, *tmp; 68 struct comm *comm, *tmp;
68 69
70 thread_stack__free(thread);
71
69 if (thread->mg) { 72 if (thread->mg) {
70 map_groups__put(thread->mg); 73 map_groups__put(thread->mg);
71 thread->mg = NULL; 74 thread->mg = NULL;
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index d34cf5c0d0d9..160fd066a7d1 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,6 +8,8 @@
8#include "symbol.h" 8#include "symbol.h"
9#include <strlist.h> 9#include <strlist.h>
10 10
11struct thread_stack;
12
11struct thread { 13struct thread {
12 union { 14 union {
13 struct rb_node rb_node; 15 struct rb_node rb_node;
@@ -26,6 +28,7 @@ struct thread {
26 u64 db_id; 28 u64 db_id;
27 29
28 void *priv; 30 void *priv;
31 struct thread_stack *ts;
29}; 32};
30 33
31struct machine; 34struct machine;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 80bfdaa0e2a4..7dc44cfe25b3 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -351,4 +351,9 @@ void mem_bswap_32(void *src, int byte_size);
351 351
352const char *get_filename_for_perf_kvm(void); 352const char *get_filename_for_perf_kvm(void);
353bool find_process(const char *name); 353bool find_process(const char *name);
354
355#ifdef HAVE_ZLIB_SUPPORT
356int gzip_decompress_to_file(const char *input, int output_fd);
357#endif
358
354#endif /* GIT_COMPAT_UTIL_H */ 359#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c
new file mode 100644
index 000000000000..495a449fc25c
--- /dev/null
+++ b/tools/perf/util/zlib.c
@@ -0,0 +1,78 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <sys/stat.h>
4#include <sys/mman.h>
5#include <zlib.h>
6
7#include "util/util.h"
8#include "util/debug.h"
9
10
11#define CHUNK_SIZE 16384
12
13int gzip_decompress_to_file(const char *input, int output_fd)
14{
15 int ret = Z_STREAM_ERROR;
16 int input_fd;
17 void *ptr;
18 int len;
19 struct stat stbuf;
20 unsigned char buf[CHUNK_SIZE];
21 z_stream zs = {
22 .zalloc = Z_NULL,
23 .zfree = Z_NULL,
24 .opaque = Z_NULL,
25 .avail_in = 0,
26 .next_in = Z_NULL,
27 };
28
29 input_fd = open(input, O_RDONLY);
30 if (input_fd < 0)
31 return -1;
32
33 if (fstat(input_fd, &stbuf) < 0)
34 goto out_close;
35
36 ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
37 if (ptr == MAP_FAILED)
38 goto out_close;
39
40 if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
41 goto out_unmap;
42
43 zs.next_in = ptr;
44 zs.avail_in = stbuf.st_size;
45
46 do {
47 zs.next_out = buf;
48 zs.avail_out = CHUNK_SIZE;
49
50 ret = inflate(&zs, Z_NO_FLUSH);
51 switch (ret) {
52 case Z_NEED_DICT:
53 ret = Z_DATA_ERROR;
54 /* fall through */
55 case Z_DATA_ERROR:
56 case Z_MEM_ERROR:
57 goto out;
58 default:
59 break;
60 }
61
62 len = CHUNK_SIZE - zs.avail_out;
63 if (writen(output_fd, buf, len) != len) {
64 ret = Z_DATA_ERROR;
65 goto out;
66 }
67
68 } while (ret != Z_STREAM_END);
69
70out:
71 inflateEnd(&zs);
72out_unmap:
73 munmap(ptr, stbuf.st_size);
74out_close:
75 close(input_fd);
76
77 return ret == Z_STREAM_END ? 0 : -1;
78}