aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-10-30 02:34:32 -0400
committerIngo Molnar <mingo@kernel.org>2014-10-30 02:34:32 -0400
commit05b2537e8dc778bb00284f8fc86b83797b8f1d37 (patch)
treeb66c9d4d7c82152a034e8ab10f809d91790f4362 /tools/perf
parentd785452c9972fac2808479eb561d5c426b6e7d3b (diff)
parenta293829df788ae96a174b315010d4b56a10e5114 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements from Arnaldo Carvalho de Melo: User visible changes: - Don't open the DWARF info multiple times, keeping instead a dwfl handle in struct dso, greatly speeding up 'perf report' on powerpc. (Sukadev Bhattiprolu) - Introduce PARSE_OPT_DISABLED option flag and use it to avoid showing undersired options in tools that provides frontends to 'perf record', like sched, kvm, etc (Namhyung Kim) Infrastructure changes: - More Intel PT work, including a facility to export sample data (comms, threads, symbol names, etc) in a database friendly way, with an script to use this to create a postgresql database. (Adrian Hunter) - Use make sure that thread->mg->machine points to the machine where the thread exists (it was being set only for the kmaps kernel modules case, do it as well for the mmaps) and use it to shorten function signatures (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Makefile.perf40
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c38
-rw-r--r--tools/perf/builtin-inject.c4
-rw-r--r--tools/perf/builtin-kvm.c25
-rw-r--r--tools/perf/builtin-probe.c65
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-script.c8
-rw-r--r--tools/perf/builtin-timechart.c9
-rw-r--r--tools/perf/builtin-trace.c6
-rw-r--r--tools/perf/config/Makefile29
-rw-r--r--tools/perf/config/Makefile.arch8
-rw-r--r--tools/perf/config/feature-checks/Makefile10
-rw-r--r--tools/perf/config/feature-checks/test-compile.c4
-rw-r--r--tools/perf/perf-read-vdso.c34
-rw-r--r--tools/perf/perf.h3
-rw-r--r--tools/perf/scripts/python/bin/export-to-postgresql-record8
-rw-r--r--tools/perf/scripts/python/bin/export-to-postgresql-report24
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py360
-rw-r--r--tools/perf/tests/code-reading.c13
-rw-r--r--tools/perf/tests/dwarf-unwind.c18
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/util/build-id.c3
-rw-r--r--tools/perf/util/callchain.c4
-rw-r--r--tools/perf/util/callchain.h6
-rw-r--r--tools/perf/util/comm.h4
-rw-r--r--tools/perf/util/db-export.c270
-rw-r--r--tools/perf/util/db-export.h86
-rw-r--r--tools/perf/util/dso.h6
-rw-r--r--tools/perf/util/event.c20
-rw-r--r--tools/perf/util/event.h16
-rw-r--r--tools/perf/util/evlist.c28
-rw-r--r--tools/perf/util/evsel.h5
-rw-r--r--tools/perf/util/find-vdso-map.c30
-rw-r--r--tools/perf/util/header.c7
-rw-r--r--tools/perf/util/machine.c55
-rw-r--r--tools/perf/util/machine.h17
-rw-r--r--tools/perf/util/map.c8
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/parse-options.c78
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/pmu.c41
-rw-r--r--tools/perf/util/pmu.h1
-rw-r--r--tools/perf/util/probe-event.c18
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c292
-rw-r--r--tools/perf/util/session.c141
-rw-r--r--tools/perf/util/session.h15
-rw-r--r--tools/perf/util/thread.c6
-rw-r--r--tools/perf/util/thread.h6
-rw-r--r--tools/perf/util/tool.h3
-rw-r--r--tools/perf/util/unwind-libdw.c8
-rw-r--r--tools/perf/util/unwind-libunwind.c17
-rw-r--r--tools/perf/util/unwind.h2
-rw-r--r--tools/perf/util/vdso.c217
-rw-r--r--tools/perf/util/vdso.h4
55 files changed, 1873 insertions, 266 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 262916f4a377..3caf7dab50e8 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -60,6 +60,12 @@ include config/utilities.mak
60# 60#
61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support 61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
62# for dwarf backtrace post unwind. 62# for dwarf backtrace post unwind.
63#
64# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32
65# for reading the 32-bit compatibility VDSO in 64-bit mode
66#
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
63 69
64ifeq ($(srctree),) 70ifeq ($(srctree),)
65srctree := $(patsubst %/,%,$(dir $(shell pwd))) 71srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +177,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
171 177
172SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) 178SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
173 179
174#
175# Single 'perf' binary right now:
176#
177PROGRAMS += $(OUTPUT)perf 180PROGRAMS += $(OUTPUT)perf
178 181
182ifndef NO_PERF_READ_VDSO32
183PROGRAMS += $(OUTPUT)perf-read-vdso32
184endif
185
186ifndef NO_PERF_READ_VDSOX32
187PROGRAMS += $(OUTPUT)perf-read-vdsox32
188endif
189
179# what 'all' will build and 'install' will install, in perfexecdir 190# what 'all' will build and 'install' will install, in perfexecdir
180ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 191ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
181 192
@@ -247,12 +258,14 @@ LIB_H += util/annotate.h
247LIB_H += util/cache.h 258LIB_H += util/cache.h
248LIB_H += util/callchain.h 259LIB_H += util/callchain.h
249LIB_H += util/build-id.h 260LIB_H += util/build-id.h
261LIB_H += util/db-export.h
250LIB_H += util/debug.h 262LIB_H += util/debug.h
251LIB_H += util/pmu.h 263LIB_H += util/pmu.h
252LIB_H += util/event.h 264LIB_H += util/event.h
253LIB_H += util/evsel.h 265LIB_H += util/evsel.h
254LIB_H += util/evlist.h 266LIB_H += util/evlist.h
255LIB_H += util/exec_cmd.h 267LIB_H += util/exec_cmd.h
268LIB_H += util/find-vdso-map.c
256LIB_H += util/levenshtein.h 269LIB_H += util/levenshtein.h
257LIB_H += util/machine.h 270LIB_H += util/machine.h
258LIB_H += util/map.h 271LIB_H += util/map.h
@@ -311,6 +324,7 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
311LIB_OBJS += $(OUTPUT)util/build-id.o 324LIB_OBJS += $(OUTPUT)util/build-id.o
312LIB_OBJS += $(OUTPUT)util/config.o 325LIB_OBJS += $(OUTPUT)util/config.o
313LIB_OBJS += $(OUTPUT)util/ctype.o 326LIB_OBJS += $(OUTPUT)util/ctype.o
327LIB_OBJS += $(OUTPUT)util/db-export.o
314LIB_OBJS += $(OUTPUT)util/pmu.o 328LIB_OBJS += $(OUTPUT)util/pmu.o
315LIB_OBJS += $(OUTPUT)util/environment.o 329LIB_OBJS += $(OUTPUT)util/environment.o
316LIB_OBJS += $(OUTPUT)util/event.o 330LIB_OBJS += $(OUTPUT)util/event.o
@@ -732,6 +746,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti
732$(OUTPUT)perf-%: %.o $(PERFLIBS) 746$(OUTPUT)perf-%: %.o $(PERFLIBS)
733 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) 747 $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
734 748
749ifndef NO_PERF_READ_VDSO32
750$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c
751 $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
752endif
753
754ifndef NO_PERF_READ_VDSOX32
755$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c
756 $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
757endif
758
735$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 759$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
736$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 760$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
737 761
@@ -876,6 +900,14 @@ install-bin: all install-gtk
876 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \ 900 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
877 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \ 901 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
878 $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace' 902 $(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
903ifndef NO_PERF_READ_VDSO32
904 $(call QUIET_INSTALL, perf-read-vdso32) \
905 $(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)';
906endif
907ifndef NO_PERF_READ_VDSOX32
908 $(call QUIET_INSTALL, perf-read-vdsox32) \
909 $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)';
910endif
879 $(call QUIET_INSTALL, libexec) \ 911 $(call QUIET_INSTALL, libexec) \
880 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 912 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
881 $(call QUIET_INSTALL, perf-archive) \ 913 $(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +960,7 @@ config-clean:
928 960
929clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean 961clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
930 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) 962 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
931 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf 963 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
932 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* 964 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
933 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 965 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
934 $(python-clean) 966 $(python-clean)
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
index d73ef8bb08c7..3bb50eac5542 100644
--- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -145,7 +145,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
145 * yet used) 145 * yet used)
146 * -1 in case of errors 146 * -1 in case of errors
147 */ 147 */
148static int check_return_addr(const char *exec_file, Dwarf_Addr pc) 148static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
149{ 149{
150 int rc = -1; 150 int rc = -1;
151 Dwfl *dwfl; 151 Dwfl *dwfl;
@@ -156,15 +156,27 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
156 Dwarf_Addr end = pc; 156 Dwarf_Addr end = pc;
157 bool signalp; 157 bool signalp;
158 158
159 dwfl = dwfl_begin(&offline_callbacks); 159 dwfl = dso->dwfl;
160 if (!dwfl) {
161 pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
162 return -1;
163 }
164 160
165 if (dwfl_report_offline(dwfl, "", exec_file, -1) == NULL) { 161 if (!dwfl) {
166 pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1)); 162 dwfl = dwfl_begin(&offline_callbacks);
167 goto out; 163 if (!dwfl) {
164 pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
165 return -1;
166 }
167
168 if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) {
169 pr_debug("dwfl_report_offline() failed %s\n",
170 dwarf_errmsg(-1));
171 /*
172 * We normally cache the DWARF debug info and never
173 * call dwfl_end(). But to prevent fd leak, free in
174 * case of error.
175 */
176 dwfl_end(dwfl);
177 goto out;
178 }
179 dso->dwfl = dwfl;
168 } 180 }
169 181
170 mod = dwfl_addrmodule(dwfl, pc); 182 mod = dwfl_addrmodule(dwfl, pc);
@@ -194,7 +206,6 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
194 rc = check_return_reg(ra_regno, frame); 206 rc = check_return_reg(ra_regno, frame);
195 207
196out: 208out:
197 dwfl_end(dwfl);
198 return rc; 209 return rc;
199} 210}
200 211
@@ -221,8 +232,7 @@ out:
221 * index: of callchain entry that needs to be ignored (if any) 232 * index: of callchain entry that needs to be ignored (if any)
222 * -1 if no entry needs to be ignored or in case of errors 233 * -1 if no entry needs to be ignored or in case of errors
223 */ 234 */
224int arch_skip_callchain_idx(struct machine *machine, struct thread *thread, 235int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
225 struct ip_callchain *chain)
226{ 236{
227 struct addr_location al; 237 struct addr_location al;
228 struct dso *dso = NULL; 238 struct dso *dso = NULL;
@@ -235,7 +245,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
235 245
236 ip = chain->ips[2]; 246 ip = chain->ips[2];
237 247
238 thread__find_addr_location(thread, machine, PERF_RECORD_MISC_USER, 248 thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
239 MAP__FUNCTION, ip, &al); 249 MAP__FUNCTION, ip, &al);
240 250
241 if (al.map) 251 if (al.map)
@@ -246,7 +256,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
246 return skip_slot; 256 return skip_slot;
247 } 257 }
248 258
249 rc = check_return_addr(dso->long_name, ip); 259 rc = check_return_addr(dso, ip);
250 260
251 pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n", 261 pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
252 dso->long_name, chain->nr, ip, rc); 262 dso->long_name, chain->nr, ip, rc);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index de99ca1bb942..84df2deed988 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -217,8 +217,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
217 goto repipe; 217 goto repipe;
218 } 218 }
219 219
220 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 220 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
221 sample->ip, &al);
222 221
223 if (al.map != NULL) { 222 if (al.map != NULL) {
224 if (!al.map->dso->hit) { 223 if (!al.map->dso->hit) {
@@ -410,6 +409,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
410 .tracing_data = perf_event__repipe_op2_synth, 409 .tracing_data = perf_event__repipe_op2_synth,
411 .finished_round = perf_event__repipe_op2_synth, 410 .finished_round = perf_event__repipe_op2_synth,
412 .build_id = perf_event__repipe_op2_synth, 411 .build_id = perf_event__repipe_op2_synth,
412 .id_index = perf_event__repipe_op2_synth,
413 }, 413 },
414 .input_name = "-", 414 .input_name = "-",
415 .samples = LIST_HEAD_INIT(inject.samples), 415 .samples = LIST_HEAD_INIT(inject.samples),
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index b65eb0507b38..3c0f3d4fb021 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1132,6 +1132,10 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1132 "-m", "1024", 1132 "-m", "1024",
1133 "-c", "1", 1133 "-c", "1",
1134 }; 1134 };
1135 const char * const kvm_stat_record_usage[] = {
1136 "perf kvm stat record [<options>]",
1137 NULL
1138 };
1135 const char * const *events_tp; 1139 const char * const *events_tp;
1136 events_tp_size = 0; 1140 events_tp_size = 0;
1137 1141
@@ -1159,6 +1163,27 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1159 for (j = 1; j < (unsigned int)argc; j++, i++) 1163 for (j = 1; j < (unsigned int)argc; j++, i++)
1160 rec_argv[i] = argv[j]; 1164 rec_argv[i] = argv[j];
1161 1165
1166 set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN);
1167 set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN);
1168 set_option_flag(record_options, 'R', "raw-samples", PARSE_OPT_HIDDEN);
1169
1170 set_option_flag(record_options, 'F', "freq", PARSE_OPT_DISABLED);
1171 set_option_flag(record_options, 0, "group", PARSE_OPT_DISABLED);
1172 set_option_flag(record_options, 'g', NULL, PARSE_OPT_DISABLED);
1173 set_option_flag(record_options, 0, "call-graph", PARSE_OPT_DISABLED);
1174 set_option_flag(record_options, 'd', "data", PARSE_OPT_DISABLED);
1175 set_option_flag(record_options, 'T', "timestamp", PARSE_OPT_DISABLED);
1176 set_option_flag(record_options, 'P', "period", PARSE_OPT_DISABLED);
1177 set_option_flag(record_options, 'n', "no-samples", PARSE_OPT_DISABLED);
1178 set_option_flag(record_options, 'N', "no-buildid-cache", PARSE_OPT_DISABLED);
1179 set_option_flag(record_options, 'B', "no-buildid", PARSE_OPT_DISABLED);
1180 set_option_flag(record_options, 'G', "cgroup", PARSE_OPT_DISABLED);
1181 set_option_flag(record_options, 'b', "branch-any", PARSE_OPT_DISABLED);
1182 set_option_flag(record_options, 'j', "branch-filter", PARSE_OPT_DISABLED);
1183 set_option_flag(record_options, 'W', "weight", PARSE_OPT_DISABLED);
1184 set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);
1185
1186 record_usage = kvm_stat_record_usage;
1162 return cmd_record(i, rec_argv, NULL); 1187 return cmd_record(i, rec_argv, NULL);
1163} 1188}
1164 1189
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 7af26acf06d9..921bb6942503 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -55,6 +55,7 @@ static struct {
55 bool show_funcs; 55 bool show_funcs;
56 bool mod_events; 56 bool mod_events;
57 bool uprobes; 57 bool uprobes;
58 bool quiet;
58 int nevents; 59 int nevents;
59 struct perf_probe_event events[MAX_PROBES]; 60 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 61 struct strlist *dellist;
@@ -312,9 +313,11 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
312#endif 313#endif
313 NULL 314 NULL
314}; 315};
315 const struct option options[] = { 316 struct option options[] = {
316 OPT_INCR('v', "verbose", &verbose, 317 OPT_INCR('v', "verbose", &verbose,
317 "be more verbose (show parsed arguments, etc)"), 318 "be more verbose (show parsed arguments, etc)"),
319 OPT_BOOLEAN('q', "quiet", &params.quiet,
320 "be quiet (do not show any mesages)"),
318 OPT_BOOLEAN('l', "list", &params.list_events, 321 OPT_BOOLEAN('l', "list", &params.list_events,
319 "list up current probe events"), 322 "list up current probe events"),
320 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 323 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
@@ -382,6 +385,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
382 }; 385 };
383 int ret; 386 int ret;
384 387
388 set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
389 set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
390 set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
391#ifdef HAVE_DWARF_SUPPORT
392 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
393 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
394#endif
395
385 argc = parse_options(argc, argv, options, probe_usage, 396 argc = parse_options(argc, argv, options, probe_usage,
386 PARSE_OPT_STOP_AT_NON_OPTION); 397 PARSE_OPT_STOP_AT_NON_OPTION);
387 if (argc > 0) { 398 if (argc > 0) {
@@ -396,6 +407,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
396 } 407 }
397 } 408 }
398 409
410 if (params.quiet) {
411 if (verbose != 0) {
412 pr_err(" Error: -v and -q are exclusive.\n");
413 return -EINVAL;
414 }
415 verbose = -1;
416 }
417
399 if (params.max_probe_points == 0) 418 if (params.max_probe_points == 0)
400 params.max_probe_points = MAX_PROBES; 419 params.max_probe_points = MAX_PROBES;
401 420
@@ -409,22 +428,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
409 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 428 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
410 429
411 if (params.list_events) { 430 if (params.list_events) {
412 if (params.mod_events) {
413 pr_err(" Error: Don't use --list with --add/--del.\n");
414 usage_with_options(probe_usage, options);
415 }
416 if (params.show_lines) {
417 pr_err(" Error: Don't use --list with --line.\n");
418 usage_with_options(probe_usage, options);
419 }
420 if (params.show_vars) {
421 pr_err(" Error: Don't use --list with --vars.\n");
422 usage_with_options(probe_usage, options);
423 }
424 if (params.show_funcs) {
425 pr_err(" Error: Don't use --list with --funcs.\n");
426 usage_with_options(probe_usage, options);
427 }
428 if (params.uprobes) { 431 if (params.uprobes) {
429 pr_warning(" Error: Don't use --list with --exec.\n"); 432 pr_warning(" Error: Don't use --list with --exec.\n");
430 usage_with_options(probe_usage, options); 433 usage_with_options(probe_usage, options);
@@ -435,19 +438,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
435 return ret; 438 return ret;
436 } 439 }
437 if (params.show_funcs) { 440 if (params.show_funcs) {
438 if (params.nevents != 0 || params.dellist) {
439 pr_err(" Error: Don't use --funcs with"
440 " --add/--del.\n");
441 usage_with_options(probe_usage, options);
442 }
443 if (params.show_lines) {
444 pr_err(" Error: Don't use --funcs with --line.\n");
445 usage_with_options(probe_usage, options);
446 }
447 if (params.show_vars) {
448 pr_err(" Error: Don't use --funcs with --vars.\n");
449 usage_with_options(probe_usage, options);
450 }
451 if (!params.filter) 441 if (!params.filter)
452 params.filter = strfilter__new(DEFAULT_FUNC_FILTER, 442 params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
453 NULL); 443 NULL);
@@ -462,16 +452,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
462 452
463#ifdef HAVE_DWARF_SUPPORT 453#ifdef HAVE_DWARF_SUPPORT
464 if (params.show_lines) { 454 if (params.show_lines) {
465 if (params.mod_events) {
466 pr_err(" Error: Don't use --line with"
467 " --add/--del.\n");
468 usage_with_options(probe_usage, options);
469 }
470 if (params.show_vars) {
471 pr_err(" Error: Don't use --line with --vars.\n");
472 usage_with_options(probe_usage, options);
473 }
474
475 ret = show_line_range(&params.line_range, params.target, 455 ret = show_line_range(&params.line_range, params.target,
476 params.uprobes); 456 params.uprobes);
477 if (ret < 0) 457 if (ret < 0)
@@ -479,11 +459,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
479 return ret; 459 return ret;
480 } 460 }
481 if (params.show_vars) { 461 if (params.show_vars) {
482 if (params.mod_events) {
483 pr_err(" Error: Don't use --vars with"
484 " --add/--del.\n");
485 usage_with_options(probe_usage, options);
486 }
487 if (!params.filter) 462 if (!params.filter)
488 params.filter = strfilter__new(DEFAULT_VAR_FILTER, 463 params.filter = strfilter__new(DEFAULT_VAR_FILTER,
489 NULL); 464 NULL);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2583a9b04317..5091a27e6d28 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -680,11 +680,12 @@ static int perf_record_config(const char *var, const char *value, void *cb)
680 return perf_default_config(var, value, cb); 680 return perf_default_config(var, value, cb);
681} 681}
682 682
683static const char * const record_usage[] = { 683static const char * const __record_usage[] = {
684 "perf record [<options>] [<command>]", 684 "perf record [<options>] [<command>]",
685 "perf record [<options>] -- <command> [<options>]", 685 "perf record [<options>] -- <command> [<options>]",
686 NULL 686 NULL
687}; 687};
688const char * const *record_usage = __record_usage;
688 689
689/* 690/*
690 * XXX Ideally would be local to cmd_record() and passed to a record__new 691 * XXX Ideally would be local to cmd_record() and passed to a record__new
@@ -725,7 +726,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp";
725 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 726 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
726 * using pipes, etc. 727 * using pipes, etc.
727 */ 728 */
728const struct option record_options[] = { 729struct option __record_options[] = {
729 OPT_CALLBACK('e', "event", &record.evlist, "event", 730 OPT_CALLBACK('e', "event", &record.evlist, "event",
730 "event selector. use 'perf list' to list available events", 731 "event selector. use 'perf list' to list available events",
731 parse_events_option), 732 parse_events_option),
@@ -802,6 +803,8 @@ const struct option record_options[] = {
802 OPT_END() 803 OPT_END()
803}; 804};
804 805
806struct option *record_options = __record_options;
807
805int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 808int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
806{ 809{
807 int err = -ENOMEM; 810 int err = -ENOMEM;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9708a1290571..ce304dfd962a 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -23,7 +23,6 @@ static char const *generate_script_lang;
23static bool debug_mode; 23static bool debug_mode;
24static u64 last_timestamp; 24static u64 last_timestamp;
25static u64 nr_unordered; 25static u64 nr_unordered;
26extern const struct option record_options[];
27static bool no_callchain; 26static bool no_callchain;
28static bool latency_format; 27static bool latency_format;
29static bool system_wide; 28static bool system_wide;
@@ -379,7 +378,6 @@ static void print_sample_start(struct perf_sample *sample,
379 378
380static void print_sample_addr(union perf_event *event, 379static void print_sample_addr(union perf_event *event,
381 struct perf_sample *sample, 380 struct perf_sample *sample,
382 struct machine *machine,
383 struct thread *thread, 381 struct thread *thread,
384 struct perf_event_attr *attr) 382 struct perf_event_attr *attr)
385{ 383{
@@ -390,7 +388,7 @@ static void print_sample_addr(union perf_event *event,
390 if (!sample_addr_correlates_sym(attr)) 388 if (!sample_addr_correlates_sym(attr))
391 return; 389 return;
392 390
393 perf_event__preprocess_sample_addr(event, sample, machine, thread, &al); 391 perf_event__preprocess_sample_addr(event, sample, thread, &al);
394 392
395 if (PRINT_FIELD(SYM)) { 393 if (PRINT_FIELD(SYM)) {
396 printf(" "); 394 printf(" ");
@@ -438,7 +436,7 @@ static void print_sample_bts(union perf_event *event,
438 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 436 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
439 !output[attr->type].user_set)) { 437 !output[attr->type].user_set)) {
440 printf(" => "); 438 printf(" => ");
441 print_sample_addr(event, sample, al->machine, thread, attr); 439 print_sample_addr(event, sample, thread, attr);
442 } 440 }
443 441
444 if (print_srcline_last) 442 if (print_srcline_last)
@@ -475,7 +473,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
475 event_format__print(evsel->tp_format, sample->cpu, 473 event_format__print(evsel->tp_format, sample->cpu,
476 sample->raw_data, sample->raw_size); 474 sample->raw_data, sample->raw_size);
477 if (PRINT_FIELD(ADDR)) 475 if (PRINT_FIELD(ADDR))
478 print_sample_addr(event, sample, al->machine, thread, attr); 476 print_sample_addr(event, sample, thread, attr);
479 477
480 if (PRINT_FIELD(IP)) { 478 if (PRINT_FIELD(IP)) {
481 if (!symbol_conf.use_callchain) 479 if (!symbol_conf.use_callchain)
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 35b425b6293f..f3bb1a4bf060 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -528,7 +528,7 @@ static const char *cat_backtrace(union perf_event *event,
528 } 528 }
529 529
530 tal.filtered = 0; 530 tal.filtered = 0;
531 thread__find_addr_location(al.thread, machine, cpumode, 531 thread__find_addr_location(al.thread, cpumode,
532 MAP__FUNCTION, ip, &tal); 532 MAP__FUNCTION, ip, &tal);
533 533
534 if (tal.sym) 534 if (tal.sym)
@@ -1963,7 +1963,7 @@ int cmd_timechart(int argc, const char **argv,
1963 NULL 1963 NULL
1964 }; 1964 };
1965 1965
1966 const struct option record_options[] = { 1966 const struct option timechart_record_options[] = {
1967 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), 1967 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1968 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, 1968 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1969 "output processes data only"), 1969 "output processes data only"),
@@ -1972,7 +1972,7 @@ int cmd_timechart(int argc, const char **argv,
1972 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), 1972 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1973 OPT_END() 1973 OPT_END()
1974 }; 1974 };
1975 const char * const record_usage[] = { 1975 const char * const timechart_record_usage[] = {
1976 "perf timechart record [<options>]", 1976 "perf timechart record [<options>]",
1977 NULL 1977 NULL
1978 }; 1978 };
@@ -1985,7 +1985,8 @@ int cmd_timechart(int argc, const char **argv,
1985 } 1985 }
1986 1986
1987 if (argc && !strncmp(argv[0], "rec", 3)) { 1987 if (argc && !strncmp(argv[0], "rec", 3)) {
1988 argc = parse_options(argc, argv, record_options, record_usage, 1988 argc = parse_options(argc, argv, timechart_record_options,
1989 timechart_record_usage,
1989 PARSE_OPT_STOP_AT_NON_OPTION); 1990 PARSE_OPT_STOP_AT_NON_OPTION);
1990 1991
1991 if (tchart.power_only && tchart.tasks_only) { 1992 if (tchart.power_only && tchart.tasks_only) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index fb126459b134..83a4835c8118 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1846,7 +1846,7 @@ static int trace__pgfault(struct trace *trace,
1846 if (trace->summary_only) 1846 if (trace->summary_only)
1847 return 0; 1847 return 0;
1848 1848
1849 thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION, 1849 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
1850 sample->ip, &al); 1850 sample->ip, &al);
1851 1851
1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); 1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
@@ -1859,11 +1859,11 @@ static int trace__pgfault(struct trace *trace,
1859 1859
1860 fprintf(trace->output, "] => "); 1860 fprintf(trace->output, "] => ");
1861 1861
1862 thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE, 1862 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
1863 sample->addr, &al); 1863 sample->addr, &al);
1864 1864
1865 if (!al.map) { 1865 if (!al.map) {
1866 thread__find_addr_location(thread, trace->host, cpumode, 1866 thread__find_addr_location(thread, cpumode,
1867 MAP__FUNCTION, sample->addr, &al); 1867 MAP__FUNCTION, sample->addr, &al);
1868 1868
1869 if (al.map) 1869 if (al.map)
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 58f609198c6d..71264e41fa85 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -230,7 +230,9 @@ VF_FEATURE_TESTS = \
230 bionic \ 230 bionic \
231 liberty \ 231 liberty \
232 liberty-z \ 232 liberty-z \
233 cplus-demangle 233 cplus-demangle \
234 compile-32 \
235 compile-x32
234 236
235# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. 237# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
236# If in the future we need per-feature checks/flags for features not 238# If in the future we need per-feature checks/flags for features not
@@ -622,6 +624,31 @@ ifdef HAVE_KVM_STAT_SUPPORT
622 CFLAGS += -DHAVE_KVM_STAT_SUPPORT 624 CFLAGS += -DHAVE_KVM_STAT_SUPPORT
623endif 625endif
624 626
627ifeq (${IS_64_BIT}, 1)
628 ifndef NO_PERF_READ_VDSO32
629 $(call feature_check,compile-32)
630 ifeq ($(feature-compile-32), 1)
631 CFLAGS += -DHAVE_PERF_READ_VDSO32
632 else
633 NO_PERF_READ_VDSO32 := 1
634 endif
635 endif
636 ifneq (${IS_X86_64}, 1)
637 NO_PERF_READ_VDSOX32 := 1
638 endif
639 ifndef NO_PERF_READ_VDSOX32
640 $(call feature_check,compile-x32)
641 ifeq ($(feature-compile-x32), 1)
642 CFLAGS += -DHAVE_PERF_READ_VDSOX32
643 else
644 NO_PERF_READ_VDSOX32 := 1
645 endif
646 endif
647else
648 NO_PERF_READ_VDSO32 := 1
649 NO_PERF_READ_VDSOX32 := 1
650endif
651
625# Among the variables below, these: 652# Among the variables below, these:
626# perfexecdir 653# perfexecdir
627# template_dir 654# template_dir
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
index 4b06719ee984..851cd0172a76 100644
--- a/tools/perf/config/Makefile.arch
+++ b/tools/perf/config/Makefile.arch
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64)
21 RAW_ARCH := x86_64 21 RAW_ARCH := x86_64
22 endif 22 endif
23endif 23endif
24
25ifeq (${IS_X86_64}, 1)
26 IS_64_BIT := 1
27else ifeq ($(ARCH),x86)
28 IS_64_BIT := 0
29else
30 IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
31endif
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 72ab2984718e..7c68ec74a808 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -27,7 +27,9 @@ FILES= \
27 test-libunwind-debug-frame.bin \ 27 test-libunwind-debug-frame.bin \
28 test-stackprotector-all.bin \ 28 test-stackprotector-all.bin \
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 \
32 test-compile-x32.bin
31 33
32CC := $(CROSS_COMPILE)gcc -MD 34CC := $(CROSS_COMPILE)gcc -MD
33PKG_CONFIG := $(CROSS_COMPILE)pkg-config 35PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -131,6 +133,12 @@ test-libdw-dwarf-unwind.bin:
131test-sync-compare-and-swap.bin: 133test-sync-compare-and-swap.bin:
132 $(BUILD) -Werror 134 $(BUILD) -Werror
133 135
136test-compile-32.bin:
137 $(CC) -m32 -o $(OUTPUT)$@ test-compile.c
138
139test-compile-x32.bin:
140 $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
141
134-include *.d 142-include *.d
135 143
136############################### 144###############################
diff --git a/tools/perf/config/feature-checks/test-compile.c b/tools/perf/config/feature-checks/test-compile.c
new file mode 100644
index 000000000000..31dbf45bf99c
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-compile.c
@@ -0,0 +1,4 @@
1int main(void)
2{
3 return 0;
4}
diff --git a/tools/perf/perf-read-vdso.c b/tools/perf/perf-read-vdso.c
new file mode 100644
index 000000000000..764e2547c25a
--- /dev/null
+++ b/tools/perf/perf-read-vdso.c
@@ -0,0 +1,34 @@
1#include <stdio.h>
2#include <string.h>
3
4#define VDSO__MAP_NAME "[vdso]"
5
6/*
7 * Include definition of find_vdso_map() also used in util/vdso.c for
8 * building perf.
9 */
10#include "util/find-vdso-map.c"
11
12int main(void)
13{
14 void *start, *end;
15 size_t size, written;
16
17 if (find_vdso_map(&start, &end))
18 return 1;
19
20 size = end - start;
21
22 while (size) {
23 written = fwrite(start, 1, size, stdout);
24 if (!written)
25 return 1;
26 start += written;
27 size -= written;
28 }
29
30 if (fflush(stdout))
31 return 1;
32
33 return 0;
34}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 220d44e44c1b..511c2831aa81 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -62,4 +62,7 @@ struct record_opts {
62 unsigned initial_delay; 62 unsigned initial_delay;
63}; 63};
64 64
65struct option;
66extern const char * const *record_usage;
67extern struct option *record_options;
65#endif 68#endif
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-record b/tools/perf/scripts/python/bin/export-to-postgresql-record
new file mode 100644
index 000000000000..221d66e05713
--- /dev/null
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-record
@@ -0,0 +1,8 @@
1#!/bin/bash
2
3#
4# export perf data to a postgresql database. Can cover
5# perf ip samples (excluding the tracepoints). No special
6# record requirements, just record what you want to export.
7#
8perf record $@
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-report b/tools/perf/scripts/python/bin/export-to-postgresql-report
new file mode 100644
index 000000000000..a8fdd15f85bf
--- /dev/null
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-report
@@ -0,0 +1,24 @@
1#!/bin/bash
2# description: export perf data to a postgresql database
3# args: [database name] [columns]
4n_args=0
5for i in "$@"
6do
7 if expr match "$i" "-" > /dev/null ; then
8 break
9 fi
10 n_args=$(( $n_args + 1 ))
11done
12if [ "$n_args" -gt 2 ] ; then
13 echo "usage: export-to-postgresql-report [database name] [columns]"
14 exit
15fi
16if [ "$n_args" -gt 1 ] ; then
17 dbname=$1
18 columns=$2
19 shift 2
20elif [ "$n_args" -gt 0 ] ; then
21 dbname=$1
22 shift
23fi
24perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
new file mode 100644
index 000000000000..d8f6df0093d6
--- /dev/null
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -0,0 +1,360 @@
1# export-to-postgresql.py: export perf data to a postgresql database
2# Copyright (c) 2014, Intel Corporation.
3#
4# This program is free software; you can redistribute it and/or modify it
5# under the terms and conditions of the GNU General Public License,
6# version 2, as published by the Free Software Foundation.
7#
8# This program is distributed in the hope it will be useful, but WITHOUT
9# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11# more details.
12
13import os
14import sys
15import struct
16import datetime
17
18from PySide.QtSql import *
19
20# Need to access PostgreSQL C library directly to use COPY FROM STDIN
21from ctypes import *
22libpq = CDLL("libpq.so.5")
23PQconnectdb = libpq.PQconnectdb
24PQconnectdb.restype = c_void_p
25PQfinish = libpq.PQfinish
26PQstatus = libpq.PQstatus
27PQexec = libpq.PQexec
28PQexec.restype = c_void_p
29PQresultStatus = libpq.PQresultStatus
30PQputCopyData = libpq.PQputCopyData
31PQputCopyData.argtypes = [ c_void_p, c_void_p, c_int ]
32PQputCopyEnd = libpq.PQputCopyEnd
33PQputCopyEnd.argtypes = [ c_void_p, c_void_p ]
34
35sys.path.append(os.environ['PERF_EXEC_PATH'] + \
36 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
37
38# These perf imports are not used at present
39#from perf_trace_context import *
40#from Core import *
41
42perf_db_export_mode = True
43
44def usage():
45 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>]"
46 print >> sys.stderr, "where: columns 'all' or 'branches'"
47 raise Exception("Too few arguments")
48
49if (len(sys.argv) < 2):
50 usage()
51
52dbname = sys.argv[1]
53
54if (len(sys.argv) >= 3):
55 columns = sys.argv[2]
56else:
57 columns = "all"
58
59if columns not in ("all", "branches"):
60 usage()
61
62branches = (columns == "branches")
63
64output_dir_name = os.getcwd() + "/" + dbname + "-perf-data"
65os.mkdir(output_dir_name)
66
67def do_query(q, s):
68 if (q.exec_(s)):
69 return
70 raise Exception("Query failed: " + q.lastError().text())
71
72print datetime.datetime.today(), "Creating database..."
73
74db = QSqlDatabase.addDatabase('QPSQL')
75query = QSqlQuery(db)
76db.setDatabaseName('postgres')
77db.open()
78try:
79 do_query(query, 'CREATE DATABASE ' + dbname)
80except:
81 os.rmdir(output_dir_name)
82 raise
83query.finish()
84query.clear()
85db.close()
86
87db.setDatabaseName(dbname)
88db.open()
89
90query = QSqlQuery(db)
91do_query(query, 'SET client_min_messages TO WARNING')
92
93do_query(query, 'CREATE TABLE selected_events ('
94 'id bigint NOT NULL,'
95 'name varchar(80))')
96do_query(query, 'CREATE TABLE machines ('
97 'id bigint NOT NULL,'
98 'pid integer,'
99 'root_dir varchar(4096))')
100do_query(query, 'CREATE TABLE threads ('
101 'id bigint NOT NULL,'
102 'machine_id bigint,'
103 'process_id bigint,'
104 'pid integer,'
105 'tid integer)')
106do_query(query, 'CREATE TABLE comms ('
107 'id bigint NOT NULL,'
108 'comm varchar(16))')
109do_query(query, 'CREATE TABLE comm_threads ('
110 'id bigint NOT NULL,'
111 'comm_id bigint,'
112 'thread_id bigint)')
113do_query(query, 'CREATE TABLE dsos ('
114 'id bigint NOT NULL,'
115 'machine_id bigint,'
116 'short_name varchar(256),'
117 'long_name varchar(4096),'
118 'build_id varchar(64))')
119do_query(query, 'CREATE TABLE symbols ('
120 'id bigint NOT NULL,'
121 'dso_id bigint,'
122 'sym_start bigint,'
123 'sym_end bigint,'
124 'binding integer,'
125 'name varchar(2048))')
126if branches:
127 do_query(query, 'CREATE TABLE samples ('
128 'id bigint NOT NULL,'
129 'evsel_id bigint,'
130 'machine_id bigint,'
131 'thread_id bigint,'
132 'comm_id bigint,'
133 'dso_id bigint,'
134 'symbol_id bigint,'
135 'sym_offset bigint,'
136 'ip bigint,'
137 'time bigint,'
138 'cpu integer,'
139 'to_dso_id bigint,'
140 'to_symbol_id bigint,'
141 'to_sym_offset bigint,'
142 'to_ip bigint)')
143else:
144 do_query(query, 'CREATE TABLE samples ('
145 'id bigint NOT NULL,'
146 'evsel_id bigint,'
147 'machine_id bigint,'
148 'thread_id bigint,'
149 'comm_id bigint,'
150 'dso_id bigint,'
151 'symbol_id bigint,'
152 'sym_offset bigint,'
153 'ip bigint,'
154 'time bigint,'
155 'cpu integer,'
156 'to_dso_id bigint,'
157 'to_symbol_id bigint,'
158 'to_sym_offset bigint,'
159 'to_ip bigint,'
160 'period bigint,'
161 'weight bigint,'
162 'transaction bigint,'
163 'data_src bigint)')
164
165do_query(query, 'CREATE VIEW samples_view AS '
166 'SELECT '
167 'id,'
168 'time,'
169 'cpu,'
170 '(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
171 '(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
172 '(SELECT comm FROM comms WHERE id = comm_id) AS command,'
173 '(SELECT name FROM selected_events WHERE id = evsel_id) AS event,'
174 'to_hex(ip) AS ip_hex,'
175 '(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
176 'sym_offset,'
177 '(SELECT short_name FROM dsos WHERE id = dso_id) AS dso_short_name,'
178 'to_hex(to_ip) AS to_ip_hex,'
179 '(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
180 'to_sym_offset,'
181 '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name'
182 ' FROM samples')
183
184
185file_header = struct.pack("!11sii", "PGCOPY\n\377\r\n\0", 0, 0)
186file_trailer = "\377\377"
187
188def open_output_file(file_name):
189 path_name = output_dir_name + "/" + file_name
190 file = open(path_name, "w+")
191 file.write(file_header)
192 return file
193
194def close_output_file(file):
195 file.write(file_trailer)
196 file.close()
197
198def copy_output_file_direct(file, table_name):
199 close_output_file(file)
200 sql = "COPY " + table_name + " FROM '" + file.name + "' (FORMAT 'binary')"
201 do_query(query, sql)
202
203# Use COPY FROM STDIN because security may prevent postgres from accessing the files directly
204def copy_output_file(file, table_name):
205 conn = PQconnectdb("dbname = " + dbname)
206 if (PQstatus(conn)):
207 raise Exception("COPY FROM STDIN PQconnectdb failed")
208 file.write(file_trailer)
209 file.seek(0)
210 sql = "COPY " + table_name + " FROM STDIN (FORMAT 'binary')"
211 res = PQexec(conn, sql)
212 if (PQresultStatus(res) != 4):
213 raise Exception("COPY FROM STDIN PQexec failed")
214 data = file.read(65536)
215 while (len(data)):
216 ret = PQputCopyData(conn, data, len(data))
217 if (ret != 1):
218 raise Exception("COPY FROM STDIN PQputCopyData failed, error " + str(ret))
219 data = file.read(65536)
220 ret = PQputCopyEnd(conn, None)
221 if (ret != 1):
222 raise Exception("COPY FROM STDIN PQputCopyEnd failed, error " + str(ret))
223 PQfinish(conn)
224
225def remove_output_file(file):
226 name = file.name
227 file.close()
228 os.unlink(name)
229
230evsel_file = open_output_file("evsel_table.bin")
231machine_file = open_output_file("machine_table.bin")
232thread_file = open_output_file("thread_table.bin")
233comm_file = open_output_file("comm_table.bin")
234comm_thread_file = open_output_file("comm_thread_table.bin")
235dso_file = open_output_file("dso_table.bin")
236symbol_file = open_output_file("symbol_table.bin")
237sample_file = open_output_file("sample_table.bin")
238
239def trace_begin():
240 print datetime.datetime.today(), "Writing to intermediate files..."
241 # id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs
242 evsel_table(0, "unknown")
243 machine_table(0, 0, "unknown")
244 thread_table(0, 0, 0, -1, -1)
245 comm_table(0, "unknown")
246 dso_table(0, 0, "unknown", "unknown", "")
247 symbol_table(0, 0, 0, 0, 0, "unknown")
248
249unhandled_count = 0
250
251def trace_end():
252 print datetime.datetime.today(), "Copying to database..."
253 copy_output_file(evsel_file, "selected_events")
254 copy_output_file(machine_file, "machines")
255 copy_output_file(thread_file, "threads")
256 copy_output_file(comm_file, "comms")
257 copy_output_file(comm_thread_file, "comm_threads")
258 copy_output_file(dso_file, "dsos")
259 copy_output_file(symbol_file, "symbols")
260 copy_output_file(sample_file, "samples")
261
262 print datetime.datetime.today(), "Removing intermediate files..."
263 remove_output_file(evsel_file)
264 remove_output_file(machine_file)
265 remove_output_file(thread_file)
266 remove_output_file(comm_file)
267 remove_output_file(comm_thread_file)
268 remove_output_file(dso_file)
269 remove_output_file(symbol_file)
270 remove_output_file(sample_file)
271 os.rmdir(output_dir_name)
272 print datetime.datetime.today(), "Adding primary keys"
273 do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
274 do_query(query, 'ALTER TABLE machines ADD PRIMARY KEY (id)')
275 do_query(query, 'ALTER TABLE threads ADD PRIMARY KEY (id)')
276 do_query(query, 'ALTER TABLE comms ADD PRIMARY KEY (id)')
277 do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)')
278 do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)')
279 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
280 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
281
282 print datetime.datetime.today(), "Adding foreign keys"
283 do_query(query, 'ALTER TABLE threads '
284 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),'
285 'ADD CONSTRAINT processfk FOREIGN KEY (process_id) REFERENCES threads (id)')
286 do_query(query, 'ALTER TABLE comm_threads '
287 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
288 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id)')
289 do_query(query, 'ALTER TABLE dsos '
290 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id)')
291 do_query(query, 'ALTER TABLE symbols '
292 'ADD CONSTRAINT dsofk FOREIGN KEY (dso_id) REFERENCES dsos (id)')
293 do_query(query, 'ALTER TABLE samples '
294 'ADD CONSTRAINT evselfk FOREIGN KEY (evsel_id) REFERENCES selected_events (id),'
295 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),'
296 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
297 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
298 'ADD CONSTRAINT dsofk FOREIGN KEY (dso_id) REFERENCES dsos (id),'
299 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
300 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
301 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
302
303 if (unhandled_count):
304 print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
305 print datetime.datetime.today(), "Done"
306
307def trace_unhandled(event_name, context, event_fields_dict):
308 global unhandled_count
309 unhandled_count += 1
310
311def sched__sched_switch(*x):
312 pass
313
314def evsel_table(evsel_id, evsel_name, *x):
315 n = len(evsel_name)
316 fmt = "!hiqi" + str(n) + "s"
317 value = struct.pack(fmt, 2, 8, evsel_id, n, evsel_name)
318 evsel_file.write(value)
319
320def machine_table(machine_id, pid, root_dir, *x):
321 n = len(root_dir)
322 fmt = "!hiqiii" + str(n) + "s"
323 value = struct.pack(fmt, 3, 8, machine_id, 4, pid, n, root_dir)
324 machine_file.write(value)
325
326def thread_table(thread_id, machine_id, process_id, pid, tid, *x):
327 value = struct.pack("!hiqiqiqiiii", 5, 8, thread_id, 8, machine_id, 8, process_id, 4, pid, 4, tid)
328 thread_file.write(value)
329
330def comm_table(comm_id, comm_str, *x):
331 n = len(comm_str)
332 fmt = "!hiqi" + str(n) + "s"
333 value = struct.pack(fmt, 2, 8, comm_id, n, comm_str)
334 comm_file.write(value)
335
336def comm_thread_table(comm_thread_id, comm_id, thread_id, *x):
337 fmt = "!hiqiqiq"
338 value = struct.pack(fmt, 3, 8, comm_thread_id, 8, comm_id, 8, thread_id)
339 comm_thread_file.write(value)
340
341def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x):
342 n1 = len(short_name)
343 n2 = len(long_name)
344 n3 = len(build_id)
345 fmt = "!hiqiqi" + str(n1) + "si" + str(n2) + "si" + str(n3) + "s"
346 value = struct.pack(fmt, 5, 8, dso_id, 8, machine_id, n1, short_name, n2, long_name, n3, build_id)
347 dso_file.write(value)
348
349def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x):
350 n = len(symbol_name)
351 fmt = "!hiqiqiqiqiii" + str(n) + "s"
352 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)
354
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):
356 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)
358 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)
360 sample_file.write(value)
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 67f2d6323558..f671ec37a7c4 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -133,8 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
133} 133}
134 134
135static int read_object_code(u64 addr, size_t len, u8 cpumode, 135static int read_object_code(u64 addr, size_t len, u8 cpumode,
136 struct thread *thread, struct machine *machine, 136 struct thread *thread, struct state *state)
137 struct state *state)
138{ 137{
139 struct addr_location al; 138 struct addr_location al;
140 unsigned char buf1[BUFSZ]; 139 unsigned char buf1[BUFSZ];
@@ -145,8 +144,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
145 144
146 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); 145 pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
147 146
148 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr, 147 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al);
149 &al);
150 if (!al.map || !al.map->dso) { 148 if (!al.map || !al.map->dso) {
151 pr_debug("thread__find_addr_map failed\n"); 149 pr_debug("thread__find_addr_map failed\n");
152 return -1; 150 return -1;
@@ -170,8 +168,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
170 len = al.map->end - addr; 168 len = al.map->end - addr;
171 169
172 /* Read the object code using perf */ 170 /* Read the object code using perf */
173 ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1, 171 ret_len = dso__data_read_offset(al.map->dso, thread->mg->machine,
174 len); 172 al.addr, buf1, len);
175 if (ret_len != len) { 173 if (ret_len != len) {
176 pr_debug("dso__data_read_offset failed\n"); 174 pr_debug("dso__data_read_offset failed\n");
177 return -1; 175 return -1;
@@ -264,8 +262,7 @@ static int process_sample_event(struct machine *machine,
264 262
265 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 263 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
266 264
267 return read_object_code(sample.ip, READLEN, cpumode, thread, machine, 265 return read_object_code(sample.ip, READLEN, cpumode, thread, state);
268 state);
269} 266}
270 267
271static int process_event(struct machine *machine, struct perf_evlist *evlist, 268static int process_event(struct machine *machine, struct perf_evlist *evlist,
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index fc25e57f4a5d..ab28cca2cb97 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -59,7 +59,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
59} 59}
60 60
61__attribute__ ((noinline)) 61__attribute__ ((noinline))
62static int unwind_thread(struct thread *thread, struct machine *machine) 62static int unwind_thread(struct thread *thread)
63{ 63{
64 struct perf_sample sample; 64 struct perf_sample sample;
65 unsigned long cnt = 0; 65 unsigned long cnt = 0;
@@ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
72 goto out; 72 goto out;
73 } 73 }
74 74
75 err = unwind__get_entries(unwind_entry, &cnt, machine, thread, 75 err = unwind__get_entries(unwind_entry, &cnt, thread,
76 &sample, MAX_STACK); 76 &sample, MAX_STACK);
77 if (err) 77 if (err)
78 pr_debug("unwind failed\n"); 78 pr_debug("unwind failed\n");
@@ -89,21 +89,21 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
89} 89}
90 90
91__attribute__ ((noinline)) 91__attribute__ ((noinline))
92static int krava_3(struct thread *thread, struct machine *machine) 92static int krava_3(struct thread *thread)
93{ 93{
94 return unwind_thread(thread, machine); 94 return unwind_thread(thread);
95} 95}
96 96
97__attribute__ ((noinline)) 97__attribute__ ((noinline))
98static int krava_2(struct thread *thread, struct machine *machine) 98static int krava_2(struct thread *thread)
99{ 99{
100 return krava_3(thread, machine); 100 return krava_3(thread);
101} 101}
102 102
103__attribute__ ((noinline)) 103__attribute__ ((noinline))
104static int krava_1(struct thread *thread, struct machine *machine) 104static int krava_1(struct thread *thread)
105{ 105{
106 return krava_2(thread, machine); 106 return krava_2(thread);
107} 107}
108 108
109int test__dwarf_unwind(void) 109int test__dwarf_unwind(void)
@@ -137,7 +137,7 @@ int test__dwarf_unwind(void)
137 goto out; 137 goto out;
138 } 138 }
139 139
140 err = krava_1(thread, machine); 140 err = krava_1(thread);
141 141
142 out: 142 out:
143 machine__delete_threads(machine); 143 machine__delete_threads(machine);
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 5a31787cc6b9..74f257a81265 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -43,7 +43,7 @@ static struct sample fake_samples[] = {
43}; 43};
44 44
45static int add_hist_entries(struct perf_evlist *evlist, 45static int add_hist_entries(struct perf_evlist *evlist,
46 struct machine *machine __maybe_unused) 46 struct machine *machine)
47{ 47{
48 struct perf_evsel *evsel; 48 struct perf_evsel *evsel;
49 struct addr_location al; 49 struct addr_location al;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 4a456fef66ca..2113f1c8611f 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -187,7 +187,7 @@ static int mmap_events(synth_cb synth)
187 187
188 pr_debug("looking for map %p\n", td->map); 188 pr_debug("looking for map %p\n", td->map);
189 189
190 thread__find_addr_map(thread, machine, 190 thread__find_addr_map(thread,
191 PERF_RECORD_MISC_USER, MAP__FUNCTION, 191 PERF_RECORD_MISC_USER, MAP__FUNCTION,
192 (unsigned long) (td->map + 1), &al); 192 (unsigned long) (td->map + 1), &al);
193 193
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a904a4cfe7d3..2e7c68e39330 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -33,8 +33,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
33 return -1; 33 return -1;
34 } 34 }
35 35
36 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 36 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
37 sample->ip, &al);
38 37
39 if (al.map != NULL) 38 if (al.map != NULL)
40 al.map->dso->hit = 1; 39 al.map->dso->hit = 1;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index c84d3f8dcb75..00229809a904 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -754,8 +754,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
754 754
755 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || 755 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
756 sort__has_parent) { 756 sort__has_parent) {
757 return machine__resolve_callchain(al->machine, evsel, al->thread, 757 return thread__resolve_callchain(al->thread, evsel, sample,
758 sample, parent, al, max_stack); 758 parent, al, max_stack);
759 } 759 }
760 return 0; 760 return 0;
761} 761}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 94cfefddf4db..3caccc2c173c 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -184,11 +184,9 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
184} 184}
185 185
186#ifdef HAVE_SKIP_CALLCHAIN_IDX 186#ifdef HAVE_SKIP_CALLCHAIN_IDX
187extern int arch_skip_callchain_idx(struct machine *machine, 187extern int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain);
188 struct thread *thread, struct ip_callchain *chain);
189#else 188#else
190static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused, 189static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
191 struct thread *thread __maybe_unused,
192 struct ip_callchain *chain __maybe_unused) 190 struct ip_callchain *chain __maybe_unused)
193{ 191{
194 return -1; 192 return -1;
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index 51c10ab257f8..71c9c39340d4 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -12,6 +12,10 @@ struct comm {
12 u64 start; 12 u64 start;
13 struct list_head list; 13 struct list_head list;
14 bool exec; 14 bool exec;
15 union { /* Tool specific area */
16 void *priv;
17 u64 db_id;
18 };
15}; 19};
16 20
17void comm__free(struct comm *comm); 21void comm__free(struct comm *comm);
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
new file mode 100644
index 000000000000..be128b075a32
--- /dev/null
+++ b/tools/perf/util/db-export.c
@@ -0,0 +1,270 @@
1/*
2 * db-export.c: Support for exporting data suitable for import to a database
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 <errno.h>
17
18#include "evsel.h"
19#include "machine.h"
20#include "thread.h"
21#include "comm.h"
22#include "symbol.h"
23#include "event.h"
24#include "db-export.h"
25
26int db_export__init(struct db_export *dbe)
27{
28 memset(dbe, 0, sizeof(struct db_export));
29 return 0;
30}
31
32void db_export__exit(struct db_export *dbe __maybe_unused)
33{
34}
35
36int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
37{
38 if (evsel->db_id)
39 return 0;
40
41 evsel->db_id = ++dbe->evsel_last_db_id;
42
43 if (dbe->export_evsel)
44 return dbe->export_evsel(dbe, evsel);
45
46 return 0;
47}
48
49int db_export__machine(struct db_export *dbe, struct machine *machine)
50{
51 if (machine->db_id)
52 return 0;
53
54 machine->db_id = ++dbe->machine_last_db_id;
55
56 if (dbe->export_machine)
57 return dbe->export_machine(dbe, machine);
58
59 return 0;
60}
61
62int db_export__thread(struct db_export *dbe, struct thread *thread,
63 struct machine *machine, struct comm *comm)
64{
65 u64 main_thread_db_id = 0;
66 int err;
67
68 if (thread->db_id)
69 return 0;
70
71 thread->db_id = ++dbe->thread_last_db_id;
72
73 if (thread->pid_ != -1) {
74 struct thread *main_thread;
75
76 if (thread->pid_ == thread->tid) {
77 main_thread = thread;
78 } else {
79 main_thread = machine__findnew_thread(machine,
80 thread->pid_,
81 thread->pid_);
82 if (!main_thread)
83 return -ENOMEM;
84 err = db_export__thread(dbe, main_thread, machine,
85 comm);
86 if (err)
87 return err;
88 if (comm) {
89 err = db_export__comm_thread(dbe, comm, thread);
90 if (err)
91 return err;
92 }
93 }
94 main_thread_db_id = main_thread->db_id;
95 }
96
97 if (dbe->export_thread)
98 return dbe->export_thread(dbe, thread, main_thread_db_id,
99 machine);
100
101 return 0;
102}
103
104int db_export__comm(struct db_export *dbe, struct comm *comm,
105 struct thread *main_thread)
106{
107 int err;
108
109 if (comm->db_id)
110 return 0;
111
112 comm->db_id = ++dbe->comm_last_db_id;
113
114 if (dbe->export_comm) {
115 err = dbe->export_comm(dbe, comm);
116 if (err)
117 return err;
118 }
119
120 return db_export__comm_thread(dbe, comm, main_thread);
121}
122
123int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
124 struct thread *thread)
125{
126 u64 db_id;
127
128 db_id = ++dbe->comm_thread_last_db_id;
129
130 if (dbe->export_comm_thread)
131 return dbe->export_comm_thread(dbe, db_id, comm, thread);
132
133 return 0;
134}
135
136int db_export__dso(struct db_export *dbe, struct dso *dso,
137 struct machine *machine)
138{
139 if (dso->db_id)
140 return 0;
141
142 dso->db_id = ++dbe->dso_last_db_id;
143
144 if (dbe->export_dso)
145 return dbe->export_dso(dbe, dso, machine);
146
147 return 0;
148}
149
150int db_export__symbol(struct db_export *dbe, struct symbol *sym,
151 struct dso *dso)
152{
153 u64 *sym_db_id = symbol__priv(sym);
154
155 if (*sym_db_id)
156 return 0;
157
158 *sym_db_id = ++dbe->symbol_last_db_id;
159
160 if (dbe->export_symbol)
161 return dbe->export_symbol(dbe, sym, dso);
162
163 return 0;
164}
165
166static struct thread *get_main_thread(struct machine *machine, struct thread *thread)
167{
168 if (thread->pid_ == thread->tid)
169 return thread;
170
171 if (thread->pid_ == -1)
172 return NULL;
173
174 return machine__find_thread(machine, thread->pid_, thread->pid_);
175}
176
177static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
178 u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
179{
180 int err;
181
182 if (al->map) {
183 struct dso *dso = al->map->dso;
184
185 err = db_export__dso(dbe, dso, al->machine);
186 if (err)
187 return err;
188 *dso_db_id = dso->db_id;
189
190 if (!al->sym) {
191 al->sym = symbol__new(al->addr, 0, 0, "unknown");
192 if (al->sym)
193 symbols__insert(&dso->symbols[al->map->type],
194 al->sym);
195 }
196
197 if (al->sym) {
198 u64 *db_id = symbol__priv(al->sym);
199
200 err = db_export__symbol(dbe, al->sym, dso);
201 if (err)
202 return err;
203 *sym_db_id = *db_id;
204 *offset = al->addr - al->sym->start;
205 }
206 }
207
208 return 0;
209}
210
211int db_export__sample(struct db_export *dbe, union perf_event *event,
212 struct perf_sample *sample, struct perf_evsel *evsel,
213 struct thread *thread, struct addr_location *al)
214{
215 struct export_sample es = {
216 .event = event,
217 .sample = sample,
218 .evsel = evsel,
219 .thread = thread,
220 .al = al,
221 };
222 struct thread *main_thread;
223 struct comm *comm = NULL;
224 int err;
225
226 err = db_export__evsel(dbe, evsel);
227 if (err)
228 return err;
229
230 err = db_export__machine(dbe, al->machine);
231 if (err)
232 return err;
233
234 main_thread = get_main_thread(al->machine, thread);
235 if (main_thread)
236 comm = machine__thread_exec_comm(al->machine, main_thread);
237
238 err = db_export__thread(dbe, thread, al->machine, comm);
239 if (err)
240 return err;
241
242 if (comm) {
243 err = db_export__comm(dbe, comm, main_thread);
244 if (err)
245 return err;
246 es.comm_db_id = comm->db_id;
247 }
248
249 es.db_id = ++dbe->sample_last_db_id;
250
251 err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
252 if (err)
253 return err;
254
255 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
256 sample_addr_correlates_sym(&evsel->attr)) {
257 struct addr_location addr_al;
258
259 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al);
260 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
261 &es.addr_sym_db_id, &es.addr_offset);
262 if (err)
263 return err;
264 }
265
266 if (dbe->export_sample)
267 return dbe->export_sample(dbe, &es);
268
269 return 0;
270}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
new file mode 100644
index 000000000000..b3643e8e5750
--- /dev/null
+++ b/tools/perf/util/db-export.h
@@ -0,0 +1,86 @@
1/*
2 * db-export.h: Support for exporting data suitable for import to a database
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_DB_EXPORT_H
17#define __PERF_DB_EXPORT_H
18
19#include <linux/types.h>
20
21struct perf_evsel;
22struct machine;
23struct thread;
24struct comm;
25struct dso;
26struct perf_sample;
27struct addr_location;
28
29struct export_sample {
30 union perf_event *event;
31 struct perf_sample *sample;
32 struct perf_evsel *evsel;
33 struct thread *thread;
34 struct addr_location *al;
35 u64 db_id;
36 u64 comm_db_id;
37 u64 dso_db_id;
38 u64 sym_db_id;
39 u64 offset; /* ip offset from symbol start */
40 u64 addr_dso_db_id;
41 u64 addr_sym_db_id;
42 u64 addr_offset; /* addr offset from symbol start */
43};
44
45struct db_export {
46 int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel);
47 int (*export_machine)(struct db_export *dbe, struct machine *machine);
48 int (*export_thread)(struct db_export *dbe, struct thread *thread,
49 u64 main_thread_db_id, struct machine *machine);
50 int (*export_comm)(struct db_export *dbe, struct comm *comm);
51 int (*export_comm_thread)(struct db_export *dbe, u64 db_id,
52 struct comm *comm, struct thread *thread);
53 int (*export_dso)(struct db_export *dbe, struct dso *dso,
54 struct machine *machine);
55 int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
56 struct dso *dso);
57 int (*export_sample)(struct db_export *dbe, struct export_sample *es);
58 u64 evsel_last_db_id;
59 u64 machine_last_db_id;
60 u64 thread_last_db_id;
61 u64 comm_last_db_id;
62 u64 comm_thread_last_db_id;
63 u64 dso_last_db_id;
64 u64 symbol_last_db_id;
65 u64 sample_last_db_id;
66};
67
68int db_export__init(struct db_export *dbe);
69void db_export__exit(struct db_export *dbe);
70int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
71int db_export__machine(struct db_export *dbe, struct machine *machine);
72int db_export__thread(struct db_export *dbe, struct thread *thread,
73 struct machine *machine, struct comm *comm);
74int db_export__comm(struct db_export *dbe, struct comm *comm,
75 struct thread *main_thread);
76int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
77 struct thread *thread);
78int db_export__dso(struct db_export *dbe, struct dso *dso,
79 struct machine *machine);
80int db_export__symbol(struct db_export *dbe, struct symbol *sym,
81 struct dso *dso);
82int db_export__sample(struct db_export *dbe, union perf_event *event,
83 struct perf_sample *sample, struct perf_evsel *evsel,
84 struct thread *thread, struct addr_location *al);
85
86#endif
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index acb651acc7fd..a316e4af321f 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -127,6 +127,7 @@ struct dso {
127 const char *long_name; 127 const char *long_name;
128 u16 long_name_len; 128 u16 long_name_len;
129 u16 short_name_len; 129 u16 short_name_len;
130 void *dwfl; /* DWARF debug info */
130 131
131 /* dso data file */ 132 /* dso data file */
132 struct { 133 struct {
@@ -138,6 +139,11 @@ struct dso {
138 struct list_head open_entry; 139 struct list_head open_entry;
139 } data; 140 } data;
140 141
142 union { /* Tool specific area */
143 void *priv;
144 u64 db_id;
145 };
146
141 char name[0]; 147 char name[0];
142}; 148};
143 149
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 4af6b279e34a..6c6d044e959a 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = {
28 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 28 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
29 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 29 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
30 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 30 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
31 [PERF_RECORD_ID_INDEX] = "ID_INDEX",
31}; 32};
32 33
33const char *perf_event__name(unsigned int id) 34const char *perf_event__name(unsigned int id)
@@ -730,12 +731,12 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,
730 return machine__process_event(machine, event, sample); 731 return machine__process_event(machine, event, sample);
731} 732}
732 733
733void thread__find_addr_map(struct thread *thread, 734void thread__find_addr_map(struct thread *thread, u8 cpumode,
734 struct machine *machine, u8 cpumode,
735 enum map_type type, u64 addr, 735 enum map_type type, u64 addr,
736 struct addr_location *al) 736 struct addr_location *al)
737{ 737{
738 struct map_groups *mg = thread->mg; 738 struct map_groups *mg = thread->mg;
739 struct machine *machine = mg->machine;
739 bool load_map = false; 740 bool load_map = false;
740 741
741 al->machine = machine; 742 al->machine = machine;
@@ -806,14 +807,14 @@ try_again:
806 } 807 }
807} 808}
808 809
809void thread__find_addr_location(struct thread *thread, struct machine *machine, 810void thread__find_addr_location(struct thread *thread,
810 u8 cpumode, enum map_type type, u64 addr, 811 u8 cpumode, enum map_type type, u64 addr,
811 struct addr_location *al) 812 struct addr_location *al)
812{ 813{
813 thread__find_addr_map(thread, machine, cpumode, type, addr, al); 814 thread__find_addr_map(thread, cpumode, type, addr, al);
814 if (al->map != NULL) 815 if (al->map != NULL)
815 al->sym = map__find_symbol(al->map, al->addr, 816 al->sym = map__find_symbol(al->map, al->addr,
816 machine->symbol_filter); 817 thread->mg->machine->symbol_filter);
817 else 818 else
818 al->sym = NULL; 819 al->sym = NULL;
819} 820}
@@ -842,8 +843,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
842 machine->vmlinux_maps[MAP__FUNCTION] == NULL) 843 machine->vmlinux_maps[MAP__FUNCTION] == NULL)
843 machine__create_kernel_maps(machine); 844 machine__create_kernel_maps(machine);
844 845
845 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 846 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al);
846 sample->ip, al);
847 dump_printf(" ...... dso: %s\n", 847 dump_printf(" ...... dso: %s\n",
848 al->map ? al->map->dso->long_name : 848 al->map ? al->map->dso->long_name :
849 al->level == 'H' ? "[hypervisor]" : "<not found>"); 849 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -902,16 +902,14 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)
902 902
903void perf_event__preprocess_sample_addr(union perf_event *event, 903void perf_event__preprocess_sample_addr(union perf_event *event,
904 struct perf_sample *sample, 904 struct perf_sample *sample,
905 struct machine *machine,
906 struct thread *thread, 905 struct thread *thread,
907 struct addr_location *al) 906 struct addr_location *al)
908{ 907{
909 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 908 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
910 909
911 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 910 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al);
912 sample->addr, al);
913 if (!al->map) 911 if (!al->map)
914 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, 912 thread__find_addr_map(thread, cpumode, MAP__VARIABLE,
915 sample->addr, al); 913 sample->addr, al);
916 914
917 al->cpu = sample->cpu; 915 al->cpu = sample->cpu;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 5699e7e2a790..8c7fe9d64e79 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -187,6 +187,7 @@ enum perf_user_event_type { /* above any possible kernel type */
187 PERF_RECORD_HEADER_TRACING_DATA = 66, 187 PERF_RECORD_HEADER_TRACING_DATA = 66,
188 PERF_RECORD_HEADER_BUILD_ID = 67, 188 PERF_RECORD_HEADER_BUILD_ID = 67,
189 PERF_RECORD_FINISHED_ROUND = 68, 189 PERF_RECORD_FINISHED_ROUND = 68,
190 PERF_RECORD_ID_INDEX = 69,
190 PERF_RECORD_HEADER_MAX 191 PERF_RECORD_HEADER_MAX
191}; 192};
192 193
@@ -239,6 +240,19 @@ struct tracing_data_event {
239 u32 size; 240 u32 size;
240}; 241};
241 242
243struct id_index_entry {
244 u64 id;
245 u64 idx;
246 u64 cpu;
247 u64 tid;
248};
249
250struct id_index_event {
251 struct perf_event_header header;
252 u64 nr;
253 struct id_index_entry entries[0];
254};
255
242union perf_event { 256union perf_event {
243 struct perf_event_header header; 257 struct perf_event_header header;
244 struct mmap_event mmap; 258 struct mmap_event mmap;
@@ -253,6 +267,7 @@ union perf_event {
253 struct event_type_event event_type; 267 struct event_type_event event_type;
254 struct tracing_data_event tracing_data; 268 struct tracing_data_event tracing_data;
255 struct build_id_event build_id; 269 struct build_id_event build_id;
270 struct id_index_event id_index;
256}; 271};
257 272
258void perf_event__print_totals(void); 273void perf_event__print_totals(void);
@@ -322,7 +337,6 @@ bool is_bts_event(struct perf_event_attr *attr);
322bool sample_addr_correlates_sym(struct perf_event_attr *attr); 337bool sample_addr_correlates_sym(struct perf_event_attr *attr);
323void perf_event__preprocess_sample_addr(union perf_event *event, 338void perf_event__preprocess_sample_addr(union perf_event *event,
324 struct perf_sample *sample, 339 struct perf_sample *sample,
325 struct machine *machine,
326 struct thread *thread, 340 struct thread *thread,
327 struct addr_location *al); 341 struct addr_location *al);
328 342
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3c9e77d6b4c2..7e23dae54f1d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -413,7 +413,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
413 int nfds = 0; 413 int nfds = 0;
414 struct perf_evsel *evsel; 414 struct perf_evsel *evsel;
415 415
416 list_for_each_entry(evsel, &evlist->entries, node) { 416 evlist__for_each(evlist, evsel) {
417 if (evsel->system_wide) 417 if (evsel->system_wide)
418 nfds += nr_cpus; 418 nfds += nr_cpus;
419 else 419 else
@@ -527,6 +527,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
527 return 0; 527 return 0;
528} 528}
529 529
530static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
531 struct perf_evsel *evsel, int idx, int cpu,
532 int thread)
533{
534 struct perf_sample_id *sid = SID(evsel, cpu, thread);
535 sid->idx = idx;
536 if (evlist->cpus && cpu >= 0)
537 sid->cpu = evlist->cpus->map[cpu];
538 else
539 sid->cpu = -1;
540 if (!evsel->system_wide && evlist->threads && thread >= 0)
541 sid->tid = evlist->threads->map[thread];
542 else
543 sid->tid = -1;
544}
545
530struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) 546struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
531{ 547{
532 struct hlist_head *head; 548 struct hlist_head *head;
@@ -805,9 +821,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
805 return -1; 821 return -1;
806 } 822 }
807 823
808 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 824 if (evsel->attr.read_format & PERF_FORMAT_ID) {
809 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) 825 if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
810 return -1; 826 fd) < 0)
827 return -1;
828 perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
829 thread);
830 }
811 } 831 }
812 832
813 return 0; 833 return 0;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 163c5604e5d1..979790951bfb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -36,6 +36,9 @@ struct perf_sample_id {
36 struct hlist_node node; 36 struct hlist_node node;
37 u64 id; 37 u64 id;
38 struct perf_evsel *evsel; 38 struct perf_evsel *evsel;
39 int idx;
40 int cpu;
41 pid_t tid;
39 42
40 /* Holds total ID period value for PERF_SAMPLE_READ processing. */ 43 /* Holds total ID period value for PERF_SAMPLE_READ processing. */
41 u64 period; 44 u64 period;
@@ -54,6 +57,7 @@ struct cgroup_sel;
54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or 57 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all 58 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
56 * is used there is an id sample appended to non-sample events 59 * is used there is an id sample appended to non-sample events
60 * @priv: And what is in its containing unnamed union are tool specific
57 */ 61 */
58struct perf_evsel { 62struct perf_evsel {
59 struct list_head node; 63 struct list_head node;
@@ -73,6 +77,7 @@ struct perf_evsel {
73 union { 77 union {
74 void *priv; 78 void *priv;
75 off_t id_offset; 79 off_t id_offset;
80 u64 db_id;
76 }; 81 };
77 struct cgroup_sel *cgrp; 82 struct cgroup_sel *cgrp;
78 void *handler; 83 void *handler;
diff --git a/tools/perf/util/find-vdso-map.c b/tools/perf/util/find-vdso-map.c
new file mode 100644
index 000000000000..95ef1cffc056
--- /dev/null
+++ b/tools/perf/util/find-vdso-map.c
@@ -0,0 +1,30 @@
1static int find_vdso_map(void **start, void **end)
2{
3 FILE *maps;
4 char line[128];
5 int found = 0;
6
7 maps = fopen("/proc/self/maps", "r");
8 if (!maps) {
9 fprintf(stderr, "vdso: cannot open maps\n");
10 return -1;
11 }
12
13 while (!found && fgets(line, sizeof(line), maps)) {
14 int m = -1;
15
16 /* We care only about private r-x mappings. */
17 if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
18 start, end, &m))
19 continue;
20 if (m < 0)
21 continue;
22
23 if (!strncmp(&line[m], VDSO__MAP_NAME,
24 sizeof(VDSO__MAP_NAME) - 1))
25 found = 1;
26 }
27
28 fclose(maps);
29 return !found;
30}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 26f5b2fe5dc8..0ecf4a304cbc 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -601,8 +601,10 @@ static int __write_cpudesc(int fd, const char *cpuinfo_proc)
601 break; 601 break;
602 } 602 }
603 603
604 if (ret) 604 if (ret) {
605 ret = -1;
605 goto done; 606 goto done;
607 }
606 608
607 s = buf; 609 s = buf;
608 610
@@ -965,7 +967,8 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused,
965 n = sscanf(buf, "%*s %"PRIu64, &mem); 967 n = sscanf(buf, "%*s %"PRIu64, &mem);
966 if (n == 1) 968 if (n == 1)
967 ret = do_write(fd, &mem, sizeof(mem)); 969 ret = do_write(fd, &mem, sizeof(mem));
968 } 970 } else
971 ret = -1;
969 free(buf); 972 free(buf);
970 fclose(fp); 973 fclose(fp);
971 return ret; 974 return ret;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 34fc7c8672e4..51a630301afa 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -21,7 +21,7 @@ static void dsos__init(struct dsos *dsos)
21 21
22int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 22int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
23{ 23{
24 map_groups__init(&machine->kmaps); 24 map_groups__init(&machine->kmaps, machine);
25 RB_CLEAR_NODE(&machine->rb_node); 25 RB_CLEAR_NODE(&machine->rb_node);
26 dsos__init(&machine->user_dsos); 26 dsos__init(&machine->user_dsos);
27 dsos__init(&machine->kernel_dsos); 27 dsos__init(&machine->kernel_dsos);
@@ -32,7 +32,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
32 32
33 machine->vdso_info = NULL; 33 machine->vdso_info = NULL;
34 34
35 machine->kmaps.machine = machine;
36 machine->pid = pid; 35 machine->pid = pid;
37 36
38 machine->symbol_filter = NULL; 37 machine->symbol_filter = NULL;
@@ -319,7 +318,7 @@ static void machine__update_thread_pid(struct machine *machine,
319 goto out_err; 318 goto out_err;
320 319
321 if (!leader->mg) 320 if (!leader->mg)
322 leader->mg = map_groups__new(); 321 leader->mg = map_groups__new(machine);
323 322
324 if (!leader->mg) 323 if (!leader->mg)
325 goto out_err; 324 goto out_err;
@@ -1290,7 +1289,7 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
1290 return 0; 1289 return 0;
1291} 1290}
1292 1291
1293static void ip__resolve_ams(struct machine *machine, struct thread *thread, 1292static void ip__resolve_ams(struct thread *thread,
1294 struct addr_map_symbol *ams, 1293 struct addr_map_symbol *ams,
1295 u64 ip) 1294 u64 ip)
1296{ 1295{
@@ -1304,7 +1303,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1304 * Thus, we have to try consecutively until we find a match 1303 * Thus, we have to try consecutively until we find a match
1305 * or else, the symbol is unknown 1304 * or else, the symbol is unknown
1306 */ 1305 */
1307 thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al); 1306 thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al);
1308 1307
1309 ams->addr = ip; 1308 ams->addr = ip;
1310 ams->al_addr = al.addr; 1309 ams->al_addr = al.addr;
@@ -1312,23 +1311,21 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1312 ams->map = al.map; 1311 ams->map = al.map;
1313} 1312}
1314 1313
1315static void ip__resolve_data(struct machine *machine, struct thread *thread, 1314static void ip__resolve_data(struct thread *thread,
1316 u8 m, struct addr_map_symbol *ams, u64 addr) 1315 u8 m, struct addr_map_symbol *ams, u64 addr)
1317{ 1316{
1318 struct addr_location al; 1317 struct addr_location al;
1319 1318
1320 memset(&al, 0, sizeof(al)); 1319 memset(&al, 0, sizeof(al));
1321 1320
1322 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, 1321 thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al);
1323 &al);
1324 if (al.map == NULL) { 1322 if (al.map == NULL) {
1325 /* 1323 /*
1326 * some shared data regions have execute bit set which puts 1324 * some shared data regions have execute bit set which puts
1327 * their mapping in the MAP__FUNCTION type array. 1325 * their mapping in the MAP__FUNCTION type array.
1328 * Check there as a fallback option before dropping the sample. 1326 * Check there as a fallback option before dropping the sample.
1329 */ 1327 */
1330 thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr, 1328 thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al);
1331 &al);
1332 } 1329 }
1333 1330
1334 ams->addr = addr; 1331 ams->addr = addr;
@@ -1345,9 +1342,8 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,
1345 if (!mi) 1342 if (!mi)
1346 return NULL; 1343 return NULL;
1347 1344
1348 ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip); 1345 ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
1349 ip__resolve_data(al->machine, al->thread, al->cpumode, 1346 ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr);
1350 &mi->daddr, sample->addr);
1351 mi->data_src.val = sample->data_src; 1347 mi->data_src.val = sample->data_src;
1352 1348
1353 return mi; 1349 return mi;
@@ -1364,15 +1360,14 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
1364 return NULL; 1360 return NULL;
1365 1361
1366 for (i = 0; i < bs->nr; i++) { 1362 for (i = 0; i < bs->nr; i++) {
1367 ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to); 1363 ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to);
1368 ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from); 1364 ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from);
1369 bi[i].flags = bs->entries[i].flags; 1365 bi[i].flags = bs->entries[i].flags;
1370 } 1366 }
1371 return bi; 1367 return bi;
1372} 1368}
1373 1369
1374static int machine__resolve_callchain_sample(struct machine *machine, 1370static int thread__resolve_callchain_sample(struct thread *thread,
1375 struct thread *thread,
1376 struct ip_callchain *chain, 1371 struct ip_callchain *chain,
1377 struct symbol **parent, 1372 struct symbol **parent,
1378 struct addr_location *root_al, 1373 struct addr_location *root_al,
@@ -1396,7 +1391,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1396 * Based on DWARF debug information, some architectures skip 1391 * Based on DWARF debug information, some architectures skip
1397 * a callchain entry saved by the kernel. 1392 * a callchain entry saved by the kernel.
1398 */ 1393 */
1399 skip_idx = arch_skip_callchain_idx(machine, thread, chain); 1394 skip_idx = arch_skip_callchain_idx(thread, chain);
1400 1395
1401 for (i = 0; i < chain_nr; i++) { 1396 for (i = 0; i < chain_nr; i++) {
1402 u64 ip; 1397 u64 ip;
@@ -1438,7 +1433,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1438 } 1433 }
1439 1434
1440 al.filtered = 0; 1435 al.filtered = 0;
1441 thread__find_addr_location(thread, machine, cpumode, 1436 thread__find_addr_location(thread, cpumode,
1442 MAP__FUNCTION, ip, &al); 1437 MAP__FUNCTION, ip, &al);
1443 if (al.sym != NULL) { 1438 if (al.sym != NULL) {
1444 if (sort__has_parent && !*parent && 1439 if (sort__has_parent && !*parent &&
@@ -1469,19 +1464,15 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
1469 entry->map, entry->sym); 1464 entry->map, entry->sym);
1470} 1465}
1471 1466
1472int machine__resolve_callchain(struct machine *machine, 1467int thread__resolve_callchain(struct thread *thread,
1473 struct perf_evsel *evsel, 1468 struct perf_evsel *evsel,
1474 struct thread *thread, 1469 struct perf_sample *sample,
1475 struct perf_sample *sample, 1470 struct symbol **parent,
1476 struct symbol **parent, 1471 struct addr_location *root_al,
1477 struct addr_location *root_al, 1472 int max_stack)
1478 int max_stack)
1479{ 1473{
1480 int ret; 1474 int ret = thread__resolve_callchain_sample(thread, sample->callchain,
1481 1475 parent, root_al, max_stack);
1482 ret = machine__resolve_callchain_sample(machine, thread,
1483 sample->callchain, parent,
1484 root_al, max_stack);
1485 if (ret) 1476 if (ret)
1486 return ret; 1477 return ret;
1487 1478
@@ -1495,7 +1486,7 @@ int machine__resolve_callchain(struct machine *machine,
1495 (!sample->user_stack.size)) 1486 (!sample->user_stack.size))
1496 return 0; 1487 return 0;
1497 1488
1498 return unwind__get_entries(unwind_entry, &callchain_cursor, machine, 1489 return unwind__get_entries(unwind_entry, &callchain_cursor,
1499 thread, sample, max_stack); 1490 thread, sample, max_stack);
1500 1491
1501} 1492}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 2b651a7f5d0d..e8b7779a0a3f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -40,6 +40,10 @@ struct machine {
40 u64 kernel_start; 40 u64 kernel_start;
41 symbol_filter_t symbol_filter; 41 symbol_filter_t symbol_filter;
42 pid_t *current_tid; 42 pid_t *current_tid;
43 union { /* Tool specific area */
44 void *priv;
45 u64 db_id;
46 };
43}; 47};
44 48
45static inline 49static inline
@@ -122,13 +126,12 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
122 struct addr_location *al); 126 struct addr_location *al);
123struct mem_info *sample__resolve_mem(struct perf_sample *sample, 127struct mem_info *sample__resolve_mem(struct perf_sample *sample,
124 struct addr_location *al); 128 struct addr_location *al);
125int machine__resolve_callchain(struct machine *machine, 129int thread__resolve_callchain(struct thread *thread,
126 struct perf_evsel *evsel, 130 struct perf_evsel *evsel,
127 struct thread *thread, 131 struct perf_sample *sample,
128 struct perf_sample *sample, 132 struct symbol **parent,
129 struct symbol **parent, 133 struct addr_location *root_al,
130 struct addr_location *root_al, 134 int max_stack);
131 int max_stack);
132 135
133/* 136/*
134 * Default guest kernel is defined by parameter --guestkallsyms 137 * Default guest kernel is defined by parameter --guestkallsyms
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 2137c4596ec7..040a785c857b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -413,14 +413,14 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
413 return ip + map->reloc; 413 return ip + map->reloc;
414} 414}
415 415
416void map_groups__init(struct map_groups *mg) 416void map_groups__init(struct map_groups *mg, struct machine *machine)
417{ 417{
418 int i; 418 int i;
419 for (i = 0; i < MAP__NR_TYPES; ++i) { 419 for (i = 0; i < MAP__NR_TYPES; ++i) {
420 mg->maps[i] = RB_ROOT; 420 mg->maps[i] = RB_ROOT;
421 INIT_LIST_HEAD(&mg->removed_maps[i]); 421 INIT_LIST_HEAD(&mg->removed_maps[i]);
422 } 422 }
423 mg->machine = NULL; 423 mg->machine = machine;
424 mg->refcnt = 1; 424 mg->refcnt = 1;
425} 425}
426 426
@@ -471,12 +471,12 @@ bool map_groups__empty(struct map_groups *mg)
471 return true; 471 return true;
472} 472}
473 473
474struct map_groups *map_groups__new(void) 474struct map_groups *map_groups__new(struct machine *machine)
475{ 475{
476 struct map_groups *mg = malloc(sizeof(*mg)); 476 struct map_groups *mg = malloc(sizeof(*mg));
477 477
478 if (mg != NULL) 478 if (mg != NULL)
479 map_groups__init(mg); 479 map_groups__init(mg, machine);
480 480
481 return mg; 481 return mg;
482} 482}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2f83954af050..6951a9d42339 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -64,7 +64,7 @@ struct map_groups {
64 int refcnt; 64 int refcnt;
65}; 65};
66 66
67struct map_groups *map_groups__new(void); 67struct map_groups *map_groups__new(struct machine *machine);
68void map_groups__delete(struct map_groups *mg); 68void map_groups__delete(struct map_groups *mg);
69bool map_groups__empty(struct map_groups *mg); 69bool map_groups__empty(struct map_groups *mg);
70 70
@@ -150,7 +150,7 @@ void maps__remove(struct rb_root *maps, struct map *map);
150struct map *maps__find(struct rb_root *maps, u64 addr); 150struct map *maps__find(struct rb_root *maps, u64 addr);
151struct map *maps__first(struct rb_root *maps); 151struct map *maps__first(struct rb_root *maps);
152struct map *maps__next(struct map *map); 152struct map *maps__next(struct map *map);
153void map_groups__init(struct map_groups *mg); 153void map_groups__init(struct map_groups *mg, struct machine *machine);
154void map_groups__exit(struct map_groups *mg); 154void map_groups__exit(struct map_groups *mg);
155int map_groups__clone(struct map_groups *mg, 155int map_groups__clone(struct map_groups *mg,
156 struct map_groups *parent, enum map_type type); 156 struct map_groups *parent, enum map_type type);
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index bf48092983c6..f62dee7bd924 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -42,7 +42,26 @@ static int get_value(struct parse_opt_ctx_t *p,
42 return opterror(opt, "takes no value", flags); 42 return opterror(opt, "takes no value", flags);
43 if (unset && (opt->flags & PARSE_OPT_NONEG)) 43 if (unset && (opt->flags & PARSE_OPT_NONEG))
44 return opterror(opt, "isn't available", flags); 44 return opterror(opt, "isn't available", flags);
45 45 if (opt->flags & PARSE_OPT_DISABLED)
46 return opterror(opt, "is not usable", flags);
47
48 if (opt->flags & PARSE_OPT_EXCLUSIVE) {
49 if (p->excl_opt) {
50 char msg[128];
51
52 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
53 p->excl_opt->long_name == NULL) {
54 scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
55 p->excl_opt->short_name);
56 } else {
57 scnprintf(msg, sizeof(msg), "cannot be used with %s",
58 p->excl_opt->long_name);
59 }
60 opterror(opt, msg, flags);
61 return -3;
62 }
63 p->excl_opt = opt;
64 }
46 if (!(flags & OPT_SHORT) && p->opt) { 65 if (!(flags & OPT_SHORT) && p->opt) {
47 switch (opt->type) { 66 switch (opt->type) {
48 case OPTION_CALLBACK: 67 case OPTION_CALLBACK:
@@ -343,13 +362,14 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
343 const char * const usagestr[]) 362 const char * const usagestr[])
344{ 363{
345 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 364 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
365 int excl_short_opt = 1;
366 const char *arg;
346 367
347 /* we must reset ->opt, unknown short option leave it dangling */ 368 /* we must reset ->opt, unknown short option leave it dangling */
348 ctx->opt = NULL; 369 ctx->opt = NULL;
349 370
350 for (; ctx->argc; ctx->argc--, ctx->argv++) { 371 for (; ctx->argc; ctx->argc--, ctx->argv++) {
351 const char *arg = ctx->argv[0]; 372 arg = ctx->argv[0];
352
353 if (*arg != '-' || !arg[1]) { 373 if (*arg != '-' || !arg[1]) {
354 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) 374 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
355 break; 375 break;
@@ -358,19 +378,21 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
358 } 378 }
359 379
360 if (arg[1] != '-') { 380 if (arg[1] != '-') {
361 ctx->opt = arg + 1; 381 ctx->opt = ++arg;
362 if (internal_help && *ctx->opt == 'h') 382 if (internal_help && *ctx->opt == 'h')
363 return usage_with_options_internal(usagestr, options, 0); 383 return usage_with_options_internal(usagestr, options, 0);
364 switch (parse_short_opt(ctx, options)) { 384 switch (parse_short_opt(ctx, options)) {
365 case -1: 385 case -1:
366 return parse_options_usage(usagestr, options, arg + 1, 1); 386 return parse_options_usage(usagestr, options, arg, 1);
367 case -2: 387 case -2:
368 goto unknown; 388 goto unknown;
389 case -3:
390 goto exclusive;
369 default: 391 default:
370 break; 392 break;
371 } 393 }
372 if (ctx->opt) 394 if (ctx->opt)
373 check_typos(arg + 1, options); 395 check_typos(arg, options);
374 while (ctx->opt) { 396 while (ctx->opt) {
375 if (internal_help && *ctx->opt == 'h') 397 if (internal_help && *ctx->opt == 'h')
376 return usage_with_options_internal(usagestr, options, 0); 398 return usage_with_options_internal(usagestr, options, 0);
@@ -387,6 +409,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
387 ctx->argv[0] = strdup(ctx->opt - 1); 409 ctx->argv[0] = strdup(ctx->opt - 1);
388 *(char *)ctx->argv[0] = '-'; 410 *(char *)ctx->argv[0] = '-';
389 goto unknown; 411 goto unknown;
412 case -3:
413 goto exclusive;
390 default: 414 default:
391 break; 415 break;
392 } 416 }
@@ -402,19 +426,23 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
402 break; 426 break;
403 } 427 }
404 428
405 if (internal_help && !strcmp(arg + 2, "help-all")) 429 arg += 2;
430 if (internal_help && !strcmp(arg, "help-all"))
406 return usage_with_options_internal(usagestr, options, 1); 431 return usage_with_options_internal(usagestr, options, 1);
407 if (internal_help && !strcmp(arg + 2, "help")) 432 if (internal_help && !strcmp(arg, "help"))
408 return usage_with_options_internal(usagestr, options, 0); 433 return usage_with_options_internal(usagestr, options, 0);
409 if (!strcmp(arg + 2, "list-opts")) 434 if (!strcmp(arg, "list-opts"))
410 return PARSE_OPT_LIST_OPTS; 435 return PARSE_OPT_LIST_OPTS;
411 if (!strcmp(arg + 2, "list-cmds")) 436 if (!strcmp(arg, "list-cmds"))
412 return PARSE_OPT_LIST_SUBCMDS; 437 return PARSE_OPT_LIST_SUBCMDS;
413 switch (parse_long_opt(ctx, arg + 2, options)) { 438 switch (parse_long_opt(ctx, arg, options)) {
414 case -1: 439 case -1:
415 return parse_options_usage(usagestr, options, arg + 2, 0); 440 return parse_options_usage(usagestr, options, arg, 0);
416 case -2: 441 case -2:
417 goto unknown; 442 goto unknown;
443 case -3:
444 excl_short_opt = 0;
445 goto exclusive;
418 default: 446 default:
419 break; 447 break;
420 } 448 }
@@ -426,6 +454,17 @@ unknown:
426 ctx->opt = NULL; 454 ctx->opt = NULL;
427 } 455 }
428 return PARSE_OPT_DONE; 456 return PARSE_OPT_DONE;
457
458exclusive:
459 parse_options_usage(usagestr, options, arg, excl_short_opt);
460 if ((excl_short_opt && ctx->excl_opt->short_name) ||
461 ctx->excl_opt->long_name == NULL) {
462 char opt = ctx->excl_opt->short_name;
463 parse_options_usage(NULL, options, &opt, 1);
464 } else {
465 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
466 }
467 return PARSE_OPT_HELP;
429} 468}
430 469
431int parse_options_end(struct parse_opt_ctx_t *ctx) 470int parse_options_end(struct parse_opt_ctx_t *ctx)
@@ -509,6 +548,8 @@ static void print_option_help(const struct option *opts, int full)
509 } 548 }
510 if (!full && (opts->flags & PARSE_OPT_HIDDEN)) 549 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
511 return; 550 return;
551 if (opts->flags & PARSE_OPT_DISABLED)
552 return;
512 553
513 pos = fprintf(stderr, " "); 554 pos = fprintf(stderr, " ");
514 if (opts->short_name) 555 if (opts->short_name)
@@ -679,3 +720,16 @@ int parse_opt_verbosity_cb(const struct option *opt,
679 } 720 }
680 return 0; 721 return 0;
681} 722}
723
724void set_option_flag(struct option *opts, int shortopt, const char *longopt,
725 int flag)
726{
727 for (; opts->type != OPTION_END; opts++) {
728 if ((shortopt && opts->short_name == shortopt) ||
729 (opts->long_name && longopt &&
730 !strcmp(opts->long_name, longopt))) {
731 opts->flags |= flag;
732 break;
733 }
734 }
735}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index b59ba858e73d..97b153fb4999 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -38,6 +38,8 @@ enum parse_opt_option_flags {
38 PARSE_OPT_NONEG = 4, 38 PARSE_OPT_NONEG = 4,
39 PARSE_OPT_HIDDEN = 8, 39 PARSE_OPT_HIDDEN = 8,
40 PARSE_OPT_LASTARG_DEFAULT = 16, 40 PARSE_OPT_LASTARG_DEFAULT = 16,
41 PARSE_OPT_DISABLED = 32,
42 PARSE_OPT_EXCLUSIVE = 64,
41}; 43};
42 44
43struct option; 45struct option;
@@ -173,6 +175,7 @@ struct parse_opt_ctx_t {
173 const char **out; 175 const char **out;
174 int argc, cpidx; 176 int argc, cpidx;
175 const char *opt; 177 const char *opt;
178 const struct option *excl_opt;
176 int flags; 179 int flags;
177}; 180};
178 181
@@ -211,4 +214,5 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
211 214
212extern const char *parse_options_fix_filename(const char *prefix, const char *file); 215extern const char *parse_options_fix_filename(const char *prefix, const char *file);
213 216
217void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
214#endif /* __PERF_PARSE_OPTIONS_H */ 218#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e243ad962a4d..881b75490533 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -747,15 +747,18 @@ void print_pmu_events(const char *event_glob, bool name_only)
747 747
748 pmu = NULL; 748 pmu = NULL;
749 len = 0; 749 len = 0;
750 while ((pmu = perf_pmu__scan(pmu)) != NULL) 750 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
751 list_for_each_entry(alias, &pmu->aliases, list) 751 list_for_each_entry(alias, &pmu->aliases, list)
752 len++; 752 len++;
753 aliases = malloc(sizeof(char *) * len); 753 if (pmu->selectable)
754 len++;
755 }
756 aliases = zalloc(sizeof(char *) * len);
754 if (!aliases) 757 if (!aliases)
755 return; 758 goto out_enomem;
756 pmu = NULL; 759 pmu = NULL;
757 j = 0; 760 j = 0;
758 while ((pmu = perf_pmu__scan(pmu)) != NULL) 761 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
759 list_for_each_entry(alias, &pmu->aliases, list) { 762 list_for_each_entry(alias, &pmu->aliases, list) {
760 char *name = format_alias(buf, sizeof(buf), pmu, alias); 763 char *name = format_alias(buf, sizeof(buf), pmu, alias);
761 bool is_cpu = !strcmp(pmu->name, "cpu"); 764 bool is_cpu = !strcmp(pmu->name, "cpu");
@@ -765,13 +768,23 @@ void print_pmu_events(const char *event_glob, bool name_only)
765 (!is_cpu && strglobmatch(alias->name, 768 (!is_cpu && strglobmatch(alias->name,
766 event_glob)))) 769 event_glob))))
767 continue; 770 continue;
768 aliases[j] = name; 771
769 if (is_cpu && !name_only) 772 if (is_cpu && !name_only)
770 aliases[j] = format_alias_or(buf, sizeof(buf), 773 name = format_alias_or(buf, sizeof(buf), pmu, alias);
771 pmu, alias); 774
772 aliases[j] = strdup(aliases[j]); 775 aliases[j] = strdup(name);
776 if (aliases[j] == NULL)
777 goto out_enomem;
773 j++; 778 j++;
774 } 779 }
780 if (pmu->selectable) {
781 char *s;
782 if (asprintf(&s, "%s//", pmu->name) < 0)
783 goto out_enomem;
784 aliases[j] = s;
785 j++;
786 }
787 }
775 len = j; 788 len = j;
776 qsort(aliases, len, sizeof(char *), cmp_string); 789 qsort(aliases, len, sizeof(char *), cmp_string);
777 for (j = 0; j < len; j++) { 790 for (j = 0; j < len; j++) {
@@ -780,12 +793,20 @@ void print_pmu_events(const char *event_glob, bool name_only)
780 continue; 793 continue;
781 } 794 }
782 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 795 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
783 zfree(&aliases[j]);
784 printed++; 796 printed++;
785 } 797 }
786 if (printed) 798 if (printed)
787 printf("\n"); 799 printf("\n");
788 free(aliases); 800out_free:
801 for (j = 0; j < len; j++)
802 zfree(&aliases[j]);
803 zfree(&aliases);
804 return;
805
806out_enomem:
807 printf("FATAL: not enough memory to print PMU events\n");
808 if (aliases)
809 goto out_free;
789} 810}
790 811
791bool pmu_have_event(const char *pname, const char *name) 812bool pmu_have_event(const char *pname, const char *name)
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index fe9dfbee8eed..8092de78e818 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -18,6 +18,7 @@ struct perf_event_attr;
18struct perf_pmu { 18struct perf_pmu {
19 char *name; 19 char *name;
20 __u32 type; 20 __u32 type;
21 bool selectable;
21 struct perf_event_attr *default_config; 22 struct perf_event_attr *default_config;
22 struct cpu_map *cpus; 23 struct cpu_map *cpus;
23 struct list_head format; /* HEAD struct perf_pmu_format -> list */ 24 struct list_head format; /* HEAD struct perf_pmu_format -> list */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index c150ca4343eb..28eb1417cb2a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1910,21 +1910,21 @@ static int show_perf_probe_event(struct perf_probe_event *pev,
1910 if (ret < 0) 1910 if (ret < 0)
1911 return ret; 1911 return ret;
1912 1912
1913 printf(" %-20s (on %s", buf, place); 1913 pr_info(" %-20s (on %s", buf, place);
1914 if (module) 1914 if (module)
1915 printf(" in %s", module); 1915 pr_info(" in %s", module);
1916 1916
1917 if (pev->nargs > 0) { 1917 if (pev->nargs > 0) {
1918 printf(" with"); 1918 pr_info(" with");
1919 for (i = 0; i < pev->nargs; i++) { 1919 for (i = 0; i < pev->nargs; i++) {
1920 ret = synthesize_perf_probe_arg(&pev->args[i], 1920 ret = synthesize_perf_probe_arg(&pev->args[i],
1921 buf, 128); 1921 buf, 128);
1922 if (ret < 0) 1922 if (ret < 0)
1923 break; 1923 break;
1924 printf(" %s", buf); 1924 pr_info(" %s", buf);
1925 } 1925 }
1926 } 1926 }
1927 printf(")\n"); 1927 pr_info(")\n");
1928 free(place); 1928 free(place);
1929 return ret; 1929 return ret;
1930} 1930}
@@ -2124,7 +2124,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2124 } 2124 }
2125 2125
2126 ret = 0; 2126 ret = 0;
2127 printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 2127 pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
2128 for (i = 0; i < ntevs; i++) { 2128 for (i = 0; i < ntevs; i++) {
2129 tev = &tevs[i]; 2129 tev = &tevs[i];
2130 if (pev->event) 2130 if (pev->event)
@@ -2179,8 +2179,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2179 2179
2180 if (ret >= 0) { 2180 if (ret >= 0) {
2181 /* Show how to use the event. */ 2181 /* Show how to use the event. */
2182 printf("\nYou can now use it in all perf tools, such as:\n\n"); 2182 pr_info("\nYou can now use it in all perf tools, such as:\n\n");
2183 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 2183 pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
2184 tev->event); 2184 tev->event);
2185 } 2185 }
2186 2186
@@ -2444,7 +2444,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
2444 goto error; 2444 goto error;
2445 } 2445 }
2446 2446
2447 printf("Removed event: %s\n", ent->s); 2447 pr_info("Removed event: %s\n", ent->s);
2448 return 0; 2448 return 0;
2449error: 2449error:
2450 pr_warning("Failed to delete event: %s\n", 2450 pr_warning("Failed to delete event: %s\n",
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 496f21cadd97..2fd7ee8f18c7 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,6 +24,7 @@
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <string.h> 26#include <string.h>
27#include <stdbool.h>
27#include <errno.h> 28#include <errno.h>
28 29
29#include "../../perf.h" 30#include "../../perf.h"
@@ -33,6 +34,9 @@
33#include "../util.h" 34#include "../util.h"
34#include "../event.h" 35#include "../event.h"
35#include "../thread.h" 36#include "../thread.h"
37#include "../comm.h"
38#include "../machine.h"
39#include "../db-export.h"
36#include "../trace-event.h" 40#include "../trace-event.h"
37#include "../machine.h" 41#include "../machine.h"
38 42
@@ -53,6 +57,21 @@ static int zero_flag_atom;
53 57
54static PyObject *main_module, *main_dict; 58static PyObject *main_module, *main_dict;
55 59
60struct tables {
61 struct db_export dbe;
62 PyObject *evsel_handler;
63 PyObject *machine_handler;
64 PyObject *thread_handler;
65 PyObject *comm_handler;
66 PyObject *comm_thread_handler;
67 PyObject *dso_handler;
68 PyObject *symbol_handler;
69 PyObject *sample_handler;
70 bool db_export_mode;
71};
72
73static struct tables tables_global;
74
56static void handler_call_die(const char *handler_name) NORETURN; 75static void handler_call_die(const char *handler_name) NORETURN;
57static void handler_call_die(const char *handler_name) 76static void handler_call_die(const char *handler_name)
58{ 77{
@@ -312,9 +331,9 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
312 if (!symbol_conf.use_callchain || !sample->callchain) 331 if (!symbol_conf.use_callchain || !sample->callchain)
313 goto exit; 332 goto exit;
314 333
315 if (machine__resolve_callchain(al->machine, evsel, al->thread, 334 if (thread__resolve_callchain(al->thread, evsel,
316 sample, NULL, NULL, 335 sample, NULL, NULL,
317 PERF_MAX_STACK_DEPTH) != 0) { 336 PERF_MAX_STACK_DEPTH) != 0) {
318 pr_err("Failed to resolve callchain. Skipping\n"); 337 pr_err("Failed to resolve callchain. Skipping\n");
319 goto exit; 338 goto exit;
320 } 339 }
@@ -475,6 +494,211 @@ static void python_process_tracepoint(struct perf_sample *sample,
475 Py_DECREF(t); 494 Py_DECREF(t);
476} 495}
477 496
497static PyObject *tuple_new(unsigned int sz)
498{
499 PyObject *t;
500
501 t = PyTuple_New(sz);
502 if (!t)
503 Py_FatalError("couldn't create Python tuple");
504 return t;
505}
506
507static int tuple_set_u64(PyObject *t, unsigned int pos, u64 val)
508{
509#if BITS_PER_LONG == 64
510 return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
511#endif
512#if BITS_PER_LONG == 32
513 return PyTuple_SetItem(t, pos, PyLong_FromLongLong(val));
514#endif
515}
516
517static int tuple_set_s32(PyObject *t, unsigned int pos, s32 val)
518{
519 return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
520}
521
522static int tuple_set_string(PyObject *t, unsigned int pos, const char *s)
523{
524 return PyTuple_SetItem(t, pos, PyString_FromString(s));
525}
526
527static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel)
528{
529 struct tables *tables = container_of(dbe, struct tables, dbe);
530 PyObject *t;
531
532 t = tuple_new(2);
533
534 tuple_set_u64(t, 0, evsel->db_id);
535 tuple_set_string(t, 1, perf_evsel__name(evsel));
536
537 call_object(tables->evsel_handler, t, "evsel_table");
538
539 Py_DECREF(t);
540
541 return 0;
542}
543
544static int python_export_machine(struct db_export *dbe,
545 struct machine *machine)
546{
547 struct tables *tables = container_of(dbe, struct tables, dbe);
548 PyObject *t;
549
550 t = tuple_new(3);
551
552 tuple_set_u64(t, 0, machine->db_id);
553 tuple_set_s32(t, 1, machine->pid);
554 tuple_set_string(t, 2, machine->root_dir ? machine->root_dir : "");
555
556 call_object(tables->machine_handler, t, "machine_table");
557
558 Py_DECREF(t);
559
560 return 0;
561}
562
563static int python_export_thread(struct db_export *dbe, struct thread *thread,
564 u64 main_thread_db_id, struct machine *machine)
565{
566 struct tables *tables = container_of(dbe, struct tables, dbe);
567 PyObject *t;
568
569 t = tuple_new(5);
570
571 tuple_set_u64(t, 0, thread->db_id);
572 tuple_set_u64(t, 1, machine->db_id);
573 tuple_set_u64(t, 2, main_thread_db_id);
574 tuple_set_s32(t, 3, thread->pid_);
575 tuple_set_s32(t, 4, thread->tid);
576
577 call_object(tables->thread_handler, t, "thread_table");
578
579 Py_DECREF(t);
580
581 return 0;
582}
583
584static int python_export_comm(struct db_export *dbe, struct comm *comm)
585{
586 struct tables *tables = container_of(dbe, struct tables, dbe);
587 PyObject *t;
588
589 t = tuple_new(2);
590
591 tuple_set_u64(t, 0, comm->db_id);
592 tuple_set_string(t, 1, comm__str(comm));
593
594 call_object(tables->comm_handler, t, "comm_table");
595
596 Py_DECREF(t);
597
598 return 0;
599}
600
601static int python_export_comm_thread(struct db_export *dbe, u64 db_id,
602 struct comm *comm, struct thread *thread)
603{
604 struct tables *tables = container_of(dbe, struct tables, dbe);
605 PyObject *t;
606
607 t = tuple_new(3);
608
609 tuple_set_u64(t, 0, db_id);
610 tuple_set_u64(t, 1, comm->db_id);
611 tuple_set_u64(t, 2, thread->db_id);
612
613 call_object(tables->comm_thread_handler, t, "comm_thread_table");
614
615 Py_DECREF(t);
616
617 return 0;
618}
619
620static int python_export_dso(struct db_export *dbe, struct dso *dso,
621 struct machine *machine)
622{
623 struct tables *tables = container_of(dbe, struct tables, dbe);
624 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
625 PyObject *t;
626
627 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
628
629 t = tuple_new(5);
630
631 tuple_set_u64(t, 0, dso->db_id);
632 tuple_set_u64(t, 1, machine->db_id);
633 tuple_set_string(t, 2, dso->short_name);
634 tuple_set_string(t, 3, dso->long_name);
635 tuple_set_string(t, 4, sbuild_id);
636
637 call_object(tables->dso_handler, t, "dso_table");
638
639 Py_DECREF(t);
640
641 return 0;
642}
643
644static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
645 struct dso *dso)
646{
647 struct tables *tables = container_of(dbe, struct tables, dbe);
648 u64 *sym_db_id = symbol__priv(sym);
649 PyObject *t;
650
651 t = tuple_new(6);
652
653 tuple_set_u64(t, 0, *sym_db_id);
654 tuple_set_u64(t, 1, dso->db_id);
655 tuple_set_u64(t, 2, sym->start);
656 tuple_set_u64(t, 3, sym->end);
657 tuple_set_s32(t, 4, sym->binding);
658 tuple_set_string(t, 5, sym->name);
659
660 call_object(tables->symbol_handler, t, "symbol_table");
661
662 Py_DECREF(t);
663
664 return 0;
665}
666
667static int python_export_sample(struct db_export *dbe,
668 struct export_sample *es)
669{
670 struct tables *tables = container_of(dbe, struct tables, dbe);
671 PyObject *t;
672
673 t = tuple_new(19);
674
675 tuple_set_u64(t, 0, es->db_id);
676 tuple_set_u64(t, 1, es->evsel->db_id);
677 tuple_set_u64(t, 2, es->al->machine->db_id);
678 tuple_set_u64(t, 3, es->thread->db_id);
679 tuple_set_u64(t, 4, es->comm_db_id);
680 tuple_set_u64(t, 5, es->dso_db_id);
681 tuple_set_u64(t, 6, es->sym_db_id);
682 tuple_set_u64(t, 7, es->offset);
683 tuple_set_u64(t, 8, es->sample->ip);
684 tuple_set_u64(t, 9, es->sample->time);
685 tuple_set_s32(t, 10, es->sample->cpu);
686 tuple_set_u64(t, 11, es->addr_dso_db_id);
687 tuple_set_u64(t, 12, es->addr_sym_db_id);
688 tuple_set_u64(t, 13, es->addr_offset);
689 tuple_set_u64(t, 14, es->sample->addr);
690 tuple_set_u64(t, 15, es->sample->period);
691 tuple_set_u64(t, 16, es->sample->weight);
692 tuple_set_u64(t, 17, es->sample->transaction);
693 tuple_set_u64(t, 18, es->sample->data_src);
694
695 call_object(tables->sample_handler, t, "sample_table");
696
697 Py_DECREF(t);
698
699 return 0;
700}
701
478static void python_process_general_event(struct perf_sample *sample, 702static void python_process_general_event(struct perf_sample *sample,
479 struct perf_evsel *evsel, 703 struct perf_evsel *evsel,
480 struct thread *thread, 704 struct thread *thread,
@@ -551,19 +775,25 @@ exit:
551 Py_DECREF(t); 775 Py_DECREF(t);
552} 776}
553 777
554static void python_process_event(union perf_event *event __maybe_unused, 778static void python_process_event(union perf_event *event,
555 struct perf_sample *sample, 779 struct perf_sample *sample,
556 struct perf_evsel *evsel, 780 struct perf_evsel *evsel,
557 struct thread *thread, 781 struct thread *thread,
558 struct addr_location *al) 782 struct addr_location *al)
559{ 783{
784 struct tables *tables = &tables_global;
785
560 switch (evsel->attr.type) { 786 switch (evsel->attr.type) {
561 case PERF_TYPE_TRACEPOINT: 787 case PERF_TYPE_TRACEPOINT:
562 python_process_tracepoint(sample, evsel, thread, al); 788 python_process_tracepoint(sample, evsel, thread, al);
563 break; 789 break;
564 /* Reserve for future process_hw/sw/raw APIs */ 790 /* Reserve for future process_hw/sw/raw APIs */
565 default: 791 default:
566 python_process_general_event(sample, evsel, thread, al); 792 if (tables->db_export_mode)
793 db_export__sample(&tables->dbe, event, sample, evsel,
794 thread, al);
795 else
796 python_process_general_event(sample, evsel, thread, al);
567 } 797 }
568} 798}
569 799
@@ -589,11 +819,57 @@ error:
589 return -1; 819 return -1;
590} 820}
591 821
822#define SET_TABLE_HANDLER_(name, handler_name, table_name) do { \
823 tables->handler_name = get_handler(#table_name); \
824 if (tables->handler_name) \
825 tables->dbe.export_ ## name = python_export_ ## name; \
826} while (0)
827
828#define SET_TABLE_HANDLER(name) \
829 SET_TABLE_HANDLER_(name, name ## _handler, name ## _table)
830
831static void set_table_handlers(struct tables *tables)
832{
833 const char *perf_db_export_mode = "perf_db_export_mode";
834 PyObject *db_export_mode;
835 int ret;
836
837 memset(tables, 0, sizeof(struct tables));
838 if (db_export__init(&tables->dbe))
839 Py_FatalError("failed to initialize export");
840
841 db_export_mode = PyDict_GetItemString(main_dict, perf_db_export_mode);
842 if (!db_export_mode)
843 return;
844
845 ret = PyObject_IsTrue(db_export_mode);
846 if (ret == -1)
847 handler_call_die(perf_db_export_mode);
848 if (!ret)
849 return;
850
851 tables->db_export_mode = true;
852 /*
853 * Reserve per symbol space for symbol->db_id via symbol__priv()
854 */
855 symbol_conf.priv_size = sizeof(u64);
856
857 SET_TABLE_HANDLER(evsel);
858 SET_TABLE_HANDLER(machine);
859 SET_TABLE_HANDLER(thread);
860 SET_TABLE_HANDLER(comm);
861 SET_TABLE_HANDLER(comm_thread);
862 SET_TABLE_HANDLER(dso);
863 SET_TABLE_HANDLER(symbol);
864 SET_TABLE_HANDLER(sample);
865}
866
592/* 867/*
593 * Start trace script 868 * Start trace script
594 */ 869 */
595static int python_start_script(const char *script, int argc, const char **argv) 870static int python_start_script(const char *script, int argc, const char **argv)
596{ 871{
872 struct tables *tables = &tables_global;
597 const char **command_line; 873 const char **command_line;
598 char buf[PATH_MAX]; 874 char buf[PATH_MAX];
599 int i, err = 0; 875 int i, err = 0;
@@ -632,6 +908,8 @@ static int python_start_script(const char *script, int argc, const char **argv)
632 908
633 free(command_line); 909 free(command_line);
634 910
911 set_table_handlers(tables);
912
635 return err; 913 return err;
636error: 914error:
637 Py_Finalize(); 915 Py_Finalize();
@@ -650,8 +928,12 @@ static int python_flush_script(void)
650 */ 928 */
651static int python_stop_script(void) 929static int python_stop_script(void)
652{ 930{
931 struct tables *tables = &tables_global;
932
653 try_call_object("trace_end", NULL); 933 try_call_object("trace_end", NULL);
654 934
935 db_export__exit(&tables->dbe);
936
655 Py_XDECREF(main_dict); 937 Py_XDECREF(main_dict);
656 Py_XDECREF(main_module); 938 Py_XDECREF(main_module);
657 Py_Finalize(); 939 Py_Finalize();
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 6702ac28754b..f4478ce72fdb 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -228,6 +228,15 @@ static int process_finished_round(struct perf_tool *tool,
228 union perf_event *event, 228 union perf_event *event,
229 struct perf_session *session); 229 struct perf_session *session);
230 230
231static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
232 union perf_event *event __maybe_unused,
233 struct perf_session *perf_session
234 __maybe_unused)
235{
236 dump_printf(": unhandled!\n");
237 return 0;
238}
239
231void perf_tool__fill_defaults(struct perf_tool *tool) 240void perf_tool__fill_defaults(struct perf_tool *tool)
232{ 241{
233 if (tool->sample == NULL) 242 if (tool->sample == NULL)
@@ -262,6 +271,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
262 else 271 else
263 tool->finished_round = process_finished_round_stub; 272 tool->finished_round = process_finished_round_stub;
264 } 273 }
274 if (tool->id_index == NULL)
275 tool->id_index = process_id_index_stub;
265} 276}
266 277
267static void swap_sample_id_all(union perf_event *event, void *data) 278static void swap_sample_id_all(union perf_event *event, void *data)
@@ -460,6 +471,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
460 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 471 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
461 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, 472 [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
462 [PERF_RECORD_HEADER_BUILD_ID] = NULL, 473 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
474 [PERF_RECORD_ID_INDEX] = perf_event__all64_swap,
463 [PERF_RECORD_HEADER_MAX] = NULL, 475 [PERF_RECORD_HEADER_MAX] = NULL,
464}; 476};
465 477
@@ -888,11 +900,26 @@ static s64 perf_session__process_user_event(struct perf_session *session,
888 return tool->build_id(tool, event, session); 900 return tool->build_id(tool, event, session);
889 case PERF_RECORD_FINISHED_ROUND: 901 case PERF_RECORD_FINISHED_ROUND:
890 return tool->finished_round(tool, event, session); 902 return tool->finished_round(tool, event, session);
903 case PERF_RECORD_ID_INDEX:
904 return tool->id_index(tool, event, session);
891 default: 905 default:
892 return -EINVAL; 906 return -EINVAL;
893 } 907 }
894} 908}
895 909
910int perf_session__deliver_synth_event(struct perf_session *session,
911 union perf_event *event,
912 struct perf_sample *sample,
913 struct perf_tool *tool)
914{
915 events_stats__inc(&session->stats, event->header.type);
916
917 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
918 return perf_session__process_user_event(session, event, tool, 0);
919
920 return perf_session__deliver_event(session, event, sample, tool, 0);
921}
922
896static void event_swap(union perf_event *event, bool sample_id_all) 923static void event_swap(union perf_event *event, bool sample_id_all)
897{ 924{
898 perf_event__swap_op swap; 925 perf_event__swap_op swap;
@@ -1417,9 +1444,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1417 if (symbol_conf.use_callchain && sample->callchain) { 1444 if (symbol_conf.use_callchain && sample->callchain) {
1418 struct addr_location node_al; 1445 struct addr_location node_al;
1419 1446
1420 if (machine__resolve_callchain(al->machine, evsel, al->thread, 1447 if (thread__resolve_callchain(al->thread, evsel,
1421 sample, NULL, NULL, 1448 sample, NULL, NULL,
1422 PERF_MAX_STACK_DEPTH) != 0) { 1449 PERF_MAX_STACK_DEPTH) != 0) {
1423 if (verbose) 1450 if (verbose)
1424 error("Failed to resolve callchain. Skipping\n"); 1451 error("Failed to resolve callchain. Skipping\n");
1425 return; 1452 return;
@@ -1594,3 +1621,111 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1594out: 1621out:
1595 return err; 1622 return err;
1596} 1623}
1624
1625int perf_event__process_id_index(struct perf_tool *tool __maybe_unused,
1626 union perf_event *event,
1627 struct perf_session *session)
1628{
1629 struct perf_evlist *evlist = session->evlist;
1630 struct id_index_event *ie = &event->id_index;
1631 size_t i, nr, max_nr;
1632
1633 max_nr = (ie->header.size - sizeof(struct id_index_event)) /
1634 sizeof(struct id_index_entry);
1635 nr = ie->nr;
1636 if (nr > max_nr)
1637 return -EINVAL;
1638
1639 if (dump_trace)
1640 fprintf(stdout, " nr: %zu\n", nr);
1641
1642 for (i = 0; i < nr; i++) {
1643 struct id_index_entry *e = &ie->entries[i];
1644 struct perf_sample_id *sid;
1645
1646 if (dump_trace) {
1647 fprintf(stdout, " ... id: %"PRIu64, e->id);
1648 fprintf(stdout, " idx: %"PRIu64, e->idx);
1649 fprintf(stdout, " cpu: %"PRId64, e->cpu);
1650 fprintf(stdout, " tid: %"PRId64"\n", e->tid);
1651 }
1652
1653 sid = perf_evlist__id2sid(evlist, e->id);
1654 if (!sid)
1655 return -ENOENT;
1656 sid->idx = e->idx;
1657 sid->cpu = e->cpu;
1658 sid->tid = e->tid;
1659 }
1660 return 0;
1661}
1662
1663int perf_event__synthesize_id_index(struct perf_tool *tool,
1664 perf_event__handler_t process,
1665 struct perf_evlist *evlist,
1666 struct machine *machine)
1667{
1668 union perf_event *ev;
1669 struct perf_evsel *evsel;
1670 size_t nr = 0, i = 0, sz, max_nr, n;
1671 int err;
1672
1673 pr_debug2("Synthesizing id index\n");
1674
1675 max_nr = (UINT16_MAX - sizeof(struct id_index_event)) /
1676 sizeof(struct id_index_entry);
1677
1678 evlist__for_each(evlist, evsel)
1679 nr += evsel->ids;
1680
1681 n = nr > max_nr ? max_nr : nr;
1682 sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry);
1683 ev = zalloc(sz);
1684 if (!ev)
1685 return -ENOMEM;
1686
1687 ev->id_index.header.type = PERF_RECORD_ID_INDEX;
1688 ev->id_index.header.size = sz;
1689 ev->id_index.nr = n;
1690
1691 evlist__for_each(evlist, evsel) {
1692 u32 j;
1693
1694 for (j = 0; j < evsel->ids; j++) {
1695 struct id_index_entry *e;
1696 struct perf_sample_id *sid;
1697
1698 if (i >= n) {
1699 err = process(tool, ev, NULL, machine);
1700 if (err)
1701 goto out_err;
1702 nr -= n;
1703 i = 0;
1704 }
1705
1706 e = &ev->id_index.entries[i++];
1707
1708 e->id = evsel->id[j];
1709
1710 sid = perf_evlist__id2sid(evlist, e->id);
1711 if (!sid) {
1712 free(ev);
1713 return -ENOENT;
1714 }
1715
1716 e->idx = sid->idx;
1717 e->cpu = sid->cpu;
1718 e->tid = sid->tid;
1719 }
1720 }
1721
1722 sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry);
1723 ev->id_index.header.size = sz;
1724 ev->id_index.nr = nr;
1725
1726 err = process(tool, ev, NULL, machine);
1727out_err:
1728 free(ev);
1729
1730 return err;
1731}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a4be851f1a90..dc26ebf60fe4 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -126,4 +126,19 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
126extern volatile int session_done; 126extern volatile int session_done;
127 127
128#define session_done() ACCESS_ONCE(session_done) 128#define session_done() ACCESS_ONCE(session_done)
129
130int perf_session__deliver_synth_event(struct perf_session *session,
131 union perf_event *event,
132 struct perf_sample *sample,
133 struct perf_tool *tool);
134
135int perf_event__process_id_index(struct perf_tool *tool,
136 union perf_event *event,
137 struct perf_session *session);
138
139int perf_event__synthesize_id_index(struct perf_tool *tool,
140 perf_event__handler_t process,
141 struct perf_evlist *evlist,
142 struct machine *machine);
143
129#endif /* __PERF_SESSION_H */ 144#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index c41411726c7a..bf5bf858b7f6 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -15,7 +15,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
15 pid_t pid = thread->pid_; 15 pid_t pid = thread->pid_;
16 16
17 if (pid == thread->tid || pid == -1) { 17 if (pid == thread->tid || pid == -1) {
18 thread->mg = map_groups__new(); 18 thread->mg = map_groups__new(machine);
19 } else { 19 } else {
20 leader = machine__findnew_thread(machine, pid, pid); 20 leader = machine__findnew_thread(machine, pid, pid);
21 if (leader) 21 if (leader)
@@ -198,7 +198,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
198} 198}
199 199
200void thread__find_cpumode_addr_location(struct thread *thread, 200void thread__find_cpumode_addr_location(struct thread *thread,
201 struct machine *machine,
202 enum map_type type, u64 addr, 201 enum map_type type, u64 addr,
203 struct addr_location *al) 202 struct addr_location *al)
204{ 203{
@@ -211,8 +210,7 @@ void thread__find_cpumode_addr_location(struct thread *thread,
211 }; 210 };
212 211
213 for (i = 0; i < ARRAY_SIZE(cpumodes); i++) { 212 for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
214 thread__find_addr_location(thread, machine, cpumodes[i], type, 213 thread__find_addr_location(thread, cpumodes[i], type, addr, al);
215 addr, al);
216 if (al->map) 214 if (al->map)
217 break; 215 break;
218 } 216 }
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 8c75fa774706..d34cf5c0d0d9 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -23,6 +23,7 @@ struct thread {
23 bool dead; /* if set thread has exited */ 23 bool dead; /* if set thread has exited */
24 struct list_head comm_list; 24 struct list_head comm_list;
25 int comm_len; 25 int comm_len;
26 u64 db_id;
26 27
27 void *priv; 28 void *priv;
28}; 29};
@@ -54,16 +55,15 @@ void thread__insert_map(struct thread *thread, struct map *map);
54int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); 55int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
55size_t thread__fprintf(struct thread *thread, FILE *fp); 56size_t thread__fprintf(struct thread *thread, FILE *fp);
56 57
57void thread__find_addr_map(struct thread *thread, struct machine *machine, 58void thread__find_addr_map(struct thread *thread,
58 u8 cpumode, enum map_type type, u64 addr, 59 u8 cpumode, enum map_type type, u64 addr,
59 struct addr_location *al); 60 struct addr_location *al);
60 61
61void thread__find_addr_location(struct thread *thread, struct machine *machine, 62void thread__find_addr_location(struct thread *thread,
62 u8 cpumode, enum map_type type, u64 addr, 63 u8 cpumode, enum map_type type, u64 addr,
63 struct addr_location *al); 64 struct addr_location *al);
64 65
65void thread__find_cpumode_addr_location(struct thread *thread, 66void thread__find_cpumode_addr_location(struct thread *thread,
66 struct machine *machine,
67 enum map_type type, u64 addr, 67 enum map_type type, u64 addr,
68 struct addr_location *al); 68 struct addr_location *al);
69 69
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index f11636966a0f..bb2708bbfaca 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -39,7 +39,8 @@ struct perf_tool {
39 event_attr_op attr; 39 event_attr_op attr;
40 event_op2 tracing_data; 40 event_op2 tracing_data;
41 event_op2 finished_round, 41 event_op2 finished_round,
42 build_id; 42 build_id,
43 id_index;
43 bool ordered_events; 44 bool ordered_events;
44 bool ordering_requires_timestamps; 45 bool ordering_requires_timestamps;
45}; 46};
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 7419768c38b1..2dcfe9a7c8d0 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -26,7 +26,7 @@ static int __report_module(struct addr_location *al, u64 ip,
26 Dwfl_Module *mod; 26 Dwfl_Module *mod;
27 struct dso *dso = NULL; 27 struct dso *dso = NULL;
28 28
29 thread__find_addr_location(ui->thread, ui->machine, 29 thread__find_addr_location(ui->thread,
30 PERF_RECORD_MISC_USER, 30 PERF_RECORD_MISC_USER,
31 MAP__FUNCTION, ip, al); 31 MAP__FUNCTION, ip, al);
32 32
@@ -89,7 +89,7 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
89 struct addr_location al; 89 struct addr_location al;
90 ssize_t size; 90 ssize_t size;
91 91
92 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, 92 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
93 MAP__FUNCTION, addr, &al); 93 MAP__FUNCTION, addr, &al);
94 if (!al.map) { 94 if (!al.map) {
95 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 95 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
@@ -164,14 +164,14 @@ frame_callback(Dwfl_Frame *state, void *arg)
164} 164}
165 165
166int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 166int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
167 struct machine *machine, struct thread *thread, 167 struct thread *thread,
168 struct perf_sample *data, 168 struct perf_sample *data,
169 int max_stack) 169 int max_stack)
170{ 170{
171 struct unwind_info ui = { 171 struct unwind_info ui = {
172 .sample = data, 172 .sample = data,
173 .thread = thread, 173 .thread = thread,
174 .machine = machine, 174 .machine = thread->mg->machine,
175 .cb = cb, 175 .cb = cb,
176 .arg = arg, 176 .arg = arg,
177 .max_stack = max_stack, 177 .max_stack = max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 4d45c0dfe343..371219a6daf1 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -284,7 +284,7 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
284{ 284{
285 struct addr_location al; 285 struct addr_location al;
286 286
287 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, 287 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
288 MAP__FUNCTION, ip, &al); 288 MAP__FUNCTION, ip, &al);
289 return al.map; 289 return al.map;
290} 290}
@@ -374,7 +374,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
374 struct addr_location al; 374 struct addr_location al;
375 ssize_t size; 375 ssize_t size;
376 376
377 thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER, 377 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
378 MAP__FUNCTION, addr, &al); 378 MAP__FUNCTION, addr, &al);
379 if (!al.map) { 379 if (!al.map) {
380 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 380 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
@@ -476,14 +476,13 @@ static void put_unwind_info(unw_addr_space_t __maybe_unused as,
476 pr_debug("unwind: put_unwind_info called\n"); 476 pr_debug("unwind: put_unwind_info called\n");
477} 477}
478 478
479static int entry(u64 ip, struct thread *thread, struct machine *machine, 479static int entry(u64 ip, struct thread *thread,
480 unwind_entry_cb_t cb, void *arg) 480 unwind_entry_cb_t cb, void *arg)
481{ 481{
482 struct unwind_entry e; 482 struct unwind_entry e;
483 struct addr_location al; 483 struct addr_location al;
484 484
485 thread__find_addr_location(thread, machine, 485 thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
486 PERF_RECORD_MISC_USER,
487 MAP__FUNCTION, ip, &al); 486 MAP__FUNCTION, ip, &al);
488 487
489 e.ip = ip; 488 e.ip = ip;
@@ -586,21 +585,21 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
586 unw_word_t ip; 585 unw_word_t ip;
587 586
588 unw_get_reg(&c, UNW_REG_IP, &ip); 587 unw_get_reg(&c, UNW_REG_IP, &ip);
589 ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0; 588 ret = ip ? entry(ip, ui->thread, cb, arg) : 0;
590 } 589 }
591 590
592 return ret; 591 return ret;
593} 592}
594 593
595int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 594int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
596 struct machine *machine, struct thread *thread, 595 struct thread *thread,
597 struct perf_sample *data, int max_stack) 596 struct perf_sample *data, int max_stack)
598{ 597{
599 u64 ip; 598 u64 ip;
600 struct unwind_info ui = { 599 struct unwind_info ui = {
601 .sample = data, 600 .sample = data,
602 .thread = thread, 601 .thread = thread,
603 .machine = machine, 602 .machine = thread->mg->machine,
604 }; 603 };
605 int ret; 604 int ret;
606 605
@@ -611,7 +610,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
611 if (ret) 610 if (ret)
612 return ret; 611 return ret;
613 612
614 ret = entry(ip, thread, machine, cb, arg); 613 ret = entry(ip, thread, cb, arg);
615 if (ret) 614 if (ret)
616 return -ENOMEM; 615 return -ENOMEM;
617 616
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index f50b737235eb..12790cf94618 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -16,7 +16,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
16 16
17#ifdef HAVE_DWARF_UNWIND_SUPPORT 17#ifdef HAVE_DWARF_UNWIND_SUPPORT
18int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 18int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
19 struct machine *machine,
20 struct thread *thread, 19 struct thread *thread,
21 struct perf_sample *data, int max_stack); 20 struct perf_sample *data, int max_stack);
22/* libunwind specific */ 21/* libunwind specific */
@@ -38,7 +37,6 @@ static inline void unwind__finish_access(struct thread *thread __maybe_unused) {
38static inline int 37static inline int
39unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, 38unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
40 void *arg __maybe_unused, 39 void *arg __maybe_unused,
41 struct machine *machine __maybe_unused,
42 struct thread *thread __maybe_unused, 40 struct thread *thread __maybe_unused,
43 struct perf_sample *data __maybe_unused, 41 struct perf_sample *data __maybe_unused,
44 int max_stack __maybe_unused) 42 int max_stack __maybe_unused)
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index adca69384fcc..5c7dd796979d 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -12,9 +12,16 @@
12#include "util.h" 12#include "util.h"
13#include "symbol.h" 13#include "symbol.h"
14#include "machine.h" 14#include "machine.h"
15#include "thread.h"
15#include "linux/string.h" 16#include "linux/string.h"
16#include "debug.h" 17#include "debug.h"
17 18
19/*
20 * Include definition of find_vdso_map() also used in perf-read-vdso.c for
21 * building perf-read-vdso32 and perf-read-vdsox32.
22 */
23#include "find-vdso-map.c"
24
18#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" 25#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
19 26
20struct vdso_file { 27struct vdso_file {
@@ -22,10 +29,15 @@ struct vdso_file {
22 bool error; 29 bool error;
23 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)]; 30 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
24 const char *dso_name; 31 const char *dso_name;
32 const char *read_prog;
25}; 33};
26 34
27struct vdso_info { 35struct vdso_info {
28 struct vdso_file vdso; 36 struct vdso_file vdso;
37#if BITS_PER_LONG == 64
38 struct vdso_file vdso32;
39 struct vdso_file vdsox32;
40#endif
29}; 41};
30 42
31static struct vdso_info *vdso_info__new(void) 43static struct vdso_info *vdso_info__new(void)
@@ -35,42 +47,23 @@ static struct vdso_info *vdso_info__new(void)
35 .temp_file_name = VDSO__TEMP_FILE_NAME, 47 .temp_file_name = VDSO__TEMP_FILE_NAME,
36 .dso_name = DSO__NAME_VDSO, 48 .dso_name = DSO__NAME_VDSO,
37 }, 49 },
50#if BITS_PER_LONG == 64
51 .vdso32 = {
52 .temp_file_name = VDSO__TEMP_FILE_NAME,
53 .dso_name = DSO__NAME_VDSO32,
54 .read_prog = "perf-read-vdso32",
55 },
56 .vdsox32 = {
57 .temp_file_name = VDSO__TEMP_FILE_NAME,
58 .dso_name = DSO__NAME_VDSOX32,
59 .read_prog = "perf-read-vdsox32",
60 },
61#endif
38 }; 62 };
39 63
40 return memdup(&vdso_info_init, sizeof(vdso_info_init)); 64 return memdup(&vdso_info_init, sizeof(vdso_info_init));
41} 65}
42 66
43static int find_vdso_map(void **start, void **end)
44{
45 FILE *maps;
46 char line[128];
47 int found = 0;
48
49 maps = fopen("/proc/self/maps", "r");
50 if (!maps) {
51 pr_err("vdso: cannot open maps\n");
52 return -1;
53 }
54
55 while (!found && fgets(line, sizeof(line), maps)) {
56 int m = -1;
57
58 /* We care only about private r-x mappings. */
59 if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
60 start, end, &m))
61 continue;
62 if (m < 0)
63 continue;
64
65 if (!strncmp(&line[m], VDSO__MAP_NAME,
66 sizeof(VDSO__MAP_NAME) - 1))
67 found = 1;
68 }
69
70 fclose(maps);
71 return !found;
72}
73
74static char *get_file(struct vdso_file *vdso_file) 67static char *get_file(struct vdso_file *vdso_file)
75{ 68{
76 char *vdso = NULL; 69 char *vdso = NULL;
@@ -117,6 +110,12 @@ void vdso__exit(struct machine *machine)
117 110
118 if (vdso_info->vdso.found) 111 if (vdso_info->vdso.found)
119 unlink(vdso_info->vdso.temp_file_name); 112 unlink(vdso_info->vdso.temp_file_name);
113#if BITS_PER_LONG == 64
114 if (vdso_info->vdso32.found)
115 unlink(vdso_info->vdso32.temp_file_name);
116 if (vdso_info->vdsox32.found)
117 unlink(vdso_info->vdsox32.temp_file_name);
118#endif
120 119
121 zfree(&machine->vdso_info); 120 zfree(&machine->vdso_info);
122} 121}
@@ -135,6 +134,153 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
135 return dso; 134 return dso;
136} 135}
137 136
137#if BITS_PER_LONG == 64
138
139static enum dso_type machine__thread_dso_type(struct machine *machine,
140 struct thread *thread)
141{
142 enum dso_type dso_type = DSO__TYPE_UNKNOWN;
143 struct map *map;
144 struct dso *dso;
145
146 map = map_groups__first(thread->mg, MAP__FUNCTION);
147 for (; map ; map = map_groups__next(map)) {
148 dso = map->dso;
149 if (!dso || dso->long_name[0] != '/')
150 continue;
151 dso_type = dso__type(dso, machine);
152 if (dso_type != DSO__TYPE_UNKNOWN)
153 break;
154 }
155
156 return dso_type;
157}
158
159static int vdso__do_copy_compat(FILE *f, int fd)
160{
161 char buf[4096];
162 size_t count;
163
164 while (1) {
165 count = fread(buf, 1, sizeof(buf), f);
166 if (ferror(f))
167 return -errno;
168 if (feof(f))
169 break;
170 if (count && writen(fd, buf, count) != (ssize_t)count)
171 return -errno;
172 }
173
174 return 0;
175}
176
177static int vdso__copy_compat(const char *prog, int fd)
178{
179 FILE *f;
180 int err;
181
182 f = popen(prog, "r");
183 if (!f)
184 return -errno;
185
186 err = vdso__do_copy_compat(f, fd);
187
188 if (pclose(f) == -1)
189 return -errno;
190
191 return err;
192}
193
194static int vdso__create_compat_file(const char *prog, char *temp_name)
195{
196 int fd, err;
197
198 fd = mkstemp(temp_name);
199 if (fd < 0)
200 return -errno;
201
202 err = vdso__copy_compat(prog, fd);
203
204 if (close(fd) == -1)
205 return -errno;
206
207 return err;
208}
209
210static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
211{
212 int err;
213
214 if (vdso_file->found)
215 return vdso_file->temp_file_name;
216
217 if (vdso_file->error)
218 return NULL;
219
220 err = vdso__create_compat_file(vdso_file->read_prog,
221 vdso_file->temp_file_name);
222 if (err) {
223 pr_err("%s failed, error %d\n", vdso_file->read_prog, err);
224 vdso_file->error = true;
225 return NULL;
226 }
227
228 vdso_file->found = true;
229
230 return vdso_file->temp_file_name;
231}
232
233static struct dso *vdso__findnew_compat(struct machine *machine,
234 struct vdso_file *vdso_file)
235{
236 const char *file_name;
237 struct dso *dso;
238
239 dso = dsos__find(&machine->user_dsos, vdso_file->dso_name, true);
240 if (dso)
241 return dso;
242
243 file_name = vdso__get_compat_file(vdso_file);
244 if (!file_name)
245 return NULL;
246
247 return vdso__new(machine, vdso_file->dso_name, file_name);
248}
249
250static int vdso__dso_findnew_compat(struct machine *machine,
251 struct thread *thread,
252 struct vdso_info *vdso_info,
253 struct dso **dso)
254{
255 enum dso_type dso_type;
256
257 dso_type = machine__thread_dso_type(machine, thread);
258
259#ifndef HAVE_PERF_READ_VDSO32
260 if (dso_type == DSO__TYPE_32BIT)
261 return 0;
262#endif
263#ifndef HAVE_PERF_READ_VDSOX32
264 if (dso_type == DSO__TYPE_X32BIT)
265 return 0;
266#endif
267
268 switch (dso_type) {
269 case DSO__TYPE_32BIT:
270 *dso = vdso__findnew_compat(machine, &vdso_info->vdso32);
271 return 1;
272 case DSO__TYPE_X32BIT:
273 *dso = vdso__findnew_compat(machine, &vdso_info->vdsox32);
274 return 1;
275 case DSO__TYPE_UNKNOWN:
276 case DSO__TYPE_64BIT:
277 default:
278 return 0;
279 }
280}
281
282#endif
283
138struct dso *vdso__dso_findnew(struct machine *machine, 284struct dso *vdso__dso_findnew(struct machine *machine,
139 struct thread *thread __maybe_unused) 285 struct thread *thread __maybe_unused)
140{ 286{
@@ -148,6 +294,11 @@ struct dso *vdso__dso_findnew(struct machine *machine,
148 if (!vdso_info) 294 if (!vdso_info)
149 return NULL; 295 return NULL;
150 296
297#if BITS_PER_LONG == 64
298 if (vdso__dso_findnew_compat(machine, thread, vdso_info, &dso))
299 return dso;
300#endif
301
151 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true); 302 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
152 if (!dso) { 303 if (!dso) {
153 char *file; 304 char *file;
@@ -164,5 +315,7 @@ struct dso *vdso__dso_findnew(struct machine *machine,
164 315
165bool dso__is_vdso(struct dso *dso) 316bool dso__is_vdso(struct dso *dso)
166{ 317{
167 return !strcmp(dso->short_name, DSO__NAME_VDSO); 318 return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
319 !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
320 !strcmp(dso->short_name, DSO__NAME_VDSOX32);
168} 321}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
index af9d6929a215..d97da1616f0c 100644
--- a/tools/perf/util/vdso.h
+++ b/tools/perf/util/vdso.h
@@ -7,7 +7,9 @@
7 7
8#define VDSO__MAP_NAME "[vdso]" 8#define VDSO__MAP_NAME "[vdso]"
9 9
10#define DSO__NAME_VDSO "[vdso]" 10#define DSO__NAME_VDSO "[vdso]"
11#define DSO__NAME_VDSO32 "[vdso32]"
12#define DSO__NAME_VDSOX32 "[vdsox32]"
11 13
12static inline bool is_vdso_map(const char *filename) 14static inline bool is_vdso_map(const char *filename)
13{ 15{