aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile12
-rw-r--r--tools/include/asm/bug.h (renamed from tools/perf/util/include/asm/bug.h)9
-rw-r--r--tools/include/linux/compiler.h (renamed from tools/perf/util/include/linux/compiler.h)12
-rw-r--r--tools/lib/api/Makefile (renamed from tools/lib/lk/Makefile)18
-rw-r--r--tools/lib/api/fs/debugfs.c (renamed from tools/lib/lk/debugfs.c)0
-rw-r--r--tools/lib/api/fs/debugfs.h (renamed from tools/lib/lk/debugfs.h)6
-rw-r--r--tools/lib/symbol/kallsyms.c58
-rw-r--r--tools/lib/symbol/kallsyms.h24
-rw-r--r--tools/lib/traceevent/Makefile189
-rw-r--r--tools/lib/traceevent/event-parse.c108
-rw-r--r--tools/lib/traceevent/event-parse.h69
-rw-r--r--tools/lib/traceevent/event-plugin.c215
-rw-r--r--tools/lib/traceevent/parse-filter.c673
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c24
-rw-r--r--tools/lib/traceevent/plugin_function.c160
-rw-r--r--tools/lib/traceevent/plugin_hrtimer.c78
-rw-r--r--tools/lib/traceevent/plugin_jbd2.c68
-rw-r--r--tools/lib/traceevent/plugin_kmem.c72
-rw-r--r--tools/lib/traceevent/plugin_kvm.c436
-rw-r--r--tools/lib/traceevent/plugin_mac80211.c95
-rw-r--r--tools/lib/traceevent/plugin_sched_switch.c148
-rw-r--r--tools/lib/traceevent/plugin_scsi.c423
-rw-r--r--tools/lib/traceevent/plugin_xen.c130
-rw-r--r--tools/perf/Documentation/perf-archive.txt6
-rw-r--r--tools/perf/Documentation/perf-kvm.txt34
-rw-r--r--tools/perf/Documentation/perf-record.txt16
-rw-r--r--tools/perf/Documentation/perf-report.txt9
-rw-r--r--tools/perf/Documentation/perf-script.txt14
-rw-r--r--tools/perf/Documentation/perf-stat.txt2
-rw-r--r--tools/perf/Documentation/perf-timechart.txt42
-rw-r--r--tools/perf/Documentation/perf-top.txt5
-rw-r--r--tools/perf/MANIFEST6
-rw-r--r--tools/perf/Makefile7
-rw-r--r--tools/perf/Makefile.perf65
-rw-r--r--tools/perf/arch/common.c3
-rw-r--r--tools/perf/builtin-annotate.c17
-rw-r--r--tools/perf/builtin-diff.c103
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-inject.c67
-rw-r--r--tools/perf/builtin-kvm.c25
-rw-r--r--tools/perf/builtin-mem.c5
-rw-r--r--tools/perf/builtin-probe.c19
-rw-r--r--tools/perf/builtin-record.c199
-rw-r--r--tools/perf/builtin-report.c451
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-script.c266
-rw-r--r--tools/perf/builtin-stat.c186
-rw-r--r--tools/perf/builtin-timechart.c754
-rw-r--r--tools/perf/builtin-top.c66
-rw-r--r--tools/perf/builtin-trace.c96
-rw-r--r--tools/perf/config/Makefile130
-rw-r--r--tools/perf/config/Makefile.arch22
-rw-r--r--tools/perf/config/feature-checks/.gitignore2
-rw-r--r--tools/perf/config/feature-checks/Makefile120
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-stackprotector.c6
-rw-r--r--tools/perf/config/feature-checks/test-volatile-register-var.c6
-rw-r--r--tools/perf/config/utilities.mak7
-rw-r--r--tools/perf/perf-completion.sh (renamed from tools/perf/bash_completion)104
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/tests/attr/test-record-no-inherit2
-rw-r--r--tools/perf/tests/code-reading.c9
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c2
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/tests/keep-tracking.c9
-rw-r--r--tools/perf/tests/make58
-rw-r--r--tools/perf/tests/mmap-basic.c25
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c18
-rw-r--r--tools/perf/tests/parse-events.c12
-rw-r--r--tools/perf/tests/perf-record.c23
-rwxr-xr-xtools/perf/tests/perf-targz-src-pkg21
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c8
-rw-r--r--tools/perf/tests/sw-clock.c18
-rw-r--r--tools/perf/tests/task-exit.c33
-rw-r--r--tools/perf/ui/browser.c8
-rw-r--r--tools/perf/ui/browser.h2
-rw-r--r--tools/perf/ui/browsers/header.c127
-rw-r--r--tools/perf/ui/browsers/hists.c68
-rw-r--r--tools/perf/ui/browsers/scripts.c3
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/ui/gtk/util.c3
-rw-r--r--tools/perf/ui/stdio/hist.c2
-rw-r--r--tools/perf/ui/tui/util.c19
-rw-r--r--tools/perf/util/alias.c6
-rw-r--r--tools/perf/util/annotate.c75
-rw-r--r--tools/perf/util/annotate.h9
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/cgroup.c6
-rw-r--r--tools/perf/util/color.c15
-rw-r--r--tools/perf/util/color.h1
-rw-r--r--tools/perf/util/comm.c2
-rw-r--r--tools/perf/util/data.c6
-rw-r--r--tools/perf/util/data.h14
-rw-r--r--tools/perf/util/debug.c31
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/dso.c134
-rw-r--r--tools/perf/util/dso.h31
-rw-r--r--tools/perf/util/event.c61
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/evlist.c123
-rw-r--r--tools/perf/util/evlist.h81
-rw-r--r--tools/perf/util/evsel.c73
-rw-r--r--tools/perf/util/evsel.h7
-rw-r--r--tools/perf/util/header.c69
-rw-r--r--tools/perf/util/header.h10
-rw-r--r--tools/perf/util/help.c7
-rw-r--r--tools/perf/util/hist.c27
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/machine.c34
-rw-r--r--tools/perf/util/map.c17
-rw-r--r--tools/perf/util/map.h2
-rw-r--r--tools/perf/util/parse-events.c43
-rw-r--r--tools/perf/util/parse-options.c21
-rw-r--r--tools/perf/util/parse-options.h8
-rw-r--r--tools/perf/util/pmu.c142
-rw-r--r--tools/perf/util/pmu.h3
-rw-r--r--tools/perf/util/probe-event.c243
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c33
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c3
-rw-r--r--tools/perf/util/record.c52
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c22
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c28
-rw-r--r--tools/perf/util/session.c110
-rw-r--r--tools/perf/util/session.h10
-rw-r--r--tools/perf/util/setup.py4
-rw-r--r--tools/perf/util/sort.c22
-rw-r--r--tools/perf/util/srcline.c72
-rw-r--r--tools/perf/util/strbuf.c2
-rw-r--r--tools/perf/util/strfilter.c2
-rw-r--r--tools/perf/util/string.c2
-rw-r--r--tools/perf/util/strlist.c3
-rw-r--r--tools/perf/util/svghelper.c235
-rw-r--r--tools/perf/util/svghelper.h17
-rw-r--r--tools/perf/util/symbol-elf.c3
-rw-r--r--tools/perf/util/symbol-minimal.c4
-rw-r--r--tools/perf/util/symbol.c165
-rw-r--r--tools/perf/util/symbol.h11
-rw-r--r--tools/perf/util/target.c11
-rw-r--r--tools/perf/util/target.h17
-rw-r--r--tools/perf/util/thread.c2
-rw-r--r--tools/perf/util/thread.h12
-rw-r--r--tools/perf/util/thread_map.c20
-rw-r--r--tools/perf/util/top.c2
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/trace-event-info.c12
-rw-r--r--tools/perf/util/trace-event-parse.c13
-rw-r--r--tools/perf/util/trace-event-read.c20
-rw-r--r--tools/perf/util/trace-event-scripting.c3
-rw-r--r--tools/perf/util/trace-event.c82
-rw-r--r--tools/perf/util/trace-event.h16
-rw-r--r--tools/perf/util/unwind.c8
-rw-r--r--tools/perf/util/util.c136
-rw-r--r--tools/perf/util/util.h26
-rw-r--r--tools/perf/util/values.c14
-rw-r--r--tools/perf/util/vdso.c2
-rw-r--r--tools/scripts/Makefile.include4
-rw-r--r--tools/vm/Makefile14
-rw-r--r--tools/vm/page-types.c2
163 files changed, 6469 insertions, 2448 deletions
diff --git a/tools/Makefile b/tools/Makefile
index a9b02008443c..927cd46d36dc 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -39,10 +39,10 @@ cpupower: FORCE
39cgroup firewire guest usb virtio vm net: FORCE 39cgroup firewire guest usb virtio vm net: FORCE
40 $(call descend,$@) 40 $(call descend,$@)
41 41
42liblk: FORCE 42libapikfs: FORCE
43 $(call descend,lib/lk) 43 $(call descend,lib/api)
44 44
45perf: liblk FORCE 45perf: libapikfs FORCE
46 $(call descend,$@) 46 $(call descend,$@)
47 47
48selftests: FORCE 48selftests: FORCE
@@ -80,10 +80,10 @@ cpupower_clean:
80cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: 80cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
81 $(call descend,$(@:_clean=),clean) 81 $(call descend,$(@:_clean=),clean)
82 82
83liblk_clean: 83libapikfs_clean:
84 $(call descend,lib/lk,clean) 84 $(call descend,lib/api,clean)
85 85
86perf_clean: liblk_clean 86perf_clean: libapikfs_clean
87 $(call descend,$(@:_clean=),clean) 87 $(call descend,$(@:_clean=),clean)
88 88
89selftests_clean: 89selftests_clean:
diff --git a/tools/perf/util/include/asm/bug.h b/tools/include/asm/bug.h
index 7fcc6810adc2..9e5f4846967f 100644
--- a/tools/perf/util/include/asm/bug.h
+++ b/tools/include/asm/bug.h
@@ -1,5 +1,7 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H 1#ifndef _TOOLS_ASM_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H 2#define _TOOLS_ASM_BUG_H
3
4#include <linux/compiler.h>
3 5
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) 6#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5 7
@@ -19,4 +21,5 @@
19 __warned = 1; \ 21 __warned = 1; \
20 unlikely(__ret_warn_once); \ 22 unlikely(__ret_warn_once); \
21}) 23})
22#endif 24
25#endif /* _TOOLS_ASM_BUG_H */
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/include/linux/compiler.h
index b003ad7200b2..fbc6665c6d53 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_LINUX_COMPILER_H_ 1#ifndef _TOOLS_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_ 2#define _TOOLS_LINUX_COMPILER_H_
3 3
4#ifndef __always_inline 4#ifndef __always_inline
5# define __always_inline inline __attribute__((always_inline)) 5# define __always_inline inline __attribute__((always_inline))
@@ -27,4 +27,12 @@
27# define __weak __attribute__((weak)) 27# define __weak __attribute__((weak))
28#endif 28#endif
29 29
30#ifndef likely
31# define likely(x) __builtin_expect(!!(x), 1)
30#endif 32#endif
33
34#ifndef unlikely
35# define unlikely(x) __builtin_expect(!!(x), 0)
36#endif
37
38#endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/lib/lk/Makefile b/tools/lib/api/Makefile
index 3dba0a4aebbf..ed2f51e11b80 100644
--- a/tools/lib/lk/Makefile
+++ b/tools/lib/api/Makefile
@@ -1,4 +1,5 @@
1include ../../scripts/Makefile.include 1include ../../scripts/Makefile.include
2include ../../perf/config/utilities.mak # QUIET_CLEAN
2 3
3CC = $(CROSS_COMPILE)gcc 4CC = $(CROSS_COMPILE)gcc
4AR = $(CROSS_COMPILE)ar 5AR = $(CROSS_COMPILE)ar
@@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar
7LIB_H= 8LIB_H=
8LIB_OBJS= 9LIB_OBJS=
9 10
10LIB_H += debugfs.h 11LIB_H += fs/debugfs.h
11 12
12LIB_OBJS += $(OUTPUT)debugfs.o 13LIB_OBJS += $(OUTPUT)fs/debugfs.o
13 14
14LIBFILE = liblk.a 15LIBFILE = libapikfs.a
15 16
16CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC 17CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
17EXTLIBS = -lelf -lpthread -lrt -lm 18EXTLIBS = -lelf -lpthread -lrt -lm
@@ -25,14 +26,17 @@ $(LIBFILE): $(LIB_OBJS)
25 26
26$(LIB_OBJS): $(LIB_H) 27$(LIB_OBJS): $(LIB_H)
27 28
28$(OUTPUT)%.o: %.c 29libapi_dirs:
30 $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
31
32$(OUTPUT)%.o: %.c libapi_dirs
29 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 33 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
30$(OUTPUT)%.s: %.c 34$(OUTPUT)%.s: %.c libapi_dirs
31 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 35 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
32$(OUTPUT)%.o: %.S 36$(OUTPUT)%.o: %.S libapi_dirs
33 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 37 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
34 38
35clean: 39clean:
36 $(RM) $(LIB_OBJS) $(LIBFILE) 40 $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE)
37 41
38.PHONY: clean 42.PHONY: clean
diff --git a/tools/lib/lk/debugfs.c b/tools/lib/api/fs/debugfs.c
index 7c4347962353..7c4347962353 100644
--- a/tools/lib/lk/debugfs.c
+++ b/tools/lib/api/fs/debugfs.c
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/api/fs/debugfs.h
index 935c59bdb442..f19d3df9609d 100644
--- a/tools/lib/lk/debugfs.h
+++ b/tools/lib/api/fs/debugfs.h
@@ -1,5 +1,5 @@
1#ifndef __LK_DEBUGFS_H__ 1#ifndef __API_DEBUGFS_H__
2#define __LK_DEBUGFS_H__ 2#define __API_DEBUGFS_H__
3 3
4#define _STR(x) #x 4#define _STR(x) #x
5#define STR(x) _STR(x) 5#define STR(x) _STR(x)
@@ -26,4 +26,4 @@ char *debugfs_mount(const char *mountpoint);
26 26
27extern char debugfs_mountpoint[]; 27extern char debugfs_mountpoint[];
28 28
29#endif /* __LK_DEBUGFS_H__ */ 29#endif /* __API_DEBUGFS_H__ */
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c
new file mode 100644
index 000000000000..18bc271a4bbc
--- /dev/null
+++ b/tools/lib/symbol/kallsyms.c
@@ -0,0 +1,58 @@
1#include "symbol/kallsyms.h"
2#include <stdio.h>
3#include <stdlib.h>
4
5int kallsyms__parse(const char *filename, void *arg,
6 int (*process_symbol)(void *arg, const char *name,
7 char type, u64 start))
8{
9 char *line = NULL;
10 size_t n;
11 int err = -1;
12 FILE *file = fopen(filename, "r");
13
14 if (file == NULL)
15 goto out_failure;
16
17 err = 0;
18
19 while (!feof(file)) {
20 u64 start;
21 int line_len, len;
22 char symbol_type;
23 char *symbol_name;
24
25 line_len = getline(&line, &n, file);
26 if (line_len < 0 || !line)
27 break;
28
29 line[--line_len] = '\0'; /* \n */
30
31 len = hex2u64(line, &start);
32
33 len++;
34 if (len + 2 >= line_len)
35 continue;
36
37 symbol_type = line[len];
38 len += 2;
39 symbol_name = line + len;
40 len = line_len - len;
41
42 if (len >= KSYM_NAME_LEN) {
43 err = -1;
44 break;
45 }
46
47 err = process_symbol(arg, symbol_name, symbol_type, start);
48 if (err)
49 break;
50 }
51
52 free(line);
53 fclose(file);
54 return err;
55
56out_failure:
57 return -1;
58}
diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h
new file mode 100644
index 000000000000..6084f5e18b3c
--- /dev/null
+++ b/tools/lib/symbol/kallsyms.h
@@ -0,0 +1,24 @@
1#ifndef __TOOLS_KALLSYMS_H_
2#define __TOOLS_KALLSYMS_H_ 1
3
4#include <elf.h>
5#include <linux/ctype.h>
6#include <linux/types.h>
7
8#ifndef KSYM_NAME_LEN
9#define KSYM_NAME_LEN 256
10#endif
11
12static inline u8 kallsyms2elf_type(char type)
13{
14 if (type == 'W')
15 return STB_WEAK;
16
17 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
18}
19
20int kallsyms__parse(const char *filename, void *arg,
21 int (*process_symbol)(void *arg, const char *name,
22 char type, u64 start));
23
24#endif /* __TOOLS_KALLSYMS_H_ */
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index fc1502098595..f778d48ac609 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -43,6 +43,32 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))'
43export man_dir man_dir_SQ INSTALL 43export man_dir man_dir_SQ INSTALL
44export DESTDIR DESTDIR_SQ 44export DESTDIR DESTDIR_SQ
45 45
46set_plugin_dir := 1
47
48# Set plugin_dir to preffered global plugin location
49# If we install under $HOME directory we go under
50# $(HOME)/.traceevent/plugins
51#
52# We dont set PLUGIN_DIR in case we install under $HOME
53# directory, because by default the code looks under:
54# $(HOME)/.traceevent/plugins by default.
55#
56ifeq ($(plugin_dir),)
57ifeq ($(prefix),$(HOME))
58override plugin_dir = $(HOME)/.traceevent/plugins
59set_plugin_dir := 0
60else
61override plugin_dir = $(prefix)/lib/traceevent/plugins
62endif
63endif
64
65ifeq ($(set_plugin_dir),1)
66PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)"
67PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
68endif
69
70include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include
71
46# copy a bit from Linux kbuild 72# copy a bit from Linux kbuild
47 73
48ifeq ("$(origin V)", "command line") 74ifeq ("$(origin V)", "command line")
@@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line")
57endif 83endif
58 84
59ifeq ($(BUILD_SRC),) 85ifeq ($(BUILD_SRC),)
60ifneq ($(BUILD_OUTPUT),) 86ifneq ($(OUTPUT),)
61 87
62define build_output 88define build_output
63 $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \ 89 $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \
64 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 90 BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1
65endef 91endef
66 92
67saved-output := $(BUILD_OUTPUT)
68BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
69$(if $(BUILD_OUTPUT),, \
70 $(error output directory "$(saved-output)" does not exist))
71
72all: sub-make 93all: sub-make
73 94
74$(MAKECMDGOALS): sub-make 95$(MAKECMDGOALS): sub-make
@@ -80,7 +101,7 @@ sub-make: force
80# Leave processing to above invocation of make 101# Leave processing to above invocation of make
81skip-makefile := 1 102skip-makefile := 1
82 103
83endif # BUILD_OUTPUT 104endif # OUTPUT
84endif # BUILD_SRC 105endif # BUILD_SRC
85 106
86# We process the rest of the Makefile if this is the final invocation of make 107# We process the rest of the Makefile if this is the final invocation of make
@@ -96,6 +117,7 @@ export prefix bindir src obj
96# Shell quotes 117# Shell quotes
97bindir_SQ = $(subst ','\'',$(bindir)) 118bindir_SQ = $(subst ','\'',$(bindir))
98bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) 119bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
120plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
99 121
100LIB_FILE = libtraceevent.a libtraceevent.so 122LIB_FILE = libtraceevent.a libtraceevent.so
101 123
@@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
125 147
126ifeq ($(VERBOSE),1) 148ifeq ($(VERBOSE),1)
127 Q = 149 Q =
128 print_compile =
129 print_app_build =
130 print_fpic_compile =
131 print_shared_lib_compile =
132 print_plugin_obj_compile =
133 print_plugin_build =
134 print_install =
135else 150else
136 Q = @ 151 Q = @
137 print_compile = echo ' CC '$(OBJ);
138 print_app_build = echo ' BUILD '$(OBJ);
139 print_fpic_compile = echo ' CC FPIC '$(OBJ);
140 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
141 print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
142 print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
143 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
144 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
145endif 152endif
146 153
147do_fpic_compile = \
148 ($(print_fpic_compile) \
149 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
150
151do_app_build = \
152 ($(print_app_build) \
153 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
154
155do_compile_shared_library = \ 154do_compile_shared_library = \
156 ($(print_shared_lib_compile) \ 155 ($(print_shared_lib_compile) \
157 $(CC) --shared $^ -o $@) 156 $(CC) --shared $^ -o $@)
158 157
159do_compile_plugin_obj = \
160 ($(print_plugin_obj_compile) \
161 $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
162
163do_plugin_build = \ 158do_plugin_build = \
164 ($(print_plugin_build) \ 159 ($(print_plugin_build) \
165 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) 160 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
@@ -169,23 +164,37 @@ do_build_static_lib = \
169 $(RM) $@; $(AR) rcs $@ $^) 164 $(RM) $@; $(AR) rcs $@ $^)
170 165
171 166
172define do_compile 167do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
173 $(print_compile) \
174 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
175endef
176 168
177$(obj)/%.o: $(src)/%.c 169$(obj)/%.o: $(src)/%.c
178 $(Q)$(call do_compile) 170 $(call do_compile)
179 171
180%.o: $(src)/%.c 172%.o: $(src)/%.c
181 $(Q)$(call do_compile) 173 $(call do_compile)
182 174
183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 175PEVENT_LIB_OBJS = event-parse.o
176PEVENT_LIB_OBJS += event-plugin.o
177PEVENT_LIB_OBJS += trace-seq.o
178PEVENT_LIB_OBJS += parse-filter.o
179PEVENT_LIB_OBJS += parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o 180PEVENT_LIB_OBJS += kbuffer-parse.o
185 181
186ALL_OBJS = $(PEVENT_LIB_OBJS) 182PLUGIN_OBJS = plugin_jbd2.o
183PLUGIN_OBJS += plugin_hrtimer.o
184PLUGIN_OBJS += plugin_kmem.o
185PLUGIN_OBJS += plugin_kvm.o
186PLUGIN_OBJS += plugin_mac80211.o
187PLUGIN_OBJS += plugin_sched_switch.o
188PLUGIN_OBJS += plugin_function.o
189PLUGIN_OBJS += plugin_xen.o
190PLUGIN_OBJS += plugin_scsi.o
191PLUGIN_OBJS += plugin_cfg80211.o
192
193PLUGINS := $(PLUGIN_OBJS:.o=.so)
194
195ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
187 196
188CMD_TARGETS = $(LIB_FILE) 197CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
189 198
190TARGETS = $(CMD_TARGETS) 199TARGETS = $(CMD_TARGETS)
191 200
@@ -195,32 +204,40 @@ all: all_cmd
195all_cmd: $(CMD_TARGETS) 204all_cmd: $(CMD_TARGETS)
196 205
197libtraceevent.so: $(PEVENT_LIB_OBJS) 206libtraceevent.so: $(PEVENT_LIB_OBJS)
198 $(Q)$(do_compile_shared_library) 207 $(QUIET_LINK)$(CC) --shared $^ -o $@
199 208
200libtraceevent.a: $(PEVENT_LIB_OBJS) 209libtraceevent.a: $(PEVENT_LIB_OBJS)
201 $(Q)$(do_build_static_lib) 210 $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
211
212plugins: $(PLUGINS)
202 213
203$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS 214$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
204 $(Q)$(do_fpic_compile) 215 $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@
216
217$(PLUGIN_OBJS): %.o : $(src)/%.c
218 $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $<
219
220$(PLUGINS): %.so: %.o
221 $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<
205 222
206define make_version.h 223define make_version.h
207 (echo '/* This file is automatically generated. Do not modify. */'; \ 224 (echo '/* This file is automatically generated. Do not modify. */'; \
208 echo \#define VERSION_CODE $(shell \ 225 echo \#define VERSION_CODE $(shell \
209 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ 226 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
210 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ 227 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
211 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ 228 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
212 echo '#define FILE_VERSION '$(FILE_VERSION); \ 229 echo '#define FILE_VERSION '$(FILE_VERSION); \
213 ) > $1 230 ) > $1
214endef 231endef
215 232
216define update_version.h 233define update_version.h
217 ($(call make_version.h, $@.tmp); \ 234 ($(call make_version.h, $@.tmp); \
218 if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 235 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
219 rm -f $@.tmp; \ 236 rm -f $@.tmp; \
220 else \ 237 else \
221 echo ' UPDATE $@'; \ 238 echo ' UPDATE $@'; \
222 mv -f $@.tmp $@; \ 239 mv -f $@.tmp $@; \
223 fi); 240 fi);
224endef 241endef
225 242
226ep_version.h: force 243ep_version.h: force
@@ -229,13 +246,13 @@ ep_version.h: force
229VERSION_FILES = ep_version.h 246VERSION_FILES = ep_version.h
230 247
231define update_dir 248define update_dir
232 (echo $1 > $@.tmp; \ 249 (echo $1 > $@.tmp; \
233 if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 250 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
234 rm -f $@.tmp; \ 251 rm -f $@.tmp; \
235 else \ 252 else \
236 echo ' UPDATE $@'; \ 253 echo ' UPDATE $@'; \
237 mv -f $@.tmp $@; \ 254 mv -f $@.tmp $@; \
238 fi); 255 fi);
239endef 256endef
240 257
241## make deps 258## make deps
@@ -245,10 +262,10 @@ all_deps := $(all_objs:%.o=.%.d)
245 262
246# let .d file also depends on the source and header files 263# let .d file also depends on the source and header files
247define check_deps 264define check_deps
248 @set -e; $(RM) $@; \ 265 @set -e; $(RM) $@; \
249 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ 266 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
250 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 267 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
251 $(RM) $@.$$$$ 268 $(RM) $@.$$$$
252endef 269endef
253 270
254$(all_deps): .%.d: $(src)/%.c 271$(all_deps): .%.d: $(src)/%.c
@@ -283,27 +300,41 @@ TAGS: force
283 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' 300 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
284 301
285define do_install 302define do_install
286 $(print_install) \
287 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ 303 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
288 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ 304 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
289 fi; \ 305 fi; \
290 $(INSTALL) $1 '$(DESTDIR_SQ)$2' 306 $(INSTALL) $1 '$(DESTDIR_SQ)$2'
291endef 307endef
292 308
293install_lib: all_cmd 309define do_install_plugins
294 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) 310 for plugin in $1; do \
311 $(call do_install,$$plugin,$(plugin_dir_SQ)); \
312 done
313endef
314
315install_lib: all_cmd install_plugins
316 $(call QUIET_INSTALL, $(LIB_FILE)) \
317 $(call do_install,$(LIB_FILE),$(bindir_SQ))
318
319install_plugins: $(PLUGINS)
320 $(call QUIET_INSTALL, trace_plugins) \
321 $(call do_install_plugins, $(PLUGINS))
295 322
296install: install_lib 323install: install_lib
297 324
298clean: 325clean:
299 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d 326 $(call QUIET_CLEAN, libtraceevent) \
300 $(RM) TRACEEVENT-CFLAGS tags TAGS 327 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
328 $(RM) TRACEEVENT-CFLAGS tags TAGS
301 329
302endif # skip-makefile 330endif # skip-makefile
303 331
304PHONY += force 332PHONY += force plugins
305force: 333force:
306 334
335plugins:
336 @echo > /dev/null
337
307# Declare the contents of the .PHONY variable as phony. We keep that 338# Declare the contents of the .PHONY variable as phony. We keep that
308# information in a variable so we can use it in if_changed and friends. 339# information in a variable so we can use it in if_changed and friends.
309.PHONY: $(PHONY) 340.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 217c82ee3665..2ce565a73dd5 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2710 struct print_arg *farg; 2710 struct print_arg *farg;
2711 enum event_type type; 2711 enum event_type type;
2712 char *token; 2712 char *token;
2713 const char *test;
2714 int i; 2713 int i;
2715 2714
2716 arg->type = PRINT_FUNC; 2715 arg->type = PRINT_FUNC;
@@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2727 } 2726 }
2728 2727
2729 type = process_arg(event, farg, &token); 2728 type = process_arg(event, farg, &token);
2730 if (i < (func->nr_args - 1)) 2729 if (i < (func->nr_args - 1)) {
2731 test = ","; 2730 if (type != EVENT_DELIM || strcmp(token, ",") != 0) {
2732 else 2731 warning("Error: function '%s()' expects %d arguments but event %s only uses %d",
2733 test = ")"; 2732 func->name, func->nr_args,
2734 2733 event->name, i + 1);
2735 if (test_type_token(type, token, EVENT_DELIM, test)) { 2734 goto err;
2736 free_arg(farg); 2735 }
2737 free_token(token); 2736 } else {
2738 return EVENT_ERROR; 2737 if (type != EVENT_DELIM || strcmp(token, ")") != 0) {
2738 warning("Error: function '%s()' only expects %d arguments but event %s has more",
2739 func->name, func->nr_args, event->name);
2740 goto err;
2741 }
2739 } 2742 }
2740 2743
2741 *next_arg = farg; 2744 *next_arg = farg;
@@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2747 *tok = token; 2750 *tok = token;
2748 2751
2749 return type; 2752 return type;
2753
2754err:
2755 free_arg(farg);
2756 free_token(token);
2757 return EVENT_ERROR;
2750} 2758}
2751 2759
2752static enum event_type 2760static enum event_type
@@ -4099,6 +4107,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4099 unsigned long long val; 4107 unsigned long long val;
4100 struct func_map *func; 4108 struct func_map *func;
4101 const char *saveptr; 4109 const char *saveptr;
4110 struct trace_seq p;
4102 char *bprint_fmt = NULL; 4111 char *bprint_fmt = NULL;
4103 char format[32]; 4112 char format[32];
4104 int show_func; 4113 int show_func;
@@ -4306,8 +4315,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4306 format[len] = 0; 4315 format[len] = 0;
4307 if (!len_as_arg) 4316 if (!len_as_arg)
4308 len_arg = -1; 4317 len_arg = -1;
4309 print_str_arg(s, data, size, event, 4318 /* Use helper trace_seq */
4319 trace_seq_init(&p);
4320 print_str_arg(&p, data, size, event,
4310 format, len_arg, arg); 4321 format, len_arg, arg);
4322 trace_seq_terminate(&p);
4323 trace_seq_puts(s, p.buffer);
4311 arg = arg->next; 4324 arg = arg->next;
4312 break; 4325 break;
4313 default: 4326 default:
@@ -5116,8 +5129,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
5116 return ret; 5129 return ret;
5117} 5130}
5118 5131
5132static enum pevent_errno
5133__pevent_parse_event(struct pevent *pevent,
5134 struct event_format **eventp,
5135 const char *buf, unsigned long size,
5136 const char *sys)
5137{
5138 int ret = __pevent_parse_format(eventp, pevent, buf, size, sys);
5139 struct event_format *event = *eventp;
5140
5141 if (event == NULL)
5142 return ret;
5143
5144 if (pevent && add_event(pevent, event)) {
5145 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5146 goto event_add_failed;
5147 }
5148
5149#define PRINT_ARGS 0
5150 if (PRINT_ARGS && event->print_fmt.args)
5151 print_args(event->print_fmt.args);
5152
5153 return 0;
5154
5155event_add_failed:
5156 pevent_free_format(event);
5157 return ret;
5158}
5159
5119/** 5160/**
5120 * pevent_parse_format - parse the event format 5161 * pevent_parse_format - parse the event format
5162 * @pevent: the handle to the pevent
5163 * @eventp: returned format
5121 * @buf: the buffer storing the event format string 5164 * @buf: the buffer storing the event format string
5122 * @size: the size of @buf 5165 * @size: the size of @buf
5123 * @sys: the system the event belongs to 5166 * @sys: the system the event belongs to
@@ -5129,10 +5172,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
5129 * 5172 *
5130 * /sys/kernel/debug/tracing/events/.../.../format 5173 * /sys/kernel/debug/tracing/events/.../.../format
5131 */ 5174 */
5132enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 5175enum pevent_errno pevent_parse_format(struct pevent *pevent,
5176 struct event_format **eventp,
5177 const char *buf,
5133 unsigned long size, const char *sys) 5178 unsigned long size, const char *sys)
5134{ 5179{
5135 return __pevent_parse_format(eventp, NULL, buf, size, sys); 5180 return __pevent_parse_event(pevent, eventp, buf, size, sys);
5136} 5181}
5137 5182
5138/** 5183/**
@@ -5153,25 +5198,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
5153 unsigned long size, const char *sys) 5198 unsigned long size, const char *sys)
5154{ 5199{
5155 struct event_format *event = NULL; 5200 struct event_format *event = NULL;
5156 int ret = __pevent_parse_format(&event, pevent, buf, size, sys); 5201 return __pevent_parse_event(pevent, &event, buf, size, sys);
5157
5158 if (event == NULL)
5159 return ret;
5160
5161 if (add_event(pevent, event)) {
5162 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5163 goto event_add_failed;
5164 }
5165
5166#define PRINT_ARGS 0
5167 if (PRINT_ARGS && event->print_fmt.args)
5168 print_args(event->print_fmt.args);
5169
5170 return 0;
5171
5172event_add_failed:
5173 pevent_free_format(event);
5174 return ret;
5175} 5202}
5176 5203
5177#undef _PE 5204#undef _PE
@@ -5203,22 +5230,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused,
5203 5230
5204 idx = errnum - __PEVENT_ERRNO__START - 1; 5231 idx = errnum - __PEVENT_ERRNO__START - 1;
5205 msg = pevent_error_str[idx]; 5232 msg = pevent_error_str[idx];
5206 5233 snprintf(buf, buflen, "%s", msg);
5207 switch (errnum) {
5208 case PEVENT_ERRNO__MEM_ALLOC_FAILED:
5209 case PEVENT_ERRNO__PARSE_EVENT_FAILED:
5210 case PEVENT_ERRNO__READ_ID_FAILED:
5211 case PEVENT_ERRNO__READ_FORMAT_FAILED:
5212 case PEVENT_ERRNO__READ_PRINT_FAILED:
5213 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
5214 case PEVENT_ERRNO__INVALID_ARG_TYPE:
5215 snprintf(buf, buflen, "%s", msg);
5216 break;
5217
5218 default:
5219 /* cannot reach here */
5220 break;
5221 }
5222 5234
5223 return 0; 5235 return 0;
5224} 5236}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 8d73d2594f65..cf5db9013f2c 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -23,6 +23,7 @@
23#include <stdbool.h> 23#include <stdbool.h>
24#include <stdarg.h> 24#include <stdarg.h>
25#include <regex.h> 25#include <regex.h>
26#include <string.h>
26 27
27#ifndef __maybe_unused 28#ifndef __maybe_unused
28#define __maybe_unused __attribute__((unused)) 29#define __maybe_unused __attribute__((unused))
@@ -355,12 +356,35 @@ enum pevent_flag {
355 _PE(READ_FORMAT_FAILED, "failed to read event format"), \ 356 _PE(READ_FORMAT_FAILED, "failed to read event format"), \
356 _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ 357 _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
357 _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ 358 _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
358 _PE(INVALID_ARG_TYPE, "invalid argument type") 359 _PE(INVALID_ARG_TYPE, "invalid argument type"), \
360 _PE(INVALID_EXP_TYPE, "invalid expression type"), \
361 _PE(INVALID_OP_TYPE, "invalid operator type"), \
362 _PE(INVALID_EVENT_NAME, "invalid event name"), \
363 _PE(EVENT_NOT_FOUND, "no event found"), \
364 _PE(SYNTAX_ERROR, "syntax error"), \
365 _PE(ILLEGAL_RVALUE, "illegal rvalue"), \
366 _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \
367 _PE(INVALID_REGEX, "regex did not compute"), \
368 _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \
369 _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \
370 _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \
371 _PE(REPARENT_FAILED, "failed to reparent filter OP"), \
372 _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \
373 _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \
374 _PE(ILLEGAL_TOKEN, "illegal token"), \
375 _PE(INVALID_PAREN, "open parenthesis cannot come here"), \
376 _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \
377 _PE(UNKNOWN_TOKEN, "unknown token"), \
378 _PE(FILTER_NOT_FOUND, "no filter found"), \
379 _PE(NOT_A_NUMBER, "must have number field"), \
380 _PE(NO_FILTER, "no filters exists"), \
381 _PE(FILTER_MISS, "record does not match to filter")
359 382
360#undef _PE 383#undef _PE
361#define _PE(__code, __str) PEVENT_ERRNO__ ## __code 384#define _PE(__code, __str) PEVENT_ERRNO__ ## __code
362enum pevent_errno { 385enum pevent_errno {
363 PEVENT_ERRNO__SUCCESS = 0, 386 PEVENT_ERRNO__SUCCESS = 0,
387 PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS,
364 388
365 /* 389 /*
366 * Choose an arbitrary negative big number not to clash with standard 390 * Choose an arbitrary negative big number not to clash with standard
@@ -377,6 +401,11 @@ enum pevent_errno {
377}; 401};
378#undef _PE 402#undef _PE
379 403
404struct plugin_list;
405
406struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
407void traceevent_unload_plugins(struct plugin_list *plugin_list);
408
380struct cmdline; 409struct cmdline;
381struct cmdline_list; 410struct cmdline_list;
382struct func_map; 411struct func_map;
@@ -522,6 +551,15 @@ __data2host8(struct pevent *pevent, unsigned long long data)
522 __data2host8(pevent, __val); \ 551 __data2host8(pevent, __val); \
523}) 552})
524 553
554static inline int traceevent_host_bigendian(void)
555{
556 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
557 unsigned int val;
558
559 memcpy(&val, str, 4);
560 return val == 0x01020304;
561}
562
525/* taken from kernel/trace/trace.h */ 563/* taken from kernel/trace/trace.h */
526enum trace_flag_type { 564enum trace_flag_type {
527 TRACE_FLAG_IRQS_OFF = 0x01, 565 TRACE_FLAG_IRQS_OFF = 0x01,
@@ -547,7 +585,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz
547 585
548enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, 586enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
549 unsigned long size, const char *sys); 587 unsigned long size, const char *sys);
550enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 588enum pevent_errno pevent_parse_format(struct pevent *pevent,
589 struct event_format **eventp,
590 const char *buf,
551 unsigned long size, const char *sys); 591 unsigned long size, const char *sys);
552void pevent_free_format(struct event_format *event); 592void pevent_free_format(struct event_format *event);
553 593
@@ -811,18 +851,22 @@ struct filter_type {
811 struct filter_arg *filter; 851 struct filter_arg *filter;
812}; 852};
813 853
854#define PEVENT_FILTER_ERROR_BUFSZ 1024
855
814struct event_filter { 856struct event_filter {
815 struct pevent *pevent; 857 struct pevent *pevent;
816 int filters; 858 int filters;
817 struct filter_type *event_filters; 859 struct filter_type *event_filters;
860 char error_buffer[PEVENT_FILTER_ERROR_BUFSZ];
818}; 861};
819 862
820struct event_filter *pevent_filter_alloc(struct pevent *pevent); 863struct event_filter *pevent_filter_alloc(struct pevent *pevent);
821 864
822#define FILTER_NONE -2 865/* for backward compatibility */
823#define FILTER_NOEXIST -1 866#define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND
824#define FILTER_MISS 0 867#define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER
825#define FILTER_MATCH 1 868#define FILTER_MISS PEVENT_ERRNO__FILTER_MISS
869#define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH
826 870
827enum filter_trivial_type { 871enum filter_trivial_type {
828 FILTER_TRIVIAL_FALSE, 872 FILTER_TRIVIAL_FALSE,
@@ -830,20 +874,21 @@ enum filter_trivial_type {
830 FILTER_TRIVIAL_BOTH, 874 FILTER_TRIVIAL_BOTH,
831}; 875};
832 876
833int pevent_filter_add_filter_str(struct event_filter *filter, 877enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
834 const char *filter_str, 878 const char *filter_str);
835 char **error_str);
836 879
880enum pevent_errno pevent_filter_match(struct event_filter *filter,
881 struct pevent_record *record);
837 882
838int pevent_filter_match(struct event_filter *filter, 883int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
839 struct pevent_record *record); 884 char *buf, size_t buflen);
840 885
841int pevent_event_filtered(struct event_filter *filter, 886int pevent_event_filtered(struct event_filter *filter,
842 int event_id); 887 int event_id);
843 888
844void pevent_filter_reset(struct event_filter *filter); 889void pevent_filter_reset(struct event_filter *filter);
845 890
846void pevent_filter_clear_trivial(struct event_filter *filter, 891int pevent_filter_clear_trivial(struct event_filter *filter,
847 enum filter_trivial_type type); 892 enum filter_trivial_type type);
848 893
849void pevent_filter_free(struct event_filter *filter); 894void pevent_filter_free(struct event_filter *filter);
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
new file mode 100644
index 000000000000..125f5676bcb5
--- /dev/null
+++ b/tools/lib/traceevent/event-plugin.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20
21#include <string.h>
22#include <dlfcn.h>
23#include <stdlib.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <dirent.h>
28#include "event-parse.h"
29#include "event-utils.h"
30
31#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
32
33struct plugin_list {
34 struct plugin_list *next;
35 char *name;
36 void *handle;
37};
38
39static void
40load_plugin(struct pevent *pevent, const char *path,
41 const char *file, void *data)
42{
43 struct plugin_list **plugin_list = data;
44 pevent_plugin_load_func func;
45 struct plugin_list *list;
46 const char *alias;
47 char *plugin;
48 void *handle;
49
50 plugin = malloc(strlen(path) + strlen(file) + 2);
51 if (!plugin) {
52 warning("could not allocate plugin memory\n");
53 return;
54 }
55
56 strcpy(plugin, path);
57 strcat(plugin, "/");
58 strcat(plugin, file);
59
60 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
61 if (!handle) {
62 warning("could not load plugin '%s'\n%s\n",
63 plugin, dlerror());
64 goto out_free;
65 }
66
67 alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
68 if (!alias)
69 alias = file;
70
71 func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
72 if (!func) {
73 warning("could not find func '%s' in plugin '%s'\n%s\n",
74 PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
75 goto out_free;
76 }
77
78 list = malloc(sizeof(*list));
79 if (!list) {
80 warning("could not allocate plugin memory\n");
81 goto out_free;
82 }
83
84 list->next = *plugin_list;
85 list->handle = handle;
86 list->name = plugin;
87 *plugin_list = list;
88
89 pr_stat("registering plugin: %s", plugin);
90 func(pevent);
91 return;
92
93 out_free:
94 free(plugin);
95}
96
97static void
98load_plugins_dir(struct pevent *pevent, const char *suffix,
99 const char *path,
100 void (*load_plugin)(struct pevent *pevent,
101 const char *path,
102 const char *name,
103 void *data),
104 void *data)
105{
106 struct dirent *dent;
107 struct stat st;
108 DIR *dir;
109 int ret;
110
111 ret = stat(path, &st);
112 if (ret < 0)
113 return;
114
115 if (!S_ISDIR(st.st_mode))
116 return;
117
118 dir = opendir(path);
119 if (!dir)
120 return;
121
122 while ((dent = readdir(dir))) {
123 const char *name = dent->d_name;
124
125 if (strcmp(name, ".") == 0 ||
126 strcmp(name, "..") == 0)
127 continue;
128
129 /* Only load plugins that end in suffix */
130 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
131 continue;
132
133 load_plugin(pevent, path, name, data);
134 }
135
136 closedir(dir);
137}
138
139static void
140load_plugins(struct pevent *pevent, const char *suffix,
141 void (*load_plugin)(struct pevent *pevent,
142 const char *path,
143 const char *name,
144 void *data),
145 void *data)
146{
147 char *home;
148 char *path;
149 char *envdir;
150
151 /*
152 * If a system plugin directory was defined,
153 * check that first.
154 */
155#ifdef PLUGIN_DIR
156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data);
157#endif
158
159 /*
160 * Next let the environment-set plugin directory
161 * override the system defaults.
162 */
163 envdir = getenv("TRACEEVENT_PLUGIN_DIR");
164 if (envdir)
165 load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
166
167 /*
168 * Now let the home directory override the environment
169 * or system defaults.
170 */
171 home = getenv("HOME");
172 if (!home)
173 return;
174
175 path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
176 if (!path) {
177 warning("could not allocate plugin memory\n");
178 return;
179 }
180
181 strcpy(path, home);
182 strcat(path, "/");
183 strcat(path, LOCAL_PLUGIN_DIR);
184
185 load_plugins_dir(pevent, suffix, path, load_plugin, data);
186
187 free(path);
188}
189
190struct plugin_list*
191traceevent_load_plugins(struct pevent *pevent)
192{
193 struct plugin_list *list = NULL;
194
195 load_plugins(pevent, ".so", load_plugin, &list);
196 return list;
197}
198
199void
200traceevent_unload_plugins(struct plugin_list *plugin_list)
201{
202 pevent_plugin_unload_func func;
203 struct plugin_list *list;
204
205 while (plugin_list) {
206 list = plugin_list;
207 plugin_list = list->next;
208 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
209 if (func)
210 func();
211 dlclose(list->handle);
212 free(list->name);
213 free(list);
214 }
215}
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 2500e75583fc..b50234402fc2 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -38,41 +38,31 @@ struct event_list {
38 struct event_format *event; 38 struct event_format *event;
39}; 39};
40 40
41#define MAX_ERR_STR_SIZE 256 41static void show_error(char *error_buf, const char *fmt, ...)
42
43static void show_error(char **error_str, const char *fmt, ...)
44{ 42{
45 unsigned long long index; 43 unsigned long long index;
46 const char *input; 44 const char *input;
47 char *error;
48 va_list ap; 45 va_list ap;
49 int len; 46 int len;
50 int i; 47 int i;
51 48
52 if (!error_str)
53 return;
54
55 input = pevent_get_input_buf(); 49 input = pevent_get_input_buf();
56 index = pevent_get_input_buf_ptr(); 50 index = pevent_get_input_buf_ptr();
57 len = input ? strlen(input) : 0; 51 len = input ? strlen(input) : 0;
58 52
59 error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
60
61 if (len) { 53 if (len) {
62 strcpy(error, input); 54 strcpy(error_buf, input);
63 error[len] = '\n'; 55 error_buf[len] = '\n';
64 for (i = 1; i < len && i < index; i++) 56 for (i = 1; i < len && i < index; i++)
65 error[len+i] = ' '; 57 error_buf[len+i] = ' ';
66 error[len + i] = '^'; 58 error_buf[len + i] = '^';
67 error[len + i + 1] = '\n'; 59 error_buf[len + i + 1] = '\n';
68 len += i+2; 60 len += i+2;
69 } 61 }
70 62
71 va_start(ap, fmt); 63 va_start(ap, fmt);
72 vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); 64 vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap);
73 va_end(ap); 65 va_end(ap);
74
75 *error_str = error;
76} 66}
77 67
78static void free_token(char *token) 68static void free_token(char *token)
@@ -95,7 +85,11 @@ static enum event_type read_token(char **tok)
95 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && 85 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
96 pevent_peek_char() == '~') { 86 pevent_peek_char() == '~') {
97 /* append it */ 87 /* append it */
98 *tok = malloc_or_die(3); 88 *tok = malloc(3);
89 if (*tok == NULL) {
90 free_token(token);
91 return EVENT_ERROR;
92 }
99 sprintf(*tok, "%c%c", *token, '~'); 93 sprintf(*tok, "%c%c", *token, '~');
100 free_token(token); 94 free_token(token);
101 /* Now remove the '~' from the buffer */ 95 /* Now remove the '~' from the buffer */
@@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int id)
147 if (filter_type) 141 if (filter_type)
148 return filter_type; 142 return filter_type;
149 143
150 filter->event_filters = realloc(filter->event_filters, 144 filter_type = realloc(filter->event_filters,
151 sizeof(*filter->event_filters) * 145 sizeof(*filter->event_filters) *
152 (filter->filters + 1)); 146 (filter->filters + 1));
153 if (!filter->event_filters) 147 if (!filter_type)
154 die("Could not allocate filter"); 148 return NULL;
149
150 filter->event_filters = filter_type;
155 151
156 for (i = 0; i < filter->filters; i++) { 152 for (i = 0; i < filter->filters; i++) {
157 if (filter->event_filters[i].event_id > id) 153 if (filter->event_filters[i].event_id > id)
@@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
182{ 178{
183 struct event_filter *filter; 179 struct event_filter *filter;
184 180
185 filter = malloc_or_die(sizeof(*filter)); 181 filter = malloc(sizeof(*filter));
182 if (filter == NULL)
183 return NULL;
184
186 memset(filter, 0, sizeof(*filter)); 185 memset(filter, 0, sizeof(*filter));
187 filter->pevent = pevent; 186 filter->pevent = pevent;
188 pevent_ref(pevent); 187 pevent_ref(pevent);
@@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
192 191
193static struct filter_arg *allocate_arg(void) 192static struct filter_arg *allocate_arg(void)
194{ 193{
195 struct filter_arg *arg; 194 return calloc(1, sizeof(struct filter_arg));
196
197 arg = malloc_or_die(sizeof(*arg));
198 memset(arg, 0, sizeof(*arg));
199
200 return arg;
201} 195}
202 196
203static void free_arg(struct filter_arg *arg) 197static void free_arg(struct filter_arg *arg)
@@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg)
242 free(arg); 236 free(arg);
243} 237}
244 238
245static void add_event(struct event_list **events, 239static int add_event(struct event_list **events,
246 struct event_format *event) 240 struct event_format *event)
247{ 241{
248 struct event_list *list; 242 struct event_list *list;
249 243
250 list = malloc_or_die(sizeof(*list)); 244 list = malloc(sizeof(*list));
245 if (list == NULL)
246 return -1;
247
251 list->next = *events; 248 list->next = *events;
252 *events = list; 249 *events = list;
253 list->event = event; 250 list->event = event;
251 return 0;
254} 252}
255 253
256static int event_match(struct event_format *event, 254static int event_match(struct event_format *event,
@@ -265,7 +263,7 @@ static int event_match(struct event_format *event,
265 !regexec(ereg, event->name, 0, NULL, 0); 263 !regexec(ereg, event->name, 0, NULL, 0);
266} 264}
267 265
268static int 266static enum pevent_errno
269find_event(struct pevent *pevent, struct event_list **events, 267find_event(struct pevent *pevent, struct event_list **events,
270 char *sys_name, char *event_name) 268 char *sys_name, char *event_name)
271{ 269{
@@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events,
273 regex_t ereg; 271 regex_t ereg;
274 regex_t sreg; 272 regex_t sreg;
275 int match = 0; 273 int match = 0;
274 int fail = 0;
276 char *reg; 275 char *reg;
277 int ret; 276 int ret;
278 int i; 277 int i;
@@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events,
283 sys_name = NULL; 282 sys_name = NULL;
284 } 283 }
285 284
286 reg = malloc_or_die(strlen(event_name) + 3); 285 reg = malloc(strlen(event_name) + 3);
286 if (reg == NULL)
287 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
288
287 sprintf(reg, "^%s$", event_name); 289 sprintf(reg, "^%s$", event_name);
288 290
289 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); 291 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
290 free(reg); 292 free(reg);
291 293
292 if (ret) 294 if (ret)
293 return -1; 295 return PEVENT_ERRNO__INVALID_EVENT_NAME;
294 296
295 if (sys_name) { 297 if (sys_name) {
296 reg = malloc_or_die(strlen(sys_name) + 3); 298 reg = malloc(strlen(sys_name) + 3);
299 if (reg == NULL) {
300 regfree(&ereg);
301 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
302 }
303
297 sprintf(reg, "^%s$", sys_name); 304 sprintf(reg, "^%s$", sys_name);
298 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); 305 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
299 free(reg); 306 free(reg);
300 if (ret) { 307 if (ret) {
301 regfree(&ereg); 308 regfree(&ereg);
302 return -1; 309 return PEVENT_ERRNO__INVALID_EVENT_NAME;
303 } 310 }
304 } 311 }
305 312
@@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events,
307 event = pevent->events[i]; 314 event = pevent->events[i];
308 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { 315 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
309 match = 1; 316 match = 1;
310 add_event(events, event); 317 if (add_event(events, event) < 0) {
318 fail = 1;
319 break;
320 }
311 } 321 }
312 } 322 }
313 323
@@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events,
316 regfree(&sreg); 326 regfree(&sreg);
317 327
318 if (!match) 328 if (!match)
319 return -1; 329 return PEVENT_ERRNO__EVENT_NOT_FOUND;
330 if (fail)
331 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
320 332
321 return 0; 333 return 0;
322} 334}
@@ -332,14 +344,18 @@ static void free_events(struct event_list *events)
332 } 344 }
333} 345}
334 346
335static struct filter_arg * 347static enum pevent_errno
336create_arg_item(struct event_format *event, const char *token, 348create_arg_item(struct event_format *event, const char *token,
337 enum event_type type, char **error_str) 349 enum event_type type, struct filter_arg **parg, char *error_str)
338{ 350{
339 struct format_field *field; 351 struct format_field *field;
340 struct filter_arg *arg; 352 struct filter_arg *arg;
341 353
342 arg = allocate_arg(); 354 arg = allocate_arg();
355 if (arg == NULL) {
356 show_error(error_str, "failed to allocate filter arg");
357 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
358 }
343 359
344 switch (type) { 360 switch (type) {
345 361
@@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token,
349 arg->value.type = 365 arg->value.type =
350 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; 366 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
351 arg->value.str = strdup(token); 367 arg->value.str = strdup(token);
352 if (!arg->value.str) 368 if (!arg->value.str) {
353 die("malloc string"); 369 free_arg(arg);
370 show_error(error_str, "failed to allocate string filter arg");
371 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
372 }
354 break; 373 break;
355 case EVENT_ITEM: 374 case EVENT_ITEM:
356 /* if it is a number, then convert it */ 375 /* if it is a number, then convert it */
@@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token,
377 break; 396 break;
378 default: 397 default:
379 free_arg(arg); 398 free_arg(arg);
380 show_error(error_str, "expected a value but found %s", 399 show_error(error_str, "expected a value but found %s", token);
381 token); 400 return PEVENT_ERRNO__UNEXPECTED_TYPE;
382 return NULL;
383 } 401 }
384 return arg; 402 *parg = arg;
403 return 0;
385} 404}
386 405
387static struct filter_arg * 406static struct filter_arg *
@@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype)
390 struct filter_arg *arg; 409 struct filter_arg *arg;
391 410
392 arg = allocate_arg(); 411 arg = allocate_arg();
412 if (!arg)
413 return NULL;
414
393 arg->type = FILTER_ARG_OP; 415 arg->type = FILTER_ARG_OP;
394 arg->op.type = btype; 416 arg->op.type = btype;
395 417
@@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype)
402 struct filter_arg *arg; 424 struct filter_arg *arg;
403 425
404 arg = allocate_arg(); 426 arg = allocate_arg();
427 if (!arg)
428 return NULL;
429
405 arg->type = FILTER_ARG_EXP; 430 arg->type = FILTER_ARG_EXP;
406 arg->op.type = etype; 431 arg->op.type = etype;
407 432
@@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype)
414 struct filter_arg *arg; 439 struct filter_arg *arg;
415 440
416 arg = allocate_arg(); 441 arg = allocate_arg();
442 if (!arg)
443 return NULL;
444
417 /* Use NUM and change if necessary */ 445 /* Use NUM and change if necessary */
418 arg->type = FILTER_ARG_NUM; 446 arg->type = FILTER_ARG_NUM;
419 arg->op.type = etype; 447 arg->op.type = etype;
@@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype)
421 return arg; 449 return arg;
422} 450}
423 451
424static int add_right(struct filter_arg *op, struct filter_arg *arg, 452static enum pevent_errno
425 char **error_str) 453add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
426{ 454{
427 struct filter_arg *left; 455 struct filter_arg *left;
428 char *str; 456 char *str;
@@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
453 case FILTER_ARG_FIELD: 481 case FILTER_ARG_FIELD:
454 break; 482 break;
455 default: 483 default:
456 show_error(error_str, 484 show_error(error_str, "Illegal rvalue");
457 "Illegal rvalue"); 485 return PEVENT_ERRNO__ILLEGAL_RVALUE;
458 return -1;
459 } 486 }
460 487
461 /* 488 /*
@@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
502 if (left->type != FILTER_ARG_FIELD) { 529 if (left->type != FILTER_ARG_FIELD) {
503 show_error(error_str, 530 show_error(error_str,
504 "Illegal lvalue for string comparison"); 531 "Illegal lvalue for string comparison");
505 return -1; 532 return PEVENT_ERRNO__ILLEGAL_LVALUE;
506 } 533 }
507 534
508 /* Make sure this is a valid string compare */ 535 /* Make sure this is a valid string compare */
@@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
521 show_error(error_str, 548 show_error(error_str,
522 "RegEx '%s' did not compute", 549 "RegEx '%s' did not compute",
523 str); 550 str);
524 return -1; 551 return PEVENT_ERRNO__INVALID_REGEX;
525 } 552 }
526 break; 553 break;
527 default: 554 default:
528 show_error(error_str, 555 show_error(error_str,
529 "Illegal comparison for string"); 556 "Illegal comparison for string");
530 return -1; 557 return PEVENT_ERRNO__ILLEGAL_STRING_CMP;
531 } 558 }
532 559
533 op->type = FILTER_ARG_STR; 560 op->type = FILTER_ARG_STR;
534 op->str.type = op_type; 561 op->str.type = op_type;
535 op->str.field = left->field.field; 562 op->str.field = left->field.field;
536 op->str.val = strdup(str); 563 op->str.val = strdup(str);
537 if (!op->str.val) 564 if (!op->str.val) {
538 die("malloc string"); 565 show_error(error_str, "Failed to allocate string filter");
566 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
567 }
539 /* 568 /*
540 * Need a buffer to copy data for tests 569 * Need a buffer to copy data for tests
541 */ 570 */
542 op->str.buffer = malloc_or_die(op->str.field->size + 1); 571 op->str.buffer = malloc(op->str.field->size + 1);
572 if (!op->str.buffer) {
573 show_error(error_str, "Failed to allocate string filter");
574 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
575 }
543 /* Null terminate this buffer */ 576 /* Null terminate this buffer */
544 op->str.buffer[op->str.field->size] = 0; 577 op->str.buffer[op->str.field->size] = 0;
545 578
@@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
557 case FILTER_CMP_NOT_REGEX: 590 case FILTER_CMP_NOT_REGEX:
558 show_error(error_str, 591 show_error(error_str,
559 "Op not allowed with integers"); 592 "Op not allowed with integers");
560 return -1; 593 return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
561 594
562 default: 595 default:
563 break; 596 break;
@@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
577 return 0; 610 return 0;
578 611
579 out_fail: 612 out_fail:
580 show_error(error_str, 613 show_error(error_str, "Syntax error");
581 "Syntax error"); 614 return PEVENT_ERRNO__SYNTAX_ERROR;
582 return -1;
583} 615}
584 616
585static struct filter_arg * 617static struct filter_arg *
@@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b)
592 return arg; 624 return arg;
593} 625}
594 626
595static int add_left(struct filter_arg *op, struct filter_arg *arg) 627static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
596{ 628{
597 switch (op->type) { 629 switch (op->type) {
598 case FILTER_ARG_EXP: 630 case FILTER_ARG_EXP:
@@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg)
611 /* left arg of compares must be a field */ 643 /* left arg of compares must be a field */
612 if (arg->type != FILTER_ARG_FIELD && 644 if (arg->type != FILTER_ARG_FIELD &&
613 arg->type != FILTER_ARG_BOOLEAN) 645 arg->type != FILTER_ARG_BOOLEAN)
614 return -1; 646 return PEVENT_ERRNO__INVALID_ARG_TYPE;
615 op->num.left = arg; 647 op->num.left = arg;
616 break; 648 break;
617 default: 649 default:
618 return -1; 650 return PEVENT_ERRNO__INVALID_ARG_TYPE;
619 } 651 }
620 return 0; 652 return 0;
621} 653}
@@ -728,15 +760,18 @@ enum filter_vals {
728 FILTER_VAL_TRUE, 760 FILTER_VAL_TRUE,
729}; 761};
730 762
731void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, 763static enum pevent_errno
732 struct filter_arg *arg) 764reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
765 struct filter_arg *arg, char *error_str)
733{ 766{
734 struct filter_arg *other_child; 767 struct filter_arg *other_child;
735 struct filter_arg **ptr; 768 struct filter_arg **ptr;
736 769
737 if (parent->type != FILTER_ARG_OP && 770 if (parent->type != FILTER_ARG_OP &&
738 arg->type != FILTER_ARG_OP) 771 arg->type != FILTER_ARG_OP) {
739 die("can not reparent other than OP"); 772 show_error(error_str, "can not reparent other than OP");
773 return PEVENT_ERRNO__REPARENT_NOT_OP;
774 }
740 775
741 /* Get the sibling */ 776 /* Get the sibling */
742 if (old_child->op.right == arg) { 777 if (old_child->op.right == arg) {
@@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
745 } else if (old_child->op.left == arg) { 780 } else if (old_child->op.left == arg) {
746 ptr = &old_child->op.left; 781 ptr = &old_child->op.left;
747 other_child = old_child->op.right; 782 other_child = old_child->op.right;
748 } else 783 } else {
749 die("Error in reparent op, find other child"); 784 show_error(error_str, "Error in reparent op, find other child");
785 return PEVENT_ERRNO__REPARENT_FAILED;
786 }
750 787
751 /* Detach arg from old_child */ 788 /* Detach arg from old_child */
752 *ptr = NULL; 789 *ptr = NULL;
@@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
757 *parent = *arg; 794 *parent = *arg;
758 /* Free arg without recussion */ 795 /* Free arg without recussion */
759 free(arg); 796 free(arg);
760 return; 797 return 0;
761 } 798 }
762 799
763 if (parent->op.right == old_child) 800 if (parent->op.right == old_child)
764 ptr = &parent->op.right; 801 ptr = &parent->op.right;
765 else if (parent->op.left == old_child) 802 else if (parent->op.left == old_child)
766 ptr = &parent->op.left; 803 ptr = &parent->op.left;
767 else 804 else {
768 die("Error in reparent op"); 805 show_error(error_str, "Error in reparent op");
806 return PEVENT_ERRNO__REPARENT_FAILED;
807 }
808
769 *ptr = arg; 809 *ptr = arg;
770 810
771 free_arg(old_child); 811 free_arg(old_child);
812 return 0;
772} 813}
773 814
774enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) 815/* Returns either filter_vals (success) or pevent_errno (failfure) */
816static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
817 char *error_str)
775{ 818{
776 enum filter_vals lval, rval; 819 int lval, rval;
777 820
778 switch (arg->type) { 821 switch (arg->type) {
779 822
@@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
788 return FILTER_VAL_NORM; 831 return FILTER_VAL_NORM;
789 832
790 case FILTER_ARG_EXP: 833 case FILTER_ARG_EXP:
791 lval = test_arg(arg, arg->exp.left); 834 lval = test_arg(arg, arg->exp.left, error_str);
792 if (lval != FILTER_VAL_NORM) 835 if (lval != FILTER_VAL_NORM)
793 return lval; 836 return lval;
794 rval = test_arg(arg, arg->exp.right); 837 rval = test_arg(arg, arg->exp.right, error_str);
795 if (rval != FILTER_VAL_NORM) 838 if (rval != FILTER_VAL_NORM)
796 return rval; 839 return rval;
797 return FILTER_VAL_NORM; 840 return FILTER_VAL_NORM;
798 841
799 case FILTER_ARG_NUM: 842 case FILTER_ARG_NUM:
800 lval = test_arg(arg, arg->num.left); 843 lval = test_arg(arg, arg->num.left, error_str);
801 if (lval != FILTER_VAL_NORM) 844 if (lval != FILTER_VAL_NORM)
802 return lval; 845 return lval;
803 rval = test_arg(arg, arg->num.right); 846 rval = test_arg(arg, arg->num.right, error_str);
804 if (rval != FILTER_VAL_NORM) 847 if (rval != FILTER_VAL_NORM)
805 return rval; 848 return rval;
806 return FILTER_VAL_NORM; 849 return FILTER_VAL_NORM;
807 850
808 case FILTER_ARG_OP: 851 case FILTER_ARG_OP:
809 if (arg->op.type != FILTER_OP_NOT) { 852 if (arg->op.type != FILTER_OP_NOT) {
810 lval = test_arg(arg, arg->op.left); 853 lval = test_arg(arg, arg->op.left, error_str);
811 switch (lval) { 854 switch (lval) {
812 case FILTER_VAL_NORM: 855 case FILTER_VAL_NORM:
813 break; 856 break;
814 case FILTER_VAL_TRUE: 857 case FILTER_VAL_TRUE:
815 if (arg->op.type == FILTER_OP_OR) 858 if (arg->op.type == FILTER_OP_OR)
816 return FILTER_VAL_TRUE; 859 return FILTER_VAL_TRUE;
817 rval = test_arg(arg, arg->op.right); 860 rval = test_arg(arg, arg->op.right, error_str);
818 if (rval != FILTER_VAL_NORM) 861 if (rval != FILTER_VAL_NORM)
819 return rval; 862 return rval;
820 863
821 reparent_op_arg(parent, arg, arg->op.right); 864 return reparent_op_arg(parent, arg, arg->op.right,
822 return FILTER_VAL_NORM; 865 error_str);
823 866
824 case FILTER_VAL_FALSE: 867 case FILTER_VAL_FALSE:
825 if (arg->op.type == FILTER_OP_AND) 868 if (arg->op.type == FILTER_OP_AND)
826 return FILTER_VAL_FALSE; 869 return FILTER_VAL_FALSE;
827 rval = test_arg(arg, arg->op.right); 870 rval = test_arg(arg, arg->op.right, error_str);
828 if (rval != FILTER_VAL_NORM) 871 if (rval != FILTER_VAL_NORM)
829 return rval; 872 return rval;
830 873
831 reparent_op_arg(parent, arg, arg->op.right); 874 return reparent_op_arg(parent, arg, arg->op.right,
832 return FILTER_VAL_NORM; 875 error_str);
876
877 default:
878 return lval;
833 } 879 }
834 } 880 }
835 881
836 rval = test_arg(arg, arg->op.right); 882 rval = test_arg(arg, arg->op.right, error_str);
837 switch (rval) { 883 switch (rval) {
838 case FILTER_VAL_NORM: 884 case FILTER_VAL_NORM:
885 default:
839 break; 886 break;
887
840 case FILTER_VAL_TRUE: 888 case FILTER_VAL_TRUE:
841 if (arg->op.type == FILTER_OP_OR) 889 if (arg->op.type == FILTER_OP_OR)
842 return FILTER_VAL_TRUE; 890 return FILTER_VAL_TRUE;
843 if (arg->op.type == FILTER_OP_NOT) 891 if (arg->op.type == FILTER_OP_NOT)
844 return FILTER_VAL_FALSE; 892 return FILTER_VAL_FALSE;
845 893
846 reparent_op_arg(parent, arg, arg->op.left); 894 return reparent_op_arg(parent, arg, arg->op.left,
847 return FILTER_VAL_NORM; 895 error_str);
848 896
849 case FILTER_VAL_FALSE: 897 case FILTER_VAL_FALSE:
850 if (arg->op.type == FILTER_OP_AND) 898 if (arg->op.type == FILTER_OP_AND)
@@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
852 if (arg->op.type == FILTER_OP_NOT) 900 if (arg->op.type == FILTER_OP_NOT)
853 return FILTER_VAL_TRUE; 901 return FILTER_VAL_TRUE;
854 902
855 reparent_op_arg(parent, arg, arg->op.left); 903 return reparent_op_arg(parent, arg, arg->op.left,
856 return FILTER_VAL_NORM; 904 error_str);
857 } 905 }
858 906
859 return FILTER_VAL_NORM; 907 return rval;
860 default: 908 default:
861 die("bad arg in filter tree"); 909 show_error(error_str, "bad arg in filter tree");
910 return PEVENT_ERRNO__BAD_FILTER_ARG;
862 } 911 }
863 return FILTER_VAL_NORM; 912 return FILTER_VAL_NORM;
864} 913}
865 914
866/* Remove any unknown event fields */ 915/* Remove any unknown event fields */
867static struct filter_arg *collapse_tree(struct filter_arg *arg) 916static int collapse_tree(struct filter_arg *arg,
917 struct filter_arg **arg_collapsed, char *error_str)
868{ 918{
869 enum filter_vals ret; 919 int ret;
870 920
871 ret = test_arg(arg, arg); 921 ret = test_arg(arg, arg, error_str);
872 switch (ret) { 922 switch (ret) {
873 case FILTER_VAL_NORM: 923 case FILTER_VAL_NORM:
874 return arg; 924 break;
875 925
876 case FILTER_VAL_TRUE: 926 case FILTER_VAL_TRUE:
877 case FILTER_VAL_FALSE: 927 case FILTER_VAL_FALSE:
878 free_arg(arg); 928 free_arg(arg);
879 arg = allocate_arg(); 929 arg = allocate_arg();
880 arg->type = FILTER_ARG_BOOLEAN; 930 if (arg) {
881 arg->boolean.value = ret == FILTER_VAL_TRUE; 931 arg->type = FILTER_ARG_BOOLEAN;
932 arg->boolean.value = ret == FILTER_VAL_TRUE;
933 } else {
934 show_error(error_str, "Failed to allocate filter arg");
935 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
936 }
937 break;
938
939 default:
940 /* test_arg() already set the error_str */
941 free_arg(arg);
942 arg = NULL;
943 break;
882 } 944 }
883 945
884 return arg; 946 *arg_collapsed = arg;
947 return ret;
885} 948}
886 949
887static int 950static enum pevent_errno
888process_filter(struct event_format *event, struct filter_arg **parg, 951process_filter(struct event_format *event, struct filter_arg **parg,
889 char **error_str, int not) 952 char *error_str, int not)
890{ 953{
891 enum event_type type; 954 enum event_type type;
892 char *token = NULL; 955 char *token = NULL;
@@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
898 enum filter_op_type btype; 961 enum filter_op_type btype;
899 enum filter_exp_type etype; 962 enum filter_exp_type etype;
900 enum filter_cmp_type ctype; 963 enum filter_cmp_type ctype;
901 int ret; 964 enum pevent_errno ret;
902 965
903 *parg = NULL; 966 *parg = NULL;
904 967
@@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
909 case EVENT_SQUOTE: 972 case EVENT_SQUOTE:
910 case EVENT_DQUOTE: 973 case EVENT_DQUOTE:
911 case EVENT_ITEM: 974 case EVENT_ITEM:
912 arg = create_arg_item(event, token, type, error_str); 975 ret = create_arg_item(event, token, type, &arg, error_str);
913 if (!arg) 976 if (ret < 0)
914 goto fail; 977 goto fail;
915 if (!left_item) 978 if (!left_item)
916 left_item = arg; 979 left_item = arg;
@@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg,
923 if (not) { 986 if (not) {
924 arg = NULL; 987 arg = NULL;
925 if (current_op) 988 if (current_op)
926 goto fail_print; 989 goto fail_syntax;
927 free(token); 990 free(token);
928 *parg = current_exp; 991 *parg = current_exp;
929 return 0; 992 return 0;
930 } 993 }
931 } else 994 } else
932 goto fail_print; 995 goto fail_syntax;
933 arg = NULL; 996 arg = NULL;
934 break; 997 break;
935 998
936 case EVENT_DELIM: 999 case EVENT_DELIM:
937 if (*token == ',') { 1000 if (*token == ',') {
938 show_error(error_str, 1001 show_error(error_str, "Illegal token ','");
939 "Illegal token ','"); 1002 ret = PEVENT_ERRNO__ILLEGAL_TOKEN;
940 goto fail; 1003 goto fail;
941 } 1004 }
942 1005
@@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg,
944 if (left_item) { 1007 if (left_item) {
945 show_error(error_str, 1008 show_error(error_str,
946 "Open paren can not come after item"); 1009 "Open paren can not come after item");
1010 ret = PEVENT_ERRNO__INVALID_PAREN;
947 goto fail; 1011 goto fail;
948 } 1012 }
949 if (current_exp) { 1013 if (current_exp) {
950 show_error(error_str, 1014 show_error(error_str,
951 "Open paren can not come after expression"); 1015 "Open paren can not come after expression");
1016 ret = PEVENT_ERRNO__INVALID_PAREN;
952 goto fail; 1017 goto fail;
953 } 1018 }
954 1019
955 ret = process_filter(event, &arg, error_str, 0); 1020 ret = process_filter(event, &arg, error_str, 0);
956 if (ret != 1) { 1021 if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) {
957 if (ret == 0) 1022 if (ret == 0) {
958 show_error(error_str, 1023 show_error(error_str,
959 "Unbalanced number of '('"); 1024 "Unbalanced number of '('");
1025 ret = PEVENT_ERRNO__UNBALANCED_PAREN;
1026 }
960 goto fail; 1027 goto fail;
961 } 1028 }
962 ret = 0; 1029 ret = 0;
@@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
964 /* A not wants just one expression */ 1031 /* A not wants just one expression */
965 if (not) { 1032 if (not) {
966 if (current_op) 1033 if (current_op)
967 goto fail_print; 1034 goto fail_syntax;
968 *parg = arg; 1035 *parg = arg;
969 return 0; 1036 return 0;
970 } 1037 }
@@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg,
979 1046
980 } else { /* ')' */ 1047 } else { /* ')' */
981 if (!current_op && !current_exp) 1048 if (!current_op && !current_exp)
982 goto fail_print; 1049 goto fail_syntax;
983 1050
984 /* Make sure everything is finished at this level */ 1051 /* Make sure everything is finished at this level */
985 if (current_exp && !check_op_done(current_exp)) 1052 if (current_exp && !check_op_done(current_exp))
986 goto fail_print; 1053 goto fail_syntax;
987 if (current_op && !check_op_done(current_op)) 1054 if (current_op && !check_op_done(current_op))
988 goto fail_print; 1055 goto fail_syntax;
989 1056
990 if (current_op) 1057 if (current_op)
991 *parg = current_op; 1058 *parg = current_op;
992 else 1059 else
993 *parg = current_exp; 1060 *parg = current_exp;
994 return 1; 1061 return PEVENT_ERRNO__UNBALANCED_PAREN;
995 } 1062 }
996 break; 1063 break;
997 1064
@@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1003 case OP_BOOL: 1070 case OP_BOOL:
1004 /* Logic ops need a left expression */ 1071 /* Logic ops need a left expression */
1005 if (!current_exp && !current_op) 1072 if (!current_exp && !current_op)
1006 goto fail_print; 1073 goto fail_syntax;
1007 /* fall through */ 1074 /* fall through */
1008 case OP_NOT: 1075 case OP_NOT:
1009 /* logic only processes ops and exp */ 1076 /* logic only processes ops and exp */
1010 if (left_item) 1077 if (left_item)
1011 goto fail_print; 1078 goto fail_syntax;
1012 break; 1079 break;
1013 case OP_EXP: 1080 case OP_EXP:
1014 case OP_CMP: 1081 case OP_CMP:
1015 if (!left_item) 1082 if (!left_item)
1016 goto fail_print; 1083 goto fail_syntax;
1017 break; 1084 break;
1018 case OP_NONE: 1085 case OP_NONE:
1019 show_error(error_str, 1086 show_error(error_str,
1020 "Unknown op token %s", token); 1087 "Unknown op token %s", token);
1088 ret = PEVENT_ERRNO__UNKNOWN_TOKEN;
1021 goto fail; 1089 goto fail;
1022 } 1090 }
1023 1091
@@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1025 switch (op_type) { 1093 switch (op_type) {
1026 case OP_BOOL: 1094 case OP_BOOL:
1027 arg = create_arg_op(btype); 1095 arg = create_arg_op(btype);
1096 if (arg == NULL)
1097 goto fail_alloc;
1028 if (current_op) 1098 if (current_op)
1029 ret = add_left(arg, current_op); 1099 ret = add_left(arg, current_op);
1030 else 1100 else
@@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1035 1105
1036 case OP_NOT: 1106 case OP_NOT:
1037 arg = create_arg_op(btype); 1107 arg = create_arg_op(btype);
1108 if (arg == NULL)
1109 goto fail_alloc;
1038 if (current_op) 1110 if (current_op)
1039 ret = add_right(current_op, arg, error_str); 1111 ret = add_right(current_op, arg, error_str);
1040 if (ret < 0) 1112 if (ret < 0)
@@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1054 arg = create_arg_exp(etype); 1126 arg = create_arg_exp(etype);
1055 else 1127 else
1056 arg = create_arg_cmp(ctype); 1128 arg = create_arg_cmp(ctype);
1129 if (arg == NULL)
1130 goto fail_alloc;
1057 1131
1058 if (current_op) 1132 if (current_op)
1059 ret = add_right(current_op, arg, error_str); 1133 ret = add_right(current_op, arg, error_str);
@@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1062 ret = add_left(arg, left_item); 1136 ret = add_left(arg, left_item);
1063 if (ret < 0) { 1137 if (ret < 0) {
1064 arg = NULL; 1138 arg = NULL;
1065 goto fail_print; 1139 goto fail_syntax;
1066 } 1140 }
1067 current_exp = arg; 1141 current_exp = arg;
1068 break; 1142 break;
@@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1071 } 1145 }
1072 arg = NULL; 1146 arg = NULL;
1073 if (ret < 0) 1147 if (ret < 0)
1074 goto fail_print; 1148 goto fail_syntax;
1075 break; 1149 break;
1076 case EVENT_NONE: 1150 case EVENT_NONE:
1077 break; 1151 break;
1152 case EVENT_ERROR:
1153 goto fail_alloc;
1078 default: 1154 default:
1079 goto fail_print; 1155 goto fail_syntax;
1080 } 1156 }
1081 } while (type != EVENT_NONE); 1157 } while (type != EVENT_NONE);
1082 1158
1083 if (!current_op && !current_exp) 1159 if (!current_op && !current_exp)
1084 goto fail_print; 1160 goto fail_syntax;
1085 1161
1086 if (!current_op) 1162 if (!current_op)
1087 current_op = current_exp; 1163 current_op = current_exp;
1088 1164
1089 current_op = collapse_tree(current_op); 1165 ret = collapse_tree(current_op, parg, error_str);
1166 if (ret < 0)
1167 goto fail;
1090 1168
1091 *parg = current_op; 1169 *parg = current_op;
1092 1170
1093 return 0; 1171 return 0;
1094 1172
1095 fail_print: 1173 fail_alloc:
1174 show_error(error_str, "failed to allocate filter arg");
1175 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
1176 goto fail;
1177 fail_syntax:
1096 show_error(error_str, "Syntax error"); 1178 show_error(error_str, "Syntax error");
1179 ret = PEVENT_ERRNO__SYNTAX_ERROR;
1097 fail: 1180 fail:
1098 free_arg(current_op); 1181 free_arg(current_op);
1099 free_arg(current_exp); 1182 free_arg(current_exp);
1100 free_arg(arg); 1183 free_arg(arg);
1101 free(token); 1184 free(token);
1102 return -1; 1185 return ret;
1103} 1186}
1104 1187
1105static int 1188static enum pevent_errno
1106process_event(struct event_format *event, const char *filter_str, 1189process_event(struct event_format *event, const char *filter_str,
1107 struct filter_arg **parg, char **error_str) 1190 struct filter_arg **parg, char *error_str)
1108{ 1191{
1109 int ret; 1192 int ret;
1110 1193
1111 pevent_buffer_init(filter_str, strlen(filter_str)); 1194 pevent_buffer_init(filter_str, strlen(filter_str));
1112 1195
1113 ret = process_filter(event, parg, error_str, 0); 1196 ret = process_filter(event, parg, error_str, 0);
1114 if (ret == 1) {
1115 show_error(error_str,
1116 "Unbalanced number of ')'");
1117 return -1;
1118 }
1119 if (ret < 0) 1197 if (ret < 0)
1120 return ret; 1198 return ret;
1121 1199
1122 /* If parg is NULL, then make it into FALSE */ 1200 /* If parg is NULL, then make it into FALSE */
1123 if (!*parg) { 1201 if (!*parg) {
1124 *parg = allocate_arg(); 1202 *parg = allocate_arg();
1203 if (*parg == NULL)
1204 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1205
1125 (*parg)->type = FILTER_ARG_BOOLEAN; 1206 (*parg)->type = FILTER_ARG_BOOLEAN;
1126 (*parg)->boolean.value = FILTER_FALSE; 1207 (*parg)->boolean.value = FILTER_FALSE;
1127 } 1208 }
@@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str,
1129 return 0; 1210 return 0;
1130} 1211}
1131 1212
1132static int filter_event(struct event_filter *filter, 1213static enum pevent_errno
1133 struct event_format *event, 1214filter_event(struct event_filter *filter, struct event_format *event,
1134 const char *filter_str, char **error_str) 1215 const char *filter_str, char *error_str)
1135{ 1216{
1136 struct filter_type *filter_type; 1217 struct filter_type *filter_type;
1137 struct filter_arg *arg; 1218 struct filter_arg *arg;
1138 int ret; 1219 enum pevent_errno ret;
1139 1220
1140 if (filter_str) { 1221 if (filter_str) {
1141 ret = process_event(event, filter_str, &arg, error_str); 1222 ret = process_event(event, filter_str, &arg, error_str);
@@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter,
1145 } else { 1226 } else {
1146 /* just add a TRUE arg */ 1227 /* just add a TRUE arg */
1147 arg = allocate_arg(); 1228 arg = allocate_arg();
1229 if (arg == NULL)
1230 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1231
1148 arg->type = FILTER_ARG_BOOLEAN; 1232 arg->type = FILTER_ARG_BOOLEAN;
1149 arg->boolean.value = FILTER_TRUE; 1233 arg->boolean.value = FILTER_TRUE;
1150 } 1234 }
1151 1235
1152 filter_type = add_filter_type(filter, event->id); 1236 filter_type = add_filter_type(filter, event->id);
1237 if (filter_type == NULL)
1238 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1239
1153 if (filter_type->filter) 1240 if (filter_type->filter)
1154 free_arg(filter_type->filter); 1241 free_arg(filter_type->filter);
1155 filter_type->filter = arg; 1242 filter_type->filter = arg;
@@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter,
1157 return 0; 1244 return 0;
1158} 1245}
1159 1246
1247static void filter_init_error_buf(struct event_filter *filter)
1248{
1249 /* clear buffer to reset show error */
1250 pevent_buffer_init("", 0);
1251 filter->error_buffer[0] = '\0';
1252}
1253
1160/** 1254/**
1161 * pevent_filter_add_filter_str - add a new filter 1255 * pevent_filter_add_filter_str - add a new filter
1162 * @filter: the event filter to add to 1256 * @filter: the event filter to add to
1163 * @filter_str: the filter string that contains the filter 1257 * @filter_str: the filter string that contains the filter
1164 * @error_str: string containing reason for failed filter
1165 *
1166 * Returns 0 if the filter was successfully added
1167 * -1 if there was an error.
1168 * 1258 *
1169 * On error, if @error_str points to a string pointer, 1259 * Returns 0 if the filter was successfully added or a
1170 * it is set to the reason that the filter failed. 1260 * negative error code. Use pevent_filter_strerror() to see
1171 * This string must be freed with "free". 1261 * actual error message in case of error.
1172 */ 1262 */
1173int pevent_filter_add_filter_str(struct event_filter *filter, 1263enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
1174 const char *filter_str, 1264 const char *filter_str)
1175 char **error_str)
1176{ 1265{
1177 struct pevent *pevent = filter->pevent; 1266 struct pevent *pevent = filter->pevent;
1178 struct event_list *event; 1267 struct event_list *event;
@@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1183 char *event_name = NULL; 1272 char *event_name = NULL;
1184 char *sys_name = NULL; 1273 char *sys_name = NULL;
1185 char *sp; 1274 char *sp;
1186 int rtn = 0; 1275 enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */
1187 int len; 1276 int len;
1188 int ret; 1277 int ret;
1189 1278
1190 /* clear buffer to reset show error */ 1279 filter_init_error_buf(filter);
1191 pevent_buffer_init("", 0);
1192
1193 if (error_str)
1194 *error_str = NULL;
1195 1280
1196 filter_start = strchr(filter_str, ':'); 1281 filter_start = strchr(filter_str, ':');
1197 if (filter_start) 1282 if (filter_start)
@@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1199 else 1284 else
1200 len = strlen(filter_str); 1285 len = strlen(filter_str);
1201 1286
1202
1203 do { 1287 do {
1204 next_event = strchr(filter_str, ','); 1288 next_event = strchr(filter_str, ',');
1205 if (next_event && 1289 if (next_event &&
@@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1210 else 1294 else
1211 len = strlen(filter_str); 1295 len = strlen(filter_str);
1212 1296
1213 this_event = malloc_or_die(len + 1); 1297 this_event = malloc(len + 1);
1298 if (this_event == NULL) {
1299 /* This can only happen when events is NULL, but still */
1300 free_events(events);
1301 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1302 }
1214 memcpy(this_event, filter_str, len); 1303 memcpy(this_event, filter_str, len);
1215 this_event[len] = 0; 1304 this_event[len] = 0;
1216 1305
@@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1223 event_name = strtok_r(NULL, "/", &sp); 1312 event_name = strtok_r(NULL, "/", &sp);
1224 1313
1225 if (!sys_name) { 1314 if (!sys_name) {
1226 show_error(error_str, "No filter found");
1227 /* This can only happen when events is NULL, but still */ 1315 /* This can only happen when events is NULL, but still */
1228 free_events(events); 1316 free_events(events);
1229 free(this_event); 1317 free(this_event);
1230 return -1; 1318 return PEVENT_ERRNO__FILTER_NOT_FOUND;
1231 } 1319 }
1232 1320
1233 /* Find this event */ 1321 /* Find this event */
1234 ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); 1322 ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
1235 if (ret < 0) { 1323 if (ret < 0) {
1236 if (event_name)
1237 show_error(error_str,
1238 "No event found under '%s.%s'",
1239 sys_name, event_name);
1240 else
1241 show_error(error_str,
1242 "No event found under '%s'",
1243 sys_name);
1244 free_events(events); 1324 free_events(events);
1245 free(this_event); 1325 free(this_event);
1246 return -1; 1326 return ret;
1247 } 1327 }
1248 free(this_event); 1328 free(this_event);
1249 } while (filter_str); 1329 } while (filter_str);
@@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1255 /* filter starts here */ 1335 /* filter starts here */
1256 for (event = events; event; event = event->next) { 1336 for (event = events; event; event = event->next) {
1257 ret = filter_event(filter, event->event, filter_start, 1337 ret = filter_event(filter, event->event, filter_start,
1258 error_str); 1338 filter->error_buffer);
1259 /* Failures are returned if a parse error happened */ 1339 /* Failures are returned if a parse error happened */
1260 if (ret < 0) 1340 if (ret < 0)
1261 rtn = ret; 1341 rtn = ret;
@@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1263 if (ret >= 0 && pevent->test_filters) { 1343 if (ret >= 0 && pevent->test_filters) {
1264 char *test; 1344 char *test;
1265 test = pevent_filter_make_string(filter, event->event->id); 1345 test = pevent_filter_make_string(filter, event->event->id);
1266 printf(" '%s: %s'\n", event->event->name, test); 1346 if (test) {
1267 free(test); 1347 printf(" '%s: %s'\n", event->event->name, test);
1348 free(test);
1349 }
1268 } 1350 }
1269 } 1351 }
1270 1352
@@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type)
1282} 1364}
1283 1365
1284/** 1366/**
1367 * pevent_filter_strerror - fill error message in a buffer
1368 * @filter: the event filter contains error
1369 * @err: the error code
1370 * @buf: the buffer to be filled in
1371 * @buflen: the size of the buffer
1372 *
1373 * Returns 0 if message was filled successfully, -1 if error
1374 */
1375int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
1376 char *buf, size_t buflen)
1377{
1378 if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END)
1379 return -1;
1380
1381 if (strlen(filter->error_buffer) > 0) {
1382 size_t len = snprintf(buf, buflen, "%s", filter->error_buffer);
1383
1384 if (len > buflen)
1385 return -1;
1386 return 0;
1387 }
1388
1389 return pevent_strerror(filter->pevent, err, buf, buflen);
1390}
1391
1392/**
1285 * pevent_filter_remove_event - remove a filter for an event 1393 * pevent_filter_remove_event - remove a filter for an event
1286 * @filter: the event filter to remove from 1394 * @filter: the event filter to remove from
1287 * @event_id: the event to remove a filter for 1395 * @event_id: the event to remove a filter for
@@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter,
1374 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { 1482 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
1375 /* Add trivial event */ 1483 /* Add trivial event */
1376 arg = allocate_arg(); 1484 arg = allocate_arg();
1485 if (arg == NULL)
1486 return -1;
1487
1377 arg->type = FILTER_ARG_BOOLEAN; 1488 arg->type = FILTER_ARG_BOOLEAN;
1378 if (strcmp(str, "TRUE") == 0) 1489 if (strcmp(str, "TRUE") == 0)
1379 arg->boolean.value = 1; 1490 arg->boolean.value = 1;
@@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter,
1381 arg->boolean.value = 0; 1492 arg->boolean.value = 0;
1382 1493
1383 filter_type = add_filter_type(filter, event->id); 1494 filter_type = add_filter_type(filter, event->id);
1495 if (filter_type == NULL)
1496 return -1;
1497
1384 filter_type->filter = arg; 1498 filter_type->filter = arg;
1385 1499
1386 free(str); 1500 free(str);
@@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
1482 * @type: remove only true, false, or both 1596 * @type: remove only true, false, or both
1483 * 1597 *
1484 * Removes filters that only contain a TRUE or FALES boolean arg. 1598 * Removes filters that only contain a TRUE or FALES boolean arg.
1599 *
1600 * Returns 0 on success and -1 if there was a problem.
1485 */ 1601 */
1486void pevent_filter_clear_trivial(struct event_filter *filter, 1602int pevent_filter_clear_trivial(struct event_filter *filter,
1487 enum filter_trivial_type type) 1603 enum filter_trivial_type type)
1488{ 1604{
1489 struct filter_type *filter_type; 1605 struct filter_type *filter_type;
@@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
1492 int i; 1608 int i;
1493 1609
1494 if (!filter->filters) 1610 if (!filter->filters)
1495 return; 1611 return 0;
1496 1612
1497 /* 1613 /*
1498 * Two steps, first get all ids with trivial filters. 1614 * Two steps, first get all ids with trivial filters.
1499 * then remove those ids. 1615 * then remove those ids.
1500 */ 1616 */
1501 for (i = 0; i < filter->filters; i++) { 1617 for (i = 0; i < filter->filters; i++) {
1618 int *new_ids;
1619
1502 filter_type = &filter->event_filters[i]; 1620 filter_type = &filter->event_filters[i];
1503 if (filter_type->filter->type != FILTER_ARG_BOOLEAN) 1621 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1504 continue; 1622 continue;
@@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
1513 break; 1631 break;
1514 } 1632 }
1515 1633
1516 ids = realloc(ids, sizeof(*ids) * (count + 1)); 1634 new_ids = realloc(ids, sizeof(*ids) * (count + 1));
1517 if (!ids) 1635 if (!new_ids) {
1518 die("Can't allocate ids"); 1636 free(ids);
1637 return -1;
1638 }
1639
1640 ids = new_ids;
1519 ids[count++] = filter_type->event_id; 1641 ids[count++] = filter_type->event_id;
1520 } 1642 }
1521 1643
1522 if (!count) 1644 if (!count)
1523 return; 1645 return 0;
1524 1646
1525 for (i = 0; i < count; i++) 1647 for (i = 0; i < count; i++)
1526 pevent_filter_remove_event(filter, ids[i]); 1648 pevent_filter_remove_event(filter, ids[i]);
1527 1649
1528 free(ids); 1650 free(ids);
1651 return 0;
1529} 1652}
1530 1653
1531/** 1654/**
@@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
1565 } 1688 }
1566} 1689}
1567 1690
1568static int test_filter(struct event_format *event, 1691static int test_filter(struct event_format *event, struct filter_arg *arg,
1569 struct filter_arg *arg, struct pevent_record *record); 1692 struct pevent_record *record, enum pevent_errno *err);
1570 1693
1571static const char * 1694static const char *
1572get_comm(struct event_format *event, struct pevent_record *record) 1695get_comm(struct event_format *event, struct pevent_record *record)
@@ -1612,15 +1735,24 @@ get_value(struct event_format *event,
1612} 1735}
1613 1736
1614static unsigned long long 1737static unsigned long long
1615get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); 1738get_arg_value(struct event_format *event, struct filter_arg *arg,
1739 struct pevent_record *record, enum pevent_errno *err);
1616 1740
1617static unsigned long long 1741static unsigned long long
1618get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1742get_exp_value(struct event_format *event, struct filter_arg *arg,
1743 struct pevent_record *record, enum pevent_errno *err)
1619{ 1744{
1620 unsigned long long lval, rval; 1745 unsigned long long lval, rval;
1621 1746
1622 lval = get_arg_value(event, arg->exp.left, record); 1747 lval = get_arg_value(event, arg->exp.left, record, err);
1623 rval = get_arg_value(event, arg->exp.right, record); 1748 rval = get_arg_value(event, arg->exp.right, record, err);
1749
1750 if (*err) {
1751 /*
1752 * There was an error, no need to process anymore.
1753 */
1754 return 0;
1755 }
1624 1756
1625 switch (arg->exp.type) { 1757 switch (arg->exp.type) {
1626 case FILTER_EXP_ADD: 1758 case FILTER_EXP_ADD:
@@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_
1655 1787
1656 case FILTER_EXP_NOT: 1788 case FILTER_EXP_NOT:
1657 default: 1789 default:
1658 die("error in exp"); 1790 if (!*err)
1791 *err = PEVENT_ERRNO__INVALID_EXP_TYPE;
1659 } 1792 }
1660 return 0; 1793 return 0;
1661} 1794}
1662 1795
1663static unsigned long long 1796static unsigned long long
1664get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1797get_arg_value(struct event_format *event, struct filter_arg *arg,
1798 struct pevent_record *record, enum pevent_errno *err)
1665{ 1799{
1666 switch (arg->type) { 1800 switch (arg->type) {
1667 case FILTER_ARG_FIELD: 1801 case FILTER_ARG_FIELD:
1668 return get_value(event, arg->field.field, record); 1802 return get_value(event, arg->field.field, record);
1669 1803
1670 case FILTER_ARG_VALUE: 1804 case FILTER_ARG_VALUE:
1671 if (arg->value.type != FILTER_NUMBER) 1805 if (arg->value.type != FILTER_NUMBER) {
1672 die("must have number field!"); 1806 if (!*err)
1807 *err = PEVENT_ERRNO__NOT_A_NUMBER;
1808 }
1673 return arg->value.val; 1809 return arg->value.val;
1674 1810
1675 case FILTER_ARG_EXP: 1811 case FILTER_ARG_EXP:
1676 return get_exp_value(event, arg, record); 1812 return get_exp_value(event, arg, record, err);
1677 1813
1678 default: 1814 default:
1679 die("oops in filter"); 1815 if (!*err)
1816 *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
1680 } 1817 }
1681 return 0; 1818 return 0;
1682} 1819}
1683 1820
1684static int test_num(struct event_format *event, 1821static int test_num(struct event_format *event, struct filter_arg *arg,
1685 struct filter_arg *arg, struct pevent_record *record) 1822 struct pevent_record *record, enum pevent_errno *err)
1686{ 1823{
1687 unsigned long long lval, rval; 1824 unsigned long long lval, rval;
1688 1825
1689 lval = get_arg_value(event, arg->num.left, record); 1826 lval = get_arg_value(event, arg->num.left, record, err);
1690 rval = get_arg_value(event, arg->num.right, record); 1827 rval = get_arg_value(event, arg->num.right, record, err);
1828
1829 if (*err) {
1830 /*
1831 * There was an error, no need to process anymore.
1832 */
1833 return 0;
1834 }
1691 1835
1692 switch (arg->num.type) { 1836 switch (arg->num.type) {
1693 case FILTER_CMP_EQ: 1837 case FILTER_CMP_EQ:
@@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event,
1709 return lval <= rval; 1853 return lval <= rval;
1710 1854
1711 default: 1855 default:
1712 /* ?? */ 1856 if (!*err)
1857 *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
1713 return 0; 1858 return 0;
1714 } 1859 }
1715} 1860}
@@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
1756 return val; 1901 return val;
1757} 1902}
1758 1903
1759static int test_str(struct event_format *event, 1904static int test_str(struct event_format *event, struct filter_arg *arg,
1760 struct filter_arg *arg, struct pevent_record *record) 1905 struct pevent_record *record, enum pevent_errno *err)
1761{ 1906{
1762 const char *val; 1907 const char *val;
1763 1908
@@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event,
1781 return regexec(&arg->str.reg, val, 0, NULL, 0); 1926 return regexec(&arg->str.reg, val, 0, NULL, 0);
1782 1927
1783 default: 1928 default:
1784 /* ?? */ 1929 if (!*err)
1930 *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP;
1785 return 0; 1931 return 0;
1786 } 1932 }
1787} 1933}
1788 1934
1789static int test_op(struct event_format *event, 1935static int test_op(struct event_format *event, struct filter_arg *arg,
1790 struct filter_arg *arg, struct pevent_record *record) 1936 struct pevent_record *record, enum pevent_errno *err)
1791{ 1937{
1792 switch (arg->op.type) { 1938 switch (arg->op.type) {
1793 case FILTER_OP_AND: 1939 case FILTER_OP_AND:
1794 return test_filter(event, arg->op.left, record) && 1940 return test_filter(event, arg->op.left, record, err) &&
1795 test_filter(event, arg->op.right, record); 1941 test_filter(event, arg->op.right, record, err);
1796 1942
1797 case FILTER_OP_OR: 1943 case FILTER_OP_OR:
1798 return test_filter(event, arg->op.left, record) || 1944 return test_filter(event, arg->op.left, record, err) ||
1799 test_filter(event, arg->op.right, record); 1945 test_filter(event, arg->op.right, record, err);
1800 1946
1801 case FILTER_OP_NOT: 1947 case FILTER_OP_NOT:
1802 return !test_filter(event, arg->op.right, record); 1948 return !test_filter(event, arg->op.right, record, err);
1803 1949
1804 default: 1950 default:
1805 /* ?? */ 1951 if (!*err)
1952 *err = PEVENT_ERRNO__INVALID_OP_TYPE;
1806 return 0; 1953 return 0;
1807 } 1954 }
1808} 1955}
1809 1956
1810static int test_filter(struct event_format *event, 1957static int test_filter(struct event_format *event, struct filter_arg *arg,
1811 struct filter_arg *arg, struct pevent_record *record) 1958 struct pevent_record *record, enum pevent_errno *err)
1812{ 1959{
1960 if (*err) {
1961 /*
1962 * There was an error, no need to process anymore.
1963 */
1964 return 0;
1965 }
1966
1813 switch (arg->type) { 1967 switch (arg->type) {
1814 case FILTER_ARG_BOOLEAN: 1968 case FILTER_ARG_BOOLEAN:
1815 /* easy case */ 1969 /* easy case */
1816 return arg->boolean.value; 1970 return arg->boolean.value;
1817 1971
1818 case FILTER_ARG_OP: 1972 case FILTER_ARG_OP:
1819 return test_op(event, arg, record); 1973 return test_op(event, arg, record, err);
1820 1974
1821 case FILTER_ARG_NUM: 1975 case FILTER_ARG_NUM:
1822 return test_num(event, arg, record); 1976 return test_num(event, arg, record, err);
1823 1977
1824 case FILTER_ARG_STR: 1978 case FILTER_ARG_STR:
1825 return test_str(event, arg, record); 1979 return test_str(event, arg, record, err);
1826 1980
1827 case FILTER_ARG_EXP: 1981 case FILTER_ARG_EXP:
1828 case FILTER_ARG_VALUE: 1982 case FILTER_ARG_VALUE:
@@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event,
1831 * Expressions, fields and values evaluate 1985 * Expressions, fields and values evaluate
1832 * to true if they return non zero 1986 * to true if they return non zero
1833 */ 1987 */
1834 return !!get_arg_value(event, arg, record); 1988 return !!get_arg_value(event, arg, record, err);
1835 1989
1836 default: 1990 default:
1837 die("oops!"); 1991 if (!*err)
1838 /* ?? */ 1992 *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
1839 return 0; 1993 return 0;
1840 } 1994 }
1841} 1995}
@@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event,
1848 * Returns 1 if filter found for @event_id 2002 * Returns 1 if filter found for @event_id
1849 * otherwise 0; 2003 * otherwise 0;
1850 */ 2004 */
1851int pevent_event_filtered(struct event_filter *filter, 2005int pevent_event_filtered(struct event_filter *filter, int event_id)
1852 int event_id)
1853{ 2006{
1854 struct filter_type *filter_type; 2007 struct filter_type *filter_type;
1855 2008
@@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *filter,
1866 * @filter: filter struct with filter information 2019 * @filter: filter struct with filter information
1867 * @record: the record to test against the filter 2020 * @record: the record to test against the filter
1868 * 2021 *
1869 * Returns: 2022 * Returns: match result or error code (prefixed with PEVENT_ERRNO__)
1870 * 1 - filter found for event and @record matches 2023 * FILTER_MATCH - filter found for event and @record matches
1871 * 0 - filter found for event and @record does not match 2024 * FILTER_MISS - filter found for event and @record does not match
1872 * -1 - no filter found for @record's event 2025 * FILTER_NOT_FOUND - no filter found for @record's event
1873 * -2 - if no filters exist 2026 * NO_FILTER - if no filters exist
2027 * otherwise - error occurred during test
1874 */ 2028 */
1875int pevent_filter_match(struct event_filter *filter, 2029enum pevent_errno pevent_filter_match(struct event_filter *filter,
1876 struct pevent_record *record) 2030 struct pevent_record *record)
1877{ 2031{
1878 struct pevent *pevent = filter->pevent; 2032 struct pevent *pevent = filter->pevent;
1879 struct filter_type *filter_type; 2033 struct filter_type *filter_type;
1880 int event_id; 2034 int event_id;
2035 int ret;
2036 enum pevent_errno err = 0;
2037
2038 filter_init_error_buf(filter);
1881 2039
1882 if (!filter->filters) 2040 if (!filter->filters)
1883 return FILTER_NONE; 2041 return PEVENT_ERRNO__NO_FILTER;
1884 2042
1885 event_id = pevent_data_type(pevent, record); 2043 event_id = pevent_data_type(pevent, record);
1886 2044
1887 filter_type = find_filter_type(filter, event_id); 2045 filter_type = find_filter_type(filter, event_id);
1888
1889 if (!filter_type) 2046 if (!filter_type)
1890 return FILTER_NOEXIST; 2047 return PEVENT_ERRNO__FILTER_NOT_FOUND;
2048
2049 ret = test_filter(filter_type->event, filter_type->filter, record, &err);
2050 if (err)
2051 return err;
1891 2052
1892 return test_filter(filter_type->event, filter_type->filter, record) ? 2053 return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS;
1893 FILTER_MATCH : FILTER_MISS;
1894} 2054}
1895 2055
1896static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) 2056static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
@@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1902 int left_val = -1; 2062 int left_val = -1;
1903 int right_val = -1; 2063 int right_val = -1;
1904 int val; 2064 int val;
1905 int len;
1906 2065
1907 switch (arg->op.type) { 2066 switch (arg->op.type) {
1908 case FILTER_OP_AND: 2067 case FILTER_OP_AND:
@@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1949 default: 2108 default:
1950 break; 2109 break;
1951 } 2110 }
1952 str = malloc_or_die(6); 2111 asprintf(&str, val ? "TRUE" : "FALSE");
1953 if (val)
1954 strcpy(str, "TRUE");
1955 else
1956 strcpy(str, "FALSE");
1957 break; 2112 break;
1958 } 2113 }
1959 } 2114 }
@@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1971 break; 2126 break;
1972 } 2127 }
1973 2128
1974 len = strlen(left) + strlen(right) + strlen(op) + 10; 2129 asprintf(&str, "(%s) %s (%s)", left, op, right);
1975 str = malloc_or_die(len);
1976 snprintf(str, len, "(%s) %s (%s)",
1977 left, op, right);
1978 break; 2130 break;
1979 2131
1980 case FILTER_OP_NOT: 2132 case FILTER_OP_NOT:
@@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1990 right_val = 0; 2142 right_val = 0;
1991 if (right_val >= 0) { 2143 if (right_val >= 0) {
1992 /* just return the opposite */ 2144 /* just return the opposite */
1993 str = malloc_or_die(6); 2145 asprintf(&str, right_val ? "FALSE" : "TRUE");
1994 if (right_val)
1995 strcpy(str, "FALSE");
1996 else
1997 strcpy(str, "TRUE");
1998 break; 2146 break;
1999 } 2147 }
2000 len = strlen(right) + strlen(op) + 3; 2148 asprintf(&str, "%s(%s)", op, right);
2001 str = malloc_or_die(len);
2002 snprintf(str, len, "%s(%s)", op, right);
2003 break; 2149 break;
2004 2150
2005 default: 2151 default:
@@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
2013 2159
2014static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) 2160static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
2015{ 2161{
2016 char *str; 2162 char *str = NULL;
2017
2018 str = malloc_or_die(30);
2019 2163
2020 snprintf(str, 30, "%lld", arg->value.val); 2164 asprintf(&str, "%lld", arg->value.val);
2021 2165
2022 return str; 2166 return str;
2023} 2167}
@@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2033 char *rstr; 2177 char *rstr;
2034 char *op; 2178 char *op;
2035 char *str = NULL; 2179 char *str = NULL;
2036 int len;
2037 2180
2038 lstr = arg_to_str(filter, arg->exp.left); 2181 lstr = arg_to_str(filter, arg->exp.left);
2039 rstr = arg_to_str(filter, arg->exp.right); 2182 rstr = arg_to_str(filter, arg->exp.right);
@@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2072 op = "^"; 2215 op = "^";
2073 break; 2216 break;
2074 default: 2217 default:
2075 die("oops in exp"); 2218 op = "[ERROR IN EXPRESSION TYPE]";
2219 break;
2076 } 2220 }
2077 2221
2078 len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; 2222 asprintf(&str, "%s %s %s", lstr, op, rstr);
2079 str = malloc_or_die(len);
2080 snprintf(str, len, "%s %s %s", lstr, op, rstr);
2081out: 2223out:
2082 free(lstr); 2224 free(lstr);
2083 free(rstr); 2225 free(rstr);
@@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2091 char *rstr; 2233 char *rstr;
2092 char *str = NULL; 2234 char *str = NULL;
2093 char *op = NULL; 2235 char *op = NULL;
2094 int len;
2095 2236
2096 lstr = arg_to_str(filter, arg->num.left); 2237 lstr = arg_to_str(filter, arg->num.left);
2097 rstr = arg_to_str(filter, arg->num.right); 2238 rstr = arg_to_str(filter, arg->num.right);
@@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2122 if (!op) 2263 if (!op)
2123 op = "<="; 2264 op = "<=";
2124 2265
2125 len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; 2266 asprintf(&str, "%s %s %s", lstr, op, rstr);
2126 str = malloc_or_die(len);
2127 sprintf(str, "%s %s %s", lstr, op, rstr);
2128
2129 break; 2267 break;
2130 2268
2131 default: 2269 default:
@@ -2143,7 +2281,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2143{ 2281{
2144 char *str = NULL; 2282 char *str = NULL;
2145 char *op = NULL; 2283 char *op = NULL;
2146 int len;
2147 2284
2148 switch (arg->str.type) { 2285 switch (arg->str.type) {
2149 case FILTER_CMP_MATCH: 2286 case FILTER_CMP_MATCH:
@@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2161 if (!op) 2298 if (!op)
2162 op = "!~"; 2299 op = "!~";
2163 2300
2164 len = strlen(arg->str.field->name) + strlen(op) + 2301 asprintf(&str, "%s %s \"%s\"",
2165 strlen(arg->str.val) + 6; 2302 arg->str.field->name, op, arg->str.val);
2166 str = malloc_or_die(len);
2167 snprintf(str, len, "%s %s \"%s\"",
2168 arg->str.field->name,
2169 op, arg->str.val);
2170 break; 2303 break;
2171 2304
2172 default: 2305 default:
@@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2178 2311
2179static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) 2312static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2180{ 2313{
2181 char *str; 2314 char *str = NULL;
2182 2315
2183 switch (arg->type) { 2316 switch (arg->type) {
2184 case FILTER_ARG_BOOLEAN: 2317 case FILTER_ARG_BOOLEAN:
2185 str = malloc_or_die(6); 2318 asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE");
2186 if (arg->boolean.value)
2187 strcpy(str, "TRUE");
2188 else
2189 strcpy(str, "FALSE");
2190 return str; 2319 return str;
2191 2320
2192 case FILTER_ARG_OP: 2321 case FILTER_ARG_OP:
@@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2221 * 2350 *
2222 * Returns a string that displays the filter contents. 2351 * Returns a string that displays the filter contents.
2223 * This string must be freed with free(str). 2352 * This string must be freed with free(str).
2224 * NULL is returned if no filter is found. 2353 * NULL is returned if no filter is found or allocation failed.
2225 */ 2354 */
2226char * 2355char *
2227pevent_filter_make_string(struct event_filter *filter, int event_id) 2356pevent_filter_make_string(struct event_filter *filter, int event_id)
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c
new file mode 100644
index 000000000000..dcab8e873c21
--- /dev/null
+++ b/tools/lib/traceevent/plugin_cfg80211.c
@@ -0,0 +1,24 @@
1#include <stdio.h>
2#include <string.h>
3#include <inttypes.h>
4#include <endian.h>
5#include "event-parse.h"
6
7static unsigned long long
8process___le16_to_cpup(struct trace_seq *s,
9 unsigned long long *args)
10{
11 uint16_t *val = (uint16_t *) args[0];
12 return val ? (long long) le16toh(*val) : 0;
13}
14
15int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
16{
17 pevent_register_print_function(pevent,
18 process___le16_to_cpup,
19 PEVENT_FUNC_ARG_INT,
20 "__le16_to_cpup",
21 PEVENT_FUNC_ARG_PTR,
22 PEVENT_FUNC_ARG_VOID);
23 return 0;
24}
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
new file mode 100644
index 000000000000..aad92ad5e96f
--- /dev/null
+++ b/tools/lib/traceevent/plugin_function.c
@@ -0,0 +1,160 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25#include "event-utils.h"
26
27static struct func_stack {
28 int size;
29 char **stack;
30} *fstack;
31
32static int cpus = -1;
33
34#define STK_BLK 10
35
36static void add_child(struct func_stack *stack, const char *child, int pos)
37{
38 int i;
39
40 if (!child)
41 return;
42
43 if (pos < stack->size)
44 free(stack->stack[pos]);
45 else {
46 char **ptr;
47
48 ptr = realloc(stack->stack, sizeof(char *) *
49 (stack->size + STK_BLK));
50 if (!ptr) {
51 warning("could not allocate plugin memory\n");
52 return;
53 }
54
55 stack->stack = ptr;
56
57 for (i = stack->size; i < stack->size + STK_BLK; i++)
58 stack->stack[i] = NULL;
59 stack->size += STK_BLK;
60 }
61
62 stack->stack[pos] = strdup(child);
63}
64
65static int add_and_get_index(const char *parent, const char *child, int cpu)
66{
67 int i;
68
69 if (cpu < 0)
70 return 0;
71
72 if (cpu > cpus) {
73 struct func_stack *ptr;
74
75 ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
76 if (!ptr) {
77 warning("could not allocate plugin memory\n");
78 return 0;
79 }
80
81 fstack = ptr;
82
83 /* Account for holes in the cpu count */
84 for (i = cpus + 1; i <= cpu; i++)
85 memset(&fstack[i], 0, sizeof(fstack[i]));
86 cpus = cpu;
87 }
88
89 for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
90 if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
91 add_child(&fstack[cpu], child, i+1);
92 return i;
93 }
94 }
95
96 /* Not found */
97 add_child(&fstack[cpu], parent, 0);
98 add_child(&fstack[cpu], child, 1);
99 return 0;
100}
101
102static int function_handler(struct trace_seq *s, struct pevent_record *record,
103 struct event_format *event, void *context)
104{
105 struct pevent *pevent = event->pevent;
106 unsigned long long function;
107 unsigned long long pfunction;
108 const char *func;
109 const char *parent;
110 int index;
111
112 if (pevent_get_field_val(s, event, "ip", record, &function, 1))
113 return trace_seq_putc(s, '!');
114
115 func = pevent_find_function(pevent, function);
116
117 if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
118 return trace_seq_putc(s, '!');
119
120 parent = pevent_find_function(pevent, pfunction);
121
122 index = add_and_get_index(parent, func, record->cpu);
123
124 trace_seq_printf(s, "%*s", index*3, "");
125
126 if (func)
127 trace_seq_printf(s, "%s", func);
128 else
129 trace_seq_printf(s, "0x%llx", function);
130
131 trace_seq_printf(s, " <-- ");
132 if (parent)
133 trace_seq_printf(s, "%s", parent);
134 else
135 trace_seq_printf(s, "0x%llx", pfunction);
136
137 return 0;
138}
139
140int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
141{
142 pevent_register_event_handler(pevent, -1, "ftrace", "function",
143 function_handler, NULL);
144 return 0;
145}
146
147void PEVENT_PLUGIN_UNLOADER(void)
148{
149 int i, x;
150
151 for (i = 0; i <= cpus; i++) {
152 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
153 free(fstack[i].stack[x]);
154 free(fstack[i].stack);
155 }
156
157 free(fstack);
158 fstack = NULL;
159 cpus = -1;
160}
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c
new file mode 100644
index 000000000000..0b0ebf30aa44
--- /dev/null
+++ b/tools/lib/traceevent/plugin_hrtimer.c
@@ -0,0 +1,78 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
4 *
5 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License (not later!)
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses>
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "event-parse.h"
26
27static int timer_expire_handler(struct trace_seq *s,
28 struct pevent_record *record,
29 struct event_format *event, void *context)
30{
31 trace_seq_printf(s, "hrtimer=");
32
33 if (pevent_print_num_field(s, "0x%llx", event, "timer",
34 record, 0) == -1)
35 pevent_print_num_field(s, "0x%llx", event, "hrtimer",
36 record, 1);
37
38 trace_seq_printf(s, " now=");
39
40 pevent_print_num_field(s, "%llu", event, "now", record, 1);
41
42 pevent_print_func_field(s, " function=%s", event, "function",
43 record, 0);
44 return 0;
45}
46
47static int timer_start_handler(struct trace_seq *s,
48 struct pevent_record *record,
49 struct event_format *event, void *context)
50{
51 trace_seq_printf(s, "hrtimer=");
52
53 if (pevent_print_num_field(s, "0x%llx", event, "timer",
54 record, 0) == -1)
55 pevent_print_num_field(s, "0x%llx", event, "hrtimer",
56 record, 1);
57
58 pevent_print_func_field(s, " function=%s", event, "function",
59 record, 0);
60
61 trace_seq_printf(s, " expires=");
62 pevent_print_num_field(s, "%llu", event, "expires", record, 1);
63
64 trace_seq_printf(s, " softexpires=");
65 pevent_print_num_field(s, "%llu", event, "softexpires", record, 1);
66 return 0;
67}
68
69int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
70{
71 pevent_register_event_handler(pevent, -1,
72 "timer", "hrtimer_expire_entry",
73 timer_expire_handler, NULL);
74
75 pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start",
76 timer_start_handler, NULL);
77 return 0;
78}
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c
new file mode 100644
index 000000000000..2f93f81f0bac
--- /dev/null
+++ b/tools/lib/traceevent/plugin_jbd2.c
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26#define MINORBITS 20
27#define MINORMASK ((1U << MINORBITS) - 1)
28
29#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
30#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
31
32static unsigned long long
33process_jbd2_dev_to_name(struct trace_seq *s,
34 unsigned long long *args)
35{
36 unsigned int dev = args[0];
37
38 trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev));
39 return 0;
40}
41
42static unsigned long long
43process_jiffies_to_msecs(struct trace_seq *s,
44 unsigned long long *args)
45{
46 unsigned long long jiffies = args[0];
47
48 trace_seq_printf(s, "%lld", jiffies);
49 return jiffies;
50}
51
52int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
53{
54 pevent_register_print_function(pevent,
55 process_jbd2_dev_to_name,
56 PEVENT_FUNC_ARG_STRING,
57 "jbd2_dev_to_name",
58 PEVENT_FUNC_ARG_INT,
59 PEVENT_FUNC_ARG_VOID);
60
61 pevent_register_print_function(pevent,
62 process_jiffies_to_msecs,
63 PEVENT_FUNC_ARG_LONG,
64 "jiffies_to_msecs",
65 PEVENT_FUNC_ARG_LONG,
66 PEVENT_FUNC_ARG_VOID);
67 return 0;
68}
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c
new file mode 100644
index 000000000000..7115c8037ea8
--- /dev/null
+++ b/tools/lib/traceevent/plugin_kmem.c
@@ -0,0 +1,72 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
27 struct event_format *event, void *context)
28{
29 struct format_field *field;
30 unsigned long long val, addr;
31 void *data = record->data;
32 const char *func;
33
34 field = pevent_find_field(event, "call_site");
35 if (!field)
36 return 1;
37
38 if (pevent_read_number_field(field, data, &val))
39 return 1;
40
41 func = pevent_find_function(event->pevent, val);
42 if (!func)
43 return 1;
44
45 addr = pevent_find_function_address(event->pevent, val);
46
47 trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
48 return 1;
49}
50
51int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
52{
53 pevent_register_event_handler(pevent, -1, "kmem", "kfree",
54 call_site_handler, NULL);
55
56 pevent_register_event_handler(pevent, -1, "kmem", "kmalloc",
57 call_site_handler, NULL);
58
59 pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
60 call_site_handler, NULL);
61
62 pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
63 call_site_handler, NULL);
64
65 pevent_register_event_handler(pevent, -1, "kmem",
66 "kmem_cache_alloc_node",
67 call_site_handler, NULL);
68
69 pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
70 call_site_handler, NULL);
71 return 0;
72}
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c
new file mode 100644
index 000000000000..a0e282c6b967
--- /dev/null
+++ b/tools/lib/traceevent/plugin_kvm.c
@@ -0,0 +1,436 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdint.h>
24
25#include "event-parse.h"
26
27#ifdef HAVE_UDIS86
28
29#include <udis86.h>
30
31static ud_t ud;
32
33static void init_disassembler(void)
34{
35 ud_init(&ud);
36 ud_set_syntax(&ud, UD_SYN_ATT);
37}
38
39static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
40 int cr0_pe, int eflags_vm,
41 int cs_d, int cs_l)
42{
43 int mode;
44
45 if (!cr0_pe)
46 mode = 16;
47 else if (eflags_vm)
48 mode = 16;
49 else if (cs_l)
50 mode = 64;
51 else if (cs_d)
52 mode = 32;
53 else
54 mode = 16;
55
56 ud_set_pc(&ud, rip);
57 ud_set_mode(&ud, mode);
58 ud_set_input_buffer(&ud, insn, len);
59 ud_disassemble(&ud);
60 return ud_insn_asm(&ud);
61}
62
63#else
64
65static void init_disassembler(void)
66{
67}
68
69static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
70 int cr0_pe, int eflags_vm,
71 int cs_d, int cs_l)
72{
73 static char out[15*3+1];
74 int i;
75
76 for (i = 0; i < len; ++i)
77 sprintf(out + i * 3, "%02x ", insn[i]);
78 out[len*3-1] = '\0';
79 return out;
80}
81
82#endif
83
84
85#define VMX_EXIT_REASONS \
86 _ER(EXCEPTION_NMI, 0) \
87 _ER(EXTERNAL_INTERRUPT, 1) \
88 _ER(TRIPLE_FAULT, 2) \
89 _ER(PENDING_INTERRUPT, 7) \
90 _ER(NMI_WINDOW, 8) \
91 _ER(TASK_SWITCH, 9) \
92 _ER(CPUID, 10) \
93 _ER(HLT, 12) \
94 _ER(INVD, 13) \
95 _ER(INVLPG, 14) \
96 _ER(RDPMC, 15) \
97 _ER(RDTSC, 16) \
98 _ER(VMCALL, 18) \
99 _ER(VMCLEAR, 19) \
100 _ER(VMLAUNCH, 20) \
101 _ER(VMPTRLD, 21) \
102 _ER(VMPTRST, 22) \
103 _ER(VMREAD, 23) \
104 _ER(VMRESUME, 24) \
105 _ER(VMWRITE, 25) \
106 _ER(VMOFF, 26) \
107 _ER(VMON, 27) \
108 _ER(CR_ACCESS, 28) \
109 _ER(DR_ACCESS, 29) \
110 _ER(IO_INSTRUCTION, 30) \
111 _ER(MSR_READ, 31) \
112 _ER(MSR_WRITE, 32) \
113 _ER(MWAIT_INSTRUCTION, 36) \
114 _ER(MONITOR_INSTRUCTION, 39) \
115 _ER(PAUSE_INSTRUCTION, 40) \
116 _ER(MCE_DURING_VMENTRY, 41) \
117 _ER(TPR_BELOW_THRESHOLD, 43) \
118 _ER(APIC_ACCESS, 44) \
119 _ER(EOI_INDUCED, 45) \
120 _ER(EPT_VIOLATION, 48) \
121 _ER(EPT_MISCONFIG, 49) \
122 _ER(INVEPT, 50) \
123 _ER(PREEMPTION_TIMER, 52) \
124 _ER(WBINVD, 54) \
125 _ER(XSETBV, 55) \
126 _ER(APIC_WRITE, 56) \
127 _ER(INVPCID, 58)
128
129#define SVM_EXIT_REASONS \
130 _ER(EXIT_READ_CR0, 0x000) \
131 _ER(EXIT_READ_CR3, 0x003) \
132 _ER(EXIT_READ_CR4, 0x004) \
133 _ER(EXIT_READ_CR8, 0x008) \
134 _ER(EXIT_WRITE_CR0, 0x010) \
135 _ER(EXIT_WRITE_CR3, 0x013) \
136 _ER(EXIT_WRITE_CR4, 0x014) \
137 _ER(EXIT_WRITE_CR8, 0x018) \
138 _ER(EXIT_READ_DR0, 0x020) \
139 _ER(EXIT_READ_DR1, 0x021) \
140 _ER(EXIT_READ_DR2, 0x022) \
141 _ER(EXIT_READ_DR3, 0x023) \
142 _ER(EXIT_READ_DR4, 0x024) \
143 _ER(EXIT_READ_DR5, 0x025) \
144 _ER(EXIT_READ_DR6, 0x026) \
145 _ER(EXIT_READ_DR7, 0x027) \
146 _ER(EXIT_WRITE_DR0, 0x030) \
147 _ER(EXIT_WRITE_DR1, 0x031) \
148 _ER(EXIT_WRITE_DR2, 0x032) \
149 _ER(EXIT_WRITE_DR3, 0x033) \
150 _ER(EXIT_WRITE_DR4, 0x034) \
151 _ER(EXIT_WRITE_DR5, 0x035) \
152 _ER(EXIT_WRITE_DR6, 0x036) \
153 _ER(EXIT_WRITE_DR7, 0x037) \
154 _ER(EXIT_EXCP_BASE, 0x040) \
155 _ER(EXIT_INTR, 0x060) \
156 _ER(EXIT_NMI, 0x061) \
157 _ER(EXIT_SMI, 0x062) \
158 _ER(EXIT_INIT, 0x063) \
159 _ER(EXIT_VINTR, 0x064) \
160 _ER(EXIT_CR0_SEL_WRITE, 0x065) \
161 _ER(EXIT_IDTR_READ, 0x066) \
162 _ER(EXIT_GDTR_READ, 0x067) \
163 _ER(EXIT_LDTR_READ, 0x068) \
164 _ER(EXIT_TR_READ, 0x069) \
165 _ER(EXIT_IDTR_WRITE, 0x06a) \
166 _ER(EXIT_GDTR_WRITE, 0x06b) \
167 _ER(EXIT_LDTR_WRITE, 0x06c) \
168 _ER(EXIT_TR_WRITE, 0x06d) \
169 _ER(EXIT_RDTSC, 0x06e) \
170 _ER(EXIT_RDPMC, 0x06f) \
171 _ER(EXIT_PUSHF, 0x070) \
172 _ER(EXIT_POPF, 0x071) \
173 _ER(EXIT_CPUID, 0x072) \
174 _ER(EXIT_RSM, 0x073) \
175 _ER(EXIT_IRET, 0x074) \
176 _ER(EXIT_SWINT, 0x075) \
177 _ER(EXIT_INVD, 0x076) \
178 _ER(EXIT_PAUSE, 0x077) \
179 _ER(EXIT_HLT, 0x078) \
180 _ER(EXIT_INVLPG, 0x079) \
181 _ER(EXIT_INVLPGA, 0x07a) \
182 _ER(EXIT_IOIO, 0x07b) \
183 _ER(EXIT_MSR, 0x07c) \
184 _ER(EXIT_TASK_SWITCH, 0x07d) \
185 _ER(EXIT_FERR_FREEZE, 0x07e) \
186 _ER(EXIT_SHUTDOWN, 0x07f) \
187 _ER(EXIT_VMRUN, 0x080) \
188 _ER(EXIT_VMMCALL, 0x081) \
189 _ER(EXIT_VMLOAD, 0x082) \
190 _ER(EXIT_VMSAVE, 0x083) \
191 _ER(EXIT_STGI, 0x084) \
192 _ER(EXIT_CLGI, 0x085) \
193 _ER(EXIT_SKINIT, 0x086) \
194 _ER(EXIT_RDTSCP, 0x087) \
195 _ER(EXIT_ICEBP, 0x088) \
196 _ER(EXIT_WBINVD, 0x089) \
197 _ER(EXIT_MONITOR, 0x08a) \
198 _ER(EXIT_MWAIT, 0x08b) \
199 _ER(EXIT_MWAIT_COND, 0x08c) \
200 _ER(EXIT_NPF, 0x400) \
201 _ER(EXIT_ERR, -1)
202
203#define _ER(reason, val) { #reason, val },
204struct str_values {
205 const char *str;
206 int val;
207};
208
209static struct str_values vmx_exit_reasons[] = {
210 VMX_EXIT_REASONS
211 { NULL, -1}
212};
213
214static struct str_values svm_exit_reasons[] = {
215 SVM_EXIT_REASONS
216 { NULL, -1}
217};
218
219static struct isa_exit_reasons {
220 unsigned isa;
221 struct str_values *strings;
222} isa_exit_reasons[] = {
223 { .isa = 1, .strings = vmx_exit_reasons },
224 { .isa = 2, .strings = svm_exit_reasons },
225 { }
226};
227
228static const char *find_exit_reason(unsigned isa, int val)
229{
230 struct str_values *strings = NULL;
231 int i;
232
233 for (i = 0; isa_exit_reasons[i].strings; ++i)
234 if (isa_exit_reasons[i].isa == isa) {
235 strings = isa_exit_reasons[i].strings;
236 break;
237 }
238 if (!strings)
239 return "UNKNOWN-ISA";
240 for (i = 0; strings[i].val >= 0; i++)
241 if (strings[i].val == val)
242 break;
243 if (strings[i].str)
244 return strings[i].str;
245 return "UNKNOWN";
246}
247
248static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
249 struct event_format *event, void *context)
250{
251 unsigned long long isa;
252 unsigned long long val;
253 unsigned long long info1 = 0, info2 = 0;
254
255 if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0)
256 return -1;
257
258 if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
259 isa = 1;
260
261 trace_seq_printf(s, "reason %s", find_exit_reason(isa, val));
262
263 pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
264
265 if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
266 && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
267 trace_seq_printf(s, " info %llx %llx", info1, info2);
268
269 return 0;
270}
271
272#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
273#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
274#define KVM_EMUL_INSN_F_CS_D (1 << 2)
275#define KVM_EMUL_INSN_F_CS_L (1 << 3)
276
277static int kvm_emulate_insn_handler(struct trace_seq *s,
278 struct pevent_record *record,
279 struct event_format *event, void *context)
280{
281 unsigned long long rip, csbase, len, flags, failed;
282 int llen;
283 uint8_t *insn;
284 const char *disasm;
285
286 if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
287 return -1;
288
289 if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
290 return -1;
291
292 if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
293 return -1;
294
295 if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
296 return -1;
297
298 if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
299 return -1;
300
301 insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
302 if (!insn)
303 return -1;
304
305 disasm = disassemble(insn, len, rip,
306 flags & KVM_EMUL_INSN_F_CR0_PE,
307 flags & KVM_EMUL_INSN_F_EFL_VM,
308 flags & KVM_EMUL_INSN_F_CS_D,
309 flags & KVM_EMUL_INSN_F_CS_L);
310
311 trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
312 failed ? " FAIL" : "");
313 return 0;
314}
315
316union kvm_mmu_page_role {
317 unsigned word;
318 struct {
319 unsigned glevels:4;
320 unsigned level:4;
321 unsigned quadrant:2;
322 unsigned pad_for_nice_hex_output:6;
323 unsigned direct:1;
324 unsigned access:3;
325 unsigned invalid:1;
326 unsigned cr4_pge:1;
327 unsigned nxe:1;
328 };
329};
330
331static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
332 struct event_format *event, void *context)
333{
334 unsigned long long val;
335 static const char *access_str[] = {
336 "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
337 };
338 union kvm_mmu_page_role role;
339
340 if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
341 return -1;
342
343 role.word = (int)val;
344
345 /*
346 * We can only use the structure if file is of the same
347 * endianess.
348 */
349 if (pevent_is_file_bigendian(event->pevent) ==
350 pevent_is_host_bigendian(event->pevent)) {
351
352 trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe",
353 role.level,
354 role.glevels,
355 role.quadrant,
356 role.direct ? " direct" : "",
357 access_str[role.access],
358 role.invalid ? " invalid" : "",
359 role.cr4_pge ? "" : "!",
360 role.nxe ? "" : "!");
361 } else
362 trace_seq_printf(s, "WORD: %08x", role.word);
363
364 pevent_print_num_field(s, " root %u ", event,
365 "root_count", record, 1);
366
367 if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
368 return -1;
369
370 trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
371 return 0;
372}
373
374static int kvm_mmu_get_page_handler(struct trace_seq *s,
375 struct pevent_record *record,
376 struct event_format *event, void *context)
377{
378 unsigned long long val;
379
380 if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
381 return -1;
382
383 trace_seq_printf(s, "%s ", val ? "new" : "existing");
384
385 if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
386 return -1;
387
388 trace_seq_printf(s, "sp gfn %llx ", val);
389 return kvm_mmu_print_role(s, record, event, context);
390}
391
392#define PT_WRITABLE_SHIFT 1
393#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
394
395static unsigned long long
396process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
397{
398 unsigned long pte = args[0];
399 return pte & PT_WRITABLE_MASK;
400}
401
402int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
403{
404 init_disassembler();
405
406 pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
407 kvm_exit_handler, NULL);
408
409 pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
410 kvm_emulate_insn_handler, NULL);
411
412 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
413 kvm_mmu_get_page_handler, NULL);
414
415 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
416 kvm_mmu_print_role, NULL);
417
418 pevent_register_event_handler(pevent, -1,
419 "kvmmmu", "kvm_mmu_unsync_page",
420 kvm_mmu_print_role, NULL);
421
422 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
423 kvm_mmu_print_role, NULL);
424
425 pevent_register_event_handler(pevent, -1, "kvmmmu",
426 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
427 NULL);
428
429 pevent_register_print_function(pevent,
430 process_is_writable_pte,
431 PEVENT_FUNC_ARG_INT,
432 "is_writable_pte",
433 PEVENT_FUNC_ARG_LONG,
434 PEVENT_FUNC_ARG_VOID);
435 return 0;
436}
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c
new file mode 100644
index 000000000000..558a3b91c046
--- /dev/null
+++ b/tools/lib/traceevent/plugin_mac80211.c
@@ -0,0 +1,95 @@
1/*
2 * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26#define INDENT 65
27
28static void print_string(struct trace_seq *s, struct event_format *event,
29 const char *name, const void *data)
30{
31 struct format_field *f = pevent_find_field(event, name);
32 int offset;
33 int length;
34
35 if (!f) {
36 trace_seq_printf(s, "NOTFOUND:%s", name);
37 return;
38 }
39
40 offset = f->offset;
41 length = f->size;
42
43 if (!strncmp(f->type, "__data_loc", 10)) {
44 unsigned long long v;
45 if (pevent_read_number_field(f, data, &v)) {
46 trace_seq_printf(s, "invalid_data_loc");
47 return;
48 }
49 offset = v & 0xffff;
50 length = v >> 16;
51 }
52
53 trace_seq_printf(s, "%.*s", length, (char *)data + offset);
54}
55
56#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0)
57#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0)
58#define SP() trace_seq_putc(s, ' ')
59
60static int drv_bss_info_changed(struct trace_seq *s,
61 struct pevent_record *record,
62 struct event_format *event, void *context)
63{
64 void *data = record->data;
65
66 print_string(s, event, "wiphy_name", data);
67 trace_seq_printf(s, " vif:");
68 print_string(s, event, "vif_name", data);
69 pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1);
70
71 trace_seq_printf(s, "\n%*s", INDENT, "");
72 SF("assoc"); SP();
73 SF("aid"); SP();
74 SF("cts"); SP();
75 SF("shortpre"); SP();
76 SF("shortslot"); SP();
77 SF("dtimper"); SP();
78 trace_seq_printf(s, "\n%*s", INDENT, "");
79 SF("bcnint"); SP();
80 SFX("assoc_cap"); SP();
81 SFX("basic_rates"); SP();
82 SF("enable_beacon");
83 trace_seq_printf(s, "\n%*s", INDENT, "");
84 SF("ht_operation_mode");
85
86 return 0;
87}
88
89int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
90{
91 pevent_register_event_handler(pevent, -1, "mac80211",
92 "drv_bss_info_changed",
93 drv_bss_info_changed, NULL);
94 return 0;
95}
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c
new file mode 100644
index 000000000000..fea3724aa24f
--- /dev/null
+++ b/tools/lib/traceevent/plugin_sched_switch.c
@@ -0,0 +1,148 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26static void write_state(struct trace_seq *s, int val)
27{
28 const char states[] = "SDTtZXxW";
29 int found = 0;
30 int i;
31
32 for (i = 0; i < (sizeof(states) - 1); i++) {
33 if (!(val & (1 << i)))
34 continue;
35
36 if (found)
37 trace_seq_putc(s, '|');
38
39 found = 1;
40 trace_seq_putc(s, states[i]);
41 }
42
43 if (!found)
44 trace_seq_putc(s, 'R');
45}
46
47static void write_and_save_comm(struct format_field *field,
48 struct pevent_record *record,
49 struct trace_seq *s, int pid)
50{
51 const char *comm;
52 int len;
53
54 comm = (char *)(record->data + field->offset);
55 len = s->len;
56 trace_seq_printf(s, "%.*s",
57 field->size, comm);
58
59 /* make sure the comm has a \0 at the end. */
60 trace_seq_terminate(s);
61 comm = &s->buffer[len];
62
63 /* Help out the comm to ids. This will handle dups */
64 pevent_register_comm(field->event->pevent, comm, pid);
65}
66
67static int sched_wakeup_handler(struct trace_seq *s,
68 struct pevent_record *record,
69 struct event_format *event, void *context)
70{
71 struct format_field *field;
72 unsigned long long val;
73
74 if (pevent_get_field_val(s, event, "pid", record, &val, 1))
75 return trace_seq_putc(s, '!');
76
77 field = pevent_find_any_field(event, "comm");
78 if (field) {
79 write_and_save_comm(field, record, s, val);
80 trace_seq_putc(s, ':');
81 }
82 trace_seq_printf(s, "%lld", val);
83
84 if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
85 trace_seq_printf(s, " [%lld]", val);
86
87 if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
88 trace_seq_printf(s, " success=%lld", val);
89
90 if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
91 trace_seq_printf(s, " CPU:%03llu", val);
92
93 return 0;
94}
95
96static int sched_switch_handler(struct trace_seq *s,
97 struct pevent_record *record,
98 struct event_format *event, void *context)
99{
100 struct format_field *field;
101 unsigned long long val;
102
103 if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
104 return trace_seq_putc(s, '!');
105
106 field = pevent_find_any_field(event, "prev_comm");
107 if (field) {
108 write_and_save_comm(field, record, s, val);
109 trace_seq_putc(s, ':');
110 }
111 trace_seq_printf(s, "%lld ", val);
112
113 if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
114 trace_seq_printf(s, "[%lld] ", val);
115
116 if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
117 write_state(s, val);
118
119 trace_seq_puts(s, " ==> ");
120
121 if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
122 return trace_seq_putc(s, '!');
123
124 field = pevent_find_any_field(event, "next_comm");
125 if (field) {
126 write_and_save_comm(field, record, s, val);
127 trace_seq_putc(s, ':');
128 }
129 trace_seq_printf(s, "%lld", val);
130
131 if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
132 trace_seq_printf(s, " [%lld]", val);
133
134 return 0;
135}
136
137int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
138{
139 pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
140 sched_switch_handler, NULL);
141
142 pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
143 sched_wakeup_handler, NULL);
144
145 pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
146 sched_wakeup_handler, NULL);
147 return 0;
148}
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c
new file mode 100644
index 000000000000..6fb8e3e3fcad
--- /dev/null
+++ b/tools/lib/traceevent/plugin_scsi.c
@@ -0,0 +1,423 @@
1#include <stdio.h>
2#include <string.h>
3#include <inttypes.h>
4#include "event-parse.h"
5
6typedef unsigned long sector_t;
7typedef uint64_t u64;
8typedef unsigned int u32;
9
10/*
11 * SCSI opcodes
12 */
13#define TEST_UNIT_READY 0x00
14#define REZERO_UNIT 0x01
15#define REQUEST_SENSE 0x03
16#define FORMAT_UNIT 0x04
17#define READ_BLOCK_LIMITS 0x05
18#define REASSIGN_BLOCKS 0x07
19#define INITIALIZE_ELEMENT_STATUS 0x07
20#define READ_6 0x08
21#define WRITE_6 0x0a
22#define SEEK_6 0x0b
23#define READ_REVERSE 0x0f
24#define WRITE_FILEMARKS 0x10
25#define SPACE 0x11
26#define INQUIRY 0x12
27#define RECOVER_BUFFERED_DATA 0x14
28#define MODE_SELECT 0x15
29#define RESERVE 0x16
30#define RELEASE 0x17
31#define COPY 0x18
32#define ERASE 0x19
33#define MODE_SENSE 0x1a
34#define START_STOP 0x1b
35#define RECEIVE_DIAGNOSTIC 0x1c
36#define SEND_DIAGNOSTIC 0x1d
37#define ALLOW_MEDIUM_REMOVAL 0x1e
38
39#define READ_FORMAT_CAPACITIES 0x23
40#define SET_WINDOW 0x24
41#define READ_CAPACITY 0x25
42#define READ_10 0x28
43#define WRITE_10 0x2a
44#define SEEK_10 0x2b
45#define POSITION_TO_ELEMENT 0x2b
46#define WRITE_VERIFY 0x2e
47#define VERIFY 0x2f
48#define SEARCH_HIGH 0x30
49#define SEARCH_EQUAL 0x31
50#define SEARCH_LOW 0x32
51#define SET_LIMITS 0x33
52#define PRE_FETCH 0x34
53#define READ_POSITION 0x34
54#define SYNCHRONIZE_CACHE 0x35
55#define LOCK_UNLOCK_CACHE 0x36
56#define READ_DEFECT_DATA 0x37
57#define MEDIUM_SCAN 0x38
58#define COMPARE 0x39
59#define COPY_VERIFY 0x3a
60#define WRITE_BUFFER 0x3b
61#define READ_BUFFER 0x3c
62#define UPDATE_BLOCK 0x3d
63#define READ_LONG 0x3e
64#define WRITE_LONG 0x3f
65#define CHANGE_DEFINITION 0x40
66#define WRITE_SAME 0x41
67#define UNMAP 0x42
68#define READ_TOC 0x43
69#define READ_HEADER 0x44
70#define GET_EVENT_STATUS_NOTIFICATION 0x4a
71#define LOG_SELECT 0x4c
72#define LOG_SENSE 0x4d
73#define XDWRITEREAD_10 0x53
74#define MODE_SELECT_10 0x55
75#define RESERVE_10 0x56
76#define RELEASE_10 0x57
77#define MODE_SENSE_10 0x5a
78#define PERSISTENT_RESERVE_IN 0x5e
79#define PERSISTENT_RESERVE_OUT 0x5f
80#define VARIABLE_LENGTH_CMD 0x7f
81#define REPORT_LUNS 0xa0
82#define SECURITY_PROTOCOL_IN 0xa2
83#define MAINTENANCE_IN 0xa3
84#define MAINTENANCE_OUT 0xa4
85#define MOVE_MEDIUM 0xa5
86#define EXCHANGE_MEDIUM 0xa6
87#define READ_12 0xa8
88#define WRITE_12 0xaa
89#define READ_MEDIA_SERIAL_NUMBER 0xab
90#define WRITE_VERIFY_12 0xae
91#define VERIFY_12 0xaf
92#define SEARCH_HIGH_12 0xb0
93#define SEARCH_EQUAL_12 0xb1
94#define SEARCH_LOW_12 0xb2
95#define SECURITY_PROTOCOL_OUT 0xb5
96#define READ_ELEMENT_STATUS 0xb8
97#define SEND_VOLUME_TAG 0xb6
98#define WRITE_LONG_2 0xea
99#define EXTENDED_COPY 0x83
100#define RECEIVE_COPY_RESULTS 0x84
101#define ACCESS_CONTROL_IN 0x86
102#define ACCESS_CONTROL_OUT 0x87
103#define READ_16 0x88
104#define WRITE_16 0x8a
105#define READ_ATTRIBUTE 0x8c
106#define WRITE_ATTRIBUTE 0x8d
107#define VERIFY_16 0x8f
108#define SYNCHRONIZE_CACHE_16 0x91
109#define WRITE_SAME_16 0x93
110#define SERVICE_ACTION_IN 0x9e
111/* values for service action in */
112#define SAI_READ_CAPACITY_16 0x10
113#define SAI_GET_LBA_STATUS 0x12
114/* values for VARIABLE_LENGTH_CMD service action codes
115 * see spc4r17 Section D.3.5, table D.7 and D.8 */
116#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
117/* values for maintenance in */
118#define MI_REPORT_IDENTIFYING_INFORMATION 0x05
119#define MI_REPORT_TARGET_PGS 0x0a
120#define MI_REPORT_ALIASES 0x0b
121#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
122#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
123#define MI_REPORT_PRIORITY 0x0e
124#define MI_REPORT_TIMESTAMP 0x0f
125#define MI_MANAGEMENT_PROTOCOL_IN 0x10
126/* value for MI_REPORT_TARGET_PGS ext header */
127#define MI_EXT_HDR_PARAM_FMT 0x20
128/* values for maintenance out */
129#define MO_SET_IDENTIFYING_INFORMATION 0x06
130#define MO_SET_TARGET_PGS 0x0a
131#define MO_CHANGE_ALIASES 0x0b
132#define MO_SET_PRIORITY 0x0e
133#define MO_SET_TIMESTAMP 0x0f
134#define MO_MANAGEMENT_PROTOCOL_OUT 0x10
135/* values for variable length command */
136#define XDREAD_32 0x03
137#define XDWRITE_32 0x04
138#define XPWRITE_32 0x06
139#define XDWRITEREAD_32 0x07
140#define READ_32 0x09
141#define VERIFY_32 0x0a
142#define WRITE_32 0x0b
143#define WRITE_SAME_32 0x0d
144
145#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
146#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
147
148static const char *
149scsi_trace_misc(struct trace_seq *, unsigned char *, int);
150
151static const char *
152scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
153{
154 const char *ret = p->buffer + p->len;
155 sector_t lba = 0, txlen = 0;
156
157 lba |= ((cdb[1] & 0x1F) << 16);
158 lba |= (cdb[2] << 8);
159 lba |= cdb[3];
160 txlen = cdb[4];
161
162 trace_seq_printf(p, "lba=%llu txlen=%llu",
163 (unsigned long long)lba, (unsigned long long)txlen);
164 trace_seq_putc(p, 0);
165 return ret;
166}
167
168static const char *
169scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
170{
171 const char *ret = p->buffer + p->len;
172 sector_t lba = 0, txlen = 0;
173
174 lba |= (cdb[2] << 24);
175 lba |= (cdb[3] << 16);
176 lba |= (cdb[4] << 8);
177 lba |= cdb[5];
178 txlen |= (cdb[7] << 8);
179 txlen |= cdb[8];
180
181 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
182 (unsigned long long)lba, (unsigned long long)txlen,
183 cdb[1] >> 5);
184
185 if (cdb[0] == WRITE_SAME)
186 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
187
188 trace_seq_putc(p, 0);
189 return ret;
190}
191
192static const char *
193scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
194{
195 const char *ret = p->buffer + p->len;
196 sector_t lba = 0, txlen = 0;
197
198 lba |= (cdb[2] << 24);
199 lba |= (cdb[3] << 16);
200 lba |= (cdb[4] << 8);
201 lba |= cdb[5];
202 txlen |= (cdb[6] << 24);
203 txlen |= (cdb[7] << 16);
204 txlen |= (cdb[8] << 8);
205 txlen |= cdb[9];
206
207 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
208 (unsigned long long)lba, (unsigned long long)txlen,
209 cdb[1] >> 5);
210 trace_seq_putc(p, 0);
211 return ret;
212}
213
214static const char *
215scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
216{
217 const char *ret = p->buffer + p->len;
218 sector_t lba = 0, txlen = 0;
219
220 lba |= ((u64)cdb[2] << 56);
221 lba |= ((u64)cdb[3] << 48);
222 lba |= ((u64)cdb[4] << 40);
223 lba |= ((u64)cdb[5] << 32);
224 lba |= (cdb[6] << 24);
225 lba |= (cdb[7] << 16);
226 lba |= (cdb[8] << 8);
227 lba |= cdb[9];
228 txlen |= (cdb[10] << 24);
229 txlen |= (cdb[11] << 16);
230 txlen |= (cdb[12] << 8);
231 txlen |= cdb[13];
232
233 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
234 (unsigned long long)lba, (unsigned long long)txlen,
235 cdb[1] >> 5);
236
237 if (cdb[0] == WRITE_SAME_16)
238 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
239
240 trace_seq_putc(p, 0);
241 return ret;
242}
243
244static const char *
245scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
246{
247 const char *ret = p->buffer + p->len, *cmd;
248 sector_t lba = 0, txlen = 0;
249 u32 ei_lbrt = 0;
250
251 switch (SERVICE_ACTION32(cdb)) {
252 case READ_32:
253 cmd = "READ";
254 break;
255 case VERIFY_32:
256 cmd = "VERIFY";
257 break;
258 case WRITE_32:
259 cmd = "WRITE";
260 break;
261 case WRITE_SAME_32:
262 cmd = "WRITE_SAME";
263 break;
264 default:
265 trace_seq_printf(p, "UNKNOWN");
266 goto out;
267 }
268
269 lba |= ((u64)cdb[12] << 56);
270 lba |= ((u64)cdb[13] << 48);
271 lba |= ((u64)cdb[14] << 40);
272 lba |= ((u64)cdb[15] << 32);
273 lba |= (cdb[16] << 24);
274 lba |= (cdb[17] << 16);
275 lba |= (cdb[18] << 8);
276 lba |= cdb[19];
277 ei_lbrt |= (cdb[20] << 24);
278 ei_lbrt |= (cdb[21] << 16);
279 ei_lbrt |= (cdb[22] << 8);
280 ei_lbrt |= cdb[23];
281 txlen |= (cdb[28] << 24);
282 txlen |= (cdb[29] << 16);
283 txlen |= (cdb[30] << 8);
284 txlen |= cdb[31];
285
286 trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
287 cmd, (unsigned long long)lba,
288 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
289
290 if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
291 trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
292
293out:
294 trace_seq_putc(p, 0);
295 return ret;
296}
297
298static const char *
299scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
300{
301 const char *ret = p->buffer + p->len;
302 unsigned int regions = cdb[7] << 8 | cdb[8];
303
304 trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
305 trace_seq_putc(p, 0);
306 return ret;
307}
308
309static const char *
310scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
311{
312 const char *ret = p->buffer + p->len, *cmd;
313 sector_t lba = 0;
314 u32 alloc_len = 0;
315
316 switch (SERVICE_ACTION16(cdb)) {
317 case SAI_READ_CAPACITY_16:
318 cmd = "READ_CAPACITY_16";
319 break;
320 case SAI_GET_LBA_STATUS:
321 cmd = "GET_LBA_STATUS";
322 break;
323 default:
324 trace_seq_printf(p, "UNKNOWN");
325 goto out;
326 }
327
328 lba |= ((u64)cdb[2] << 56);
329 lba |= ((u64)cdb[3] << 48);
330 lba |= ((u64)cdb[4] << 40);
331 lba |= ((u64)cdb[5] << 32);
332 lba |= (cdb[6] << 24);
333 lba |= (cdb[7] << 16);
334 lba |= (cdb[8] << 8);
335 lba |= cdb[9];
336 alloc_len |= (cdb[10] << 24);
337 alloc_len |= (cdb[11] << 16);
338 alloc_len |= (cdb[12] << 8);
339 alloc_len |= cdb[13];
340
341 trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
342 (unsigned long long)lba, alloc_len);
343
344out:
345 trace_seq_putc(p, 0);
346 return ret;
347}
348
349static const char *
350scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
351{
352 switch (SERVICE_ACTION32(cdb)) {
353 case READ_32:
354 case VERIFY_32:
355 case WRITE_32:
356 case WRITE_SAME_32:
357 return scsi_trace_rw32(p, cdb, len);
358 default:
359 return scsi_trace_misc(p, cdb, len);
360 }
361}
362
363static const char *
364scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
365{
366 const char *ret = p->buffer + p->len;
367
368 trace_seq_printf(p, "-");
369 trace_seq_putc(p, 0);
370 return ret;
371}
372
373const char *
374scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
375{
376 switch (cdb[0]) {
377 case READ_6:
378 case WRITE_6:
379 return scsi_trace_rw6(p, cdb, len);
380 case READ_10:
381 case VERIFY:
382 case WRITE_10:
383 case WRITE_SAME:
384 return scsi_trace_rw10(p, cdb, len);
385 case READ_12:
386 case VERIFY_12:
387 case WRITE_12:
388 return scsi_trace_rw12(p, cdb, len);
389 case READ_16:
390 case VERIFY_16:
391 case WRITE_16:
392 case WRITE_SAME_16:
393 return scsi_trace_rw16(p, cdb, len);
394 case UNMAP:
395 return scsi_trace_unmap(p, cdb, len);
396 case SERVICE_ACTION_IN:
397 return scsi_trace_service_action_in(p, cdb, len);
398 case VARIABLE_LENGTH_CMD:
399 return scsi_trace_varlen(p, cdb, len);
400 default:
401 return scsi_trace_misc(p, cdb, len);
402 }
403}
404
405unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
406 unsigned long long *args)
407{
408 scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]);
409 return 0;
410}
411
412int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
413{
414 pevent_register_print_function(pevent,
415 process_scsi_trace_parse_cdb,
416 PEVENT_FUNC_ARG_STRING,
417 "scsi_trace_parse_cdb",
418 PEVENT_FUNC_ARG_PTR,
419 PEVENT_FUNC_ARG_PTR,
420 PEVENT_FUNC_ARG_INT,
421 PEVENT_FUNC_ARG_VOID);
422 return 0;
423}
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c
new file mode 100644
index 000000000000..e7794298f3a9
--- /dev/null
+++ b/tools/lib/traceevent/plugin_xen.c
@@ -0,0 +1,130 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include "event-parse.h"
5
6#define __HYPERVISOR_set_trap_table 0
7#define __HYPERVISOR_mmu_update 1
8#define __HYPERVISOR_set_gdt 2
9#define __HYPERVISOR_stack_switch 3
10#define __HYPERVISOR_set_callbacks 4
11#define __HYPERVISOR_fpu_taskswitch 5
12#define __HYPERVISOR_sched_op_compat 6
13#define __HYPERVISOR_dom0_op 7
14#define __HYPERVISOR_set_debugreg 8
15#define __HYPERVISOR_get_debugreg 9
16#define __HYPERVISOR_update_descriptor 10
17#define __HYPERVISOR_memory_op 12
18#define __HYPERVISOR_multicall 13
19#define __HYPERVISOR_update_va_mapping 14
20#define __HYPERVISOR_set_timer_op 15
21#define __HYPERVISOR_event_channel_op_compat 16
22#define __HYPERVISOR_xen_version 17
23#define __HYPERVISOR_console_io 18
24#define __HYPERVISOR_physdev_op_compat 19
25#define __HYPERVISOR_grant_table_op 20
26#define __HYPERVISOR_vm_assist 21
27#define __HYPERVISOR_update_va_mapping_otherdomain 22
28#define __HYPERVISOR_iret 23 /* x86 only */
29#define __HYPERVISOR_vcpu_op 24
30#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
31#define __HYPERVISOR_mmuext_op 26
32#define __HYPERVISOR_acm_op 27
33#define __HYPERVISOR_nmi_op 28
34#define __HYPERVISOR_sched_op 29
35#define __HYPERVISOR_callback_op 30
36#define __HYPERVISOR_xenoprof_op 31
37#define __HYPERVISOR_event_channel_op 32
38#define __HYPERVISOR_physdev_op 33
39#define __HYPERVISOR_hvm_op 34
40#define __HYPERVISOR_tmem_op 38
41
42/* Architecture-specific hypercall definitions. */
43#define __HYPERVISOR_arch_0 48
44#define __HYPERVISOR_arch_1 49
45#define __HYPERVISOR_arch_2 50
46#define __HYPERVISOR_arch_3 51
47#define __HYPERVISOR_arch_4 52
48#define __HYPERVISOR_arch_5 53
49#define __HYPERVISOR_arch_6 54
50#define __HYPERVISOR_arch_7 55
51
52#define N(x) [__HYPERVISOR_##x] = "("#x")"
53static const char *xen_hypercall_names[] = {
54 N(set_trap_table),
55 N(mmu_update),
56 N(set_gdt),
57 N(stack_switch),
58 N(set_callbacks),
59 N(fpu_taskswitch),
60 N(sched_op_compat),
61 N(dom0_op),
62 N(set_debugreg),
63 N(get_debugreg),
64 N(update_descriptor),
65 N(memory_op),
66 N(multicall),
67 N(update_va_mapping),
68 N(set_timer_op),
69 N(event_channel_op_compat),
70 N(xen_version),
71 N(console_io),
72 N(physdev_op_compat),
73 N(grant_table_op),
74 N(vm_assist),
75 N(update_va_mapping_otherdomain),
76 N(iret),
77 N(vcpu_op),
78 N(set_segment_base),
79 N(mmuext_op),
80 N(acm_op),
81 N(nmi_op),
82 N(sched_op),
83 N(callback_op),
84 N(xenoprof_op),
85 N(event_channel_op),
86 N(physdev_op),
87 N(hvm_op),
88
89/* Architecture-specific hypercall definitions. */
90 N(arch_0),
91 N(arch_1),
92 N(arch_2),
93 N(arch_3),
94 N(arch_4),
95 N(arch_5),
96 N(arch_6),
97 N(arch_7),
98};
99#undef N
100
101#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
102
103static const char *xen_hypercall_name(unsigned op)
104{
105 if (op < ARRAY_SIZE(xen_hypercall_names) &&
106 xen_hypercall_names[op] != NULL)
107 return xen_hypercall_names[op];
108
109 return "";
110}
111
112unsigned long long process_xen_hypercall_name(struct trace_seq *s,
113 unsigned long long *args)
114{
115 unsigned int op = args[0];
116
117 trace_seq_printf(s, "%s", xen_hypercall_name(op));
118 return 0;
119}
120
121int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
122{
123 pevent_register_print_function(pevent,
124 process_xen_hypercall_name,
125 PEVENT_FUNC_ARG_STRING,
126 "xen_hypercall_name",
127 PEVENT_FUNC_ARG_INT,
128 PEVENT_FUNC_ARG_VOID);
129 return 0;
130}
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
index 5032a142853e..ac6ecbb3e669 100644
--- a/tools/perf/Documentation/perf-archive.txt
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -12,9 +12,9 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files 15This command runs perf-buildid-list --with-hits, and collects the files with the
16with the buildids found so that analysis of perf.data contents can be possible 16buildids found so that analysis of perf.data contents can be possible on another
17on another machine. 17machine.
18 18
19 19
20SEE ALSO 20SEE ALSO
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 6a06cefe9642..52276a6d2b75 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -10,9 +10,9 @@ SYNOPSIS
10[verse] 10[verse]
11'perf kvm' [--host] [--guest] [--guestmount=<path> 11'perf kvm' [--host] [--guest] [--guestmount=<path>
12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] 12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
13 {top|record|report|diff|buildid-list} 13 {top|record|report|diff|buildid-list} [<options>]
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} 15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} [<options>]
16'perf kvm stat [record|report|live] [<options>] 16'perf kvm stat [record|report|live] [<options>]
17 17
18DESCRIPTION 18DESCRIPTION
@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm:
24 of an arbitrary workload. 24 of an arbitrary workload.
25 25
26 'perf kvm record <command>' to record the performance counter profile 26 'perf kvm record <command>' to record the performance counter profile
27 of an arbitrary workload and save it into a perf data file. If both 27 of an arbitrary workload and save it into a perf data file. We set the
28 --host and --guest are input, the perf data file name is perf.data.kvm. 28 default behavior of perf kvm as --guest, so if neither --host nor --guest
29 If there is no --host but --guest, the file name is perf.data.guest. 29 is input, the perf data file name is perf.data.guest. If --host is input,
30 If there is no --guest but --host, the file name is perf.data.host. 30 the perf data file name is perf.data.kvm. If you want to record data into
31 perf.data.host, please input --host --no-guest. The behaviors are shown as
32 following:
33 Default('') -> perf.data.guest
34 --host -> perf.data.kvm
35 --guest -> perf.data.guest
36 --host --guest -> perf.data.kvm
37 --host --no-guest -> perf.data.host
31 38
32 'perf kvm report' to display the performance counter profile information 39 'perf kvm report' to display the performance counter profile information
33 recorded via perf kvm record. 40 recorded via perf kvm record.
@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm:
37 44
38 'perf kvm buildid-list' to display the buildids found in a perf data file, 45 'perf kvm buildid-list' to display the buildids found in a perf data file,
39 so that other tools can be used to fetch packages with matching symbol tables 46 so that other tools can be used to fetch packages with matching symbol tables
40 for use by perf report. 47 for use by perf report. As buildid is read from /sys/kernel/notes in os, then
48 if you want to list the buildid for guest, please make sure your perf data file
49 was captured with --guestmount in perf kvm record.
41 50
42 'perf kvm stat <command>' to run a command and gather performance counter 51 'perf kvm stat <command>' to run a command and gather performance counter
43 statistics. 52 statistics.
@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm:
58OPTIONS 67OPTIONS
59------- 68-------
60-i:: 69-i::
61--input=:: 70--input=<path>::
62 Input file name. 71 Input file name.
63-o:: 72-o::
64--output:: 73--output=<path>::
65 Output file name. 74 Output file name.
66--host=:: 75--host::
67 Collect host side performance profile. 76 Collect host side performance profile.
68--guest=:: 77--guest::
69 Collect guest side performance profile. 78 Collect guest side performance profile.
70--guestmount=<path>:: 79--guestmount=<path>::
71 Guest os root file system mount directory. Users mounts guest os 80 Guest os root file system mount directory. Users mounts guest os
@@ -84,6 +93,9 @@ OPTIONS
84 kernel module information. Users copy it out from guest os. 93 kernel module information. Users copy it out from guest os.
85--guestvmlinux=<path>:: 94--guestvmlinux=<path>::
86 Guest os kernel vmlinux. 95 Guest os kernel vmlinux.
96-v::
97--verbose::
98 Be more verbose (show counter open errors, etc).
87 99
88STAT REPORT OPTIONS 100STAT REPORT OPTIONS
89------------------- 101-------------------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 43b42c4f4a91..82bffac036e1 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -57,6 +57,8 @@ OPTIONS
57-t:: 57-t::
58--tid=:: 58--tid=::
59 Record events on existing thread ID (comma separated list). 59 Record events on existing thread ID (comma separated list).
60 This option also disables inheritance by default. Enable it by adding
61 --inherit.
60 62
61-u:: 63-u::
62--uid=:: 64--uid=::
@@ -201,11 +203,15 @@ abort events and some memory events in precise mode on modern Intel CPUs.
201--transaction:: 203--transaction::
202Record transaction flags for transaction related events. 204Record transaction flags for transaction related events.
203 205
204--force-per-cpu:: 206--per-thread::
205Force the use of per-cpu mmaps. By default, when tasks are specified (i.e. -p, 207Use per-thread mmaps. By default per-cpu mmaps are created. This option
206-t or -u options) per-thread mmaps are created. This option overrides that and 208overrides that and uses per-thread mmaps. A side-effect of that is that
207forces per-cpu mmaps. A side-effect of that is that inheritance is 209inheritance is automatically disabled. --per-thread is ignored with a warning
208automatically enabled. Add the -i option also to disable inheritance. 210if combined with -a or -C options.
211
212--initial-delay msecs::
213After starting the program, wait msecs before measuring. This is useful to
214filter out the startup phase of the program, which is often very different.
209 215
210SEE ALSO 216SEE ALSO
211-------- 217--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 10a279871251..8eab8a4bdeb8 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -237,6 +237,15 @@ OPTIONS
237 Do not show entries which have an overhead under that percent. 237 Do not show entries which have an overhead under that percent.
238 (Default: 0). 238 (Default: 0).
239 239
240--header::
241 Show header information in the perf.data file. This includes
242 various information like hostname, OS and perf version, cpu/mem
243 info, perf command line, event list and so on. Currently only
244 --stdio output supports this feature.
245
246--header-only::
247 Show only perf.data header (forces --stdio).
248
240SEE ALSO 249SEE ALSO
241-------- 250--------
242linkperf:perf-stat[1], linkperf:perf-annotate[1] 251linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index e9cbfcddfa3f..05f9a0a6784c 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,7 +115,7 @@ OPTIONS
115-f:: 115-f::
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline.
119 Field list can be prepended with the type, trace, sw or hw, 119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
@@ -203,6 +203,18 @@ OPTIONS
203--show-kernel-path:: 203--show-kernel-path::
204 Try to resolve the path of [kernel.kallsyms] 204 Try to resolve the path of [kernel.kallsyms]
205 205
206--show-task-events
207 Display task related events (e.g. FORK, COMM, EXIT).
208
209--show-mmap-events
210 Display mmap related events (e.g. MMAP, MMAP2).
211
212--header
213 Show perf.data header.
214
215--header-only
216 Show only perf.data header.
217
206SEE ALSO 218SEE ALSO
207-------- 219--------
208linkperf:perf-record[1], linkperf:perf-script-perl[1], 220linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 80c7da6732f2..29ee857c09c6 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -133,7 +133,7 @@ use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor. 133core number and the number of online logical processors on that physical processor.
134 134
135-D msecs:: 135-D msecs::
136--initial-delay msecs:: 136--delay msecs::
137After starting the program, wait msecs before measuring. This is useful to 137After starting the program, wait msecs before measuring. This is useful to
138filter out the startup phase of the program, which is often very different. 138filter out the startup phase of the program, which is often very different.
139 139
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 3ff8bd4f0b4d..bc5990c33dc0 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -8,8 +8,7 @@ perf-timechart - Tool to visualize total system behavior during a workload
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf timechart' record <command> 11'perf timechart' [<timechart options>] {record} [<record options>]
12'perf timechart' [<options>]
13 12
14DESCRIPTION 13DESCRIPTION
15----------- 14-----------
@@ -21,8 +20,8 @@ There are two variants of perf timechart:
21 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 20 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
22 that can be viewed with popular SVG viewers such as 'Inkscape'. 21 that can be viewed with popular SVG viewers such as 'Inkscape'.
23 22
24OPTIONS 23TIMECHART OPTIONS
25------- 24-----------------
26-o:: 25-o::
27--output=:: 26--output=::
28 Select the output file (default: output.svg) 27 Select the output file (default: output.svg)
@@ -35,6 +34,9 @@ OPTIONS
35-P:: 34-P::
36--power-only:: 35--power-only::
37 Only output the CPU power section of the diagram 36 Only output the CPU power section of the diagram
37-T::
38--tasks-only::
39 Don't output processor state transitions
38-p:: 40-p::
39--process:: 41--process::
40 Select the processes to display, by name or PID 42 Select the processes to display, by name or PID
@@ -54,6 +56,38 @@ $ perf timechart
54 56
55 Written 10.2 seconds of trace to output.svg. 57 Written 10.2 seconds of trace to output.svg.
56 58
59Record system-wide timechart:
60
61 $ perf timechart record
62
63 then generate timechart and highlight 'gcc' tasks:
64
65 $ perf timechart --highlight gcc
66
67-n::
68--proc-num::
69 Print task info for at least given number of tasks.
70-t::
71--topology::
72 Sort CPUs according to topology.
73--highlight=<duration_nsecs|task_name>::
74 Highlight tasks (using different color) that run more than given
75 duration or tasks with given name. If number is given it's interpreted
76 as number of nanoseconds. If non-numeric string is given it's
77 interpreted as task name.
78
79RECORD OPTIONS
80--------------
81-P::
82--power-only::
83 Record only power-related events
84-T::
85--tasks-only::
86 Record only tasks-related events
87-g::
88--callchain::
89 Do call-graph (stack chain/backtrace) recording
90
57SEE ALSO 91SEE ALSO
58-------- 92--------
59linkperf:perf-record[1] 93linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 7de01dd79688..cdd8d4946dba 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -50,7 +50,6 @@ Default is to monitor all CPUS.
50--count-filter=<count>:: 50--count-filter=<count>::
51 Only display functions with more events than this. 51 Only display functions with more events than this.
52 52
53-g::
54--group:: 53--group::
55 Put the counters into a counter group. 54 Put the counters into a counter group.
56 55
@@ -143,12 +142,12 @@ Default is to monitor all CPUS.
143--asm-raw:: 142--asm-raw::
144 Show raw instruction encoding of assembly instructions. 143 Show raw instruction encoding of assembly instructions.
145 144
146-G:: 145-g::
147 Enables call-graph (stack chain/backtrace) recording. 146 Enables call-graph (stack chain/backtrace) recording.
148 147
149--call-graph:: 148--call-graph::
150 Setup and enable call-graph (stack chain/backtrace) recording, 149 Setup and enable call-graph (stack chain/backtrace) recording,
151 implies -G. 150 implies -g.
152 151
153--max-stack:: 152--max-stack::
154 Set the stack depth limit when parsing the callchain, anything 153 Set the stack depth limit when parsing the callchain, anything
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 025de796067c..f41572d0dd76 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,7 +1,11 @@
1tools/perf 1tools/perf
2tools/scripts 2tools/scripts
3tools/lib/traceevent 3tools/lib/traceevent
4tools/lib/lk 4tools/lib/api
5tools/lib/symbol/kallsyms.c
6tools/lib/symbol/kallsyms.h
7tools/include/asm/bug.h
8tools/include/linux/compiler.h
5include/linux/const.h 9include/linux/const.h
6include/linux/perf_event.h 10include/linux/perf_event.h
7include/linux/rbtree.h 11include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4835618a5608..eefb9fb0c02f 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -60,8 +60,11 @@ endef
60 60
61# 61#
62# Needed if no target specified: 62# Needed if no target specified:
63# (Except for tags and TAGS targets. The reason is that the
64# Makefile does not treat tags/TAGS as targets but as files
65# and thus won't rebuilt them once they are in place.)
63# 66#
64all: 67all tags TAGS:
65 $(print_msg) 68 $(print_msg)
66 $(make) 69 $(make)
67 70
@@ -77,3 +80,5 @@ clean:
77%: 80%:
78 $(print_msg) 81 $(print_msg)
79 $(make) 82 $(make)
83
84.PHONY: tags TAGS
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7fc8f179cae7..87d7726cee2d 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -86,7 +86,7 @@ FLEX = flex
86BISON = bison 86BISON = bison
87STRIP = strip 87STRIP = strip
88 88
89LK_DIR = $(srctree)/tools/lib/lk/ 89LIB_DIR = $(srctree)/tools/lib/api/
90TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ 90TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
91 91
92# include config/Makefile by default and rule out 92# include config/Makefile by default and rule out
@@ -105,7 +105,7 @@ ifeq ($(config),1)
105include config/Makefile 105include config/Makefile
106endif 106endif
107 107
108export prefix bindir sharedir sysconfdir 108export prefix bindir sharedir sysconfdir DESTDIR
109 109
110# sparse is architecture-neutral, which means that we need to tell it 110# sparse is architecture-neutral, which means that we need to tell it
111# explicitly what architecture to check for. Fix this up for yours.. 111# explicitly what architecture to check for. Fix this up for yours..
@@ -127,20 +127,20 @@ strip-libs = $(filter-out -l%,$(1))
127ifneq ($(OUTPUT),) 127ifneq ($(OUTPUT),)
128 TE_PATH=$(OUTPUT) 128 TE_PATH=$(OUTPUT)
129ifneq ($(subdir),) 129ifneq ($(subdir),)
130 LK_PATH=$(OUTPUT)/../lib/lk/ 130 LIB_PATH=$(OUTPUT)/../lib/api/
131else 131else
132 LK_PATH=$(OUTPUT) 132 LIB_PATH=$(OUTPUT)
133endif 133endif
134else 134else
135 TE_PATH=$(TRACE_EVENT_DIR) 135 TE_PATH=$(TRACE_EVENT_DIR)
136 LK_PATH=$(LK_DIR) 136 LIB_PATH=$(LIB_DIR)
137endif 137endif
138 138
139LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 139LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
140export LIBTRACEEVENT 140export LIBTRACEEVENT
141 141
142LIBLK = $(LK_PATH)liblk.a 142LIBAPIKFS = $(LIB_PATH)libapikfs.a
143export LIBLK 143export LIBAPIKFS
144 144
145# python extension build directories 145# python extension build directories
146PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 146PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
@@ -151,7 +151,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
151python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 151python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
152 152
153PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 153PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
154PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK) 154PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS)
155 155
156$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 156$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
157 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ 157 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
@@ -202,6 +202,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
202 202
203LIB_FILE=$(OUTPUT)libperf.a 203LIB_FILE=$(OUTPUT)libperf.a
204 204
205LIB_H += ../lib/symbol/kallsyms.h
205LIB_H += ../../include/uapi/linux/perf_event.h 206LIB_H += ../../include/uapi/linux/perf_event.h
206LIB_H += ../../include/linux/rbtree.h 207LIB_H += ../../include/linux/rbtree.h
207LIB_H += ../../include/linux/list.h 208LIB_H += ../../include/linux/list.h
@@ -210,7 +211,7 @@ LIB_H += ../../include/linux/hash.h
210LIB_H += ../../include/linux/stringify.h 211LIB_H += ../../include/linux/stringify.h
211LIB_H += util/include/linux/bitmap.h 212LIB_H += util/include/linux/bitmap.h
212LIB_H += util/include/linux/bitops.h 213LIB_H += util/include/linux/bitops.h
213LIB_H += util/include/linux/compiler.h 214LIB_H += ../include/linux/compiler.h
214LIB_H += util/include/linux/const.h 215LIB_H += util/include/linux/const.h
215LIB_H += util/include/linux/ctype.h 216LIB_H += util/include/linux/ctype.h
216LIB_H += util/include/linux/kernel.h 217LIB_H += util/include/linux/kernel.h
@@ -225,7 +226,7 @@ LIB_H += util/include/linux/string.h
225LIB_H += util/include/linux/types.h 226LIB_H += util/include/linux/types.h
226LIB_H += util/include/linux/linkage.h 227LIB_H += util/include/linux/linkage.h
227LIB_H += util/include/asm/asm-offsets.h 228LIB_H += util/include/asm/asm-offsets.h
228LIB_H += util/include/asm/bug.h 229LIB_H += ../include/asm/bug.h
229LIB_H += util/include/asm/byteorder.h 230LIB_H += util/include/asm/byteorder.h
230LIB_H += util/include/asm/hweight.h 231LIB_H += util/include/asm/hweight.h
231LIB_H += util/include/asm/swab.h 232LIB_H += util/include/asm/swab.h
@@ -312,6 +313,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o
312LIB_OBJS += $(OUTPUT)util/evsel.o 313LIB_OBJS += $(OUTPUT)util/evsel.o
313LIB_OBJS += $(OUTPUT)util/exec_cmd.o 314LIB_OBJS += $(OUTPUT)util/exec_cmd.o
314LIB_OBJS += $(OUTPUT)util/help.o 315LIB_OBJS += $(OUTPUT)util/help.o
316LIB_OBJS += $(OUTPUT)util/kallsyms.o
315LIB_OBJS += $(OUTPUT)util/levenshtein.o 317LIB_OBJS += $(OUTPUT)util/levenshtein.o
316LIB_OBJS += $(OUTPUT)util/parse-options.o 318LIB_OBJS += $(OUTPUT)util/parse-options.o
317LIB_OBJS += $(OUTPUT)util/parse-events.o 319LIB_OBJS += $(OUTPUT)util/parse-events.o
@@ -353,6 +355,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o
353LIB_OBJS += $(OUTPUT)util/trace-event-read.o 355LIB_OBJS += $(OUTPUT)util/trace-event-read.o
354LIB_OBJS += $(OUTPUT)util/trace-event-info.o 356LIB_OBJS += $(OUTPUT)util/trace-event-info.o
355LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o 357LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
358LIB_OBJS += $(OUTPUT)util/trace-event.o
356LIB_OBJS += $(OUTPUT)util/svghelper.o 359LIB_OBJS += $(OUTPUT)util/svghelper.o
357LIB_OBJS += $(OUTPUT)util/sort.o 360LIB_OBJS += $(OUTPUT)util/sort.o
358LIB_OBJS += $(OUTPUT)util/hist.o 361LIB_OBJS += $(OUTPUT)util/hist.o
@@ -438,7 +441,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
438BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 441BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
439BUILTIN_OBJS += $(OUTPUT)builtin-mem.o 442BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
440 443
441PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) 444PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT)
442 445
443# We choose to avoid "if .. else if .. else .. endif endif" 446# We choose to avoid "if .. else if .. else .. endif endif"
444# because maintaining the nesting to match is a pain. If 447# because maintaining the nesting to match is a pain. If
@@ -486,6 +489,7 @@ ifndef NO_SLANG
486 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 489 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
487 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 490 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
488 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 491 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
492 LIB_OBJS += $(OUTPUT)ui/browsers/header.o
489 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 493 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
490 LIB_OBJS += $(OUTPUT)ui/tui/util.o 494 LIB_OBJS += $(OUTPUT)ui/tui/util.o
491 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 495 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
@@ -671,6 +675,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
671$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS 675$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
672 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< 676 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
673 677
678$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS
679 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
680
674$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 681$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
675 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 682 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
676 683
@@ -710,26 +717,33 @@ $(LIB_FILE): $(LIB_OBJS)
710# libtraceevent.a 717# libtraceevent.a
711TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) 718TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
712 719
713$(LIBTRACEEVENT): $(TE_SOURCES) 720LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT)
714 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a 721LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)"
722LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
723
724$(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS
725 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins
715 726
716$(LIBTRACEEVENT)-clean: 727$(LIBTRACEEVENT)-clean:
717 $(call QUIET_CLEAN, libtraceevent) 728 $(call QUIET_CLEAN, libtraceevent)
718 @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null 729 @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
719 730
720LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) 731install-traceevent-plugins: $(LIBTRACEEVENT)
732 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
733
734LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
721 735
722# if subdir is set, we've been called from above so target has been built 736# if subdir is set, we've been called from above so target has been built
723# already 737# already
724$(LIBLK): $(LIBLK_SOURCES) 738$(LIBAPIKFS): $(LIBAPIKFS_SOURCES)
725ifeq ($(subdir),) 739ifeq ($(subdir),)
726 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a 740 $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a
727endif 741endif
728 742
729$(LIBLK)-clean: 743$(LIBAPIKFS)-clean:
730ifeq ($(subdir),) 744ifeq ($(subdir),)
731 $(call QUIET_CLEAN, liblk) 745 $(call QUIET_CLEAN, libapikfs)
732 @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null 746 @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
733endif 747endif
734 748
735help: 749help:
@@ -785,7 +799,7 @@ cscope:
785 799
786### Detect prefix changes 800### Detect prefix changes
787TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 801TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
788 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 802 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ)
789 803
790$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS 804$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
791 @FLAGS='$(TRACK_CFLAGS)'; \ 805 @FLAGS='$(TRACK_CFLAGS)'; \
@@ -840,16 +854,16 @@ ifndef NO_LIBPYTHON
840 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ 854 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
841 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 855 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
842endif 856endif
843 $(call QUIET_INSTALL, bash_completion-script) \ 857 $(call QUIET_INSTALL, perf_completion-script) \
844 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ 858 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
845 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 859 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
846 $(call QUIET_INSTALL, tests) \ 860 $(call QUIET_INSTALL, tests) \
847 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ 861 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
848 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ 862 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
849 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ 863 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
850 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 864 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
851 865
852install: install-bin try-install-man 866install: install-bin try-install-man install-traceevent-plugins
853 867
854install-python_ext: 868install-python_ext:
855 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 869 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
@@ -868,12 +882,11 @@ config-clean:
868 $(call QUIET_CLEAN, config) 882 $(call QUIET_CLEAN, config)
869 @$(MAKE) -C config/feature-checks clean >/dev/null 883 @$(MAKE) -C config/feature-checks clean >/dev/null
870 884
871clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean 885clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
872 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) 886 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
873 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf 887 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
874 $(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)util/*-bison* $(OUTPUT)util/*-flex* 888 $(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)util/*-bison* $(OUTPUT)util/*-flex*
875 $(call QUIET_CLEAN, Documentation) 889 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
876 @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
877 $(python-clean) 890 $(python-clean)
878 891
879# 892#
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index aacef07ebf31..42faf369211c 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -154,8 +154,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
154 } 154 }
155 if (lookup_path(buf)) 155 if (lookup_path(buf))
156 goto out; 156 goto out;
157 free(buf); 157 zfree(&buf);
158 buf = NULL;
159 } 158 }
160 159
161 if (!strcmp(arch, "arm")) 160 if (!strcmp(arch, "arm"))
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4087ab19823c..0da603b79b61 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -69,15 +69,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
69 if (he == NULL) 69 if (he == NULL)
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 ret = 0; 72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 if (he->ms.sym != NULL) {
74 struct annotation *notes = symbol__annotation(he->ms.sym);
75 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
76 return -ENOMEM;
77
78 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
79 }
80
81 evsel->hists.stats.total_period += sample->period; 73 evsel->hists.stats.total_period += sample->period;
82 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 74 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
83 return ret; 75 return ret;
@@ -188,8 +180,7 @@ find_next:
188 * symbol, free he->ms.sym->src to signal we already 180 * symbol, free he->ms.sym->src to signal we already
189 * processed this symbol. 181 * processed this symbol.
190 */ 182 */
191 free(notes->src); 183 zfree(&notes->src);
192 notes->src = NULL;
193 } 184 }
194 } 185 }
195} 186}
@@ -241,7 +232,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
241 perf_session__fprintf_dsos(session, stdout); 232 perf_session__fprintf_dsos(session, stdout);
242 233
243 total_nr_samples = 0; 234 total_nr_samples = 0;
244 list_for_each_entry(pos, &session->evlist->entries, node) { 235 evlist__for_each(session->evlist, pos) {
245 struct hists *hists = &pos->hists; 236 struct hists *hists = &pos->hists;
246 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 237 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
247 238
@@ -373,7 +364,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
373 364
374 if (argc) { 365 if (argc) {
375 /* 366 /*
376 * Special case: if there's an argument left then assume tha 367 * Special case: if there's an argument left then assume that
377 * it's a symbol filter: 368 * it's a symbol filter:
378 */ 369 */
379 if (argc > 1) 370 if (argc > 1)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 3b67ea2444bd..a77e31246c00 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -356,9 +356,10 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
356{ 356{
357 struct perf_evsel *e; 357 struct perf_evsel *e;
358 358
359 list_for_each_entry(e, &evlist->entries, node) 359 evlist__for_each(evlist, e) {
360 if (perf_evsel__match2(evsel, e)) 360 if (perf_evsel__match2(evsel, e))
361 return e; 361 return e;
362 }
362 363
363 return NULL; 364 return NULL;
364} 365}
@@ -367,7 +368,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
367{ 368{
368 struct perf_evsel *evsel; 369 struct perf_evsel *evsel;
369 370
370 list_for_each_entry(evsel, &evlist->entries, node) { 371 evlist__for_each(evlist, evsel) {
371 struct hists *hists = &evsel->hists; 372 struct hists *hists = &evsel->hists;
372 373
373 hists__collapse_resort(hists, NULL); 374 hists__collapse_resort(hists, NULL);
@@ -614,7 +615,7 @@ static void data_process(void)
614 struct perf_evsel *evsel_base; 615 struct perf_evsel *evsel_base;
615 bool first = true; 616 bool first = true;
616 617
617 list_for_each_entry(evsel_base, &evlist_base->entries, node) { 618 evlist__for_each(evlist_base, evsel_base) {
618 struct data__file *d; 619 struct data__file *d;
619 int i; 620 int i;
620 621
@@ -654,7 +655,7 @@ static void data__free(struct data__file *d)
654 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { 655 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
655 struct diff_hpp_fmt *fmt = &d->fmt[col]; 656 struct diff_hpp_fmt *fmt = &d->fmt[col];
656 657
657 free(fmt->header); 658 zfree(&fmt->header);
658 } 659 }
659} 660}
660 661
@@ -769,6 +770,81 @@ static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
769 return ret; 770 return ret;
770} 771}
771 772
773static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
774 struct perf_hpp *hpp, struct hist_entry *he,
775 int comparison_method)
776{
777 struct diff_hpp_fmt *dfmt =
778 container_of(fmt, struct diff_hpp_fmt, fmt);
779 struct hist_entry *pair = get_pair_fmt(he, dfmt);
780 double diff;
781 s64 wdiff;
782 char pfmt[20] = " ";
783
784 if (!pair)
785 goto dummy_print;
786
787 switch (comparison_method) {
788 case COMPUTE_DELTA:
789 if (pair->diff.computed)
790 diff = pair->diff.period_ratio_delta;
791 else
792 diff = compute_delta(he, pair);
793
794 if (fabs(diff) < 0.01)
795 goto dummy_print;
796 scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
797 return percent_color_snprintf(hpp->buf, hpp->size,
798 pfmt, diff);
799 case COMPUTE_RATIO:
800 if (he->dummy)
801 goto dummy_print;
802 if (pair->diff.computed)
803 diff = pair->diff.period_ratio;
804 else
805 diff = compute_ratio(he, pair);
806
807 scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
808 return value_color_snprintf(hpp->buf, hpp->size,
809 pfmt, diff);
810 case COMPUTE_WEIGHTED_DIFF:
811 if (he->dummy)
812 goto dummy_print;
813 if (pair->diff.computed)
814 wdiff = pair->diff.wdiff;
815 else
816 wdiff = compute_wdiff(he, pair);
817
818 scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
819 return color_snprintf(hpp->buf, hpp->size,
820 get_percent_color(wdiff),
821 pfmt, wdiff);
822 default:
823 BUG_ON(1);
824 }
825dummy_print:
826 return scnprintf(hpp->buf, hpp->size, "%*s",
827 dfmt->header_width, pfmt);
828}
829
830static int hpp__color_delta(struct perf_hpp_fmt *fmt,
831 struct perf_hpp *hpp, struct hist_entry *he)
832{
833 return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
834}
835
836static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
837 struct perf_hpp *hpp, struct hist_entry *he)
838{
839 return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
840}
841
842static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
843 struct perf_hpp *hpp, struct hist_entry *he)
844{
845 return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
846}
847
772static void 848static void
773hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) 849hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
774{ 850{
@@ -940,8 +1016,22 @@ static void data__hpp_register(struct data__file *d, int idx)
940 fmt->entry = hpp__entry_global; 1016 fmt->entry = hpp__entry_global;
941 1017
942 /* TODO more colors */ 1018 /* TODO more colors */
943 if (idx == PERF_HPP_DIFF__BASELINE) 1019 switch (idx) {
1020 case PERF_HPP_DIFF__BASELINE:
944 fmt->color = hpp__color_baseline; 1021 fmt->color = hpp__color_baseline;
1022 break;
1023 case PERF_HPP_DIFF__DELTA:
1024 fmt->color = hpp__color_delta;
1025 break;
1026 case PERF_HPP_DIFF__RATIO:
1027 fmt->color = hpp__color_ratio;
1028 break;
1029 case PERF_HPP_DIFF__WEIGHTED_DIFF:
1030 fmt->color = hpp__color_wdiff;
1031 break;
1032 default:
1033 break;
1034 }
945 1035
946 init_header(d, dfmt); 1036 init_header(d, dfmt);
947 perf_hpp__column_register(fmt); 1037 perf_hpp__column_register(fmt);
@@ -1000,8 +1090,7 @@ static int data_init(int argc, const char **argv)
1000 data__files_cnt = argc; 1090 data__files_cnt = argc;
1001 use_default = false; 1091 use_default = false;
1002 } 1092 }
1003 } else if (symbol_conf.default_guest_vmlinux_name || 1093 } else if (perf_guest) {
1004 symbol_conf.default_guest_kallsyms) {
1005 defaults[0] = "perf.data.host"; 1094 defaults[0] = "perf.data.host";
1006 defaults[1] = "perf.data.guest"; 1095 defaults[1] = "perf.data.guest";
1007 } 1096 }
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 20b0f12763b0..c99e0de7e54a 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -29,7 +29,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
29 if (session == NULL) 29 if (session == NULL)
30 return -ENOMEM; 30 return -ENOMEM;
31 31
32 list_for_each_entry(pos, &session->evlist->entries, node) 32 evlist__for_each(session->evlist, pos)
33 perf_evsel__fprintf(pos, details, stdout); 33 perf_evsel__fprintf(pos, details, stdout);
34 34
35 perf_session__delete(session); 35 perf_session__delete(session);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6a2508589460..b3466018bbd7 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -22,14 +22,13 @@
22#include <linux/list.h> 22#include <linux/list.h>
23 23
24struct perf_inject { 24struct perf_inject {
25 struct perf_tool tool; 25 struct perf_tool tool;
26 bool build_ids; 26 bool build_ids;
27 bool sched_stat; 27 bool sched_stat;
28 const char *input_name; 28 const char *input_name;
29 int pipe_output, 29 struct perf_data_file output;
30 output; 30 u64 bytes_written;
31 u64 bytes_written; 31 struct list_head samples;
32 struct list_head samples;
33}; 32};
34 33
35struct event_entry { 34struct event_entry {
@@ -42,21 +41,14 @@ static int perf_event__repipe_synth(struct perf_tool *tool,
42 union perf_event *event) 41 union perf_event *event)
43{ 42{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 43 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 uint32_t size; 44 ssize_t size;
46 void *buf = event;
47 45
48 size = event->header.size; 46 size = perf_data_file__write(&inject->output, event,
49 47 event->header.size);
50 while (size) { 48 if (size < 0)
51 int ret = write(inject->output, buf, size); 49 return -errno;
52 if (ret < 0)
53 return -errno;
54
55 size -= ret;
56 buf += ret;
57 inject->bytes_written += ret;
58 }
59 50
51 inject->bytes_written += size;
60 return 0; 52 return 0;
61} 53}
62 54
@@ -80,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
80 if (ret) 72 if (ret)
81 return ret; 73 return ret;
82 74
83 if (!inject->pipe_output) 75 if (&inject->output.is_pipe)
84 return 0; 76 return 0;
85 77
86 return perf_event__repipe_synth(tool, event); 78 return perf_event__repipe_synth(tool, event);
@@ -355,6 +347,7 @@ static int __cmd_inject(struct perf_inject *inject)
355 .path = inject->input_name, 347 .path = inject->input_name,
356 .mode = PERF_DATA_MODE_READ, 348 .mode = PERF_DATA_MODE_READ,
357 }; 349 };
350 struct perf_data_file *file_out = &inject->output;
358 351
359 signal(SIGINT, sig_handler); 352 signal(SIGINT, sig_handler);
360 353
@@ -376,7 +369,7 @@ static int __cmd_inject(struct perf_inject *inject)
376 369
377 inject->tool.ordered_samples = true; 370 inject->tool.ordered_samples = true;
378 371
379 list_for_each_entry(evsel, &session->evlist->entries, node) { 372 evlist__for_each(session->evlist, evsel) {
380 const char *name = perf_evsel__name(evsel); 373 const char *name = perf_evsel__name(evsel);
381 374
382 if (!strcmp(name, "sched:sched_switch")) { 375 if (!strcmp(name, "sched:sched_switch")) {
@@ -391,14 +384,14 @@ static int __cmd_inject(struct perf_inject *inject)
391 } 384 }
392 } 385 }
393 386
394 if (!inject->pipe_output) 387 if (!file_out->is_pipe)
395 lseek(inject->output, session->header.data_offset, SEEK_SET); 388 lseek(file_out->fd, session->header.data_offset, SEEK_SET);
396 389
397 ret = perf_session__process_events(session, &inject->tool); 390 ret = perf_session__process_events(session, &inject->tool);
398 391
399 if (!inject->pipe_output) { 392 if (!file_out->is_pipe) {
400 session->header.data_size = inject->bytes_written; 393 session->header.data_size = inject->bytes_written;
401 perf_session__write_header(session, session->evlist, inject->output, true); 394 perf_session__write_header(session, session->evlist, file_out->fd, true);
402 } 395 }
403 396
404 perf_session__delete(session); 397 perf_session__delete(session);
@@ -427,14 +420,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
427 }, 420 },
428 .input_name = "-", 421 .input_name = "-",
429 .samples = LIST_HEAD_INIT(inject.samples), 422 .samples = LIST_HEAD_INIT(inject.samples),
423 .output = {
424 .path = "-",
425 .mode = PERF_DATA_MODE_WRITE,
426 },
430 }; 427 };
431 const char *output_name = "-";
432 const struct option options[] = { 428 const struct option options[] = {
433 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 429 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
434 "Inject build-ids into the output stream"), 430 "Inject build-ids into the output stream"),
435 OPT_STRING('i', "input", &inject.input_name, "file", 431 OPT_STRING('i', "input", &inject.input_name, "file",
436 "input file name"), 432 "input file name"),
437 OPT_STRING('o', "output", &output_name, "file", 433 OPT_STRING('o', "output", &inject.output.path, "file",
438 "output file name"), 434 "output file name"),
439 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 435 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
440 "Merge sched-stat and sched-switch for getting events " 436 "Merge sched-stat and sched-switch for getting events "
@@ -456,16 +452,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
456 if (argc) 452 if (argc)
457 usage_with_options(inject_usage, options); 453 usage_with_options(inject_usage, options);
458 454
459 if (!strcmp(output_name, "-")) { 455 if (perf_data_file__open(&inject.output)) {
460 inject.pipe_output = 1; 456 perror("failed to create output file");
461 inject.output = STDOUT_FILENO; 457 return -1;
462 } else {
463 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
464 S_IRUSR | S_IWUSR);
465 if (inject.output < 0) {
466 perror("failed to create output file");
467 return -1;
468 }
469 } 458 }
470 459
471 if (symbol__init() < 0) 460 if (symbol__init() < 0)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index f8bf5f244d77..a7350519c63f 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -13,7 +13,7 @@
13#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/trace-event.h" 14#include "util/trace-event.h"
15#include "util/debug.h" 15#include "util/debug.h"
16#include <lk/debugfs.h> 16#include <api/fs/debugfs.h>
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h" 19#include "util/top.h"
@@ -89,7 +89,7 @@ struct exit_reasons_table {
89 89
90struct perf_kvm_stat { 90struct perf_kvm_stat {
91 struct perf_tool tool; 91 struct perf_tool tool;
92 struct perf_record_opts opts; 92 struct record_opts opts;
93 struct perf_evlist *evlist; 93 struct perf_evlist *evlist;
94 struct perf_session *session; 94 struct perf_session *session;
95 95
@@ -1158,9 +1158,7 @@ out:
1158 if (kvm->timerfd >= 0) 1158 if (kvm->timerfd >= 0)
1159 close(kvm->timerfd); 1159 close(kvm->timerfd);
1160 1160
1161 if (pollfds) 1161 free(pollfds);
1162 free(pollfds);
1163
1164 return err; 1162 return err;
1165} 1163}
1166 1164
@@ -1176,7 +1174,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1176 * Note: exclude_{guest,host} do not apply here. 1174 * Note: exclude_{guest,host} do not apply here.
1177 * This command processes KVM tracepoints from host only 1175 * This command processes KVM tracepoints from host only
1178 */ 1176 */
1179 list_for_each_entry(pos, &evlist->entries, node) { 1177 evlist__for_each(evlist, pos) {
1180 struct perf_event_attr *attr = &pos->attr; 1178 struct perf_event_attr *attr = &pos->attr;
1181 1179
1182 /* make sure these *are* set */ 1180 /* make sure these *are* set */
@@ -1232,7 +1230,7 @@ static int read_events(struct perf_kvm_stat *kvm)
1232 .ordered_samples = true, 1230 .ordered_samples = true,
1233 }; 1231 };
1234 struct perf_data_file file = { 1232 struct perf_data_file file = {
1235 .path = input_name, 1233 .path = kvm->file_name,
1236 .mode = PERF_DATA_MODE_READ, 1234 .mode = PERF_DATA_MODE_READ,
1237 }; 1235 };
1238 1236
@@ -1558,10 +1556,8 @@ out:
1558 if (kvm->session) 1556 if (kvm->session)
1559 perf_session__delete(kvm->session); 1557 perf_session__delete(kvm->session);
1560 kvm->session = NULL; 1558 kvm->session = NULL;
1561 if (kvm->evlist) { 1559 if (kvm->evlist)
1562 perf_evlist__delete_maps(kvm->evlist);
1563 perf_evlist__delete(kvm->evlist); 1560 perf_evlist__delete(kvm->evlist);
1564 }
1565 1561
1566 return err; 1562 return err;
1567} 1563}
@@ -1690,6 +1686,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1690 "file", "file saving guest os /proc/kallsyms"), 1686 "file", "file saving guest os /proc/kallsyms"),
1691 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, 1687 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
1692 "file", "file saving guest os /proc/modules"), 1688 "file", "file saving guest os /proc/modules"),
1689 OPT_INCR('v', "verbose", &verbose,
1690 "be more verbose (show counter open errors, etc)"),
1693 OPT_END() 1691 OPT_END()
1694 }; 1692 };
1695 1693
@@ -1711,12 +1709,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1711 perf_guest = 1; 1709 perf_guest = 1;
1712 1710
1713 if (!file_name) { 1711 if (!file_name) {
1714 if (perf_host && !perf_guest) 1712 file_name = get_filename_for_perf_kvm();
1715 file_name = strdup("perf.data.host");
1716 else if (!perf_host && perf_guest)
1717 file_name = strdup("perf.data.guest");
1718 else
1719 file_name = strdup("perf.data.kvm");
1720 1713
1721 if (!file_name) { 1714 if (!file_name) {
1722 pr_err("Failed to allocate memory for filename\n"); 1715 pr_err("Failed to allocate memory for filename\n");
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 31c00f186da1..2e3ade69a58e 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -62,7 +62,6 @@ static int
62dump_raw_samples(struct perf_tool *tool, 62dump_raw_samples(struct perf_tool *tool,
63 union perf_event *event, 63 union perf_event *event,
64 struct perf_sample *sample, 64 struct perf_sample *sample,
65 struct perf_evsel *evsel __maybe_unused,
66 struct machine *machine) 65 struct machine *machine)
67{ 66{
68 struct perf_mem *mem = container_of(tool, struct perf_mem, tool); 67 struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
@@ -112,10 +111,10 @@ dump_raw_samples(struct perf_tool *tool,
112static int process_sample_event(struct perf_tool *tool, 111static int process_sample_event(struct perf_tool *tool,
113 union perf_event *event, 112 union perf_event *event,
114 struct perf_sample *sample, 113 struct perf_sample *sample,
115 struct perf_evsel *evsel, 114 struct perf_evsel *evsel __maybe_unused,
116 struct machine *machine) 115 struct machine *machine)
117{ 116{
118 return dump_raw_samples(tool, event, sample, evsel, machine); 117 return dump_raw_samples(tool, event, sample, machine);
119} 118}
120 119
121static int report_raw_events(struct perf_mem *mem) 120static int report_raw_events(struct perf_mem *mem)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 6ea9e85bdc00..43ff33d0007b 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
37#include "util/strfilter.h" 37#include "util/strfilter.h"
38#include "util/symbol.h" 38#include "util/symbol.h"
39#include "util/debug.h" 39#include "util/debug.h"
40#include <lk/debugfs.h> 40#include <api/fs/debugfs.h>
41#include "util/parse-options.h" 41#include "util/parse-options.h"
42#include "util/probe-finder.h" 42#include "util/probe-finder.h"
43#include "util/probe-event.h" 43#include "util/probe-event.h"
@@ -169,6 +169,7 @@ static int opt_set_target(const struct option *opt, const char *str,
169 int unset __maybe_unused) 169 int unset __maybe_unused)
170{ 170{
171 int ret = -ENOENT; 171 int ret = -ENOENT;
172 char *tmp;
172 173
173 if (str && !params.target) { 174 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec")) 175 if (!strcmp(opt->long_name, "exec"))
@@ -180,7 +181,19 @@ static int opt_set_target(const struct option *opt, const char *str,
180 else 181 else
181 return ret; 182 return ret;
182 183
183 params.target = str; 184 /* Expand given path to absolute path, except for modulename */
185 if (params.uprobes || strchr(str, '/')) {
186 tmp = realpath(str, NULL);
187 if (!tmp) {
188 pr_warning("Failed to get the absolute path of %s: %m\n", str);
189 return ret;
190 }
191 } else {
192 tmp = strdup(str);
193 if (!tmp)
194 return -ENOMEM;
195 }
196 params.target = tmp;
184 ret = 0; 197 ret = 0;
185 } 198 }
186 199
@@ -411,7 +424,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
411 } 424 }
412 425
413#ifdef HAVE_DWARF_SUPPORT 426#ifdef HAVE_DWARF_SUPPORT
414 if (params.show_lines && !params.uprobes) { 427 if (params.show_lines) {
415 if (params.mod_events) { 428 if (params.mod_events) {
416 pr_err(" Error: Don't use --line with" 429 pr_err(" Error: Don't use --line with"
417 " --add/--del.\n"); 430 " --add/--del.\n");
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 7c8020a32784..07d4cf8d3fd3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -62,9 +62,9 @@ static void __handle_on_exit_funcs(void)
62} 62}
63#endif 63#endif
64 64
65struct perf_record { 65struct record {
66 struct perf_tool tool; 66 struct perf_tool tool;
67 struct perf_record_opts opts; 67 struct record_opts opts;
68 u64 bytes_written; 68 u64 bytes_written;
69 struct perf_data_file file; 69 struct perf_data_file file;
70 struct perf_evlist *evlist; 70 struct perf_evlist *evlist;
@@ -76,46 +76,27 @@ struct perf_record {
76 long samples; 76 long samples;
77}; 77};
78 78
79static int do_write_output(struct perf_record *rec, void *buf, size_t size) 79static int record__write(struct record *rec, void *bf, size_t size)
80{ 80{
81 struct perf_data_file *file = &rec->file; 81 if (perf_data_file__write(rec->session->file, bf, size) < 0) {
82 82 pr_err("failed to write perf data, error: %m\n");
83 while (size) { 83 return -1;
84 ssize_t ret = write(file->fd, buf, size);
85
86 if (ret < 0) {
87 pr_err("failed to write perf data, error: %m\n");
88 return -1;
89 }
90
91 size -= ret;
92 buf += ret;
93
94 rec->bytes_written += ret;
95 } 84 }
96 85
86 rec->bytes_written += size;
97 return 0; 87 return 0;
98} 88}
99 89
100static int write_output(struct perf_record *rec, void *buf, size_t size)
101{
102 return do_write_output(rec, buf, size);
103}
104
105static int process_synthesized_event(struct perf_tool *tool, 90static int process_synthesized_event(struct perf_tool *tool,
106 union perf_event *event, 91 union perf_event *event,
107 struct perf_sample *sample __maybe_unused, 92 struct perf_sample *sample __maybe_unused,
108 struct machine *machine __maybe_unused) 93 struct machine *machine __maybe_unused)
109{ 94{
110 struct perf_record *rec = container_of(tool, struct perf_record, tool); 95 struct record *rec = container_of(tool, struct record, tool);
111 if (write_output(rec, event, event->header.size) < 0) 96 return record__write(rec, event, event->header.size);
112 return -1;
113
114 return 0;
115} 97}
116 98
117static int perf_record__mmap_read(struct perf_record *rec, 99static int record__mmap_read(struct record *rec, struct perf_mmap *md)
118 struct perf_mmap *md)
119{ 100{
120 unsigned int head = perf_mmap__read_head(md); 101 unsigned int head = perf_mmap__read_head(md);
121 unsigned int old = md->prev; 102 unsigned int old = md->prev;
@@ -136,7 +117,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
136 size = md->mask + 1 - (old & md->mask); 117 size = md->mask + 1 - (old & md->mask);
137 old += size; 118 old += size;
138 119
139 if (write_output(rec, buf, size) < 0) { 120 if (record__write(rec, buf, size) < 0) {
140 rc = -1; 121 rc = -1;
141 goto out; 122 goto out;
142 } 123 }
@@ -146,7 +127,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
146 size = head - old; 127 size = head - old;
147 old += size; 128 old += size;
148 129
149 if (write_output(rec, buf, size) < 0) { 130 if (record__write(rec, buf, size) < 0) {
150 rc = -1; 131 rc = -1;
151 goto out; 132 goto out;
152 } 133 }
@@ -171,9 +152,9 @@ static void sig_handler(int sig)
171 signr = sig; 152 signr = sig;
172} 153}
173 154
174static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) 155static void record__sig_exit(int exit_status __maybe_unused, void *arg)
175{ 156{
176 struct perf_record *rec = arg; 157 struct record *rec = arg;
177 int status; 158 int status;
178 159
179 if (rec->evlist->workload.pid > 0) { 160 if (rec->evlist->workload.pid > 0) {
@@ -191,18 +172,18 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
191 signal(signr, SIG_DFL); 172 signal(signr, SIG_DFL);
192} 173}
193 174
194static int perf_record__open(struct perf_record *rec) 175static int record__open(struct record *rec)
195{ 176{
196 char msg[512]; 177 char msg[512];
197 struct perf_evsel *pos; 178 struct perf_evsel *pos;
198 struct perf_evlist *evlist = rec->evlist; 179 struct perf_evlist *evlist = rec->evlist;
199 struct perf_session *session = rec->session; 180 struct perf_session *session = rec->session;
200 struct perf_record_opts *opts = &rec->opts; 181 struct record_opts *opts = &rec->opts;
201 int rc = 0; 182 int rc = 0;
202 183
203 perf_evlist__config(evlist, opts); 184 perf_evlist__config(evlist, opts);
204 185
205 list_for_each_entry(pos, &evlist->entries, node) { 186 evlist__for_each(evlist, pos) {
206try_again: 187try_again:
207 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 188 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
208 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { 189 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
@@ -232,7 +213,7 @@ try_again:
232 "Consider increasing " 213 "Consider increasing "
233 "/proc/sys/kernel/perf_event_mlock_kb,\n" 214 "/proc/sys/kernel/perf_event_mlock_kb,\n"
234 "or try again with a smaller value of -m/--mmap_pages.\n" 215 "or try again with a smaller value of -m/--mmap_pages.\n"
235 "(current value: %d)\n", opts->mmap_pages); 216 "(current value: %u)\n", opts->mmap_pages);
236 rc = -errno; 217 rc = -errno;
237 } else { 218 } else {
238 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 219 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
@@ -247,7 +228,7 @@ out:
247 return rc; 228 return rc;
248} 229}
249 230
250static int process_buildids(struct perf_record *rec) 231static int process_buildids(struct record *rec)
251{ 232{
252 struct perf_data_file *file = &rec->file; 233 struct perf_data_file *file = &rec->file;
253 struct perf_session *session = rec->session; 234 struct perf_session *session = rec->session;
@@ -262,9 +243,9 @@ static int process_buildids(struct perf_record *rec)
262 size, &build_id__mark_dso_hit_ops); 243 size, &build_id__mark_dso_hit_ops);
263} 244}
264 245
265static void perf_record__exit(int status, void *arg) 246static void record__exit(int status, void *arg)
266{ 247{
267 struct perf_record *rec = arg; 248 struct record *rec = arg;
268 struct perf_data_file *file = &rec->file; 249 struct perf_data_file *file = &rec->file;
269 250
270 if (status != 0) 251 if (status != 0)
@@ -320,14 +301,14 @@ static struct perf_event_header finished_round_event = {
320 .type = PERF_RECORD_FINISHED_ROUND, 301 .type = PERF_RECORD_FINISHED_ROUND,
321}; 302};
322 303
323static int perf_record__mmap_read_all(struct perf_record *rec) 304static int record__mmap_read_all(struct record *rec)
324{ 305{
325 int i; 306 int i;
326 int rc = 0; 307 int rc = 0;
327 308
328 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 309 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
329 if (rec->evlist->mmap[i].base) { 310 if (rec->evlist->mmap[i].base) {
330 if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 311 if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
331 rc = -1; 312 rc = -1;
332 goto out; 313 goto out;
333 } 314 }
@@ -335,16 +316,14 @@ static int perf_record__mmap_read_all(struct perf_record *rec)
335 } 316 }
336 317
337 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 318 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
338 rc = write_output(rec, &finished_round_event, 319 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
339 sizeof(finished_round_event));
340 320
341out: 321out:
342 return rc; 322 return rc;
343} 323}
344 324
345static void perf_record__init_features(struct perf_record *rec) 325static void record__init_features(struct record *rec)
346{ 326{
347 struct perf_evlist *evsel_list = rec->evlist;
348 struct perf_session *session = rec->session; 327 struct perf_session *session = rec->session;
349 int feat; 328 int feat;
350 329
@@ -354,32 +333,46 @@ static void perf_record__init_features(struct perf_record *rec)
354 if (rec->no_buildid) 333 if (rec->no_buildid)
355 perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 334 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
356 335
357 if (!have_tracepoints(&evsel_list->entries)) 336 if (!have_tracepoints(&rec->evlist->entries))
358 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 337 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
359 338
360 if (!rec->opts.branch_stack) 339 if (!rec->opts.branch_stack)
361 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 340 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
362} 341}
363 342
364static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 343static volatile int workload_exec_errno;
344
345/*
346 * perf_evlist__prepare_workload will send a SIGUSR1
347 * if the fork fails, since we asked by setting its
348 * want_signal to true.
349 */
350static void workload_exec_failed_signal(int signo, siginfo_t *info,
351 void *ucontext __maybe_unused)
352{
353 workload_exec_errno = info->si_value.sival_int;
354 done = 1;
355 signr = signo;
356 child_finished = 1;
357}
358
359static int __cmd_record(struct record *rec, int argc, const char **argv)
365{ 360{
366 int err; 361 int err;
367 unsigned long waking = 0; 362 unsigned long waking = 0;
368 const bool forks = argc > 0; 363 const bool forks = argc > 0;
369 struct machine *machine; 364 struct machine *machine;
370 struct perf_tool *tool = &rec->tool; 365 struct perf_tool *tool = &rec->tool;
371 struct perf_record_opts *opts = &rec->opts; 366 struct record_opts *opts = &rec->opts;
372 struct perf_evlist *evsel_list = rec->evlist;
373 struct perf_data_file *file = &rec->file; 367 struct perf_data_file *file = &rec->file;
374 struct perf_session *session; 368 struct perf_session *session;
375 bool disabled = false; 369 bool disabled = false;
376 370
377 rec->progname = argv[0]; 371 rec->progname = argv[0];
378 372
379 on_exit(perf_record__sig_exit, rec); 373 on_exit(record__sig_exit, rec);
380 signal(SIGCHLD, sig_handler); 374 signal(SIGCHLD, sig_handler);
381 signal(SIGINT, sig_handler); 375 signal(SIGINT, sig_handler);
382 signal(SIGUSR1, sig_handler);
383 signal(SIGTERM, sig_handler); 376 signal(SIGTERM, sig_handler);
384 377
385 session = perf_session__new(file, false, NULL); 378 session = perf_session__new(file, false, NULL);
@@ -390,37 +383,37 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
390 383
391 rec->session = session; 384 rec->session = session;
392 385
393 perf_record__init_features(rec); 386 record__init_features(rec);
394 387
395 if (forks) { 388 if (forks) {
396 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 389 err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
397 argv, file->is_pipe, 390 argv, file->is_pipe,
398 true); 391 workload_exec_failed_signal);
399 if (err < 0) { 392 if (err < 0) {
400 pr_err("Couldn't run the workload!\n"); 393 pr_err("Couldn't run the workload!\n");
401 goto out_delete_session; 394 goto out_delete_session;
402 } 395 }
403 } 396 }
404 397
405 if (perf_record__open(rec) != 0) { 398 if (record__open(rec) != 0) {
406 err = -1; 399 err = -1;
407 goto out_delete_session; 400 goto out_delete_session;
408 } 401 }
409 402
410 if (!evsel_list->nr_groups) 403 if (!rec->evlist->nr_groups)
411 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 404 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
412 405
413 /* 406 /*
414 * perf_session__delete(session) will be called at perf_record__exit() 407 * perf_session__delete(session) will be called at record__exit()
415 */ 408 */
416 on_exit(perf_record__exit, rec); 409 on_exit(record__exit, rec);
417 410
418 if (file->is_pipe) { 411 if (file->is_pipe) {
419 err = perf_header__write_pipe(file->fd); 412 err = perf_header__write_pipe(file->fd);
420 if (err < 0) 413 if (err < 0)
421 goto out_delete_session; 414 goto out_delete_session;
422 } else { 415 } else {
423 err = perf_session__write_header(session, evsel_list, 416 err = perf_session__write_header(session, rec->evlist,
424 file->fd, false); 417 file->fd, false);
425 if (err < 0) 418 if (err < 0)
426 goto out_delete_session; 419 goto out_delete_session;
@@ -444,7 +437,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
444 goto out_delete_session; 437 goto out_delete_session;
445 } 438 }
446 439
447 if (have_tracepoints(&evsel_list->entries)) { 440 if (have_tracepoints(&rec->evlist->entries)) {
448 /* 441 /*
449 * FIXME err <= 0 here actually means that 442 * FIXME err <= 0 here actually means that
450 * there were no tracepoints so its not really 443 * there were no tracepoints so its not really
@@ -453,7 +446,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
453 * return this more properly and also 446 * return this more properly and also
454 * propagate errors that now are calling die() 447 * propagate errors that now are calling die()
455 */ 448 */
456 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list, 449 err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
457 process_synthesized_event); 450 process_synthesized_event);
458 if (err <= 0) { 451 if (err <= 0) {
459 pr_err("Couldn't record tracing data.\n"); 452 pr_err("Couldn't record tracing data.\n");
@@ -485,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
485 perf_event__synthesize_guest_os, tool); 478 perf_event__synthesize_guest_os, tool);
486 } 479 }
487 480
488 err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads, 481 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
489 process_synthesized_event, opts->sample_address); 482 process_synthesized_event, opts->sample_address);
490 if (err != 0) 483 if (err != 0)
491 goto out_delete_session; 484 goto out_delete_session;
@@ -506,19 +499,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
506 * (apart from group members) have enable_on_exec=1 set, 499 * (apart from group members) have enable_on_exec=1 set,
507 * so don't spoil it by prematurely enabling them. 500 * so don't spoil it by prematurely enabling them.
508 */ 501 */
509 if (!target__none(&opts->target)) 502 if (!target__none(&opts->target) && !opts->initial_delay)
510 perf_evlist__enable(evsel_list); 503 perf_evlist__enable(rec->evlist);
511 504
512 /* 505 /*
513 * Let the child rip 506 * Let the child rip
514 */ 507 */
515 if (forks) 508 if (forks)
516 perf_evlist__start_workload(evsel_list); 509 perf_evlist__start_workload(rec->evlist);
510
511 if (opts->initial_delay) {
512 usleep(opts->initial_delay * 1000);
513 perf_evlist__enable(rec->evlist);
514 }
517 515
518 for (;;) { 516 for (;;) {
519 int hits = rec->samples; 517 int hits = rec->samples;
520 518
521 if (perf_record__mmap_read_all(rec) < 0) { 519 if (record__mmap_read_all(rec) < 0) {
522 err = -1; 520 err = -1;
523 goto out_delete_session; 521 goto out_delete_session;
524 } 522 }
@@ -526,7 +524,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
526 if (hits == rec->samples) { 524 if (hits == rec->samples) {
527 if (done) 525 if (done)
528 break; 526 break;
529 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 527 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
530 waking++; 528 waking++;
531 } 529 }
532 530
@@ -536,11 +534,19 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
536 * disable events in this case. 534 * disable events in this case.
537 */ 535 */
538 if (done && !disabled && !target__none(&opts->target)) { 536 if (done && !disabled && !target__none(&opts->target)) {
539 perf_evlist__disable(evsel_list); 537 perf_evlist__disable(rec->evlist);
540 disabled = true; 538 disabled = true;
541 } 539 }
542 } 540 }
543 541
542 if (forks && workload_exec_errno) {
543 char msg[512];
544 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
545 pr_err("Workload failed: %s\n", emsg);
546 err = -1;
547 goto out_delete_session;
548 }
549
544 if (quiet || signr == SIGUSR1) 550 if (quiet || signr == SIGUSR1)
545 return 0; 551 return 0;
546 552
@@ -677,7 +683,7 @@ static int get_stack_size(char *str, unsigned long *_size)
677} 683}
678#endif /* HAVE_LIBUNWIND_SUPPORT */ 684#endif /* HAVE_LIBUNWIND_SUPPORT */
679 685
680int record_parse_callchain(const char *arg, struct perf_record_opts *opts) 686int record_parse_callchain(const char *arg, struct record_opts *opts)
681{ 687{
682 char *tok, *name, *saveptr = NULL; 688 char *tok, *name, *saveptr = NULL;
683 char *buf; 689 char *buf;
@@ -733,7 +739,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
733 return ret; 739 return ret;
734} 740}
735 741
736static void callchain_debug(struct perf_record_opts *opts) 742static void callchain_debug(struct record_opts *opts)
737{ 743{
738 pr_debug("callchain: type %d\n", opts->call_graph); 744 pr_debug("callchain: type %d\n", opts->call_graph);
739 745
@@ -746,7 +752,7 @@ int record_parse_callchain_opt(const struct option *opt,
746 const char *arg, 752 const char *arg,
747 int unset) 753 int unset)
748{ 754{
749 struct perf_record_opts *opts = opt->value; 755 struct record_opts *opts = opt->value;
750 int ret; 756 int ret;
751 757
752 /* --no-call-graph */ 758 /* --no-call-graph */
@@ -767,7 +773,7 @@ int record_callchain_opt(const struct option *opt,
767 const char *arg __maybe_unused, 773 const char *arg __maybe_unused,
768 int unset __maybe_unused) 774 int unset __maybe_unused)
769{ 775{
770 struct perf_record_opts *opts = opt->value; 776 struct record_opts *opts = opt->value;
771 777
772 if (opts->call_graph == CALLCHAIN_NONE) 778 if (opts->call_graph == CALLCHAIN_NONE)
773 opts->call_graph = CALLCHAIN_FP; 779 opts->call_graph = CALLCHAIN_FP;
@@ -783,8 +789,8 @@ static const char * const record_usage[] = {
783}; 789};
784 790
785/* 791/*
786 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new 792 * XXX Ideally would be local to cmd_record() and passed to a record__new
787 * because we need to have access to it in perf_record__exit, that is called 793 * because we need to have access to it in record__exit, that is called
788 * after cmd_record() exits, but since record_options need to be accessible to 794 * after cmd_record() exits, but since record_options need to be accessible to
789 * builtin-script, leave it here. 795 * builtin-script, leave it here.
790 * 796 *
@@ -792,7 +798,7 @@ static const char * const record_usage[] = {
792 * 798 *
793 * Just say no to tons of global variables, sigh. 799 * Just say no to tons of global variables, sigh.
794 */ 800 */
795static struct perf_record record = { 801static struct record record = {
796 .opts = { 802 .opts = {
797 .mmap_pages = UINT_MAX, 803 .mmap_pages = UINT_MAX,
798 .user_freq = UINT_MAX, 804 .user_freq = UINT_MAX,
@@ -800,6 +806,7 @@ static struct perf_record record = {
800 .freq = 4000, 806 .freq = 4000,
801 .target = { 807 .target = {
802 .uses_mmap = true, 808 .uses_mmap = true,
809 .default_per_cpu = true,
803 }, 810 },
804 }, 811 },
805}; 812};
@@ -815,7 +822,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp";
815/* 822/*
816 * XXX Will stay a global variable till we fix builtin-script.c to stop messing 823 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
817 * with it and switch to use the library functions in perf_evlist that came 824 * with it and switch to use the library functions in perf_evlist that came
818 * from builtin-record.c, i.e. use perf_record_opts, 825 * from builtin-record.c, i.e. use record_opts,
819 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 826 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
820 * using pipes, etc. 827 * using pipes, etc.
821 */ 828 */
@@ -842,8 +849,9 @@ const struct option record_options[] = {
842 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 849 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
843 OPT_STRING('o', "output", &record.file.path, "file", 850 OPT_STRING('o', "output", &record.file.path, "file",
844 "output file name"), 851 "output file name"),
845 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 852 OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
846 "child tasks do not inherit counters"), 853 &record.opts.no_inherit_set,
854 "child tasks do not inherit counters"),
847 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 855 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
848 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 856 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
849 "number of mmap data pages", 857 "number of mmap data pages",
@@ -874,6 +882,8 @@ const struct option record_options[] = {
874 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 882 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
875 "monitor event in cgroup name only", 883 "monitor event in cgroup name only",
876 parse_cgroups), 884 parse_cgroups),
885 OPT_UINTEGER(0, "initial-delay", &record.opts.initial_delay,
886 "ms to wait before starting measurement after program start"),
877 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 887 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
878 "user to profile"), 888 "user to profile"),
879 889
@@ -888,24 +898,21 @@ const struct option record_options[] = {
888 "sample by weight (on special events only)"), 898 "sample by weight (on special events only)"),
889 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, 899 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
890 "sample transaction flags (special events only)"), 900 "sample transaction flags (special events only)"),
891 OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu, 901 OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
892 "force the use of per-cpu mmaps"), 902 "use per-thread mmaps"),
893 OPT_END() 903 OPT_END()
894}; 904};
895 905
896int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 906int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
897{ 907{
898 int err = -ENOMEM; 908 int err = -ENOMEM;
899 struct perf_evlist *evsel_list; 909 struct record *rec = &record;
900 struct perf_record *rec = &record;
901 char errbuf[BUFSIZ]; 910 char errbuf[BUFSIZ];
902 911
903 evsel_list = perf_evlist__new(); 912 rec->evlist = perf_evlist__new();
904 if (evsel_list == NULL) 913 if (rec->evlist == NULL)
905 return -ENOMEM; 914 return -ENOMEM;
906 915
907 rec->evlist = evsel_list;
908
909 argc = parse_options(argc, argv, record_options, record_usage, 916 argc = parse_options(argc, argv, record_options, record_usage,
910 PARSE_OPT_STOP_AT_NON_OPTION); 917 PARSE_OPT_STOP_AT_NON_OPTION);
911 if (!argc && target__none(&rec->opts.target)) 918 if (!argc && target__none(&rec->opts.target))
@@ -932,12 +939,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
932 if (rec->no_buildid_cache || rec->no_buildid) 939 if (rec->no_buildid_cache || rec->no_buildid)
933 disable_buildid_cache(); 940 disable_buildid_cache();
934 941
935 if (evsel_list->nr_entries == 0 && 942 if (rec->evlist->nr_entries == 0 &&
936 perf_evlist__add_default(evsel_list) < 0) { 943 perf_evlist__add_default(rec->evlist) < 0) {
937 pr_err("Not enough memory for event selector list\n"); 944 pr_err("Not enough memory for event selector list\n");
938 goto out_symbol_exit; 945 goto out_symbol_exit;
939 } 946 }
940 947
948 if (rec->opts.target.tid && !rec->opts.no_inherit_set)
949 rec->opts.no_inherit = true;
950
941 err = target__validate(&rec->opts.target); 951 err = target__validate(&rec->opts.target);
942 if (err) { 952 if (err) {
943 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 953 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
@@ -956,20 +966,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
956 } 966 }
957 967
958 err = -ENOMEM; 968 err = -ENOMEM;
959 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 969 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
960 usage_with_options(record_usage, record_options); 970 usage_with_options(record_usage, record_options);
961 971
962 if (perf_record_opts__config(&rec->opts)) { 972 if (record_opts__config(&rec->opts)) {
963 err = -EINVAL; 973 err = -EINVAL;
964 goto out_free_fd; 974 goto out_symbol_exit;
965 } 975 }
966 976
967 err = __cmd_record(&record, argc, argv); 977 err = __cmd_record(&record, argc, argv);
968
969 perf_evlist__munmap(evsel_list);
970 perf_evlist__close(evsel_list);
971out_free_fd:
972 perf_evlist__delete_maps(evsel_list);
973out_symbol_exit: 978out_symbol_exit:
974 symbol__exit(); 979 symbol__exit();
975 return err; 980 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8cf8e66ba594..46864dd7eb83 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -39,7 +39,7 @@
39#include <dlfcn.h> 39#include <dlfcn.h>
40#include <linux/bitmap.h> 40#include <linux/bitmap.h>
41 41
42struct perf_report { 42struct report {
43 struct perf_tool tool; 43 struct perf_tool tool;
44 struct perf_session *session; 44 struct perf_session *session;
45 bool force, use_tui, use_gtk, use_stdio; 45 bool force, use_tui, use_gtk, use_stdio;
@@ -49,6 +49,8 @@ struct perf_report {
49 bool show_threads; 49 bool show_threads;
50 bool inverted_callchain; 50 bool inverted_callchain;
51 bool mem_mode; 51 bool mem_mode;
52 bool header;
53 bool header_only;
52 int max_stack; 54 int max_stack;
53 struct perf_read_values show_threads_values; 55 struct perf_read_values show_threads_values;
54 const char *pretty_printing_style; 56 const char *pretty_printing_style;
@@ -58,14 +60,14 @@ struct perf_report {
58 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 60 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
59}; 61};
60 62
61static int perf_report_config(const char *var, const char *value, void *cb) 63static int report__config(const char *var, const char *value, void *cb)
62{ 64{
63 if (!strcmp(var, "report.group")) { 65 if (!strcmp(var, "report.group")) {
64 symbol_conf.event_group = perf_config_bool(var, value); 66 symbol_conf.event_group = perf_config_bool(var, value);
65 return 0; 67 return 0;
66 } 68 }
67 if (!strcmp(var, "report.percent-limit")) { 69 if (!strcmp(var, "report.percent-limit")) {
68 struct perf_report *rep = cb; 70 struct report *rep = cb;
69 rep->min_percent = strtof(value, NULL); 71 rep->min_percent = strtof(value, NULL);
70 return 0; 72 return 0;
71 } 73 }
@@ -73,31 +75,40 @@ static int perf_report_config(const char *var, const char *value, void *cb)
73 return perf_default_config(var, value, cb); 75 return perf_default_config(var, value, cb);
74} 76}
75 77
76static int perf_report__add_mem_hist_entry(struct perf_tool *tool, 78static int report__resolve_callchain(struct report *rep, struct symbol **parent,
77 struct addr_location *al, 79 struct perf_evsel *evsel, struct addr_location *al,
78 struct perf_sample *sample, 80 struct perf_sample *sample)
79 struct perf_evsel *evsel,
80 struct machine *machine,
81 union perf_event *event)
82{ 81{
83 struct perf_report *rep = container_of(tool, struct perf_report, tool); 82 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
83 return machine__resolve_callchain(al->machine, evsel, al->thread, sample,
84 parent, al, rep->max_stack);
85 }
86 return 0;
87}
88
89static int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
90{
91 if (!symbol_conf.use_callchain)
92 return 0;
93 return callchain_append(he->callchain, &callchain_cursor, sample->period);
94}
95
96static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
97 struct perf_sample *sample, struct perf_evsel *evsel,
98 union perf_event *event)
99{
100 struct report *rep = container_of(tool, struct report, tool);
84 struct symbol *parent = NULL; 101 struct symbol *parent = NULL;
85 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 102 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
86 int err = 0;
87 struct hist_entry *he; 103 struct hist_entry *he;
88 struct mem_info *mi, *mx; 104 struct mem_info *mi, *mx;
89 uint64_t cost; 105 uint64_t cost;
106 int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
90 107
91 if ((sort__has_parent || symbol_conf.use_callchain) && 108 if (err)
92 sample->callchain) { 109 return err;
93 err = machine__resolve_callchain(machine, evsel, al->thread,
94 sample, &parent, al,
95 rep->max_stack);
96 if (err)
97 return err;
98 }
99 110
100 mi = machine__resolve_mem(machine, al->thread, sample, cpumode); 111 mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
101 if (!mi) 112 if (!mi)
102 return -ENOMEM; 113 return -ENOMEM;
103 114
@@ -120,77 +131,36 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
120 if (!he) 131 if (!he)
121 return -ENOMEM; 132 return -ENOMEM;
122 133
123 /* 134 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
124 * In the TUI browser, we are doing integrated annotation, 135 if (err)
125 * so we don't allocate the extra space needed because the stdio 136 goto out;
126 * code will not use it.
127 */
128 if (sort__has_sym && he->ms.sym && use_browser > 0) {
129 struct annotation *notes = symbol__annotation(he->ms.sym);
130
131 assert(evsel != NULL);
132
133 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
134 goto out;
135
136 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
137 if (err)
138 goto out;
139 }
140
141 if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
142 struct annotation *notes;
143 137
144 mx = he->mem_info; 138 mx = he->mem_info;
145 139 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
146 notes = symbol__annotation(mx->daddr.sym); 140 if (err)
147 if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) 141 goto out;
148 goto out;
149
150 err = symbol__inc_addr_samples(mx->daddr.sym,
151 mx->daddr.map,
152 evsel->idx,
153 mx->daddr.al_addr);
154 if (err)
155 goto out;
156 }
157 142
158 evsel->hists.stats.total_period += cost; 143 evsel->hists.stats.total_period += cost;
159 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 144 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
160 err = 0; 145 err = hist_entry__append_callchain(he, sample);
161
162 if (symbol_conf.use_callchain) {
163 err = callchain_append(he->callchain,
164 &callchain_cursor,
165 sample->period);
166 }
167out: 146out:
168 return err; 147 return err;
169} 148}
170 149
171static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 150static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
172 struct addr_location *al, 151 struct perf_sample *sample, struct perf_evsel *evsel)
173 struct perf_sample *sample,
174 struct perf_evsel *evsel,
175 struct machine *machine)
176{ 152{
177 struct perf_report *rep = container_of(tool, struct perf_report, tool); 153 struct report *rep = container_of(tool, struct report, tool);
178 struct symbol *parent = NULL; 154 struct symbol *parent = NULL;
179 int err = 0;
180 unsigned i; 155 unsigned i;
181 struct hist_entry *he; 156 struct hist_entry *he;
182 struct branch_info *bi, *bx; 157 struct branch_info *bi, *bx;
158 int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
183 159
184 if ((sort__has_parent || symbol_conf.use_callchain) 160 if (err)
185 && sample->callchain) { 161 return err;
186 err = machine__resolve_callchain(machine, evsel, al->thread,
187 sample, &parent, al,
188 rep->max_stack);
189 if (err)
190 return err;
191 }
192 162
193 bi = machine__resolve_bstack(machine, al->thread, 163 bi = machine__resolve_bstack(al->machine, al->thread,
194 sample->branch_stack); 164 sample->branch_stack);
195 if (!bi) 165 if (!bi)
196 return -ENOMEM; 166 return -ENOMEM;
@@ -212,35 +182,15 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
212 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, 182 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
213 1, 1, 0); 183 1, 1, 0);
214 if (he) { 184 if (he) {
215 struct annotation *notes;
216 bx = he->branch_info; 185 bx = he->branch_info;
217 if (bx->from.sym && use_browser == 1 && sort__has_sym) { 186 err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
218 notes = symbol__annotation(bx->from.sym); 187 if (err)
219 if (!notes->src 188 goto out;
220 && symbol__alloc_hist(bx->from.sym) < 0) 189
221 goto out; 190 err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
222 191 if (err)
223 err = symbol__inc_addr_samples(bx->from.sym, 192 goto out;
224 bx->from.map,
225 evsel->idx,
226 bx->from.al_addr);
227 if (err)
228 goto out;
229 }
230 193
231 if (bx->to.sym && use_browser == 1 && sort__has_sym) {
232 notes = symbol__annotation(bx->to.sym);
233 if (!notes->src
234 && symbol__alloc_hist(bx->to.sym) < 0)
235 goto out;
236
237 err = symbol__inc_addr_samples(bx->to.sym,
238 bx->to.map,
239 evsel->idx,
240 bx->to.al_addr);
241 if (err)
242 goto out;
243 }
244 evsel->hists.stats.total_period += 1; 194 evsel->hists.stats.total_period += 1;
245 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 195 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
246 } else 196 } else
@@ -252,24 +202,16 @@ out:
252 return err; 202 return err;
253} 203}
254 204
255static int perf_evsel__add_hist_entry(struct perf_tool *tool, 205static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
256 struct perf_evsel *evsel, 206 struct addr_location *al, struct perf_sample *sample)
257 struct addr_location *al,
258 struct perf_sample *sample,
259 struct machine *machine)
260{ 207{
261 struct perf_report *rep = container_of(tool, struct perf_report, tool); 208 struct report *rep = container_of(tool, struct report, tool);
262 struct symbol *parent = NULL; 209 struct symbol *parent = NULL;
263 int err = 0;
264 struct hist_entry *he; 210 struct hist_entry *he;
211 int err = report__resolve_callchain(rep, &parent, evsel, al, sample);
265 212
266 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 213 if (err)
267 err = machine__resolve_callchain(machine, evsel, al->thread, 214 return err;
268 sample, &parent, al,
269 rep->max_stack);
270 if (err)
271 return err;
272 }
273 215
274 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, 216 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
275 sample->period, sample->weight, 217 sample->period, sample->weight,
@@ -277,30 +219,11 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool,
277 if (he == NULL) 219 if (he == NULL)
278 return -ENOMEM; 220 return -ENOMEM;
279 221
280 if (symbol_conf.use_callchain) { 222 err = hist_entry__append_callchain(he, sample);
281 err = callchain_append(he->callchain, 223 if (err)
282 &callchain_cursor, 224 goto out;
283 sample->period);
284 if (err)
285 return err;
286 }
287 /*
288 * Only in the TUI browser we are doing integrated annotation,
289 * so we don't allocated the extra space needed because the stdio
290 * code will not use it.
291 */
292 if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
293 struct annotation *notes = symbol__annotation(he->ms.sym);
294
295 assert(evsel != NULL);
296
297 err = -ENOMEM;
298 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
299 goto out;
300
301 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
302 }
303 225
226 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
304 evsel->hists.stats.total_period += sample->period; 227 evsel->hists.stats.total_period += sample->period;
305 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 228 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
306out: 229out:
@@ -314,13 +237,13 @@ static int process_sample_event(struct perf_tool *tool,
314 struct perf_evsel *evsel, 237 struct perf_evsel *evsel,
315 struct machine *machine) 238 struct machine *machine)
316{ 239{
317 struct perf_report *rep = container_of(tool, struct perf_report, tool); 240 struct report *rep = container_of(tool, struct report, tool);
318 struct addr_location al; 241 struct addr_location al;
319 int ret; 242 int ret;
320 243
321 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 244 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
322 fprintf(stderr, "problem processing %d event, skipping it.\n", 245 pr_debug("problem processing %d event, skipping it.\n",
323 event->header.type); 246 event->header.type);
324 return -1; 247 return -1;
325 } 248 }
326 249
@@ -331,21 +254,18 @@ static int process_sample_event(struct perf_tool *tool,
331 return 0; 254 return 0;
332 255
333 if (sort__mode == SORT_MODE__BRANCH) { 256 if (sort__mode == SORT_MODE__BRANCH) {
334 ret = perf_report__add_branch_hist_entry(tool, &al, sample, 257 ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
335 evsel, machine);
336 if (ret < 0) 258 if (ret < 0)
337 pr_debug("problem adding lbr entry, skipping event\n"); 259 pr_debug("problem adding lbr entry, skipping event\n");
338 } else if (rep->mem_mode == 1) { 260 } else if (rep->mem_mode == 1) {
339 ret = perf_report__add_mem_hist_entry(tool, &al, sample, 261 ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
340 evsel, machine, event);
341 if (ret < 0) 262 if (ret < 0)
342 pr_debug("problem adding mem entry, skipping event\n"); 263 pr_debug("problem adding mem entry, skipping event\n");
343 } else { 264 } else {
344 if (al.map != NULL) 265 if (al.map != NULL)
345 al.map->dso->hit = 1; 266 al.map->dso->hit = 1;
346 267
347 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, 268 ret = report__add_hist_entry(tool, evsel, &al, sample);
348 machine);
349 if (ret < 0) 269 if (ret < 0)
350 pr_debug("problem incrementing symbol period, skipping event\n"); 270 pr_debug("problem incrementing symbol period, skipping event\n");
351 } 271 }
@@ -358,7 +278,7 @@ static int process_read_event(struct perf_tool *tool,
358 struct perf_evsel *evsel, 278 struct perf_evsel *evsel,
359 struct machine *machine __maybe_unused) 279 struct machine *machine __maybe_unused)
360{ 280{
361 struct perf_report *rep = container_of(tool, struct perf_report, tool); 281 struct report *rep = container_of(tool, struct report, tool);
362 282
363 if (rep->show_threads) { 283 if (rep->show_threads) {
364 const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; 284 const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
@@ -377,7 +297,7 @@ static int process_read_event(struct perf_tool *tool,
377} 297}
378 298
379/* For pipe mode, sample_type is not currently set */ 299/* For pipe mode, sample_type is not currently set */
380static int perf_report__setup_sample_type(struct perf_report *rep) 300static int report__setup_sample_type(struct report *rep)
381{ 301{
382 struct perf_session *session = rep->session; 302 struct perf_session *session = rep->session;
383 u64 sample_type = perf_evlist__combined_sample_type(session->evlist); 303 u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
@@ -422,8 +342,7 @@ static void sig_handler(int sig __maybe_unused)
422 session_done = 1; 342 session_done = 1;
423} 343}
424 344
425static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 345static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
426 struct hists *hists,
427 const char *evname, FILE *fp) 346 const char *evname, FILE *fp)
428{ 347{
429 size_t ret; 348 size_t ret;
@@ -460,12 +379,12 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
460} 379}
461 380
462static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 381static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
463 struct perf_report *rep, 382 struct report *rep,
464 const char *help) 383 const char *help)
465{ 384{
466 struct perf_evsel *pos; 385 struct perf_evsel *pos;
467 386
468 list_for_each_entry(pos, &evlist->entries, node) { 387 evlist__for_each(evlist, pos) {
469 struct hists *hists = &pos->hists; 388 struct hists *hists = &pos->hists;
470 const char *evname = perf_evsel__name(pos); 389 const char *evname = perf_evsel__name(pos);
471 390
@@ -473,7 +392,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
473 !perf_evsel__is_group_leader(pos)) 392 !perf_evsel__is_group_leader(pos))
474 continue; 393 continue;
475 394
476 hists__fprintf_nr_sample_events(rep, hists, evname, stdout); 395 hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
477 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); 396 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
478 fprintf(stdout, "\n\n"); 397 fprintf(stdout, "\n\n");
479 } 398 }
@@ -493,43 +412,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
493 return 0; 412 return 0;
494} 413}
495 414
496static int __cmd_report(struct perf_report *rep) 415static void report__warn_kptr_restrict(const struct report *rep)
497{ 416{
498 int ret = -EINVAL; 417 struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
499 u64 nr_samples; 418 struct kmap *kernel_kmap = map__kmap(kernel_map);
500 struct perf_session *session = rep->session;
501 struct perf_evsel *pos;
502 struct map *kernel_map;
503 struct kmap *kernel_kmap;
504 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
505 struct ui_progress prog;
506 struct perf_data_file *file = session->file;
507
508 signal(SIGINT, sig_handler);
509
510 if (rep->cpu_list) {
511 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
512 rep->cpu_bitmap);
513 if (ret)
514 return ret;
515 }
516
517 if (use_browser <= 0)
518 perf_session__fprintf_info(session, stdout, rep->show_full_info);
519
520 if (rep->show_threads)
521 perf_read_values_init(&rep->show_threads_values);
522 419
523 ret = perf_report__setup_sample_type(rep);
524 if (ret)
525 return ret;
526
527 ret = perf_session__process_events(session, &rep->tool);
528 if (ret)
529 return ret;
530
531 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
532 kernel_kmap = map__kmap(kernel_map);
533 if (kernel_map == NULL || 420 if (kernel_map == NULL ||
534 (kernel_map->dso->hit && 421 (kernel_map->dso->hit &&
535 (kernel_kmap->ref_reloc_sym == NULL || 422 (kernel_kmap->ref_reloc_sym == NULL ||
@@ -552,26 +439,73 @@ static int __cmd_report(struct perf_report *rep)
552"Samples in kernel modules can't be resolved as well.\n\n", 439"Samples in kernel modules can't be resolved as well.\n\n",
553 desc); 440 desc);
554 } 441 }
442}
555 443
556 if (verbose > 3) 444static int report__gtk_browse_hists(struct report *rep, const char *help)
557 perf_session__fprintf(session, stdout); 445{
446 int (*hist_browser)(struct perf_evlist *evlist, const char *help,
447 struct hist_browser_timer *timer, float min_pcnt);
558 448
559 if (verbose > 2) 449 hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");
560 perf_session__fprintf_dsos(session, stdout);
561 450
562 if (dump_trace) { 451 if (hist_browser == NULL) {
563 perf_session__fprintf_nr_events(session, stdout); 452 ui__error("GTK browser not found!\n");
564 return 0; 453 return -1;
565 } 454 }
566 455
567 nr_samples = 0; 456 return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
568 list_for_each_entry(pos, &session->evlist->entries, node) 457}
458
459static int report__browse_hists(struct report *rep)
460{
461 int ret;
462 struct perf_session *session = rep->session;
463 struct perf_evlist *evlist = session->evlist;
464 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
465
466 switch (use_browser) {
467 case 1:
468 ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
469 rep->min_percent,
470 &session->header.env);
471 /*
472 * Usually "ret" is the last pressed key, and we only
473 * care if the key notifies us to switch data file.
474 */
475 if (ret != K_SWITCH_INPUT_DATA)
476 ret = 0;
477 break;
478 case 2:
479 ret = report__gtk_browse_hists(rep, help);
480 break;
481 default:
482 ret = perf_evlist__tty_browse_hists(evlist, rep, help);
483 break;
484 }
485
486 return ret;
487}
488
489static u64 report__collapse_hists(struct report *rep)
490{
491 struct ui_progress prog;
492 struct perf_evsel *pos;
493 u64 nr_samples = 0;
494 /*
495 * Count number of histogram entries to use when showing progress,
496 * reusing nr_samples variable.
497 */
498 evlist__for_each(rep->session->evlist, pos)
569 nr_samples += pos->hists.nr_entries; 499 nr_samples += pos->hists.nr_entries;
570 500
571 ui_progress__init(&prog, nr_samples, "Merging related events..."); 501 ui_progress__init(&prog, nr_samples, "Merging related events...");
572 502 /*
503 * Count total number of samples, will be used to check if this
504 * session had any.
505 */
573 nr_samples = 0; 506 nr_samples = 0;
574 list_for_each_entry(pos, &session->evlist->entries, node) { 507
508 evlist__for_each(rep->session->evlist, pos) {
575 struct hists *hists = &pos->hists; 509 struct hists *hists = &pos->hists;
576 510
577 if (pos->idx == 0) 511 if (pos->idx == 0)
@@ -589,8 +523,57 @@ static int __cmd_report(struct perf_report *rep)
589 hists__link(leader_hists, hists); 523 hists__link(leader_hists, hists);
590 } 524 }
591 } 525 }
526
592 ui_progress__finish(); 527 ui_progress__finish();
593 528
529 return nr_samples;
530}
531
532static int __cmd_report(struct report *rep)
533{
534 int ret;
535 u64 nr_samples;
536 struct perf_session *session = rep->session;
537 struct perf_evsel *pos;
538 struct perf_data_file *file = session->file;
539
540 signal(SIGINT, sig_handler);
541
542 if (rep->cpu_list) {
543 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
544 rep->cpu_bitmap);
545 if (ret)
546 return ret;
547 }
548
549 if (rep->show_threads)
550 perf_read_values_init(&rep->show_threads_values);
551
552 ret = report__setup_sample_type(rep);
553 if (ret)
554 return ret;
555
556 ret = perf_session__process_events(session, &rep->tool);
557 if (ret)
558 return ret;
559
560 report__warn_kptr_restrict(rep);
561
562 if (use_browser == 0) {
563 if (verbose > 3)
564 perf_session__fprintf(session, stdout);
565
566 if (verbose > 2)
567 perf_session__fprintf_dsos(session, stdout);
568
569 if (dump_trace) {
570 perf_session__fprintf_nr_events(session, stdout);
571 return 0;
572 }
573 }
574
575 nr_samples = report__collapse_hists(rep);
576
594 if (session_done()) 577 if (session_done())
595 return 0; 578 return 0;
596 579
@@ -599,47 +582,16 @@ static int __cmd_report(struct perf_report *rep)
599 return 0; 582 return 0;
600 } 583 }
601 584
602 list_for_each_entry(pos, &session->evlist->entries, node) 585 evlist__for_each(session->evlist, pos)
603 hists__output_resort(&pos->hists); 586 hists__output_resort(&pos->hists);
604 587
605 if (use_browser > 0) { 588 return report__browse_hists(rep);
606 if (use_browser == 1) {
607 ret = perf_evlist__tui_browse_hists(session->evlist,
608 help, NULL,
609 rep->min_percent,
610 &session->header.env);
611 /*
612 * Usually "ret" is the last pressed key, and we only
613 * care if the key notifies us to switch data file.
614 */
615 if (ret != K_SWITCH_INPUT_DATA)
616 ret = 0;
617
618 } else if (use_browser == 2) {
619 int (*hist_browser)(struct perf_evlist *,
620 const char *,
621 struct hist_browser_timer *,
622 float min_pcnt);
623
624 hist_browser = dlsym(perf_gtk_handle,
625 "perf_evlist__gtk_browse_hists");
626 if (hist_browser == NULL) {
627 ui__error("GTK browser not found!\n");
628 return ret;
629 }
630 hist_browser(session->evlist, help, NULL,
631 rep->min_percent);
632 }
633 } else
634 perf_evlist__tty_browse_hists(session->evlist, rep, help);
635
636 return ret;
637} 589}
638 590
639static int 591static int
640parse_callchain_opt(const struct option *opt, const char *arg, int unset) 592parse_callchain_opt(const struct option *opt, const char *arg, int unset)
641{ 593{
642 struct perf_report *rep = (struct perf_report *)opt->value; 594 struct report *rep = (struct report *)opt->value;
643 char *tok, *tok2; 595 char *tok, *tok2;
644 char *endptr; 596 char *endptr;
645 597
@@ -721,7 +673,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
721 return -1; 673 return -1;
722setup: 674setup:
723 if (callchain_register_param(&callchain_param) < 0) { 675 if (callchain_register_param(&callchain_param) < 0) {
724 fprintf(stderr, "Can't register callchain params\n"); 676 pr_err("Can't register callchain params\n");
725 return -1; 677 return -1;
726 } 678 }
727 return 0; 679 return 0;
@@ -759,7 +711,7 @@ static int
759parse_percent_limit(const struct option *opt, const char *str, 711parse_percent_limit(const struct option *opt, const char *str,
760 int unset __maybe_unused) 712 int unset __maybe_unused)
761{ 713{
762 struct perf_report *rep = opt->value; 714 struct report *rep = opt->value;
763 715
764 rep->min_percent = strtof(str, NULL); 716 rep->min_percent = strtof(str, NULL);
765 return 0; 717 return 0;
@@ -777,7 +729,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
777 "perf report [<options>]", 729 "perf report [<options>]",
778 NULL 730 NULL
779 }; 731 };
780 struct perf_report report = { 732 struct report report = {
781 .tool = { 733 .tool = {
782 .sample = process_sample_event, 734 .sample = process_sample_event,
783 .mmap = perf_event__process_mmap, 735 .mmap = perf_event__process_mmap,
@@ -820,6 +772,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
820 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), 772 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
821 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 773 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
822 "Use the stdio interface"), 774 "Use the stdio interface"),
775 OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
776 OPT_BOOLEAN(0, "header-only", &report.header_only,
777 "Show only data header."),
823 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 778 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
824 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 779 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
825 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 780 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
@@ -890,7 +845,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
890 .mode = PERF_DATA_MODE_READ, 845 .mode = PERF_DATA_MODE_READ,
891 }; 846 };
892 847
893 perf_config(perf_report_config, &report); 848 perf_config(report__config, &report);
894 849
895 argc = parse_options(argc, argv, options, report_usage, 0); 850 argc = parse_options(argc, argv, options, report_usage, 0);
896 851
@@ -940,7 +895,7 @@ repeat:
940 } 895 }
941 if (report.mem_mode) { 896 if (report.mem_mode) {
942 if (sort__mode == SORT_MODE__BRANCH) { 897 if (sort__mode == SORT_MODE__BRANCH) {
943 fprintf(stderr, "branch and mem mode incompatible\n"); 898 pr_err("branch and mem mode incompatible\n");
944 goto error; 899 goto error;
945 } 900 }
946 sort__mode = SORT_MODE__MEMORY; 901 sort__mode = SORT_MODE__MEMORY;
@@ -963,6 +918,10 @@ repeat:
963 goto error; 918 goto error;
964 } 919 }
965 920
921 /* Force tty output for header output. */
922 if (report.header || report.header_only)
923 use_browser = 0;
924
966 if (strcmp(input_name, "-") != 0) 925 if (strcmp(input_name, "-") != 0)
967 setup_browser(true); 926 setup_browser(true);
968 else { 927 else {
@@ -970,6 +929,16 @@ repeat:
970 perf_hpp__init(); 929 perf_hpp__init();
971 } 930 }
972 931
932 if (report.header || report.header_only) {
933 perf_session__fprintf_info(session, stdout,
934 report.show_full_info);
935 if (report.header_only)
936 return 0;
937 } else if (use_browser == 0) {
938 fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
939 stdout);
940 }
941
973 /* 942 /*
974 * Only in the TUI browser we are doing integrated annotation, 943 * Only in the TUI browser we are doing integrated annotation,
975 * so don't allocate extra space that won't be used in the stdio 944 * so don't allocate extra space that won't be used in the stdio
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 0f3c65518a2c..6a76a07b6789 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -469,7 +469,7 @@ static void *thread_func(void *ctx)
469 char comm2[22]; 469 char comm2[22];
470 int fd; 470 int fd;
471 471
472 free(parms); 472 zfree(&parms);
473 473
474 sprintf(comm2, ":%s", this_task->comm); 474 sprintf(comm2, ":%s", this_task->comm);
475 prctl(PR_SET_NAME, comm2); 475 prctl(PR_SET_NAME, comm2);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index baf17989a216..9e9c91f5b7fa 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -43,6 +43,7 @@ enum perf_output_field {
43 PERF_OUTPUT_DSO = 1U << 9, 43 PERF_OUTPUT_DSO = 1U << 9,
44 PERF_OUTPUT_ADDR = 1U << 10, 44 PERF_OUTPUT_ADDR = 1U << 10,
45 PERF_OUTPUT_SYMOFFSET = 1U << 11, 45 PERF_OUTPUT_SYMOFFSET = 1U << 11,
46 PERF_OUTPUT_SRCLINE = 1U << 12,
46}; 47};
47 48
48struct output_option { 49struct output_option {
@@ -61,6 +62,7 @@ struct output_option {
61 {.str = "dso", .field = PERF_OUTPUT_DSO}, 62 {.str = "dso", .field = PERF_OUTPUT_DSO},
62 {.str = "addr", .field = PERF_OUTPUT_ADDR}, 63 {.str = "addr", .field = PERF_OUTPUT_ADDR},
63 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, 64 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
65 {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
64}; 66};
65 67
66/* default set to maintain compatibility with current format */ 68/* default set to maintain compatibility with current format */
@@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
210 "to DSO.\n"); 212 "to DSO.\n");
211 return -EINVAL; 213 return -EINVAL;
212 } 214 }
215 if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
216 pr_err("Display of source line number requested but sample IP is not\n"
217 "selected. Hence, no address to lookup the source line number.\n");
218 return -EINVAL;
219 }
213 220
214 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 221 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
215 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", 222 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
@@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
245 252
246 if (PRINT_FIELD(SYMOFFSET)) 253 if (PRINT_FIELD(SYMOFFSET))
247 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; 254 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
255
256 if (PRINT_FIELD(SRCLINE))
257 output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE;
248} 258}
249 259
250/* 260/*
@@ -280,6 +290,30 @@ static int perf_session__check_output_opt(struct perf_session *session)
280 set_print_ip_opts(&evsel->attr); 290 set_print_ip_opts(&evsel->attr);
281 } 291 }
282 292
293 /*
294 * set default for tracepoints to print symbols only
295 * if callchains are present
296 */
297 if (symbol_conf.use_callchain &&
298 !output[PERF_TYPE_TRACEPOINT].user_set) {
299 struct perf_event_attr *attr;
300
301 j = PERF_TYPE_TRACEPOINT;
302 evsel = perf_session__find_first_evtype(session, j);
303 if (evsel == NULL)
304 goto out;
305
306 attr = &evsel->attr;
307
308 if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {
309 output[j].fields |= PERF_OUTPUT_IP;
310 output[j].fields |= PERF_OUTPUT_SYM;
311 output[j].fields |= PERF_OUTPUT_DSO;
312 set_print_ip_opts(attr);
313 }
314 }
315
316out:
283 return 0; 317 return 0;
284} 318}
285 319
@@ -288,7 +322,6 @@ static void print_sample_start(struct perf_sample *sample,
288 struct perf_evsel *evsel) 322 struct perf_evsel *evsel)
289{ 323{
290 struct perf_event_attr *attr = &evsel->attr; 324 struct perf_event_attr *attr = &evsel->attr;
291 const char *evname = NULL;
292 unsigned long secs; 325 unsigned long secs;
293 unsigned long usecs; 326 unsigned long usecs;
294 unsigned long long nsecs; 327 unsigned long long nsecs;
@@ -323,11 +356,6 @@ static void print_sample_start(struct perf_sample *sample,
323 usecs = nsecs / NSECS_PER_USEC; 356 usecs = nsecs / NSECS_PER_USEC;
324 printf("%5lu.%06lu: ", secs, usecs); 357 printf("%5lu.%06lu: ", secs, usecs);
325 } 358 }
326
327 if (PRINT_FIELD(EVNAME)) {
328 evname = perf_evsel__name(evsel);
329 printf("%s: ", evname ? evname : "[unknown]");
330 }
331} 359}
332 360
333static bool is_bts_event(struct perf_event_attr *attr) 361static bool is_bts_event(struct perf_event_attr *attr)
@@ -395,8 +423,8 @@ static void print_sample_addr(union perf_event *event,
395static void print_sample_bts(union perf_event *event, 423static void print_sample_bts(union perf_event *event,
396 struct perf_sample *sample, 424 struct perf_sample *sample,
397 struct perf_evsel *evsel, 425 struct perf_evsel *evsel,
398 struct machine *machine, 426 struct thread *thread,
399 struct thread *thread) 427 struct addr_location *al)
400{ 428{
401 struct perf_event_attr *attr = &evsel->attr; 429 struct perf_event_attr *attr = &evsel->attr;
402 430
@@ -406,7 +434,7 @@ static void print_sample_bts(union perf_event *event,
406 printf(" "); 434 printf(" ");
407 else 435 else
408 printf("\n"); 436 printf("\n");
409 perf_evsel__print_ip(evsel, event, sample, machine, 437 perf_evsel__print_ip(evsel, sample, al,
410 output[attr->type].print_ip_opts, 438 output[attr->type].print_ip_opts,
411 PERF_MAX_STACK_DEPTH); 439 PERF_MAX_STACK_DEPTH);
412 } 440 }
@@ -417,15 +445,14 @@ static void print_sample_bts(union perf_event *event,
417 if (PRINT_FIELD(ADDR) || 445 if (PRINT_FIELD(ADDR) ||
418 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 446 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
419 !output[attr->type].user_set)) 447 !output[attr->type].user_set))
420 print_sample_addr(event, sample, machine, thread, attr); 448 print_sample_addr(event, sample, al->machine, thread, attr);
421 449
422 printf("\n"); 450 printf("\n");
423} 451}
424 452
425static void process_event(union perf_event *event, struct perf_sample *sample, 453static void process_event(union perf_event *event, struct perf_sample *sample,
426 struct perf_evsel *evsel, struct machine *machine, 454 struct perf_evsel *evsel, struct thread *thread,
427 struct thread *thread, 455 struct addr_location *al)
428 struct addr_location *al __maybe_unused)
429{ 456{
430 struct perf_event_attr *attr = &evsel->attr; 457 struct perf_event_attr *attr = &evsel->attr;
431 458
@@ -434,8 +461,13 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
434 461
435 print_sample_start(sample, thread, evsel); 462 print_sample_start(sample, thread, evsel);
436 463
464 if (PRINT_FIELD(EVNAME)) {
465 const char *evname = perf_evsel__name(evsel);
466 printf("%s: ", evname ? evname : "[unknown]");
467 }
468
437 if (is_bts_event(attr)) { 469 if (is_bts_event(attr)) {
438 print_sample_bts(event, sample, evsel, machine, thread); 470 print_sample_bts(event, sample, evsel, thread, al);
439 return; 471 return;
440 } 472 }
441 473
@@ -443,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
443 event_format__print(evsel->tp_format, sample->cpu, 475 event_format__print(evsel->tp_format, sample->cpu,
444 sample->raw_data, sample->raw_size); 476 sample->raw_data, sample->raw_size);
445 if (PRINT_FIELD(ADDR)) 477 if (PRINT_FIELD(ADDR))
446 print_sample_addr(event, sample, machine, thread, attr); 478 print_sample_addr(event, sample, al->machine, thread, attr);
447 479
448 if (PRINT_FIELD(IP)) { 480 if (PRINT_FIELD(IP)) {
449 if (!symbol_conf.use_callchain) 481 if (!symbol_conf.use_callchain)
@@ -451,7 +483,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
451 else 483 else
452 printf("\n"); 484 printf("\n");
453 485
454 perf_evsel__print_ip(evsel, event, sample, machine, 486 perf_evsel__print_ip(evsel, sample, al,
455 output[attr->type].print_ip_opts, 487 output[attr->type].print_ip_opts,
456 PERF_MAX_STACK_DEPTH); 488 PERF_MAX_STACK_DEPTH);
457 } 489 }
@@ -540,7 +572,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
540 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 572 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
541 return 0; 573 return 0;
542 574
543 scripting_ops->process_event(event, sample, evsel, machine, thread, &al); 575 scripting_ops->process_event(event, sample, evsel, thread, &al);
544 576
545 evsel->hists.stats.total_period += sample->period; 577 evsel->hists.stats.total_period += sample->period;
546 return 0; 578 return 0;
@@ -549,6 +581,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
549struct perf_script { 581struct perf_script {
550 struct perf_tool tool; 582 struct perf_tool tool;
551 struct perf_session *session; 583 struct perf_session *session;
584 bool show_task_events;
585 bool show_mmap_events;
552}; 586};
553 587
554static int process_attr(struct perf_tool *tool, union perf_event *event, 588static int process_attr(struct perf_tool *tool, union perf_event *event,
@@ -569,7 +603,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
569 if (evsel->attr.type >= PERF_TYPE_MAX) 603 if (evsel->attr.type >= PERF_TYPE_MAX)
570 return 0; 604 return 0;
571 605
572 list_for_each_entry(pos, &evlist->entries, node) { 606 evlist__for_each(evlist, pos) {
573 if (pos->attr.type == evsel->attr.type && pos != evsel) 607 if (pos->attr.type == evsel->attr.type && pos != evsel)
574 return 0; 608 return 0;
575 } 609 }
@@ -579,6 +613,163 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
579 return perf_evsel__check_attr(evsel, scr->session); 613 return perf_evsel__check_attr(evsel, scr->session);
580} 614}
581 615
616static int process_comm_event(struct perf_tool *tool,
617 union perf_event *event,
618 struct perf_sample *sample,
619 struct machine *machine)
620{
621 struct thread *thread;
622 struct perf_script *script = container_of(tool, struct perf_script, tool);
623 struct perf_session *session = script->session;
624 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
625 int ret = -1;
626
627 thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid);
628 if (thread == NULL) {
629 pr_debug("problem processing COMM event, skipping it.\n");
630 return -1;
631 }
632
633 if (perf_event__process_comm(tool, event, sample, machine) < 0)
634 goto out;
635
636 if (!evsel->attr.sample_id_all) {
637 sample->cpu = 0;
638 sample->time = 0;
639 sample->tid = event->comm.tid;
640 sample->pid = event->comm.pid;
641 }
642 print_sample_start(sample, thread, evsel);
643 perf_event__fprintf(event, stdout);
644 ret = 0;
645
646out:
647 return ret;
648}
649
650static int process_fork_event(struct perf_tool *tool,
651 union perf_event *event,
652 struct perf_sample *sample,
653 struct machine *machine)
654{
655 struct thread *thread;
656 struct perf_script *script = container_of(tool, struct perf_script, tool);
657 struct perf_session *session = script->session;
658 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
659
660 if (perf_event__process_fork(tool, event, sample, machine) < 0)
661 return -1;
662
663 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
664 if (thread == NULL) {
665 pr_debug("problem processing FORK event, skipping it.\n");
666 return -1;
667 }
668
669 if (!evsel->attr.sample_id_all) {
670 sample->cpu = 0;
671 sample->time = event->fork.time;
672 sample->tid = event->fork.tid;
673 sample->pid = event->fork.pid;
674 }
675 print_sample_start(sample, thread, evsel);
676 perf_event__fprintf(event, stdout);
677
678 return 0;
679}
680static int process_exit_event(struct perf_tool *tool,
681 union perf_event *event,
682 struct perf_sample *sample,
683 struct machine *machine)
684{
685 struct thread *thread;
686 struct perf_script *script = container_of(tool, struct perf_script, tool);
687 struct perf_session *session = script->session;
688 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
689
690 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
691 if (thread == NULL) {
692 pr_debug("problem processing EXIT event, skipping it.\n");
693 return -1;
694 }
695
696 if (!evsel->attr.sample_id_all) {
697 sample->cpu = 0;
698 sample->time = 0;
699 sample->tid = event->comm.tid;
700 sample->pid = event->comm.pid;
701 }
702 print_sample_start(sample, thread, evsel);
703 perf_event__fprintf(event, stdout);
704
705 if (perf_event__process_exit(tool, event, sample, machine) < 0)
706 return -1;
707
708 return 0;
709}
710
711static int process_mmap_event(struct perf_tool *tool,
712 union perf_event *event,
713 struct perf_sample *sample,
714 struct machine *machine)
715{
716 struct thread *thread;
717 struct perf_script *script = container_of(tool, struct perf_script, tool);
718 struct perf_session *session = script->session;
719 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
720
721 if (perf_event__process_mmap(tool, event, sample, machine) < 0)
722 return -1;
723
724 thread = machine__findnew_thread(machine, event->mmap.pid, event->mmap.tid);
725 if (thread == NULL) {
726 pr_debug("problem processing MMAP event, skipping it.\n");
727 return -1;
728 }
729
730 if (!evsel->attr.sample_id_all) {
731 sample->cpu = 0;
732 sample->time = 0;
733 sample->tid = event->mmap.tid;
734 sample->pid = event->mmap.pid;
735 }
736 print_sample_start(sample, thread, evsel);
737 perf_event__fprintf(event, stdout);
738
739 return 0;
740}
741
742static int process_mmap2_event(struct perf_tool *tool,
743 union perf_event *event,
744 struct perf_sample *sample,
745 struct machine *machine)
746{
747 struct thread *thread;
748 struct perf_script *script = container_of(tool, struct perf_script, tool);
749 struct perf_session *session = script->session;
750 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
751
752 if (perf_event__process_mmap2(tool, event, sample, machine) < 0)
753 return -1;
754
755 thread = machine__findnew_thread(machine, event->mmap2.pid, event->mmap2.tid);
756 if (thread == NULL) {
757 pr_debug("problem processing MMAP2 event, skipping it.\n");
758 return -1;
759 }
760
761 if (!evsel->attr.sample_id_all) {
762 sample->cpu = 0;
763 sample->time = 0;
764 sample->tid = event->mmap2.tid;
765 sample->pid = event->mmap2.pid;
766 }
767 print_sample_start(sample, thread, evsel);
768 perf_event__fprintf(event, stdout);
769
770 return 0;
771}
772
582static void sig_handler(int sig __maybe_unused) 773static void sig_handler(int sig __maybe_unused)
583{ 774{
584 session_done = 1; 775 session_done = 1;
@@ -590,6 +781,17 @@ static int __cmd_script(struct perf_script *script)
590 781
591 signal(SIGINT, sig_handler); 782 signal(SIGINT, sig_handler);
592 783
784 /* override event processing functions */
785 if (script->show_task_events) {
786 script->tool.comm = process_comm_event;
787 script->tool.fork = process_fork_event;
788 script->tool.exit = process_exit_event;
789 }
790 if (script->show_mmap_events) {
791 script->tool.mmap = process_mmap_event;
792 script->tool.mmap2 = process_mmap2_event;
793 }
794
593 ret = perf_session__process_events(script->session, &script->tool); 795 ret = perf_session__process_events(script->session, &script->tool);
594 796
595 if (debug_mode) 797 if (debug_mode)
@@ -900,9 +1102,9 @@ static struct script_desc *script_desc__new(const char *name)
900 1102
901static void script_desc__delete(struct script_desc *s) 1103static void script_desc__delete(struct script_desc *s)
902{ 1104{
903 free(s->name); 1105 zfree(&s->name);
904 free(s->half_liner); 1106 zfree(&s->half_liner);
905 free(s->args); 1107 zfree(&s->args);
906 free(s); 1108 free(s);
907} 1109}
908 1110
@@ -1107,8 +1309,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
1107 snprintf(evname, len + 1, "%s", p); 1309 snprintf(evname, len + 1, "%s", p);
1108 1310
1109 match = 0; 1311 match = 0;
1110 list_for_each_entry(pos, 1312 evlist__for_each(session->evlist, pos) {
1111 &session->evlist->entries, node) {
1112 if (!strcmp(perf_evsel__name(pos), evname)) { 1313 if (!strcmp(perf_evsel__name(pos), evname)) {
1113 match = 1; 1314 match = 1;
1114 break; 1315 break;
@@ -1290,6 +1491,8 @@ static int have_cmd(int argc, const char **argv)
1290int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1491int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1291{ 1492{
1292 bool show_full_info = false; 1493 bool show_full_info = false;
1494 bool header = false;
1495 bool header_only = false;
1293 char *rec_script_path = NULL; 1496 char *rec_script_path = NULL;
1294 char *rep_script_path = NULL; 1497 char *rep_script_path = NULL;
1295 struct perf_session *session; 1498 struct perf_session *session;
@@ -1328,6 +1531,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1328 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1531 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1329 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 1532 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
1330 "do various checks like samples ordering and lost events"), 1533 "do various checks like samples ordering and lost events"),
1534 OPT_BOOLEAN(0, "header", &header, "Show data header."),
1535 OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."),
1331 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1536 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1332 "file", "vmlinux pathname"), 1537 "file", "vmlinux pathname"),
1333 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 1538 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
@@ -1352,6 +1557,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1352 "display extended information from perf.data file"), 1557 "display extended information from perf.data file"),
1353 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, 1558 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
1354 "Show the path of [kernel.kallsyms]"), 1559 "Show the path of [kernel.kallsyms]"),
1560 OPT_BOOLEAN('\0', "show-task-events", &script.show_task_events,
1561 "Show the fork/comm/exit events"),
1562 OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,
1563 "Show the mmap events"),
1355 OPT_END() 1564 OPT_END()
1356 }; 1565 };
1357 const char * const script_usage[] = { 1566 const char * const script_usage[] = {
@@ -1540,6 +1749,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1540 if (session == NULL) 1749 if (session == NULL)
1541 return -ENOMEM; 1750 return -ENOMEM;
1542 1751
1752 if (header || header_only) {
1753 perf_session__fprintf_info(session, stdout, show_full_info);
1754 if (header_only)
1755 return 0;
1756 }
1757
1543 script.session = session; 1758 script.session = session;
1544 1759
1545 if (cpu_list) { 1760 if (cpu_list) {
@@ -1547,9 +1762,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1547 return -1; 1762 return -1;
1548 } 1763 }
1549 1764
1550 if (!script_name && !generate_script_lang)
1551 perf_session__fprintf_info(session, stdout, show_full_info);
1552
1553 if (!no_callchain) 1765 if (!no_callchain)
1554 symbol_conf.use_callchain = true; 1766 symbol_conf.use_callchain = true;
1555 else 1767 else
@@ -1588,7 +1800,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1588 return -1; 1800 return -1;
1589 } 1801 }
1590 1802
1591 err = scripting_ops->generate_script(session->pevent, 1803 err = scripting_ops->generate_script(session->tevent.pevent,
1592 "perf-script"); 1804 "perf-script");
1593 goto out; 1805 goto out;
1594 } 1806 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ee0d565f83e3..8b0e1c9234d9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -138,6 +138,7 @@ static const char *post_cmd = NULL;
138static bool sync_run = false; 138static bool sync_run = false;
139static unsigned int interval = 0; 139static unsigned int interval = 0;
140static unsigned int initial_delay = 0; 140static unsigned int initial_delay = 0;
141static unsigned int unit_width = 4; /* strlen("unit") */
141static bool forever = false; 142static bool forever = false;
142static struct timespec ref_time; 143static struct timespec ref_time;
143static struct cpu_map *aggr_map; 144static struct cpu_map *aggr_map;
@@ -184,8 +185,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
184 185
185static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 186static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
186{ 187{
187 free(evsel->priv); 188 zfree(&evsel->priv);
188 evsel->priv = NULL;
189} 189}
190 190
191static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) 191static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
@@ -207,15 +207,14 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
207 207
208static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 208static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
209{ 209{
210 free(evsel->prev_raw_counts); 210 zfree(&evsel->prev_raw_counts);
211 evsel->prev_raw_counts = NULL;
212} 211}
213 212
214static void perf_evlist__free_stats(struct perf_evlist *evlist) 213static void perf_evlist__free_stats(struct perf_evlist *evlist)
215{ 214{
216 struct perf_evsel *evsel; 215 struct perf_evsel *evsel;
217 216
218 list_for_each_entry(evsel, &evlist->entries, node) { 217 evlist__for_each(evlist, evsel) {
219 perf_evsel__free_stat_priv(evsel); 218 perf_evsel__free_stat_priv(evsel);
220 perf_evsel__free_counts(evsel); 219 perf_evsel__free_counts(evsel);
221 perf_evsel__free_prev_raw_counts(evsel); 220 perf_evsel__free_prev_raw_counts(evsel);
@@ -226,7 +225,7 @@ static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
226{ 225{
227 struct perf_evsel *evsel; 226 struct perf_evsel *evsel;
228 227
229 list_for_each_entry(evsel, &evlist->entries, node) { 228 evlist__for_each(evlist, evsel) {
230 if (perf_evsel__alloc_stat_priv(evsel) < 0 || 229 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
231 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || 230 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
232 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) 231 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
@@ -260,7 +259,7 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)
260{ 259{
261 struct perf_evsel *evsel; 260 struct perf_evsel *evsel;
262 261
263 list_for_each_entry(evsel, &evlist->entries, node) { 262 evlist__for_each(evlist, evsel) {
264 perf_evsel__reset_stat_priv(evsel); 263 perf_evsel__reset_stat_priv(evsel);
265 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); 264 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
266 } 265 }
@@ -327,13 +326,13 @@ static struct perf_evsel *nth_evsel(int n)
327 326
328 /* Assumes this only called when evsel_list does not change anymore. */ 327 /* Assumes this only called when evsel_list does not change anymore. */
329 if (!array) { 328 if (!array) {
330 list_for_each_entry(ev, &evsel_list->entries, node) 329 evlist__for_each(evsel_list, ev)
331 array_len++; 330 array_len++;
332 array = malloc(array_len * sizeof(void *)); 331 array = malloc(array_len * sizeof(void *));
333 if (!array) 332 if (!array)
334 exit(ENOMEM); 333 exit(ENOMEM);
335 j = 0; 334 j = 0;
336 list_for_each_entry(ev, &evsel_list->entries, node) 335 evlist__for_each(evsel_list, ev)
337 array[j++] = ev; 336 array[j++] = ev;
338 } 337 }
339 if (n < array_len) 338 if (n < array_len)
@@ -441,13 +440,13 @@ static void print_interval(void)
441 char prefix[64]; 440 char prefix[64];
442 441
443 if (aggr_mode == AGGR_GLOBAL) { 442 if (aggr_mode == AGGR_GLOBAL) {
444 list_for_each_entry(counter, &evsel_list->entries, node) { 443 evlist__for_each(evsel_list, counter) {
445 ps = counter->priv; 444 ps = counter->priv;
446 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 445 memset(ps->res_stats, 0, sizeof(ps->res_stats));
447 read_counter_aggr(counter); 446 read_counter_aggr(counter);
448 } 447 }
449 } else { 448 } else {
450 list_for_each_entry(counter, &evsel_list->entries, node) { 449 evlist__for_each(evsel_list, counter) {
451 ps = counter->priv; 450 ps = counter->priv;
452 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 451 memset(ps->res_stats, 0, sizeof(ps->res_stats));
453 read_counter(counter); 452 read_counter(counter);
@@ -461,17 +460,17 @@ static void print_interval(void)
461 if (num_print_interval == 0 && !csv_output) { 460 if (num_print_interval == 0 && !csv_output) {
462 switch (aggr_mode) { 461 switch (aggr_mode) {
463 case AGGR_SOCKET: 462 case AGGR_SOCKET:
464 fprintf(output, "# time socket cpus counts events\n"); 463 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
465 break; 464 break;
466 case AGGR_CORE: 465 case AGGR_CORE:
467 fprintf(output, "# time core cpus counts events\n"); 466 fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit");
468 break; 467 break;
469 case AGGR_NONE: 468 case AGGR_NONE:
470 fprintf(output, "# time CPU counts events\n"); 469 fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit");
471 break; 470 break;
472 case AGGR_GLOBAL: 471 case AGGR_GLOBAL:
473 default: 472 default:
474 fprintf(output, "# time counts events\n"); 473 fprintf(output, "# time counts %*s events\n", unit_width, "unit");
475 } 474 }
476 } 475 }
477 476
@@ -484,12 +483,12 @@ static void print_interval(void)
484 print_aggr(prefix); 483 print_aggr(prefix);
485 break; 484 break;
486 case AGGR_NONE: 485 case AGGR_NONE:
487 list_for_each_entry(counter, &evsel_list->entries, node) 486 evlist__for_each(evsel_list, counter)
488 print_counter(counter, prefix); 487 print_counter(counter, prefix);
489 break; 488 break;
490 case AGGR_GLOBAL: 489 case AGGR_GLOBAL:
491 default: 490 default:
492 list_for_each_entry(counter, &evsel_list->entries, node) 491 evlist__for_each(evsel_list, counter)
493 print_counter_aggr(counter, prefix); 492 print_counter_aggr(counter, prefix);
494 } 493 }
495 494
@@ -505,17 +504,31 @@ static void handle_initial_delay(void)
505 nthreads = thread_map__nr(evsel_list->threads); 504 nthreads = thread_map__nr(evsel_list->threads);
506 505
507 usleep(initial_delay * 1000); 506 usleep(initial_delay * 1000);
508 list_for_each_entry(counter, &evsel_list->entries, node) 507 evlist__for_each(evsel_list, counter)
509 perf_evsel__enable(counter, ncpus, nthreads); 508 perf_evsel__enable(counter, ncpus, nthreads);
510 } 509 }
511} 510}
512 511
512static volatile int workload_exec_errno;
513
514/*
515 * perf_evlist__prepare_workload will send a SIGUSR1
516 * if the fork fails, since we asked by setting its
517 * want_signal to true.
518 */
519static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info,
520 void *ucontext __maybe_unused)
521{
522 workload_exec_errno = info->si_value.sival_int;
523}
524
513static int __run_perf_stat(int argc, const char **argv) 525static int __run_perf_stat(int argc, const char **argv)
514{ 526{
515 char msg[512]; 527 char msg[512];
516 unsigned long long t0, t1; 528 unsigned long long t0, t1;
517 struct perf_evsel *counter; 529 struct perf_evsel *counter;
518 struct timespec ts; 530 struct timespec ts;
531 size_t l;
519 int status = 0; 532 int status = 0;
520 const bool forks = (argc > 0); 533 const bool forks = (argc > 0);
521 534
@@ -528,8 +541,8 @@ static int __run_perf_stat(int argc, const char **argv)
528 } 541 }
529 542
530 if (forks) { 543 if (forks) {
531 if (perf_evlist__prepare_workload(evsel_list, &target, argv, 544 if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
532 false, false) < 0) { 545 workload_exec_failed_signal) < 0) {
533 perror("failed to prepare workload"); 546 perror("failed to prepare workload");
534 return -1; 547 return -1;
535 } 548 }
@@ -539,7 +552,7 @@ static int __run_perf_stat(int argc, const char **argv)
539 if (group) 552 if (group)
540 perf_evlist__set_leader(evsel_list); 553 perf_evlist__set_leader(evsel_list);
541 554
542 list_for_each_entry(counter, &evsel_list->entries, node) { 555 evlist__for_each(evsel_list, counter) {
543 if (create_perf_stat_counter(counter) < 0) { 556 if (create_perf_stat_counter(counter) < 0) {
544 /* 557 /*
545 * PPC returns ENXIO for HW counters until 2.6.37 558 * PPC returns ENXIO for HW counters until 2.6.37
@@ -565,6 +578,10 @@ static int __run_perf_stat(int argc, const char **argv)
565 return -1; 578 return -1;
566 } 579 }
567 counter->supported = true; 580 counter->supported = true;
581
582 l = strlen(counter->unit);
583 if (l > unit_width)
584 unit_width = l;
568 } 585 }
569 586
570 if (perf_evlist__apply_filters(evsel_list)) { 587 if (perf_evlist__apply_filters(evsel_list)) {
@@ -590,6 +607,13 @@ static int __run_perf_stat(int argc, const char **argv)
590 } 607 }
591 } 608 }
592 wait(&status); 609 wait(&status);
610
611 if (workload_exec_errno) {
612 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
613 pr_err("Workload failed: %s\n", emsg);
614 return -1;
615 }
616
593 if (WIFSIGNALED(status)) 617 if (WIFSIGNALED(status))
594 psignal(WTERMSIG(status), argv[0]); 618 psignal(WTERMSIG(status), argv[0]);
595 } else { 619 } else {
@@ -606,13 +630,13 @@ static int __run_perf_stat(int argc, const char **argv)
606 update_stats(&walltime_nsecs_stats, t1 - t0); 630 update_stats(&walltime_nsecs_stats, t1 - t0);
607 631
608 if (aggr_mode == AGGR_GLOBAL) { 632 if (aggr_mode == AGGR_GLOBAL) {
609 list_for_each_entry(counter, &evsel_list->entries, node) { 633 evlist__for_each(evsel_list, counter) {
610 read_counter_aggr(counter); 634 read_counter_aggr(counter);
611 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 635 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
612 thread_map__nr(evsel_list->threads)); 636 thread_map__nr(evsel_list->threads));
613 } 637 }
614 } else { 638 } else {
615 list_for_each_entry(counter, &evsel_list->entries, node) { 639 evlist__for_each(evsel_list, counter) {
616 read_counter(counter); 640 read_counter(counter);
617 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 641 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
618 } 642 }
@@ -621,7 +645,7 @@ static int __run_perf_stat(int argc, const char **argv)
621 return WEXITSTATUS(status); 645 return WEXITSTATUS(status);
622} 646}
623 647
624static int run_perf_stat(int argc __maybe_unused, const char **argv) 648static int run_perf_stat(int argc, const char **argv)
625{ 649{
626 int ret; 650 int ret;
627 651
@@ -704,14 +728,25 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
704static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 728static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
705{ 729{
706 double msecs = avg / 1e6; 730 double msecs = avg / 1e6;
707 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 731 const char *fmt_v, *fmt_n;
708 char name[25]; 732 char name[25];
709 733
734 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
735 fmt_n = csv_output ? "%s" : "%-25s";
736
710 aggr_printout(evsel, cpu, nr); 737 aggr_printout(evsel, cpu, nr);
711 738
712 scnprintf(name, sizeof(name), "%s%s", 739 scnprintf(name, sizeof(name), "%s%s",
713 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 740 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
714 fprintf(output, fmt, msecs, csv_sep, name); 741
742 fprintf(output, fmt_v, msecs, csv_sep);
743
744 if (csv_output)
745 fprintf(output, "%s%s", evsel->unit, csv_sep);
746 else
747 fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep);
748
749 fprintf(output, fmt_n, name);
715 750
716 if (evsel->cgrp) 751 if (evsel->cgrp)
717 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 752 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,21 +943,31 @@ static void print_ll_cache_misses(int cpu,
908static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 943static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
909{ 944{
910 double total, ratio = 0.0, total2; 945 double total, ratio = 0.0, total2;
946 double sc = evsel->scale;
911 const char *fmt; 947 const char *fmt;
912 948
913 if (csv_output) 949 if (csv_output) {
914 fmt = "%.0f%s%s"; 950 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
915 else if (big_num) 951 } else {
916 fmt = "%'18.0f%s%-25s"; 952 if (big_num)
917 else 953 fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s";
918 fmt = "%18.0f%s%-25s"; 954 else
955 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
956 }
919 957
920 aggr_printout(evsel, cpu, nr); 958 aggr_printout(evsel, cpu, nr);
921 959
922 if (aggr_mode == AGGR_GLOBAL) 960 if (aggr_mode == AGGR_GLOBAL)
923 cpu = 0; 961 cpu = 0;
924 962
925 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel)); 963 fprintf(output, fmt, avg, csv_sep);
964
965 if (evsel->unit)
966 fprintf(output, "%-*s%s",
967 csv_output ? 0 : unit_width,
968 evsel->unit, csv_sep);
969
970 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel));
926 971
927 if (evsel->cgrp) 972 if (evsel->cgrp)
928 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 973 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -941,7 +986,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
941 986
942 if (total && avg) { 987 if (total && avg) {
943 ratio = total / avg; 988 ratio = total / avg;
944 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); 989 fprintf(output, "\n");
990 if (aggr_mode == AGGR_NONE)
991 fprintf(output, " ");
992 fprintf(output, " # %5.2f stalled cycles per insn", ratio);
945 } 993 }
946 994
947 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 995 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -1061,6 +1109,7 @@ static void print_aggr(char *prefix)
1061{ 1109{
1062 struct perf_evsel *counter; 1110 struct perf_evsel *counter;
1063 int cpu, cpu2, s, s2, id, nr; 1111 int cpu, cpu2, s, s2, id, nr;
1112 double uval;
1064 u64 ena, run, val; 1113 u64 ena, run, val;
1065 1114
1066 if (!(aggr_map || aggr_get_id)) 1115 if (!(aggr_map || aggr_get_id))
@@ -1068,7 +1117,7 @@ static void print_aggr(char *prefix)
1068 1117
1069 for (s = 0; s < aggr_map->nr; s++) { 1118 for (s = 0; s < aggr_map->nr; s++) {
1070 id = aggr_map->map[s]; 1119 id = aggr_map->map[s];
1071 list_for_each_entry(counter, &evsel_list->entries, node) { 1120 evlist__for_each(evsel_list, counter) {
1072 val = ena = run = 0; 1121 val = ena = run = 0;
1073 nr = 0; 1122 nr = 0;
1074 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1123 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1087,11 +1136,17 @@ static void print_aggr(char *prefix)
1087 if (run == 0 || ena == 0) { 1136 if (run == 0 || ena == 0) {
1088 aggr_printout(counter, id, nr); 1137 aggr_printout(counter, id, nr);
1089 1138
1090 fprintf(output, "%*s%s%*s", 1139 fprintf(output, "%*s%s",
1091 csv_output ? 0 : 18, 1140 csv_output ? 0 : 18,
1092 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1141 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1093 csv_sep, 1142 csv_sep);
1094 csv_output ? 0 : -24, 1143
1144 fprintf(output, "%-*s%s",
1145 csv_output ? 0 : unit_width,
1146 counter->unit, csv_sep);
1147
1148 fprintf(output, "%*s",
1149 csv_output ? 0 : -25,
1095 perf_evsel__name(counter)); 1150 perf_evsel__name(counter));
1096 1151
1097 if (counter->cgrp) 1152 if (counter->cgrp)
@@ -1101,11 +1156,12 @@ static void print_aggr(char *prefix)
1101 fputc('\n', output); 1156 fputc('\n', output);
1102 continue; 1157 continue;
1103 } 1158 }
1159 uval = val * counter->scale;
1104 1160
1105 if (nsec_counter(counter)) 1161 if (nsec_counter(counter))
1106 nsec_printout(id, nr, counter, val); 1162 nsec_printout(id, nr, counter, uval);
1107 else 1163 else
1108 abs_printout(id, nr, counter, val); 1164 abs_printout(id, nr, counter, uval);
1109 1165
1110 if (!csv_output) { 1166 if (!csv_output) {
1111 print_noise(counter, 1.0); 1167 print_noise(counter, 1.0);
@@ -1128,16 +1184,21 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1128 struct perf_stat *ps = counter->priv; 1184 struct perf_stat *ps = counter->priv;
1129 double avg = avg_stats(&ps->res_stats[0]); 1185 double avg = avg_stats(&ps->res_stats[0]);
1130 int scaled = counter->counts->scaled; 1186 int scaled = counter->counts->scaled;
1187 double uval;
1131 1188
1132 if (prefix) 1189 if (prefix)
1133 fprintf(output, "%s", prefix); 1190 fprintf(output, "%s", prefix);
1134 1191
1135 if (scaled == -1) { 1192 if (scaled == -1) {
1136 fprintf(output, "%*s%s%*s", 1193 fprintf(output, "%*s%s",
1137 csv_output ? 0 : 18, 1194 csv_output ? 0 : 18,
1138 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1195 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1139 csv_sep, 1196 csv_sep);
1140 csv_output ? 0 : -24, 1197 fprintf(output, "%-*s%s",
1198 csv_output ? 0 : unit_width,
1199 counter->unit, csv_sep);
1200 fprintf(output, "%*s",
1201 csv_output ? 0 : -25,
1141 perf_evsel__name(counter)); 1202 perf_evsel__name(counter));
1142 1203
1143 if (counter->cgrp) 1204 if (counter->cgrp)
@@ -1147,10 +1208,12 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1147 return; 1208 return;
1148 } 1209 }
1149 1210
1211 uval = avg * counter->scale;
1212
1150 if (nsec_counter(counter)) 1213 if (nsec_counter(counter))
1151 nsec_printout(-1, 0, counter, avg); 1214 nsec_printout(-1, 0, counter, uval);
1152 else 1215 else
1153 abs_printout(-1, 0, counter, avg); 1216 abs_printout(-1, 0, counter, uval);
1154 1217
1155 print_noise(counter, avg); 1218 print_noise(counter, avg);
1156 1219
@@ -1177,6 +1240,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1177static void print_counter(struct perf_evsel *counter, char *prefix) 1240static void print_counter(struct perf_evsel *counter, char *prefix)
1178{ 1241{
1179 u64 ena, run, val; 1242 u64 ena, run, val;
1243 double uval;
1180 int cpu; 1244 int cpu;
1181 1245
1182 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1246 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1188,14 +1252,20 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1188 fprintf(output, "%s", prefix); 1252 fprintf(output, "%s", prefix);
1189 1253
1190 if (run == 0 || ena == 0) { 1254 if (run == 0 || ena == 0) {
1191 fprintf(output, "CPU%*d%s%*s%s%*s", 1255 fprintf(output, "CPU%*d%s%*s%s",
1192 csv_output ? 0 : -4, 1256 csv_output ? 0 : -4,
1193 perf_evsel__cpus(counter)->map[cpu], csv_sep, 1257 perf_evsel__cpus(counter)->map[cpu], csv_sep,
1194 csv_output ? 0 : 18, 1258 csv_output ? 0 : 18,
1195 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1259 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1196 csv_sep, 1260 csv_sep);
1197 csv_output ? 0 : -24, 1261
1198 perf_evsel__name(counter)); 1262 fprintf(output, "%-*s%s",
1263 csv_output ? 0 : unit_width,
1264 counter->unit, csv_sep);
1265
1266 fprintf(output, "%*s",
1267 csv_output ? 0 : -25,
1268 perf_evsel__name(counter));
1199 1269
1200 if (counter->cgrp) 1270 if (counter->cgrp)
1201 fprintf(output, "%s%s", 1271 fprintf(output, "%s%s",
@@ -1205,10 +1275,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1205 continue; 1275 continue;
1206 } 1276 }
1207 1277
1278 uval = val * counter->scale;
1279
1208 if (nsec_counter(counter)) 1280 if (nsec_counter(counter))
1209 nsec_printout(cpu, 0, counter, val); 1281 nsec_printout(cpu, 0, counter, uval);
1210 else 1282 else
1211 abs_printout(cpu, 0, counter, val); 1283 abs_printout(cpu, 0, counter, uval);
1212 1284
1213 if (!csv_output) { 1285 if (!csv_output) {
1214 print_noise(counter, 1.0); 1286 print_noise(counter, 1.0);
@@ -1256,11 +1328,11 @@ static void print_stat(int argc, const char **argv)
1256 print_aggr(NULL); 1328 print_aggr(NULL);
1257 break; 1329 break;
1258 case AGGR_GLOBAL: 1330 case AGGR_GLOBAL:
1259 list_for_each_entry(counter, &evsel_list->entries, node) 1331 evlist__for_each(evsel_list, counter)
1260 print_counter_aggr(counter, NULL); 1332 print_counter_aggr(counter, NULL);
1261 break; 1333 break;
1262 case AGGR_NONE: 1334 case AGGR_NONE:
1263 list_for_each_entry(counter, &evsel_list->entries, node) 1335 evlist__for_each(evsel_list, counter)
1264 print_counter(counter, NULL); 1336 print_counter(counter, NULL);
1265 break; 1337 break;
1266 default: 1338 default:
@@ -1710,14 +1782,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1710 if (interval && interval < 100) { 1782 if (interval && interval < 100) {
1711 pr_err("print interval must be >= 100ms\n"); 1783 pr_err("print interval must be >= 100ms\n");
1712 parse_options_usage(stat_usage, options, "I", 1); 1784 parse_options_usage(stat_usage, options, "I", 1);
1713 goto out_free_maps; 1785 goto out;
1714 } 1786 }
1715 1787
1716 if (perf_evlist__alloc_stats(evsel_list, interval)) 1788 if (perf_evlist__alloc_stats(evsel_list, interval))
1717 goto out_free_maps; 1789 goto out;
1718 1790
1719 if (perf_stat_init_aggr_mode()) 1791 if (perf_stat_init_aggr_mode())
1720 goto out_free_maps; 1792 goto out;
1721 1793
1722 /* 1794 /*
1723 * We dont want to block the signals - that would cause 1795 * We dont want to block the signals - that would cause
@@ -1749,8 +1821,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1749 print_stat(argc, argv); 1821 print_stat(argc, argv);
1750 1822
1751 perf_evlist__free_stats(evsel_list); 1823 perf_evlist__free_stats(evsel_list);
1752out_free_maps:
1753 perf_evlist__delete_maps(evsel_list);
1754out: 1824out:
1755 perf_evlist__delete(evsel_list); 1825 perf_evlist__delete(evsel_list);
1756 return status; 1826 return status;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 41c9bde2fb67..652af0b66a62 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -41,25 +41,29 @@
41#define SUPPORT_OLD_POWER_EVENTS 1 41#define SUPPORT_OLD_POWER_EVENTS 1
42#define PWR_EVENT_EXIT -1 42#define PWR_EVENT_EXIT -1
43 43
44
45static unsigned int numcpus;
46static u64 min_freq; /* Lowest CPU frequency seen */
47static u64 max_freq; /* Highest CPU frequency seen */
48static u64 turbo_frequency;
49
50static u64 first_time, last_time;
51
52static bool power_only;
53
54
55struct per_pid; 44struct per_pid;
56struct per_pidcomm;
57
58struct cpu_sample;
59struct power_event; 45struct power_event;
60struct wake_event; 46struct wake_event;
61 47
62struct sample_wrapper; 48struct timechart {
49 struct perf_tool tool;
50 struct per_pid *all_data;
51 struct power_event *power_events;
52 struct wake_event *wake_events;
53 int proc_num;
54 unsigned int numcpus;
55 u64 min_freq, /* Lowest CPU frequency seen */
56 max_freq, /* Highest CPU frequency seen */
57 turbo_frequency,
58 first_time, last_time;
59 bool power_only,
60 tasks_only,
61 with_backtrace,
62 topology;
63};
64
65struct per_pidcomm;
66struct cpu_sample;
63 67
64/* 68/*
65 * Datastructure layout: 69 * Datastructure layout:
@@ -124,10 +128,9 @@ struct cpu_sample {
124 u64 end_time; 128 u64 end_time;
125 int type; 129 int type;
126 int cpu; 130 int cpu;
131 const char *backtrace;
127}; 132};
128 133
129static struct per_pid *all_data;
130
131#define CSTATE 1 134#define CSTATE 1
132#define PSTATE 2 135#define PSTATE 2
133 136
@@ -145,12 +148,9 @@ struct wake_event {
145 int waker; 148 int waker;
146 int wakee; 149 int wakee;
147 u64 time; 150 u64 time;
151 const char *backtrace;
148}; 152};
149 153
150static struct power_event *power_events;
151static struct wake_event *wake_events;
152
153struct process_filter;
154struct process_filter { 154struct process_filter {
155 char *name; 155 char *name;
156 int pid; 156 int pid;
@@ -160,9 +160,9 @@ struct process_filter {
160static struct process_filter *process_filter; 160static struct process_filter *process_filter;
161 161
162 162
163static struct per_pid *find_create_pid(int pid) 163static struct per_pid *find_create_pid(struct timechart *tchart, int pid)
164{ 164{
165 struct per_pid *cursor = all_data; 165 struct per_pid *cursor = tchart->all_data;
166 166
167 while (cursor) { 167 while (cursor) {
168 if (cursor->pid == pid) 168 if (cursor->pid == pid)
@@ -172,16 +172,16 @@ static struct per_pid *find_create_pid(int pid)
172 cursor = zalloc(sizeof(*cursor)); 172 cursor = zalloc(sizeof(*cursor));
173 assert(cursor != NULL); 173 assert(cursor != NULL);
174 cursor->pid = pid; 174 cursor->pid = pid;
175 cursor->next = all_data; 175 cursor->next = tchart->all_data;
176 all_data = cursor; 176 tchart->all_data = cursor;
177 return cursor; 177 return cursor;
178} 178}
179 179
180static void pid_set_comm(int pid, char *comm) 180static void pid_set_comm(struct timechart *tchart, int pid, char *comm)
181{ 181{
182 struct per_pid *p; 182 struct per_pid *p;
183 struct per_pidcomm *c; 183 struct per_pidcomm *c;
184 p = find_create_pid(pid); 184 p = find_create_pid(tchart, pid);
185 c = p->all; 185 c = p->all;
186 while (c) { 186 while (c) {
187 if (c->comm && strcmp(c->comm, comm) == 0) { 187 if (c->comm && strcmp(c->comm, comm) == 0) {
@@ -203,14 +203,14 @@ static void pid_set_comm(int pid, char *comm)
203 p->all = c; 203 p->all = c;
204} 204}
205 205
206static void pid_fork(int pid, int ppid, u64 timestamp) 206static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
207{ 207{
208 struct per_pid *p, *pp; 208 struct per_pid *p, *pp;
209 p = find_create_pid(pid); 209 p = find_create_pid(tchart, pid);
210 pp = find_create_pid(ppid); 210 pp = find_create_pid(tchart, ppid);
211 p->ppid = ppid; 211 p->ppid = ppid;
212 if (pp->current && pp->current->comm && !p->current) 212 if (pp->current && pp->current->comm && !p->current)
213 pid_set_comm(pid, pp->current->comm); 213 pid_set_comm(tchart, pid, pp->current->comm);
214 214
215 p->start_time = timestamp; 215 p->start_time = timestamp;
216 if (p->current) { 216 if (p->current) {
@@ -219,23 +219,24 @@ static void pid_fork(int pid, int ppid, u64 timestamp)
219 } 219 }
220} 220}
221 221
222static void pid_exit(int pid, u64 timestamp) 222static void pid_exit(struct timechart *tchart, int pid, u64 timestamp)
223{ 223{
224 struct per_pid *p; 224 struct per_pid *p;
225 p = find_create_pid(pid); 225 p = find_create_pid(tchart, pid);
226 p->end_time = timestamp; 226 p->end_time = timestamp;
227 if (p->current) 227 if (p->current)
228 p->current->end_time = timestamp; 228 p->current->end_time = timestamp;
229} 229}
230 230
231static void 231static void pid_put_sample(struct timechart *tchart, int pid, int type,
232pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) 232 unsigned int cpu, u64 start, u64 end,
233 const char *backtrace)
233{ 234{
234 struct per_pid *p; 235 struct per_pid *p;
235 struct per_pidcomm *c; 236 struct per_pidcomm *c;
236 struct cpu_sample *sample; 237 struct cpu_sample *sample;
237 238
238 p = find_create_pid(pid); 239 p = find_create_pid(tchart, pid);
239 c = p->current; 240 c = p->current;
240 if (!c) { 241 if (!c) {
241 c = zalloc(sizeof(*c)); 242 c = zalloc(sizeof(*c));
@@ -252,6 +253,7 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
252 sample->type = type; 253 sample->type = type;
253 sample->next = c->samples; 254 sample->next = c->samples;
254 sample->cpu = cpu; 255 sample->cpu = cpu;
256 sample->backtrace = backtrace;
255 c->samples = sample; 257 c->samples = sample;
256 258
257 if (sample->type == TYPE_RUNNING && end > start && start > 0) { 259 if (sample->type == TYPE_RUNNING && end > start && start > 0) {
@@ -272,84 +274,47 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 274static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 275static u64 cpus_pstate_state[MAX_CPUS];
274 276
275static int process_comm_event(struct perf_tool *tool __maybe_unused, 277static int process_comm_event(struct perf_tool *tool,
276 union perf_event *event, 278 union perf_event *event,
277 struct perf_sample *sample __maybe_unused, 279 struct perf_sample *sample __maybe_unused,
278 struct machine *machine __maybe_unused) 280 struct machine *machine __maybe_unused)
279{ 281{
280 pid_set_comm(event->comm.tid, event->comm.comm); 282 struct timechart *tchart = container_of(tool, struct timechart, tool);
283 pid_set_comm(tchart, event->comm.tid, event->comm.comm);
281 return 0; 284 return 0;
282} 285}
283 286
284static int process_fork_event(struct perf_tool *tool __maybe_unused, 287static int process_fork_event(struct perf_tool *tool,
285 union perf_event *event, 288 union perf_event *event,
286 struct perf_sample *sample __maybe_unused, 289 struct perf_sample *sample __maybe_unused,
287 struct machine *machine __maybe_unused) 290 struct machine *machine __maybe_unused)
288{ 291{
289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 292 struct timechart *tchart = container_of(tool, struct timechart, tool);
293 pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time);
290 return 0; 294 return 0;
291} 295}
292 296
293static int process_exit_event(struct perf_tool *tool __maybe_unused, 297static int process_exit_event(struct perf_tool *tool,
294 union perf_event *event, 298 union perf_event *event,
295 struct perf_sample *sample __maybe_unused, 299 struct perf_sample *sample __maybe_unused,
296 struct machine *machine __maybe_unused) 300 struct machine *machine __maybe_unused)
297{ 301{
298 pid_exit(event->fork.pid, event->fork.time); 302 struct timechart *tchart = container_of(tool, struct timechart, tool);
303 pid_exit(tchart, event->fork.pid, event->fork.time);
299 return 0; 304 return 0;
300} 305}
301 306
302struct trace_entry {
303 unsigned short type;
304 unsigned char flags;
305 unsigned char preempt_count;
306 int pid;
307 int lock_depth;
308};
309
310#ifdef SUPPORT_OLD_POWER_EVENTS 307#ifdef SUPPORT_OLD_POWER_EVENTS
311static int use_old_power_events; 308static int use_old_power_events;
312struct power_entry_old {
313 struct trace_entry te;
314 u64 type;
315 u64 value;
316 u64 cpu_id;
317};
318#endif 309#endif
319 310
320struct power_processor_entry {
321 struct trace_entry te;
322 u32 state;
323 u32 cpu_id;
324};
325
326#define TASK_COMM_LEN 16
327struct wakeup_entry {
328 struct trace_entry te;
329 char comm[TASK_COMM_LEN];
330 int pid;
331 int prio;
332 int success;
333};
334
335struct sched_switch {
336 struct trace_entry te;
337 char prev_comm[TASK_COMM_LEN];
338 int prev_pid;
339 int prev_prio;
340 long prev_state; /* Arjan weeps. */
341 char next_comm[TASK_COMM_LEN];
342 int next_pid;
343 int next_prio;
344};
345
346static void c_state_start(int cpu, u64 timestamp, int state) 311static void c_state_start(int cpu, u64 timestamp, int state)
347{ 312{
348 cpus_cstate_start_times[cpu] = timestamp; 313 cpus_cstate_start_times[cpu] = timestamp;
349 cpus_cstate_state[cpu] = state; 314 cpus_cstate_state[cpu] = state;
350} 315}
351 316
352static void c_state_end(int cpu, u64 timestamp) 317static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp)
353{ 318{
354 struct power_event *pwr = zalloc(sizeof(*pwr)); 319 struct power_event *pwr = zalloc(sizeof(*pwr));
355 320
@@ -361,12 +326,12 @@ static void c_state_end(int cpu, u64 timestamp)
361 pwr->end_time = timestamp; 326 pwr->end_time = timestamp;
362 pwr->cpu = cpu; 327 pwr->cpu = cpu;
363 pwr->type = CSTATE; 328 pwr->type = CSTATE;
364 pwr->next = power_events; 329 pwr->next = tchart->power_events;
365 330
366 power_events = pwr; 331 tchart->power_events = pwr;
367} 332}
368 333
369static void p_state_change(int cpu, u64 timestamp, u64 new_freq) 334static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
370{ 335{
371 struct power_event *pwr; 336 struct power_event *pwr;
372 337
@@ -382,73 +347,78 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
382 pwr->end_time = timestamp; 347 pwr->end_time = timestamp;
383 pwr->cpu = cpu; 348 pwr->cpu = cpu;
384 pwr->type = PSTATE; 349 pwr->type = PSTATE;
385 pwr->next = power_events; 350 pwr->next = tchart->power_events;
386 351
387 if (!pwr->start_time) 352 if (!pwr->start_time)
388 pwr->start_time = first_time; 353 pwr->start_time = tchart->first_time;
389 354
390 power_events = pwr; 355 tchart->power_events = pwr;
391 356
392 cpus_pstate_state[cpu] = new_freq; 357 cpus_pstate_state[cpu] = new_freq;
393 cpus_pstate_start_times[cpu] = timestamp; 358 cpus_pstate_start_times[cpu] = timestamp;
394 359
395 if ((u64)new_freq > max_freq) 360 if ((u64)new_freq > tchart->max_freq)
396 max_freq = new_freq; 361 tchart->max_freq = new_freq;
397 362
398 if (new_freq < min_freq || min_freq == 0) 363 if (new_freq < tchart->min_freq || tchart->min_freq == 0)
399 min_freq = new_freq; 364 tchart->min_freq = new_freq;
400 365
401 if (new_freq == max_freq - 1000) 366 if (new_freq == tchart->max_freq - 1000)
402 turbo_frequency = max_freq; 367 tchart->turbo_frequency = tchart->max_freq;
403} 368}
404 369
405static void 370static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
406sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te) 371 int waker, int wakee, u8 flags, const char *backtrace)
407{ 372{
408 struct per_pid *p; 373 struct per_pid *p;
409 struct wakeup_entry *wake = (void *)te;
410 struct wake_event *we = zalloc(sizeof(*we)); 374 struct wake_event *we = zalloc(sizeof(*we));
411 375
412 if (!we) 376 if (!we)
413 return; 377 return;
414 378
415 we->time = timestamp; 379 we->time = timestamp;
416 we->waker = pid; 380 we->waker = waker;
381 we->backtrace = backtrace;
417 382
418 if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ)) 383 if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ))
419 we->waker = -1; 384 we->waker = -1;
420 385
421 we->wakee = wake->pid; 386 we->wakee = wakee;
422 we->next = wake_events; 387 we->next = tchart->wake_events;
423 wake_events = we; 388 tchart->wake_events = we;
424 p = find_create_pid(we->wakee); 389 p = find_create_pid(tchart, we->wakee);
425 390
426 if (p && p->current && p->current->state == TYPE_NONE) { 391 if (p && p->current && p->current->state == TYPE_NONE) {
427 p->current->state_since = timestamp; 392 p->current->state_since = timestamp;
428 p->current->state = TYPE_WAITING; 393 p->current->state = TYPE_WAITING;
429 } 394 }
430 if (p && p->current && p->current->state == TYPE_BLOCKED) { 395 if (p && p->current && p->current->state == TYPE_BLOCKED) {
431 pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp); 396 pid_put_sample(tchart, p->pid, p->current->state, cpu,
397 p->current->state_since, timestamp, NULL);
432 p->current->state_since = timestamp; 398 p->current->state_since = timestamp;
433 p->current->state = TYPE_WAITING; 399 p->current->state = TYPE_WAITING;
434 } 400 }
435} 401}
436 402
437static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) 403static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
404 int prev_pid, int next_pid, u64 prev_state,
405 const char *backtrace)
438{ 406{
439 struct per_pid *p = NULL, *prev_p; 407 struct per_pid *p = NULL, *prev_p;
440 struct sched_switch *sw = (void *)te;
441
442 408
443 prev_p = find_create_pid(sw->prev_pid); 409 prev_p = find_create_pid(tchart, prev_pid);
444 410
445 p = find_create_pid(sw->next_pid); 411 p = find_create_pid(tchart, next_pid);
446 412
447 if (prev_p->current && prev_p->current->state != TYPE_NONE) 413 if (prev_p->current && prev_p->current->state != TYPE_NONE)
448 pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp); 414 pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
415 prev_p->current->state_since, timestamp,
416 backtrace);
449 if (p && p->current) { 417 if (p && p->current) {
450 if (p->current->state != TYPE_NONE) 418 if (p->current->state != TYPE_NONE)
451 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); 419 pid_put_sample(tchart, next_pid, p->current->state, cpu,
420 p->current->state_since, timestamp,
421 backtrace);
452 422
453 p->current->state_since = timestamp; 423 p->current->state_since = timestamp;
454 p->current->state = TYPE_RUNNING; 424 p->current->state = TYPE_RUNNING;
@@ -457,109 +427,211 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
457 if (prev_p->current) { 427 if (prev_p->current) {
458 prev_p->current->state = TYPE_NONE; 428 prev_p->current->state = TYPE_NONE;
459 prev_p->current->state_since = timestamp; 429 prev_p->current->state_since = timestamp;
460 if (sw->prev_state & 2) 430 if (prev_state & 2)
461 prev_p->current->state = TYPE_BLOCKED; 431 prev_p->current->state = TYPE_BLOCKED;
462 if (sw->prev_state == 0) 432 if (prev_state == 0)
463 prev_p->current->state = TYPE_WAITING; 433 prev_p->current->state = TYPE_WAITING;
464 } 434 }
465} 435}
466 436
467typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 437static const char *cat_backtrace(union perf_event *event,
468 struct perf_sample *sample); 438 struct perf_sample *sample,
439 struct machine *machine)
440{
441 struct addr_location al;
442 unsigned int i;
443 char *p = NULL;
444 size_t p_len;
445 u8 cpumode = PERF_RECORD_MISC_USER;
446 struct addr_location tal;
447 struct ip_callchain *chain = sample->callchain;
448 FILE *f = open_memstream(&p, &p_len);
449
450 if (!f) {
451 perror("open_memstream error");
452 return NULL;
453 }
454
455 if (!chain)
456 goto exit;
469 457
470static int process_sample_event(struct perf_tool *tool __maybe_unused, 458 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
471 union perf_event *event __maybe_unused, 459 fprintf(stderr, "problem processing %d event, skipping it.\n",
460 event->header.type);
461 goto exit;
462 }
463
464 for (i = 0; i < chain->nr; i++) {
465 u64 ip;
466
467 if (callchain_param.order == ORDER_CALLEE)
468 ip = chain->ips[i];
469 else
470 ip = chain->ips[chain->nr - i - 1];
471
472 if (ip >= PERF_CONTEXT_MAX) {
473 switch (ip) {
474 case PERF_CONTEXT_HV:
475 cpumode = PERF_RECORD_MISC_HYPERVISOR;
476 break;
477 case PERF_CONTEXT_KERNEL:
478 cpumode = PERF_RECORD_MISC_KERNEL;
479 break;
480 case PERF_CONTEXT_USER:
481 cpumode = PERF_RECORD_MISC_USER;
482 break;
483 default:
484 pr_debug("invalid callchain context: "
485 "%"PRId64"\n", (s64) ip);
486
487 /*
488 * It seems the callchain is corrupted.
489 * Discard all.
490 */
491 zfree(&p);
492 goto exit;
493 }
494 continue;
495 }
496
497 tal.filtered = false;
498 thread__find_addr_location(al.thread, machine, cpumode,
499 MAP__FUNCTION, ip, &tal);
500
501 if (tal.sym)
502 fprintf(f, "..... %016" PRIx64 " %s\n", ip,
503 tal.sym->name);
504 else
505 fprintf(f, "..... %016" PRIx64 "\n", ip);
506 }
507
508exit:
509 fclose(f);
510
511 return p;
512}
513
514typedef int (*tracepoint_handler)(struct timechart *tchart,
515 struct perf_evsel *evsel,
516 struct perf_sample *sample,
517 const char *backtrace);
518
519static int process_sample_event(struct perf_tool *tool,
520 union perf_event *event,
472 struct perf_sample *sample, 521 struct perf_sample *sample,
473 struct perf_evsel *evsel, 522 struct perf_evsel *evsel,
474 struct machine *machine __maybe_unused) 523 struct machine *machine)
475{ 524{
525 struct timechart *tchart = container_of(tool, struct timechart, tool);
526
476 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 527 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
477 if (!first_time || first_time > sample->time) 528 if (!tchart->first_time || tchart->first_time > sample->time)
478 first_time = sample->time; 529 tchart->first_time = sample->time;
479 if (last_time < sample->time) 530 if (tchart->last_time < sample->time)
480 last_time = sample->time; 531 tchart->last_time = sample->time;
481 } 532 }
482 533
483 if (sample->cpu > numcpus)
484 numcpus = sample->cpu;
485
486 if (evsel->handler != NULL) { 534 if (evsel->handler != NULL) {
487 tracepoint_handler f = evsel->handler; 535 tracepoint_handler f = evsel->handler;
488 return f(evsel, sample); 536 return f(tchart, evsel, sample,
537 cat_backtrace(event, sample, machine));
489 } 538 }
490 539
491 return 0; 540 return 0;
492} 541}
493 542
494static int 543static int
495process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused, 544process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
496 struct perf_sample *sample) 545 struct perf_evsel *evsel,
546 struct perf_sample *sample,
547 const char *backtrace __maybe_unused)
497{ 548{
498 struct power_processor_entry *ppe = sample->raw_data; 549 u32 state = perf_evsel__intval(evsel, sample, "state");
550 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
499 551
500 if (ppe->state == (u32) PWR_EVENT_EXIT) 552 if (state == (u32)PWR_EVENT_EXIT)
501 c_state_end(ppe->cpu_id, sample->time); 553 c_state_end(tchart, cpu_id, sample->time);
502 else 554 else
503 c_state_start(ppe->cpu_id, sample->time, ppe->state); 555 c_state_start(cpu_id, sample->time, state);
504 return 0; 556 return 0;
505} 557}
506 558
507static int 559static int
508process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused, 560process_sample_cpu_frequency(struct timechart *tchart,
509 struct perf_sample *sample) 561 struct perf_evsel *evsel,
562 struct perf_sample *sample,
563 const char *backtrace __maybe_unused)
510{ 564{
511 struct power_processor_entry *ppe = sample->raw_data; 565 u32 state = perf_evsel__intval(evsel, sample, "state");
566 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
512 567
513 p_state_change(ppe->cpu_id, sample->time, ppe->state); 568 p_state_change(tchart, cpu_id, sample->time, state);
514 return 0; 569 return 0;
515} 570}
516 571
517static int 572static int
518process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused, 573process_sample_sched_wakeup(struct timechart *tchart,
519 struct perf_sample *sample) 574 struct perf_evsel *evsel,
575 struct perf_sample *sample,
576 const char *backtrace)
520{ 577{
521 struct trace_entry *te = sample->raw_data; 578 u8 flags = perf_evsel__intval(evsel, sample, "common_flags");
579 int waker = perf_evsel__intval(evsel, sample, "common_pid");
580 int wakee = perf_evsel__intval(evsel, sample, "pid");
522 581
523 sched_wakeup(sample->cpu, sample->time, sample->pid, te); 582 sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
524 return 0; 583 return 0;
525} 584}
526 585
527static int 586static int
528process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused, 587process_sample_sched_switch(struct timechart *tchart,
529 struct perf_sample *sample) 588 struct perf_evsel *evsel,
589 struct perf_sample *sample,
590 const char *backtrace)
530{ 591{
531 struct trace_entry *te = sample->raw_data; 592 int prev_pid = perf_evsel__intval(evsel, sample, "prev_pid");
593 int next_pid = perf_evsel__intval(evsel, sample, "next_pid");
594 u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
532 595
533 sched_switch(sample->cpu, sample->time, te); 596 sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
597 prev_state, backtrace);
534 return 0; 598 return 0;
535} 599}
536 600
537#ifdef SUPPORT_OLD_POWER_EVENTS 601#ifdef SUPPORT_OLD_POWER_EVENTS
538static int 602static int
539process_sample_power_start(struct perf_evsel *evsel __maybe_unused, 603process_sample_power_start(struct timechart *tchart __maybe_unused,
540 struct perf_sample *sample) 604 struct perf_evsel *evsel,
605 struct perf_sample *sample,
606 const char *backtrace __maybe_unused)
541{ 607{
542 struct power_entry_old *peo = sample->raw_data; 608 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
609 u64 value = perf_evsel__intval(evsel, sample, "value");
543 610
544 c_state_start(peo->cpu_id, sample->time, peo->value); 611 c_state_start(cpu_id, sample->time, value);
545 return 0; 612 return 0;
546} 613}
547 614
548static int 615static int
549process_sample_power_end(struct perf_evsel *evsel __maybe_unused, 616process_sample_power_end(struct timechart *tchart,
550 struct perf_sample *sample) 617 struct perf_evsel *evsel __maybe_unused,
618 struct perf_sample *sample,
619 const char *backtrace __maybe_unused)
551{ 620{
552 c_state_end(sample->cpu, sample->time); 621 c_state_end(tchart, sample->cpu, sample->time);
553 return 0; 622 return 0;
554} 623}
555 624
556static int 625static int
557process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, 626process_sample_power_frequency(struct timechart *tchart,
558 struct perf_sample *sample) 627 struct perf_evsel *evsel,
628 struct perf_sample *sample,
629 const char *backtrace __maybe_unused)
559{ 630{
560 struct power_entry_old *peo = sample->raw_data; 631 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
632 u64 value = perf_evsel__intval(evsel, sample, "value");
561 633
562 p_state_change(peo->cpu_id, sample->time, peo->value); 634 p_state_change(tchart, cpu_id, sample->time, value);
563 return 0; 635 return 0;
564} 636}
565#endif /* SUPPORT_OLD_POWER_EVENTS */ 637#endif /* SUPPORT_OLD_POWER_EVENTS */
@@ -568,12 +640,12 @@ process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
568 * After the last sample we need to wrap up the current C/P state 640 * After the last sample we need to wrap up the current C/P state
569 * and close out each CPU for these. 641 * and close out each CPU for these.
570 */ 642 */
571static void end_sample_processing(void) 643static void end_sample_processing(struct timechart *tchart)
572{ 644{
573 u64 cpu; 645 u64 cpu;
574 struct power_event *pwr; 646 struct power_event *pwr;
575 647
576 for (cpu = 0; cpu <= numcpus; cpu++) { 648 for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
577 /* C state */ 649 /* C state */
578#if 0 650#if 0
579 pwr = zalloc(sizeof(*pwr)); 651 pwr = zalloc(sizeof(*pwr));
@@ -582,12 +654,12 @@ static void end_sample_processing(void)
582 654
583 pwr->state = cpus_cstate_state[cpu]; 655 pwr->state = cpus_cstate_state[cpu];
584 pwr->start_time = cpus_cstate_start_times[cpu]; 656 pwr->start_time = cpus_cstate_start_times[cpu];
585 pwr->end_time = last_time; 657 pwr->end_time = tchart->last_time;
586 pwr->cpu = cpu; 658 pwr->cpu = cpu;
587 pwr->type = CSTATE; 659 pwr->type = CSTATE;
588 pwr->next = power_events; 660 pwr->next = tchart->power_events;
589 661
590 power_events = pwr; 662 tchart->power_events = pwr;
591#endif 663#endif
592 /* P state */ 664 /* P state */
593 665
@@ -597,32 +669,32 @@ static void end_sample_processing(void)
597 669
598 pwr->state = cpus_pstate_state[cpu]; 670 pwr->state = cpus_pstate_state[cpu];
599 pwr->start_time = cpus_pstate_start_times[cpu]; 671 pwr->start_time = cpus_pstate_start_times[cpu];
600 pwr->end_time = last_time; 672 pwr->end_time = tchart->last_time;
601 pwr->cpu = cpu; 673 pwr->cpu = cpu;
602 pwr->type = PSTATE; 674 pwr->type = PSTATE;
603 pwr->next = power_events; 675 pwr->next = tchart->power_events;
604 676
605 if (!pwr->start_time) 677 if (!pwr->start_time)
606 pwr->start_time = first_time; 678 pwr->start_time = tchart->first_time;
607 if (!pwr->state) 679 if (!pwr->state)
608 pwr->state = min_freq; 680 pwr->state = tchart->min_freq;
609 power_events = pwr; 681 tchart->power_events = pwr;
610 } 682 }
611} 683}
612 684
613/* 685/*
614 * Sort the pid datastructure 686 * Sort the pid datastructure
615 */ 687 */
616static void sort_pids(void) 688static void sort_pids(struct timechart *tchart)
617{ 689{
618 struct per_pid *new_list, *p, *cursor, *prev; 690 struct per_pid *new_list, *p, *cursor, *prev;
619 /* sort by ppid first, then by pid, lowest to highest */ 691 /* sort by ppid first, then by pid, lowest to highest */
620 692
621 new_list = NULL; 693 new_list = NULL;
622 694
623 while (all_data) { 695 while (tchart->all_data) {
624 p = all_data; 696 p = tchart->all_data;
625 all_data = p->next; 697 tchart->all_data = p->next;
626 p->next = NULL; 698 p->next = NULL;
627 699
628 if (new_list == NULL) { 700 if (new_list == NULL) {
@@ -655,14 +727,14 @@ static void sort_pids(void)
655 prev->next = p; 727 prev->next = p;
656 } 728 }
657 } 729 }
658 all_data = new_list; 730 tchart->all_data = new_list;
659} 731}
660 732
661 733
662static void draw_c_p_states(void) 734static void draw_c_p_states(struct timechart *tchart)
663{ 735{
664 struct power_event *pwr; 736 struct power_event *pwr;
665 pwr = power_events; 737 pwr = tchart->power_events;
666 738
667 /* 739 /*
668 * two pass drawing so that the P state bars are on top of the C state blocks 740 * two pass drawing so that the P state bars are on top of the C state blocks
@@ -673,30 +745,30 @@ static void draw_c_p_states(void)
673 pwr = pwr->next; 745 pwr = pwr->next;
674 } 746 }
675 747
676 pwr = power_events; 748 pwr = tchart->power_events;
677 while (pwr) { 749 while (pwr) {
678 if (pwr->type == PSTATE) { 750 if (pwr->type == PSTATE) {
679 if (!pwr->state) 751 if (!pwr->state)
680 pwr->state = min_freq; 752 pwr->state = tchart->min_freq;
681 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); 753 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
682 } 754 }
683 pwr = pwr->next; 755 pwr = pwr->next;
684 } 756 }
685} 757}
686 758
687static void draw_wakeups(void) 759static void draw_wakeups(struct timechart *tchart)
688{ 760{
689 struct wake_event *we; 761 struct wake_event *we;
690 struct per_pid *p; 762 struct per_pid *p;
691 struct per_pidcomm *c; 763 struct per_pidcomm *c;
692 764
693 we = wake_events; 765 we = tchart->wake_events;
694 while (we) { 766 while (we) {
695 int from = 0, to = 0; 767 int from = 0, to = 0;
696 char *task_from = NULL, *task_to = NULL; 768 char *task_from = NULL, *task_to = NULL;
697 769
698 /* locate the column of the waker and wakee */ 770 /* locate the column of the waker and wakee */
699 p = all_data; 771 p = tchart->all_data;
700 while (p) { 772 while (p) {
701 if (p->pid == we->waker || p->pid == we->wakee) { 773 if (p->pid == we->waker || p->pid == we->wakee) {
702 c = p->all; 774 c = p->all;
@@ -739,11 +811,12 @@ static void draw_wakeups(void)
739 } 811 }
740 812
741 if (we->waker == -1) 813 if (we->waker == -1)
742 svg_interrupt(we->time, to); 814 svg_interrupt(we->time, to, we->backtrace);
743 else if (from && to && abs(from - to) == 1) 815 else if (from && to && abs(from - to) == 1)
744 svg_wakeline(we->time, from, to); 816 svg_wakeline(we->time, from, to, we->backtrace);
745 else 817 else
746 svg_partial_wakeline(we->time, from, task_from, to, task_to); 818 svg_partial_wakeline(we->time, from, task_from, to,
819 task_to, we->backtrace);
747 we = we->next; 820 we = we->next;
748 821
749 free(task_from); 822 free(task_from);
@@ -751,19 +824,25 @@ static void draw_wakeups(void)
751 } 824 }
752} 825}
753 826
754static void draw_cpu_usage(void) 827static void draw_cpu_usage(struct timechart *tchart)
755{ 828{
756 struct per_pid *p; 829 struct per_pid *p;
757 struct per_pidcomm *c; 830 struct per_pidcomm *c;
758 struct cpu_sample *sample; 831 struct cpu_sample *sample;
759 p = all_data; 832 p = tchart->all_data;
760 while (p) { 833 while (p) {
761 c = p->all; 834 c = p->all;
762 while (c) { 835 while (c) {
763 sample = c->samples; 836 sample = c->samples;
764 while (sample) { 837 while (sample) {
765 if (sample->type == TYPE_RUNNING) 838 if (sample->type == TYPE_RUNNING) {
766 svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); 839 svg_process(sample->cpu,
840 sample->start_time,
841 sample->end_time,
842 p->pid,
843 c->comm,
844 sample->backtrace);
845 }
767 846
768 sample = sample->next; 847 sample = sample->next;
769 } 848 }
@@ -773,16 +852,16 @@ static void draw_cpu_usage(void)
773 } 852 }
774} 853}
775 854
776static void draw_process_bars(void) 855static void draw_process_bars(struct timechart *tchart)
777{ 856{
778 struct per_pid *p; 857 struct per_pid *p;
779 struct per_pidcomm *c; 858 struct per_pidcomm *c;
780 struct cpu_sample *sample; 859 struct cpu_sample *sample;
781 int Y = 0; 860 int Y = 0;
782 861
783 Y = 2 * numcpus + 2; 862 Y = 2 * tchart->numcpus + 2;
784 863
785 p = all_data; 864 p = tchart->all_data;
786 while (p) { 865 while (p) {
787 c = p->all; 866 c = p->all;
788 while (c) { 867 while (c) {
@@ -796,11 +875,20 @@ static void draw_process_bars(void)
796 sample = c->samples; 875 sample = c->samples;
797 while (sample) { 876 while (sample) {
798 if (sample->type == TYPE_RUNNING) 877 if (sample->type == TYPE_RUNNING)
799 svg_sample(Y, sample->cpu, sample->start_time, sample->end_time); 878 svg_running(Y, sample->cpu,
879 sample->start_time,
880 sample->end_time,
881 sample->backtrace);
800 if (sample->type == TYPE_BLOCKED) 882 if (sample->type == TYPE_BLOCKED)
801 svg_box(Y, sample->start_time, sample->end_time, "blocked"); 883 svg_blocked(Y, sample->cpu,
884 sample->start_time,
885 sample->end_time,
886 sample->backtrace);
802 if (sample->type == TYPE_WAITING) 887 if (sample->type == TYPE_WAITING)
803 svg_waiting(Y, sample->start_time, sample->end_time); 888 svg_waiting(Y, sample->cpu,
889 sample->start_time,
890 sample->end_time,
891 sample->backtrace);
804 sample = sample->next; 892 sample = sample->next;
805 } 893 }
806 894
@@ -853,21 +941,21 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
853 return 0; 941 return 0;
854} 942}
855 943
856static int determine_display_tasks_filtered(void) 944static int determine_display_tasks_filtered(struct timechart *tchart)
857{ 945{
858 struct per_pid *p; 946 struct per_pid *p;
859 struct per_pidcomm *c; 947 struct per_pidcomm *c;
860 int count = 0; 948 int count = 0;
861 949
862 p = all_data; 950 p = tchart->all_data;
863 while (p) { 951 while (p) {
864 p->display = 0; 952 p->display = 0;
865 if (p->start_time == 1) 953 if (p->start_time == 1)
866 p->start_time = first_time; 954 p->start_time = tchart->first_time;
867 955
868 /* no exit marker, task kept running to the end */ 956 /* no exit marker, task kept running to the end */
869 if (p->end_time == 0) 957 if (p->end_time == 0)
870 p->end_time = last_time; 958 p->end_time = tchart->last_time;
871 959
872 c = p->all; 960 c = p->all;
873 961
@@ -875,7 +963,7 @@ static int determine_display_tasks_filtered(void)
875 c->display = 0; 963 c->display = 0;
876 964
877 if (c->start_time == 1) 965 if (c->start_time == 1)
878 c->start_time = first_time; 966 c->start_time = tchart->first_time;
879 967
880 if (passes_filter(p, c)) { 968 if (passes_filter(p, c)) {
881 c->display = 1; 969 c->display = 1;
@@ -884,7 +972,7 @@ static int determine_display_tasks_filtered(void)
884 } 972 }
885 973
886 if (c->end_time == 0) 974 if (c->end_time == 0)
887 c->end_time = last_time; 975 c->end_time = tchart->last_time;
888 976
889 c = c->next; 977 c = c->next;
890 } 978 }
@@ -893,25 +981,25 @@ static int determine_display_tasks_filtered(void)
893 return count; 981 return count;
894} 982}
895 983
896static int determine_display_tasks(u64 threshold) 984static int determine_display_tasks(struct timechart *tchart, u64 threshold)
897{ 985{
898 struct per_pid *p; 986 struct per_pid *p;
899 struct per_pidcomm *c; 987 struct per_pidcomm *c;
900 int count = 0; 988 int count = 0;
901 989
902 if (process_filter) 990 if (process_filter)
903 return determine_display_tasks_filtered(); 991 return determine_display_tasks_filtered(tchart);
904 992
905 p = all_data; 993 p = tchart->all_data;
906 while (p) { 994 while (p) {
907 p->display = 0; 995 p->display = 0;
908 if (p->start_time == 1) 996 if (p->start_time == 1)
909 p->start_time = first_time; 997 p->start_time = tchart->first_time;
910 998
911 /* no exit marker, task kept running to the end */ 999 /* no exit marker, task kept running to the end */
912 if (p->end_time == 0) 1000 if (p->end_time == 0)
913 p->end_time = last_time; 1001 p->end_time = tchart->last_time;
914 if (p->total_time >= threshold && !power_only) 1002 if (p->total_time >= threshold)
915 p->display = 1; 1003 p->display = 1;
916 1004
917 c = p->all; 1005 c = p->all;
@@ -920,15 +1008,15 @@ static int determine_display_tasks(u64 threshold)
920 c->display = 0; 1008 c->display = 0;
921 1009
922 if (c->start_time == 1) 1010 if (c->start_time == 1)
923 c->start_time = first_time; 1011 c->start_time = tchart->first_time;
924 1012
925 if (c->total_time >= threshold && !power_only) { 1013 if (c->total_time >= threshold) {
926 c->display = 1; 1014 c->display = 1;
927 count++; 1015 count++;
928 } 1016 }
929 1017
930 if (c->end_time == 0) 1018 if (c->end_time == 0)
931 c->end_time = last_time; 1019 c->end_time = tchart->last_time;
932 1020
933 c = c->next; 1021 c = c->next;
934 } 1022 }
@@ -941,45 +1029,74 @@ static int determine_display_tasks(u64 threshold)
941 1029
942#define TIME_THRESH 10000000 1030#define TIME_THRESH 10000000
943 1031
944static void write_svg_file(const char *filename) 1032static void write_svg_file(struct timechart *tchart, const char *filename)
945{ 1033{
946 u64 i; 1034 u64 i;
947 int count; 1035 int count;
1036 int thresh = TIME_THRESH;
948 1037
949 numcpus++; 1038 if (tchart->power_only)
950 1039 tchart->proc_num = 0;
951 1040
952 count = determine_display_tasks(TIME_THRESH); 1041 /* We'd like to show at least proc_num tasks;
1042 * be less picky if we have fewer */
1043 do {
1044 count = determine_display_tasks(tchart, thresh);
1045 thresh /= 10;
1046 } while (!process_filter && thresh && count < tchart->proc_num);
953 1047
954 /* We'd like to show at least 15 tasks; be less picky if we have fewer */ 1048 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
955 if (count < 15)
956 count = determine_display_tasks(TIME_THRESH / 10);
957
958 open_svg(filename, numcpus, count, first_time, last_time);
959 1049
960 svg_time_grid(); 1050 svg_time_grid();
961 svg_legenda(); 1051 svg_legenda();
962 1052
963 for (i = 0; i < numcpus; i++) 1053 for (i = 0; i < tchart->numcpus; i++)
964 svg_cpu_box(i, max_freq, turbo_frequency); 1054 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
965 1055
966 draw_cpu_usage(); 1056 draw_cpu_usage(tchart);
967 draw_process_bars(); 1057 if (tchart->proc_num)
968 draw_c_p_states(); 1058 draw_process_bars(tchart);
969 draw_wakeups(); 1059 if (!tchart->tasks_only)
1060 draw_c_p_states(tchart);
1061 if (tchart->proc_num)
1062 draw_wakeups(tchart);
970 1063
971 svg_close(); 1064 svg_close();
972} 1065}
973 1066
974static int __cmd_timechart(const char *output_name) 1067static int process_header(struct perf_file_section *section __maybe_unused,
1068 struct perf_header *ph,
1069 int feat,
1070 int fd __maybe_unused,
1071 void *data)
1072{
1073 struct timechart *tchart = data;
1074
1075 switch (feat) {
1076 case HEADER_NRCPUS:
1077 tchart->numcpus = ph->env.nr_cpus_avail;
1078 break;
1079
1080 case HEADER_CPU_TOPOLOGY:
1081 if (!tchart->topology)
1082 break;
1083
1084 if (svg_build_topology_map(ph->env.sibling_cores,
1085 ph->env.nr_sibling_cores,
1086 ph->env.sibling_threads,
1087 ph->env.nr_sibling_threads))
1088 fprintf(stderr, "problem building topology\n");
1089 break;
1090
1091 default:
1092 break;
1093 }
1094
1095 return 0;
1096}
1097
1098static int __cmd_timechart(struct timechart *tchart, const char *output_name)
975{ 1099{
976 struct perf_tool perf_timechart = {
977 .comm = process_comm_event,
978 .fork = process_fork_event,
979 .exit = process_exit_event,
980 .sample = process_sample_event,
981 .ordered_samples = true,
982 };
983 const struct perf_evsel_str_handler power_tracepoints[] = { 1100 const struct perf_evsel_str_handler power_tracepoints[] = {
984 { "power:cpu_idle", process_sample_cpu_idle }, 1101 { "power:cpu_idle", process_sample_cpu_idle },
985 { "power:cpu_frequency", process_sample_cpu_frequency }, 1102 { "power:cpu_frequency", process_sample_cpu_frequency },
@@ -997,12 +1114,17 @@ static int __cmd_timechart(const char *output_name)
997 }; 1114 };
998 1115
999 struct perf_session *session = perf_session__new(&file, false, 1116 struct perf_session *session = perf_session__new(&file, false,
1000 &perf_timechart); 1117 &tchart->tool);
1001 int ret = -EINVAL; 1118 int ret = -EINVAL;
1002 1119
1003 if (session == NULL) 1120 if (session == NULL)
1004 return -ENOMEM; 1121 return -ENOMEM;
1005 1122
1123 (void)perf_header__process_sections(&session->header,
1124 perf_data_file__fd(session->file),
1125 tchart,
1126 process_header);
1127
1006 if (!perf_session__has_traces(session, "timechart record")) 1128 if (!perf_session__has_traces(session, "timechart record"))
1007 goto out_delete; 1129 goto out_delete;
1008 1130
@@ -1012,69 +1134,111 @@ static int __cmd_timechart(const char *output_name)
1012 goto out_delete; 1134 goto out_delete;
1013 } 1135 }
1014 1136
1015 ret = perf_session__process_events(session, &perf_timechart); 1137 ret = perf_session__process_events(session, &tchart->tool);
1016 if (ret) 1138 if (ret)
1017 goto out_delete; 1139 goto out_delete;
1018 1140
1019 end_sample_processing(); 1141 end_sample_processing(tchart);
1020 1142
1021 sort_pids(); 1143 sort_pids(tchart);
1022 1144
1023 write_svg_file(output_name); 1145 write_svg_file(tchart, output_name);
1024 1146
1025 pr_info("Written %2.1f seconds of trace to %s.\n", 1147 pr_info("Written %2.1f seconds of trace to %s.\n",
1026 (last_time - first_time) / 1000000000.0, output_name); 1148 (tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
1027out_delete: 1149out_delete:
1028 perf_session__delete(session); 1150 perf_session__delete(session);
1029 return ret; 1151 return ret;
1030} 1152}
1031 1153
1032static int __cmd_record(int argc, const char **argv) 1154static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1033{ 1155{
1034#ifdef SUPPORT_OLD_POWER_EVENTS 1156 unsigned int rec_argc, i, j;
1035 const char * const record_old_args[] = { 1157 const char **rec_argv;
1158 const char **p;
1159 unsigned int record_elems;
1160
1161 const char * const common_args[] = {
1036 "record", "-a", "-R", "-c", "1", 1162 "record", "-a", "-R", "-c", "1",
1163 };
1164 unsigned int common_args_nr = ARRAY_SIZE(common_args);
1165
1166 const char * const backtrace_args[] = {
1167 "-g",
1168 };
1169 unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args);
1170
1171 const char * const power_args[] = {
1172 "-e", "power:cpu_frequency",
1173 "-e", "power:cpu_idle",
1174 };
1175 unsigned int power_args_nr = ARRAY_SIZE(power_args);
1176
1177 const char * const old_power_args[] = {
1178#ifdef SUPPORT_OLD_POWER_EVENTS
1037 "-e", "power:power_start", 1179 "-e", "power:power_start",
1038 "-e", "power:power_end", 1180 "-e", "power:power_end",
1039 "-e", "power:power_frequency", 1181 "-e", "power:power_frequency",
1040 "-e", "sched:sched_wakeup",
1041 "-e", "sched:sched_switch",
1042 };
1043#endif 1182#endif
1044 const char * const record_new_args[] = { 1183 };
1045 "record", "-a", "-R", "-c", "1", 1184 unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args);
1046 "-e", "power:cpu_frequency", 1185
1047 "-e", "power:cpu_idle", 1186 const char * const tasks_args[] = {
1048 "-e", "sched:sched_wakeup", 1187 "-e", "sched:sched_wakeup",
1049 "-e", "sched:sched_switch", 1188 "-e", "sched:sched_switch",
1050 }; 1189 };
1051 unsigned int rec_argc, i, j; 1190 unsigned int tasks_args_nr = ARRAY_SIZE(tasks_args);
1052 const char **rec_argv;
1053 const char * const *record_args = record_new_args;
1054 unsigned int record_elems = ARRAY_SIZE(record_new_args);
1055 1191
1056#ifdef SUPPORT_OLD_POWER_EVENTS 1192#ifdef SUPPORT_OLD_POWER_EVENTS
1057 if (!is_valid_tracepoint("power:cpu_idle") && 1193 if (!is_valid_tracepoint("power:cpu_idle") &&
1058 is_valid_tracepoint("power:power_start")) { 1194 is_valid_tracepoint("power:power_start")) {
1059 use_old_power_events = 1; 1195 use_old_power_events = 1;
1060 record_args = record_old_args; 1196 power_args_nr = 0;
1061 record_elems = ARRAY_SIZE(record_old_args); 1197 } else {
1198 old_power_args_nr = 0;
1062 } 1199 }
1063#endif 1200#endif
1064 1201
1065 rec_argc = record_elems + argc - 1; 1202 if (tchart->power_only)
1203 tasks_args_nr = 0;
1204
1205 if (tchart->tasks_only) {
1206 power_args_nr = 0;
1207 old_power_args_nr = 0;
1208 }
1209
1210 if (!tchart->with_backtrace)
1211 backtrace_args_no = 0;
1212
1213 record_elems = common_args_nr + tasks_args_nr +
1214 power_args_nr + old_power_args_nr + backtrace_args_no;
1215
1216 rec_argc = record_elems + argc;
1066 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1217 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1067 1218
1068 if (rec_argv == NULL) 1219 if (rec_argv == NULL)
1069 return -ENOMEM; 1220 return -ENOMEM;
1070 1221
1071 for (i = 0; i < record_elems; i++) 1222 p = rec_argv;
1072 rec_argv[i] = strdup(record_args[i]); 1223 for (i = 0; i < common_args_nr; i++)
1224 *p++ = strdup(common_args[i]);
1225
1226 for (i = 0; i < backtrace_args_no; i++)
1227 *p++ = strdup(backtrace_args[i]);
1228
1229 for (i = 0; i < tasks_args_nr; i++)
1230 *p++ = strdup(tasks_args[i]);
1231
1232 for (i = 0; i < power_args_nr; i++)
1233 *p++ = strdup(power_args[i]);
1073 1234
1074 for (j = 1; j < (unsigned int)argc; j++, i++) 1235 for (i = 0; i < old_power_args_nr; i++)
1075 rec_argv[i] = argv[j]; 1236 *p++ = strdup(old_power_args[i]);
1076 1237
1077 return cmd_record(i, rec_argv, NULL); 1238 for (j = 1; j < (unsigned int)argc; j++)
1239 *p++ = argv[j];
1240
1241 return cmd_record(rec_argc, rec_argv, NULL);
1078} 1242}
1079 1243
1080static int 1244static int
@@ -1086,20 +1250,56 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
1086 return 0; 1250 return 0;
1087} 1251}
1088 1252
1253static int
1254parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1255 int __maybe_unused unset)
1256{
1257 unsigned long duration = strtoul(arg, NULL, 0);
1258
1259 if (svg_highlight || svg_highlight_name)
1260 return -1;
1261
1262 if (duration)
1263 svg_highlight = duration;
1264 else
1265 svg_highlight_name = strdup(arg);
1266
1267 return 0;
1268}
1269
1089int cmd_timechart(int argc, const char **argv, 1270int cmd_timechart(int argc, const char **argv,
1090 const char *prefix __maybe_unused) 1271 const char *prefix __maybe_unused)
1091{ 1272{
1273 struct timechart tchart = {
1274 .tool = {
1275 .comm = process_comm_event,
1276 .fork = process_fork_event,
1277 .exit = process_exit_event,
1278 .sample = process_sample_event,
1279 .ordered_samples = true,
1280 },
1281 .proc_num = 15,
1282 };
1092 const char *output_name = "output.svg"; 1283 const char *output_name = "output.svg";
1093 const struct option options[] = { 1284 const struct option timechart_options[] = {
1094 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1285 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1095 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1286 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1096 OPT_INTEGER('w', "width", &svg_page_width, "page width"), 1287 OPT_INTEGER('w', "width", &svg_page_width, "page width"),
1097 OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), 1288 OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
1289 "highlight tasks. Pass duration in ns or process name.",
1290 parse_highlight),
1291 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1292 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1293 "output processes data only"),
1098 OPT_CALLBACK('p', "process", NULL, "process", 1294 OPT_CALLBACK('p', "process", NULL, "process",
1099 "process selector. Pass a pid or process name.", 1295 "process selector. Pass a pid or process name.",
1100 parse_process), 1296 parse_process),
1101 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1297 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1102 "Look for files with symbols relative to this directory"), 1298 "Look for files with symbols relative to this directory"),
1299 OPT_INTEGER('n', "proc-num", &tchart.proc_num,
1300 "min. number of tasks to print"),
1301 OPT_BOOLEAN('t', "topology", &tchart.topology,
1302 "sort CPUs according to topology"),
1103 OPT_END() 1303 OPT_END()
1104 }; 1304 };
1105 const char * const timechart_usage[] = { 1305 const char * const timechart_usage[] = {
@@ -1107,17 +1307,41 @@ int cmd_timechart(int argc, const char **argv,
1107 NULL 1307 NULL
1108 }; 1308 };
1109 1309
1110 argc = parse_options(argc, argv, options, timechart_usage, 1310 const struct option record_options[] = {
1311 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1312 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1313 "output processes data only"),
1314 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1315 OPT_END()
1316 };
1317 const char * const record_usage[] = {
1318 "perf timechart record [<options>]",
1319 NULL
1320 };
1321 argc = parse_options(argc, argv, timechart_options, timechart_usage,
1111 PARSE_OPT_STOP_AT_NON_OPTION); 1322 PARSE_OPT_STOP_AT_NON_OPTION);
1112 1323
1324 if (tchart.power_only && tchart.tasks_only) {
1325 pr_err("-P and -T options cannot be used at the same time.\n");
1326 return -1;
1327 }
1328
1113 symbol__init(); 1329 symbol__init();
1114 1330
1115 if (argc && !strncmp(argv[0], "rec", 3)) 1331 if (argc && !strncmp(argv[0], "rec", 3)) {
1116 return __cmd_record(argc, argv); 1332 argc = parse_options(argc, argv, record_options, record_usage,
1117 else if (argc) 1333 PARSE_OPT_STOP_AT_NON_OPTION);
1118 usage_with_options(timechart_usage, options); 1334
1335 if (tchart.power_only && tchart.tasks_only) {
1336 pr_err("-P and -T options cannot be used at the same time.\n");
1337 return -1;
1338 }
1339
1340 return timechart__record(&tchart, argc, argv);
1341 } else if (argc)
1342 usage_with_options(timechart_usage, timechart_options);
1119 1343
1120 setup_pager(); 1344 setup_pager();
1121 1345
1122 return __cmd_timechart(output_name); 1346 return __cmd_timechart(&tchart, output_name);
1123} 1347}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 71e6402729a8..569dd87690ef 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -189,21 +189,18 @@ static void perf_top__record_precise_ip(struct perf_top *top,
189 if (pthread_mutex_trylock(&notes->lock)) 189 if (pthread_mutex_trylock(&notes->lock))
190 return; 190 return;
191 191
192 if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
193 pthread_mutex_unlock(&notes->lock);
194 pr_err("Not enough memory for annotating '%s' symbol!\n",
195 sym->name);
196 sleep(1);
197 return;
198 }
199
200 ip = he->ms.map->map_ip(he->ms.map, ip); 192 ip = he->ms.map->map_ip(he->ms.map, ip);
201 err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); 193 err = hist_entry__inc_addr_samples(he, counter, ip);
202 194
203 pthread_mutex_unlock(&notes->lock); 195 pthread_mutex_unlock(&notes->lock);
204 196
205 if (err == -ERANGE && !he->ms.map->erange_warned) 197 if (err == -ERANGE && !he->ms.map->erange_warned)
206 ui__warn_map_erange(he->ms.map, sym, ip); 198 ui__warn_map_erange(he->ms.map, sym, ip);
199 else if (err == -ENOMEM) {
200 pr_err("Not enough memory for annotating '%s' symbol!\n",
201 sym->name);
202 sleep(1);
203 }
207} 204}
208 205
209static void perf_top__show_details(struct perf_top *top) 206static void perf_top__show_details(struct perf_top *top)
@@ -485,7 +482,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
485 482
486 fprintf(stderr, "\nAvailable events:"); 483 fprintf(stderr, "\nAvailable events:");
487 484
488 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 485 evlist__for_each(top->evlist, top->sym_evsel)
489 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); 486 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
490 487
491 prompt_integer(&counter, "Enter details event counter"); 488 prompt_integer(&counter, "Enter details event counter");
@@ -496,7 +493,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
496 sleep(1); 493 sleep(1);
497 break; 494 break;
498 } 495 }
499 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 496 evlist__for_each(top->evlist, top->sym_evsel)
500 if (top->sym_evsel->idx == counter) 497 if (top->sym_evsel->idx == counter)
501 break; 498 break;
502 } else 499 } else
@@ -578,7 +575,7 @@ static void *display_thread_tui(void *arg)
578 * Zooming in/out UIDs. For now juse use whatever the user passed 575 * Zooming in/out UIDs. For now juse use whatever the user passed
579 * via --uid. 576 * via --uid.
580 */ 577 */
581 list_for_each_entry(pos, &top->evlist->entries, node) 578 evlist__for_each(top->evlist, pos)
582 pos->hists.uid_filter_str = top->record_opts.target.uid_str; 579 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
583 580
584 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, 581 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
@@ -634,26 +631,9 @@ repeat:
634 return NULL; 631 return NULL;
635} 632}
636 633
637/* Tag samples to be skipped. */
638static const char *skip_symbols[] = {
639 "intel_idle",
640 "default_idle",
641 "native_safe_halt",
642 "cpu_idle",
643 "enter_idle",
644 "exit_idle",
645 "mwait_idle",
646 "mwait_idle_with_hints",
647 "poll_idle",
648 "ppc64_runlatch_off",
649 "pseries_dedicated_idle_sleep",
650 NULL
651};
652
653static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) 634static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
654{ 635{
655 const char *name = sym->name; 636 const char *name = sym->name;
656 int i;
657 637
658 /* 638 /*
659 * ppc64 uses function descriptors and appends a '.' to the 639 * ppc64 uses function descriptors and appends a '.' to the
@@ -671,12 +651,8 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
671 strstr(name, "_text_end")) 651 strstr(name, "_text_end"))
672 return 1; 652 return 1;
673 653
674 for (i = 0; skip_symbols[i]; i++) { 654 if (symbol__is_idle(sym))
675 if (!strcmp(skip_symbols[i], name)) { 655 sym->ignore = true;
676 sym->ignore = true;
677 break;
678 }
679 }
680 656
681 return 0; 657 return 0;
682} 658}
@@ -878,11 +854,11 @@ static int perf_top__start_counters(struct perf_top *top)
878 char msg[512]; 854 char msg[512];
879 struct perf_evsel *counter; 855 struct perf_evsel *counter;
880 struct perf_evlist *evlist = top->evlist; 856 struct perf_evlist *evlist = top->evlist;
881 struct perf_record_opts *opts = &top->record_opts; 857 struct record_opts *opts = &top->record_opts;
882 858
883 perf_evlist__config(evlist, opts); 859 perf_evlist__config(evlist, opts);
884 860
885 list_for_each_entry(counter, &evlist->entries, node) { 861 evlist__for_each(evlist, counter) {
886try_again: 862try_again:
887 if (perf_evsel__open(counter, top->evlist->cpus, 863 if (perf_evsel__open(counter, top->evlist->cpus,
888 top->evlist->threads) < 0) { 864 top->evlist->threads) < 0) {
@@ -930,7 +906,7 @@ static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
930 906
931static int __cmd_top(struct perf_top *top) 907static int __cmd_top(struct perf_top *top)
932{ 908{
933 struct perf_record_opts *opts = &top->record_opts; 909 struct record_opts *opts = &top->record_opts;
934 pthread_t thread; 910 pthread_t thread;
935 int ret; 911 int ret;
936 912
@@ -1052,7 +1028,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1052 .max_stack = PERF_MAX_STACK_DEPTH, 1028 .max_stack = PERF_MAX_STACK_DEPTH,
1053 .sym_pcnt_filter = 5, 1029 .sym_pcnt_filter = 5,
1054 }; 1030 };
1055 struct perf_record_opts *opts = &top.record_opts; 1031 struct record_opts *opts = &top.record_opts;
1056 struct target *target = &opts->target; 1032 struct target *target = &opts->target;
1057 const struct option options[] = { 1033 const struct option options[] = {
1058 OPT_CALLBACK('e', "event", &top.evlist, "event", 1034 OPT_CALLBACK('e', "event", &top.evlist, "event",
@@ -1084,7 +1060,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1084 "dump the symbol table used for profiling"), 1060 "dump the symbol table used for profiling"),
1085 OPT_INTEGER('f', "count-filter", &top.count_filter, 1061 OPT_INTEGER('f', "count-filter", &top.count_filter,
1086 "only display functions with more events than this"), 1062 "only display functions with more events than this"),
1087 OPT_BOOLEAN('g', "group", &opts->group, 1063 OPT_BOOLEAN(0, "group", &opts->group,
1088 "put the counters into a counter group"), 1064 "put the counters into a counter group"),
1089 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, 1065 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
1090 "child tasks do not inherit counters"), 1066 "child tasks do not inherit counters"),
@@ -1105,7 +1081,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1105 " abort, in_tx, transaction"), 1081 " abort, in_tx, transaction"),
1106 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1082 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1107 "Show a column with the number of samples"), 1083 "Show a column with the number of samples"),
1108 OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, 1084 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts,
1109 NULL, "enables call-graph recording", 1085 NULL, "enables call-graph recording",
1110 &callchain_opt), 1086 &callchain_opt),
1111 OPT_CALLBACK(0, "call-graph", &top.record_opts, 1087 OPT_CALLBACK(0, "call-graph", &top.record_opts,
@@ -1195,7 +1171,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1195 if (!top.evlist->nr_entries && 1171 if (!top.evlist->nr_entries &&
1196 perf_evlist__add_default(top.evlist) < 0) { 1172 perf_evlist__add_default(top.evlist) < 0) {
1197 ui__error("Not enough memory for event selector list\n"); 1173 ui__error("Not enough memory for event selector list\n");
1198 goto out_delete_maps; 1174 goto out_delete_evlist;
1199 } 1175 }
1200 1176
1201 symbol_conf.nr_events = top.evlist->nr_entries; 1177 symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1203,9 +1179,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1203 if (top.delay_secs < 1) 1179 if (top.delay_secs < 1)
1204 top.delay_secs = 1; 1180 top.delay_secs = 1;
1205 1181
1206 if (perf_record_opts__config(opts)) { 1182 if (record_opts__config(opts)) {
1207 status = -EINVAL; 1183 status = -EINVAL;
1208 goto out_delete_maps; 1184 goto out_delete_evlist;
1209 } 1185 }
1210 1186
1211 top.sym_evsel = perf_evlist__first(top.evlist); 1187 top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1230,8 +1206,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1230 1206
1231 status = __cmd_top(&top); 1207 status = __cmd_top(&top);
1232 1208
1233out_delete_maps:
1234 perf_evlist__delete_maps(top.evlist);
1235out_delete_evlist: 1209out_delete_evlist:
1236 perf_evlist__delete(top.evlist); 1210 perf_evlist__delete(top.evlist);
1237 1211
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 8be17fc462ba..4bd44aba343e 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -11,6 +11,8 @@
11#include "util/intlist.h" 11#include "util/intlist.h"
12#include "util/thread_map.h" 12#include "util/thread_map.h"
13#include "util/stat.h" 13#include "util/stat.h"
14#include "trace-event.h"
15#include "util/parse-events.h"
14 16
15#include <libaudit.h> 17#include <libaudit.h>
16#include <stdlib.h> 18#include <stdlib.h>
@@ -144,8 +146,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
144 146
145static void perf_evsel__delete_priv(struct perf_evsel *evsel) 147static void perf_evsel__delete_priv(struct perf_evsel *evsel)
146{ 148{
147 free(evsel->priv); 149 zfree(&evsel->priv);
148 evsel->priv = NULL;
149 perf_evsel__delete(evsel); 150 perf_evsel__delete(evsel);
150} 151}
151 152
@@ -163,8 +164,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
163 return -ENOMEM; 164 return -ENOMEM;
164 165
165out_delete: 166out_delete:
166 free(evsel->priv); 167 zfree(&evsel->priv);
167 evsel->priv = NULL;
168 return -ENOENT; 168 return -ENOENT;
169} 169}
170 170
@@ -172,6 +172,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void
172{ 172{
173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); 173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
174 174
175 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
176 if (evsel == NULL)
177 evsel = perf_evsel__newtp("syscalls", direction);
178
175 if (evsel) { 179 if (evsel) {
176 if (perf_evsel__init_syscall_tp(evsel, handler)) 180 if (perf_evsel__init_syscall_tp(evsel, handler))
177 goto out_delete; 181 goto out_delete;
@@ -1153,29 +1157,30 @@ struct trace {
1153 int max; 1157 int max;
1154 struct syscall *table; 1158 struct syscall *table;
1155 } syscalls; 1159 } syscalls;
1156 struct perf_record_opts opts; 1160 struct record_opts opts;
1157 struct machine *host; 1161 struct machine *host;
1158 u64 base_time; 1162 u64 base_time;
1159 bool full_time;
1160 FILE *output; 1163 FILE *output;
1161 unsigned long nr_events; 1164 unsigned long nr_events;
1162 struct strlist *ev_qualifier; 1165 struct strlist *ev_qualifier;
1163 bool not_ev_qualifier;
1164 bool live;
1165 const char *last_vfs_getname; 1166 const char *last_vfs_getname;
1166 struct intlist *tid_list; 1167 struct intlist *tid_list;
1167 struct intlist *pid_list; 1168 struct intlist *pid_list;
1169 double duration_filter;
1170 double runtime_ms;
1171 struct {
1172 u64 vfs_getname,
1173 proc_getname;
1174 } stats;
1175 bool not_ev_qualifier;
1176 bool live;
1177 bool full_time;
1168 bool sched; 1178 bool sched;
1169 bool multiple_threads; 1179 bool multiple_threads;
1170 bool summary; 1180 bool summary;
1171 bool summary_only; 1181 bool summary_only;
1172 bool show_comm; 1182 bool show_comm;
1173 bool show_tool_stats; 1183 bool show_tool_stats;
1174 double duration_filter;
1175 double runtime_ms;
1176 struct {
1177 u64 vfs_getname, proc_getname;
1178 } stats;
1179}; 1184};
1180 1185
1181static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1186static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1272,10 +1277,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1272 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); 1277 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1273 struct thread_trace *ttrace = arg->thread->priv; 1278 struct thread_trace *ttrace = arg->thread->priv;
1274 1279
1275 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { 1280 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1276 free(ttrace->paths.table[fd]); 1281 zfree(&ttrace->paths.table[fd]);
1277 ttrace->paths.table[fd] = NULL;
1278 }
1279 1282
1280 return printed; 1283 return printed;
1281} 1284}
@@ -1430,11 +1433,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1430 sc->fmt = syscall_fmt__find(sc->name); 1433 sc->fmt = syscall_fmt__find(sc->name);
1431 1434
1432 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); 1435 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1433 sc->tp_format = event_format__new("syscalls", tp_name); 1436 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1434 1437
1435 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { 1438 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1436 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); 1439 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1437 sc->tp_format = event_format__new("syscalls", tp_name); 1440 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1438 } 1441 }
1439 1442
1440 if (sc->tp_format == NULL) 1443 if (sc->tp_format == NULL)
@@ -1764,8 +1767,10 @@ static int trace__process_sample(struct perf_tool *tool,
1764 if (!trace->full_time && trace->base_time == 0) 1767 if (!trace->full_time && trace->base_time == 0)
1765 trace->base_time = sample->time; 1768 trace->base_time = sample->time;
1766 1769
1767 if (handler) 1770 if (handler) {
1771 ++trace->nr_events;
1768 handler(trace, evsel, sample); 1772 handler(trace, evsel, sample);
1773 }
1769 1774
1770 return err; 1775 return err;
1771} 1776}
@@ -1800,10 +1805,11 @@ static int trace__record(int argc, const char **argv)
1800 "-R", 1805 "-R",
1801 "-m", "1024", 1806 "-m", "1024",
1802 "-c", "1", 1807 "-c", "1",
1803 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", 1808 "-e",
1804 }; 1809 };
1805 1810
1806 rec_argc = ARRAY_SIZE(record_args) + argc; 1811 /* +1 is for the event string below */
1812 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
1807 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1813 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1808 1814
1809 if (rec_argv == NULL) 1815 if (rec_argv == NULL)
@@ -1812,6 +1818,17 @@ static int trace__record(int argc, const char **argv)
1812 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1818 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1813 rec_argv[i] = record_args[i]; 1819 rec_argv[i] = record_args[i];
1814 1820
1821 /* event string may be different for older kernels - e.g., RHEL6 */
1822 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1823 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1824 else if (is_valid_tracepoint("syscalls:sys_enter"))
1825 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1826 else {
1827 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1828 return -1;
1829 }
1830 i++;
1831
1815 for (j = 0; j < (unsigned int)argc; j++, i++) 1832 for (j = 0; j < (unsigned int)argc; j++, i++)
1816 rec_argv[i] = argv[j]; 1833 rec_argv[i] = argv[j];
1817 1834
@@ -1869,7 +1886,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1869 err = trace__symbols_init(trace, evlist); 1886 err = trace__symbols_init(trace, evlist);
1870 if (err < 0) { 1887 if (err < 0) {
1871 fprintf(trace->output, "Problems initializing symbol libraries!\n"); 1888 fprintf(trace->output, "Problems initializing symbol libraries!\n");
1872 goto out_delete_maps; 1889 goto out_delete_evlist;
1873 } 1890 }
1874 1891
1875 perf_evlist__config(evlist, &trace->opts); 1892 perf_evlist__config(evlist, &trace->opts);
@@ -1879,10 +1896,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1879 1896
1880 if (forks) { 1897 if (forks) {
1881 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 1898 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
1882 argv, false, false); 1899 argv, false, NULL);
1883 if (err < 0) { 1900 if (err < 0) {
1884 fprintf(trace->output, "Couldn't run the workload!\n"); 1901 fprintf(trace->output, "Couldn't run the workload!\n");
1885 goto out_delete_maps; 1902 goto out_delete_evlist;
1886 } 1903 }
1887 } 1904 }
1888 1905
@@ -1890,10 +1907,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1890 if (err < 0) 1907 if (err < 0)
1891 goto out_error_open; 1908 goto out_error_open;
1892 1909
1893 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1910 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
1894 if (err < 0) { 1911 if (err < 0) {
1895 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); 1912 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1896 goto out_close_evlist; 1913 goto out_delete_evlist;
1897 } 1914 }
1898 1915
1899 perf_evlist__enable(evlist); 1916 perf_evlist__enable(evlist);
@@ -1977,11 +1994,6 @@ out_disable:
1977 } 1994 }
1978 } 1995 }
1979 1996
1980 perf_evlist__munmap(evlist);
1981out_close_evlist:
1982 perf_evlist__close(evlist);
1983out_delete_maps:
1984 perf_evlist__delete_maps(evlist);
1985out_delete_evlist: 1997out_delete_evlist:
1986 perf_evlist__delete(evlist); 1998 perf_evlist__delete(evlist);
1987out: 1999out:
@@ -2047,6 +2059,10 @@ static int trace__replay(struct trace *trace)
2047 2059
2048 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2060 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2049 "raw_syscalls:sys_enter"); 2061 "raw_syscalls:sys_enter");
2062 /* older kernels have syscalls tp versus raw_syscalls */
2063 if (evsel == NULL)
2064 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2065 "syscalls:sys_enter");
2050 if (evsel == NULL) { 2066 if (evsel == NULL) {
2051 pr_err("Data file does not have raw_syscalls:sys_enter event\n"); 2067 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2052 goto out; 2068 goto out;
@@ -2060,6 +2076,9 @@ static int trace__replay(struct trace *trace)
2060 2076
2061 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2077 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2062 "raw_syscalls:sys_exit"); 2078 "raw_syscalls:sys_exit");
2079 if (evsel == NULL)
2080 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2081 "syscalls:sys_exit");
2063 if (evsel == NULL) { 2082 if (evsel == NULL) {
2064 pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2083 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2065 goto out; 2084 goto out;
@@ -2158,7 +2177,6 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2158 size_t printed = data->printed; 2177 size_t printed = data->printed;
2159 struct trace *trace = data->trace; 2178 struct trace *trace = data->trace;
2160 struct thread_trace *ttrace = thread->priv; 2179 struct thread_trace *ttrace = thread->priv;
2161 const char *color;
2162 double ratio; 2180 double ratio;
2163 2181
2164 if (ttrace == NULL) 2182 if (ttrace == NULL)
@@ -2166,17 +2184,9 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2166 2184
2167 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; 2185 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2168 2186
2169 color = PERF_COLOR_NORMAL; 2187 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
2170 if (ratio > 50.0)
2171 color = PERF_COLOR_RED;
2172 else if (ratio > 25.0)
2173 color = PERF_COLOR_GREEN;
2174 else if (ratio > 5.0)
2175 color = PERF_COLOR_YELLOW;
2176
2177 printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid);
2178 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2188 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2179 printed += color_fprintf(fp, color, "%.1f%%", ratio); 2189 printed += fprintf(fp, "%.1f%%", ratio);
2180 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2190 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2181 printed += thread__dump_stats(ttrace, trace, fp); 2191 printed += thread__dump_stats(ttrace, trace, fp);
2182 2192
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f7d11a811c74..01dd43df0d04 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -1,28 +1,26 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2 1
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 2ifeq ($(src-perf),)
4 -e s/arm.*/arm/ -e s/sa110/arm/ \ 3src-perf := $(srctree)/tools/perf
5 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 4endif
6 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
7 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
8NO_PERF_REGS := 1
9CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
10 5
11# Additional ARCH settings for x86 6ifeq ($(obj-perf),)
12ifeq ($(ARCH),i386) 7obj-perf := $(OUTPUT)
13 override ARCH := x86
14 NO_PERF_REGS := 0
15 LIBUNWIND_LIBS = -lunwind -lunwind-x86
16endif 8endif
17 9
18ifeq ($(ARCH),x86_64) 10ifneq ($(obj-perf),)
19 override ARCH := x86 11obj-perf := $(abspath $(obj-perf))/
20 IS_X86_64 := 0 12endif
21 ifeq (, $(findstring m32,$(CFLAGS))) 13
22 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) 14LIB_INCLUDE := $(srctree)/tools/lib/
23 endif 15CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
16
17include $(src-perf)/config/Makefile.arch
18
19NO_PERF_REGS := 1
20
21# Additional ARCH settings for x86
22ifeq ($(ARCH),x86)
24 ifeq (${IS_X86_64}, 1) 23 ifeq (${IS_X86_64}, 1)
25 RAW_ARCH := x86_64
26 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT 24 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S 25 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
28 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 26 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
@@ -36,24 +34,31 @@ ifeq ($(ARCH),arm)
36 LIBUNWIND_LIBS = -lunwind -lunwind-arm 34 LIBUNWIND_LIBS = -lunwind -lunwind-arm
37endif 35endif
38 36
39ifeq ($(NO_PERF_REGS),0) 37ifeq ($(LIBUNWIND_LIBS),)
40 CFLAGS += -DHAVE_PERF_REGS_SUPPORT 38 NO_LIBUNWIND := 1
41endif 39else
42 40 #
43ifeq ($(src-perf),) 41 # For linking with debug library, run like:
44src-perf := $(srctree)/tools/perf 42 #
45endif 43 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
44 #
45 ifdef LIBUNWIND_DIR
46 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
47 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
48 endif
49 LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
46 50
47ifeq ($(obj-perf),) 51 # Set per-feature check compilation flags
48obj-perf := $(OUTPUT) 52 FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
53 FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
54 FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
55 FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
49endif 56endif
50 57
51ifneq ($(obj-perf),) 58ifeq ($(NO_PERF_REGS),0)
52obj-perf := $(abspath $(obj-perf))/ 59 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
53endif 60endif
54 61
55LIB_INCLUDE := $(srctree)/tools/lib/
56
57# include ARCH specific config 62# include ARCH specific config
58-include $(src-perf)/arch/$(ARCH)/Makefile 63-include $(src-perf)/arch/$(ARCH)/Makefile
59 64
@@ -102,7 +107,7 @@ endif
102 107
103feature_check = $(eval $(feature_check_code)) 108feature_check = $(eval $(feature_check_code))
104define feature_check_code 109define feature_check_code
105 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) 110 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
106endef 111endef
107 112
108feature_set = $(eval $(feature_set_code)) 113feature_set = $(eval $(feature_set_code))
@@ -141,16 +146,26 @@ CORE_FEATURE_TESTS = \
141 libslang \ 146 libslang \
142 libunwind \ 147 libunwind \
143 on-exit \ 148 on-exit \
144 stackprotector \
145 stackprotector-all \ 149 stackprotector-all \
146 timerfd 150 timerfd
147 151
152# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
153# If in the future we need per-feature checks/flags for features not
154# mentioned in this list we need to refactor this ;-).
155set_test_all_flags = $(eval $(set_test_all_flags_code))
156define set_test_all_flags_code
157 FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1))
158 FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
159endef
160
161$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
162
148# 163#
149# So here we detect whether test-all was rebuilt, to be able 164# So here we detect whether test-all was rebuilt, to be able
150# to skip the print-out of the long features list if the file 165# to skip the print-out of the long features list if the file
151# existed before and after it was built: 166# existed before and after it was built:
152# 167#
153ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),) 168ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
154 test-all-failed := 1 169 test-all-failed := 1
155else 170else
156 test-all-failed := 0 171 test-all-failed := 0
@@ -180,7 +195,7 @@ ifeq ($(feature-all), 1)
180 # 195 #
181 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) 196 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
182else 197else
183 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) 198 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1)
184 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) 199 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
185endif 200endif
186 201
@@ -209,10 +224,6 @@ ifeq ($(feature-stackprotector-all), 1)
209 CFLAGS += -fstack-protector-all 224 CFLAGS += -fstack-protector-all
210endif 225endif
211 226
212ifeq ($(feature-stackprotector), 1)
213 CFLAGS += -Wstack-protector
214endif
215
216ifeq ($(DEBUG),0) 227ifeq ($(DEBUG),0)
217 ifeq ($(feature-fortify-source), 1) 228 ifeq ($(feature-fortify-source), 1)
218 CFLAGS += -D_FORTIFY_SOURCE=2 229 CFLAGS += -D_FORTIFY_SOURCE=2
@@ -221,6 +232,7 @@ endif
221 232
222CFLAGS += -I$(src-perf)/util/include 233CFLAGS += -I$(src-perf)/util/include
223CFLAGS += -I$(src-perf)/arch/$(ARCH)/include 234CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
235CFLAGS += -I$(srctree)/tools/include/
224CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi 236CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
225CFLAGS += -I$(srctree)/arch/$(ARCH)/include 237CFLAGS += -I$(srctree)/arch/$(ARCH)/include
226CFLAGS += -I$(srctree)/include/uapi 238CFLAGS += -I$(srctree)/include/uapi
@@ -310,21 +322,7 @@ ifndef NO_LIBELF
310 endif # NO_DWARF 322 endif # NO_DWARF
311endif # NO_LIBELF 323endif # NO_LIBELF
312 324
313ifeq ($(LIBUNWIND_LIBS),)
314 NO_LIBUNWIND := 1
315endif
316
317ifndef NO_LIBUNWIND 325ifndef NO_LIBUNWIND
318 #
319 # For linking with debug library, run like:
320 #
321 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
322 #
323 ifdef LIBUNWIND_DIR
324 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
325 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
326 endif
327
328 ifneq ($(feature-libunwind), 1) 326 ifneq ($(feature-libunwind), 1)
329 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); 327 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
330 NO_LIBUNWIND := 1 328 NO_LIBUNWIND := 1
@@ -339,14 +337,12 @@ ifndef NO_LIBUNWIND
339 # non-ARM has no dwarf_find_debug_frame() function: 337 # non-ARM has no dwarf_find_debug_frame() function:
340 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME 338 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
341 endif 339 endif
342 endif
343endif
344 340
345ifndef NO_LIBUNWIND 341 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
346 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT 342 EXTLIBS += $(LIBUNWIND_LIBS)
347 EXTLIBS += $(LIBUNWIND_LIBS) 343 CFLAGS += $(LIBUNWIND_CFLAGS)
348 CFLAGS += $(LIBUNWIND_CFLAGS) 344 LDFLAGS += $(LIBUNWIND_LDFLAGS)
349 LDFLAGS += $(LIBUNWIND_LDFLAGS) 345 endif # ifneq ($(feature-libunwind), 1)
350endif 346endif
351 347
352ifndef NO_LIBAUDIT 348ifndef NO_LIBAUDIT
@@ -533,7 +529,7 @@ endif
533 529
534ifndef NO_LIBNUMA 530ifndef NO_LIBNUMA
535 ifeq ($(feature-libnuma), 0) 531 ifeq ($(feature-libnuma), 0)
536 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); 532 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev);
537 NO_LIBNUMA := 1 533 NO_LIBNUMA := 1
538 else 534 else
539 CFLAGS += -DHAVE_LIBNUMA_SUPPORT 535 CFLAGS += -DHAVE_LIBNUMA_SUPPORT
@@ -598,3 +594,11 @@ else
598perfexec_instdir = $(prefix)/$(perfexecdir) 594perfexec_instdir = $(prefix)/$(perfexecdir)
599endif 595endif
600perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 596perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
597
598# If we install to $(HOME) we keep the traceevent default:
599# $(HOME)/.traceevent/plugins
600# Otherwise we install plugins into the global $(libdir).
601ifdef DESTDIR
602plugindir=$(libdir)/traceevent/plugins
603plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir))
604endif
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
new file mode 100644
index 000000000000..fef8ae922800
--- /dev/null
+++ b/tools/perf/config/Makefile.arch
@@ -0,0 +1,22 @@
1
2uname_M := $(shell uname -m 2>/dev/null || echo not)
3
4ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
5 -e s/arm.*/arm/ -e s/sa110/arm/ \
6 -e s/s390x/s390/ -e s/parisc64/parisc/ \
7 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
8 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
9
10# Additional ARCH settings for x86
11ifeq ($(ARCH),i386)
12 override ARCH := x86
13endif
14
15ifeq ($(ARCH),x86_64)
16 override ARCH := x86
17 IS_X86_64 := 0
18 ifeq (, $(findstring m32,$(CFLAGS)))
19 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
20 RAW_ARCH := x86_64
21 endif
22endif
diff --git a/tools/perf/config/feature-checks/.gitignore b/tools/perf/config/feature-checks/.gitignore
new file mode 100644
index 000000000000..80f3da0c3515
--- /dev/null
+++ b/tools/perf/config/feature-checks/.gitignore
@@ -0,0 +1,2 @@
1*.d
2*.bin
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 87e790017c69..7cf6fcdacebe 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -1,94 +1,90 @@
1 1
2FILES= \ 2FILES= \
3 test-all \ 3 test-all.bin \
4 test-backtrace \ 4 test-backtrace.bin \
5 test-bionic \ 5 test-bionic.bin \
6 test-dwarf \ 6 test-dwarf.bin \
7 test-fortify-source \ 7 test-fortify-source.bin \
8 test-glibc \ 8 test-glibc.bin \
9 test-gtk2 \ 9 test-gtk2.bin \
10 test-gtk2-infobar \ 10 test-gtk2-infobar.bin \
11 test-hello \ 11 test-hello.bin \
12 test-libaudit \ 12 test-libaudit.bin \
13 test-libbfd \ 13 test-libbfd.bin \
14 test-liberty \ 14 test-liberty.bin \
15 test-liberty-z \ 15 test-liberty-z.bin \
16 test-cplus-demangle \ 16 test-cplus-demangle.bin \
17 test-libelf \ 17 test-libelf.bin \
18 test-libelf-getphdrnum \ 18 test-libelf-getphdrnum.bin \
19 test-libelf-mmap \ 19 test-libelf-mmap.bin \
20 test-libnuma \ 20 test-libnuma.bin \
21 test-libperl \ 21 test-libperl.bin \
22 test-libpython \ 22 test-libpython.bin \
23 test-libpython-version \ 23 test-libpython-version.bin \
24 test-libslang \ 24 test-libslang.bin \
25 test-libunwind \ 25 test-libunwind.bin \
26 test-libunwind-debug-frame \ 26 test-libunwind-debug-frame.bin \
27 test-on-exit \ 27 test-on-exit.bin \
28 test-stackprotector-all \ 28 test-stackprotector-all.bin \
29 test-stackprotector \ 29 test-timerfd.bin
30 test-timerfd
31 30
32CC := $(CC) -MD 31CC := $(CC) -MD
33 32
34all: $(FILES) 33all: $(FILES)
35 34
36BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c 35BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
37 36
38############################### 37###############################
39 38
40test-all: 39test-all.bin:
41 $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl 40 $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
42 41
43test-hello: 42test-hello.bin:
44 $(BUILD) 43 $(BUILD)
45 44
46test-stackprotector-all: 45test-stackprotector-all.bin:
47 $(BUILD) -Werror -fstack-protector-all 46 $(BUILD) -Werror -fstack-protector-all
48 47
49test-stackprotector: 48test-fortify-source.bin:
50 $(BUILD) -Werror -fstack-protector -Wstack-protector
51
52test-fortify-source:
53 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 49 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
54 50
55test-bionic: 51test-bionic.bin:
56 $(BUILD) 52 $(BUILD)
57 53
58test-libelf: 54test-libelf.bin:
59 $(BUILD) -lelf 55 $(BUILD) -lelf
60 56
61test-glibc: 57test-glibc.bin:
62 $(BUILD) 58 $(BUILD)
63 59
64test-dwarf: 60test-dwarf.bin:
65 $(BUILD) -ldw 61 $(BUILD) -ldw
66 62
67test-libelf-mmap: 63test-libelf-mmap.bin:
68 $(BUILD) -lelf 64 $(BUILD) -lelf
69 65
70test-libelf-getphdrnum: 66test-libelf-getphdrnum.bin:
71 $(BUILD) -lelf 67 $(BUILD) -lelf
72 68
73test-libnuma: 69test-libnuma.bin:
74 $(BUILD) -lnuma 70 $(BUILD) -lnuma
75 71
76test-libunwind: 72test-libunwind.bin:
77 $(BUILD) $(LIBUNWIND_LIBS) -lelf 73 $(BUILD) -lelf
78 74
79test-libunwind-debug-frame: 75test-libunwind-debug-frame.bin:
80 $(BUILD) $(LIBUNWIND_LIBS) -lelf 76 $(BUILD) -lelf
81 77
82test-libaudit: 78test-libaudit.bin:
83 $(BUILD) -laudit 79 $(BUILD) -laudit
84 80
85test-libslang: 81test-libslang.bin:
86 $(BUILD) -I/usr/include/slang -lslang 82 $(BUILD) -I/usr/include/slang -lslang
87 83
88test-gtk2: 84test-gtk2.bin:
89 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 85 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
90 86
91test-gtk2-infobar: 87test-gtk2-infobar.bin:
92 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 88 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
93 89
94grep-libs = $(filter -l%,$(1)) 90grep-libs = $(filter -l%,$(1))
@@ -100,7 +96,7 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
100PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 96PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
101FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 97FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
102 98
103test-libperl: 99test-libperl.bin:
104 $(BUILD) $(FLAGS_PERL_EMBED) 100 $(BUILD) $(FLAGS_PERL_EMBED)
105 101
106override PYTHON := python 102override PYTHON := python
@@ -117,31 +113,31 @@ PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
117PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 113PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
118FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 114FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
119 115
120test-libpython: 116test-libpython.bin:
121 $(BUILD) $(FLAGS_PYTHON_EMBED) 117 $(BUILD) $(FLAGS_PYTHON_EMBED)
122 118
123test-libpython-version: 119test-libpython-version.bin:
124 $(BUILD) $(FLAGS_PYTHON_EMBED) 120 $(BUILD) $(FLAGS_PYTHON_EMBED)
125 121
126test-libbfd: 122test-libbfd.bin:
127 $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl 123 $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
128 124
129test-liberty: 125test-liberty.bin:
130 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty 126 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
131 127
132test-liberty-z: 128test-liberty-z.bin:
133 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz 129 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
134 130
135test-cplus-demangle: 131test-cplus-demangle.bin:
136 $(BUILD) -liberty 132 $(BUILD) -liberty
137 133
138test-on-exit: 134test-on-exit.bin:
139 $(BUILD) 135 $(BUILD)
140 136
141test-backtrace: 137test-backtrace.bin:
142 $(BUILD) 138 $(BUILD)
143 139
144test-timerfd: 140test-timerfd.bin:
145 $(BUILD) 141 $(BUILD)
146 142
147-include *.d 143-include *.d
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 59e7a705e146..9b8a544155bb 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -85,6 +85,10 @@
85# include "test-timerfd.c" 85# include "test-timerfd.c"
86#undef main 86#undef main
87 87
88#define main main_test_stackprotector_all
89# include "test-stackprotector-all.c"
90#undef main
91
88int main(int argc, char *argv[]) 92int main(int argc, char *argv[])
89{ 93{
90 main_test_libpython(); 94 main_test_libpython();
@@ -106,6 +110,7 @@ int main(int argc, char *argv[])
106 main_test_backtrace(); 110 main_test_backtrace();
107 main_test_libnuma(); 111 main_test_libnuma();
108 main_test_timerfd(); 112 main_test_timerfd();
113 main_test_stackprotector_all();
109 114
110 return 0; 115 return 0;
111} 116}
diff --git a/tools/perf/config/feature-checks/test-stackprotector.c b/tools/perf/config/feature-checks/test-stackprotector.c
deleted file mode 100644
index c9f398d87868..000000000000
--- a/tools/perf/config/feature-checks/test-stackprotector.c
+++ /dev/null
@@ -1,6 +0,0 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-volatile-register-var.c b/tools/perf/config/feature-checks/test-volatile-register-var.c
deleted file mode 100644
index c9f398d87868..000000000000
--- a/tools/perf/config/feature-checks/test-volatile-register-var.c
+++ /dev/null
@@ -1,6 +0,0 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index f168debc5be2..4d985e0f03f5 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -178,10 +178,3 @@ endef
178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181
182ifneq ($(findstring $(MAKEFLAGS),s),s)
183 ifneq ($(V),1)
184 QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
185 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
186 endif
187endif
diff --git a/tools/perf/bash_completion b/tools/perf/perf-completion.sh
index 62e157db2e2b..496e2abb5482 100644
--- a/tools/perf/bash_completion
+++ b/tools/perf/perf-completion.sh
@@ -1,4 +1,4 @@
1# perf completion 1# perf bash and zsh completion
2 2
3# Taken from git.git's completion script. 3# Taken from git.git's completion script.
4__my_reassemble_comp_words_by_ref() 4__my_reassemble_comp_words_by_ref()
@@ -89,37 +89,117 @@ __ltrim_colon_completions()
89 fi 89 fi
90} 90}
91 91
92type perf &>/dev/null && 92__perfcomp ()
93_perf()
94{ 93{
95 local cur words cword prev cmd 94 COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
95}
96 96
97 COMPREPLY=() 97__perfcomp_colon ()
98 _get_comp_words_by_ref -n =: cur words cword prev 98{
99 __perfcomp "$1" "$2"
100 __ltrim_colon_completions $cur
101}
102
103__perf_main ()
104{
105 local cmd
99 106
100 cmd=${words[0]} 107 cmd=${words[0]}
108 COMPREPLY=()
101 109
102 # List perf subcommands or long options 110 # List perf subcommands or long options
103 if [ $cword -eq 1 ]; then 111 if [ $cword -eq 1 ]; then
104 if [[ $cur == --* ]]; then 112 if [[ $cur == --* ]]; then
105 COMPREPLY=( $( compgen -W '--help --version \ 113 __perfcomp '--help --version \
106 --exec-path --html-path --paginate --no-pager \ 114 --exec-path --html-path --paginate --no-pager \
107 --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) 115 --perf-dir --work-tree --debugfs-dir' -- "$cur"
108 else 116 else
109 cmds=$($cmd --list-cmds) 117 cmds=$($cmd --list-cmds)
110 COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) 118 __perfcomp "$cmds" "$cur"
111 fi 119 fi
112 # List possible events for -e option 120 # List possible events for -e option
113 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then 121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
114 evts=$($cmd list --raw-dump) 122 evts=$($cmd list --raw-dump)
115 COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) 123 __perfcomp_colon "$evts" "$cur"
116 __ltrim_colon_completions $cur 124 # List subcommands for 'perf kvm'
125 elif [[ $prev == "kvm" ]]; then
126 subcmds="top record report diff buildid-list stat"
127 __perfcomp_colon "$subcmds" "$cur"
117 # List long option names 128 # List long option names
118 elif [[ $cur == --* ]]; then 129 elif [[ $cur == --* ]]; then
119 subcmd=${words[1]} 130 subcmd=${words[1]}
120 opts=$($cmd $subcmd --list-opts) 131 opts=$($cmd $subcmd --list-opts)
121 COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) 132 __perfcomp "$opts" "$cur"
122 fi 133 fi
134}
135
136if [[ -n ${ZSH_VERSION-} ]]; then
137 autoload -U +X compinit && compinit
138
139 __perfcomp ()
140 {
141 emulate -L zsh
142
143 local c IFS=$' \t\n'
144 local -a array
145
146 for c in ${=1}; do
147 case $c in
148 --*=*|*.) ;;
149 *) c="$c " ;;
150 esac
151 array[${#array[@]}+1]="$c"
152 done
153
154 compset -P '*[=:]'
155 compadd -Q -S '' -a -- array && _ret=0
156 }
157
158 __perfcomp_colon ()
159 {
160 emulate -L zsh
161
162 local cur_="${2-$cur}"
163 local c IFS=$' \t\n'
164 local -a array
165
166 if [[ "$cur_" == *:* ]]; then
167 local colon_word=${cur_%"${cur_##*:}"}
168 fi
169
170 for c in ${=1}; do
171 case $c in
172 --*=*|*.) ;;
173 *) c="$c " ;;
174 esac
175 array[$#array+1]=${c#"$colon_word"}
176 done
177
178 compset -P '*[=:]'
179 compadd -Q -S '' -a -- array && _ret=0
180 }
181
182 _perf ()
183 {
184 local _ret=1 cur cword prev
185 cur=${words[CURRENT]}
186 prev=${words[CURRENT-1]}
187 let cword=CURRENT-1
188 emulate ksh -c __perf_main
189 let _ret && _default && _ret=0
190 return _ret
191 }
192
193 compdef _perf perf
194 return
195fi
196
197type perf &>/dev/null &&
198_perf()
199{
200 local cur words cword prev
201 _get_comp_words_by_ref -n =: cur words cword prev
202 __perf_main
123} && 203} &&
124 204
125complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ 205complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 8b38b4e80ec2..431798a4110d 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,7 +13,7 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include <lk/debugfs.h> 16#include <api/fs/debugfs.h>
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char perf_usage_string[] = 19const char perf_usage_string[] =
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index b079304bd53d..af1ce6e14a93 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -247,13 +247,14 @@ enum perf_call_graph_mode {
247 CALLCHAIN_DWARF 247 CALLCHAIN_DWARF
248}; 248};
249 249
250struct perf_record_opts { 250struct record_opts {
251 struct target target; 251 struct target target;
252 int call_graph; 252 int call_graph;
253 bool group; 253 bool group;
254 bool inherit_stat; 254 bool inherit_stat;
255 bool no_delay; 255 bool no_delay;
256 bool no_inherit; 256 bool no_inherit;
257 bool no_inherit_set;
257 bool no_samples; 258 bool no_samples;
258 bool raw_samples; 259 bool raw_samples;
259 bool sample_address; 260 bool sample_address;
@@ -268,6 +269,7 @@ struct perf_record_opts {
268 u64 user_interval; 269 u64 user_interval;
269 u16 stack_dump_size; 270 u16 stack_dump_size;
270 bool sample_transaction; 271 bool sample_transaction;
272 unsigned initial_delay;
271}; 273};
272 274
273#endif 275#endif
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
index 9079a25cd643..44edcb2edcd5 100644
--- a/tools/perf/tests/attr/test-record-no-inherit
+++ b/tools/perf/tests/attr/test-record-no-inherit
@@ -3,5 +3,5 @@ command = record
3args = -i kill >/dev/null 2>&1 3args = -i kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_type=259 6sample_type=263
7inherit=0 7inherit=0
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 85d4919dd623..653a8fe2db95 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -391,7 +391,7 @@ static int do_test_code_reading(bool try_kcore)
391 struct machines machines; 391 struct machines machines;
392 struct machine *machine; 392 struct machine *machine;
393 struct thread *thread; 393 struct thread *thread;
394 struct perf_record_opts opts = { 394 struct record_opts opts = {
395 .mmap_pages = UINT_MAX, 395 .mmap_pages = UINT_MAX,
396 .user_freq = UINT_MAX, 396 .user_freq = UINT_MAX,
397 .user_interval = ULLONG_MAX, 397 .user_interval = ULLONG_MAX,
@@ -540,14 +540,11 @@ static int do_test_code_reading(bool try_kcore)
540 err = TEST_CODE_READING_OK; 540 err = TEST_CODE_READING_OK;
541out_err: 541out_err:
542 if (evlist) { 542 if (evlist) {
543 perf_evlist__munmap(evlist);
544 perf_evlist__close(evlist);
545 perf_evlist__delete(evlist); 543 perf_evlist__delete(evlist);
546 } 544 } else {
547 if (cpus)
548 cpu_map__delete(cpus); 545 cpu_map__delete(cpus);
549 if (threads)
550 thread_map__delete(threads); 546 thread_map__delete(threads);
547 }
551 machines__destroy_kernel_maps(&machines); 548 machines__destroy_kernel_maps(&machines);
552 machine__delete_threads(machine); 549 machine__delete_threads(machine);
553 machines__exit(&machines); 550 machines__exit(&machines);
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 0197bda9c461..465cdbc345cf 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -79,7 +79,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
79 } 79 }
80 80
81 err = 0; 81 err = 0;
82 list_for_each_entry(evsel, &evlist->entries, node) { 82 evlist__for_each(evlist, evsel) {
83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { 83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
84 --err; 84 --err;
85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); 85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 173bf42cc03e..2b6519e0e36f 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -208,7 +208,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
208 * However the second evsel also has a collapsed entry for 208 * However the second evsel also has a collapsed entry for
209 * "bash [libc] malloc" so total 9 entries will be in the tree. 209 * "bash [libc] malloc" so total 9 entries will be in the tree.
210 */ 210 */
211 list_for_each_entry(evsel, &evlist->entries, node) { 211 evlist__for_each(evlist, evsel) {
212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
213 const union perf_event event = { 213 const union perf_event event = {
214 .header = { 214 .header = {
@@ -466,7 +466,7 @@ int test__hists_link(void)
466 if (err < 0) 466 if (err < 0)
467 goto out; 467 goto out;
468 468
469 list_for_each_entry(evsel, &evlist->entries, node) { 469 evlist__for_each(evlist, evsel) {
470 hists__collapse_resort(&evsel->hists, NULL); 470 hists__collapse_resort(&evsel->hists, NULL);
471 471
472 if (verbose > 2) 472 if (verbose > 2)
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 376c35608534..497957f269d8 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -51,7 +51,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
51 */ 51 */
52int test__keep_tracking(void) 52int test__keep_tracking(void)
53{ 53{
54 struct perf_record_opts opts = { 54 struct record_opts opts = {
55 .mmap_pages = UINT_MAX, 55 .mmap_pages = UINT_MAX,
56 .user_freq = UINT_MAX, 56 .user_freq = UINT_MAX,
57 .user_interval = ULLONG_MAX, 57 .user_interval = ULLONG_MAX,
@@ -142,14 +142,11 @@ int test__keep_tracking(void)
142out_err: 142out_err:
143 if (evlist) { 143 if (evlist) {
144 perf_evlist__disable(evlist); 144 perf_evlist__disable(evlist);
145 perf_evlist__munmap(evlist);
146 perf_evlist__close(evlist);
147 perf_evlist__delete(evlist); 145 perf_evlist__delete(evlist);
148 } 146 } else {
149 if (cpus)
150 cpu_map__delete(cpus); 147 cpu_map__delete(cpus);
151 if (threads)
152 thread_map__delete(threads); 148 thread_map__delete(threads);
149 }
153 150
154 return err; 151 return err;
155} 152}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2ca0abf1b2b6..00544b8b644b 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,6 +1,16 @@
1PERF := . 1PERF := .
2MK := Makefile 2MK := Makefile
3 3
4include config/Makefile.arch
5
6# FIXME looks like x86 is the only arch running tests ;-)
7# we need some IS_(32/64) flag to make this generic
8ifeq ($(IS_X86_64),1)
9lib = lib64
10else
11lib = lib
12endif
13
4has = $(shell which $1 2>/dev/null) 14has = $(shell which $1 2>/dev/null)
5 15
6# standard single make variable specified 16# standard single make variable specified
@@ -106,10 +116,36 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so
106test_make_perf_o := test -f $(PERF)/perf.o 116test_make_perf_o := test -f $(PERF)/perf.o
107test_make_util_map_o := test -f $(PERF)/util/map.o 117test_make_util_map_o := test -f $(PERF)/util/map.o
108 118
109test_make_install := test -x $$TMP_DEST/bin/perf 119define test_dest_files
110test_make_install_O := $(test_make_install) 120 for file in $(1); do \
111test_make_install_bin := $(test_make_install) 121 if [ ! -x $$TMP_DEST/$$file ]; then \
112test_make_install_bin_O := $(test_make_install) 122 echo " failed to find: $$file"; \
123 fi \
124 done
125endef
126
127installed_files_bin := bin/perf
128installed_files_bin += etc/bash_completion.d/perf
129installed_files_bin += libexec/perf-core/perf-archive
130
131installed_files_plugins := $(lib)/traceevent/plugins/plugin_cfg80211.so
132installed_files_plugins += $(lib)/traceevent/plugins/plugin_scsi.so
133installed_files_plugins += $(lib)/traceevent/plugins/plugin_xen.so
134installed_files_plugins += $(lib)/traceevent/plugins/plugin_function.so
135installed_files_plugins += $(lib)/traceevent/plugins/plugin_sched_switch.so
136installed_files_plugins += $(lib)/traceevent/plugins/plugin_mac80211.so
137installed_files_plugins += $(lib)/traceevent/plugins/plugin_kvm.so
138installed_files_plugins += $(lib)/traceevent/plugins/plugin_kmem.so
139installed_files_plugins += $(lib)/traceevent/plugins/plugin_hrtimer.so
140installed_files_plugins += $(lib)/traceevent/plugins/plugin_jbd2.so
141
142installed_files_all := $(installed_files_bin)
143installed_files_all += $(installed_files_plugins)
144
145test_make_install := $(call test_dest_files,$(installed_files_all))
146test_make_install_O := $(call test_dest_files,$(installed_files_all))
147test_make_install_bin := $(call test_dest_files,$(installed_files_bin))
148test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin))
113 149
114# FIXME nothing gets installed 150# FIXME nothing gets installed
115test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 151test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
@@ -162,7 +198,7 @@ $(run):
162 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ 198 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
163 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 199 echo "- $@: $$cmd" && echo $$cmd > $@ && \
164 ( eval $$cmd ) >> $@ 2>&1; \ 200 ( eval $$cmd ) >> $@ 2>&1; \
165 echo " test: $(call test,$@)"; \ 201 echo " test: $(call test,$@)" >> $@ 2>&1; \
166 $(call test,$@) && \ 202 $(call test,$@) && \
167 rm -f $@ \ 203 rm -f $@ \
168 rm -rf $$TMP_DEST 204 rm -rf $$TMP_DEST
@@ -174,16 +210,22 @@ $(run_O):
174 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 210 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
175 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 211 echo "- $@: $$cmd" && echo $$cmd > $@ && \
176 ( eval $$cmd ) >> $@ 2>&1 && \ 212 ( eval $$cmd ) >> $@ 2>&1 && \
177 echo " test: $(call test_O,$@)"; \ 213 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
178 $(call test_O,$@) && \ 214 $(call test_O,$@) && \
179 rm -f $@ && \ 215 rm -f $@ && \
180 rm -rf $$TMP_O \ 216 rm -rf $$TMP_O \
181 rm -rf $$TMP_DEST 217 rm -rf $$TMP_DEST
182 218
183all: $(run) $(run_O) 219tarpkg:
220 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
221 echo "- $@: $$cmd" && echo $$cmd > $@ && \
222 ( eval $$cmd ) >> $@ 2>&1
223
224
225all: $(run) $(run_O) tarpkg
184 @echo OK 226 @echo OK
185 227
186out: $(run_O) 228out: $(run_O)
187 @echo OK 229 @echo OK
188 230
189.PHONY: all $(run) $(run_O) clean 231.PHONY: all $(run) $(run_O) tarpkg clean
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index d64ab79c6d35..142263492f6f 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -68,7 +68,7 @@ int test__basic_mmap(void)
68 evsels[i] = perf_evsel__newtp("syscalls", name); 68 evsels[i] = perf_evsel__newtp("syscalls", name);
69 if (evsels[i] == NULL) { 69 if (evsels[i] == NULL) {
70 pr_debug("perf_evsel__new\n"); 70 pr_debug("perf_evsel__new\n");
71 goto out_free_evlist; 71 goto out_delete_evlist;
72 } 72 }
73 73
74 evsels[i]->attr.wakeup_events = 1; 74 evsels[i]->attr.wakeup_events = 1;
@@ -80,7 +80,7 @@ int test__basic_mmap(void)
80 pr_debug("failed to open counter: %s, " 80 pr_debug("failed to open counter: %s, "
81 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 81 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
82 strerror(errno)); 82 strerror(errno));
83 goto out_close_fd; 83 goto out_delete_evlist;
84 } 84 }
85 85
86 nr_events[i] = 0; 86 nr_events[i] = 0;
@@ -90,7 +90,7 @@ int test__basic_mmap(void)
90 if (perf_evlist__mmap(evlist, 128, true) < 0) { 90 if (perf_evlist__mmap(evlist, 128, true) < 0) {
91 pr_debug("failed to mmap events: %d (%s)\n", errno, 91 pr_debug("failed to mmap events: %d (%s)\n", errno,
92 strerror(errno)); 92 strerror(errno));
93 goto out_close_fd; 93 goto out_delete_evlist;
94 } 94 }
95 95
96 for (i = 0; i < nsyscalls; ++i) 96 for (i = 0; i < nsyscalls; ++i)
@@ -105,13 +105,13 @@ int test__basic_mmap(void)
105 if (event->header.type != PERF_RECORD_SAMPLE) { 105 if (event->header.type != PERF_RECORD_SAMPLE) {
106 pr_debug("unexpected %s event\n", 106 pr_debug("unexpected %s event\n",
107 perf_event__name(event->header.type)); 107 perf_event__name(event->header.type));
108 goto out_munmap; 108 goto out_delete_evlist;
109 } 109 }
110 110
111 err = perf_evlist__parse_sample(evlist, event, &sample); 111 err = perf_evlist__parse_sample(evlist, event, &sample);
112 if (err) { 112 if (err) {
113 pr_err("Can't parse sample, err = %d\n", err); 113 pr_err("Can't parse sample, err = %d\n", err);
114 goto out_munmap; 114 goto out_delete_evlist;
115 } 115 }
116 116
117 err = -1; 117 err = -1;
@@ -119,30 +119,27 @@ int test__basic_mmap(void)
119 if (evsel == NULL) { 119 if (evsel == NULL) {
120 pr_debug("event with id %" PRIu64 120 pr_debug("event with id %" PRIu64
121 " doesn't map to an evsel\n", sample.id); 121 " doesn't map to an evsel\n", sample.id);
122 goto out_munmap; 122 goto out_delete_evlist;
123 } 123 }
124 nr_events[evsel->idx]++; 124 nr_events[evsel->idx]++;
125 perf_evlist__mmap_consume(evlist, 0); 125 perf_evlist__mmap_consume(evlist, 0);
126 } 126 }
127 127
128 err = 0; 128 err = 0;
129 list_for_each_entry(evsel, &evlist->entries, node) { 129 evlist__for_each(evlist, evsel) {
130 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 130 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
131 pr_debug("expected %d %s events, got %d\n", 131 pr_debug("expected %d %s events, got %d\n",
132 expected_nr_events[evsel->idx], 132 expected_nr_events[evsel->idx],
133 perf_evsel__name(evsel), nr_events[evsel->idx]); 133 perf_evsel__name(evsel), nr_events[evsel->idx]);
134 err = -1; 134 err = -1;
135 goto out_munmap; 135 goto out_delete_evlist;
136 } 136 }
137 } 137 }
138 138
139out_munmap: 139out_delete_evlist:
140 perf_evlist__munmap(evlist);
141out_close_fd:
142 for (i = 0; i < nsyscalls; ++i)
143 perf_evsel__close_fd(evsels[i], 1, threads->nr);
144out_free_evlist:
145 perf_evlist__delete(evlist); 140 perf_evlist__delete(evlist);
141 cpus = NULL;
142 threads = NULL;
146out_free_cpus: 143out_free_cpus:
147 cpu_map__delete(cpus); 144 cpu_map__delete(cpus);
148out_free_threads: 145out_free_threads:
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 41cc0badb74b..5a016f66f5d2 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -6,7 +6,7 @@
6 6
7int test__syscall_open_tp_fields(void) 7int test__syscall_open_tp_fields(void)
8{ 8{
9 struct perf_record_opts opts = { 9 struct record_opts opts = {
10 .target = { 10 .target = {
11 .uid = UINT_MAX, 11 .uid = UINT_MAX,
12 .uses_mmap = true, 12 .uses_mmap = true,
@@ -48,13 +48,13 @@ int test__syscall_open_tp_fields(void)
48 err = perf_evlist__open(evlist); 48 err = perf_evlist__open(evlist);
49 if (err < 0) { 49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_maps; 51 goto out_delete_evlist;
52 } 52 }
53 53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false); 54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) { 55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_close_evlist; 57 goto out_delete_evlist;
58 } 58 }
59 59
60 perf_evlist__enable(evlist); 60 perf_evlist__enable(evlist);
@@ -85,7 +85,7 @@ int test__syscall_open_tp_fields(void)
85 err = perf_evsel__parse_sample(evsel, event, &sample); 85 err = perf_evsel__parse_sample(evsel, event, &sample);
86 if (err) { 86 if (err) {
87 pr_err("Can't parse sample, err = %d\n", err); 87 pr_err("Can't parse sample, err = %d\n", err);
88 goto out_munmap; 88 goto out_delete_evlist;
89 } 89 }
90 90
91 tp_flags = perf_evsel__intval(evsel, &sample, "flags"); 91 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
@@ -93,7 +93,7 @@ int test__syscall_open_tp_fields(void)
93 if (flags != tp_flags) { 93 if (flags != tp_flags) {
94 pr_debug("%s: Expected flags=%#x, got %#x\n", 94 pr_debug("%s: Expected flags=%#x, got %#x\n",
95 __func__, flags, tp_flags); 95 __func__, flags, tp_flags);
96 goto out_munmap; 96 goto out_delete_evlist;
97 } 97 }
98 98
99 goto out_ok; 99 goto out_ok;
@@ -105,17 +105,11 @@ int test__syscall_open_tp_fields(void)
105 105
106 if (++nr_polls > 5) { 106 if (++nr_polls > 5) {
107 pr_debug("%s: no events!\n", __func__); 107 pr_debug("%s: no events!\n", __func__);
108 goto out_munmap; 108 goto out_delete_evlist;
109 } 109 }
110 } 110 }
111out_ok: 111out_ok:
112 err = 0; 112 err = 0;
113out_munmap:
114 perf_evlist__munmap(evlist);
115out_close_evlist:
116 perf_evlist__close(evlist);
117out_delete_maps:
118 perf_evlist__delete_maps(evlist);
119out_delete_evlist: 113out_delete_evlist:
120 perf_evlist__delete(evlist); 114 perf_evlist__delete(evlist);
121out: 115out:
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 3cbd10496087..4db0ae617d70 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,7 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "fs.h" 5#include "fs.h"
6#include <lk/debugfs.h> 6#include <api/fs/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
9 9
@@ -30,7 +30,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
30 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 30 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
31 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); 31 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
32 32
33 list_for_each_entry(evsel, &evlist->entries, node) { 33 evlist__for_each(evlist, evsel) {
34 TEST_ASSERT_VAL("wrong type", 34 TEST_ASSERT_VAL("wrong type",
35 PERF_TYPE_TRACEPOINT == evsel->attr.type); 35 PERF_TYPE_TRACEPOINT == evsel->attr.type);
36 TEST_ASSERT_VAL("wrong sample_type", 36 TEST_ASSERT_VAL("wrong sample_type",
@@ -201,7 +201,7 @@ test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
201 201
202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
203 203
204 list_for_each_entry(evsel, &evlist->entries, node) { 204 evlist__for_each(evlist, evsel) {
205 TEST_ASSERT_VAL("wrong exclude_user", 205 TEST_ASSERT_VAL("wrong exclude_user",
206 !evsel->attr.exclude_user); 206 !evsel->attr.exclude_user);
207 TEST_ASSERT_VAL("wrong exclude_kernel", 207 TEST_ASSERT_VAL("wrong exclude_kernel",
@@ -1385,10 +1385,10 @@ static int test_event(struct evlist_test *e)
1385 if (ret) { 1385 if (ret) {
1386 pr_debug("failed to parse event '%s', err %d\n", 1386 pr_debug("failed to parse event '%s', err %d\n",
1387 e->name, ret); 1387 e->name, ret);
1388 return ret; 1388 } else {
1389 ret = e->check(evlist);
1389 } 1390 }
1390 1391
1391 ret = e->check(evlist);
1392 perf_evlist__delete(evlist); 1392 perf_evlist__delete(evlist);
1393 1393
1394 return ret; 1394 return ret;
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 93a62b06c3af..39cc7c3c0d0c 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -34,7 +34,7 @@ realloc:
34 34
35int test__PERF_RECORD(void) 35int test__PERF_RECORD(void)
36{ 36{
37 struct perf_record_opts opts = { 37 struct record_opts opts = {
38 .target = { 38 .target = {
39 .uid = UINT_MAX, 39 .uid = UINT_MAX,
40 .uses_mmap = true, 40 .uses_mmap = true,
@@ -83,11 +83,10 @@ int test__PERF_RECORD(void)
83 * so that we have time to open the evlist (calling sys_perf_event_open 83 * so that we have time to open the evlist (calling sys_perf_event_open
84 * on all the fds) and then mmap them. 84 * on all the fds) and then mmap them.
85 */ 85 */
86 err = perf_evlist__prepare_workload(evlist, &opts.target, argv, 86 err = perf_evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
87 false, false);
88 if (err < 0) { 87 if (err < 0) {
89 pr_debug("Couldn't run the workload!\n"); 88 pr_debug("Couldn't run the workload!\n");
90 goto out_delete_maps; 89 goto out_delete_evlist;
91 } 90 }
92 91
93 /* 92 /*
@@ -102,7 +101,7 @@ int test__PERF_RECORD(void)
102 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 101 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
103 if (err < 0) { 102 if (err < 0) {
104 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 103 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
105 goto out_delete_maps; 104 goto out_delete_evlist;
106 } 105 }
107 106
108 cpu = err; 107 cpu = err;
@@ -112,7 +111,7 @@ int test__PERF_RECORD(void)
112 */ 111 */
113 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 112 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
114 pr_debug("sched_setaffinity: %s\n", strerror(errno)); 113 pr_debug("sched_setaffinity: %s\n", strerror(errno));
115 goto out_delete_maps; 114 goto out_delete_evlist;
116 } 115 }
117 116
118 /* 117 /*
@@ -122,7 +121,7 @@ int test__PERF_RECORD(void)
122 err = perf_evlist__open(evlist); 121 err = perf_evlist__open(evlist);
123 if (err < 0) { 122 if (err < 0) {
124 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 123 pr_debug("perf_evlist__open: %s\n", strerror(errno));
125 goto out_delete_maps; 124 goto out_delete_evlist;
126 } 125 }
127 126
128 /* 127 /*
@@ -133,7 +132,7 @@ int test__PERF_RECORD(void)
133 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 132 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
134 if (err < 0) { 133 if (err < 0) {
135 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 134 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
136 goto out_close_evlist; 135 goto out_delete_evlist;
137 } 136 }
138 137
139 /* 138 /*
@@ -166,7 +165,7 @@ int test__PERF_RECORD(void)
166 if (verbose) 165 if (verbose)
167 perf_event__fprintf(event, stderr); 166 perf_event__fprintf(event, stderr);
168 pr_debug("Couldn't parse sample\n"); 167 pr_debug("Couldn't parse sample\n");
169 goto out_err; 168 goto out_delete_evlist;
170 } 169 }
171 170
172 if (verbose) { 171 if (verbose) {
@@ -303,12 +302,6 @@ found_exit:
303 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); 302 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
304 ++errs; 303 ++errs;
305 } 304 }
306out_err:
307 perf_evlist__munmap(evlist);
308out_close_evlist:
309 perf_evlist__close(evlist);
310out_delete_maps:
311 perf_evlist__delete_maps(evlist);
312out_delete_evlist: 305out_delete_evlist:
313 perf_evlist__delete(evlist); 306 perf_evlist__delete(evlist);
314out: 307out:
diff --git a/tools/perf/tests/perf-targz-src-pkg b/tools/perf/tests/perf-targz-src-pkg
new file mode 100755
index 000000000000..238aa3927c71
--- /dev/null
+++ b/tools/perf/tests/perf-targz-src-pkg
@@ -0,0 +1,21 @@
1#!/bin/sh
2# Test one of the main kernel Makefile targets to generate a perf sources tarball
3# suitable for build outside the full kernel sources.
4#
5# This is to test that the tools/perf/MANIFEST file lists all the files needed to
6# be in such tarball, which sometimes gets broken when we move files around,
7# like when we made some files that were in tools/perf/ available to other tools/
8# codebases by moving it to tools/include/, etc.
9
10PERF=$1
11cd ${PERF}/../..
12make perf-targz-src-pkg > /dev/null
13TARBALL=$(ls -rt perf-*.tar.gz)
14TMP_DEST=$(mktemp -d)
15tar xf ${TARBALL} -C $TMP_DEST
16rm -f ${TARBALL}
17cd - > /dev/null
18make -C $TMP_DEST/perf*/tools/perf > /dev/null 2>&1
19RC=$?
20rm -rf ${TMP_DEST}
21exit $RC
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 4ca1b938f6a6..47146d388dbf 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -46,7 +46,7 @@ static u64 rdtsc(void)
46 */ 46 */
47int test__perf_time_to_tsc(void) 47int test__perf_time_to_tsc(void)
48{ 48{
49 struct perf_record_opts opts = { 49 struct record_opts opts = {
50 .mmap_pages = UINT_MAX, 50 .mmap_pages = UINT_MAX,
51 .user_freq = UINT_MAX, 51 .user_freq = UINT_MAX,
52 .user_interval = ULLONG_MAX, 52 .user_interval = ULLONG_MAX,
@@ -166,14 +166,8 @@ next_event:
166out_err: 166out_err:
167 if (evlist) { 167 if (evlist) {
168 perf_evlist__disable(evlist); 168 perf_evlist__disable(evlist);
169 perf_evlist__munmap(evlist);
170 perf_evlist__close(evlist);
171 perf_evlist__delete(evlist); 169 perf_evlist__delete(evlist);
172 } 170 }
173 if (cpus)
174 cpu_map__delete(cpus);
175 if (threads)
176 thread_map__delete(threads);
177 171
178 return err; 172 return err;
179} 173}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 6664a7cd828c..983d6b8562a8 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -45,7 +45,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
45 evsel = perf_evsel__new(&attr); 45 evsel = perf_evsel__new(&attr);
46 if (evsel == NULL) { 46 if (evsel == NULL) {
47 pr_debug("perf_evsel__new\n"); 47 pr_debug("perf_evsel__new\n");
48 goto out_free_evlist; 48 goto out_delete_evlist;
49 } 49 }
50 perf_evlist__add(evlist, evsel); 50 perf_evlist__add(evlist, evsel);
51 51
@@ -54,7 +54,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
54 if (!evlist->cpus || !evlist->threads) { 54 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM; 55 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n"); 56 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps; 57 goto out_delete_evlist;
58 } 58 }
59 59
60 if (perf_evlist__open(evlist)) { 60 if (perf_evlist__open(evlist)) {
@@ -63,14 +63,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
63 err = -errno; 63 err = -errno;
64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", 64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
65 strerror(errno), knob, (u64)attr.sample_freq); 65 strerror(errno), knob, (u64)attr.sample_freq);
66 goto out_delete_maps; 66 goto out_delete_evlist;
67 } 67 }
68 68
69 err = perf_evlist__mmap(evlist, 128, true); 69 err = perf_evlist__mmap(evlist, 128, true);
70 if (err < 0) { 70 if (err < 0) {
71 pr_debug("failed to mmap event: %d (%s)\n", errno, 71 pr_debug("failed to mmap event: %d (%s)\n", errno,
72 strerror(errno)); 72 strerror(errno));
73 goto out_close_evlist; 73 goto out_delete_evlist;
74 } 74 }
75 75
76 perf_evlist__enable(evlist); 76 perf_evlist__enable(evlist);
@@ -90,7 +90,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
90 err = perf_evlist__parse_sample(evlist, event, &sample); 90 err = perf_evlist__parse_sample(evlist, event, &sample);
91 if (err < 0) { 91 if (err < 0) {
92 pr_debug("Error during parse sample\n"); 92 pr_debug("Error during parse sample\n");
93 goto out_unmap_evlist; 93 goto out_delete_evlist;
94 } 94 }
95 95
96 total_periods += sample.period; 96 total_periods += sample.period;
@@ -105,13 +105,7 @@ next_event:
105 err = -1; 105 err = -1;
106 } 106 }
107 107
108out_unmap_evlist: 108out_delete_evlist:
109 perf_evlist__munmap(evlist);
110out_close_evlist:
111 perf_evlist__close(evlist);
112out_delete_maps:
113 perf_evlist__delete_maps(evlist);
114out_free_evlist:
115 perf_evlist__delete(evlist); 109 perf_evlist__delete(evlist);
116 return err; 110 return err;
117} 111}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index d09ab579119e..5ff3db318f12 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -9,12 +9,21 @@
9static int exited; 9static int exited;
10static int nr_exit; 10static int nr_exit;
11 11
12static void sig_handler(int sig) 12static void sig_handler(int sig __maybe_unused)
13{ 13{
14 exited = 1; 14 exited = 1;
15}
15 16
16 if (sig == SIGUSR1) 17/*
17 nr_exit = -1; 18 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since
19 * we asked by setting its exec_error to this handler.
20 */
21static void workload_exec_failed_signal(int signo __maybe_unused,
22 siginfo_t *info __maybe_unused,
23 void *ucontext __maybe_unused)
24{
25 exited = 1;
26 nr_exit = -1;
18} 27}
19 28
20/* 29/*
@@ -35,7 +44,6 @@ int test__task_exit(void)
35 const char *argv[] = { "true", NULL }; 44 const char *argv[] = { "true", NULL };
36 45
37 signal(SIGCHLD, sig_handler); 46 signal(SIGCHLD, sig_handler);
38 signal(SIGUSR1, sig_handler);
39 47
40 evlist = perf_evlist__new_default(); 48 evlist = perf_evlist__new_default();
41 if (evlist == NULL) { 49 if (evlist == NULL) {
@@ -54,13 +62,14 @@ int test__task_exit(void)
54 if (!evlist->cpus || !evlist->threads) { 62 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM; 63 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n"); 64 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps; 65 goto out_delete_evlist;
58 } 66 }
59 67
60 err = perf_evlist__prepare_workload(evlist, &target, argv, false, true); 68 err = perf_evlist__prepare_workload(evlist, &target, argv, false,
69 workload_exec_failed_signal);
61 if (err < 0) { 70 if (err < 0) {
62 pr_debug("Couldn't run the workload!\n"); 71 pr_debug("Couldn't run the workload!\n");
63 goto out_delete_maps; 72 goto out_delete_evlist;
64 } 73 }
65 74
66 evsel = perf_evlist__first(evlist); 75 evsel = perf_evlist__first(evlist);
@@ -74,13 +83,13 @@ int test__task_exit(void)
74 err = perf_evlist__open(evlist); 83 err = perf_evlist__open(evlist);
75 if (err < 0) { 84 if (err < 0) {
76 pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); 85 pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
77 goto out_delete_maps; 86 goto out_delete_evlist;
78 } 87 }
79 88
80 if (perf_evlist__mmap(evlist, 128, true) < 0) { 89 if (perf_evlist__mmap(evlist, 128, true) < 0) {
81 pr_debug("failed to mmap events: %d (%s)\n", errno, 90 pr_debug("failed to mmap events: %d (%s)\n", errno,
82 strerror(errno)); 91 strerror(errno));
83 goto out_close_evlist; 92 goto out_delete_evlist;
84 } 93 }
85 94
86 perf_evlist__start_workload(evlist); 95 perf_evlist__start_workload(evlist);
@@ -103,11 +112,7 @@ retry:
103 err = -1; 112 err = -1;
104 } 113 }
105 114
106 perf_evlist__munmap(evlist); 115out_delete_evlist:
107out_close_evlist:
108 perf_evlist__close(evlist);
109out_delete_maps:
110 perf_evlist__delete_maps(evlist);
111 perf_evlist__delete(evlist); 116 perf_evlist__delete(evlist);
112 return err; 117 return err;
113} 118}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index cbaa7af45513..d11541d4d7d7 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -256,8 +256,7 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
256 __ui_browser__show_title(browser, title); 256 __ui_browser__show_title(browser, title);
257 257
258 browser->title = title; 258 browser->title = title;
259 free(browser->helpline); 259 zfree(&browser->helpline);
260 browser->helpline = NULL;
261 260
262 va_start(ap, helpline); 261 va_start(ap, helpline);
263 err = vasprintf(&browser->helpline, helpline, ap); 262 err = vasprintf(&browser->helpline, helpline, ap);
@@ -268,12 +267,11 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
268 return err ? 0 : -1; 267 return err ? 0 : -1;
269} 268}
270 269
271void ui_browser__hide(struct ui_browser *browser __maybe_unused) 270void ui_browser__hide(struct ui_browser *browser)
272{ 271{
273 pthread_mutex_lock(&ui__lock); 272 pthread_mutex_lock(&ui__lock);
274 ui_helpline__pop(); 273 ui_helpline__pop();
275 free(browser->helpline); 274 zfree(&browser->helpline);
276 browser->helpline = NULL;
277 pthread_mutex_unlock(&ui__lock); 275 pthread_mutex_unlock(&ui__lock);
278} 276}
279 277
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 7d45d2f53601..118cca29dd26 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -59,6 +59,8 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text);
59bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 59bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
60int ui_browser__input_window(const char *title, const char *text, char *input, 60int ui_browser__input_window(const char *title, const char *text, char *input,
61 const char *exit_msg, int delay_sec); 61 const char *exit_msg, int delay_sec);
62struct perf_session_env;
63int tui__header_window(struct perf_session_env *env);
62 64
63void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 65void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
64unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 66unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c
new file mode 100644
index 000000000000..89c16b988618
--- /dev/null
+++ b/tools/perf/ui/browsers/header.c
@@ -0,0 +1,127 @@
1#include "util/cache.h"
2#include "util/debug.h"
3#include "ui/browser.h"
4#include "ui/ui.h"
5#include "ui/util.h"
6#include "ui/libslang.h"
7#include "util/header.h"
8#include "util/session.h"
9
10static void ui_browser__argv_write(struct ui_browser *browser,
11 void *entry, int row)
12{
13 char **arg = entry;
14 char *str = *arg;
15 char empty[] = " ";
16 bool current_entry = ui_browser__is_current_entry(browser, row);
17 unsigned long offset = (unsigned long)browser->priv;
18
19 if (offset >= strlen(str))
20 str = empty;
21 else
22 str = str + offset;
23
24 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
25 HE_COLORSET_NORMAL);
26
27 slsmg_write_nstring(str, browser->width);
28}
29
30static int list_menu__run(struct ui_browser *menu)
31{
32 int key;
33 unsigned long offset;
34 const char help[] =
35 "h/?/F1 Show this window\n"
36 "UP/DOWN/PGUP\n"
37 "PGDN/SPACE\n"
38 "LEFT/RIGHT Navigate\n"
39 "q/ESC/CTRL+C Exit browser";
40
41 if (ui_browser__show(menu, "Header information", "Press 'q' to exit") < 0)
42 return -1;
43
44 while (1) {
45 key = ui_browser__run(menu, 0);
46
47 switch (key) {
48 case K_RIGHT:
49 offset = (unsigned long)menu->priv;
50 offset += 10;
51 menu->priv = (void *)offset;
52 continue;
53 case K_LEFT:
54 offset = (unsigned long)menu->priv;
55 if (offset >= 10)
56 offset -= 10;
57 menu->priv = (void *)offset;
58 continue;
59 case K_F1:
60 case 'h':
61 case '?':
62 ui_browser__help_window(menu, help);
63 continue;
64 case K_ESC:
65 case 'q':
66 case CTRL('c'):
67 key = -1;
68 break;
69 default:
70 continue;
71 }
72
73 break;
74 }
75
76 ui_browser__hide(menu);
77 return key;
78}
79
80static int ui__list_menu(int argc, char * const argv[])
81{
82 struct ui_browser menu = {
83 .entries = (void *)argv,
84 .refresh = ui_browser__argv_refresh,
85 .seek = ui_browser__argv_seek,
86 .write = ui_browser__argv_write,
87 .nr_entries = argc,
88 };
89
90 return list_menu__run(&menu);
91}
92
93int tui__header_window(struct perf_session_env *env)
94{
95 int i, argc = 0;
96 char **argv;
97 struct perf_session *session;
98 char *ptr, *pos;
99 size_t size;
100 FILE *fp = open_memstream(&ptr, &size);
101
102 session = container_of(env, struct perf_session, header.env);
103 perf_header__fprintf_info(session, fp, true);
104 fclose(fp);
105
106 for (pos = ptr, argc = 0; (pos = strchr(pos, '\n')) != NULL; pos++)
107 argc++;
108
109 argv = calloc(argc + 1, sizeof(*argv));
110 if (argv == NULL)
111 goto out;
112
113 argv[0] = pos = ptr;
114 for (i = 1; (pos = strchr(pos, '\n')) != NULL; i++) {
115 *pos++ = '\0';
116 argv[i] = pos;
117 }
118
119 BUG_ON(i != argc + 1);
120
121 ui__list_menu(argc, argv);
122
123out:
124 free(argv);
125 free(ptr);
126 return 0;
127}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a440e03cd8c2..b720b92eba6e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1267,10 +1267,8 @@ static inline void free_popup_options(char **options, int n)
1267{ 1267{
1268 int i; 1268 int i;
1269 1269
1270 for (i = 0; i < n; ++i) { 1270 for (i = 0; i < n; ++i)
1271 free(options[i]); 1271 zfree(&options[i]);
1272 options[i] = NULL;
1273 }
1274} 1272}
1275 1273
1276/* Check whether the browser is for 'top' or 'report' */ 1274/* Check whether the browser is for 'top' or 'report' */
@@ -1329,7 +1327,7 @@ static int switch_data_file(void)
1329 1327
1330 abs_path[nr_options] = strdup(path); 1328 abs_path[nr_options] = strdup(path);
1331 if (!abs_path[nr_options]) { 1329 if (!abs_path[nr_options]) {
1332 free(options[nr_options]); 1330 zfree(&options[nr_options]);
1333 ui__warning("Can't search all data files due to memory shortage.\n"); 1331 ui__warning("Can't search all data files due to memory shortage.\n");
1334 fclose(file); 1332 fclose(file);
1335 break; 1333 break;
@@ -1400,6 +1398,36 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1400 char script_opt[64]; 1398 char script_opt[64];
1401 int delay_secs = hbt ? hbt->refresh : 0; 1399 int delay_secs = hbt ? hbt->refresh : 0;
1402 1400
1401#define HIST_BROWSER_HELP_COMMON \
1402 "h/?/F1 Show this window\n" \
1403 "UP/DOWN/PGUP\n" \
1404 "PGDN/SPACE Navigate\n" \
1405 "q/ESC/CTRL+C Exit browser\n\n" \
1406 "For multiple event sessions:\n\n" \
1407 "TAB/UNTAB Switch events\n\n" \
1408 "For symbolic views (--sort has sym):\n\n" \
1409 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1410 "<- Zoom out\n" \
1411 "a Annotate current symbol\n" \
1412 "C Collapse all callchains\n" \
1413 "d Zoom into current DSO\n" \
1414 "E Expand all callchains\n" \
1415
1416 /* help messages are sorted by lexical order of the hotkey */
1417 const char report_help[] = HIST_BROWSER_HELP_COMMON
1418 "i Show header information\n"
1419 "P Print histograms to perf.hist.N\n"
1420 "r Run available scripts\n"
1421 "s Switch to another data file in PWD\n"
1422 "t Zoom into current Thread\n"
1423 "V Verbose (DSO names in callchains, etc)\n"
1424 "/ Filter symbol by name";
1425 const char top_help[] = HIST_BROWSER_HELP_COMMON
1426 "P Print histograms to perf.hist.N\n"
1427 "t Zoom into current Thread\n"
1428 "V Verbose (DSO names in callchains, etc)\n"
1429 "/ Filter symbol by name";
1430
1403 if (browser == NULL) 1431 if (browser == NULL)
1404 return -1; 1432 return -1;
1405 1433
@@ -1484,29 +1512,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1484 if (is_report_browser(hbt)) 1512 if (is_report_browser(hbt))
1485 goto do_data_switch; 1513 goto do_data_switch;
1486 continue; 1514 continue;
1515 case 'i':
1516 /* env->arch is NULL for live-mode (i.e. perf top) */
1517 if (env->arch)
1518 tui__header_window(env);
1519 continue;
1487 case K_F1: 1520 case K_F1:
1488 case 'h': 1521 case 'h':
1489 case '?': 1522 case '?':
1490 ui_browser__help_window(&browser->b, 1523 ui_browser__help_window(&browser->b,
1491 "h/?/F1 Show this window\n" 1524 is_report_browser(hbt) ? report_help : top_help);
1492 "UP/DOWN/PGUP\n"
1493 "PGDN/SPACE Navigate\n"
1494 "q/ESC/CTRL+C Exit browser\n\n"
1495 "For multiple event sessions:\n\n"
1496 "TAB/UNTAB Switch events\n\n"
1497 "For symbolic views (--sort has sym):\n\n"
1498 "-> Zoom into DSO/Threads & Annotate current symbol\n"
1499 "<- Zoom out\n"
1500 "a Annotate current symbol\n"
1501 "C Collapse all callchains\n"
1502 "E Expand all callchains\n"
1503 "d Zoom into current DSO\n"
1504 "t Zoom into current Thread\n"
1505 "r Run available scripts('perf report' only)\n"
1506 "s Switch to another data file in PWD ('perf report' only)\n"
1507 "P Print histograms to perf.hist.N\n"
1508 "V Verbose (DSO names in callchains, etc)\n"
1509 "/ Filter symbol by name");
1510 continue; 1525 continue;
1511 case K_ENTER: 1526 case K_ENTER:
1512 case K_RIGHT: 1527 case K_RIGHT:
@@ -1923,7 +1938,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1923 1938
1924 ui_helpline__push("Press ESC to exit"); 1939 ui_helpline__push("Press ESC to exit");
1925 1940
1926 list_for_each_entry(pos, &evlist->entries, node) { 1941 evlist__for_each(evlist, pos) {
1927 const char *ev_name = perf_evsel__name(pos); 1942 const char *ev_name = perf_evsel__name(pos);
1928 size_t line_len = strlen(ev_name) + 7; 1943 size_t line_len = strlen(ev_name) + 7;
1929 1944
@@ -1955,9 +1970,10 @@ single_entry:
1955 struct perf_evsel *pos; 1970 struct perf_evsel *pos;
1956 1971
1957 nr_entries = 0; 1972 nr_entries = 0;
1958 list_for_each_entry(pos, &evlist->entries, node) 1973 evlist__for_each(evlist, pos) {
1959 if (perf_evsel__is_group_leader(pos)) 1974 if (perf_evsel__is_group_leader(pos))
1960 nr_entries++; 1975 nr_entries++;
1976 }
1961 1977
1962 if (nr_entries == 1) 1978 if (nr_entries == 1)
1963 goto single_entry; 1979 goto single_entry;
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index d63c68ea02a8..402d2bd30b09 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -173,8 +173,7 @@ int script_browse(const char *script_opt)
173 if (script.b.width > AVERAGE_LINE_LEN) 173 if (script.b.width > AVERAGE_LINE_LEN)
174 script.b.width = AVERAGE_LINE_LEN; 174 script.b.width = AVERAGE_LINE_LEN;
175 175
176 if (line) 176 free(line);
177 free(line);
178 pclose(fp); 177 pclose(fp);
179 178
180 script.nr_lines = nr_entries; 179 script.nr_lines = nr_entries;
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 2ca66cc1160f..5b95c44f3435 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -375,7 +375,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
375 375
376 gtk_container_add(GTK_CONTAINER(window), vbox); 376 gtk_container_add(GTK_CONTAINER(window), vbox);
377 377
378 list_for_each_entry(pos, &evlist->entries, node) { 378 evlist__for_each(evlist, pos) {
379 struct hists *hists = &pos->hists; 379 struct hists *hists = &pos->hists;
380 const char *evname = perf_evsel__name(pos); 380 const char *evname = perf_evsel__name(pos);
381 GtkWidget *scrolled_window; 381 GtkWidget *scrolled_window;
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index 696c1fbe4248..52e7fc48af9f 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -23,8 +23,7 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
23 if (!perf_gtk__is_active_context(*ctx)) 23 if (!perf_gtk__is_active_context(*ctx))
24 return -1; 24 return -1;
25 25
26 free(*ctx); 26 zfree(ctx);
27 *ctx = NULL;
28 return 0; 27 return 0;
29} 28}
30 29
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index c244cb524ef2..831fbb77d1ff 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -510,7 +510,7 @@ print_entries:
510 510
511 free(line); 511 free(line);
512out: 512out:
513 free(rem_sq_bracket); 513 zfree(&rem_sq_bracket);
514 514
515 return ret; 515 return ret;
516} 516}
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
index 092902e30cee..bf890f72fe80 100644
--- a/tools/perf/ui/tui/util.c
+++ b/tools/perf/ui/tui/util.c
@@ -92,6 +92,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
92 t = sep + 1; 92 t = sep + 1;
93 } 93 }
94 94
95 pthread_mutex_lock(&ui__lock);
96
95 max_len += 2; 97 max_len += 2;
96 nr_lines += 8; 98 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2; 99 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
@@ -120,13 +122,19 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
120 SLsmg_write_nstring((char *)exit_msg, max_len); 122 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh(); 123 SLsmg_refresh();
122 124
125 pthread_mutex_unlock(&ui__lock);
126
123 x += 2; 127 x += 2;
124 len = 0; 128 len = 0;
125 key = ui__getch(delay_secs); 129 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 130 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
131 pthread_mutex_lock(&ui__lock);
132
127 if (key == K_BKSPC) { 133 if (key == K_BKSPC) {
128 if (len == 0) 134 if (len == 0) {
135 pthread_mutex_unlock(&ui__lock);
129 goto next_key; 136 goto next_key;
137 }
130 SLsmg_gotorc(y, x + --len); 138 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' '); 139 SLsmg_write_char(' ');
132 } else { 140 } else {
@@ -136,6 +144,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
136 } 144 }
137 SLsmg_refresh(); 145 SLsmg_refresh();
138 146
147 pthread_mutex_unlock(&ui__lock);
148
139 /* XXX more graceful overflow handling needed */ 149 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) { 150 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!"); 151 ui_helpline__push("maximum size of symbol name reached!");
@@ -174,6 +184,8 @@ int ui__question_window(const char *title, const char *text,
174 t = sep + 1; 184 t = sep + 1;
175 } 185 }
176 186
187 pthread_mutex_lock(&ui__lock);
188
177 max_len += 2; 189 max_len += 2;
178 nr_lines += 4; 190 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2, 191 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
@@ -195,6 +207,9 @@ int ui__question_window(const char *title, const char *text,
195 SLsmg_gotorc(y + nr_lines - 1, x); 207 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len); 208 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh(); 209 SLsmg_refresh();
210
211 pthread_mutex_unlock(&ui__lock);
212
198 return ui__getch(delay_secs); 213 return ui__getch(delay_secs);
199} 214}
200 215
@@ -215,9 +230,7 @@ static int __ui__warning(const char *title, const char *format, va_list args)
215 if (vasprintf(&s, format, args) > 0) { 230 if (vasprintf(&s, format, args) > 0) {
216 int key; 231 int key;
217 232
218 pthread_mutex_lock(&ui__lock);
219 key = ui__question_window(title, s, "Press any key...", 0); 233 key = ui__question_window(title, s, "Press any key...", 0);
220 pthread_mutex_unlock(&ui__lock);
221 free(s); 234 free(s);
222 return key; 235 return key;
223 } 236 }
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index e6d134773d0a..c0b43ee40d95 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -55,8 +55,7 @@ int split_cmdline(char *cmdline, const char ***argv)
55 src++; 55 src++;
56 c = cmdline[src]; 56 c = cmdline[src];
57 if (!c) { 57 if (!c) {
58 free(*argv); 58 zfree(argv);
59 *argv = NULL;
60 return error("cmdline ends with \\"); 59 return error("cmdline ends with \\");
61 } 60 }
62 } 61 }
@@ -68,8 +67,7 @@ int split_cmdline(char *cmdline, const char ***argv)
68 cmdline[dst] = 0; 67 cmdline[dst] = 0;
69 68
70 if (quoted) { 69 if (quoted) {
71 free(*argv); 70 zfree(argv);
72 *argv = NULL;
73 return error("unclosed quote"); 71 return error("unclosed quote");
74 } 72 }
75 73
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index cf6242c92ee2..469eb679fb9d 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -26,10 +26,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
26 26
27static void ins__delete(struct ins_operands *ops) 27static void ins__delete(struct ins_operands *ops)
28{ 28{
29 free(ops->source.raw); 29 zfree(&ops->source.raw);
30 free(ops->source.name); 30 zfree(&ops->source.name);
31 free(ops->target.raw); 31 zfree(&ops->target.raw);
32 free(ops->target.name); 32 zfree(&ops->target.name);
33} 33}
34 34
35static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 35static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
@@ -185,8 +185,7 @@ static int lock__parse(struct ins_operands *ops)
185 return 0; 185 return 0;
186 186
187out_free_ops: 187out_free_ops:
188 free(ops->locked.ops); 188 zfree(&ops->locked.ops);
189 ops->locked.ops = NULL;
190 return 0; 189 return 0;
191} 190}
192 191
@@ -205,9 +204,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
205 204
206static void lock__delete(struct ins_operands *ops) 205static void lock__delete(struct ins_operands *ops)
207{ 206{
208 free(ops->locked.ops); 207 zfree(&ops->locked.ops);
209 free(ops->target.raw); 208 zfree(&ops->target.raw);
210 free(ops->target.name); 209 zfree(&ops->target.name);
211} 210}
212 211
213static struct ins_ops lock_ops = { 212static struct ins_ops lock_ops = {
@@ -256,8 +255,7 @@ static int mov__parse(struct ins_operands *ops)
256 return 0; 255 return 0;
257 256
258out_free_source: 257out_free_source:
259 free(ops->source.raw); 258 zfree(&ops->source.raw);
260 ops->source.raw = NULL;
261 return -1; 259 return -1;
262} 260}
263 261
@@ -464,17 +462,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym)
464 pthread_mutex_unlock(&notes->lock); 462 pthread_mutex_unlock(&notes->lock);
465} 463}
466 464
467int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 465static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
468 int evidx, u64 addr) 466 struct annotation *notes, int evidx, u64 addr)
469{ 467{
470 unsigned offset; 468 unsigned offset;
471 struct annotation *notes;
472 struct sym_hist *h; 469 struct sym_hist *h;
473 470
474 notes = symbol__annotation(sym);
475 if (notes->src == NULL)
476 return -ENOMEM;
477
478 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 471 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
479 472
480 if (addr < sym->start || addr > sym->end) 473 if (addr < sym->start || addr > sym->end)
@@ -491,6 +484,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
491 return 0; 484 return 0;
492} 485}
493 486
487static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
488 int evidx, u64 addr)
489{
490 struct annotation *notes;
491
492 if (sym == NULL || use_browser != 1 || !sort__has_sym)
493 return 0;
494
495 notes = symbol__annotation(sym);
496 if (notes->src == NULL) {
497 if (symbol__alloc_hist(sym) < 0)
498 return -ENOMEM;
499 }
500
501 return __symbol__inc_addr_samples(sym, map, notes, evidx, addr);
502}
503
504int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx)
505{
506 return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr);
507}
508
509int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
510{
511 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
512}
513
494static void disasm_line__init_ins(struct disasm_line *dl) 514static void disasm_line__init_ins(struct disasm_line *dl)
495{ 515{
496 dl->ins = ins__find(dl->name); 516 dl->ins = ins__find(dl->name);
@@ -538,8 +558,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp)
538 return 0; 558 return 0;
539 559
540out_free_name: 560out_free_name:
541 free(*namep); 561 zfree(namep);
542 *namep = NULL;
543 return -1; 562 return -1;
544} 563}
545 564
@@ -564,7 +583,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs
564 return dl; 583 return dl;
565 584
566out_free_line: 585out_free_line:
567 free(dl->line); 586 zfree(&dl->line);
568out_delete: 587out_delete:
569 free(dl); 588 free(dl);
570 return NULL; 589 return NULL;
@@ -572,8 +591,8 @@ out_delete:
572 591
573void disasm_line__free(struct disasm_line *dl) 592void disasm_line__free(struct disasm_line *dl)
574{ 593{
575 free(dl->line); 594 zfree(&dl->line);
576 free(dl->name); 595 zfree(&dl->name);
577 if (dl->ins && dl->ins->ops->free) 596 if (dl->ins && dl->ins->ops->free)
578 dl->ins->ops->free(&dl->ops); 597 dl->ins->ops->free(&dl->ops);
579 else 598 else
@@ -900,7 +919,7 @@ fallback:
900 * cache, or is just a kallsyms file, well, lets hope that this 919 * cache, or is just a kallsyms file, well, lets hope that this
901 * DSO is the same as when 'perf record' ran. 920 * DSO is the same as when 'perf record' ran.
902 */ 921 */
903 filename = dso->long_name; 922 filename = (char *)dso->long_name;
904 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 923 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
905 symbol_conf.symfs, filename); 924 symbol_conf.symfs, filename);
906 free_filename = false; 925 free_filename = false;
@@ -1091,8 +1110,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1091 src_line = (void *)src_line + sizeof_src_line; 1110 src_line = (void *)src_line + sizeof_src_line;
1092 } 1111 }
1093 1112
1094 free(notes->src->lines); 1113 zfree(&notes->src->lines);
1095 notes->src->lines = NULL;
1096} 1114}
1097 1115
1098/* Get the filename:line for the colored entries */ 1116/* Get the filename:line for the colored entries */
@@ -1376,3 +1394,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1376 1394
1377 return 0; 1395 return 0;
1378} 1396}
1397
1398int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1399{
1400 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1401}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 834b7b57b788..b2aef59d6bb2 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -132,12 +132,17 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
132 return &a->annotation; 132 return &a->annotation;
133} 133}
134 134
135int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 135int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx);
136 int evidx, u64 addr); 136
137int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
138
137int symbol__alloc_hist(struct symbol *sym); 139int symbol__alloc_hist(struct symbol *sym);
138void symbol__annotate_zero_histograms(struct symbol *sym); 140void symbol__annotate_zero_histograms(struct symbol *sym);
139 141
140int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 142int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
143
144int hist_entry__annotate(struct hist_entry *he, size_t privsize);
145
141int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 146int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
142int symbol__annotate_printf(struct symbol *sym, struct map *map, 147int symbol__annotate_printf(struct symbol *sym, struct map *map,
143 struct perf_evsel *evsel, bool full_paths, 148 struct perf_evsel *evsel, bool full_paths,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a92770c98cc7..6baabe63182b 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
89 return raw - build_id; 89 return raw - build_id;
90} 90}
91 91
92char *dso__build_id_filename(struct dso *dso, char *bf, size_t size) 92char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
93{ 93{
94 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 94 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
95 95
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 929f28a7c14d..845ef865eced 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
11 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf); 12int build_id__sprintf(const u8 *build_id, int len, char *bf);
13char *dso__build_id_filename(struct dso *dso, char *bf, size_t size); 13char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
14 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel, 16 struct perf_sample *sample, struct perf_evsel *evsel,
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 4f7f989876ec..08b25af9eea1 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -146,7 +146,7 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
146 146
147struct option; 147struct option;
148 148
149int record_parse_callchain(const char *arg, struct perf_record_opts *opts); 149int record_parse_callchain(const char *arg, struct record_opts *opts);
150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
151int record_callchain_opt(const struct option *opt, const char *arg, int unset); 151int record_callchain_opt(const struct option *opt, const char *arg, int unset);
152 152
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 96bbda1ddb83..88f7be399432 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
81 /* 81 /*
82 * check if cgrp is already defined, if so we reuse it 82 * check if cgrp is already defined, if so we reuse it
83 */ 83 */
84 list_for_each_entry(counter, &evlist->entries, node) { 84 evlist__for_each(evlist, counter) {
85 cgrp = counter->cgrp; 85 cgrp = counter->cgrp;
86 if (!cgrp) 86 if (!cgrp)
87 continue; 87 continue;
@@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
110 * if add cgroup N, then need to find event N 110 * if add cgroup N, then need to find event N
111 */ 111 */
112 n = 0; 112 n = 0;
113 list_for_each_entry(counter, &evlist->entries, node) { 113 evlist__for_each(evlist, counter) {
114 if (n == nr_cgroups) 114 if (n == nr_cgroups)
115 goto found; 115 goto found;
116 n++; 116 n++;
@@ -133,7 +133,7 @@ void close_cgroup(struct cgroup_sel *cgrp)
133 /* XXX: not reentrant */ 133 /* XXX: not reentrant */
134 if (--cgrp->refcnt == 0) { 134 if (--cgrp->refcnt == 0) {
135 close(cgrp->fd); 135 close(cgrp->fd);
136 free(cgrp->name); 136 zfree(&cgrp->name);
137 free(cgrp); 137 free(cgrp);
138 } 138 }
139} 139}
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 66e44a5019d5..87b8672eb413 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,6 +1,7 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include "cache.h" 2#include "cache.h"
3#include "color.h" 3#include "color.h"
4#include <math.h>
4 5
5int perf_use_color_default = -1; 6int perf_use_color_default = -1;
6 7
@@ -298,10 +299,10 @@ const char *get_percent_color(double percent)
298 * entries in green - and keep the low overhead places 299 * entries in green - and keep the low overhead places
299 * normal: 300 * normal:
300 */ 301 */
301 if (percent >= MIN_RED) 302 if (fabs(percent) >= MIN_RED)
302 color = PERF_COLOR_RED; 303 color = PERF_COLOR_RED;
303 else { 304 else {
304 if (percent > MIN_GREEN) 305 if (fabs(percent) > MIN_GREEN)
305 color = PERF_COLOR_GREEN; 306 color = PERF_COLOR_GREEN;
306 } 307 }
307 return color; 308 return color;
@@ -318,15 +319,19 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
318 return r; 319 return r;
319} 320}
320 321
322int value_color_snprintf(char *bf, size_t size, const char *fmt, double value)
323{
324 const char *color = get_percent_color(value);
325 return color_snprintf(bf, size, color, fmt, value);
326}
327
321int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) 328int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
322{ 329{
323 va_list args; 330 va_list args;
324 double percent; 331 double percent;
325 const char *color;
326 332
327 va_start(args, fmt); 333 va_start(args, fmt);
328 percent = va_arg(args, double); 334 percent = va_arg(args, double);
329 va_end(args); 335 va_end(args);
330 color = get_percent_color(percent); 336 return value_color_snprintf(bf, size, fmt, percent);
331 return color_snprintf(bf, size, color, fmt, percent);
332} 337}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index fced3840e99c..7ff30a62a132 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -39,6 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); 39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); 43int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
43int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 44int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
44const char *get_percent_color(double percent); 45const char *get_percent_color(double percent);
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index ee0df0e24cdb..67d1e404c0cb 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -21,7 +21,7 @@ static void comm_str__put(struct comm_str *cs)
21{ 21{
22 if (!--cs->ref) { 22 if (!--cs->ref) {
23 rb_erase(&cs->rb_node, &comm_str_root); 23 rb_erase(&cs->rb_node, &comm_str_root);
24 free(cs->str); 24 zfree(&cs->str);
25 free(cs); 25 free(cs);
26 } 26 }
27} 27}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 7d09faf85cf1..1fbcd8bdc11b 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -118,3 +118,9 @@ void perf_data_file__close(struct perf_data_file *file)
118{ 118{
119 close(file->fd); 119 close(file->fd);
120} 120}
121
122ssize_t perf_data_file__write(struct perf_data_file *file,
123 void *buf, size_t size)
124{
125 return writen(file->fd, buf, size);
126}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 8c2df80152a5..2b15d0c95c7f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -9,12 +9,12 @@ enum perf_data_mode {
9}; 9};
10 10
11struct perf_data_file { 11struct perf_data_file {
12 const char *path; 12 const char *path;
13 int fd; 13 int fd;
14 bool is_pipe; 14 bool is_pipe;
15 bool force; 15 bool force;
16 unsigned long size; 16 unsigned long size;
17 enum perf_data_mode mode; 17 enum perf_data_mode mode;
18}; 18};
19 19
20static inline bool perf_data_file__is_read(struct perf_data_file *file) 20static inline bool perf_data_file__is_read(struct perf_data_file *file)
@@ -44,5 +44,7 @@ static inline unsigned long perf_data_file__size(struct perf_data_file *file)
44 44
45int perf_data_file__open(struct perf_data_file *file); 45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file); 46void perf_data_file__close(struct perf_data_file *file);
47ssize_t perf_data_file__write(struct perf_data_file *file,
48 void *buf, size_t size);
47 49
48#endif /* __PERF_DATA_H */ 50#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 399e74c34c1a..299b55586502 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -16,23 +16,46 @@
16int verbose; 16int verbose;
17bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
18 18
19int eprintf(int level, const char *fmt, ...) 19static int _eprintf(int level, const char *fmt, va_list args)
20{ 20{
21 va_list args;
22 int ret = 0; 21 int ret = 0;
23 22
24 if (verbose >= level) { 23 if (verbose >= level) {
25 va_start(args, fmt);
26 if (use_browser >= 1) 24 if (use_browser >= 1)
27 ui_helpline__vshow(fmt, args); 25 ui_helpline__vshow(fmt, args);
28 else 26 else
29 ret = vfprintf(stderr, fmt, args); 27 ret = vfprintf(stderr, fmt, args);
30 va_end(args);
31 } 28 }
32 29
33 return ret; 30 return ret;
34} 31}
35 32
33int eprintf(int level, const char *fmt, ...)
34{
35 va_list args;
36 int ret;
37
38 va_start(args, fmt);
39 ret = _eprintf(level, fmt, args);
40 va_end(args);
41
42 return ret;
43}
44
45/*
46 * Overloading libtraceevent standard info print
47 * function, display with -v in perf.
48 */
49void pr_stat(const char *fmt, ...)
50{
51 va_list args;
52
53 va_start(args, fmt);
54 _eprintf(1, fmt, args);
55 va_end(args);
56 eprintf(1, "\n");
57}
58
36int dump_printf(const char *fmt, ...) 59int dump_printf(const char *fmt, ...)
37{ 60{
38 va_list args; 61 va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index efbd98805ad0..443694c36b03 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event);
17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19 19
20void pr_stat(const char *fmt, ...);
21
20#endif /* __PERF_DEBUG_H */ 22#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index af4c687cc49b..4045d086d9d9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -28,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso)
28 return origin[dso->symtab_type]; 28 return origin[dso->symtab_type];
29} 29}
30 30
31int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 31int dso__read_binary_type_filename(const struct dso *dso,
32 char *root_dir, char *file, size_t size) 32 enum dso_binary_type type,
33 char *root_dir, char *filename, size_t size)
33{ 34{
34 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 35 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
35 int ret = 0; 36 int ret = 0;
@@ -38,36 +39,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
38 case DSO_BINARY_TYPE__DEBUGLINK: { 39 case DSO_BINARY_TYPE__DEBUGLINK: {
39 char *debuglink; 40 char *debuglink;
40 41
41 strncpy(file, dso->long_name, size); 42 strncpy(filename, dso->long_name, size);
42 debuglink = file + dso->long_name_len; 43 debuglink = filename + dso->long_name_len;
43 while (debuglink != file && *debuglink != '/') 44 while (debuglink != filename && *debuglink != '/')
44 debuglink--; 45 debuglink--;
45 if (*debuglink == '/') 46 if (*debuglink == '/')
46 debuglink++; 47 debuglink++;
47 filename__read_debuglink(dso->long_name, debuglink, 48 filename__read_debuglink(dso->long_name, debuglink,
48 size - (debuglink - file)); 49 size - (debuglink - filename));
49 } 50 }
50 break; 51 break;
51 case DSO_BINARY_TYPE__BUILD_ID_CACHE: 52 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
52 /* skip the locally configured cache if a symfs is given */ 53 /* skip the locally configured cache if a symfs is given */
53 if (symbol_conf.symfs[0] || 54 if (symbol_conf.symfs[0] ||
54 (dso__build_id_filename(dso, file, size) == NULL)) 55 (dso__build_id_filename(dso, filename, size) == NULL))
55 ret = -1; 56 ret = -1;
56 break; 57 break;
57 58
58 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 59 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
59 snprintf(file, size, "%s/usr/lib/debug%s.debug", 60 snprintf(filename, size, "%s/usr/lib/debug%s.debug",
60 symbol_conf.symfs, dso->long_name); 61 symbol_conf.symfs, dso->long_name);
61 break; 62 break;
62 63
63 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 64 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
64 snprintf(file, size, "%s/usr/lib/debug%s", 65 snprintf(filename, size, "%s/usr/lib/debug%s",
65 symbol_conf.symfs, dso->long_name); 66 symbol_conf.symfs, dso->long_name);
66 break; 67 break;
67 68
68 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 69 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
69 { 70 {
70 char *last_slash; 71 const char *last_slash;
71 size_t len; 72 size_t len;
72 size_t dir_size; 73 size_t dir_size;
73 74
@@ -75,14 +76,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
75 while (last_slash != dso->long_name && *last_slash != '/') 76 while (last_slash != dso->long_name && *last_slash != '/')
76 last_slash--; 77 last_slash--;
77 78
78 len = scnprintf(file, size, "%s", symbol_conf.symfs); 79 len = scnprintf(filename, size, "%s", symbol_conf.symfs);
79 dir_size = last_slash - dso->long_name + 2; 80 dir_size = last_slash - dso->long_name + 2;
80 if (dir_size > (size - len)) { 81 if (dir_size > (size - len)) {
81 ret = -1; 82 ret = -1;
82 break; 83 break;
83 } 84 }
84 len += scnprintf(file + len, dir_size, "%s", dso->long_name); 85 len += scnprintf(filename + len, dir_size, "%s", dso->long_name);
85 len += scnprintf(file + len , size - len, ".debug%s", 86 len += scnprintf(filename + len , size - len, ".debug%s",
86 last_slash); 87 last_slash);
87 break; 88 break;
88 } 89 }
@@ -96,7 +97,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
96 build_id__sprintf(dso->build_id, 97 build_id__sprintf(dso->build_id,
97 sizeof(dso->build_id), 98 sizeof(dso->build_id),
98 build_id_hex); 99 build_id_hex);
99 snprintf(file, size, 100 snprintf(filename, size,
100 "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 101 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
101 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 102 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
102 break; 103 break;
@@ -104,23 +105,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
104 case DSO_BINARY_TYPE__VMLINUX: 105 case DSO_BINARY_TYPE__VMLINUX:
105 case DSO_BINARY_TYPE__GUEST_VMLINUX: 106 case DSO_BINARY_TYPE__GUEST_VMLINUX:
106 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 107 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
107 snprintf(file, size, "%s%s", 108 snprintf(filename, size, "%s%s",
108 symbol_conf.symfs, dso->long_name); 109 symbol_conf.symfs, dso->long_name);
109 break; 110 break;
110 111
111 case DSO_BINARY_TYPE__GUEST_KMODULE: 112 case DSO_BINARY_TYPE__GUEST_KMODULE:
112 snprintf(file, size, "%s%s%s", symbol_conf.symfs, 113 snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
113 root_dir, dso->long_name); 114 root_dir, dso->long_name);
114 break; 115 break;
115 116
116 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 117 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
117 snprintf(file, size, "%s%s", symbol_conf.symfs, 118 snprintf(filename, size, "%s%s", symbol_conf.symfs,
118 dso->long_name); 119 dso->long_name);
119 break; 120 break;
120 121
121 case DSO_BINARY_TYPE__KCORE: 122 case DSO_BINARY_TYPE__KCORE:
122 case DSO_BINARY_TYPE__GUEST_KCORE: 123 case DSO_BINARY_TYPE__GUEST_KCORE:
123 snprintf(file, size, "%s", dso->long_name); 124 snprintf(filename, size, "%s", dso->long_name);
124 break; 125 break;
125 126
126 default: 127 default:
@@ -137,19 +138,18 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
137 138
138static int open_dso(struct dso *dso, struct machine *machine) 139static int open_dso(struct dso *dso, struct machine *machine)
139{ 140{
140 char *root_dir = (char *) "";
141 char *name;
142 int fd; 141 int fd;
142 char *root_dir = (char *)"";
143 char *name = malloc(PATH_MAX);
143 144
144 name = malloc(PATH_MAX);
145 if (!name) 145 if (!name)
146 return -ENOMEM; 146 return -ENOMEM;
147 147
148 if (machine) 148 if (machine)
149 root_dir = machine->root_dir; 149 root_dir = machine->root_dir;
150 150
151 if (dso__binary_type_file(dso, dso->data_type, 151 if (dso__read_binary_type_filename(dso, dso->binary_type,
152 root_dir, name, PATH_MAX)) { 152 root_dir, name, PATH_MAX)) {
153 free(name); 153 free(name);
154 return -EINVAL; 154 return -EINVAL;
155 } 155 }
@@ -161,26 +161,26 @@ static int open_dso(struct dso *dso, struct machine *machine)
161 161
162int dso__data_fd(struct dso *dso, struct machine *machine) 162int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 163{
164 static enum dso_binary_type binary_type_data[] = { 164 enum dso_binary_type binary_type_data[] = {
165 DSO_BINARY_TYPE__BUILD_ID_CACHE, 165 DSO_BINARY_TYPE__BUILD_ID_CACHE,
166 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 166 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
167 DSO_BINARY_TYPE__NOT_FOUND, 167 DSO_BINARY_TYPE__NOT_FOUND,
168 }; 168 };
169 int i = 0; 169 int i = 0;
170 170
171 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) 171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND)
172 return open_dso(dso, machine); 172 return open_dso(dso, machine);
173 173
174 do { 174 do {
175 int fd; 175 int fd;
176 176
177 dso->data_type = binary_type_data[i++]; 177 dso->binary_type = binary_type_data[i++];
178 178
179 fd = open_dso(dso, machine); 179 fd = open_dso(dso, machine);
180 if (fd >= 0) 180 if (fd >= 0)
181 return fd; 181 return fd;
182 182
183 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); 183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 184
185 return -EINVAL; 185 return -EINVAL;
186} 186}
@@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root)
200 } 200 }
201} 201}
202 202
203static struct dso_cache* 203static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset)
204dso_cache__find(struct rb_root *root, u64 offset)
205{ 204{
206 struct rb_node **p = &root->rb_node; 205 struct rb_node * const *p = &root->rb_node;
207 struct rb_node *parent = NULL; 206 const struct rb_node *parent = NULL;
208 struct dso_cache *cache; 207 struct dso_cache *cache;
209 208
210 while (*p != NULL) { 209 while (*p != NULL) {
@@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
379 * processing we had no idea this was the kernel dso. 378 * processing we had no idea this was the kernel dso.
380 */ 379 */
381 if (dso != NULL) { 380 if (dso != NULL) {
382 dso__set_short_name(dso, short_name); 381 dso__set_short_name(dso, short_name, false);
383 dso->kernel = dso_type; 382 dso->kernel = dso_type;
384 } 383 }
385 384
386 return dso; 385 return dso;
387} 386}
388 387
389void dso__set_long_name(struct dso *dso, char *name) 388void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
390{ 389{
391 if (name == NULL) 390 if (name == NULL)
392 return; 391 return;
393 dso->long_name = name; 392
394 dso->long_name_len = strlen(name); 393 if (dso->long_name_allocated)
394 free((char *)dso->long_name);
395
396 dso->long_name = name;
397 dso->long_name_len = strlen(name);
398 dso->long_name_allocated = name_allocated;
395} 399}
396 400
397void dso__set_short_name(struct dso *dso, const char *name) 401void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
398{ 402{
399 if (name == NULL) 403 if (name == NULL)
400 return; 404 return;
401 dso->short_name = name; 405
402 dso->short_name_len = strlen(name); 406 if (dso->short_name_allocated)
407 free((char *)dso->short_name);
408
409 dso->short_name = name;
410 dso->short_name_len = strlen(name);
411 dso->short_name_allocated = name_allocated;
403} 412}
404 413
405static void dso__set_basename(struct dso *dso) 414static void dso__set_basename(struct dso *dso)
406{ 415{
407 dso__set_short_name(dso, basename(dso->long_name)); 416 /*
417 * basename() may modify path buffer, so we must pass
418 * a copy.
419 */
420 char *base, *lname = strdup(dso->long_name);
421
422 if (!lname)
423 return;
424
425 /*
426 * basename() may return a pointer to internal
427 * storage which is reused in subsequent calls
428 * so copy the result.
429 */
430 base = strdup(basename(lname));
431
432 free(lname);
433
434 if (!base)
435 return;
436
437 dso__set_short_name(dso, base, true);
408} 438}
409 439
410int dso__name_len(const struct dso *dso) 440int dso__name_len(const struct dso *dso)
@@ -439,18 +469,19 @@ struct dso *dso__new(const char *name)
439 if (dso != NULL) { 469 if (dso != NULL) {
440 int i; 470 int i;
441 strcpy(dso->name, name); 471 strcpy(dso->name, name);
442 dso__set_long_name(dso, dso->name); 472 dso__set_long_name(dso, dso->name, false);
443 dso__set_short_name(dso, dso->name); 473 dso__set_short_name(dso, dso->name, false);
444 for (i = 0; i < MAP__NR_TYPES; ++i) 474 for (i = 0; i < MAP__NR_TYPES; ++i)
445 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
446 dso->cache = RB_ROOT; 476 dso->cache = RB_ROOT;
447 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
448 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
449 dso->loaded = 0; 479 dso->loaded = 0;
450 dso->rel = 0; 480 dso->rel = 0;
451 dso->sorted_by_name = 0; 481 dso->sorted_by_name = 0;
452 dso->has_build_id = 0; 482 dso->has_build_id = 0;
453 dso->has_srcline = 1; 483 dso->has_srcline = 1;
484 dso->a2l_fails = 1;
454 dso->kernel = DSO_TYPE_USER; 485 dso->kernel = DSO_TYPE_USER;
455 dso->needs_swap = DSO_SWAP__UNSET; 486 dso->needs_swap = DSO_SWAP__UNSET;
456 INIT_LIST_HEAD(&dso->node); 487 INIT_LIST_HEAD(&dso->node);
@@ -464,11 +495,20 @@ void dso__delete(struct dso *dso)
464 int i; 495 int i;
465 for (i = 0; i < MAP__NR_TYPES; ++i) 496 for (i = 0; i < MAP__NR_TYPES; ++i)
466 symbols__delete(&dso->symbols[i]); 497 symbols__delete(&dso->symbols[i]);
467 if (dso->sname_alloc) 498
468 free((char *)dso->short_name); 499 if (dso->short_name_allocated) {
469 if (dso->lname_alloc) 500 zfree((char **)&dso->short_name);
470 free(dso->long_name); 501 dso->short_name_allocated = false;
502 }
503
504 if (dso->long_name_allocated) {
505 zfree((char **)&dso->long_name);
506 dso->long_name_allocated = false;
507 }
508
471 dso_cache__free(&dso->cache); 509 dso_cache__free(&dso->cache);
510 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename);
472 free(dso); 512 free(dso);
473} 513}
474 514
@@ -543,7 +583,7 @@ void dsos__add(struct list_head *head, struct dso *dso)
543 list_add_tail(&dso->node, head); 583 list_add_tail(&dso->node, head);
544} 584}
545 585
546struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) 586struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
547{ 587{
548 struct dso *pos; 588 struct dso *pos;
549 589
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 9ac666abbe7e..cd7d6f078cdd 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -77,23 +77,26 @@ struct dso {
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache; 79 struct rb_root cache;
80 void *a2l;
81 char *symsrc_filename;
82 unsigned int a2l_fails;
80 enum dso_kernel_type kernel; 83 enum dso_kernel_type kernel;
81 enum dso_swap_type needs_swap; 84 enum dso_swap_type needs_swap;
82 enum dso_binary_type symtab_type; 85 enum dso_binary_type symtab_type;
83 enum dso_binary_type data_type; 86 enum dso_binary_type binary_type;
84 u8 adjust_symbols:1; 87 u8 adjust_symbols:1;
85 u8 has_build_id:1; 88 u8 has_build_id:1;
86 u8 has_srcline:1; 89 u8 has_srcline:1;
87 u8 hit:1; 90 u8 hit:1;
88 u8 annotate_warned:1; 91 u8 annotate_warned:1;
89 u8 sname_alloc:1; 92 u8 short_name_allocated:1;
90 u8 lname_alloc:1; 93 u8 long_name_allocated:1;
91 u8 sorted_by_name; 94 u8 sorted_by_name;
92 u8 loaded; 95 u8 loaded;
93 u8 rel; 96 u8 rel;
94 u8 build_id[BUILD_ID_SIZE]; 97 u8 build_id[BUILD_ID_SIZE];
95 const char *short_name; 98 const char *short_name;
96 char *long_name; 99 const char *long_name;
97 u16 long_name_len; 100 u16 long_name_len;
98 u16 short_name_len; 101 u16 short_name_len;
99 char name[0]; 102 char name[0];
@@ -107,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type)
107struct dso *dso__new(const char *name); 110struct dso *dso__new(const char *name);
108void dso__delete(struct dso *dso); 111void dso__delete(struct dso *dso);
109 112
110void dso__set_short_name(struct dso *dso, const char *name); 113void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
111void dso__set_long_name(struct dso *dso, char *name); 114void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
112 115
113int dso__name_len(const struct dso *dso); 116int dso__name_len(const struct dso *dso);
114 117
@@ -125,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso,
125int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); 128int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
126 129
127char dso__symtab_origin(const struct dso *dso); 130char dso__symtab_origin(const struct dso *dso);
128int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 131int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
129 char *root_dir, char *file, size_t size); 132 char *root_dir, char *filename, size_t size);
130 133
131int dso__data_fd(struct dso *dso, struct machine *machine); 134int dso__data_fd(struct dso *dso, struct machine *machine);
132ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 135ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
@@ -140,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
140 const char *short_name, int dso_type); 143 const char *short_name, int dso_type);
141 144
142void dsos__add(struct list_head *head, struct dso *dso); 145void dsos__add(struct list_head *head, struct dso *dso);
143struct dso *dsos__find(struct list_head *head, const char *name, 146struct dso *dsos__find(const struct list_head *head, const char *name,
144 bool cmp_short); 147 bool cmp_short);
145struct dso *__dsos__findnew(struct list_head *head, const char *name); 148struct dso *__dsos__findnew(struct list_head *head, const char *name);
146bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 149bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
@@ -156,14 +159,16 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
156 159
157static inline bool dso__is_vmlinux(struct dso *dso) 160static inline bool dso__is_vmlinux(struct dso *dso)
158{ 161{
159 return dso->data_type == DSO_BINARY_TYPE__VMLINUX || 162 return dso->binary_type == DSO_BINARY_TYPE__VMLINUX ||
160 dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX; 163 dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
161} 164}
162 165
163static inline bool dso__is_kcore(struct dso *dso) 166static inline bool dso__is_kcore(struct dso *dso)
164{ 167{
165 return dso->data_type == DSO_BINARY_TYPE__KCORE || 168 return dso->binary_type == DSO_BINARY_TYPE__KCORE ||
166 dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; 169 dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
167} 170}
168 171
172void dso__free_a2l(struct dso *dso);
173
169#endif /* __PERF_DSO */ 174#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb788c109fe6..1fc1c2f04772 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -7,6 +7,7 @@
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9#include "thread_map.h" 9#include "thread_map.h"
10#include "symbol/kallsyms.h"
10 11
11static const char *perf_event__names[] = { 12static const char *perf_event__names[] = {
12 [0] = "TOTAL", 13 [0] = "TOTAL",
@@ -105,8 +106,12 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
105 106
106 memset(&event->comm, 0, sizeof(event->comm)); 107 memset(&event->comm, 0, sizeof(event->comm));
107 108
108 tgid = perf_event__get_comm_tgid(pid, event->comm.comm, 109 if (machine__is_host(machine))
109 sizeof(event->comm.comm)); 110 tgid = perf_event__get_comm_tgid(pid, event->comm.comm,
111 sizeof(event->comm.comm));
112 else
113 tgid = machine->pid;
114
110 if (tgid < 0) 115 if (tgid < 0)
111 goto out; 116 goto out;
112 117
@@ -128,7 +133,11 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
128 goto out; 133 goto out;
129 } 134 }
130 135
131 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 136 if (machine__is_default_guest(machine))
137 return 0;
138
139 snprintf(filename, sizeof(filename), "%s/proc/%d/task",
140 machine->root_dir, pid);
132 141
133 tasks = opendir(filename); 142 tasks = opendir(filename);
134 if (tasks == NULL) { 143 if (tasks == NULL) {
@@ -166,18 +175,22 @@ out:
166 return tgid; 175 return tgid;
167} 176}
168 177
169static int perf_event__synthesize_mmap_events(struct perf_tool *tool, 178int perf_event__synthesize_mmap_events(struct perf_tool *tool,
170 union perf_event *event, 179 union perf_event *event,
171 pid_t pid, pid_t tgid, 180 pid_t pid, pid_t tgid,
172 perf_event__handler_t process, 181 perf_event__handler_t process,
173 struct machine *machine, 182 struct machine *machine,
174 bool mmap_data) 183 bool mmap_data)
175{ 184{
176 char filename[PATH_MAX]; 185 char filename[PATH_MAX];
177 FILE *fp; 186 FILE *fp;
178 int rc = 0; 187 int rc = 0;
179 188
180 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 189 if (machine__is_default_guest(machine))
190 return 0;
191
192 snprintf(filename, sizeof(filename), "%s/proc/%d/maps",
193 machine->root_dir, pid);
181 194
182 fp = fopen(filename, "r"); 195 fp = fopen(filename, "r");
183 if (fp == NULL) { 196 if (fp == NULL) {
@@ -217,7 +230,10 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
217 /* 230 /*
218 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 231 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
219 */ 232 */
220 event->header.misc = PERF_RECORD_MISC_USER; 233 if (machine__is_host(machine))
234 event->header.misc = PERF_RECORD_MISC_USER;
235 else
236 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
221 237
222 if (prot[2] != 'x') { 238 if (prot[2] != 'x') {
223 if (!mmap_data || prot[0] != 'r') 239 if (!mmap_data || prot[0] != 'r')
@@ -386,6 +402,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
386 struct machine *machine, bool mmap_data) 402 struct machine *machine, bool mmap_data)
387{ 403{
388 DIR *proc; 404 DIR *proc;
405 char proc_path[PATH_MAX];
389 struct dirent dirent, *next; 406 struct dirent dirent, *next;
390 union perf_event *comm_event, *mmap_event; 407 union perf_event *comm_event, *mmap_event;
391 int err = -1; 408 int err = -1;
@@ -398,7 +415,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
398 if (mmap_event == NULL) 415 if (mmap_event == NULL)
399 goto out_free_comm; 416 goto out_free_comm;
400 417
401 proc = opendir("/proc"); 418 if (machine__is_default_guest(machine))
419 return 0;
420
421 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
422 proc = opendir(proc_path);
423
402 if (proc == NULL) 424 if (proc == NULL)
403 goto out_free_mmap; 425 goto out_free_mmap;
404 426
@@ -637,6 +659,7 @@ void thread__find_addr_map(struct thread *thread,
637 struct map_groups *mg = &thread->mg; 659 struct map_groups *mg = &thread->mg;
638 bool load_map = false; 660 bool load_map = false;
639 661
662 al->machine = machine;
640 al->thread = thread; 663 al->thread = thread;
641 al->addr = addr; 664 al->addr = addr;
642 al->cpumode = cpumode; 665 al->cpumode = cpumode;
@@ -657,15 +680,10 @@ void thread__find_addr_map(struct thread *thread,
657 al->level = 'g'; 680 al->level = 'g';
658 mg = &machine->kmaps; 681 mg = &machine->kmaps;
659 load_map = true; 682 load_map = true;
683 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
684 al->level = 'u';
660 } else { 685 } else {
661 /* 686 al->level = 'H';
662 * 'u' means guest os user space.
663 * TODO: We don't support guest user space. Might support late.
664 */
665 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
666 al->level = 'u';
667 else
668 al->level = 'H';
669 al->map = NULL; 687 al->map = NULL;
670 688
671 if ((cpumode == PERF_RECORD_MISC_GUEST_USER || 689 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
@@ -732,8 +750,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
732 if (thread == NULL) 750 if (thread == NULL)
733 return -1; 751 return -1;
734 752
735 if (symbol_conf.comm_list && 753 if (thread__is_filtered(thread))
736 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread)))
737 goto out_filtered; 754 goto out_filtered;
738 755
739 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 756 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 30fec9901e44..faf6e219be21 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -266,6 +266,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
266 const struct perf_sample *sample, 266 const struct perf_sample *sample,
267 bool swapped); 267 bool swapped);
268 268
269int perf_event__synthesize_mmap_events(struct perf_tool *tool,
270 union perf_event *event,
271 pid_t pid, pid_t tgid,
272 perf_event__handler_t process,
273 struct machine *machine,
274 bool mmap_data);
275
269size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); 276size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
270size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 277size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
271size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); 278size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index bbc746aa5716..40bd2c04df8a 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -7,7 +7,7 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include <lk/debugfs.h> 10#include <api/fs/debugfs.h>
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
@@ -81,7 +81,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
81{ 81{
82 struct perf_evsel *evsel; 82 struct perf_evsel *evsel;
83 83
84 list_for_each_entry(evsel, &evlist->entries, node) 84 evlist__for_each(evlist, evsel)
85 perf_evsel__calc_id_pos(evsel); 85 perf_evsel__calc_id_pos(evsel);
86 86
87 perf_evlist__set_id_pos(evlist); 87 perf_evlist__set_id_pos(evlist);
@@ -91,7 +91,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
91{ 91{
92 struct perf_evsel *pos, *n; 92 struct perf_evsel *pos, *n;
93 93
94 list_for_each_entry_safe(pos, n, &evlist->entries, node) { 94 evlist__for_each_safe(evlist, n, pos) {
95 list_del_init(&pos->node); 95 list_del_init(&pos->node);
96 perf_evsel__delete(pos); 96 perf_evsel__delete(pos);
97 } 97 }
@@ -101,14 +101,18 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
101 101
102void perf_evlist__exit(struct perf_evlist *evlist) 102void perf_evlist__exit(struct perf_evlist *evlist)
103{ 103{
104 free(evlist->mmap); 104 zfree(&evlist->mmap);
105 free(evlist->pollfd); 105 zfree(&evlist->pollfd);
106 evlist->mmap = NULL;
107 evlist->pollfd = NULL;
108} 106}
109 107
110void perf_evlist__delete(struct perf_evlist *evlist) 108void perf_evlist__delete(struct perf_evlist *evlist)
111{ 109{
110 perf_evlist__munmap(evlist);
111 perf_evlist__close(evlist);
112 cpu_map__delete(evlist->cpus);
113 thread_map__delete(evlist->threads);
114 evlist->cpus = NULL;
115 evlist->threads = NULL;
112 perf_evlist__purge(evlist); 116 perf_evlist__purge(evlist);
113 perf_evlist__exit(evlist); 117 perf_evlist__exit(evlist);
114 free(evlist); 118 free(evlist);
@@ -144,7 +148,7 @@ void __perf_evlist__set_leader(struct list_head *list)
144 148
145 leader->nr_members = evsel->idx - leader->idx + 1; 149 leader->nr_members = evsel->idx - leader->idx + 1;
146 150
147 list_for_each_entry(evsel, list, node) { 151 __evlist__for_each(list, evsel) {
148 evsel->leader = leader; 152 evsel->leader = leader;
149 } 153 }
150} 154}
@@ -203,7 +207,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist,
203 return 0; 207 return 0;
204 208
205out_delete_partial_list: 209out_delete_partial_list:
206 list_for_each_entry_safe(evsel, n, &head, node) 210 __evlist__for_each_safe(&head, n, evsel)
207 perf_evsel__delete(evsel); 211 perf_evsel__delete(evsel);
208 return -1; 212 return -1;
209} 213}
@@ -224,7 +228,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
224{ 228{
225 struct perf_evsel *evsel; 229 struct perf_evsel *evsel;
226 230
227 list_for_each_entry(evsel, &evlist->entries, node) { 231 evlist__for_each(evlist, evsel) {
228 if (evsel->attr.type == PERF_TYPE_TRACEPOINT && 232 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
229 (int)evsel->attr.config == id) 233 (int)evsel->attr.config == id)
230 return evsel; 234 return evsel;
@@ -239,7 +243,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
239{ 243{
240 struct perf_evsel *evsel; 244 struct perf_evsel *evsel;
241 245
242 list_for_each_entry(evsel, &evlist->entries, node) { 246 evlist__for_each(evlist, evsel) {
243 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && 247 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
244 (strcmp(evsel->name, name) == 0)) 248 (strcmp(evsel->name, name) == 0))
245 return evsel; 249 return evsel;
@@ -269,7 +273,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
269 int nr_threads = thread_map__nr(evlist->threads); 273 int nr_threads = thread_map__nr(evlist->threads);
270 274
271 for (cpu = 0; cpu < nr_cpus; cpu++) { 275 for (cpu = 0; cpu < nr_cpus; cpu++) {
272 list_for_each_entry(pos, &evlist->entries, node) { 276 evlist__for_each(evlist, pos) {
273 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 277 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
274 continue; 278 continue;
275 for (thread = 0; thread < nr_threads; thread++) 279 for (thread = 0; thread < nr_threads; thread++)
@@ -287,7 +291,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
287 int nr_threads = thread_map__nr(evlist->threads); 291 int nr_threads = thread_map__nr(evlist->threads);
288 292
289 for (cpu = 0; cpu < nr_cpus; cpu++) { 293 for (cpu = 0; cpu < nr_cpus; cpu++) {
290 list_for_each_entry(pos, &evlist->entries, node) { 294 evlist__for_each(evlist, pos) {
291 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 295 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
292 continue; 296 continue;
293 for (thread = 0; thread < nr_threads; thread++) 297 for (thread = 0; thread < nr_threads; thread++)
@@ -584,11 +588,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
584{ 588{
585 int i; 589 int i;
586 590
591 if (evlist->mmap == NULL)
592 return;
593
587 for (i = 0; i < evlist->nr_mmaps; i++) 594 for (i = 0; i < evlist->nr_mmaps; i++)
588 __perf_evlist__munmap(evlist, i); 595 __perf_evlist__munmap(evlist, i);
589 596
590 free(evlist->mmap); 597 zfree(&evlist->mmap);
591 evlist->mmap = NULL;
592} 598}
593 599
594static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 600static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
@@ -624,7 +630,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
624{ 630{
625 struct perf_evsel *evsel; 631 struct perf_evsel *evsel;
626 632
627 list_for_each_entry(evsel, &evlist->entries, node) { 633 evlist__for_each(evlist, evsel) {
628 int fd = FD(evsel, cpu, thread); 634 int fd = FD(evsel, cpu, thread);
629 635
630 if (*output == -1) { 636 if (*output == -1) {
@@ -732,11 +738,13 @@ static long parse_pages_arg(const char *str, unsigned long min,
732 return -EINVAL; 738 return -EINVAL;
733 } 739 }
734 740
735 if ((pages == 0) && (min == 0)) { 741 if (pages == 0 && min == 0) {
736 /* leave number of pages at 0 */ 742 /* leave number of pages at 0 */
737 } else if (pages < (1UL << 31) && !is_power_of_2(pages)) { 743 } else if (!is_power_of_2(pages)) {
738 /* round pages up to next power of 2 */ 744 /* round pages up to next power of 2 */
739 pages = next_pow2(pages); 745 pages = next_pow2_l(pages);
746 if (!pages)
747 return -EINVAL;
740 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", 748 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n",
741 pages * page_size, pages); 749 pages * page_size, pages);
742 } 750 }
@@ -754,7 +762,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
754 unsigned long max = UINT_MAX; 762 unsigned long max = UINT_MAX;
755 long pages; 763 long pages;
756 764
757 if (max < SIZE_MAX / page_size) 765 if (max > SIZE_MAX / page_size)
758 max = SIZE_MAX / page_size; 766 max = SIZE_MAX / page_size;
759 767
760 pages = parse_pages_arg(str, 1, max); 768 pages = parse_pages_arg(str, 1, max);
@@ -798,7 +806,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
798 pr_debug("mmap size %zuB\n", evlist->mmap_len); 806 pr_debug("mmap size %zuB\n", evlist->mmap_len);
799 mask = evlist->mmap_len - page_size - 1; 807 mask = evlist->mmap_len - page_size - 1;
800 808
801 list_for_each_entry(evsel, &evlist->entries, node) { 809 evlist__for_each(evlist, evsel) {
802 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 810 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
803 evsel->sample_id == NULL && 811 evsel->sample_id == NULL &&
804 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) 812 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0)
@@ -819,11 +827,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
819 if (evlist->threads == NULL) 827 if (evlist->threads == NULL)
820 return -1; 828 return -1;
821 829
822 if (target->force_per_cpu) 830 if (target__uses_dummy_map(target))
823 evlist->cpus = cpu_map__new(target->cpu_list);
824 else if (target__has_task(target))
825 evlist->cpus = cpu_map__dummy_new();
826 else if (!target__has_cpu(target) && !target->uses_mmap)
827 evlist->cpus = cpu_map__dummy_new(); 831 evlist->cpus = cpu_map__dummy_new();
828 else 832 else
829 evlist->cpus = cpu_map__new(target->cpu_list); 833 evlist->cpus = cpu_map__new(target->cpu_list);
@@ -838,14 +842,6 @@ out_delete_threads:
838 return -1; 842 return -1;
839} 843}
840 844
841void perf_evlist__delete_maps(struct perf_evlist *evlist)
842{
843 cpu_map__delete(evlist->cpus);
844 thread_map__delete(evlist->threads);
845 evlist->cpus = NULL;
846 evlist->threads = NULL;
847}
848
849int perf_evlist__apply_filters(struct perf_evlist *evlist) 845int perf_evlist__apply_filters(struct perf_evlist *evlist)
850{ 846{
851 struct perf_evsel *evsel; 847 struct perf_evsel *evsel;
@@ -853,7 +849,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
853 const int ncpus = cpu_map__nr(evlist->cpus), 849 const int ncpus = cpu_map__nr(evlist->cpus),
854 nthreads = thread_map__nr(evlist->threads); 850 nthreads = thread_map__nr(evlist->threads);
855 851
856 list_for_each_entry(evsel, &evlist->entries, node) { 852 evlist__for_each(evlist, evsel) {
857 if (evsel->filter == NULL) 853 if (evsel->filter == NULL)
858 continue; 854 continue;
859 855
@@ -872,7 +868,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
872 const int ncpus = cpu_map__nr(evlist->cpus), 868 const int ncpus = cpu_map__nr(evlist->cpus),
873 nthreads = thread_map__nr(evlist->threads); 869 nthreads = thread_map__nr(evlist->threads);
874 870
875 list_for_each_entry(evsel, &evlist->entries, node) { 871 evlist__for_each(evlist, evsel) {
876 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); 872 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
877 if (err) 873 if (err)
878 break; 874 break;
@@ -891,7 +887,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
891 if (evlist->id_pos < 0 || evlist->is_pos < 0) 887 if (evlist->id_pos < 0 || evlist->is_pos < 0)
892 return false; 888 return false;
893 889
894 list_for_each_entry(pos, &evlist->entries, node) { 890 evlist__for_each(evlist, pos) {
895 if (pos->id_pos != evlist->id_pos || 891 if (pos->id_pos != evlist->id_pos ||
896 pos->is_pos != evlist->is_pos) 892 pos->is_pos != evlist->is_pos)
897 return false; 893 return false;
@@ -907,7 +903,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
907 if (evlist->combined_sample_type) 903 if (evlist->combined_sample_type)
908 return evlist->combined_sample_type; 904 return evlist->combined_sample_type;
909 905
910 list_for_each_entry(evsel, &evlist->entries, node) 906 evlist__for_each(evlist, evsel)
911 evlist->combined_sample_type |= evsel->attr.sample_type; 907 evlist->combined_sample_type |= evsel->attr.sample_type;
912 908
913 return evlist->combined_sample_type; 909 return evlist->combined_sample_type;
@@ -925,7 +921,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
925 u64 read_format = first->attr.read_format; 921 u64 read_format = first->attr.read_format;
926 u64 sample_type = first->attr.sample_type; 922 u64 sample_type = first->attr.sample_type;
927 923
928 list_for_each_entry_continue(pos, &evlist->entries, node) { 924 evlist__for_each(evlist, pos) {
929 if (read_format != pos->attr.read_format) 925 if (read_format != pos->attr.read_format)
930 return false; 926 return false;
931 } 927 }
@@ -982,7 +978,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
982{ 978{
983 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; 979 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
984 980
985 list_for_each_entry_continue(pos, &evlist->entries, node) { 981 evlist__for_each_continue(evlist, pos) {
986 if (first->attr.sample_id_all != pos->attr.sample_id_all) 982 if (first->attr.sample_id_all != pos->attr.sample_id_all)
987 return false; 983 return false;
988 } 984 }
@@ -1008,7 +1004,7 @@ void perf_evlist__close(struct perf_evlist *evlist)
1008 int ncpus = cpu_map__nr(evlist->cpus); 1004 int ncpus = cpu_map__nr(evlist->cpus);
1009 int nthreads = thread_map__nr(evlist->threads); 1005 int nthreads = thread_map__nr(evlist->threads);
1010 1006
1011 list_for_each_entry_reverse(evsel, &evlist->entries, node) 1007 evlist__for_each_reverse(evlist, evsel)
1012 perf_evsel__close(evsel, ncpus, nthreads); 1008 perf_evsel__close(evsel, ncpus, nthreads);
1013} 1009}
1014 1010
@@ -1019,7 +1015,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
1019 1015
1020 perf_evlist__update_id_pos(evlist); 1016 perf_evlist__update_id_pos(evlist);
1021 1017
1022 list_for_each_entry(evsel, &evlist->entries, node) { 1018 evlist__for_each(evlist, evsel) {
1023 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 1019 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
1024 if (err < 0) 1020 if (err < 0)
1025 goto out_err; 1021 goto out_err;
@@ -1034,7 +1030,7 @@ out_err:
1034 1030
1035int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, 1031int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target,
1036 const char *argv[], bool pipe_output, 1032 const char *argv[], bool pipe_output,
1037 bool want_signal) 1033 void (*exec_error)(int signo, siginfo_t *info, void *ucontext))
1038{ 1034{
1039 int child_ready_pipe[2], go_pipe[2]; 1035 int child_ready_pipe[2], go_pipe[2];
1040 char bf; 1036 char bf;
@@ -1078,12 +1074,25 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
1078 1074
1079 execvp(argv[0], (char **)argv); 1075 execvp(argv[0], (char **)argv);
1080 1076
1081 perror(argv[0]); 1077 if (exec_error) {
1082 if (want_signal) 1078 union sigval val;
1083 kill(getppid(), SIGUSR1); 1079
1080 val.sival_int = errno;
1081 if (sigqueue(getppid(), SIGUSR1, val))
1082 perror(argv[0]);
1083 } else
1084 perror(argv[0]);
1084 exit(-1); 1085 exit(-1);
1085 } 1086 }
1086 1087
1088 if (exec_error) {
1089 struct sigaction act = {
1090 .sa_flags = SA_SIGINFO,
1091 .sa_sigaction = exec_error,
1092 };
1093 sigaction(SIGUSR1, &act, NULL);
1094 }
1095
1087 if (target__none(target)) 1096 if (target__none(target))
1088 evlist->threads->map[0] = evlist->workload.pid; 1097 evlist->threads->map[0] = evlist->workload.pid;
1089 1098
@@ -1145,7 +1154,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1145 struct perf_evsel *evsel; 1154 struct perf_evsel *evsel;
1146 size_t printed = 0; 1155 size_t printed = 0;
1147 1156
1148 list_for_each_entry(evsel, &evlist->entries, node) { 1157 evlist__for_each(evlist, evsel) {
1149 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", 1158 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "",
1150 perf_evsel__name(evsel)); 1159 perf_evsel__name(evsel));
1151 } 1160 }
@@ -1193,8 +1202,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1193 "Error:\t%s.\n" 1202 "Error:\t%s.\n"
1194 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); 1203 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
1195 1204
1196 if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) 1205 value = perf_event_paranoid();
1197 break;
1198 1206
1199 printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); 1207 printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
1200 1208
@@ -1215,3 +1223,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1215 1223
1216 return 0; 1224 return 0;
1217} 1225}
1226
1227void perf_evlist__to_front(struct perf_evlist *evlist,
1228 struct perf_evsel *move_evsel)
1229{
1230 struct perf_evsel *evsel, *n;
1231 LIST_HEAD(move);
1232
1233 if (move_evsel == perf_evlist__first(evlist))
1234 return;
1235
1236 evlist__for_each_safe(evlist, n, evsel) {
1237 if (evsel->leader == move_evsel->leader)
1238 list_move_tail(&evsel->node, &move);
1239 }
1240
1241 list_splice(&move, &evlist->entries);
1242}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 649d6ea98a84..f5173cd63693 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -12,7 +12,7 @@
12struct pollfd; 12struct pollfd;
13struct thread_map; 13struct thread_map;
14struct cpu_map; 14struct cpu_map;
15struct perf_record_opts; 15struct record_opts;
16 16
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -97,14 +97,14 @@ void perf_evlist__close(struct perf_evlist *evlist);
97 97
98void perf_evlist__set_id_pos(struct perf_evlist *evlist); 98void perf_evlist__set_id_pos(struct perf_evlist *evlist);
99bool perf_can_sample_identifier(void); 99bool perf_can_sample_identifier(void);
100void perf_evlist__config(struct perf_evlist *evlist, 100void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts);
101 struct perf_record_opts *opts); 101int record_opts__config(struct record_opts *opts);
102int perf_record_opts__config(struct perf_record_opts *opts);
103 102
104int perf_evlist__prepare_workload(struct perf_evlist *evlist, 103int perf_evlist__prepare_workload(struct perf_evlist *evlist,
105 struct target *target, 104 struct target *target,
106 const char *argv[], bool pipe_output, 105 const char *argv[], bool pipe_output,
107 bool want_signal); 106 void (*exec_error)(int signo, siginfo_t *info,
107 void *ucontext));
108int perf_evlist__start_workload(struct perf_evlist *evlist); 108int perf_evlist__start_workload(struct perf_evlist *evlist);
109 109
110int perf_evlist__parse_mmap_pages(const struct option *opt, 110int perf_evlist__parse_mmap_pages(const struct option *opt,
@@ -135,7 +135,6 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
135} 135}
136 136
137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); 137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
138void perf_evlist__delete_maps(struct perf_evlist *evlist);
139int perf_evlist__apply_filters(struct perf_evlist *evlist); 138int perf_evlist__apply_filters(struct perf_evlist *evlist);
140 139
141void __perf_evlist__set_leader(struct list_head *list); 140void __perf_evlist__set_leader(struct list_head *list);
@@ -193,4 +192,74 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md,
193 pc->data_tail = tail; 192 pc->data_tail = tail;
194} 193}
195 194
195bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str);
196void perf_evlist__to_front(struct perf_evlist *evlist,
197 struct perf_evsel *move_evsel);
198
199/**
200 * __evlist__for_each - iterate thru all the evsels
201 * @list: list_head instance to iterate
202 * @evsel: struct evsel iterator
203 */
204#define __evlist__for_each(list, evsel) \
205 list_for_each_entry(evsel, list, node)
206
207/**
208 * evlist__for_each - iterate thru all the evsels
209 * @evlist: evlist instance to iterate
210 * @evsel: struct evsel iterator
211 */
212#define evlist__for_each(evlist, evsel) \
213 __evlist__for_each(&(evlist)->entries, evsel)
214
215/**
216 * __evlist__for_each_continue - continue iteration thru all the evsels
217 * @list: list_head instance to iterate
218 * @evsel: struct evsel iterator
219 */
220#define __evlist__for_each_continue(list, evsel) \
221 list_for_each_entry_continue(evsel, list, node)
222
223/**
224 * evlist__for_each_continue - continue iteration thru all the evsels
225 * @evlist: evlist instance to iterate
226 * @evsel: struct evsel iterator
227 */
228#define evlist__for_each_continue(evlist, evsel) \
229 __evlist__for_each_continue(&(evlist)->entries, evsel)
230
231/**
232 * __evlist__for_each_reverse - iterate thru all the evsels in reverse order
233 * @list: list_head instance to iterate
234 * @evsel: struct evsel iterator
235 */
236#define __evlist__for_each_reverse(list, evsel) \
237 list_for_each_entry_reverse(evsel, list, node)
238
239/**
240 * evlist__for_each_reverse - iterate thru all the evsels in reverse order
241 * @evlist: evlist instance to iterate
242 * @evsel: struct evsel iterator
243 */
244#define evlist__for_each_reverse(evlist, evsel) \
245 __evlist__for_each_reverse(&(evlist)->entries, evsel)
246
247/**
248 * __evlist__for_each_safe - safely iterate thru all the evsels
249 * @list: list_head instance to iterate
250 * @tmp: struct evsel temp iterator
251 * @evsel: struct evsel iterator
252 */
253#define __evlist__for_each_safe(list, tmp, evsel) \
254 list_for_each_entry_safe(evsel, tmp, list, node)
255
256/**
257 * evlist__for_each_safe - safely iterate thru all the evsels
258 * @evlist: evlist instance to iterate
259 * @evsel: struct evsel iterator
260 * @tmp: struct evsel temp iterator
261 */
262#define evlist__for_each_safe(evlist, tmp, evsel) \
263 __evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
264
196#endif /* __PERF_EVLIST_H */ 265#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 46dd4c2a41ce..cd4630abfa43 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -9,7 +9,7 @@
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include <lk/debugfs.h> 12#include <api/fs/debugfs.h>
13#include <traceevent/event-parse.h> 13#include <traceevent/event-parse.h>
14#include <linux/hw_breakpoint.h> 14#include <linux/hw_breakpoint.h>
15#include <linux/perf_event.h> 15#include <linux/perf_event.h>
@@ -23,6 +23,7 @@
23#include "target.h" 23#include "target.h"
24#include "perf_regs.h" 24#include "perf_regs.h"
25#include "debug.h" 25#include "debug.h"
26#include "trace-event.h"
26 27
27static struct { 28static struct {
28 bool sample_id_all; 29 bool sample_id_all;
@@ -162,6 +163,8 @@ void perf_evsel__init(struct perf_evsel *evsel,
162 evsel->idx = idx; 163 evsel->idx = idx;
163 evsel->attr = *attr; 164 evsel->attr = *attr;
164 evsel->leader = evsel; 165 evsel->leader = evsel;
166 evsel->unit = "";
167 evsel->scale = 1.0;
165 INIT_LIST_HEAD(&evsel->node); 168 INIT_LIST_HEAD(&evsel->node);
166 hists__init(&evsel->hists); 169 hists__init(&evsel->hists);
167 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 170 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -178,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
178 return evsel; 181 return evsel;
179} 182}
180 183
181struct event_format *event_format__new(const char *sys, const char *name)
182{
183 int fd, n;
184 char *filename;
185 void *bf = NULL, *nbf;
186 size_t size = 0, alloc_size = 0;
187 struct event_format *format = NULL;
188
189 if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
190 goto out;
191
192 fd = open(filename, O_RDONLY);
193 if (fd < 0)
194 goto out_free_filename;
195
196 do {
197 if (size == alloc_size) {
198 alloc_size += BUFSIZ;
199 nbf = realloc(bf, alloc_size);
200 if (nbf == NULL)
201 goto out_free_bf;
202 bf = nbf;
203 }
204
205 n = read(fd, bf + size, alloc_size - size);
206 if (n < 0)
207 goto out_free_bf;
208 size += n;
209 } while (n > 0);
210
211 pevent_parse_format(&format, bf, size, sys);
212
213out_free_bf:
214 free(bf);
215 close(fd);
216out_free_filename:
217 free(filename);
218out:
219 return format;
220}
221
222struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) 184struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
223{ 185{
224 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 186 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
@@ -233,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
233 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) 195 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
234 goto out_free; 196 goto out_free;
235 197
236 evsel->tp_format = event_format__new(sys, name); 198 evsel->tp_format = trace_event__tp_format(sys, name);
237 if (evsel->tp_format == NULL) 199 if (evsel->tp_format == NULL)
238 goto out_free; 200 goto out_free;
239 201
@@ -246,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
246 return evsel; 208 return evsel;
247 209
248out_free: 210out_free:
249 free(evsel->name); 211 zfree(&evsel->name);
250 free(evsel); 212 free(evsel);
251 return NULL; 213 return NULL;
252} 214}
@@ -566,12 +528,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
566 * enable/disable events specifically, as there's no 528 * enable/disable events specifically, as there's no
567 * initial traced exec call. 529 * initial traced exec call.
568 */ 530 */
569void perf_evsel__config(struct perf_evsel *evsel, 531void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
570 struct perf_record_opts *opts)
571{ 532{
572 struct perf_evsel *leader = evsel->leader; 533 struct perf_evsel *leader = evsel->leader;
573 struct perf_event_attr *attr = &evsel->attr; 534 struct perf_event_attr *attr = &evsel->attr;
574 int track = !evsel->idx; /* only the first counter needs these */ 535 int track = !evsel->idx; /* only the first counter needs these */
536 bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
575 537
576 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; 538 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
577 attr->inherit = !opts->no_inherit; 539 attr->inherit = !opts->no_inherit;
@@ -645,7 +607,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
645 } 607 }
646 } 608 }
647 609
648 if (target__has_cpu(&opts->target) || opts->target.force_per_cpu) 610 if (target__has_cpu(&opts->target))
649 perf_evsel__set_sample_bit(evsel, CPU); 611 perf_evsel__set_sample_bit(evsel, CPU);
650 612
651 if (opts->period) 613 if (opts->period)
@@ -653,7 +615,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
653 615
654 if (!perf_missing_features.sample_id_all && 616 if (!perf_missing_features.sample_id_all &&
655 (opts->sample_time || !opts->no_inherit || 617 (opts->sample_time || !opts->no_inherit ||
656 target__has_cpu(&opts->target) || opts->target.force_per_cpu)) 618 target__has_cpu(&opts->target) || per_cpu))
657 perf_evsel__set_sample_bit(evsel, TIME); 619 perf_evsel__set_sample_bit(evsel, TIME);
658 620
659 if (opts->raw_samples) { 621 if (opts->raw_samples) {
@@ -696,7 +658,8 @@ void perf_evsel__config(struct perf_evsel *evsel,
696 * Setting enable_on_exec for independent events and 658 * Setting enable_on_exec for independent events and
697 * group leaders for traced executed by perf. 659 * group leaders for traced executed by perf.
698 */ 660 */
699 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) 661 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
662 !opts->initial_delay)
700 attr->enable_on_exec = 1; 663 attr->enable_on_exec = 1;
701} 664}
702 665
@@ -788,8 +751,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel)
788{ 751{
789 xyarray__delete(evsel->sample_id); 752 xyarray__delete(evsel->sample_id);
790 evsel->sample_id = NULL; 753 evsel->sample_id = NULL;
791 free(evsel->id); 754 zfree(&evsel->id);
792 evsel->id = NULL;
793} 755}
794 756
795void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 757void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -805,7 +767,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
805 767
806void perf_evsel__free_counts(struct perf_evsel *evsel) 768void perf_evsel__free_counts(struct perf_evsel *evsel)
807{ 769{
808 free(evsel->counts); 770 zfree(&evsel->counts);
809} 771}
810 772
811void perf_evsel__exit(struct perf_evsel *evsel) 773void perf_evsel__exit(struct perf_evsel *evsel)
@@ -819,10 +781,10 @@ void perf_evsel__delete(struct perf_evsel *evsel)
819{ 781{
820 perf_evsel__exit(evsel); 782 perf_evsel__exit(evsel);
821 close_cgroup(evsel->cgrp); 783 close_cgroup(evsel->cgrp);
822 free(evsel->group_name); 784 zfree(&evsel->group_name);
823 if (evsel->tp_format) 785 if (evsel->tp_format)
824 pevent_free_format(evsel->tp_format); 786 pevent_free_format(evsel->tp_format);
825 free(evsel->name); 787 zfree(&evsel->name);
826 free(evsel); 788 free(evsel);
827} 789}
828 790
@@ -1998,8 +1960,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1998 evsel->attr.type = PERF_TYPE_SOFTWARE; 1960 evsel->attr.type = PERF_TYPE_SOFTWARE;
1999 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; 1961 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
2000 1962
2001 free(evsel->name); 1963 zfree(&evsel->name);
2002 evsel->name = NULL;
2003 return true; 1964 return true;
2004 } 1965 }
2005 1966
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 1ea7c92e6e33..f1b325665aae 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -68,6 +68,8 @@ struct perf_evsel {
68 u32 ids; 68 u32 ids;
69 struct hists hists; 69 struct hists hists;
70 char *name; 70 char *name;
71 double scale;
72 const char *unit;
71 struct event_format *tp_format; 73 struct event_format *tp_format;
72 union { 74 union {
73 void *priv; 75 void *priv;
@@ -94,7 +96,7 @@ struct perf_evsel {
94struct cpu_map; 96struct cpu_map;
95struct thread_map; 97struct thread_map;
96struct perf_evlist; 98struct perf_evlist;
97struct perf_record_opts; 99struct record_opts;
98 100
99struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); 101struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
100 102
@@ -118,7 +120,7 @@ void perf_evsel__exit(struct perf_evsel *evsel);
118void perf_evsel__delete(struct perf_evsel *evsel); 120void perf_evsel__delete(struct perf_evsel *evsel);
119 121
120void perf_evsel__config(struct perf_evsel *evsel, 122void perf_evsel__config(struct perf_evsel *evsel,
121 struct perf_record_opts *opts); 123 struct record_opts *opts);
122 124
123int __perf_evsel__sample_size(u64 sample_type); 125int __perf_evsel__sample_size(u64 sample_type);
124void perf_evsel__calc_id_pos(struct perf_evsel *evsel); 126void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
@@ -138,6 +140,7 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
138int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 140int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
139 char *bf, size_t size); 141 char *bf, size_t size);
140const char *perf_evsel__name(struct perf_evsel *evsel); 142const char *perf_evsel__name(struct perf_evsel *evsel);
143
141const char *perf_evsel__group_name(struct perf_evsel *evsel); 144const char *perf_evsel__group_name(struct perf_evsel *evsel);
142int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); 145int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
143 146
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1cd035708931..bb3e0ede6183 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv)
177 continue; \ 177 continue; \
178 else 178 else
179 179
180static int write_buildid(char *name, size_t name_len, u8 *build_id, 180static int write_buildid(const char *name, size_t name_len, u8 *build_id,
181 pid_t pid, u16 misc, int fd) 181 pid_t pid, u16 misc, int fd)
182{ 182{
183 int err; 183 int err;
@@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head,
209 209
210 dsos__for_each_with_build_id(pos, head) { 210 dsos__for_each_with_build_id(pos, head) {
211 int err; 211 int err;
212 char *name; 212 const char *name;
213 size_t name_len; 213 size_t name_len;
214 214
215 if (!pos->hit) 215 if (!pos->hit)
@@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
387{ 387{
388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
389 bool is_vdso = is_vdso_map(dso->short_name); 389 bool is_vdso = is_vdso_map(dso->short_name);
390 char *name = dso->long_name; 390 const char *name = dso->long_name;
391 char nm[PATH_MAX]; 391 char nm[PATH_MAX];
392 392
393 if (dso__is_kcore(dso)) { 393 if (dso__is_kcore(dso)) {
@@ -643,8 +643,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused,
643 if (ret < 0) 643 if (ret < 0)
644 return ret; 644 return ret;
645 645
646 list_for_each_entry(evsel, &evlist->entries, node) { 646 evlist__for_each(evlist, evsel) {
647
648 ret = do_write(fd, &evsel->attr, sz); 647 ret = do_write(fd, &evsel->attr, sz);
649 if (ret < 0) 648 if (ret < 0)
650 return ret; 649 return ret;
@@ -800,10 +799,10 @@ static void free_cpu_topo(struct cpu_topo *tp)
800 return; 799 return;
801 800
802 for (i = 0 ; i < tp->core_sib; i++) 801 for (i = 0 ; i < tp->core_sib; i++)
803 free(tp->core_siblings[i]); 802 zfree(&tp->core_siblings[i]);
804 803
805 for (i = 0 ; i < tp->thread_sib; i++) 804 for (i = 0 ; i < tp->thread_sib; i++)
806 free(tp->thread_siblings[i]); 805 zfree(&tp->thread_siblings[i]);
807 806
808 free(tp); 807 free(tp);
809} 808}
@@ -1092,7 +1091,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1092 if (ret < 0) 1091 if (ret < 0)
1093 return ret; 1092 return ret;
1094 1093
1095 list_for_each_entry(evsel, &evlist->entries, node) { 1094 evlist__for_each(evlist, evsel) {
1096 if (perf_evsel__is_group_leader(evsel) && 1095 if (perf_evsel__is_group_leader(evsel) &&
1097 evsel->nr_members > 1) { 1096 evsel->nr_members > 1) {
1098 const char *name = evsel->group_name ?: "{anon_group}"; 1097 const char *name = evsel->group_name ?: "{anon_group}";
@@ -1232,10 +1231,8 @@ static void free_event_desc(struct perf_evsel *events)
1232 return; 1231 return;
1233 1232
1234 for (evsel = events; evsel->attr.size; evsel++) { 1233 for (evsel = events; evsel->attr.size; evsel++) {
1235 if (evsel->name) 1234 zfree(&evsel->name);
1236 free(evsel->name); 1235 zfree(&evsel->id);
1237 if (evsel->id)
1238 free(evsel->id);
1239 } 1236 }
1240 1237
1241 free(events); 1238 free(events);
@@ -1326,8 +1323,7 @@ read_event_desc(struct perf_header *ph, int fd)
1326 } 1323 }
1327 } 1324 }
1328out: 1325out:
1329 if (buf) 1326 free(buf);
1330 free(buf);
1331 return events; 1327 return events;
1332error: 1328error:
1333 if (events) 1329 if (events)
@@ -1490,7 +1486,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1490 1486
1491 session = container_of(ph, struct perf_session, header); 1487 session = container_of(ph, struct perf_session, header);
1492 1488
1493 list_for_each_entry(evsel, &session->evlist->entries, node) { 1489 evlist__for_each(session->evlist, evsel) {
1494 if (perf_evsel__is_group_leader(evsel) && 1490 if (perf_evsel__is_group_leader(evsel) &&
1495 evsel->nr_members > 1) { 1491 evsel->nr_members > 1) {
1496 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", 1492 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
@@ -1709,7 +1705,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1709 struct perf_header *ph, int fd, 1705 struct perf_header *ph, int fd,
1710 void *data __maybe_unused) 1706 void *data __maybe_unused)
1711{ 1707{
1712 size_t ret; 1708 ssize_t ret;
1713 u32 nr; 1709 u32 nr;
1714 1710
1715 ret = readn(fd, &nr, sizeof(nr)); 1711 ret = readn(fd, &nr, sizeof(nr));
@@ -1753,7 +1749,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1753 void *data __maybe_unused) 1749 void *data __maybe_unused)
1754{ 1750{
1755 uint64_t mem; 1751 uint64_t mem;
1756 size_t ret; 1752 ssize_t ret;
1757 1753
1758 ret = readn(fd, &mem, sizeof(mem)); 1754 ret = readn(fd, &mem, sizeof(mem));
1759 if (ret != sizeof(mem)) 1755 if (ret != sizeof(mem))
@@ -1771,7 +1767,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
1771{ 1767{
1772 struct perf_evsel *evsel; 1768 struct perf_evsel *evsel;
1773 1769
1774 list_for_each_entry(evsel, &evlist->entries, node) { 1770 evlist__for_each(evlist, evsel) {
1775 if (evsel->idx == idx) 1771 if (evsel->idx == idx)
1776 return evsel; 1772 return evsel;
1777 } 1773 }
@@ -1822,7 +1818,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1822 struct perf_header *ph, int fd, 1818 struct perf_header *ph, int fd,
1823 void *data __maybe_unused) 1819 void *data __maybe_unused)
1824{ 1820{
1825 size_t ret; 1821 ssize_t ret;
1826 char *str; 1822 char *str;
1827 u32 nr, i; 1823 u32 nr, i;
1828 struct strbuf sb; 1824 struct strbuf sb;
@@ -1858,7 +1854,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1858 struct perf_header *ph, int fd, 1854 struct perf_header *ph, int fd,
1859 void *data __maybe_unused) 1855 void *data __maybe_unused)
1860{ 1856{
1861 size_t ret; 1857 ssize_t ret;
1862 u32 nr, i; 1858 u32 nr, i;
1863 char *str; 1859 char *str;
1864 struct strbuf sb; 1860 struct strbuf sb;
@@ -1914,7 +1910,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1914 struct perf_header *ph, int fd, 1910 struct perf_header *ph, int fd,
1915 void *data __maybe_unused) 1911 void *data __maybe_unused)
1916{ 1912{
1917 size_t ret; 1913 ssize_t ret;
1918 u32 nr, node, i; 1914 u32 nr, node, i;
1919 char *str; 1915 char *str;
1920 uint64_t mem_total, mem_free; 1916 uint64_t mem_total, mem_free;
@@ -1974,7 +1970,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1974 struct perf_header *ph, int fd, 1970 struct perf_header *ph, int fd,
1975 void *data __maybe_unused) 1971 void *data __maybe_unused)
1976{ 1972{
1977 size_t ret; 1973 ssize_t ret;
1978 char *name; 1974 char *name;
1979 u32 pmu_num; 1975 u32 pmu_num;
1980 u32 type; 1976 u32 type;
@@ -2074,7 +2070,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
2074 session->evlist->nr_groups = nr_groups; 2070 session->evlist->nr_groups = nr_groups;
2075 2071
2076 i = nr = 0; 2072 i = nr = 0;
2077 list_for_each_entry(evsel, &session->evlist->entries, node) { 2073 evlist__for_each(session->evlist, evsel) {
2078 if (evsel->idx == (int) desc[i].leader_idx) { 2074 if (evsel->idx == (int) desc[i].leader_idx) {
2079 evsel->leader = evsel; 2075 evsel->leader = evsel;
2080 /* {anon_group} is a dummy name */ 2076 /* {anon_group} is a dummy name */
@@ -2108,7 +2104,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
2108 ret = 0; 2104 ret = 0;
2109out_free: 2105out_free:
2110 for (i = 0; i < nr_groups; i++) 2106 for (i = 0; i < nr_groups; i++)
2111 free(desc[i].name); 2107 zfree(&desc[i].name);
2112 free(desc); 2108 free(desc);
2113 2109
2114 return ret; 2110 return ret;
@@ -2301,7 +2297,7 @@ int perf_session__write_header(struct perf_session *session,
2301 2297
2302 lseek(fd, sizeof(f_header), SEEK_SET); 2298 lseek(fd, sizeof(f_header), SEEK_SET);
2303 2299
2304 list_for_each_entry(evsel, &evlist->entries, node) { 2300 evlist__for_each(session->evlist, evsel) {
2305 evsel->id_offset = lseek(fd, 0, SEEK_CUR); 2301 evsel->id_offset = lseek(fd, 0, SEEK_CUR);
2306 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); 2302 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
2307 if (err < 0) { 2303 if (err < 0) {
@@ -2312,7 +2308,7 @@ int perf_session__write_header(struct perf_session *session,
2312 2308
2313 attr_offset = lseek(fd, 0, SEEK_CUR); 2309 attr_offset = lseek(fd, 0, SEEK_CUR);
2314 2310
2315 list_for_each_entry(evsel, &evlist->entries, node) { 2311 evlist__for_each(evlist, evsel) {
2316 f_attr = (struct perf_file_attr){ 2312 f_attr = (struct perf_file_attr){
2317 .attr = evsel->attr, 2313 .attr = evsel->attr,
2318 .ids = { 2314 .ids = {
@@ -2327,7 +2323,8 @@ int perf_session__write_header(struct perf_session *session,
2327 } 2323 }
2328 } 2324 }
2329 2325
2330 header->data_offset = lseek(fd, 0, SEEK_CUR); 2326 if (!header->data_offset)
2327 header->data_offset = lseek(fd, 0, SEEK_CUR);
2331 header->feat_offset = header->data_offset + header->data_size; 2328 header->feat_offset = header->data_offset + header->data_size;
2332 2329
2333 if (at_exit) { 2330 if (at_exit) {
@@ -2534,7 +2531,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2534int perf_file_header__read(struct perf_file_header *header, 2531int perf_file_header__read(struct perf_file_header *header,
2535 struct perf_header *ph, int fd) 2532 struct perf_header *ph, int fd)
2536{ 2533{
2537 int ret; 2534 ssize_t ret;
2538 2535
2539 lseek(fd, 0, SEEK_SET); 2536 lseek(fd, 0, SEEK_SET);
2540 2537
@@ -2628,7 +2625,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2628 struct perf_header *ph, int fd, 2625 struct perf_header *ph, int fd,
2629 bool repipe) 2626 bool repipe)
2630{ 2627{
2631 int ret; 2628 ssize_t ret;
2632 2629
2633 ret = readn(fd, header, sizeof(*header)); 2630 ret = readn(fd, header, sizeof(*header));
2634 if (ret <= 0) 2631 if (ret <= 0)
@@ -2669,7 +2666,7 @@ static int read_attr(int fd, struct perf_header *ph,
2669 struct perf_event_attr *attr = &f_attr->attr; 2666 struct perf_event_attr *attr = &f_attr->attr;
2670 size_t sz, left; 2667 size_t sz, left;
2671 size_t our_sz = sizeof(f_attr->attr); 2668 size_t our_sz = sizeof(f_attr->attr);
2672 int ret; 2669 ssize_t ret;
2673 2670
2674 memset(f_attr, 0, sizeof(*f_attr)); 2671 memset(f_attr, 0, sizeof(*f_attr));
2675 2672
@@ -2744,7 +2741,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2744{ 2741{
2745 struct perf_evsel *pos; 2742 struct perf_evsel *pos;
2746 2743
2747 list_for_each_entry(pos, &evlist->entries, node) { 2744 evlist__for_each(evlist, pos) {
2748 if (pos->attr.type == PERF_TYPE_TRACEPOINT && 2745 if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
2749 perf_evsel__prepare_tracepoint_event(pos, pevent)) 2746 perf_evsel__prepare_tracepoint_event(pos, pevent))
2750 return -1; 2747 return -1;
@@ -2834,11 +2831,11 @@ int perf_session__read_header(struct perf_session *session)
2834 2831
2835 symbol_conf.nr_events = nr_attrs; 2832 symbol_conf.nr_events = nr_attrs;
2836 2833
2837 perf_header__process_sections(header, fd, &session->pevent, 2834 perf_header__process_sections(header, fd, &session->tevent,
2838 perf_file_section__process); 2835 perf_file_section__process);
2839 2836
2840 if (perf_evlist__prepare_tracepoint_events(session->evlist, 2837 if (perf_evlist__prepare_tracepoint_events(session->evlist,
2841 session->pevent)) 2838 session->tevent.pevent))
2842 goto out_delete_evlist; 2839 goto out_delete_evlist;
2843 2840
2844 return 0; 2841 return 0;
@@ -2892,7 +2889,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
2892 struct perf_evsel *evsel; 2889 struct perf_evsel *evsel;
2893 int err = 0; 2890 int err = 0;
2894 2891
2895 list_for_each_entry(evsel, &session->evlist->entries, node) { 2892 evlist__for_each(session->evlist, evsel) {
2896 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, 2893 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
2897 evsel->id, process); 2894 evsel->id, process);
2898 if (err) { 2895 if (err) {
@@ -3003,7 +3000,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
3003 lseek(fd, offset + sizeof(struct tracing_data_event), 3000 lseek(fd, offset + sizeof(struct tracing_data_event),
3004 SEEK_SET); 3001 SEEK_SET);
3005 3002
3006 size_read = trace_report(fd, &session->pevent, 3003 size_read = trace_report(fd, &session->tevent,
3007 session->repipe); 3004 session->repipe);
3008 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3005 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
3009 3006
@@ -3025,7 +3022,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
3025 } 3022 }
3026 3023
3027 perf_evlist__prepare_tracepoint_events(session->evlist, 3024 perf_evlist__prepare_tracepoint_events(session->evlist,
3028 session->pevent); 3025 session->tevent.pevent);
3029 3026
3030 return size_read + padding; 3027 return size_read + padding;
3031} 3028}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 307c9aed972e..a2d047bdf4ef 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -77,16 +77,16 @@ struct perf_session_env {
77 unsigned long long total_mem; 77 unsigned long long total_mem;
78 78
79 int nr_cmdline; 79 int nr_cmdline;
80 char *cmdline;
81 int nr_sibling_cores; 80 int nr_sibling_cores;
82 char *sibling_cores;
83 int nr_sibling_threads; 81 int nr_sibling_threads;
84 char *sibling_threads;
85 int nr_numa_nodes; 82 int nr_numa_nodes;
86 char *numa_nodes;
87 int nr_pmu_mappings; 83 int nr_pmu_mappings;
88 char *pmu_mappings;
89 int nr_groups; 84 int nr_groups;
85 char *cmdline;
86 char *sibling_cores;
87 char *sibling_threads;
88 char *numa_nodes;
89 char *pmu_mappings;
90}; 90};
91 91
92struct perf_header { 92struct perf_header {
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 8b1f6e891b8a..86c37c472263 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -22,8 +22,8 @@ static void clean_cmdnames(struct cmdnames *cmds)
22 unsigned int i; 22 unsigned int i;
23 23
24 for (i = 0; i < cmds->cnt; ++i) 24 for (i = 0; i < cmds->cnt; ++i)
25 free(cmds->names[i]); 25 zfree(&cmds->names[i]);
26 free(cmds->names); 26 zfree(&cmds->names);
27 cmds->cnt = 0; 27 cmds->cnt = 0;
28 cmds->alloc = 0; 28 cmds->alloc = 0;
29} 29}
@@ -263,9 +263,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
263 263
264 for (i = 0; i < old->cnt; i++) 264 for (i = 0; i < old->cnt; i++)
265 cmds->names[cmds->cnt++] = old->names[i]; 265 cmds->names[cmds->cnt++] = old->names[i];
266 free(old->names); 266 zfree(&old->names);
267 old->cnt = 0; 267 old->cnt = 0;
268 old->names = NULL;
269} 268}
270 269
271const char *help_unknown_cmd(const char *cmd) 270const char *help_unknown_cmd(const char *cmd)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 822903eaa201..4ed3e883240d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,4 +1,3 @@
1#include "annotate.h"
2#include "util.h" 1#include "util.h"
3#include "build-id.h" 2#include "build-id.h"
4#include "hist.h" 3#include "hist.h"
@@ -342,15 +341,15 @@ static u8 symbol__parent_filter(const struct symbol *parent)
342} 341}
343 342
344static struct hist_entry *add_hist_entry(struct hists *hists, 343static struct hist_entry *add_hist_entry(struct hists *hists,
345 struct hist_entry *entry, 344 struct hist_entry *entry,
346 struct addr_location *al, 345 struct addr_location *al)
347 u64 period,
348 u64 weight)
349{ 346{
350 struct rb_node **p; 347 struct rb_node **p;
351 struct rb_node *parent = NULL; 348 struct rb_node *parent = NULL;
352 struct hist_entry *he; 349 struct hist_entry *he;
353 int64_t cmp; 350 int64_t cmp;
351 u64 period = entry->stat.period;
352 u64 weight = entry->stat.weight;
354 353
355 p = &hists->entries_in->rb_node; 354 p = &hists->entries_in->rb_node;
356 355
@@ -373,7 +372,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
373 * This mem info was allocated from machine__resolve_mem 372 * This mem info was allocated from machine__resolve_mem
374 * and will not be used anymore. 373 * and will not be used anymore.
375 */ 374 */
376 free(entry->mem_info); 375 zfree(&entry->mem_info);
377 376
378 /* If the map of an existing hist_entry has 377 /* If the map of an existing hist_entry has
379 * become out-of-date due to an exec() or 378 * become out-of-date due to an exec() or
@@ -437,7 +436,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
437 .transaction = transaction, 436 .transaction = transaction,
438 }; 437 };
439 438
440 return add_hist_entry(hists, &entry, al, period, weight); 439 return add_hist_entry(hists, &entry, al);
441} 440}
442 441
443int64_t 442int64_t
@@ -476,8 +475,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
476 475
477void hist_entry__free(struct hist_entry *he) 476void hist_entry__free(struct hist_entry *he)
478{ 477{
479 free(he->branch_info); 478 zfree(&he->branch_info);
480 free(he->mem_info); 479 zfree(&he->mem_info);
481 free_srcline(he->srcline); 480 free_srcline(he->srcline);
482 free(he); 481 free(he);
483} 482}
@@ -807,16 +806,6 @@ void hists__filter_by_symbol(struct hists *hists)
807 } 806 }
808} 807}
809 808
810int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
811{
812 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
813}
814
815int hist_entry__annotate(struct hist_entry *he, size_t privsize)
816{
817 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
818}
819
820void events_stats__inc(struct events_stats *stats, u32 type) 809void events_stats__inc(struct events_stats *stats, u32 type)
821{ 810{
822 ++stats->nr_events[0]; 811 ++stats->nr_events[0];
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b621347a1585..a59743fa3ef7 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -111,9 +111,6 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
112 int max_cols, float min_pcnt, FILE *fp); 112 int max_cols, float min_pcnt, FILE *fp);
113 113
114int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
115int hist_entry__annotate(struct hist_entry *he, size_t privsize);
116
117void hists__filter_by_dso(struct hists *hists); 114void hists__filter_by_dso(struct hists *hists);
118void hists__filter_by_thread(struct hists *hists); 115void hists__filter_by_thread(struct hists *hists);
119void hists__filter_by_symbol(struct hists *hists); 116void hists__filter_by_symbol(struct hists *hists);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 84cdb072ac83..0130279aac51 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -9,6 +9,7 @@
9#include "strlist.h" 9#include "strlist.h"
10#include "thread.h" 10#include "thread.h"
11#include <stdbool.h> 11#include <stdbool.h>
12#include <symbol/kallsyms.h>
12#include "unwind.h" 13#include "unwind.h"
13 14
14int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 15int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
@@ -26,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
26 machine->pid = pid; 27 machine->pid = pid;
27 28
28 machine->symbol_filter = NULL; 29 machine->symbol_filter = NULL;
30 machine->id_hdr_size = 0;
29 31
30 machine->root_dir = strdup(root_dir); 32 machine->root_dir = strdup(root_dir);
31 if (machine->root_dir == NULL) 33 if (machine->root_dir == NULL)
@@ -101,8 +103,7 @@ void machine__exit(struct machine *machine)
101 map_groups__exit(&machine->kmaps); 103 map_groups__exit(&machine->kmaps);
102 dsos__delete(&machine->user_dsos); 104 dsos__delete(&machine->user_dsos);
103 dsos__delete(&machine->kernel_dsos); 105 dsos__delete(&machine->kernel_dsos);
104 free(machine->root_dir); 106 zfree(&machine->root_dir);
105 machine->root_dir = NULL;
106} 107}
107 108
108void machine__delete(struct machine *machine) 109void machine__delete(struct machine *machine)
@@ -502,15 +503,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
502 char path[PATH_MAX]; 503 char path[PATH_MAX];
503 struct process_args args; 504 struct process_args args;
504 505
505 if (machine__is_host(machine)) { 506 if (machine__is_default_guest(machine))
506 filename = "/proc/kallsyms"; 507 filename = (char *)symbol_conf.default_guest_kallsyms;
507 } else { 508 else {
508 if (machine__is_default_guest(machine)) 509 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
509 filename = (char *)symbol_conf.default_guest_kallsyms; 510 filename = path;
510 else {
511 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
512 filename = path;
513 }
514 } 511 }
515 512
516 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 513 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
@@ -565,11 +562,10 @@ void machine__destroy_kernel_maps(struct machine *machine)
565 * on one of them. 562 * on one of them.
566 */ 563 */
567 if (type == MAP__FUNCTION) { 564 if (type == MAP__FUNCTION) {
568 free((char *)kmap->ref_reloc_sym->name); 565 zfree((char **)&kmap->ref_reloc_sym->name);
569 kmap->ref_reloc_sym->name = NULL; 566 zfree(&kmap->ref_reloc_sym);
570 free(kmap->ref_reloc_sym); 567 } else
571 } 568 kmap->ref_reloc_sym = NULL;
572 kmap->ref_reloc_sym = NULL;
573 } 569 }
574 570
575 map__delete(machine->vmlinux_maps[type]); 571 map__delete(machine->vmlinux_maps[type]);
@@ -767,8 +763,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
767 ret = -1; 763 ret = -1;
768 goto out; 764 goto out;
769 } 765 }
770 dso__set_long_name(map->dso, long_name); 766 dso__set_long_name(map->dso, long_name, true);
771 map->dso->lname_alloc = 1;
772 dso__kernel_module_get_build_id(map->dso, ""); 767 dso__kernel_module_get_build_id(map->dso, "");
773 } 768 }
774 } 769 }
@@ -939,8 +934,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
939 if (name == NULL) 934 if (name == NULL)
940 goto out_problem; 935 goto out_problem;
941 936
942 map->dso->short_name = name; 937 dso__set_short_name(map->dso, name, true);
943 map->dso->sname_alloc = 1;
944 map->end = map->start + event->mmap.len; 938 map->end = map->start + event->mmap.len;
945 } else if (is_kernel_mmap) { 939 } else if (is_kernel_mmap) {
946 const char *symbol_name = (event->mmap.filename + 940 const char *symbol_name = (event->mmap.filename +
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index ef5bc913ca7a..9b9bd719aa19 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include "util.h"
14#include <linux/string.h> 15#include <linux/string.h>
15 16
16const char *map_type__name[MAP__NR_TYPES] = { 17const char *map_type__name[MAP__NR_TYPES] = {
@@ -252,6 +253,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
252 return fprintf(fp, "%s", dsoname); 253 return fprintf(fp, "%s", dsoname);
253} 254}
254 255
256int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
257 FILE *fp)
258{
259 char *srcline;
260 int ret = 0;
261
262 if (map && map->dso) {
263 srcline = get_srcline(map->dso,
264 map__rip_2objdump(map, addr));
265 if (srcline != SRCLINE_UNKNOWN)
266 ret = fprintf(fp, "%s%s", prefix, srcline);
267 free_srcline(srcline);
268 }
269 return ret;
270}
271
255/** 272/**
256 * map__rip_2objdump - convert symbol start address to objdump address. 273 * map__rip_2objdump - convert symbol start address to objdump address.
257 * @map: memory map 274 * @map: memory map
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index e4e259c3ba16..18068c6b71c1 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -103,6 +103,8 @@ struct map *map__clone(struct map *map);
103int map__overlap(struct map *l, struct map *r); 103int map__overlap(struct map *l, struct map *r);
104size_t map__fprintf(struct map *map, FILE *fp); 104size_t map__fprintf(struct map *map, FILE *fp);
105size_t map__fprintf_dsoname(struct map *map, FILE *fp); 105size_t map__fprintf_dsoname(struct map *map, FILE *fp);
106int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
107 FILE *fp);
106 108
107int map__load(struct map *map, symbol_filter_t filter); 109int map__load(struct map *map, symbol_filter_t filter);
108struct symbol *map__find_symbol(struct map *map, 110struct symbol *map__find_symbol(struct map *map,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6de6f89c2a61..a7f1b6a91fdd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,7 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include <lk/debugfs.h> 13#include <api/fs/debugfs.h>
14#include "parse-events-bison.h" 14#include "parse-events-bison.h"
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
@@ -204,7 +204,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
204 } 204 }
205 path->name = malloc(MAX_EVENT_LENGTH); 205 path->name = malloc(MAX_EVENT_LENGTH);
206 if (!path->name) { 206 if (!path->name) {
207 free(path->system); 207 zfree(&path->system);
208 free(path); 208 free(path);
209 return NULL; 209 return NULL;
210 } 210 }
@@ -236,8 +236,8 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name)
236 path->name = strdup(str+1); 236 path->name = strdup(str+1);
237 237
238 if (path->system == NULL || path->name == NULL) { 238 if (path->system == NULL || path->name == NULL) {
239 free(path->system); 239 zfree(&path->system);
240 free(path->name); 240 zfree(&path->name);
241 free(path); 241 free(path);
242 path = NULL; 242 path = NULL;
243 } 243 }
@@ -269,9 +269,10 @@ const char *event_type(int type)
269 269
270 270
271 271
272static int __add_event(struct list_head *list, int *idx, 272static struct perf_evsel *
273 struct perf_event_attr *attr, 273__add_event(struct list_head *list, int *idx,
274 char *name, struct cpu_map *cpus) 274 struct perf_event_attr *attr,
275 char *name, struct cpu_map *cpus)
275{ 276{
276 struct perf_evsel *evsel; 277 struct perf_evsel *evsel;
277 278
@@ -279,19 +280,19 @@ static int __add_event(struct list_head *list, int *idx,
279 280
280 evsel = perf_evsel__new_idx(attr, (*idx)++); 281 evsel = perf_evsel__new_idx(attr, (*idx)++);
281 if (!evsel) 282 if (!evsel)
282 return -ENOMEM; 283 return NULL;
283 284
284 evsel->cpus = cpus; 285 evsel->cpus = cpus;
285 if (name) 286 if (name)
286 evsel->name = strdup(name); 287 evsel->name = strdup(name);
287 list_add_tail(&evsel->node, list); 288 list_add_tail(&evsel->node, list);
288 return 0; 289 return evsel;
289} 290}
290 291
291static int add_event(struct list_head *list, int *idx, 292static int add_event(struct list_head *list, int *idx,
292 struct perf_event_attr *attr, char *name) 293 struct perf_event_attr *attr, char *name)
293{ 294{
294 return __add_event(list, idx, attr, name, NULL); 295 return __add_event(list, idx, attr, name, NULL) ? 0 : -ENOMEM;
295} 296}
296 297
297static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 298static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -633,6 +634,9 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
633{ 634{
634 struct perf_event_attr attr; 635 struct perf_event_attr attr;
635 struct perf_pmu *pmu; 636 struct perf_pmu *pmu;
637 struct perf_evsel *evsel;
638 char *unit;
639 double scale;
636 640
637 pmu = perf_pmu__find(name); 641 pmu = perf_pmu__find(name);
638 if (!pmu) 642 if (!pmu)
@@ -640,7 +644,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
640 644
641 memset(&attr, 0, sizeof(attr)); 645 memset(&attr, 0, sizeof(attr));
642 646
643 if (perf_pmu__check_alias(pmu, head_config)) 647 if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
644 return -EINVAL; 648 return -EINVAL;
645 649
646 /* 650 /*
@@ -652,8 +656,14 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
652 if (perf_pmu__config(pmu, &attr, head_config)) 656 if (perf_pmu__config(pmu, &attr, head_config))
653 return -EINVAL; 657 return -EINVAL;
654 658
655 return __add_event(list, idx, &attr, pmu_event_name(head_config), 659 evsel = __add_event(list, idx, &attr, pmu_event_name(head_config),
656 pmu->cpus); 660 pmu->cpus);
661 if (evsel) {
662 evsel->unit = unit;
663 evsel->scale = scale;
664 }
665
666 return evsel ? 0 : -ENOMEM;
657} 667}
658 668
659int parse_events__modifier_group(struct list_head *list, 669int parse_events__modifier_group(struct list_head *list,
@@ -810,8 +820,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
810 if (!add && get_event_modifier(&mod, str, NULL)) 820 if (!add && get_event_modifier(&mod, str, NULL))
811 return -EINVAL; 821 return -EINVAL;
812 822
813 list_for_each_entry(evsel, list, node) { 823 __evlist__for_each(list, evsel) {
814
815 if (add && get_event_modifier(&mod, str, evsel)) 824 if (add && get_event_modifier(&mod, str, evsel))
816 return -EINVAL; 825 return -EINVAL;
817 826
@@ -835,7 +844,7 @@ int parse_events_name(struct list_head *list, char *name)
835{ 844{
836 struct perf_evsel *evsel; 845 struct perf_evsel *evsel;
837 846
838 list_for_each_entry(evsel, list, node) { 847 __evlist__for_each(list, evsel) {
839 if (!evsel->name) 848 if (!evsel->name)
840 evsel->name = strdup(name); 849 evsel->name = strdup(name);
841 } 850 }
@@ -907,7 +916,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
907 ret = parse_events__scanner(str, &data, PE_START_TERMS); 916 ret = parse_events__scanner(str, &data, PE_START_TERMS);
908 if (!ret) { 917 if (!ret) {
909 list_splice(data.terms, terms); 918 list_splice(data.terms, terms);
910 free(data.terms); 919 zfree(&data.terms);
911 return 0; 920 return 0;
912 } 921 }
913 922
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 31f404a032a9..d22e3f8017dc 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -78,6 +78,8 @@ static int get_value(struct parse_opt_ctx_t *p,
78 78
79 case OPTION_BOOLEAN: 79 case OPTION_BOOLEAN:
80 *(bool *)opt->value = unset ? false : true; 80 *(bool *)opt->value = unset ? false : true;
81 if (opt->set)
82 *(bool *)opt->set = true;
81 return 0; 83 return 0;
82 84
83 case OPTION_INCR: 85 case OPTION_INCR:
@@ -224,6 +226,24 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
224 return 0; 226 return 0;
225 } 227 }
226 if (!rest) { 228 if (!rest) {
229 if (!prefixcmp(options->long_name, "no-")) {
230 /*
231 * The long name itself starts with "no-", so
232 * accept the option without "no-" so that users
233 * do not have to enter "no-no-" to get the
234 * negation.
235 */
236 rest = skip_prefix(arg, options->long_name + 3);
237 if (rest) {
238 flags |= OPT_UNSET;
239 goto match;
240 }
241 /* Abbreviated case */
242 if (!prefixcmp(options->long_name + 3, arg)) {
243 flags |= OPT_UNSET;
244 goto is_abbreviated;
245 }
246 }
227 /* abbreviated? */ 247 /* abbreviated? */
228 if (!strncmp(options->long_name, arg, arg_end - arg)) { 248 if (!strncmp(options->long_name, arg, arg_end - arg)) {
229is_abbreviated: 249is_abbreviated:
@@ -259,6 +279,7 @@ is_abbreviated:
259 if (!rest) 279 if (!rest)
260 continue; 280 continue;
261 } 281 }
282match:
262 if (*rest) { 283 if (*rest) {
263 if (*rest != '=') 284 if (*rest != '=')
264 continue; 285 continue;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index b0241e28eaf7..cbf0149cf221 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -82,6 +82,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in 82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
83 * the value when met. 83 * the value when met.
84 * CALLBACKS can use it like they want. 84 * CALLBACKS can use it like they want.
85 *
86 * `set`::
87 * whether an option was set by the user
85 */ 88 */
86struct option { 89struct option {
87 enum parse_opt_type type; 90 enum parse_opt_type type;
@@ -94,6 +97,7 @@ struct option {
94 int flags; 97 int flags;
95 parse_opt_cb *callback; 98 parse_opt_cb *callback;
96 intptr_t defval; 99 intptr_t defval;
100 bool *set;
97}; 101};
98 102
99#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) 103#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -103,6 +107,10 @@ struct option {
103#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } 107#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
104#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } 108#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
105#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } 109#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
110#define OPT_BOOLEAN_SET(s, l, v, os, h) \
111 { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
112 .value = check_vtype(v, bool *), .help = (h), \
113 .set = check_vtype(os, bool *)}
106#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } 114#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
107#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } 115#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
108#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } 116#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index c232d8dd410b..d9cab4d27192 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,19 +1,23 @@
1#include <linux/list.h> 1#include <linux/list.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h>
4#include <unistd.h> 3#include <unistd.h>
5#include <stdio.h> 4#include <stdio.h>
6#include <dirent.h> 5#include <dirent.h>
7#include "fs.h" 6#include "fs.h"
7#include <locale.h>
8#include "util.h" 8#include "util.h"
9#include "pmu.h" 9#include "pmu.h"
10#include "parse-events.h" 10#include "parse-events.h"
11#include "cpumap.h" 11#include "cpumap.h"
12 12
13#define UNIT_MAX_LEN 31 /* max length for event unit name */
14
13struct perf_pmu_alias { 15struct perf_pmu_alias {
14 char *name; 16 char *name;
15 struct list_head terms; 17 struct list_head terms;
16 struct list_head list; 18 struct list_head list;
19 char unit[UNIT_MAX_LEN+1];
20 double scale;
17}; 21};
18 22
19struct perf_pmu_format { 23struct perf_pmu_format {
@@ -94,7 +98,80 @@ static int pmu_format(const char *name, struct list_head *format)
94 return 0; 98 return 0;
95} 99}
96 100
97static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 101static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
102{
103 struct stat st;
104 ssize_t sret;
105 char scale[128];
106 int fd, ret = -1;
107 char path[PATH_MAX];
108 char *lc;
109
110 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
111
112 fd = open(path, O_RDONLY);
113 if (fd == -1)
114 return -1;
115
116 if (fstat(fd, &st) < 0)
117 goto error;
118
119 sret = read(fd, scale, sizeof(scale)-1);
120 if (sret < 0)
121 goto error;
122
123 scale[sret] = '\0';
124 /*
125 * save current locale
126 */
127 lc = setlocale(LC_NUMERIC, NULL);
128
129 /*
130 * force to C locale to ensure kernel
131 * scale string is converted correctly.
132 * kernel uses default C locale.
133 */
134 setlocale(LC_NUMERIC, "C");
135
136 alias->scale = strtod(scale, NULL);
137
138 /* restore locale */
139 setlocale(LC_NUMERIC, lc);
140
141 ret = 0;
142error:
143 close(fd);
144 return ret;
145}
146
147static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
148{
149 char path[PATH_MAX];
150 ssize_t sret;
151 int fd;
152
153 snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
154
155 fd = open(path, O_RDONLY);
156 if (fd == -1)
157 return -1;
158
159 sret = read(fd, alias->unit, UNIT_MAX_LEN);
160 if (sret < 0)
161 goto error;
162
163 close(fd);
164
165 alias->unit[sret] = '\0';
166
167 return 0;
168error:
169 close(fd);
170 alias->unit[0] = '\0';
171 return -1;
172}
173
174static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
98{ 175{
99 struct perf_pmu_alias *alias; 176 struct perf_pmu_alias *alias;
100 char buf[256]; 177 char buf[256];
@@ -110,6 +187,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
110 return -ENOMEM; 187 return -ENOMEM;
111 188
112 INIT_LIST_HEAD(&alias->terms); 189 INIT_LIST_HEAD(&alias->terms);
190 alias->scale = 1.0;
191 alias->unit[0] = '\0';
192
113 ret = parse_events_terms(&alias->terms, buf); 193 ret = parse_events_terms(&alias->terms, buf);
114 if (ret) { 194 if (ret) {
115 free(alias); 195 free(alias);
@@ -117,7 +197,14 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
117 } 197 }
118 198
119 alias->name = strdup(name); 199 alias->name = strdup(name);
200 /*
201 * load unit name and scale if available
202 */
203 perf_pmu__parse_unit(alias, dir, name);
204 perf_pmu__parse_scale(alias, dir, name);
205
120 list_add_tail(&alias->list, list); 206 list_add_tail(&alias->list, list);
207
121 return 0; 208 return 0;
122} 209}
123 210
@@ -129,6 +216,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
129{ 216{
130 struct dirent *evt_ent; 217 struct dirent *evt_ent;
131 DIR *event_dir; 218 DIR *event_dir;
219 size_t len;
132 int ret = 0; 220 int ret = 0;
133 221
134 event_dir = opendir(dir); 222 event_dir = opendir(dir);
@@ -143,13 +231,24 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
143 if (!strcmp(name, ".") || !strcmp(name, "..")) 231 if (!strcmp(name, ".") || !strcmp(name, ".."))
144 continue; 232 continue;
145 233
234 /*
235 * skip .unit and .scale info files
236 * parsed in perf_pmu__new_alias()
237 */
238 len = strlen(name);
239 if (len > 5 && !strcmp(name + len - 5, ".unit"))
240 continue;
241 if (len > 6 && !strcmp(name + len - 6, ".scale"))
242 continue;
243
146 snprintf(path, PATH_MAX, "%s/%s", dir, name); 244 snprintf(path, PATH_MAX, "%s/%s", dir, name);
147 245
148 ret = -EINVAL; 246 ret = -EINVAL;
149 file = fopen(path, "r"); 247 file = fopen(path, "r");
150 if (!file) 248 if (!file)
151 break; 249 break;
152 ret = perf_pmu__new_alias(head, name, file); 250
251 ret = perf_pmu__new_alias(head, dir, name, file);
153 fclose(file); 252 fclose(file);
154 } 253 }
155 254
@@ -406,7 +505,7 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
406 505
407/* 506/*
408 * Setup one of config[12] attr members based on the 507 * Setup one of config[12] attr members based on the
409 * user input data - temr parameter. 508 * user input data - term parameter.
410 */ 509 */
411static int pmu_config_term(struct list_head *formats, 510static int pmu_config_term(struct list_head *formats,
412 struct perf_event_attr *attr, 511 struct perf_event_attr *attr,
@@ -508,16 +607,42 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
508 return NULL; 607 return NULL;
509} 608}
510 609
610
611static int check_unit_scale(struct perf_pmu_alias *alias,
612 char **unit, double *scale)
613{
614 /*
615 * Only one term in event definition can
616 * define unit and scale, fail if there's
617 * more than one.
618 */
619 if ((*unit && alias->unit) ||
620 (*scale && alias->scale))
621 return -EINVAL;
622
623 if (alias->unit)
624 *unit = alias->unit;
625
626 if (alias->scale)
627 *scale = alias->scale;
628
629 return 0;
630}
631
511/* 632/*
512 * Find alias in the terms list and replace it with the terms 633 * Find alias in the terms list and replace it with the terms
513 * defined for the alias 634 * defined for the alias
514 */ 635 */
515int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 636int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
637 char **unit, double *scale)
516{ 638{
517 struct parse_events_term *term, *h; 639 struct parse_events_term *term, *h;
518 struct perf_pmu_alias *alias; 640 struct perf_pmu_alias *alias;
519 int ret; 641 int ret;
520 642
643 *unit = NULL;
644 *scale = 0;
645
521 list_for_each_entry_safe(term, h, head_terms, list) { 646 list_for_each_entry_safe(term, h, head_terms, list) {
522 alias = pmu_find_alias(pmu, term); 647 alias = pmu_find_alias(pmu, term);
523 if (!alias) 648 if (!alias)
@@ -525,6 +650,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
525 ret = pmu_alias_terms(alias, &term->list); 650 ret = pmu_alias_terms(alias, &term->list);
526 if (ret) 651 if (ret)
527 return ret; 652 return ret;
653
654 ret = check_unit_scale(alias, unit, scale);
655 if (ret)
656 return ret;
657
528 list_del(&term->list); 658 list_del(&term->list);
529 free(term); 659 free(term);
530 } 660 }
@@ -625,7 +755,7 @@ void print_pmu_events(const char *event_glob, bool name_only)
625 continue; 755 continue;
626 } 756 }
627 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 757 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
628 free(aliases[j]); 758 zfree(&aliases[j]);
629 printed++; 759 printed++;
630 } 760 }
631 if (printed) 761 if (printed)
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 1179b26f244a..9183380e2038 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -28,7 +28,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
28int perf_pmu__config_terms(struct list_head *formats, 28int perf_pmu__config_terms(struct list_head *formats,
29 struct perf_event_attr *attr, 29 struct perf_event_attr *attr,
30 struct list_head *head_terms); 30 struct list_head *head_terms);
31int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 31int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
32 char **unit, double *scale);
32struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 33struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
33 struct list_head *head_terms); 34 struct list_head *head_terms);
34int perf_pmu_wrap(void); 35int perf_pmu_wrap(void);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9c6989ca2bea..a4ee6b4a840f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,7 +40,7 @@
40#include "color.h" 40#include "color.h"
41#include "symbol.h" 41#include "symbol.h"
42#include "thread.h" 42#include "thread.h"
43#include <lk/debugfs.h> 43#include <api/fs/debugfs.h>
44#include "trace-event.h" /* For __maybe_unused */ 44#include "trace-event.h" /* For __maybe_unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
@@ -154,7 +154,7 @@ static struct dso *kernel_get_module_dso(const char *module)
154 154
155 vmlinux_name = symbol_conf.vmlinux_name; 155 vmlinux_name = symbol_conf.vmlinux_name;
156 if (vmlinux_name) { 156 if (vmlinux_name) {
157 if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) 157 if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
158 return NULL; 158 return NULL;
159 } else { 159 } else {
160 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 160 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
@@ -172,6 +172,54 @@ const char *kernel_get_module_path(const char *module)
172 return (dso) ? dso->long_name : NULL; 172 return (dso) ? dso->long_name : NULL;
173} 173}
174 174
175#ifdef HAVE_DWARF_SUPPORT
176/* Copied from unwind.c */
177static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
178 GElf_Shdr *shp, const char *name)
179{
180 Elf_Scn *sec = NULL;
181
182 while ((sec = elf_nextscn(elf, sec)) != NULL) {
183 char *str;
184
185 gelf_getshdr(sec, shp);
186 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
187 if (!strcmp(name, str))
188 break;
189 }
190
191 return sec;
192}
193
194static int get_text_start_address(const char *exec, unsigned long *address)
195{
196 Elf *elf;
197 GElf_Ehdr ehdr;
198 GElf_Shdr shdr;
199 int fd, ret = -ENOENT;
200
201 fd = open(exec, O_RDONLY);
202 if (fd < 0)
203 return -errno;
204
205 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
206 if (elf == NULL)
207 return -EINVAL;
208
209 if (gelf_getehdr(elf, &ehdr) == NULL)
210 goto out;
211
212 if (!elf_section_by_name(elf, &ehdr, &shdr, ".text"))
213 goto out;
214
215 *address = shdr.sh_addr - shdr.sh_offset;
216 ret = 0;
217out:
218 elf_end(elf);
219 return ret;
220}
221#endif
222
175static int init_user_exec(void) 223static int init_user_exec(void)
176{ 224{
177 int ret = 0; 225 int ret = 0;
@@ -186,6 +234,37 @@ static int init_user_exec(void)
186 return ret; 234 return ret;
187} 235}
188 236
237static int convert_exec_to_group(const char *exec, char **result)
238{
239 char *ptr1, *ptr2, *exec_copy;
240 char buf[64];
241 int ret;
242
243 exec_copy = strdup(exec);
244 if (!exec_copy)
245 return -ENOMEM;
246
247 ptr1 = basename(exec_copy);
248 if (!ptr1) {
249 ret = -EINVAL;
250 goto out;
251 }
252
253 ptr2 = strpbrk(ptr1, "-._");
254 if (ptr2)
255 *ptr2 = '\0';
256 ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
257 if (ret < 0)
258 goto out;
259
260 *result = strdup(buf);
261 ret = *result ? 0 : -ENOMEM;
262
263out:
264 free(exec_copy);
265 return ret;
266}
267
189static int convert_to_perf_probe_point(struct probe_trace_point *tp, 268static int convert_to_perf_probe_point(struct probe_trace_point *tp,
190 struct perf_probe_point *pp) 269 struct perf_probe_point *pp)
191{ 270{
@@ -261,6 +340,40 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
261 return 0; 340 return 0;
262} 341}
263 342
343static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
344 int ntevs, const char *exec)
345{
346 int i, ret = 0;
347 unsigned long offset, stext = 0;
348 char buf[32];
349
350 if (!exec)
351 return 0;
352
353 ret = get_text_start_address(exec, &stext);
354 if (ret < 0)
355 return ret;
356
357 for (i = 0; i < ntevs && ret >= 0; i++) {
358 offset = tevs[i].point.address - stext;
359 offset += tevs[i].point.offset;
360 tevs[i].point.offset = 0;
361 zfree(&tevs[i].point.symbol);
362 ret = e_snprintf(buf, 32, "0x%lx", offset);
363 if (ret < 0)
364 break;
365 tevs[i].point.module = strdup(exec);
366 tevs[i].point.symbol = strdup(buf);
367 if (!tevs[i].point.symbol || !tevs[i].point.module) {
368 ret = -ENOMEM;
369 break;
370 }
371 tevs[i].uprobes = true;
372 }
373
374 return ret;
375}
376
264static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 377static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
265 int ntevs, const char *module) 378 int ntevs, const char *module)
266{ 379{
@@ -290,9 +403,7 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
290 } 403 }
291 } 404 }
292 405
293 if (tmp) 406 free(tmp);
294 free(tmp);
295
296 return ret; 407 return ret;
297} 408}
298 409
@@ -305,15 +416,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
305 struct debuginfo *dinfo; 416 struct debuginfo *dinfo;
306 int ntevs, ret = 0; 417 int ntevs, ret = 0;
307 418
308 if (pev->uprobes) {
309 if (need_dwarf) {
310 pr_warning("Debuginfo-analysis is not yet supported"
311 " with -x/--exec option.\n");
312 return -ENOSYS;
313 }
314 return convert_name_to_addr(pev, target);
315 }
316
317 dinfo = open_debuginfo(target); 419 dinfo = open_debuginfo(target);
318 420
319 if (!dinfo) { 421 if (!dinfo) {
@@ -332,9 +434,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
332 434
333 if (ntevs > 0) { /* Succeeded to find trace events */ 435 if (ntevs > 0) { /* Succeeded to find trace events */
334 pr_debug("find %d probe_trace_events.\n", ntevs); 436 pr_debug("find %d probe_trace_events.\n", ntevs);
335 if (target) 437 if (target) {
336 ret = add_module_to_probe_trace_events(*tevs, ntevs, 438 if (pev->uprobes)
337 target); 439 ret = add_exec_to_probe_trace_events(*tevs,
440 ntevs, target);
441 else
442 ret = add_module_to_probe_trace_events(*tevs,
443 ntevs, target);
444 }
338 return ret < 0 ? ret : ntevs; 445 return ret < 0 ? ret : ntevs;
339 } 446 }
340 447
@@ -401,15 +508,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
401 case EFAULT: 508 case EFAULT:
402 raw_path = strchr(++raw_path, '/'); 509 raw_path = strchr(++raw_path, '/');
403 if (!raw_path) { 510 if (!raw_path) {
404 free(*new_path); 511 zfree(new_path);
405 *new_path = NULL;
406 return -ENOENT; 512 return -ENOENT;
407 } 513 }
408 continue; 514 continue;
409 515
410 default: 516 default:
411 free(*new_path); 517 zfree(new_path);
412 *new_path = NULL;
413 return -errno; 518 return -errno;
414 } 519 }
415 } 520 }
@@ -580,7 +685,7 @@ static int show_available_vars_at(struct debuginfo *dinfo,
580 */ 685 */
581 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 686 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
582 vl->point.offset); 687 vl->point.offset);
583 free(vl->point.symbol); 688 zfree(&vl->point.symbol);
584 nvars = 0; 689 nvars = 0;
585 if (vl->vars) { 690 if (vl->vars) {
586 strlist__for_each(node, vl->vars) { 691 strlist__for_each(node, vl->vars) {
@@ -647,16 +752,14 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
647 752
648static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 753static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
649 struct probe_trace_event **tevs __maybe_unused, 754 struct probe_trace_event **tevs __maybe_unused,
650 int max_tevs __maybe_unused, const char *target) 755 int max_tevs __maybe_unused,
756 const char *target __maybe_unused)
651{ 757{
652 if (perf_probe_event_need_dwarf(pev)) { 758 if (perf_probe_event_need_dwarf(pev)) {
653 pr_warning("Debuginfo-analysis is not supported.\n"); 759 pr_warning("Debuginfo-analysis is not supported.\n");
654 return -ENOSYS; 760 return -ENOSYS;
655 } 761 }
656 762
657 if (pev->uprobes)
658 return convert_name_to_addr(pev, target);
659
660 return 0; 763 return 0;
661} 764}
662 765
@@ -1278,8 +1381,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1278error: 1381error:
1279 pr_debug("Failed to synthesize perf probe point: %s\n", 1382 pr_debug("Failed to synthesize perf probe point: %s\n",
1280 strerror(-ret)); 1383 strerror(-ret));
1281 if (buf) 1384 free(buf);
1282 free(buf);
1283 return NULL; 1385 return NULL;
1284} 1386}
1285 1387
@@ -1480,34 +1582,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
1480 struct perf_probe_arg_field *field, *next; 1582 struct perf_probe_arg_field *field, *next;
1481 int i; 1583 int i;
1482 1584
1483 if (pev->event) 1585 free(pev->event);
1484 free(pev->event); 1586 free(pev->group);
1485 if (pev->group) 1587 free(pp->file);
1486 free(pev->group); 1588 free(pp->function);
1487 if (pp->file) 1589 free(pp->lazy_line);
1488 free(pp->file); 1590
1489 if (pp->function)
1490 free(pp->function);
1491 if (pp->lazy_line)
1492 free(pp->lazy_line);
1493 for (i = 0; i < pev->nargs; i++) { 1591 for (i = 0; i < pev->nargs; i++) {
1494 if (pev->args[i].name) 1592 free(pev->args[i].name);
1495 free(pev->args[i].name); 1593 free(pev->args[i].var);
1496 if (pev->args[i].var) 1594 free(pev->args[i].type);
1497 free(pev->args[i].var);
1498 if (pev->args[i].type)
1499 free(pev->args[i].type);
1500 field = pev->args[i].field; 1595 field = pev->args[i].field;
1501 while (field) { 1596 while (field) {
1502 next = field->next; 1597 next = field->next;
1503 if (field->name) 1598 zfree(&field->name);
1504 free(field->name);
1505 free(field); 1599 free(field);
1506 field = next; 1600 field = next;
1507 } 1601 }
1508 } 1602 }
1509 if (pev->args) 1603 free(pev->args);
1510 free(pev->args);
1511 memset(pev, 0, sizeof(*pev)); 1604 memset(pev, 0, sizeof(*pev));
1512} 1605}
1513 1606
@@ -1516,21 +1609,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1516 struct probe_trace_arg_ref *ref, *next; 1609 struct probe_trace_arg_ref *ref, *next;
1517 int i; 1610 int i;
1518 1611
1519 if (tev->event) 1612 free(tev->event);
1520 free(tev->event); 1613 free(tev->group);
1521 if (tev->group) 1614 free(tev->point.symbol);
1522 free(tev->group); 1615 free(tev->point.module);
1523 if (tev->point.symbol)
1524 free(tev->point.symbol);
1525 if (tev->point.module)
1526 free(tev->point.module);
1527 for (i = 0; i < tev->nargs; i++) { 1616 for (i = 0; i < tev->nargs; i++) {
1528 if (tev->args[i].name) 1617 free(tev->args[i].name);
1529 free(tev->args[i].name); 1618 free(tev->args[i].value);
1530 if (tev->args[i].value) 1619 free(tev->args[i].type);
1531 free(tev->args[i].value);
1532 if (tev->args[i].type)
1533 free(tev->args[i].type);
1534 ref = tev->args[i].ref; 1620 ref = tev->args[i].ref;
1535 while (ref) { 1621 while (ref) {
1536 next = ref->next; 1622 next = ref->next;
@@ -1538,8 +1624,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1538 ref = next; 1624 ref = next;
1539 } 1625 }
1540 } 1626 }
1541 if (tev->args) 1627 free(tev->args);
1542 free(tev->args);
1543 memset(tev, 0, sizeof(*tev)); 1628 memset(tev, 0, sizeof(*tev));
1544} 1629}
1545 1630
@@ -1913,14 +1998,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1913 int max_tevs, const char *target) 1998 int max_tevs, const char *target)
1914{ 1999{
1915 struct symbol *sym; 2000 struct symbol *sym;
1916 int ret = 0, i; 2001 int ret, i;
1917 struct probe_trace_event *tev; 2002 struct probe_trace_event *tev;
1918 2003
2004 if (pev->uprobes && !pev->group) {
2005 /* Replace group name if not given */
2006 ret = convert_exec_to_group(target, &pev->group);
2007 if (ret != 0) {
2008 pr_warning("Failed to make a group name.\n");
2009 return ret;
2010 }
2011 }
2012
1919 /* Convert perf_probe_event with debuginfo */ 2013 /* Convert perf_probe_event with debuginfo */
1920 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2014 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
1921 if (ret != 0) 2015 if (ret != 0)
1922 return ret; /* Found in debuginfo or got an error */ 2016 return ret; /* Found in debuginfo or got an error */
1923 2017
2018 if (pev->uprobes) {
2019 ret = convert_name_to_addr(pev, target);
2020 if (ret < 0)
2021 return ret;
2022 }
2023
1924 /* Allocate trace event buffer */ 2024 /* Allocate trace event buffer */
1925 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 2025 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1926 if (tev == NULL) 2026 if (tev == NULL)
@@ -2056,7 +2156,7 @@ end:
2056 for (i = 0; i < npevs; i++) { 2156 for (i = 0; i < npevs; i++) {
2057 for (j = 0; j < pkgs[i].ntevs; j++) 2157 for (j = 0; j < pkgs[i].ntevs; j++)
2058 clear_probe_trace_event(&pkgs[i].tevs[j]); 2158 clear_probe_trace_event(&pkgs[i].tevs[j]);
2059 free(pkgs[i].tevs); 2159 zfree(&pkgs[i].tevs);
2060 } 2160 }
2061 free(pkgs); 2161 free(pkgs);
2062 2162
@@ -2281,7 +2381,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2281 struct perf_probe_point *pp = &pev->point; 2381 struct perf_probe_point *pp = &pev->point;
2282 struct symbol *sym; 2382 struct symbol *sym;
2283 struct map *map = NULL; 2383 struct map *map = NULL;
2284 char *function = NULL, *name = NULL; 2384 char *function = NULL;
2285 int ret = -EINVAL; 2385 int ret = -EINVAL;
2286 unsigned long long vaddr = 0; 2386 unsigned long long vaddr = 0;
2287 2387
@@ -2297,12 +2397,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2297 goto out; 2397 goto out;
2298 } 2398 }
2299 2399
2300 name = realpath(exec, NULL); 2400 map = dso__new_map(exec);
2301 if (!name) {
2302 pr_warning("Cannot find realpath for %s.\n", exec);
2303 goto out;
2304 }
2305 map = dso__new_map(name);
2306 if (!map) { 2401 if (!map) {
2307 pr_warning("Cannot find appropriate DSO for %s.\n", exec); 2402 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2308 goto out; 2403 goto out;
@@ -2367,7 +2462,5 @@ out:
2367 } 2462 }
2368 if (function) 2463 if (function)
2369 free(function); 2464 free(function);
2370 if (name)
2371 free(name);
2372 return ret; 2465 return ret;
2373} 2466}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f9f3de8b4220..d481c46e0796 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -12,6 +12,7 @@ struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
14 unsigned long offset; /* Offset from symbol */ 14 unsigned long offset; /* Offset from symbol */
15 unsigned long address; /* Actual address of the trace point */
15 bool retprobe; /* Return probe flag */ 16 bool retprobe; /* Return probe flag */
16}; 17};
17 18
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ffb657ffd327..061edb162b5b 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -226,10 +226,8 @@ struct debuginfo *debuginfo__new(const char *path)
226 if (!dbg) 226 if (!dbg)
227 return NULL; 227 return NULL;
228 228
229 if (debuginfo__init_offline_dwarf(dbg, path) < 0) { 229 if (debuginfo__init_offline_dwarf(dbg, path) < 0)
230 free(dbg); 230 zfree(&dbg);
231 dbg = NULL;
232 }
233 231
234 return dbg; 232 return dbg;
235} 233}
@@ -241,10 +239,8 @@ struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
241 if (!dbg) 239 if (!dbg)
242 return NULL; 240 return NULL;
243 241
244 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) { 242 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
245 free(dbg); 243 zfree(&dbg);
246 dbg = NULL;
247 }
248 244
249 return dbg; 245 return dbg;
250} 246}
@@ -729,6 +725,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
729 return -ENOENT; 725 return -ENOENT;
730 } 726 }
731 tp->offset = (unsigned long)(paddr - sym.st_value); 727 tp->offset = (unsigned long)(paddr - sym.st_value);
728 tp->address = (unsigned long)paddr;
732 tp->symbol = strdup(symbol); 729 tp->symbol = strdup(symbol);
733 if (!tp->symbol) 730 if (!tp->symbol)
734 return -ENOMEM; 731 return -ENOMEM;
@@ -1301,8 +1298,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1301 1298
1302 ret = debuginfo__find_probes(dbg, &tf.pf); 1299 ret = debuginfo__find_probes(dbg, &tf.pf);
1303 if (ret < 0) { 1300 if (ret < 0) {
1304 free(*tevs); 1301 zfree(tevs);
1305 *tevs = NULL;
1306 return ret; 1302 return ret;
1307 } 1303 }
1308 1304
@@ -1413,13 +1409,10 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1413 if (ret < 0) { 1409 if (ret < 0) {
1414 /* Free vlist for error */ 1410 /* Free vlist for error */
1415 while (af.nvls--) { 1411 while (af.nvls--) {
1416 if (af.vls[af.nvls].point.symbol) 1412 zfree(&af.vls[af.nvls].point.symbol);
1417 free(af.vls[af.nvls].point.symbol); 1413 strlist__delete(af.vls[af.nvls].vars);
1418 if (af.vls[af.nvls].vars)
1419 strlist__delete(af.vls[af.nvls].vars);
1420 } 1414 }
1421 free(af.vls); 1415 zfree(vls);
1422 *vls = NULL;
1423 return ret; 1416 return ret;
1424 } 1417 }
1425 1418
@@ -1523,10 +1516,7 @@ post:
1523 if (fname) { 1516 if (fname) {
1524 ppt->file = strdup(fname); 1517 ppt->file = strdup(fname);
1525 if (ppt->file == NULL) { 1518 if (ppt->file == NULL) {
1526 if (ppt->function) { 1519 zfree(&ppt->function);
1527 free(ppt->function);
1528 ppt->function = NULL;
1529 }
1530 ret = -ENOMEM; 1520 ret = -ENOMEM;
1531 goto end; 1521 goto end;
1532 } 1522 }
@@ -1580,8 +1570,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1580 else 1570 else
1581 ret = 0; /* Lines are not found */ 1571 ret = 0; /* Lines are not found */
1582 else { 1572 else {
1583 free(lf->lr->path); 1573 zfree(&lf->lr->path);
1584 lf->lr->path = NULL;
1585 } 1574 }
1586 return ret; 1575 return ret;
1587} 1576}
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 239036fb2b2c..595bfc73d2ed 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,4 +18,5 @@ util/cgroup.c
18util/rblist.c 18util/rblist.c
19util/strlist.c 19util/strlist.c
20util/fs.c 20util/fs.c
21util/trace-event.c
21../../lib/rbtree.c 22../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 4bf8ace7f511..122669c18ff4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -908,9 +908,10 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
908 if (i >= pevlist->evlist.nr_entries) 908 if (i >= pevlist->evlist.nr_entries)
909 return NULL; 909 return NULL;
910 910
911 list_for_each_entry(pos, &pevlist->evlist.entries, node) 911 evlist__for_each(&pevlist->evlist, pos) {
912 if (i-- == 0) 912 if (i-- == 0)
913 break; 913 break;
914 }
914 915
915 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); 916 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
916} 917}
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index c8845b107f60..373762501dad 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -74,8 +74,7 @@ bool perf_can_sample_identifier(void)
74 return perf_probe_api(perf_probe_sample_identifier); 74 return perf_probe_api(perf_probe_sample_identifier);
75} 75}
76 76
77void perf_evlist__config(struct perf_evlist *evlist, 77void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
78 struct perf_record_opts *opts)
79{ 78{
80 struct perf_evsel *evsel; 79 struct perf_evsel *evsel;
81 bool use_sample_identifier = false; 80 bool use_sample_identifier = false;
@@ -90,19 +89,19 @@ void perf_evlist__config(struct perf_evlist *evlist,
90 if (evlist->cpus->map[0] < 0) 89 if (evlist->cpus->map[0] < 0)
91 opts->no_inherit = true; 90 opts->no_inherit = true;
92 91
93 list_for_each_entry(evsel, &evlist->entries, node) 92 evlist__for_each(evlist, evsel)
94 perf_evsel__config(evsel, opts); 93 perf_evsel__config(evsel, opts);
95 94
96 if (evlist->nr_entries > 1) { 95 if (evlist->nr_entries > 1) {
97 struct perf_evsel *first = perf_evlist__first(evlist); 96 struct perf_evsel *first = perf_evlist__first(evlist);
98 97
99 list_for_each_entry(evsel, &evlist->entries, node) { 98 evlist__for_each(evlist, evsel) {
100 if (evsel->attr.sample_type == first->attr.sample_type) 99 if (evsel->attr.sample_type == first->attr.sample_type)
101 continue; 100 continue;
102 use_sample_identifier = perf_can_sample_identifier(); 101 use_sample_identifier = perf_can_sample_identifier();
103 break; 102 break;
104 } 103 }
105 list_for_each_entry(evsel, &evlist->entries, node) 104 evlist__for_each(evlist, evsel)
106 perf_evsel__set_sample_id(evsel, use_sample_identifier); 105 perf_evsel__set_sample_id(evsel, use_sample_identifier);
107 } 106 }
108 107
@@ -123,7 +122,7 @@ static int get_max_rate(unsigned int *rate)
123 return filename__read_int(path, (int *) rate); 122 return filename__read_int(path, (int *) rate);
124} 123}
125 124
126static int perf_record_opts__config_freq(struct perf_record_opts *opts) 125static int record_opts__config_freq(struct record_opts *opts)
127{ 126{
128 bool user_freq = opts->user_freq != UINT_MAX; 127 bool user_freq = opts->user_freq != UINT_MAX;
129 unsigned int max_rate; 128 unsigned int max_rate;
@@ -173,7 +172,44 @@ static int perf_record_opts__config_freq(struct perf_record_opts *opts)
173 return 0; 172 return 0;
174} 173}
175 174
176int perf_record_opts__config(struct perf_record_opts *opts) 175int record_opts__config(struct record_opts *opts)
177{ 176{
178 return perf_record_opts__config_freq(opts); 177 return record_opts__config_freq(opts);
178}
179
180bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
181{
182 struct perf_evlist *temp_evlist;
183 struct perf_evsel *evsel;
184 int err, fd, cpu;
185 bool ret = false;
186
187 temp_evlist = perf_evlist__new();
188 if (!temp_evlist)
189 return false;
190
191 err = parse_events(temp_evlist, str);
192 if (err)
193 goto out_delete;
194
195 evsel = perf_evlist__last(temp_evlist);
196
197 if (!evlist || cpu_map__empty(evlist->cpus)) {
198 struct cpu_map *cpus = cpu_map__new(NULL);
199
200 cpu = cpus ? cpus->map[0] : 0;
201 cpu_map__delete(cpus);
202 } else {
203 cpu = evlist->cpus->map[0];
204 }
205
206 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
207 if (fd >= 0) {
208 close(fd);
209 ret = true;
210 }
211
212out_delete:
213 perf_evlist__delete(temp_evlist);
214 return ret;
179} 215}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index d5e5969f6fea..e108207c5de0 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -194,8 +194,7 @@ static void define_event_symbols(struct event_format *event,
194 zero_flag_atom = 0; 194 zero_flag_atom = 0;
195 break; 195 break;
196 case PRINT_FIELD: 196 case PRINT_FIELD:
197 if (cur_field_name) 197 free(cur_field_name);
198 free(cur_field_name);
199 cur_field_name = strdup(args->field.name); 198 cur_field_name = strdup(args->field.name);
200 break; 199 break;
201 case PRINT_FLAGS: 200 case PRINT_FLAGS:
@@ -257,12 +256,9 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
257 return event; 256 return event;
258} 257}
259 258
260static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, 259static void perl_process_tracepoint(struct perf_sample *sample,
261 struct perf_sample *sample,
262 struct perf_evsel *evsel, 260 struct perf_evsel *evsel,
263 struct machine *machine __maybe_unused, 261 struct thread *thread)
264 struct thread *thread,
265 struct addr_location *al)
266{ 262{
267 struct format_field *field; 263 struct format_field *field;
268 static char handler[256]; 264 static char handler[256];
@@ -349,10 +345,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
349 345
350static void perl_process_event_generic(union perf_event *event, 346static void perl_process_event_generic(union perf_event *event,
351 struct perf_sample *sample, 347 struct perf_sample *sample,
352 struct perf_evsel *evsel, 348 struct perf_evsel *evsel)
353 struct machine *machine __maybe_unused,
354 struct thread *thread __maybe_unused,
355 struct addr_location *al __maybe_unused)
356{ 349{
357 dSP; 350 dSP;
358 351
@@ -377,12 +370,11 @@ static void perl_process_event_generic(union perf_event *event,
377static void perl_process_event(union perf_event *event, 370static void perl_process_event(union perf_event *event,
378 struct perf_sample *sample, 371 struct perf_sample *sample,
379 struct perf_evsel *evsel, 372 struct perf_evsel *evsel,
380 struct machine *machine,
381 struct thread *thread, 373 struct thread *thread,
382 struct addr_location *al) 374 struct addr_location *al __maybe_unused)
383{ 375{
384 perl_process_tracepoint(event, sample, evsel, machine, thread, al); 376 perl_process_tracepoint(sample, evsel, thread);
385 perl_process_event_generic(event, sample, evsel, machine, thread, al); 377 perl_process_event_generic(event, sample, evsel);
386} 378}
387 379
388static void run_start_sub(void) 380static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 53c20e7fd900..cd9774df3750 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -161,8 +161,7 @@ static void define_event_symbols(struct event_format *event,
161 zero_flag_atom = 0; 161 zero_flag_atom = 0;
162 break; 162 break;
163 case PRINT_FIELD: 163 case PRINT_FIELD:
164 if (cur_field_name) 164 free(cur_field_name);
165 free(cur_field_name);
166 cur_field_name = strdup(args->field.name); 165 cur_field_name = strdup(args->field.name);
167 break; 166 break;
168 case PRINT_FLAGS: 167 case PRINT_FLAGS:
@@ -231,13 +230,10 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
231 return event; 230 return event;
232} 231}
233 232
234static void python_process_tracepoint(union perf_event *perf_event 233static void python_process_tracepoint(struct perf_sample *sample,
235 __maybe_unused, 234 struct perf_evsel *evsel,
236 struct perf_sample *sample, 235 struct thread *thread,
237 struct perf_evsel *evsel, 236 struct addr_location *al)
238 struct machine *machine __maybe_unused,
239 struct thread *thread,
240 struct addr_location *al)
241{ 237{
242 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 238 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
243 static char handler_name[256]; 239 static char handler_name[256];
@@ -351,11 +347,8 @@ static void python_process_tracepoint(union perf_event *perf_event
351 Py_DECREF(t); 347 Py_DECREF(t);
352} 348}
353 349
354static void python_process_general_event(union perf_event *perf_event 350static void python_process_general_event(struct perf_sample *sample,
355 __maybe_unused,
356 struct perf_sample *sample,
357 struct perf_evsel *evsel, 351 struct perf_evsel *evsel,
358 struct machine *machine __maybe_unused,
359 struct thread *thread, 352 struct thread *thread,
360 struct addr_location *al) 353 struct addr_location *al)
361{ 354{
@@ -411,22 +404,19 @@ exit:
411 Py_DECREF(t); 404 Py_DECREF(t);
412} 405}
413 406
414static void python_process_event(union perf_event *perf_event, 407static void python_process_event(union perf_event *event __maybe_unused,
415 struct perf_sample *sample, 408 struct perf_sample *sample,
416 struct perf_evsel *evsel, 409 struct perf_evsel *evsel,
417 struct machine *machine,
418 struct thread *thread, 410 struct thread *thread,
419 struct addr_location *al) 411 struct addr_location *al)
420{ 412{
421 switch (evsel->attr.type) { 413 switch (evsel->attr.type) {
422 case PERF_TYPE_TRACEPOINT: 414 case PERF_TYPE_TRACEPOINT:
423 python_process_tracepoint(perf_event, sample, evsel, 415 python_process_tracepoint(sample, evsel, thread, al);
424 machine, thread, al);
425 break; 416 break;
426 /* Reserve for future process_hw/sw/raw APIs */ 417 /* Reserve for future process_hw/sw/raw APIs */
427 default: 418 default:
428 python_process_general_event(perf_event, sample, evsel, 419 python_process_general_event(sample, evsel, thread, al);
429 machine, thread, al);
430 } 420 }
431} 421}
432 422
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f36d24a02445..7acc03e8f3b2 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -132,18 +132,18 @@ static void perf_session__delete_threads(struct perf_session *session)
132 132
133static void perf_session_env__delete(struct perf_session_env *env) 133static void perf_session_env__delete(struct perf_session_env *env)
134{ 134{
135 free(env->hostname); 135 zfree(&env->hostname);
136 free(env->os_release); 136 zfree(&env->os_release);
137 free(env->version); 137 zfree(&env->version);
138 free(env->arch); 138 zfree(&env->arch);
139 free(env->cpu_desc); 139 zfree(&env->cpu_desc);
140 free(env->cpuid); 140 zfree(&env->cpuid);
141 141
142 free(env->cmdline); 142 zfree(&env->cmdline);
143 free(env->sibling_cores); 143 zfree(&env->sibling_cores);
144 free(env->sibling_threads); 144 zfree(&env->sibling_threads);
145 free(env->numa_nodes); 145 zfree(&env->numa_nodes);
146 free(env->pmu_mappings); 146 zfree(&env->pmu_mappings);
147} 147}
148 148
149void perf_session__delete(struct perf_session *session) 149void perf_session__delete(struct perf_session *session)
@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
247 } 247 }
248} 248}
249 249
250void mem_bswap_32(void *src, int byte_size)
251{
252 u32 *m = src;
253 while (byte_size > 0) {
254 *m = bswap_32(*m);
255 byte_size -= sizeof(u32);
256 ++m;
257 }
258}
259
260void mem_bswap_64(void *src, int byte_size)
261{
262 u64 *m = src;
263
264 while (byte_size > 0) {
265 *m = bswap_64(*m);
266 byte_size -= sizeof(u64);
267 ++m;
268 }
269}
270
271static void swap_sample_id_all(union perf_event *event, void *data) 250static void swap_sample_id_all(union perf_event *event, void *data)
272{ 251{
273 void *end = (void *) event + event->header.size; 252 void *end = (void *) event + event->header.size;
@@ -851,6 +830,7 @@ static struct machine *
851 struct perf_sample *sample) 830 struct perf_sample *sample)
852{ 831{
853 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 832 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
833 struct machine *machine;
854 834
855 if (perf_guest && 835 if (perf_guest &&
856 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || 836 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
@@ -863,7 +843,11 @@ static struct machine *
863 else 843 else
864 pid = sample->pid; 844 pid = sample->pid;
865 845
866 return perf_session__findnew_machine(session, pid); 846 machine = perf_session__find_machine(session, pid);
847 if (!machine)
848 machine = perf_session__findnew_machine(session,
849 DEFAULT_GUEST_KERNEL_ID);
850 return machine;
867 } 851 }
868 852
869 return &session->machines.host; 853 return &session->machines.host;
@@ -1158,7 +1142,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1158 void *buf = NULL; 1142 void *buf = NULL;
1159 int skip = 0; 1143 int skip = 0;
1160 u64 head; 1144 u64 head;
1161 int err; 1145 ssize_t err;
1162 void *p; 1146 void *p;
1163 1147
1164 perf_tool__fill_defaults(tool); 1148 perf_tool__fill_defaults(tool);
@@ -1400,7 +1384,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg)
1400{ 1384{
1401 struct perf_evsel *evsel; 1385 struct perf_evsel *evsel;
1402 1386
1403 list_for_each_entry(evsel, &session->evlist->entries, node) { 1387 evlist__for_each(session->evlist, evsel) {
1404 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) 1388 if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
1405 return true; 1389 return true;
1406 } 1390 }
@@ -1458,7 +1442,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1458 1442
1459 ret += events_stats__fprintf(&session->stats, fp); 1443 ret += events_stats__fprintf(&session->stats, fp);
1460 1444
1461 list_for_each_entry(pos, &session->evlist->entries, node) { 1445 evlist__for_each(session->evlist, pos) {
1462 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1446 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1463 ret += events_stats__fprintf(&pos->hists.stats, fp); 1447 ret += events_stats__fprintf(&pos->hists.stats, fp);
1464 } 1448 }
@@ -1480,35 +1464,30 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1480{ 1464{
1481 struct perf_evsel *pos; 1465 struct perf_evsel *pos;
1482 1466
1483 list_for_each_entry(pos, &session->evlist->entries, node) { 1467 evlist__for_each(session->evlist, pos) {
1484 if (pos->attr.type == type) 1468 if (pos->attr.type == type)
1485 return pos; 1469 return pos;
1486 } 1470 }
1487 return NULL; 1471 return NULL;
1488} 1472}
1489 1473
1490void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1474void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1491 struct perf_sample *sample, struct machine *machine, 1475 struct addr_location *al,
1492 unsigned int print_opts, unsigned int stack_depth) 1476 unsigned int print_opts, unsigned int stack_depth)
1493{ 1477{
1494 struct addr_location al;
1495 struct callchain_cursor_node *node; 1478 struct callchain_cursor_node *node;
1496 int print_ip = print_opts & PRINT_IP_OPT_IP; 1479 int print_ip = print_opts & PRINT_IP_OPT_IP;
1497 int print_sym = print_opts & PRINT_IP_OPT_SYM; 1480 int print_sym = print_opts & PRINT_IP_OPT_SYM;
1498 int print_dso = print_opts & PRINT_IP_OPT_DSO; 1481 int print_dso = print_opts & PRINT_IP_OPT_DSO;
1499 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; 1482 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
1500 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; 1483 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
1484 int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
1501 char s = print_oneline ? ' ' : '\t'; 1485 char s = print_oneline ? ' ' : '\t';
1502 1486
1503 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
1504 error("problem processing %d event, skipping it.\n",
1505 event->header.type);
1506 return;
1507 }
1508
1509 if (symbol_conf.use_callchain && sample->callchain) { 1487 if (symbol_conf.use_callchain && sample->callchain) {
1488 struct addr_location node_al;
1510 1489
1511 if (machine__resolve_callchain(machine, evsel, al.thread, 1490 if (machine__resolve_callchain(al->machine, evsel, al->thread,
1512 sample, NULL, NULL, 1491 sample, NULL, NULL,
1513 PERF_MAX_STACK_DEPTH) != 0) { 1492 PERF_MAX_STACK_DEPTH) != 0) {
1514 if (verbose) 1493 if (verbose)
@@ -1517,20 +1496,31 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1517 } 1496 }
1518 callchain_cursor_commit(&callchain_cursor); 1497 callchain_cursor_commit(&callchain_cursor);
1519 1498
1499 if (print_symoffset)
1500 node_al = *al;
1501
1520 while (stack_depth) { 1502 while (stack_depth) {
1503 u64 addr = 0;
1504
1521 node = callchain_cursor_current(&callchain_cursor); 1505 node = callchain_cursor_current(&callchain_cursor);
1522 if (!node) 1506 if (!node)
1523 break; 1507 break;
1524 1508
1509 if (node->sym && node->sym->ignore)
1510 goto next;
1511
1525 if (print_ip) 1512 if (print_ip)
1526 printf("%c%16" PRIx64, s, node->ip); 1513 printf("%c%16" PRIx64, s, node->ip);
1527 1514
1515 if (node->map)
1516 addr = node->map->map_ip(node->map, node->ip);
1517
1528 if (print_sym) { 1518 if (print_sym) {
1529 printf(" "); 1519 printf(" ");
1530 if (print_symoffset) { 1520 if (print_symoffset) {
1531 al.addr = node->ip; 1521 node_al.addr = addr;
1532 al.map = node->map; 1522 node_al.map = node->map;
1533 symbol__fprintf_symname_offs(node->sym, &al, stdout); 1523 symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
1534 } else 1524 } else
1535 symbol__fprintf_symname(node->sym, stdout); 1525 symbol__fprintf_symname(node->sym, stdout);
1536 } 1526 }
@@ -1541,32 +1531,42 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1541 printf(")"); 1531 printf(")");
1542 } 1532 }
1543 1533
1534 if (print_srcline)
1535 map__fprintf_srcline(node->map, addr, "\n ",
1536 stdout);
1537
1544 if (!print_oneline) 1538 if (!print_oneline)
1545 printf("\n"); 1539 printf("\n");
1546 1540
1547 callchain_cursor_advance(&callchain_cursor);
1548
1549 stack_depth--; 1541 stack_depth--;
1542next:
1543 callchain_cursor_advance(&callchain_cursor);
1550 } 1544 }
1551 1545
1552 } else { 1546 } else {
1547 if (al->sym && al->sym->ignore)
1548 return;
1549
1553 if (print_ip) 1550 if (print_ip)
1554 printf("%16" PRIx64, sample->ip); 1551 printf("%16" PRIx64, sample->ip);
1555 1552
1556 if (print_sym) { 1553 if (print_sym) {
1557 printf(" "); 1554 printf(" ");
1558 if (print_symoffset) 1555 if (print_symoffset)
1559 symbol__fprintf_symname_offs(al.sym, &al, 1556 symbol__fprintf_symname_offs(al->sym, al,
1560 stdout); 1557 stdout);
1561 else 1558 else
1562 symbol__fprintf_symname(al.sym, stdout); 1559 symbol__fprintf_symname(al->sym, stdout);
1563 } 1560 }
1564 1561
1565 if (print_dso) { 1562 if (print_dso) {
1566 printf(" ("); 1563 printf(" (");
1567 map__fprintf_dsoname(al.map, stdout); 1564 map__fprintf_dsoname(al->map, stdout);
1568 printf(")"); 1565 printf(")");
1569 } 1566 }
1567
1568 if (print_srcline)
1569 map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
1570 } 1570 }
1571} 1571}
1572 1572
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 50f640958f0f..3140f8ae6148 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "trace-event.h"
4#include "hist.h" 5#include "hist.h"
5#include "event.h" 6#include "event.h"
6#include "header.h" 7#include "header.h"
@@ -32,7 +33,7 @@ struct perf_session {
32 struct perf_header header; 33 struct perf_header header;
33 struct machines machines; 34 struct machines machines;
34 struct perf_evlist *evlist; 35 struct perf_evlist *evlist;
35 struct pevent *pevent; 36 struct trace_event tevent;
36 struct events_stats stats; 37 struct events_stats stats;
37 bool repipe; 38 bool repipe;
38 struct ordered_samples ordered_samples; 39 struct ordered_samples ordered_samples;
@@ -44,6 +45,7 @@ struct perf_session {
44#define PRINT_IP_OPT_DSO (1<<2) 45#define PRINT_IP_OPT_DSO (1<<2)
45#define PRINT_IP_OPT_SYMOFFSET (1<<3) 46#define PRINT_IP_OPT_SYMOFFSET (1<<3)
46#define PRINT_IP_OPT_ONELINE (1<<4) 47#define PRINT_IP_OPT_ONELINE (1<<4)
48#define PRINT_IP_OPT_SRCLINE (1<<5)
47 49
48struct perf_tool; 50struct perf_tool;
49 51
@@ -72,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session,
72 74
73bool perf_session__has_traces(struct perf_session *session, const char *msg); 75bool perf_session__has_traces(struct perf_session *session, const char *msg);
74 76
75void mem_bswap_64(void *src, int byte_size);
76void mem_bswap_32(void *src, int byte_size);
77void perf_event__attr_swap(struct perf_event_attr *attr); 77void perf_event__attr_swap(struct perf_event_attr *attr);
78 78
79int perf_session__create_kernel_maps(struct perf_session *session); 79int perf_session__create_kernel_maps(struct perf_session *session);
@@ -105,8 +105,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
105struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 105struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
106 unsigned int type); 106 unsigned int type);
107 107
108void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 108void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
109 struct perf_sample *sample, struct machine *machine, 109 struct addr_location *al,
110 unsigned int print_opts, unsigned int stack_depth); 110 unsigned int print_opts, unsigned int stack_depth);
111 111
112int perf_session__cpu_bitmap(struct perf_session *session, 112int perf_session__cpu_bitmap(struct perf_session *session,
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 58ea5ca6c255..d0aee4b9dfd4 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter'
25build_lib = getenv('PYTHON_EXTBUILD_LIB') 25build_lib = getenv('PYTHON_EXTBUILD_LIB')
26build_tmp = getenv('PYTHON_EXTBUILD_TMP') 26build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27libtraceevent = getenv('LIBTRACEEVENT') 27libtraceevent = getenv('LIBTRACEEVENT')
28liblk = getenv('LIBLK') 28libapikfs = getenv('LIBAPIKFS')
29 29
30ext_sources = [f.strip() for f in file('util/python-ext-sources') 30ext_sources = [f.strip() for f in file('util/python-ext-sources')
31 if len(f.strip()) > 0 and f[0] != '#'] 31 if len(f.strip()) > 0 and f[0] != '#']
@@ -34,7 +34,7 @@ perf = Extension('perf',
34 sources = ext_sources, 34 sources = ext_sources,
35 include_dirs = ['util/include'], 35 include_dirs = ['util/include'],
36 extra_compile_args = cflags, 36 extra_compile_args = cflags,
37 extra_objects = [libtraceevent, liblk], 37 extra_objects = [libtraceevent, libapikfs],
38 ) 38 )
39 39
40setup(name='perf', 40setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 8b0bb1f4494a..635cd8f8b22e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -13,6 +13,7 @@ int have_ignore_callees = 0;
13int sort__need_collapse = 0; 13int sort__need_collapse = 0;
14int sort__has_parent = 0; 14int sort__has_parent = 0;
15int sort__has_sym = 0; 15int sort__has_sym = 0;
16int sort__has_dso = 0;
16enum sort_mode sort__mode = SORT_MODE__NORMAL; 17enum sort_mode sort__mode = SORT_MODE__NORMAL;
17 18
18enum sort_type sort__first_dimension; 19enum sort_type sort__first_dimension;
@@ -161,6 +162,11 @@ struct sort_entry sort_dso = {
161 162
162/* --sort symbol */ 163/* --sort symbol */
163 164
165static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
166{
167 return (int64_t)(right_ip - left_ip);
168}
169
164static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 170static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
165{ 171{
166 u64 ip_l, ip_r; 172 u64 ip_l, ip_r;
@@ -183,15 +189,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183 int64_t ret; 189 int64_t ret;
184 190
185 if (!left->ms.sym && !right->ms.sym) 191 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level; 192 return _sort__addr_cmp(left->ip, right->ip);
187 193
188 /* 194 /*
189 * comparing symbol address alone is not enough since it's a 195 * comparing symbol address alone is not enough since it's a
190 * relative address within a dso. 196 * relative address within a dso.
191 */ 197 */
192 ret = sort__dso_cmp(left, right); 198 if (!sort__has_dso) {
193 if (ret != 0) 199 ret = sort__dso_cmp(left, right);
194 return ret; 200 if (ret != 0)
201 return ret;
202 }
195 203
196 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 204 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
197} 205}
@@ -372,7 +380,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
372 struct addr_map_symbol *from_r = &right->branch_info->from; 380 struct addr_map_symbol *from_r = &right->branch_info->from;
373 381
374 if (!from_l->sym && !from_r->sym) 382 if (!from_l->sym && !from_r->sym)
375 return right->level - left->level; 383 return _sort__addr_cmp(from_l->addr, from_r->addr);
376 384
377 return _sort__sym_cmp(from_l->sym, from_r->sym); 385 return _sort__sym_cmp(from_l->sym, from_r->sym);
378} 386}
@@ -384,7 +392,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
384 struct addr_map_symbol *to_r = &right->branch_info->to; 392 struct addr_map_symbol *to_r = &right->branch_info->to;
385 393
386 if (!to_l->sym && !to_r->sym) 394 if (!to_l->sym && !to_r->sym)
387 return right->level - left->level; 395 return _sort__addr_cmp(to_l->addr, to_r->addr);
388 396
389 return _sort__sym_cmp(to_l->sym, to_r->sym); 397 return _sort__sym_cmp(to_l->sym, to_r->sym);
390} 398}
@@ -1056,6 +1064,8 @@ int sort_dimension__add(const char *tok)
1056 sort__has_parent = 1; 1064 sort__has_parent = 1;
1057 } else if (sd->entry == &sort_sym) { 1065 } else if (sd->entry == &sort_sym) {
1058 sort__has_sym = 1; 1066 sort__has_sym = 1;
1067 } else if (sd->entry == &sort_dso) {
1068 sort__has_dso = 1;
1059 } 1069 }
1060 1070
1061 __sort_dimension__add(sd, i); 1071 __sort_dimension__add(sd, i);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index d11aefbc4b8d..7e67879ebd25 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path)
129 129
130out: 130out:
131 if (a2l) { 131 if (a2l) {
132 free((void *)a2l->input); 132 zfree((void **)&a2l->input);
133 free(a2l); 133 free(a2l);
134 } 134 }
135 bfd_close(abfd); 135 bfd_close(abfd);
@@ -140,24 +140,30 @@ static void addr2line_cleanup(struct a2l_data *a2l)
140{ 140{
141 if (a2l->abfd) 141 if (a2l->abfd)
142 bfd_close(a2l->abfd); 142 bfd_close(a2l->abfd);
143 free((void *)a2l->input); 143 zfree((void **)&a2l->input);
144 free(a2l->syms); 144 zfree(&a2l->syms);
145 free(a2l); 145 free(a2l);
146} 146}
147 147
148static int addr2line(const char *dso_name, unsigned long addr, 148static int addr2line(const char *dso_name, unsigned long addr,
149 char **file, unsigned int *line) 149 char **file, unsigned int *line, struct dso *dso)
150{ 150{
151 int ret = 0; 151 int ret = 0;
152 struct a2l_data *a2l; 152 struct a2l_data *a2l = dso->a2l;
153
154 if (!a2l) {
155 dso->a2l = addr2line_init(dso_name);
156 a2l = dso->a2l;
157 }
153 158
154 a2l = addr2line_init(dso_name);
155 if (a2l == NULL) { 159 if (a2l == NULL) {
156 pr_warning("addr2line_init failed for %s\n", dso_name); 160 pr_warning("addr2line_init failed for %s\n", dso_name);
157 return 0; 161 return 0;
158 } 162 }
159 163
160 a2l->addr = addr; 164 a2l->addr = addr;
165 a2l->found = false;
166
161 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); 167 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
162 168
163 if (a2l->found && a2l->filename) { 169 if (a2l->found && a2l->filename) {
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr,
168 ret = 1; 174 ret = 1;
169 } 175 }
170 176
171 addr2line_cleanup(a2l);
172 return ret; 177 return ret;
173} 178}
174 179
180void dso__free_a2l(struct dso *dso)
181{
182 struct a2l_data *a2l = dso->a2l;
183
184 if (!a2l)
185 return;
186
187 addr2line_cleanup(a2l);
188
189 dso->a2l = NULL;
190}
191
175#else /* HAVE_LIBBFD_SUPPORT */ 192#else /* HAVE_LIBBFD_SUPPORT */
176 193
177static int addr2line(const char *dso_name, unsigned long addr, 194static int addr2line(const char *dso_name, unsigned long addr,
178 char **file, unsigned int *line_nr) 195 char **file, unsigned int *line_nr,
196 struct dso *dso __maybe_unused)
179{ 197{
180 FILE *fp; 198 FILE *fp;
181 char cmd[PATH_MAX]; 199 char cmd[PATH_MAX];
@@ -219,42 +237,58 @@ out:
219 pclose(fp); 237 pclose(fp);
220 return ret; 238 return ret;
221} 239}
240
241void dso__free_a2l(struct dso *dso __maybe_unused)
242{
243}
244
222#endif /* HAVE_LIBBFD_SUPPORT */ 245#endif /* HAVE_LIBBFD_SUPPORT */
223 246
247/*
248 * Number of addr2line failures (without success) before disabling it for that
249 * dso.
250 */
251#define A2L_FAIL_LIMIT 123
252
224char *get_srcline(struct dso *dso, unsigned long addr) 253char *get_srcline(struct dso *dso, unsigned long addr)
225{ 254{
226 char *file = NULL; 255 char *file = NULL;
227 unsigned line = 0; 256 unsigned line = 0;
228 char *srcline; 257 char *srcline;
229 char *dso_name = dso->long_name; 258 const char *dso_name;
230 size_t size;
231 259
232 if (!dso->has_srcline) 260 if (!dso->has_srcline)
233 return SRCLINE_UNKNOWN; 261 return SRCLINE_UNKNOWN;
234 262
263 if (dso->symsrc_filename)
264 dso_name = dso->symsrc_filename;
265 else
266 dso_name = dso->long_name;
267
235 if (dso_name[0] == '[') 268 if (dso_name[0] == '[')
236 goto out; 269 goto out;
237 270
238 if (!strncmp(dso_name, "/tmp/perf-", 10)) 271 if (!strncmp(dso_name, "/tmp/perf-", 10))
239 goto out; 272 goto out;
240 273
241 if (!addr2line(dso_name, addr, &file, &line)) 274 if (!addr2line(dso_name, addr, &file, &line, dso))
242 goto out; 275 goto out;
243 276
244 /* just calculate actual length */ 277 if (asprintf(&srcline, "%s:%u", file, line) < 0) {
245 size = snprintf(NULL, 0, "%s:%u", file, line) + 1; 278 free(file);
279 goto out;
280 }
246 281
247 srcline = malloc(size); 282 dso->a2l_fails = 0;
248 if (srcline)
249 snprintf(srcline, size, "%s:%u", file, line);
250 else
251 srcline = SRCLINE_UNKNOWN;
252 283
253 free(file); 284 free(file);
254 return srcline; 285 return srcline;
255 286
256out: 287out:
257 dso->has_srcline = 0; 288 if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
289 dso->has_srcline = 0;
290 dso__free_a2l(dso);
291 }
258 return SRCLINE_UNKNOWN; 292 return SRCLINE_UNKNOWN;
259} 293}
260 294
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index cfa906882e2c..4abe23550c73 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -28,7 +28,7 @@ void strbuf_init(struct strbuf *sb, ssize_t hint)
28void strbuf_release(struct strbuf *sb) 28void strbuf_release(struct strbuf *sb)
29{ 29{
30 if (sb->alloc) { 30 if (sb->alloc) {
31 free(sb->buf); 31 zfree(&sb->buf);
32 strbuf_init(sb, 0); 32 strbuf_init(sb, 0);
33 } 33 }
34} 34}
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index 3edd0538161f..79a757a2a15c 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -14,7 +14,7 @@ static void strfilter_node__delete(struct strfilter_node *node)
14{ 14{
15 if (node) { 15 if (node) {
16 if (node->p && !is_operator(*node->p)) 16 if (node->p && !is_operator(*node->p))
17 free((char *)node->p); 17 zfree((char **)&node->p);
18 strfilter_node__delete(node->l); 18 strfilter_node__delete(node->l);
19 strfilter_node__delete(node->r); 19 strfilter_node__delete(node->r);
20 free(node); 20 free(node);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f0b0c008c507..2553e5b55b89 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -128,7 +128,7 @@ void argv_free(char **argv)
128{ 128{
129 char **p; 129 char **p;
130 for (p = argv; *p; p++) 130 for (p = argv; *p; p++)
131 free(*p); 131 zfree(p);
132 132
133 free(argv); 133 free(argv);
134} 134}
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index eabdce0a2daa..61a90bf24b4d 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -5,6 +5,7 @@
5 */ 5 */
6 6
7#include "strlist.h" 7#include "strlist.h"
8#include "util.h"
8#include <errno.h> 9#include <errno.h>
9#include <stdio.h> 10#include <stdio.h>
10#include <stdlib.h> 11#include <stdlib.h>
@@ -38,7 +39,7 @@ out_delete:
38static void str_node__delete(struct str_node *snode, bool dupstr) 39static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 40{
40 if (dupstr) 41 if (dupstr)
41 free((void *)snode->s); 42 zfree((void **)&snode->s);
42 free(snode); 43 free(snode);
43} 44}
44 45
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 96c866045d60..43262b83c541 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -17,8 +17,12 @@
17#include <stdlib.h> 17#include <stdlib.h>
18#include <unistd.h> 18#include <unistd.h>
19#include <string.h> 19#include <string.h>
20#include <linux/bitops.h>
20 21
22#include "perf.h"
21#include "svghelper.h" 23#include "svghelper.h"
24#include "util.h"
25#include "cpumap.h"
22 26
23static u64 first_time, last_time; 27static u64 first_time, last_time;
24static u64 turbo_frequency, max_freq; 28static u64 turbo_frequency, max_freq;
@@ -28,6 +32,8 @@ static u64 turbo_frequency, max_freq;
28#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
29 33
30int svg_page_width = 1000; 34int svg_page_width = 1000;
35u64 svg_highlight;
36const char *svg_highlight_name;
31 37
32#define MIN_TEXT_SIZE 0.01 38#define MIN_TEXT_SIZE 0.01
33 39
@@ -39,9 +45,14 @@ static double cpu2slot(int cpu)
39 return 2 * cpu + 1; 45 return 2 * cpu + 1;
40} 46}
41 47
48static int *topology_map;
49
42static double cpu2y(int cpu) 50static double cpu2y(int cpu)
43{ 51{
44 return cpu2slot(cpu) * SLOT_MULT; 52 if (topology_map)
53 return cpu2slot(topology_map[cpu]) * SLOT_MULT;
54 else
55 return cpu2slot(cpu) * SLOT_MULT;
45} 56}
46 57
47static double time2pixels(u64 __time) 58static double time2pixels(u64 __time)
@@ -95,6 +106,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
95 106
96 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; 107 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
97 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); 108 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
109 fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
98 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); 110 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
99 111
100 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); 112 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
@@ -103,6 +115,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
103 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -128,14 +141,42 @@ void svg_box(int Yslot, u64 start, u64 end, const char *type)
128 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
129} 142}
130 143
131void svg_sample(int Yslot, int cpu, u64 start, u64 end) 144static char *time_to_string(u64 duration);
145void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
146{
147 if (!svgfile)
148 return;
149
150 fprintf(svgfile, "<g>\n");
151 fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu,
152 time_to_string(end - start));
153 if (backtrace)
154 fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace);
155 svg_box(Yslot, start, end, "blocked");
156 fprintf(svgfile, "</g>\n");
157}
158
159void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
132{ 160{
133 double text_size; 161 double text_size;
162 const char *type;
163
134 if (!svgfile) 164 if (!svgfile)
135 return; 165 return;
136 166
137 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n", 167 if (svg_highlight && end - start > svg_highlight)
138 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); 168 type = "sample_hi";
169 else
170 type = "sample";
171 fprintf(svgfile, "<g>\n");
172
173 fprintf(svgfile, "<title>#%d running %s</title>\n",
174 cpu, time_to_string(end - start));
175 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type);
139 180
140 text_size = (time2pixels(end)-time2pixels(start)); 181 text_size = (time2pixels(end)-time2pixels(start));
141 if (cpu > 9) 182 if (cpu > 9)
@@ -148,6 +189,7 @@ void svg_sample(int Yslot, int cpu, u64 start, u64 end)
148 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n",
149 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
150 191
192 fprintf(svgfile, "</g>\n");
151} 193}
152 194
153static char *time_to_string(u64 duration) 195static char *time_to_string(u64 duration)
@@ -168,7 +210,7 @@ static char *time_to_string(u64 duration)
168 return text; 210 return text;
169} 211}
170 212
171void svg_waiting(int Yslot, u64 start, u64 end) 213void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
172{ 214{
173 char *text; 215 char *text;
174 const char *style; 216 const char *style;
@@ -192,6 +234,9 @@ void svg_waiting(int Yslot, u64 start, u64 end)
192 font_size = round_text_size(font_size); 234 font_size = round_text_size(font_size);
193 235
194 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
195 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
196 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
197 if (font_size > MIN_TEXT_SIZE) 242 if (font_size > MIN_TEXT_SIZE)
@@ -242,28 +287,42 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
242 max_freq = __max_freq; 287 max_freq = __max_freq;
243 turbo_frequency = __turbo_freq; 288 turbo_frequency = __turbo_freq;
244 289
290 fprintf(svgfile, "<g>\n");
291
245 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n",
246 time2pixels(first_time), 293 time2pixels(first_time),
247 time2pixels(last_time)-time2pixels(first_time), 294 time2pixels(last_time)-time2pixels(first_time),
248 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
249 296
250 sprintf(cpu_string, "CPU %i", (int)cpu+1); 297 sprintf(cpu_string, "CPU %i", (int)cpu);
251 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
252 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
253 300
254 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n",
255 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303
304 fprintf(svgfile, "</g>\n");
256} 305}
257 306
258void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) 307void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
259{ 308{
260 double width; 309 double width;
310 const char *type;
261 311
262 if (!svgfile) 312 if (!svgfile)
263 return; 313 return;
264 314
315 if (svg_highlight && end - start >= svg_highlight)
316 type = "sample_hi";
317 else if (svg_highlight_name && strstr(name, svg_highlight_name))
318 type = "sample_hi";
319 else
320 type = "sample";
265 321
266 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
267 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
268 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
269 width = time2pixels(end)-time2pixels(start); 328 width = time2pixels(end)-time2pixels(start);
@@ -288,6 +347,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
288 return; 347 return;
289 348
290 349
350 fprintf(svgfile, "<g>\n");
351
291 if (type > 6) 352 if (type > 6)
292 type = 6; 353 type = 6;
293 sprintf(style, "c%i", type); 354 sprintf(style, "c%i", type);
@@ -306,6 +367,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
306 if (width > MIN_TEXT_SIZE) 367 if (width > MIN_TEXT_SIZE)
307 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n",
308 time2pixels(start), cpu2y(cpu)+width, width, type); 369 time2pixels(start), cpu2y(cpu)+width, width, type);
370
371 fprintf(svgfile, "</g>\n");
309} 372}
310 373
311static char *HzToHuman(unsigned long hz) 374static char *HzToHuman(unsigned long hz)
@@ -339,6 +402,8 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
339 if (!svgfile) 402 if (!svgfile)
340 return; 403 return;
341 404
405 fprintf(svgfile, "<g>\n");
406
342 if (max_freq) 407 if (max_freq)
343 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
344 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
@@ -347,10 +412,11 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
347 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n",
348 time2pixels(start), height+0.9, HzToHuman(freq)); 413 time2pixels(start), height+0.9, HzToHuman(freq));
349 414
415 fprintf(svgfile, "</g>\n");
350} 416}
351 417
352 418
353void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) 419void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace)
354{ 420{
355 double height; 421 double height;
356 422
@@ -358,6 +424,15 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
358 return; 424 return;
359 425
360 426
427 fprintf(svgfile, "<g>\n");
428
429 fprintf(svgfile, "<title>%s wakes up %s</title>\n",
430 desc1 ? desc1 : "?",
431 desc2 ? desc2 : "?");
432
433 if (backtrace)
434 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
435
361 if (row1 < row2) { 436 if (row1 < row2) {
362 if (row1) { 437 if (row1) {
363 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
@@ -395,9 +470,11 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
395 if (row1) 470 if (row1)
396 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
397 time2pixels(start), height); 472 time2pixels(start), height);
473
474 fprintf(svgfile, "</g>\n");
398} 475}
399 476
400void svg_wakeline(u64 start, int row1, int row2) 477void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
401{ 478{
402 double height; 479 double height;
403 480
@@ -405,6 +482,11 @@ void svg_wakeline(u64 start, int row1, int row2)
405 return; 482 return;
406 483
407 484
485 fprintf(svgfile, "<g>\n");
486
487 if (backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489
408 if (row1 < row2) 490 if (row1 < row2)
409 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
410 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
@@ -417,17 +499,28 @@ void svg_wakeline(u64 start, int row1, int row2)
417 height += SLOT_HEIGHT; 499 height += SLOT_HEIGHT;
418 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
419 time2pixels(start), height); 501 time2pixels(start), height);
502
503 fprintf(svgfile, "</g>\n");
420} 504}
421 505
422void svg_interrupt(u64 start, int row) 506void svg_interrupt(u64 start, int row, const char *backtrace)
423{ 507{
424 if (!svgfile) 508 if (!svgfile)
425 return; 509 return;
426 510
511 fprintf(svgfile, "<g>\n");
512
513 fprintf(svgfile, "<title>Wakeup from interrupt</title>\n");
514
515 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517
427 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
428 time2pixels(start), row * SLOT_MULT); 519 time2pixels(start), row * SLOT_MULT);
429 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
430 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522
523 fprintf(svgfile, "</g>\n");
431} 524}
432 525
433void svg_text(int Yslot, u64 start, const char *text) 526void svg_text(int Yslot, u64 start, const char *text)
@@ -455,6 +548,7 @@ void svg_legenda(void)
455 if (!svgfile) 548 if (!svgfile)
456 return; 549 return;
457 550
551 fprintf(svgfile, "<g>\n");
458 svg_legenda_box(0, "Running", "sample"); 552 svg_legenda_box(0, "Running", "sample");
459 svg_legenda_box(100, "Idle","c1"); 553 svg_legenda_box(100, "Idle","c1");
460 svg_legenda_box(200, "Deeper Idle", "c3"); 554 svg_legenda_box(200, "Deeper Idle", "c3");
@@ -462,6 +556,7 @@ void svg_legenda(void)
462 svg_legenda_box(550, "Sleeping", "process2"); 556 svg_legenda_box(550, "Sleeping", "process2");
463 svg_legenda_box(650, "Waiting for cpu", "waiting"); 557 svg_legenda_box(650, "Waiting for cpu", "waiting");
464 svg_legenda_box(800, "Blocked on IO", "blocked"); 558 svg_legenda_box(800, "Blocked on IO", "blocked");
559 fprintf(svgfile, "</g>\n");
465} 560}
466 561
467void svg_time_grid(void) 562void svg_time_grid(void)
@@ -499,3 +594,123 @@ void svg_close(void)
499 svgfile = NULL; 594 svgfile = NULL;
500 } 595 }
501} 596}
597
598#define cpumask_bits(maskp) ((maskp)->bits)
599typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
600
601struct topology {
602 cpumask_t *sib_core;
603 int sib_core_nr;
604 cpumask_t *sib_thr;
605 int sib_thr_nr;
606};
607
608static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
609{
610 int i;
611 int thr;
612
613 for (i = 0; i < t->sib_thr_nr; i++) {
614 if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
615 continue;
616
617 for_each_set_bit(thr,
618 cpumask_bits(&t->sib_thr[i]),
619 MAX_NR_CPUS)
620 if (map[thr] == -1)
621 map[thr] = (*pos)++;
622 }
623}
624
625static void scan_core_topology(int *map, struct topology *t)
626{
627 int pos = 0;
628 int i;
629 int cpu;
630
631 for (i = 0; i < t->sib_core_nr; i++)
632 for_each_set_bit(cpu,
633 cpumask_bits(&t->sib_core[i]),
634 MAX_NR_CPUS)
635 scan_thread_topology(map, t, cpu, &pos);
636}
637
638static int str_to_bitmap(char *s, cpumask_t *b)
639{
640 int i;
641 int ret = 0;
642 struct cpu_map *m;
643 int c;
644
645 m = cpu_map__new(s);
646 if (!m)
647 return -1;
648
649 for (i = 0; i < m->nr; i++) {
650 c = m->map[i];
651 if (c >= MAX_NR_CPUS) {
652 ret = -1;
653 break;
654 }
655
656 set_bit(c, cpumask_bits(b));
657 }
658
659 cpu_map__delete(m);
660
661 return ret;
662}
663
664int svg_build_topology_map(char *sib_core, int sib_core_nr,
665 char *sib_thr, int sib_thr_nr)
666{
667 int i;
668 struct topology t;
669
670 t.sib_core_nr = sib_core_nr;
671 t.sib_thr_nr = sib_thr_nr;
672 t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
673 t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));
674
675 if (!t.sib_core || !t.sib_thr) {
676 fprintf(stderr, "topology: no memory\n");
677 goto exit;
678 }
679
680 for (i = 0; i < sib_core_nr; i++) {
681 if (str_to_bitmap(sib_core, &t.sib_core[i])) {
682 fprintf(stderr, "topology: can't parse siblings map\n");
683 goto exit;
684 }
685
686 sib_core += strlen(sib_core) + 1;
687 }
688
689 for (i = 0; i < sib_thr_nr; i++) {
690 if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
691 fprintf(stderr, "topology: can't parse siblings map\n");
692 goto exit;
693 }
694
695 sib_thr += strlen(sib_thr) + 1;
696 }
697
698 topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
699 if (!topology_map) {
700 fprintf(stderr, "topology: no memory\n");
701 goto exit;
702 }
703
704 for (i = 0; i < MAX_NR_CPUS; i++)
705 topology_map[i] = -1;
706
707 scan_core_topology(topology_map, &t);
708
709 return 0;
710
711exit:
712 zfree(&t.sib_core);
713 zfree(&t.sib_thr);
714
715 return -1;
716}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e0781989cc31..f7b4d6e699ea 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -5,24 +5,29 @@
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_sample(int Yslot, int cpu, u64 start, u64 end); 8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_waiting(int Yslot, u64 start, u64 end); 9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
10extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
10extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); 11extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
11 12
12 13
13extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name); 14extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace);
14extern void svg_cstate(int cpu, u64 start, u64 end, int type); 15extern void svg_cstate(int cpu, u64 start, u64 end, int type);
15extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
16 17
17 18
18extern void svg_time_grid(void); 19extern void svg_time_grid(void);
19extern void svg_legenda(void); 20extern void svg_legenda(void);
20extern void svg_wakeline(u64 start, int row1, int row2); 21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
21extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2); 22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
22extern void svg_interrupt(u64 start, int row); 23extern void svg_interrupt(u64 start, int row, const char *backtrace);
23extern void svg_text(int Yslot, u64 start, const char *text); 24extern void svg_text(int Yslot, u64 start, const char *text);
24extern void svg_close(void); 25extern void svg_close(void);
26extern int svg_build_topology_map(char *sib_core, int sib_core_nr,
27 char *sib_thr, int sib_thr_nr);
25 28
26extern int svg_page_width; 29extern int svg_page_width;
30extern u64 svg_highlight;
31extern const char *svg_highlight_name;
27 32
28#endif /* __PERF_SVGHELPER_H */ 33#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index eed0b96302af..4b0a127a4d3b 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
6#include <inttypes.h> 6#include <inttypes.h>
7 7
8#include "symbol.h" 8#include "symbol.h"
9#include <symbol/kallsyms.h>
9#include "debug.h" 10#include "debug.h"
10 11
11#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT 12#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
@@ -553,7 +554,7 @@ bool symsrc__has_symtab(struct symsrc *ss)
553 554
554void symsrc__destroy(struct symsrc *ss) 555void symsrc__destroy(struct symsrc *ss)
555{ 556{
556 free(ss->name); 557 zfree(&ss->name);
557 elf_end(ss->elf); 558 elf_end(ss->elf);
558 close(ss->fd); 559 close(ss->fd);
559} 560}
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 2d2dd0532b5a..bd15f490d04f 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,4 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2#include "util.h"
2 3
3#include <stdio.h> 4#include <stdio.h>
4#include <fcntl.h> 5#include <fcntl.h>
@@ -253,6 +254,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
253 if (!ss->name) 254 if (!ss->name)
254 goto out_close; 255 goto out_close;
255 256
257 ss->fd = fd;
256 ss->type = type; 258 ss->type = type;
257 259
258 return 0; 260 return 0;
@@ -274,7 +276,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
274 276
275void symsrc__destroy(struct symsrc *ss) 277void symsrc__destroy(struct symsrc *ss)
276{ 278{
277 free(ss->name); 279 zfree(&ss->name);
278 close(ss->fd); 280 close(ss->fd);
279} 281}
280 282
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0c36965fff0..39ce9adbaaf0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -18,12 +18,9 @@
18 18
19#include <elf.h> 19#include <elf.h>
20#include <limits.h> 20#include <limits.h>
21#include <symbol/kallsyms.h>
21#include <sys/utsname.h> 22#include <sys/utsname.h>
22 23
23#ifndef KSYM_NAME_LEN
24#define KSYM_NAME_LEN 256
25#endif
26
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 24static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 25 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 26static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
446 return ret; 443 return ret;
447} 444}
448 445
449int kallsyms__parse(const char *filename, void *arg,
450 int (*process_symbol)(void *arg, const char *name,
451 char type, u64 start))
452{
453 char *line = NULL;
454 size_t n;
455 int err = -1;
456 FILE *file = fopen(filename, "r");
457
458 if (file == NULL)
459 goto out_failure;
460
461 err = 0;
462
463 while (!feof(file)) {
464 u64 start;
465 int line_len, len;
466 char symbol_type;
467 char *symbol_name;
468
469 line_len = getline(&line, &n, file);
470 if (line_len < 0 || !line)
471 break;
472
473 line[--line_len] = '\0'; /* \n */
474
475 len = hex2u64(line, &start);
476
477 len++;
478 if (len + 2 >= line_len)
479 continue;
480
481 symbol_type = line[len];
482 len += 2;
483 symbol_name = line + len;
484 len = line_len - len;
485
486 if (len >= KSYM_NAME_LEN) {
487 err = -1;
488 break;
489 }
490
491 err = process_symbol(arg, symbol_name,
492 symbol_type, start);
493 if (err)
494 break;
495 }
496
497 free(line);
498 fclose(file);
499 return err;
500
501out_failure:
502 return -1;
503}
504
505int modules__parse(const char *filename, void *arg, 446int modules__parse(const char *filename, void *arg,
506 int (*process_module)(void *arg, const char *name, 447 int (*process_module)(void *arg, const char *name,
507 u64 start)) 448 u64 start))
@@ -565,12 +506,34 @@ struct process_kallsyms_args {
565 struct dso *dso; 506 struct dso *dso;
566}; 507};
567 508
568static u8 kallsyms2elf_type(char type) 509bool symbol__is_idle(struct symbol *sym)
569{ 510{
570 if (type == 'W') 511 const char * const idle_symbols[] = {
571 return STB_WEAK; 512 "cpu_idle",
513 "intel_idle",
514 "default_idle",
515 "native_safe_halt",
516 "enter_idle",
517 "exit_idle",
518 "mwait_idle",
519 "mwait_idle_with_hints",
520 "poll_idle",
521 "ppc64_runlatch_off",
522 "pseries_dedicated_idle_sleep",
523 NULL
524 };
525
526 int i;
527
528 if (!sym)
529 return false;
530
531 for (i = 0; idle_symbols[i]; i++) {
532 if (!strcmp(idle_symbols[i], sym->name))
533 return true;
534 }
572 535
573 return isupper(type) ? STB_GLOBAL : STB_LOCAL; 536 return false;
574} 537}
575 538
576static int map__process_kallsym_symbol(void *arg, const char *name, 539static int map__process_kallsym_symbol(void *arg, const char *name,
@@ -833,7 +796,7 @@ static void delete_modules(struct rb_root *modules)
833 mi = rb_entry(next, struct module_info, rb_node); 796 mi = rb_entry(next, struct module_info, rb_node);
834 next = rb_next(&mi->rb_node); 797 next = rb_next(&mi->rb_node);
835 rb_erase(&mi->rb_node, modules); 798 rb_erase(&mi->rb_node, modules);
836 free(mi->name); 799 zfree(&mi->name);
837 free(mi); 800 free(mi);
838 } 801 }
839} 802}
@@ -1126,10 +1089,10 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1126 * dso__data_read_addr(). 1089 * dso__data_read_addr().
1127 */ 1090 */
1128 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1091 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1129 dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; 1092 dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
1130 else 1093 else
1131 dso->data_type = DSO_BINARY_TYPE__KCORE; 1094 dso->binary_type = DSO_BINARY_TYPE__KCORE;
1132 dso__set_long_name(dso, strdup(kcore_filename)); 1095 dso__set_long_name(dso, strdup(kcore_filename), true);
1133 1096
1134 close(fd); 1097 close(fd);
1135 1098
@@ -1295,8 +1258,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1295 1258
1296 enum dso_binary_type symtab_type = binary_type_symtab[i]; 1259 enum dso_binary_type symtab_type = binary_type_symtab[i];
1297 1260
1298 if (dso__binary_type_file(dso, symtab_type, 1261 if (dso__read_binary_type_filename(dso, symtab_type,
1299 root_dir, name, PATH_MAX)) 1262 root_dir, name, PATH_MAX))
1300 continue; 1263 continue;
1301 1264
1302 /* Name is now the name of the next image to try */ 1265 /* Name is now the name of the next image to try */
@@ -1306,6 +1269,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1306 if (!syms_ss && symsrc__has_symtab(ss)) { 1269 if (!syms_ss && symsrc__has_symtab(ss)) {
1307 syms_ss = ss; 1270 syms_ss = ss;
1308 next_slot = true; 1271 next_slot = true;
1272 if (!dso->symsrc_filename)
1273 dso->symsrc_filename = strdup(name);
1309 } 1274 }
1310 1275
1311 if (!runtime_ss && symsrc__possibly_runtime(ss)) { 1276 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
@@ -1376,7 +1341,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
1376} 1341}
1377 1342
1378int dso__load_vmlinux(struct dso *dso, struct map *map, 1343int dso__load_vmlinux(struct dso *dso, struct map *map,
1379 const char *vmlinux, symbol_filter_t filter) 1344 const char *vmlinux, bool vmlinux_allocated,
1345 symbol_filter_t filter)
1380{ 1346{
1381 int err = -1; 1347 int err = -1;
1382 struct symsrc ss; 1348 struct symsrc ss;
@@ -1402,10 +1368,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
1402 1368
1403 if (err > 0) { 1369 if (err > 0) {
1404 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1370 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1405 dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1371 dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1406 else 1372 else
1407 dso->data_type = DSO_BINARY_TYPE__VMLINUX; 1373 dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1408 dso__set_long_name(dso, (char *)vmlinux); 1374 dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1409 dso__set_loaded(dso, map->type); 1375 dso__set_loaded(dso, map->type);
1410 pr_debug("Using %s for symbols\n", symfs_vmlinux); 1376 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1411 } 1377 }
@@ -1424,21 +1390,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1424 1390
1425 filename = dso__build_id_filename(dso, NULL, 0); 1391 filename = dso__build_id_filename(dso, NULL, 0);
1426 if (filename != NULL) { 1392 if (filename != NULL) {
1427 err = dso__load_vmlinux(dso, map, filename, filter); 1393 err = dso__load_vmlinux(dso, map, filename, true, filter);
1428 if (err > 0) { 1394 if (err > 0)
1429 dso->lname_alloc = 1;
1430 goto out; 1395 goto out;
1431 }
1432 free(filename); 1396 free(filename);
1433 } 1397 }
1434 1398
1435 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1399 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1436 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1400 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1437 if (err > 0) { 1401 if (err > 0)
1438 dso__set_long_name(dso, strdup(vmlinux_path[i]));
1439 dso->lname_alloc = 1;
1440 break; 1402 break;
1441 }
1442 } 1403 }
1443out: 1404out:
1444 return err; 1405 return err;
@@ -1496,14 +1457,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1496 1457
1497 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 1458 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1498 1459
1460 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1461 sbuild_id);
1462
1499 /* Use /proc/kallsyms if possible */ 1463 /* Use /proc/kallsyms if possible */
1500 if (is_host) { 1464 if (is_host) {
1501 DIR *d; 1465 DIR *d;
1502 int fd; 1466 int fd;
1503 1467
1504 /* If no cached kcore go with /proc/kallsyms */ 1468 /* If no cached kcore go with /proc/kallsyms */
1505 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
1506 buildid_dir, sbuild_id);
1507 d = opendir(path); 1469 d = opendir(path);
1508 if (!d) 1470 if (!d)
1509 goto proc_kallsyms; 1471 goto proc_kallsyms;
@@ -1528,6 +1490,10 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1528 goto proc_kallsyms; 1490 goto proc_kallsyms;
1529 } 1491 }
1530 1492
1493 /* Find kallsyms in build-id cache with kcore */
1494 if (!find_matching_kcore(map, path, sizeof(path)))
1495 return strdup(path);
1496
1531 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 1497 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1532 buildid_dir, sbuild_id); 1498 buildid_dir, sbuild_id);
1533 1499
@@ -1570,15 +1536,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1570 } 1536 }
1571 1537
1572 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 1538 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
1573 err = dso__load_vmlinux(dso, map, 1539 return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
1574 symbol_conf.vmlinux_name, filter); 1540 false, filter);
1575 if (err > 0) {
1576 dso__set_long_name(dso,
1577 strdup(symbol_conf.vmlinux_name));
1578 dso->lname_alloc = 1;
1579 return err;
1580 }
1581 return err;
1582 } 1541 }
1583 1542
1584 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1543 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
@@ -1604,7 +1563,7 @@ do_kallsyms:
1604 free(kallsyms_allocated_filename); 1563 free(kallsyms_allocated_filename);
1605 1564
1606 if (err > 0 && !dso__is_kcore(dso)) { 1565 if (err > 0 && !dso__is_kcore(dso)) {
1607 dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 1566 dso__set_long_name(dso, "[kernel.kallsyms]", false);
1608 map__fixup_start(map); 1567 map__fixup_start(map);
1609 map__fixup_end(map); 1568 map__fixup_end(map);
1610 } 1569 }
@@ -1634,7 +1593,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1634 */ 1593 */
1635 if (symbol_conf.default_guest_vmlinux_name != NULL) { 1594 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1636 err = dso__load_vmlinux(dso, map, 1595 err = dso__load_vmlinux(dso, map,
1637 symbol_conf.default_guest_vmlinux_name, filter); 1596 symbol_conf.default_guest_vmlinux_name,
1597 false, filter);
1638 return err; 1598 return err;
1639 } 1599 }
1640 1600
@@ -1651,7 +1611,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1651 pr_debug("Using %s for symbols\n", kallsyms_filename); 1611 pr_debug("Using %s for symbols\n", kallsyms_filename);
1652 if (err > 0 && !dso__is_kcore(dso)) { 1612 if (err > 0 && !dso__is_kcore(dso)) {
1653 machine__mmap_name(machine, path, sizeof(path)); 1613 machine__mmap_name(machine, path, sizeof(path));
1654 dso__set_long_name(dso, strdup(path)); 1614 dso__set_long_name(dso, strdup(path), true);
1655 map__fixup_start(map); 1615 map__fixup_start(map);
1656 map__fixup_end(map); 1616 map__fixup_end(map);
1657 } 1617 }
@@ -1661,13 +1621,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1661 1621
1662static void vmlinux_path__exit(void) 1622static void vmlinux_path__exit(void)
1663{ 1623{
1664 while (--vmlinux_path__nr_entries >= 0) { 1624 while (--vmlinux_path__nr_entries >= 0)
1665 free(vmlinux_path[vmlinux_path__nr_entries]); 1625 zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1666 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1667 }
1668 1626
1669 free(vmlinux_path); 1627 zfree(&vmlinux_path);
1670 vmlinux_path = NULL;
1671} 1628}
1672 1629
1673static int vmlinux_path__init(void) 1630static int vmlinux_path__init(void)
@@ -1719,7 +1676,7 @@ out_fail:
1719 return -1; 1676 return -1;
1720} 1677}
1721 1678
1722static int setup_list(struct strlist **list, const char *list_str, 1679int setup_list(struct strlist **list, const char *list_str,
1723 const char *list_name) 1680 const char *list_name)
1724{ 1681{
1725 if (list_str == NULL) 1682 if (list_str == NULL)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 07de8fea2f48..cbd680361806 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -164,6 +164,7 @@ struct mem_info {
164}; 164};
165 165
166struct addr_location { 166struct addr_location {
167 struct machine *machine;
167 struct thread *thread; 168 struct thread *thread;
168 struct map *map; 169 struct map *map;
169 struct symbol *sym; 170 struct symbol *sym;
@@ -206,7 +207,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss);
206 207
207int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 208int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
208int dso__load_vmlinux(struct dso *dso, struct map *map, 209int dso__load_vmlinux(struct dso *dso, struct map *map,
209 const char *vmlinux, symbol_filter_t filter); 210 const char *vmlinux, bool vmlinux_allocated,
211 symbol_filter_t filter);
210int dso__load_vmlinux_path(struct dso *dso, struct map *map, 212int dso__load_vmlinux_path(struct dso *dso, struct map *map,
211 symbol_filter_t filter); 213 symbol_filter_t filter);
212int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 214int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
@@ -220,9 +222,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
220 222
221int filename__read_build_id(const char *filename, void *bf, size_t size); 223int filename__read_build_id(const char *filename, void *bf, size_t size);
222int sysfs__read_build_id(const char *filename, void *bf, size_t size); 224int sysfs__read_build_id(const char *filename, void *bf, size_t size);
223int kallsyms__parse(const char *filename, void *arg,
224 int (*process_symbol)(void *arg, const char *name,
225 char type, u64 start));
226int modules__parse(const char *filename, void *arg, 225int modules__parse(const char *filename, void *arg,
227 int (*process_module)(void *arg, const char *name, 226 int (*process_module)(void *arg, const char *name,
228 u64 start)); 227 u64 start));
@@ -240,6 +239,7 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp);
240bool symbol_type__is_a(char symbol_type, enum map_type map_type); 239bool symbol_type__is_a(char symbol_type, enum map_type map_type);
241bool symbol__restricted_filename(const char *filename, 240bool symbol__restricted_filename(const char *filename,
242 const char *restricted_filename); 241 const char *restricted_filename);
242bool symbol__is_idle(struct symbol *sym);
243 243
244int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 244int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
245 struct symsrc *runtime_ss, symbol_filter_t filter, 245 struct symsrc *runtime_ss, symbol_filter_t filter,
@@ -273,4 +273,7 @@ void kcore_extract__delete(struct kcore_extract *kce);
273int kcore_copy(const char *from_dir, const char *to_dir); 273int kcore_copy(const char *from_dir, const char *to_dir);
274int compare_proc_modules(const char *from, const char *to); 274int compare_proc_modules(const char *from, const char *to);
275 275
276int setup_list(struct strlist **list, const char *list_str,
277 const char *list_name);
278
276#endif /* __PERF_SYMBOL */ 279#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 3c778a07b7cc..e74c5963dc7a 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -55,6 +55,13 @@ enum target_errno target__validate(struct target *target)
55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; 55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM;
56 } 56 }
57 57
58 /* THREAD and SYSTEM/CPU are mutually exclusive */
59 if (target->per_thread && (target->system_wide || target->cpu_list)) {
60 target->per_thread = false;
61 if (ret == TARGET_ERRNO__SUCCESS)
62 ret = TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD;
63 }
64
58 return ret; 65 return ret;
59} 66}
60 67
@@ -100,6 +107,7 @@ static const char *target__error_str[] = {
100 "UID switch overriding CPU", 107 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM", 108 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM", 109 "UID switch overriding SYSTEM",
110 "SYSTEM/CPU switch overriding PER-THREAD",
103 "Invalid User: %s", 111 "Invalid User: %s",
104 "Problems obtaining information for user %s", 112 "Problems obtaining information for user %s",
105}; 113};
@@ -131,7 +139,8 @@ int target__strerror(struct target *target, int errnum,
131 msg = target__error_str[idx]; 139 msg = target__error_str[idx];
132 140
133 switch (errnum) { 141 switch (errnum) {
134 case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM: 142 case TARGET_ERRNO__PID_OVERRIDE_CPU ...
143 TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD:
135 snprintf(buf, buflen, "%s", msg); 144 snprintf(buf, buflen, "%s", msg);
136 break; 145 break;
137 146
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
index 2d0c50690892..7381b1ca4041 100644
--- a/tools/perf/util/target.h
+++ b/tools/perf/util/target.h
@@ -12,7 +12,8 @@ struct target {
12 uid_t uid; 12 uid_t uid;
13 bool system_wide; 13 bool system_wide;
14 bool uses_mmap; 14 bool uses_mmap;
15 bool force_per_cpu; 15 bool default_per_cpu;
16 bool per_thread;
16}; 17};
17 18
18enum target_errno { 19enum target_errno {
@@ -33,6 +34,7 @@ enum target_errno {
33 TARGET_ERRNO__UID_OVERRIDE_CPU, 34 TARGET_ERRNO__UID_OVERRIDE_CPU,
34 TARGET_ERRNO__PID_OVERRIDE_SYSTEM, 35 TARGET_ERRNO__PID_OVERRIDE_SYSTEM,
35 TARGET_ERRNO__UID_OVERRIDE_SYSTEM, 36 TARGET_ERRNO__UID_OVERRIDE_SYSTEM,
37 TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD,
36 38
37 /* for target__parse_uid() */ 39 /* for target__parse_uid() */
38 TARGET_ERRNO__INVALID_UID, 40 TARGET_ERRNO__INVALID_UID,
@@ -61,4 +63,17 @@ static inline bool target__none(struct target *target)
61 return !target__has_task(target) && !target__has_cpu(target); 63 return !target__has_task(target) && !target__has_cpu(target);
62} 64}
63 65
66static inline bool target__uses_dummy_map(struct target *target)
67{
68 bool use_dummy = false;
69
70 if (target->default_per_cpu)
71 use_dummy = target->per_thread ? true : false;
72 else if (target__has_task(target) ||
73 (!target__has_cpu(target) && !target->uses_mmap))
74 use_dummy = true;
75
76 return use_dummy;
77}
78
64#endif /* _PERF_TARGET_H */ 79#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 49eaf1d7d89d..e3948612543e 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -126,7 +126,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
126 if (!comm) 126 if (!comm)
127 return -ENOMEM; 127 return -ENOMEM;
128 err = thread__set_comm(thread, comm, timestamp); 128 err = thread__set_comm(thread, comm, timestamp);
129 if (!err) 129 if (err)
130 return err; 130 return err;
131 thread->comm_set = true; 131 thread->comm_set = true;
132 } 132 }
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 897c1b2a750a..5b856bf942e1 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -6,6 +6,7 @@
6#include <unistd.h> 6#include <unistd.h>
7#include <sys/types.h> 7#include <sys/types.h>
8#include "symbol.h" 8#include "symbol.h"
9#include <strlist.h>
9 10
10struct thread { 11struct thread {
11 union { 12 union {
@@ -66,4 +67,15 @@ static inline void thread__set_priv(struct thread *thread, void *p)
66{ 67{
67 thread->priv = p; 68 thread->priv = p;
68} 69}
70
71static inline bool thread__is_filtered(struct thread *thread)
72{
73 if (symbol_conf.comm_list &&
74 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) {
75 return true;
76 }
77
78 return false;
79}
80
69#endif /* __PERF_THREAD_H */ 81#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 9b5f856cc280..5d3215912105 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -9,6 +9,7 @@
9#include "strlist.h" 9#include "strlist.h"
10#include <string.h> 10#include <string.h>
11#include "thread_map.h" 11#include "thread_map.h"
12#include "util.h"
12 13
13/* Skip "." and ".." directories */ 14/* Skip "." and ".." directories */
14static int filter(const struct dirent *dir) 15static int filter(const struct dirent *dir)
@@ -40,7 +41,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
40 } 41 }
41 42
42 for (i=0; i<items; i++) 43 for (i=0; i<items; i++)
43 free(namelist[i]); 44 zfree(&namelist[i]);
44 free(namelist); 45 free(namelist);
45 46
46 return threads; 47 return threads;
@@ -117,7 +118,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
117 threads->map[threads->nr + i] = atoi(namelist[i]->d_name); 118 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118 119
119 for (i = 0; i < items; i++) 120 for (i = 0; i < items; i++)
120 free(namelist[i]); 121 zfree(&namelist[i]);
121 free(namelist); 122 free(namelist);
122 123
123 threads->nr += items; 124 threads->nr += items;
@@ -134,12 +135,11 @@ out_free_threads:
134 135
135out_free_namelist: 136out_free_namelist:
136 for (i = 0; i < items; i++) 137 for (i = 0; i < items; i++)
137 free(namelist[i]); 138 zfree(&namelist[i]);
138 free(namelist); 139 free(namelist);
139 140
140out_free_closedir: 141out_free_closedir:
141 free(threads); 142 zfree(&threads);
142 threads = NULL;
143 goto out_closedir; 143 goto out_closedir;
144} 144}
145 145
@@ -194,7 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
194 194
195 for (i = 0; i < items; i++) { 195 for (i = 0; i < items; i++) {
196 threads->map[j++] = atoi(namelist[i]->d_name); 196 threads->map[j++] = atoi(namelist[i]->d_name);
197 free(namelist[i]); 197 zfree(&namelist[i]);
198 } 198 }
199 threads->nr = total_tasks; 199 threads->nr = total_tasks;
200 free(namelist); 200 free(namelist);
@@ -206,12 +206,11 @@ out:
206 206
207out_free_namelist: 207out_free_namelist:
208 for (i = 0; i < items; i++) 208 for (i = 0; i < items; i++)
209 free(namelist[i]); 209 zfree(&namelist[i]);
210 free(namelist); 210 free(namelist);
211 211
212out_free_threads: 212out_free_threads:
213 free(threads); 213 zfree(&threads);
214 threads = NULL;
215 goto out; 214 goto out;
216} 215}
217 216
@@ -262,8 +261,7 @@ out:
262 return threads; 261 return threads;
263 262
264out_free_threads: 263out_free_threads:
265 free(threads); 264 zfree(&threads);
266 threads = NULL;
267 goto out; 265 goto out;
268} 266}
269 267
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index ce793c7dd23c..8e517def925b 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -26,7 +26,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
26 float samples_per_sec; 26 float samples_per_sec;
27 float ksamples_per_sec; 27 float ksamples_per_sec;
28 float esamples_percent; 28 float esamples_percent;
29 struct perf_record_opts *opts = &top->record_opts; 29 struct record_opts *opts = &top->record_opts;
30 struct target *target = &opts->target; 30 struct target *target = &opts->target;
31 size_t ret = 0; 31 size_t ret = 0;
32 32
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 88cfeaff600b..dab14d0ad3d0 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_record_opts record_opts; 17 struct record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index f3c9e551bd35..7e6fcfe8b438 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,7 +38,7 @@
38 38
39#include "../perf.h" 39#include "../perf.h"
40#include "trace-event.h" 40#include "trace-event.h"
41#include <lk/debugfs.h> 41#include <api/fs/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43 43
44#define VERSION "0.5" 44#define VERSION "0.5"
@@ -397,8 +397,8 @@ put_tracepoints_path(struct tracepoint_path *tps)
397 struct tracepoint_path *t = tps; 397 struct tracepoint_path *t = tps;
398 398
399 tps = tps->next; 399 tps = tps->next;
400 free(t->name); 400 zfree(&t->name);
401 free(t->system); 401 zfree(&t->system);
402 free(t); 402 free(t);
403 } 403 }
404} 404}
@@ -562,10 +562,8 @@ out:
562 output_fd = fd; 562 output_fd = fd;
563 } 563 }
564 564
565 if (err) { 565 if (err)
566 free(tdata); 566 zfree(&tdata);
567 tdata = NULL;
568 }
569 567
570 put_tracepoints_path(tps); 568 put_tracepoints_path(tps);
571 return tdata; 569 return tdata;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 6681f71f2f95..e0d6d07f6848 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -28,19 +28,6 @@
28#include "util.h" 28#include "util.h"
29#include "trace-event.h" 29#include "trace-event.h"
30 30
31struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
32{
33 struct pevent *pevent = pevent_alloc();
34
35 if (pevent != NULL) {
36 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
37 pevent_set_file_bigendian(pevent, file_bigendian);
38 pevent_set_host_bigendian(pevent, host_bigendian);
39 }
40
41 return pevent;
42}
43
44static int get_common_field(struct scripting_context *context, 31static int get_common_field(struct scripting_context *context,
45 int *offset, int *size, const char *type) 32 int *offset, int *size, const char *type)
46{ 33{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f2112270c663..e113e180c48f 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent)
343 return 0; 343 return 0;
344} 344}
345 345
346ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 346ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
347{ 347{
348 char buf[BUFSIZ]; 348 char buf[BUFSIZ];
349 char test[] = { 23, 8, 68 }; 349 char test[] = { 23, 8, 68 };
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
356 int host_bigendian; 356 int host_bigendian;
357 int file_long_size; 357 int file_long_size;
358 int file_page_size; 358 int file_page_size;
359 struct pevent *pevent; 359 struct pevent *pevent = NULL;
360 int err; 360 int err;
361 361
362 *ppevent = NULL;
363
364 repipe = __repipe; 362 repipe = __repipe;
365 input_fd = fd; 363 input_fd = fd;
366 364
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
390 file_bigendian = buf[0]; 388 file_bigendian = buf[0];
391 host_bigendian = bigendian(); 389 host_bigendian = bigendian();
392 390
393 pevent = read_trace_init(file_bigendian, host_bigendian); 391 if (trace_event__init(tevent)) {
394 if (pevent == NULL) { 392 pr_debug("trace_event__init failed");
395 pr_debug("read_trace_init failed");
396 goto out; 393 goto out;
397 } 394 }
398 395
396 pevent = tevent->pevent;
397
398 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
399 pevent_set_file_bigendian(pevent, file_bigendian);
400 pevent_set_host_bigendian(pevent, host_bigendian);
401
399 if (do_read(buf, 1) < 0) 402 if (do_read(buf, 1) < 0)
400 goto out; 403 goto out;
401 file_long_size = buf[0]; 404 file_long_size = buf[0];
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
432 pevent_print_printk(pevent); 435 pevent_print_printk(pevent);
433 } 436 }
434 437
435 *ppevent = pevent;
436 pevent = NULL; 438 pevent = NULL;
437 439
438out: 440out:
439 if (pevent) 441 if (pevent)
440 pevent_free(pevent); 442 trace_event__cleanup(tevent);
441 return size; 443 return size;
442} 444}
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 95199e4eea97..57aaccc1692e 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -38,9 +38,8 @@ static int stop_script_unsupported(void)
38static void process_event_unsupported(union perf_event *event __maybe_unused, 38static void process_event_unsupported(union perf_event *event __maybe_unused,
39 struct perf_sample *sample __maybe_unused, 39 struct perf_sample *sample __maybe_unused,
40 struct perf_evsel *evsel __maybe_unused, 40 struct perf_evsel *evsel __maybe_unused,
41 struct machine *machine __maybe_unused,
42 struct thread *thread __maybe_unused, 41 struct thread *thread __maybe_unused,
43 struct addr_location *al __maybe_unused) 42 struct addr_location *al __maybe_unused)
44{ 43{
45} 44}
46 45
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c
new file mode 100644
index 000000000000..d9f5f6137ab3
--- /dev/null
+++ b/tools/perf/util/trace-event.c
@@ -0,0 +1,82 @@
1
2#include <stdio.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <errno.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <linux/kernel.h>
10#include <traceevent/event-parse.h>
11#include "trace-event.h"
12#include "util.h"
13
14/*
15 * global trace_event object used by trace_event__tp_format
16 *
17 * TODO There's no cleanup call for this. Add some sort of
18 * __exit function support and call trace_event__cleanup
19 * there.
20 */
21static struct trace_event tevent;
22
23int trace_event__init(struct trace_event *t)
24{
25 struct pevent *pevent = pevent_alloc();
26
27 if (pevent) {
28 t->plugin_list = traceevent_load_plugins(pevent);
29 t->pevent = pevent;
30 }
31
32 return pevent ? 0 : -1;
33}
34
35void trace_event__cleanup(struct trace_event *t)
36{
37 pevent_free(t->pevent);
38 traceevent_unload_plugins(t->plugin_list);
39}
40
41static struct event_format*
42tp_format(const char *sys, const char *name)
43{
44 struct pevent *pevent = tevent.pevent;
45 struct event_format *event = NULL;
46 char path[PATH_MAX];
47 size_t size;
48 char *data;
49
50 scnprintf(path, PATH_MAX, "%s/%s/%s/format",
51 tracing_events_path, sys, name);
52
53 if (filename__read_str(path, &data, &size))
54 return NULL;
55
56 pevent_parse_format(pevent, &event, data, size, sys);
57
58 free(data);
59 return event;
60}
61
62struct event_format*
63trace_event__tp_format(const char *sys, const char *name)
64{
65 static bool initialized;
66
67 if (!initialized) {
68 int be = traceevent_host_bigendian();
69 struct pevent *pevent;
70
71 if (trace_event__init(&tevent))
72 return NULL;
73
74 pevent = tevent.pevent;
75 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
76 pevent_set_file_bigendian(pevent, be);
77 pevent_set_host_bigendian(pevent, be);
78 initialized = true;
79 }
80
81 return tp_format(sys, name);
82}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 04df63114109..7b6d68688327 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,17 +3,26 @@
3 3
4#include <traceevent/event-parse.h> 4#include <traceevent/event-parse.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h"
7 6
8struct machine; 7struct machine;
9struct perf_sample; 8struct perf_sample;
10union perf_event; 9union perf_event;
11struct perf_tool; 10struct perf_tool;
12struct thread; 11struct thread;
12struct plugin_list;
13
14struct trace_event {
15 struct pevent *pevent;
16 struct plugin_list *plugin_list;
17};
18
19int trace_event__init(struct trace_event *t);
20void trace_event__cleanup(struct trace_event *t);
21struct event_format*
22trace_event__tp_format(const char *sys, const char *name);
13 23
14int bigendian(void); 24int bigendian(void);
15 25
16struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
17void event_format__print(struct event_format *event, 26void event_format__print(struct event_format *event,
18 int cpu, void *data, int size); 27 int cpu, void *data, int size);
19 28
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data);
27void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 36void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
28void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 37void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
29 38
30ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); 39ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
31 40
32struct event_format *trace_find_next_event(struct pevent *pevent, 41struct event_format *trace_find_next_event(struct pevent *pevent,
33 struct event_format *event); 42 struct event_format *event);
@@ -59,7 +68,6 @@ struct scripting_ops {
59 void (*process_event) (union perf_event *event, 68 void (*process_event) (union perf_event *event,
60 struct perf_sample *sample, 69 struct perf_sample *sample,
61 struct perf_evsel *evsel, 70 struct perf_evsel *evsel,
62 struct machine *machine,
63 struct thread *thread, 71 struct thread *thread,
64 struct addr_location *al); 72 struct addr_location *al);
65 int (*generate_script) (struct pevent *pevent, const char *outfile); 73 int (*generate_script) (struct pevent *pevent, const char *outfile);
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 0efd5393de85..416f22bf3693 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -340,10 +340,10 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
340 /* Check the .debug_frame section for unwinding info */ 340 /* Check the .debug_frame section for unwinding info */
341 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { 341 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
342 memset(&di, 0, sizeof(di)); 342 memset(&di, 0, sizeof(di));
343 dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, 343 if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
344 map->start, map->end); 344 map->start, map->end))
345 return dwarf_search_unwind_table(as, ip, &di, pi, 345 return dwarf_search_unwind_table(as, ip, &di, pi,
346 need_unwind_info, arg); 346 need_unwind_info, arg);
347 } 347 }
348#endif 348#endif
349 349
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 28a0a89c1f73..42ad667bb317 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,11 +1,17 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "fs.h"
3#include <sys/mman.h> 4#include <sys/mman.h>
4#ifdef HAVE_BACKTRACE_SUPPORT 5#ifdef HAVE_BACKTRACE_SUPPORT
5#include <execinfo.h> 6#include <execinfo.h>
6#endif 7#endif
7#include <stdio.h> 8#include <stdio.h>
8#include <stdlib.h> 9#include <stdlib.h>
10#include <string.h>
11#include <errno.h>
12#include <limits.h>
13#include <byteswap.h>
14#include <linux/kernel.h>
9 15
10/* 16/*
11 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
@@ -151,21 +157,40 @@ unsigned long convert_unit(unsigned long value, char *unit)
151 return value; 157 return value;
152} 158}
153 159
154int readn(int fd, void *buf, size_t n) 160static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
155{ 161{
156 void *buf_start = buf; 162 void *buf_start = buf;
163 size_t left = n;
157 164
158 while (n) { 165 while (left) {
159 int ret = read(fd, buf, n); 166 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left);
160 168
161 if (ret <= 0) 169 if (ret <= 0)
162 return ret; 170 return ret;
163 171
164 n -= ret; 172 left -= ret;
165 buf += ret; 173 buf += ret;
166 } 174 }
167 175
168 return buf - buf_start; 176 BUG_ON((size_t)(buf - buf_start) != n);
177 return n;
178}
179
180/*
181 * Read exactly 'n' bytes or return an error.
182 */
183ssize_t readn(int fd, void *buf, size_t n)
184{
185 return ion(true, fd, buf, n);
186}
187
188/*
189 * Write exactly 'n' bytes or return an error.
190 */
191ssize_t writen(int fd, void *buf, size_t n)
192{
193 return ion(false, fd, buf, n);
169} 194}
170 195
171size_t hex_width(u64 v) 196size_t hex_width(u64 v)
@@ -413,3 +438,102 @@ int filename__read_int(const char *filename, int *value)
413 close(fd); 438 close(fd);
414 return err; 439 return err;
415} 440}
441
442int filename__read_str(const char *filename, char **buf, size_t *sizep)
443{
444 size_t size = 0, alloc_size = 0;
445 void *bf = NULL, *nbf;
446 int fd, n, err = 0;
447
448 fd = open(filename, O_RDONLY);
449 if (fd < 0)
450 return -errno;
451
452 do {
453 if (size == alloc_size) {
454 alloc_size += BUFSIZ;
455 nbf = realloc(bf, alloc_size);
456 if (!nbf) {
457 err = -ENOMEM;
458 break;
459 }
460
461 bf = nbf;
462 }
463
464 n = read(fd, bf + size, alloc_size - size);
465 if (n < 0) {
466 if (size) {
467 pr_warning("read failed %d: %s\n",
468 errno, strerror(errno));
469 err = 0;
470 } else
471 err = -errno;
472
473 break;
474 }
475
476 size += n;
477 } while (n > 0);
478
479 if (!err) {
480 *sizep = size;
481 *buf = bf;
482 } else
483 free(bf);
484
485 close(fd);
486 return err;
487}
488
489const char *get_filename_for_perf_kvm(void)
490{
491 const char *filename;
492
493 if (perf_host && !perf_guest)
494 filename = strdup("perf.data.host");
495 else if (!perf_host && perf_guest)
496 filename = strdup("perf.data.guest");
497 else
498 filename = strdup("perf.data.kvm");
499
500 return filename;
501}
502
503int perf_event_paranoid(void)
504{
505 char path[PATH_MAX];
506 const char *procfs = procfs__mountpoint();
507 int value;
508
509 if (!procfs)
510 return INT_MAX;
511
512 scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
513
514 if (filename__read_int(path, &value))
515 return INT_MAX;
516
517 return value;
518}
519
520void mem_bswap_32(void *src, int byte_size)
521{
522 u32 *m = src;
523 while (byte_size > 0) {
524 *m = bswap_32(*m);
525 byte_size -= sizeof(u32);
526 ++m;
527 }
528}
529
530void mem_bswap_64(void *src, int byte_size)
531{
532 u64 *m = src;
533
534 while (byte_size > 0) {
535 *m = bswap_64(*m);
536 byte_size -= sizeof(u64);
537 ++m;
538 }
539}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c8f362daba87..6995d66f225c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -71,8 +71,9 @@
71#include <linux/magic.h> 71#include <linux/magic.h>
72#include "types.h" 72#include "types.h"
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <lk/debugfs.h> 74#include <api/fs/debugfs.h>
75#include <termios.h> 75#include <termios.h>
76#include <linux/bitops.h>
76 77
77extern const char *graph_line; 78extern const char *graph_line;
78extern const char *graph_dotted_line; 79extern const char *graph_dotted_line;
@@ -185,6 +186,8 @@ static inline void *zalloc(size_t size)
185 return calloc(1, size); 186 return calloc(1, size);
186} 187}
187 188
189#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
190
188static inline int has_extension(const char *filename, const char *ext) 191static inline int has_extension(const char *filename, const char *ext)
189{ 192{
190 size_t len = strlen(filename); 193 size_t len = strlen(filename);
@@ -253,7 +256,8 @@ bool strlazymatch(const char *str, const char *pat);
253int strtailcmp(const char *s1, const char *s2); 256int strtailcmp(const char *s1, const char *s2);
254char *strxfrchar(char *s, char from, char to); 257char *strxfrchar(char *s, char from, char to);
255unsigned long convert_unit(unsigned long value, char *unit); 258unsigned long convert_unit(unsigned long value, char *unit);
256int readn(int fd, void *buf, size_t size); 259ssize_t readn(int fd, void *buf, size_t n);
260ssize_t writen(int fd, void *buf, size_t n);
257 261
258struct perf_event_attr; 262struct perf_event_attr;
259 263
@@ -280,6 +284,17 @@ static inline unsigned next_pow2(unsigned x)
280 return 1ULL << (32 - __builtin_clz(x - 1)); 284 return 1ULL << (32 - __builtin_clz(x - 1));
281} 285}
282 286
287static inline unsigned long next_pow2_l(unsigned long x)
288{
289#if BITS_PER_LONG == 64
290 if (x <= (1UL << 31))
291 return next_pow2(x);
292 return (unsigned long)next_pow2(x >> 32) << 32;
293#else
294 return next_pow2(x);
295#endif
296}
297
283size_t hex_width(u64 v); 298size_t hex_width(u64 v);
284int hex2u64(const char *ptr, u64 *val); 299int hex2u64(const char *ptr, u64 *val);
285 300
@@ -307,4 +322,11 @@ char *get_srcline(struct dso *dso, unsigned long addr);
307void free_srcline(char *srcline); 322void free_srcline(char *srcline);
308 323
309int filename__read_int(const char *filename, int *value); 324int filename__read_int(const char *filename, int *value);
325int filename__read_str(const char *filename, char **buf, size_t *sizep);
326int perf_event_paranoid(void);
327
328void mem_bswap_64(void *src, int byte_size);
329void mem_bswap_32(void *src, int byte_size);
330
331const char *get_filename_for_perf_kvm(void);
310#endif /* GIT_COMPAT_UTIL_H */ 332#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 697c8b4e59cc..0fb3c1fcd3e6 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -31,14 +31,14 @@ void perf_read_values_destroy(struct perf_read_values *values)
31 return; 31 return;
32 32
33 for (i = 0; i < values->threads; i++) 33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]); 34 zfree(&values->value[i]);
35 free(values->value); 35 zfree(&values->value);
36 free(values->pid); 36 zfree(&values->pid);
37 free(values->tid); 37 zfree(&values->tid);
38 free(values->counterrawid); 38 zfree(&values->counterrawid);
39 for (i = 0; i < values->counters; i++) 39 for (i = 0; i < values->counters; i++)
40 free(values->countername[i]); 40 zfree(&values->countername[i]);
41 free(values->countername); 41 zfree(&values->countername);
42} 42}
43 43
44static void perf_read_values__enlarge_threads(struct perf_read_values *values) 44static void perf_read_values__enlarge_threads(struct perf_read_values *values)
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 39159822d58f..0ddb3b8a89ec 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head)
103 dso = dso__new(VDSO__MAP_NAME); 103 dso = dso__new(VDSO__MAP_NAME);
104 if (dso != NULL) { 104 if (dso != NULL) {
105 dsos__add(head, dso); 105 dsos__add(head, dso);
106 dso__set_long_name(dso, file); 106 dso__set_long_name(dso, file, false);
107 } 107 }
108 } 108 }
109 109
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index ee76544deecb..8abbef164b4e 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -61,6 +61,7 @@ QUIET_SUBDIR1 =
61ifneq ($(findstring $(MAKEFLAGS),s),s) 61ifneq ($(findstring $(MAKEFLAGS),s),s)
62 ifneq ($(V),1) 62 ifneq ($(V),1)
63 QUIET_CC = @echo ' CC '$@; 63 QUIET_CC = @echo ' CC '$@;
64 QUIET_CC_FPIC = @echo ' CC FPIC '$@;
64 QUIET_AR = @echo ' AR '$@; 65 QUIET_AR = @echo ' AR '$@;
65 QUIET_LINK = @echo ' LINK '$@; 66 QUIET_LINK = @echo ' LINK '$@;
66 QUIET_MKDIR = @echo ' MKDIR '$@; 67 QUIET_MKDIR = @echo ' MKDIR '$@;
@@ -76,5 +77,8 @@ ifneq ($(findstring $(MAKEFLAGS),s),s)
76 +@echo ' DESCEND '$(1); \ 77 +@echo ' DESCEND '$(1); \
77 mkdir -p $(OUTPUT)$(1) && \ 78 mkdir -p $(OUTPUT)$(1) && \
78 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) 79 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
80
81 QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
82 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
79 endif 83 endif
80endif 84endif
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
index 24e9ddd93fa4..3d907dacf2ac 100644
--- a/tools/vm/Makefile
+++ b/tools/vm/Makefile
@@ -2,21 +2,21 @@
2# 2#
3TARGETS=page-types slabinfo 3TARGETS=page-types slabinfo
4 4
5LK_DIR = ../lib/lk 5LIB_DIR = ../lib/api
6LIBLK = $(LK_DIR)/liblk.a 6LIBS = $(LIB_DIR)/libapikfs.a
7 7
8CC = $(CROSS_COMPILE)gcc 8CC = $(CROSS_COMPILE)gcc
9CFLAGS = -Wall -Wextra -I../lib/ 9CFLAGS = -Wall -Wextra -I../lib/
10LDFLAGS = $(LIBLK) 10LDFLAGS = $(LIBS)
11 11
12$(TARGETS): liblk 12$(TARGETS): $(LIBS)
13 13
14liblk: 14$(LIBS):
15 make -C $(LK_DIR) 15 make -C $(LIB_DIR)
16 16
17%: %.c 17%: %.c
18 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 18 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
19 19
20clean: 20clean:
21 $(RM) page-types slabinfo 21 $(RM) page-types slabinfo
22 make -C ../lib/lk clean 22 make -C $(LIB_DIR) clean
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index d5e9d6d185c8..f9be24d9efac 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -36,7 +36,7 @@
36#include <sys/statfs.h> 36#include <sys/statfs.h>
37#include "../../include/uapi/linux/magic.h" 37#include "../../include/uapi/linux/magic.h"
38#include "../../include/uapi/linux/kernel-page-flags.h" 38#include "../../include/uapi/linux/kernel-page-flags.h"
39#include <lk/debugfs.h> 39#include <api/fs/debugfs.h>
40 40
41#ifndef MAX_PATH 41#ifndef MAX_PATH
42# define MAX_PATH 256 42# define MAX_PATH 256