aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
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{