aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--tools/Makefile16
-rw-r--r--tools/lib/lk/Makefile35
-rw-r--r--tools/lib/lk/debugfs.c (renamed from tools/perf/util/debugfs.c)49
-rw-r--r--tools/lib/lk/debugfs.h29
-rw-r--r--tools/perf/Documentation/perf-annotate.txt3
-rw-r--r--tools/perf/Documentation/perf-stat.txt2
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile38
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sparc/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/x86/util/dwarf-regs.c2
-rw-r--r--tools/perf/builtin-annotate.c23
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/builtin-record.c11
-rw-r--r--tools/perf/builtin-report.c3
-rw-r--r--tools/perf/builtin-stat.c164
-rw-r--r--tools/perf/builtin-top.c4
-rw-r--r--tools/perf/builtin-trace.c28
-rw-r--r--tools/perf/command-list.txt14
-rw-r--r--tools/perf/perf.c8
-rw-r--r--tools/perf/tests/attr.c9
-rw-r--r--tools/perf/tests/attr.py5
-rw-r--r--tools/perf/tests/attr/base-record1
-rw-r--r--tools/perf/tests/attr/base-stat1
-rw-r--r--tools/perf/tests/attr/test-record-C013
-rw-r--r--tools/perf/tests/attr/test-stat-C09
-rw-r--r--tools/perf/tests/bp_signal.c186
-rw-r--r--tools/perf/tests/bp_signal_overflow.c126
-rw-r--r--tools/perf/tests/builtin-test.c16
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_link.c2
-rw-r--r--tools/perf/tests/mmap-basic.c4
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c10
-rw-r--r--tools/perf/tests/parse-events.c4
-rw-r--r--tools/perf/tests/perf-record.c9
-rw-r--r--tools/perf/tests/sw-clock.c119
-rw-r--r--tools/perf/tests/task-exit.c123
-rw-r--r--tools/perf/tests/tests.h4
-rw-r--r--tools/perf/ui/browsers/annotate.c157
-rw-r--r--tools/perf/ui/browsers/hists.c6
-rw-r--r--tools/perf/ui/gtk/annotate.c26
-rw-r--r--tools/perf/ui/gtk/hists.c7
-rw-r--r--tools/perf/ui/hist.c7
-rw-r--r--tools/perf/util/annotate.c262
-rw-r--r--tools/perf/util/annotate.h49
-rw-r--r--tools/perf/util/debugfs.h12
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c13
-rw-r--r--tools/perf/util/evsel.h25
-rw-r--r--tools/perf/util/header.c4
-rw-r--r--tools/perf/util/hist.h5
-rw-r--r--tools/perf/util/machine.c22
-rw-r--r--tools/perf/util/machine.h1
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/session.c12
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/thread_map.h5
-rw-r--r--tools/perf/util/trace-event-info.c33
-rw-r--r--tools/perf/util/trace-event-parse.c37
-rw-r--r--tools/perf/util/trace-event-read.c201
-rw-r--r--tools/perf/util/trace-event.h4
-rw-r--r--tools/perf/util/util.c27
-rw-r--r--tools/perf/util/util.h7
-rw-r--r--tools/scripts/Makefile.include6
-rw-r--r--tools/vm/Makefile17
-rw-r--r--tools/vm/page-types.c85
75 files changed, 1432 insertions, 788 deletions
diff --git a/Makefile b/Makefile
index a05ea42c5f18..6b39246c2c67 100644
--- a/Makefile
+++ b/Makefile
@@ -1331,11 +1331,11 @@ kernelversion:
1331# Clear a bunch of variables before executing the submake 1331# Clear a bunch of variables before executing the submake
1332tools/: FORCE 1332tools/: FORCE
1333 $(Q)mkdir -p $(objtree)/tools 1333 $(Q)mkdir -p $(objtree)/tools
1334 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ 1334 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/
1335 1335
1336tools/%: FORCE 1336tools/%: FORCE
1337 $(Q)mkdir -p $(objtree)/tools 1337 $(Q)mkdir -p $(objtree)/tools
1338 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ $* 1338 $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $*
1339 1339
1340# Single targets 1340# Single targets
1341# --------------------------------------------------------------------------- 1341# ---------------------------------------------------------------------------
diff --git a/tools/Makefile b/tools/Makefile
index fa36565b209d..6aaeb6cd867d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -34,7 +34,13 @@ help:
34cpupower: FORCE 34cpupower: FORCE
35 $(call descend,power/$@) 35 $(call descend,power/$@)
36 36
37cgroup firewire lguest perf usb virtio vm: FORCE 37cgroup firewire guest usb virtio vm: FORCE
38 $(call descend,$@)
39
40liblk: FORCE
41 $(call descend,lib/lk)
42
43perf: liblk FORCE
38 $(call descend,$@) 44 $(call descend,$@)
39 45
40selftests: FORCE 46selftests: FORCE
@@ -62,7 +68,13 @@ install: cgroup_install cpupower_install firewire_install lguest_install \
62cpupower_clean: 68cpupower_clean:
63 $(call descend,power/cpupower,clean) 69 $(call descend,power/cpupower,clean)
64 70
65cgroup_clean firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean: 71cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean:
72 $(call descend,$(@:_clean=),clean)
73
74liblk_clean:
75 $(call descend,lib/lk,clean)
76
77perf_clean: liblk_clean
66 $(call descend,$(@:_clean=),clean) 78 $(call descend,$(@:_clean=),clean)
67 79
68selftests_clean: 80selftests_clean:
diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile
new file mode 100644
index 000000000000..926cbf3efc7f
--- /dev/null
+++ b/tools/lib/lk/Makefile
@@ -0,0 +1,35 @@
1include ../../scripts/Makefile.include
2
3# guard against environment variables
4LIB_H=
5LIB_OBJS=
6
7LIB_H += debugfs.h
8
9LIB_OBJS += $(OUTPUT)debugfs.o
10
11LIBFILE = liblk.a
12
13CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
14EXTLIBS = -lpthread -lrt -lelf -lm
15ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
16ALL_LDFLAGS = $(LDFLAGS)
17
18RM = rm -f
19
20$(LIBFILE): $(LIB_OBJS)
21 $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS)
22
23$(LIB_OBJS): $(LIB_H)
24
25$(OUTPUT)%.o: %.c
26 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
27$(OUTPUT)%.s: %.c
28 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
29$(OUTPUT)%.o: %.S
30 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
31
32clean:
33 $(RM) $(LIB_OBJS) $(LIBFILE)
34
35.PHONY: clean
diff --git a/tools/perf/util/debugfs.c b/tools/lib/lk/debugfs.c
index dd8b19319c03..099e7cd022e4 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/lib/lk/debugfs.c
@@ -1,36 +1,39 @@
1#include "util.h" 1#include <errno.h>
2#include "debugfs.h" 2#include <stdio.h>
3#include "cache.h" 3#include <stdlib.h>
4 4#include <string.h>
5#include <linux/kernel.h> 5#include <stdbool.h>
6#include <sys/vfs.h>
6#include <sys/mount.h> 7#include <sys/mount.h>
8#include <linux/magic.h>
9#include <linux/kernel.h>
10
11#include "debugfs.h"
7 12
8static int debugfs_premounted;
9char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; 13char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
10char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
11 14
12static const char *debugfs_known_mountpoints[] = { 15static const char * const debugfs_known_mountpoints[] = {
13 "/sys/kernel/debug/", 16 "/sys/kernel/debug/",
14 "/debug/", 17 "/debug/",
15 0, 18 0,
16}; 19};
17 20
18static int debugfs_found; 21static bool debugfs_found;
19 22
20/* find the path to the mounted debugfs */ 23/* find the path to the mounted debugfs */
21const char *debugfs_find_mountpoint(void) 24const char *debugfs_find_mountpoint(void)
22{ 25{
23 const char **ptr; 26 const char * const *ptr;
24 char type[100]; 27 char type[100];
25 FILE *fp; 28 FILE *fp;
26 29
27 if (debugfs_found) 30 if (debugfs_found)
28 return (const char *) debugfs_mountpoint; 31 return (const char *)debugfs_mountpoint;
29 32
30 ptr = debugfs_known_mountpoints; 33 ptr = debugfs_known_mountpoints;
31 while (*ptr) { 34 while (*ptr) {
32 if (debugfs_valid_mountpoint(*ptr) == 0) { 35 if (debugfs_valid_mountpoint(*ptr) == 0) {
33 debugfs_found = 1; 36 debugfs_found = true;
34 strcpy(debugfs_mountpoint, *ptr); 37 strcpy(debugfs_mountpoint, *ptr);
35 return debugfs_mountpoint; 38 return debugfs_mountpoint;
36 } 39 }
@@ -52,7 +55,7 @@ const char *debugfs_find_mountpoint(void)
52 if (strcmp(type, "debugfs") != 0) 55 if (strcmp(type, "debugfs") != 0)
53 return NULL; 56 return NULL;
54 57
55 debugfs_found = 1; 58 debugfs_found = true;
56 59
57 return debugfs_mountpoint; 60 return debugfs_mountpoint;
58} 61}
@@ -71,21 +74,12 @@ int debugfs_valid_mountpoint(const char *debugfs)
71 return 0; 74 return 0;
72} 75}
73 76
74static void debugfs_set_tracing_events_path(const char *mountpoint)
75{
76 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
77 mountpoint, "tracing/events");
78}
79
80/* mount the debugfs somewhere if it's not mounted */ 77/* mount the debugfs somewhere if it's not mounted */
81
82char *debugfs_mount(const char *mountpoint) 78char *debugfs_mount(const char *mountpoint)
83{ 79{
84 /* see if it's already mounted */ 80 /* see if it's already mounted */
85 if (debugfs_find_mountpoint()) { 81 if (debugfs_find_mountpoint())
86 debugfs_premounted = 1;
87 goto out; 82 goto out;
88 }
89 83
90 /* if not mounted and no argument */ 84 /* if not mounted and no argument */
91 if (mountpoint == NULL) { 85 if (mountpoint == NULL) {
@@ -100,15 +94,8 @@ char *debugfs_mount(const char *mountpoint)
100 return NULL; 94 return NULL;
101 95
102 /* save the mountpoint */ 96 /* save the mountpoint */
103 debugfs_found = 1; 97 debugfs_found = true;
104 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 98 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
105out: 99out:
106 debugfs_set_tracing_events_path(debugfs_mountpoint);
107 return debugfs_mountpoint; 100 return debugfs_mountpoint;
108} 101}
109
110void debugfs_set_path(const char *mountpoint)
111{
112 snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
113 debugfs_set_tracing_events_path(mountpoint);
114}
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/lk/debugfs.h
new file mode 100644
index 000000000000..935c59bdb442
--- /dev/null
+++ b/tools/lib/lk/debugfs.h
@@ -0,0 +1,29 @@
1#ifndef __LK_DEBUGFS_H__
2#define __LK_DEBUGFS_H__
3
4#define _STR(x) #x
5#define STR(x) _STR(x)
6
7/*
8 * On most systems <limits.h> would have given us this, but not on some systems
9 * (e.g. GNU/Hurd).
10 */
11#ifndef PATH_MAX
12#define PATH_MAX 4096
13#endif
14
15#ifndef DEBUGFS_MAGIC
16#define DEBUGFS_MAGIC 0x64626720
17#endif
18
19#ifndef PERF_DEBUGFS_ENVIRONMENT
20#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
21#endif
22
23const char *debugfs_find_mountpoint(void);
24int debugfs_valid_mountpoint(const char *debugfs);
25char *debugfs_mount(const char *mountpoint);
26
27extern char debugfs_mountpoint[];
28
29#endif /* __LK_DEBUGFS_H__ */
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 5ad07ef417f0..e9cd39a92dc2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -93,6 +93,9 @@ OPTIONS
93--skip-missing:: 93--skip-missing::
94 Skip symbols that cannot be annotated. 94 Skip symbols that cannot be annotated.
95 95
96--group::
97 Show event group information together
98
96SEE ALSO 99SEE ALSO
97-------- 100--------
98linkperf:perf-record[1], linkperf:perf-report[1] 101linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index faf4f4feebcc..23e587ad549e 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -52,7 +52,7 @@ OPTIONS
52 52
53-r:: 53-r::
54--repeat=<n>:: 54--repeat=<n>::
55 repeat command and print average + stddev (max: 100) 55 repeat command and print average + stddev (max: 100). 0 means forever.
56 56
57-B:: 57-B::
58--big-num:: 58--big-num::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 39d41068484f..025de796067c 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
1tools/perf 1tools/perf
2tools/scripts 2tools/scripts
3tools/lib/traceevent 3tools/lib/traceevent
4tools/lib/lk
4include/linux/const.h 5include/linux/const.h
5include/linux/perf_event.h 6include/linux/perf_event.h
6include/linux/rbtree.h 7include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index bb74c79cd16e..0230b75ed7f9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -215,6 +215,7 @@ BASIC_CFLAGS = \
215 -Iutil \ 215 -Iutil \
216 -I. \ 216 -I. \
217 -I$(TRACE_EVENT_DIR) \ 217 -I$(TRACE_EVENT_DIR) \
218 -I../lib/ \
218 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 219 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
219 220
220BASIC_LDFLAGS = 221BASIC_LDFLAGS =
@@ -240,19 +241,28 @@ SCRIPT_SH += perf-archive.sh
240grep-libs = $(filter -l%,$(1)) 241grep-libs = $(filter -l%,$(1))
241strip-libs = $(filter-out -l%,$(1)) 242strip-libs = $(filter-out -l%,$(1))
242 243
244LK_DIR = ../lib/lk/
243TRACE_EVENT_DIR = ../lib/traceevent/ 245TRACE_EVENT_DIR = ../lib/traceevent/
244 246
247LK_PATH=$(LK_DIR)
248
245ifneq ($(OUTPUT),) 249ifneq ($(OUTPUT),)
246 TE_PATH=$(OUTPUT) 250 TE_PATH=$(OUTPUT)
251ifneq ($(subdir),)
252 LK_PATH=$(OUTPUT)$(LK_DIR)
253else
254 LK_PATH=$(OUTPUT)
255endif
247else 256else
248 TE_PATH=$(TRACE_EVENT_DIR) 257 TE_PATH=$(TRACE_EVENT_DIR)
249endif 258endif
250 259
251LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 260LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
252TE_LIB := -L$(TE_PATH) -ltraceevent
253
254export LIBTRACEEVENT 261export LIBTRACEEVENT
255 262
263LIBLK = $(LK_PATH)liblk.a
264export LIBLK
265
256# python extension build directories 266# python extension build directories
257PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 267PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
258PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ 268PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -355,7 +365,6 @@ LIB_H += util/cache.h
355LIB_H += util/callchain.h 365LIB_H += util/callchain.h
356LIB_H += util/build-id.h 366LIB_H += util/build-id.h
357LIB_H += util/debug.h 367LIB_H += util/debug.h
358LIB_H += util/debugfs.h
359LIB_H += util/sysfs.h 368LIB_H += util/sysfs.h
360LIB_H += util/pmu.h 369LIB_H += util/pmu.h
361LIB_H += util/event.h 370LIB_H += util/event.h
@@ -416,7 +425,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
416LIB_OBJS += $(OUTPUT)util/build-id.o 425LIB_OBJS += $(OUTPUT)util/build-id.o
417LIB_OBJS += $(OUTPUT)util/config.o 426LIB_OBJS += $(OUTPUT)util/config.o
418LIB_OBJS += $(OUTPUT)util/ctype.o 427LIB_OBJS += $(OUTPUT)util/ctype.o
419LIB_OBJS += $(OUTPUT)util/debugfs.o
420LIB_OBJS += $(OUTPUT)util/sysfs.o 428LIB_OBJS += $(OUTPUT)util/sysfs.o
421LIB_OBJS += $(OUTPUT)util/pmu.o 429LIB_OBJS += $(OUTPUT)util/pmu.o
422LIB_OBJS += $(OUTPUT)util/environment.o 430LIB_OBJS += $(OUTPUT)util/environment.o
@@ -503,6 +511,10 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
503LIB_OBJS += $(OUTPUT)tests/pmu.o 511LIB_OBJS += $(OUTPUT)tests/pmu.o
504LIB_OBJS += $(OUTPUT)tests/hists_link.o 512LIB_OBJS += $(OUTPUT)tests/hists_link.o
505LIB_OBJS += $(OUTPUT)tests/python-use.o 513LIB_OBJS += $(OUTPUT)tests/python-use.o
514LIB_OBJS += $(OUTPUT)tests/bp_signal.o
515LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
516LIB_OBJS += $(OUTPUT)tests/task-exit.o
517LIB_OBJS += $(OUTPUT)tests/sw-clock.o
506 518
507BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 519BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
508BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 520BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -536,7 +548,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
536BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 548BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
537BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 549BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
538 550
539PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 551PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
540 552
541# 553#
542# Platform specific tweaks 554# Platform specific tweaks
@@ -1051,6 +1063,18 @@ $(LIBTRACEEVENT):
1051$(LIBTRACEEVENT)-clean: 1063$(LIBTRACEEVENT)-clean:
1052 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean 1064 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1053 1065
1066# if subdir is set, we've been called from above so target has been built
1067# already
1068$(LIBLK):
1069ifeq ($(subdir),)
1070 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
1071endif
1072
1073$(LIBLK)-clean:
1074ifeq ($(subdir),)
1075 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1076endif
1077
1054help: 1078help:
1055 @echo 'Perf make targets:' 1079 @echo 'Perf make targets:'
1056 @echo ' doc - make *all* documentation (see below)' 1080 @echo ' doc - make *all* documentation (see below)'
@@ -1171,7 +1195,7 @@ $(INSTALL_DOC_TARGETS):
1171 1195
1172### Cleaning rules 1196### Cleaning rules
1173 1197
1174clean: $(LIBTRACEEVENT)-clean 1198clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
1175 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 1199 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1176 $(RM) $(ALL_PROGRAMS) perf 1200 $(RM) $(ALL_PROGRAMS) perf
1177 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 1201 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
@@ -1181,6 +1205,6 @@ clean: $(LIBTRACEEVENT)-clean
1181 $(RM) $(OUTPUT)util/*-flex* 1205 $(RM) $(OUTPUT)util/*-flex*
1182 $(python-clean) 1206 $(python-clean)
1183 1207
1184.PHONY: all install clean strip $(LIBTRACEEVENT) 1208.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
1185.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 1209.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1186.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1210.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index e8d5c551c69c..33ec5b339da8 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,10 +8,7 @@
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11#include <stdlib.h> 11#include <stddef.h>
12#ifndef __UCLIBC__
13#include <libio.h>
14#endif
15#include <dwarf-regs.h> 12#include <dwarf-regs.h>
16 13
17struct pt_regs_dwarfnum { 14struct pt_regs_dwarfnum {
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 7cdd61d0e27c..733151cdf46e 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -9,10 +9,7 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <stdlib.h> 12#include <stddef.h>
13#ifndef __UCLIBC__
14#include <libio.h>
15#endif
16#include <dwarf-regs.h> 13#include <dwarf-regs.h>
17 14
18 15
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index e19653e025fa..0469df02ee62 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -6,7 +6,7 @@
6 * 6 *
7 */ 7 */
8 8
9#include <libio.h> 9#include <stddef.h>
10#include <dwarf-regs.h> 10#include <dwarf-regs.h>
11 11
12#define NUM_GPRS 16 12#define NUM_GPRS 16
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c
index a11edb007a6c..0d0897f57a10 100644
--- a/tools/perf/arch/sh/util/dwarf-regs.c
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -19,7 +19,7 @@
19 * 19 *
20 */ 20 */
21 21
22#include <libio.h> 22#include <stddef.h>
23#include <dwarf-regs.h> 23#include <dwarf-regs.h>
24 24
25/* 25/*
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c
index 0ab88483720c..92eda412fed3 100644
--- a/tools/perf/arch/sparc/util/dwarf-regs.c
+++ b/tools/perf/arch/sparc/util/dwarf-regs.c
@@ -9,7 +9,7 @@
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 */ 10 */
11 11
12#include <libio.h> 12#include <stddef.h>
13#include <dwarf-regs.h> 13#include <dwarf-regs.h>
14 14
15#define SPARC_MAX_REGS 96 15#define SPARC_MAX_REGS 96
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
index a794d3081928..be22dd463232 100644
--- a/tools/perf/arch/x86/util/dwarf-regs.c
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -20,7 +20,7 @@
20 * 20 *
21 */ 21 */
22 22
23#include <libio.h> 23#include <stddef.h>
24#include <dwarf-regs.h> 24#include <dwarf-regs.h>
25 25
26/* 26/*
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 2e6961ea3184..ae36f3cb5410 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -109,14 +109,16 @@ static int process_sample_event(struct perf_tool *tool,
109 return 0; 109 return 0;
110} 110}
111 111
112static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, 112static int hist_entry__tty_annotate(struct hist_entry *he,
113 struct perf_evsel *evsel,
113 struct perf_annotate *ann) 114 struct perf_annotate *ann)
114{ 115{
115 return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, 116 return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel,
116 ann->print_line, ann->full_paths, 0, 0); 117 ann->print_line, ann->full_paths, 0, 0);
117} 118}
118 119
119static void hists__find_annotations(struct hists *self, int evidx, 120static void hists__find_annotations(struct hists *self,
121 struct perf_evsel *evsel,
120 struct perf_annotate *ann) 122 struct perf_annotate *ann)
121{ 123{
122 struct rb_node *nd = rb_first(&self->entries), *next; 124 struct rb_node *nd = rb_first(&self->entries), *next;
@@ -142,14 +144,14 @@ find_next:
142 if (use_browser == 2) { 144 if (use_browser == 2) {
143 int ret; 145 int ret;
144 146
145 ret = hist_entry__gtk_annotate(he, evidx, NULL); 147 ret = hist_entry__gtk_annotate(he, evsel, NULL);
146 if (!ret || !ann->skip_missing) 148 if (!ret || !ann->skip_missing)
147 return; 149 return;
148 150
149 /* skip missing symbols */ 151 /* skip missing symbols */
150 nd = rb_next(nd); 152 nd = rb_next(nd);
151 } else if (use_browser == 1) { 153 } else if (use_browser == 1) {
152 key = hist_entry__tui_annotate(he, evidx, NULL); 154 key = hist_entry__tui_annotate(he, evsel, NULL);
153 switch (key) { 155 switch (key) {
154 case -1: 156 case -1:
155 if (!ann->skip_missing) 157 if (!ann->skip_missing)
@@ -168,7 +170,7 @@ find_next:
168 if (next != NULL) 170 if (next != NULL)
169 nd = next; 171 nd = next;
170 } else { 172 } else {
171 hist_entry__tty_annotate(he, evidx, ann); 173 hist_entry__tty_annotate(he, evsel, ann);
172 nd = rb_next(nd); 174 nd = rb_next(nd);
173 /* 175 /*
174 * Since we have a hist_entry per IP for the same 176 * Since we have a hist_entry per IP for the same
@@ -230,7 +232,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
230 total_nr_samples += nr_samples; 232 total_nr_samples += nr_samples;
231 hists__collapse_resort(hists); 233 hists__collapse_resort(hists);
232 hists__output_resort(hists); 234 hists__output_resort(hists);
233 hists__find_annotations(hists, pos->idx, ann); 235
236 if (symbol_conf.event_group &&
237 !perf_evsel__is_group_leader(pos))
238 continue;
239
240 hists__find_annotations(hists, pos, ann);
234 } 241 }
235 } 242 }
236 243
@@ -312,6 +319,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
312 "Specify disassembler style (e.g. -M intel for intel syntax)"), 319 "Specify disassembler style (e.g. -M intel for intel syntax)"),
313 OPT_STRING(0, "objdump", &objdump_path, "path", 320 OPT_STRING(0, "objdump", &objdump_path, "path",
314 "objdump binary to use for disassembly and annotations"), 321 "objdump binary to use for disassembly and annotations"),
322 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
323 "Show event group information together"),
315 OPT_END() 324 OPT_END()
316 }; 325 };
317 326
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 37a769d7f9fe..533501e2b07c 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -12,7 +12,7 @@
12#include "util/parse-options.h" 12#include "util/parse-options.h"
13#include "util/trace-event.h" 13#include "util/trace-event.h"
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/debugfs.h" 15#include <lk/debugfs.h>
16#include "util/tool.h" 16#include "util/tool.h"
17#include "util/stat.h" 17#include "util/stat.h"
18 18
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index de38a034b129..e8a66f9a6715 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 "util/debugfs.h" 40#include <lk/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"
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f1a939ebc19c..9f2344a2c506 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -474,7 +474,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
474 } 474 }
475 475
476 if (forks) { 476 if (forks) {
477 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 477 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
478 argv, opts->pipe_output,
479 true);
478 if (err < 0) { 480 if (err < 0) {
479 pr_err("Couldn't run the workload!\n"); 481 pr_err("Couldn't run the workload!\n");
480 goto out_delete_session; 482 goto out_delete_session;
@@ -964,7 +966,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
964 struct perf_record *rec = &record; 966 struct perf_record *rec = &record;
965 char errbuf[BUFSIZ]; 967 char errbuf[BUFSIZ];
966 968
967 evsel_list = perf_evlist__new(NULL, NULL); 969 evsel_list = perf_evlist__new();
968 if (evsel_list == NULL) 970 if (evsel_list == NULL)
969 return -ENOMEM; 971 return -ENOMEM;
970 972
@@ -1026,7 +1028,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1026 ui__error("%s", errbuf); 1028 ui__error("%s", errbuf);
1027 1029
1028 err = -saved_errno; 1030 err = -saved_errno;
1029 goto out_free_fd; 1031 goto out_symbol_exit;
1030 } 1032 }
1031 1033
1032 err = -ENOMEM; 1034 err = -ENOMEM;
@@ -1057,6 +1059,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1057 } 1059 }
1058 1060
1059 err = __cmd_record(&record, argc, argv); 1061 err = __cmd_record(&record, argc, argv);
1062
1063 perf_evlist__munmap(evsel_list);
1064 perf_evlist__close(evsel_list);
1060out_free_fd: 1065out_free_fd:
1061 perf_evlist__delete_maps(evsel_list); 1066 perf_evlist__delete_maps(evsel_list);
1062out_symbol_exit: 1067out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 96b5a7fee4bb..296bd219977a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -13,7 +13,6 @@
13#include "util/annotate.h" 13#include "util/annotate.h"
14#include "util/color.h" 14#include "util/color.h"
15#include <linux/list.h> 15#include <linux/list.h>
16#include "util/cache.h"
17#include <linux/rbtree.h> 16#include <linux/rbtree.h>
18#include "util/symbol.h" 17#include "util/symbol.h"
19#include "util/callchain.h" 18#include "util/callchain.h"
@@ -314,7 +313,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
314 char buf[512]; 313 char buf[512];
315 size_t size = sizeof(buf); 314 size_t size = sizeof(buf);
316 315
317 if (symbol_conf.event_group && evsel->nr_members > 1) { 316 if (perf_evsel__is_group_event(evsel)) {
318 struct perf_evsel *pos; 317 struct perf_evsel *pos;
319 318
320 perf_evsel__group_desc(evsel, buf, size); 319 perf_evsel__group_desc(evsel, buf, size);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 99848761f573..ba0bdd87c279 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -94,6 +94,7 @@ static const char *pre_cmd = NULL;
94static const char *post_cmd = NULL; 94static const char *post_cmd = NULL;
95static bool sync_run = false; 95static bool sync_run = false;
96static unsigned int interval = 0; 96static unsigned int interval = 0;
97static bool forever = false;
97static struct timespec ref_time; 98static struct timespec ref_time;
98static struct cpu_map *sock_map; 99static struct cpu_map *sock_map;
99 100
@@ -125,6 +126,11 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
125 return perf_evsel__cpus(evsel)->nr; 126 return perf_evsel__cpus(evsel)->nr;
126} 127}
127 128
129static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
130{
131 memset(evsel->priv, 0, sizeof(struct perf_stat));
132}
133
128static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 134static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
129{ 135{
130 evsel->priv = zalloc(sizeof(struct perf_stat)); 136 evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -160,6 +166,35 @@ static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
160 evsel->prev_raw_counts = NULL; 166 evsel->prev_raw_counts = NULL;
161} 167}
162 168
169static void perf_evlist__free_stats(struct perf_evlist *evlist)
170{
171 struct perf_evsel *evsel;
172
173 list_for_each_entry(evsel, &evlist->entries, node) {
174 perf_evsel__free_stat_priv(evsel);
175 perf_evsel__free_counts(evsel);
176 perf_evsel__free_prev_raw_counts(evsel);
177 }
178}
179
180static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
181{
182 struct perf_evsel *evsel;
183
184 list_for_each_entry(evsel, &evlist->entries, node) {
185 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
186 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
187 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
188 goto out_free;
189 }
190
191 return 0;
192
193out_free:
194 perf_evlist__free_stats(evlist);
195 return -1;
196}
197
163static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 198static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
164static struct stats runtime_cycles_stats[MAX_NR_CPUS]; 199static struct stats runtime_cycles_stats[MAX_NR_CPUS];
165static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 200static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
@@ -173,6 +208,29 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
173static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 208static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
174static struct stats walltime_nsecs_stats; 209static struct stats walltime_nsecs_stats;
175 210
211static void perf_stat__reset_stats(struct perf_evlist *evlist)
212{
213 struct perf_evsel *evsel;
214
215 list_for_each_entry(evsel, &evlist->entries, node) {
216 perf_evsel__reset_stat_priv(evsel);
217 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
218 }
219
220 memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
221 memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
222 memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
223 memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats));
224 memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats));
225 memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats));
226 memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats));
227 memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats));
228 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
229 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
230 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
231 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
232}
233
176static int create_perf_stat_counter(struct perf_evsel *evsel) 234static int create_perf_stat_counter(struct perf_evsel *evsel)
177{ 235{
178 struct perf_event_attr *attr = &evsel->attr; 236 struct perf_event_attr *attr = &evsel->attr;
@@ -249,7 +307,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
249 int i; 307 int i;
250 308
251 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), 309 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
252 evsel_list->threads->nr, scale) < 0) 310 thread_map__nr(evsel_list->threads), scale) < 0)
253 return -1; 311 return -1;
254 312
255 for (i = 0; i < 3; i++) 313 for (i = 0; i < 3; i++)
@@ -337,16 +395,14 @@ static void print_interval(void)
337 } 395 }
338} 396}
339 397
340static int __run_perf_stat(int argc __maybe_unused, const char **argv) 398static int __run_perf_stat(int argc, const char **argv)
341{ 399{
342 char msg[512]; 400 char msg[512];
343 unsigned long long t0, t1; 401 unsigned long long t0, t1;
344 struct perf_evsel *counter; 402 struct perf_evsel *counter;
345 struct timespec ts; 403 struct timespec ts;
346 int status = 0; 404 int status = 0;
347 int child_ready_pipe[2], go_pipe[2];
348 const bool forks = (argc > 0); 405 const bool forks = (argc > 0);
349 char buf;
350 406
351 if (interval) { 407 if (interval) {
352 ts.tv_sec = interval / 1000; 408 ts.tv_sec = interval / 1000;
@@ -362,55 +418,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
362 return -1; 418 return -1;
363 } 419 }
364 420
365 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
366 perror("failed to create pipes");
367 return -1;
368 }
369
370 if (forks) { 421 if (forks) {
371 if ((child_pid = fork()) < 0) 422 if (perf_evlist__prepare_workload(evsel_list, &target, argv,
372 perror("failed to fork"); 423 false, false) < 0) {
373 424 perror("failed to prepare workload");
374 if (!child_pid) { 425 return -1;
375 close(child_ready_pipe[0]);
376 close(go_pipe[1]);
377 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
378
379 /*
380 * Do a dummy execvp to get the PLT entry resolved,
381 * so we avoid the resolver overhead on the real
382 * execvp call.
383 */
384 execvp("", (char **)argv);
385
386 /*
387 * Tell the parent we're ready to go
388 */
389 close(child_ready_pipe[1]);
390
391 /*
392 * Wait until the parent tells us to go.
393 */
394 if (read(go_pipe[0], &buf, 1) == -1)
395 perror("unable to read pipe");
396
397 execvp(argv[0], (char **)argv);
398
399 perror(argv[0]);
400 exit(-1);
401 } 426 }
402
403 if (perf_target__none(&target))
404 evsel_list->threads->map[0] = child_pid;
405
406 /*
407 * Wait for the child to be ready to exec.
408 */
409 close(child_ready_pipe[1]);
410 close(go_pipe[0]);
411 if (read(child_ready_pipe[0], &buf, 1) == -1)
412 perror("unable to read pipe");
413 close(child_ready_pipe[0]);
414 } 427 }
415 428
416 if (group) 429 if (group)
@@ -457,7 +470,8 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
457 clock_gettime(CLOCK_MONOTONIC, &ref_time); 470 clock_gettime(CLOCK_MONOTONIC, &ref_time);
458 471
459 if (forks) { 472 if (forks) {
460 close(go_pipe[1]); 473 perf_evlist__start_workload(evsel_list);
474
461 if (interval) { 475 if (interval) {
462 while (!waitpid(child_pid, &status, WNOHANG)) { 476 while (!waitpid(child_pid, &status, WNOHANG)) {
463 nanosleep(&ts, NULL); 477 nanosleep(&ts, NULL);
@@ -488,7 +502,7 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
488 list_for_each_entry(counter, &evsel_list->entries, node) { 502 list_for_each_entry(counter, &evsel_list->entries, node) {
489 read_counter_aggr(counter); 503 read_counter_aggr(counter);
490 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 504 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
491 evsel_list->threads->nr); 505 thread_map__nr(evsel_list->threads));
492 } 506 }
493 } 507 }
494 508
@@ -1296,7 +1310,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1296 OPT_INCR('v', "verbose", &verbose, 1310 OPT_INCR('v', "verbose", &verbose,
1297 "be more verbose (show counter open errors, etc)"), 1311 "be more verbose (show counter open errors, etc)"),
1298 OPT_INTEGER('r', "repeat", &run_count, 1312 OPT_INTEGER('r', "repeat", &run_count,
1299 "repeat command and print average + stddev (max: 100)"), 1313 "repeat command and print average + stddev (max: 100, forever: 0)"),
1300 OPT_BOOLEAN('n', "null", &null_run, 1314 OPT_BOOLEAN('n', "null", &null_run,
1301 "null run - dont start any counters"), 1315 "null run - dont start any counters"),
1302 OPT_INCR('d', "detailed", &detailed_run, 1316 OPT_INCR('d', "detailed", &detailed_run,
@@ -1330,13 +1344,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1330 "perf stat [<options>] [<command>]", 1344 "perf stat [<options>] [<command>]",
1331 NULL 1345 NULL
1332 }; 1346 };
1333 struct perf_evsel *pos;
1334 int status = -ENOMEM, run_idx; 1347 int status = -ENOMEM, run_idx;
1335 const char *mode; 1348 const char *mode;
1336 1349
1337 setlocale(LC_ALL, ""); 1350 setlocale(LC_ALL, "");
1338 1351
1339 evsel_list = perf_evlist__new(NULL, NULL); 1352 evsel_list = perf_evlist__new();
1340 if (evsel_list == NULL) 1353 if (evsel_list == NULL)
1341 return -ENOMEM; 1354 return -ENOMEM;
1342 1355
@@ -1399,8 +1412,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1399 1412
1400 if (!argc && !perf_target__has_task(&target)) 1413 if (!argc && !perf_target__has_task(&target))
1401 usage_with_options(stat_usage, options); 1414 usage_with_options(stat_usage, options);
1402 if (run_count <= 0) 1415 if (run_count < 0) {
1403 usage_with_options(stat_usage, options); 1416 usage_with_options(stat_usage, options);
1417 } else if (run_count == 0) {
1418 forever = true;
1419 run_count = 1;
1420 }
1404 1421
1405 /* no_aggr, cgroup are for system-wide only */ 1422 /* no_aggr, cgroup are for system-wide only */
1406 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1423 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
@@ -1438,17 +1455,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1438 return -1; 1455 return -1;
1439 } 1456 }
1440 1457
1441 list_for_each_entry(pos, &evsel_list->entries, node) { 1458 if (perf_evlist__alloc_stats(evsel_list, interval))
1442 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1459 goto out_free_maps;
1443 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
1444 goto out_free_fd;
1445 }
1446 if (interval) {
1447 list_for_each_entry(pos, &evsel_list->entries, node) {
1448 if (perf_evsel__alloc_prev_raw_counts(pos) < 0)
1449 goto out_free_fd;
1450 }
1451 }
1452 1460
1453 /* 1461 /*
1454 * We dont want to block the signals - that would cause 1462 * We dont want to block the signals - that would cause
@@ -1457,28 +1465,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1457 * task, but being ignored by perf stat itself: 1465 * task, but being ignored by perf stat itself:
1458 */ 1466 */
1459 atexit(sig_atexit); 1467 atexit(sig_atexit);
1460 signal(SIGINT, skip_signal); 1468 if (!forever)
1469 signal(SIGINT, skip_signal);
1461 signal(SIGCHLD, skip_signal); 1470 signal(SIGCHLD, skip_signal);
1462 signal(SIGALRM, skip_signal); 1471 signal(SIGALRM, skip_signal);
1463 signal(SIGABRT, skip_signal); 1472 signal(SIGABRT, skip_signal);
1464 1473
1465 status = 0; 1474 status = 0;
1466 for (run_idx = 0; run_idx < run_count; run_idx++) { 1475 for (run_idx = 0; forever || run_idx < run_count; run_idx++) {
1467 if (run_count != 1 && verbose) 1476 if (run_count != 1 && verbose)
1468 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1477 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1469 run_idx + 1); 1478 run_idx + 1);
1470 1479
1471 status = run_perf_stat(argc, argv); 1480 status = run_perf_stat(argc, argv);
1481 if (forever && status != -1) {
1482 print_stat(argc, argv);
1483 perf_stat__reset_stats(evsel_list);
1484 }
1472 } 1485 }
1473 1486
1474 if (status != -1 && !interval) 1487 if (!forever && status != -1 && !interval)
1475 print_stat(argc, argv); 1488 print_stat(argc, argv);
1476out_free_fd: 1489
1477 list_for_each_entry(pos, &evsel_list->entries, node) { 1490 perf_evlist__free_stats(evsel_list);
1478 perf_evsel__free_stat_priv(pos); 1491out_free_maps:
1479 perf_evsel__free_counts(pos);
1480 perf_evsel__free_prev_raw_counts(pos);
1481 }
1482 perf_evlist__delete_maps(evsel_list); 1492 perf_evlist__delete_maps(evsel_list);
1483out: 1493out:
1484 perf_evlist__delete(evsel_list); 1494 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 72f6eb7b4173..b5520ad0dbb8 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -231,7 +231,7 @@ static void perf_top__show_details(struct perf_top *top)
231 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); 231 printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
232 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); 232 printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
233 233
234 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, 234 more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel,
235 0, top->sym_pcnt_filter, top->print_entries, 4); 235 0, top->sym_pcnt_filter, top->print_entries, 4);
236 if (top->zero) 236 if (top->zero)
237 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); 237 symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
@@ -1116,7 +1116,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1116 NULL 1116 NULL
1117 }; 1117 };
1118 1118
1119 top.evlist = perf_evlist__new(NULL, NULL); 1119 top.evlist = perf_evlist__new();
1120 if (top.evlist == NULL) 1120 if (top.evlist == NULL)
1121 return -ENOMEM; 1121 return -ENOMEM;
1122 1122
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index d222d7fc7e96..ab3ed4af1466 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -419,7 +419,7 @@ out_dump:
419 419
420static int trace__run(struct trace *trace, int argc, const char **argv) 420static int trace__run(struct trace *trace, int argc, const char **argv)
421{ 421{
422 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 422 struct perf_evlist *evlist = perf_evlist__new();
423 struct perf_evsel *evsel; 423 struct perf_evsel *evsel;
424 int err = -1, i; 424 int err = -1, i;
425 unsigned long before; 425 unsigned long before;
@@ -452,7 +452,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
452 err = trace__symbols_init(trace, evlist); 452 err = trace__symbols_init(trace, evlist);
453 if (err < 0) { 453 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n"); 454 printf("Problems initializing symbol libraries!\n");
455 goto out_delete_evlist; 455 goto out_delete_maps;
456 } 456 }
457 457
458 perf_evlist__config(evlist, &trace->opts); 458 perf_evlist__config(evlist, &trace->opts);
@@ -461,23 +461,24 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
461 signal(SIGINT, sig_handler); 461 signal(SIGINT, sig_handler);
462 462
463 if (forks) { 463 if (forks) {
464 err = perf_evlist__prepare_workload(evlist, &trace->opts, argv); 464 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
465 argv, false, false);
465 if (err < 0) { 466 if (err < 0) {
466 printf("Couldn't run the workload!\n"); 467 printf("Couldn't run the workload!\n");
467 goto out_delete_evlist; 468 goto out_delete_maps;
468 } 469 }
469 } 470 }
470 471
471 err = perf_evlist__open(evlist); 472 err = perf_evlist__open(evlist);
472 if (err < 0) { 473 if (err < 0) {
473 printf("Couldn't create the events: %s\n", strerror(errno)); 474 printf("Couldn't create the events: %s\n", strerror(errno));
474 goto out_delete_evlist; 475 goto out_delete_maps;
475 } 476 }
476 477
477 err = perf_evlist__mmap(evlist, UINT_MAX, false); 478 err = perf_evlist__mmap(evlist, UINT_MAX, false);
478 if (err < 0) { 479 if (err < 0) {
479 printf("Couldn't mmap the events: %s\n", strerror(errno)); 480 printf("Couldn't mmap the events: %s\n", strerror(errno));
480 goto out_delete_evlist; 481 goto out_close_evlist;
481 } 482 }
482 483
483 perf_evlist__enable(evlist); 484 perf_evlist__enable(evlist);
@@ -526,13 +527,6 @@ again:
526 continue; 527 continue;
527 } 528 }
528 529
529 if (sample.raw_data == NULL) {
530 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
531 perf_evsel__name(evsel), sample.tid,
532 sample.cpu, sample.raw_size);
533 continue;
534 }
535
536 handler = evsel->handler.func; 530 handler = evsel->handler.func;
537 handler(trace, evsel, &sample); 531 handler(trace, evsel, &sample);
538 } 532 }
@@ -540,7 +534,7 @@ again:
540 534
541 if (trace->nr_events == before) { 535 if (trace->nr_events == before) {
542 if (done) 536 if (done)
543 goto out_delete_evlist; 537 goto out_unmap_evlist;
544 538
545 poll(evlist->pollfd, evlist->nr_fds, -1); 539 poll(evlist->pollfd, evlist->nr_fds, -1);
546 } 540 }
@@ -550,6 +544,12 @@ again:
550 544
551 goto again; 545 goto again;
552 546
547out_unmap_evlist:
548 perf_evlist__munmap(evlist);
549out_close_evlist:
550 perf_evlist__close(evlist);
551out_delete_maps:
552 perf_evlist__delete_maps(evlist);
553out_delete_evlist: 553out_delete_evlist:
554 perf_evlist__delete(evlist); 554 perf_evlist__delete(evlist);
555out: 555out:
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 3e86bbd8c2d5..a28e31be6cb4 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -10,17 +10,17 @@ perf-buildid-list mainporcelain common
10perf-diff mainporcelain common 10perf-diff mainporcelain common
11perf-evlist mainporcelain common 11perf-evlist mainporcelain common
12perf-inject mainporcelain common 12perf-inject mainporcelain common
13perf-kmem mainporcelain common
14perf-kvm mainporcelain common
13perf-list mainporcelain common 15perf-list mainporcelain common
14perf-sched mainporcelain common 16perf-lock mainporcelain common
17perf-probe mainporcelain full
15perf-record mainporcelain common 18perf-record mainporcelain common
16perf-report mainporcelain common 19perf-report mainporcelain common
20perf-sched mainporcelain common
21perf-script mainporcelain common
17perf-stat mainporcelain common 22perf-stat mainporcelain common
23perf-test mainporcelain common
18perf-timechart mainporcelain common 24perf-timechart mainporcelain common
19perf-top mainporcelain common 25perf-top mainporcelain common
20perf-trace mainporcelain common 26perf-trace mainporcelain common
21perf-script mainporcelain common
22perf-probe mainporcelain full
23perf-kmem mainporcelain common
24perf-lock mainporcelain common
25perf-kvm mainporcelain common
26perf-test mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 095b88207cd3..f6ba7b73f40e 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 "util/debugfs.h" 16#include <lk/debugfs.h>
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char perf_usage_string[] = 19const char perf_usage_string[] =
@@ -193,13 +193,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
193 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 193 fprintf(stderr, "No directory given for --debugfs-dir.\n");
194 usage(perf_usage_string); 194 usage(perf_usage_string);
195 } 195 }
196 debugfs_set_path((*argv)[1]); 196 perf_debugfs_set_path((*argv)[1]);
197 if (envchanged) 197 if (envchanged)
198 *envchanged = 1; 198 *envchanged = 1;
199 (*argv)++; 199 (*argv)++;
200 (*argc)--; 200 (*argc)--;
201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
202 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 202 perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint); 203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
204 if (envchanged) 204 if (envchanged)
205 *envchanged = 1; 205 *envchanged = 1;
@@ -461,7 +461,7 @@ int main(int argc, const char **argv)
461 if (!cmd) 461 if (!cmd)
462 cmd = "perf-help"; 462 cmd = "perf-help";
463 /* get debugfs mount point from /proc/mounts */ 463 /* get debugfs mount point from /proc/mounts */
464 debugfs_mount(NULL); 464 perf_debugfs_mount(NULL);
465 /* 465 /*
466 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 466 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
467 * 467 *
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index bdcceb886f77..038de3ecb8cb 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -147,10 +147,15 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
147 147
148static int run_dir(const char *d, const char *perf) 148static int run_dir(const char *d, const char *perf)
149{ 149{
150 char v[] = "-vvvvv";
151 int vcnt = min(verbose, (int) sizeof(v) - 1);
150 char cmd[3*PATH_MAX]; 152 char cmd[3*PATH_MAX];
151 153
152 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s", 154 if (verbose)
153 d, d, perf, verbose ? "-v" : ""); 155 vcnt++;
156
157 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
158 d, d, perf, vcnt, v);
154 159
155 return system(cmd); 160 return system(cmd);
156} 161}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index 2f629ca485bc..c9b4b6269b51 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -24,6 +24,7 @@ class Unsup(Exception):
24 24
25class Event(dict): 25class Event(dict):
26 terms = [ 26 terms = [
27 'cpu',
27 'flags', 28 'flags',
28 'type', 29 'type',
29 'size', 30 'size',
@@ -121,7 +122,7 @@ class Test(object):
121 parser = ConfigParser.SafeConfigParser() 122 parser = ConfigParser.SafeConfigParser()
122 parser.read(path) 123 parser.read(path)
123 124
124 log.debug("running '%s'" % path) 125 log.warning("running '%s'" % path)
125 126
126 self.path = path 127 self.path = path
127 self.test_dir = options.test_dir 128 self.test_dir = options.test_dir
@@ -172,7 +173,7 @@ class Test(object):
172 self.perf, self.command, tempdir, self.args) 173 self.perf, self.command, tempdir, self.args)
173 ret = os.WEXITSTATUS(os.system(cmd)) 174 ret = os.WEXITSTATUS(os.system(cmd))
174 175
175 log.warning(" running '%s' ret %d " % (cmd, ret)) 176 log.info(" '%s' ret %d " % (cmd, ret))
176 177
177 if ret != int(self.ret): 178 if ret != int(self.ret):
178 raise Unsup(self) 179 raise Unsup(self)
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index 5bc3880f7be5..b4fc835de607 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -2,6 +2,7 @@
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4flags=0
5cpu=*
5type=0|1 6type=0|1
6size=96 7size=96
7config=0 8config=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 4bd79a82784f..748ee949a204 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -2,6 +2,7 @@
2fd=1 2fd=1
3group_fd=-1 3group_fd=-1
4flags=0 4flags=0
5cpu=*
5type=0 6type=0
6size=96 7size=96
7config=0 8config=0
diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0
new file mode 100644
index 000000000000..d6a7e43f61b3
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-C0
@@ -0,0 +1,13 @@
1[config]
2command = record
3args = -C 0 kill >/dev/null 2>&1
4
5[event:base-record]
6cpu=0
7
8# no enable on exec for CPU attached
9enable_on_exec=0
10
11# PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD
12# + PERF_SAMPLE_CPU added by -C 0
13sample_type=391
diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/attr/test-stat-C0
new file mode 100644
index 000000000000..aa835950751f
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-C0
@@ -0,0 +1,9 @@
1[config]
2command = stat
3args = -e cycles -C 0 kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
7# events are enabled by default when attached to cpu
8disabled=0
9enable_on_exec=0
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
new file mode 100644
index 000000000000..68daa289e94c
--- /dev/null
+++ b/tools/perf/tests/bp_signal.c
@@ -0,0 +1,186 @@
1/*
2 * Inspired by breakpoint overflow test done by
3 * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
4 * (git://github.com/deater/perf_event_tests)
5 */
6
7#include <stdlib.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <string.h>
11#include <sys/ioctl.h>
12#include <time.h>
13#include <fcntl.h>
14#include <signal.h>
15#include <sys/mman.h>
16#include <linux/compiler.h>
17#include <linux/hw_breakpoint.h>
18
19#include "tests.h"
20#include "debug.h"
21#include "perf.h"
22
23static int fd1;
24static int fd2;
25static int overflows;
26
27__attribute__ ((noinline))
28static int test_function(void)
29{
30 return time(NULL);
31}
32
33static void sig_handler(int signum __maybe_unused,
34 siginfo_t *oh __maybe_unused,
35 void *uc __maybe_unused)
36{
37 overflows++;
38
39 if (overflows > 10) {
40 /*
41 * This should be executed only once during
42 * this test, if we are here for the 10th
43 * time, consider this the recursive issue.
44 *
45 * We can get out of here by disable events,
46 * so no new SIGIO is delivered.
47 */
48 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
49 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
50 }
51}
52
53static int bp_event(void *fn, int setup_signal)
54{
55 struct perf_event_attr pe;
56 int fd;
57
58 memset(&pe, 0, sizeof(struct perf_event_attr));
59 pe.type = PERF_TYPE_BREAKPOINT;
60 pe.size = sizeof(struct perf_event_attr);
61
62 pe.config = 0;
63 pe.bp_type = HW_BREAKPOINT_X;
64 pe.bp_addr = (unsigned long) fn;
65 pe.bp_len = sizeof(long);
66
67 pe.sample_period = 1;
68 pe.sample_type = PERF_SAMPLE_IP;
69 pe.wakeup_events = 1;
70
71 pe.disabled = 1;
72 pe.exclude_kernel = 1;
73 pe.exclude_hv = 1;
74
75 fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
76 if (fd < 0) {
77 pr_debug("failed opening event %llx\n", pe.config);
78 return TEST_FAIL;
79 }
80
81 if (setup_signal) {
82 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
83 fcntl(fd, F_SETSIG, SIGIO);
84 fcntl(fd, F_SETOWN, getpid());
85 }
86
87 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
88
89 return fd;
90}
91
92static long long bp_count(int fd)
93{
94 long long count;
95 int ret;
96
97 ret = read(fd, &count, sizeof(long long));
98 if (ret != sizeof(long long)) {
99 pr_debug("failed to read: %d\n", ret);
100 return TEST_FAIL;
101 }
102
103 return count;
104}
105
106int test__bp_signal(void)
107{
108 struct sigaction sa;
109 long long count1, count2;
110
111 /* setup SIGIO signal handler */
112 memset(&sa, 0, sizeof(struct sigaction));
113 sa.sa_sigaction = (void *) sig_handler;
114 sa.sa_flags = SA_SIGINFO;
115
116 if (sigaction(SIGIO, &sa, NULL) < 0) {
117 pr_debug("failed setting up signal handler\n");
118 return TEST_FAIL;
119 }
120
121 /*
122 * We create following events:
123 *
124 * fd1 - breakpoint event on test_function with SIGIO
125 * signal configured. We should get signal
126 * notification each time the breakpoint is hit
127 *
128 * fd2 - breakpoint event on sig_handler without SIGIO
129 * configured.
130 *
131 * Following processing should happen:
132 * - execute test_function
133 * - fd1 event breakpoint hit -> count1 == 1
134 * - SIGIO is delivered -> overflows == 1
135 * - fd2 event breakpoint hit -> count2 == 1
136 *
137 * The test case check following error conditions:
138 * - we get stuck in signal handler because of debug
139 * exception being triggered receursively due to
140 * the wrong RF EFLAG management
141 *
142 * - we never trigger the sig_handler breakpoint due
143 * to the rong RF EFLAG management
144 *
145 */
146
147 fd1 = bp_event(test_function, 1);
148 fd2 = bp_event(sig_handler, 0);
149
150 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
151 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
152
153 /*
154 * Kick off the test by trigering 'fd1'
155 * breakpoint.
156 */
157 test_function();
158
159 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
160 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
161
162 count1 = bp_count(fd1);
163 count2 = bp_count(fd2);
164
165 close(fd1);
166 close(fd2);
167
168 pr_debug("count1 %lld, count2 %lld, overflow %d\n",
169 count1, count2, overflows);
170
171 if (count1 != 1) {
172 if (count1 == 11)
173 pr_debug("failed: RF EFLAG recursion issue detected\n");
174 else
175 pr_debug("failed: wrong count for bp1%lld\n", count1);
176 }
177
178 if (overflows != 1)
179 pr_debug("failed: wrong overflow hit\n");
180
181 if (count2 != 1)
182 pr_debug("failed: wrong count for bp2\n");
183
184 return count1 == 1 && overflows == 1 && count2 == 1 ?
185 TEST_OK : TEST_FAIL;
186}
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
new file mode 100644
index 000000000000..fe7ed28815f8
--- /dev/null
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -0,0 +1,126 @@
1/*
2 * Originally done by Vince Weaver <vincent.weaver@maine.edu> for
3 * perf_event_tests (git://github.com/deater/perf_event_tests)
4 */
5
6#include <stdlib.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <string.h>
10#include <sys/ioctl.h>
11#include <time.h>
12#include <fcntl.h>
13#include <signal.h>
14#include <sys/mman.h>
15#include <linux/compiler.h>
16#include <linux/hw_breakpoint.h>
17
18#include "tests.h"
19#include "debug.h"
20#include "perf.h"
21
22static int overflows;
23
24__attribute__ ((noinline))
25static int test_function(void)
26{
27 return time(NULL);
28}
29
30static void sig_handler(int signum __maybe_unused,
31 siginfo_t *oh __maybe_unused,
32 void *uc __maybe_unused)
33{
34 overflows++;
35}
36
37static long long bp_count(int fd)
38{
39 long long count;
40 int ret;
41
42 ret = read(fd, &count, sizeof(long long));
43 if (ret != sizeof(long long)) {
44 pr_debug("failed to read: %d\n", ret);
45 return TEST_FAIL;
46 }
47
48 return count;
49}
50
51#define EXECUTIONS 10000
52#define THRESHOLD 100
53
54int test__bp_signal_overflow(void)
55{
56 struct perf_event_attr pe;
57 struct sigaction sa;
58 long long count;
59 int fd, i, fails = 0;
60
61 /* setup SIGIO signal handler */
62 memset(&sa, 0, sizeof(struct sigaction));
63 sa.sa_sigaction = (void *) sig_handler;
64 sa.sa_flags = SA_SIGINFO;
65
66 if (sigaction(SIGIO, &sa, NULL) < 0) {
67 pr_debug("failed setting up signal handler\n");
68 return TEST_FAIL;
69 }
70
71 memset(&pe, 0, sizeof(struct perf_event_attr));
72 pe.type = PERF_TYPE_BREAKPOINT;
73 pe.size = sizeof(struct perf_event_attr);
74
75 pe.config = 0;
76 pe.bp_type = HW_BREAKPOINT_X;
77 pe.bp_addr = (unsigned long) test_function;
78 pe.bp_len = sizeof(long);
79
80 pe.sample_period = THRESHOLD;
81 pe.sample_type = PERF_SAMPLE_IP;
82 pe.wakeup_events = 1;
83
84 pe.disabled = 1;
85 pe.exclude_kernel = 1;
86 pe.exclude_hv = 1;
87
88 fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
89 if (fd < 0) {
90 pr_debug("failed opening event %llx\n", pe.config);
91 return TEST_FAIL;
92 }
93
94 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
95 fcntl(fd, F_SETSIG, SIGIO);
96 fcntl(fd, F_SETOWN, getpid());
97
98 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
99 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
100
101 for (i = 0; i < EXECUTIONS; i++)
102 test_function();
103
104 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
105
106 count = bp_count(fd);
107
108 close(fd);
109
110 pr_debug("count %lld, overflow %d\n",
111 count, overflows);
112
113 if (count != EXECUTIONS) {
114 pr_debug("\tWrong number of executions %lld != %d\n",
115 count, EXECUTIONS);
116 fails++;
117 }
118
119 if (overflows != EXECUTIONS / THRESHOLD) {
120 pr_debug("\tWrong number of overflows %d != %d\n",
121 overflows, EXECUTIONS / THRESHOLD);
122 fails++;
123 }
124
125 return fails ? TEST_FAIL : TEST_OK;
126}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index acb98e0e39f2..0918ada4cc41 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -78,6 +78,22 @@ static struct test {
78 .func = test__python_use, 78 .func = test__python_use,
79 }, 79 },
80 { 80 {
81 .desc = "Test breakpoint overflow signal handler",
82 .func = test__bp_signal,
83 },
84 {
85 .desc = "Test breakpoint overflow sampling",
86 .func = test__bp_signal_overflow,
87 },
88 {
89 .desc = "Test number of exit event of a simple workload",
90 .func = test__task_exit,
91 },
92 {
93 .desc = "Test software clock events have valid period values",
94 .func = test__sw_clock_freq,
95 },
96 {
81 .func = NULL, 97 .func = NULL,
82 }, 98 },
83}; 99};
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 0fd99a9adb91..0197bda9c461 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -8,7 +8,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
8 char name[128]; 8 char name[128];
9 int type, op, err = 0, ret = 0, i, idx; 9 int type, op, err = 0, ret = 0, i, idx;
10 struct perf_evsel *evsel; 10 struct perf_evsel *evsel;
11 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 11 struct perf_evlist *evlist = perf_evlist__new();
12 12
13 if (evlist == NULL) 13 if (evlist == NULL)
14 return -ENOMEM; 14 return -ENOMEM;
@@ -64,7 +64,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
64{ 64{
65 int i, err; 65 int i, err;
66 struct perf_evsel *evsel; 66 struct perf_evsel *evsel;
67 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 67 struct perf_evlist *evlist = perf_evlist__new();
68 68
69 if (evlist == NULL) 69 if (evlist == NULL)
70 return -ENOMEM; 70 return -ENOMEM;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 1be64a6c5daf..e0c0267858a1 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -436,7 +436,7 @@ int test__hists_link(void)
436 struct machines machines; 436 struct machines machines;
437 struct machine *machine = NULL; 437 struct machine *machine = NULL;
438 struct perf_evsel *evsel, *first; 438 struct perf_evsel *evsel, *first;
439 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 439 struct perf_evlist *evlist = perf_evlist__new();
440 440
441 if (evlist == NULL) 441 if (evlist == NULL)
442 return -ENOMEM; 442 return -ENOMEM;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index cdd50755af51..5b1b5aba722b 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -53,12 +53,14 @@ int test__basic_mmap(void)
53 goto out_free_cpus; 53 goto out_free_cpus;
54 } 54 }
55 55
56 evlist = perf_evlist__new(cpus, threads); 56 evlist = perf_evlist__new();
57 if (evlist == NULL) { 57 if (evlist == NULL) {
58 pr_debug("perf_evlist__new\n"); 58 pr_debug("perf_evlist__new\n");
59 goto out_free_cpus; 59 goto out_free_cpus;
60 } 60 }
61 61
62 perf_evlist__set_maps(evlist, cpus, threads);
63
62 for (i = 0; i < nsyscalls; ++i) { 64 for (i = 0; i < nsyscalls; ++i) {
63 char name[64]; 65 char name[64];
64 66
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 1c52fdc1164e..fc5b9fca8b47 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -18,7 +18,7 @@ int test__syscall_open_tp_fields(void)
18 }; 18 };
19 const char *filename = "/etc/passwd"; 19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY; 20 int flags = O_RDONLY | O_DIRECTORY;
21 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 21 struct perf_evlist *evlist = perf_evlist__new();
22 struct perf_evsel *evsel; 22 struct perf_evsel *evsel;
23 int err = -1, i, nr_events = 0, nr_polls = 0; 23 int err = -1, i, nr_events = 0, nr_polls = 0;
24 24
@@ -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_evlist; 51 goto out_delete_maps;
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_delete_evlist; 57 goto out_close_evlist;
58 } 58 }
59 59
60 perf_evlist__enable(evlist); 60 perf_evlist__enable(evlist);
@@ -110,6 +110,10 @@ out_ok:
110 err = 0; 110 err = 0;
111out_munmap: 111out_munmap:
112 perf_evlist__munmap(evlist); 112 perf_evlist__munmap(evlist);
113out_close_evlist:
114 perf_evlist__close(evlist);
115out_delete_maps:
116 perf_evlist__delete_maps(evlist);
113out_delete_evlist: 117out_delete_evlist:
114 perf_evlist__delete(evlist); 118 perf_evlist__delete(evlist);
115out: 119out:
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index c5636f36fe31..88e2f44cb157 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 "sysfs.h" 5#include "sysfs.h"
6#include "debugfs.h" 6#include <lk/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
9 9
@@ -1218,7 +1218,7 @@ static int test_event(struct evlist_test *e)
1218 struct perf_evlist *evlist; 1218 struct perf_evlist *evlist;
1219 int ret; 1219 int ret;
1220 1220
1221 evlist = perf_evlist__new(NULL, NULL); 1221 evlist = perf_evlist__new();
1222 if (evlist == NULL) 1222 if (evlist == NULL)
1223 return -ENOMEM; 1223 return -ENOMEM;
1224 1224
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 1e8e5128d0da..72d8881873b0 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -45,7 +45,7 @@ int test__PERF_RECORD(void)
45 }; 45 };
46 cpu_set_t cpu_mask; 46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 48 struct perf_evlist *evlist = perf_evlist__new();
49 struct perf_evsel *evsel; 49 struct perf_evsel *evsel;
50 struct perf_sample sample; 50 struct perf_sample sample;
51 const char *cmd = "sleep"; 51 const char *cmd = "sleep";
@@ -93,7 +93,8 @@ int test__PERF_RECORD(void)
93 * so that we have time to open the evlist (calling sys_perf_event_open 93 * so that we have time to open the evlist (calling sys_perf_event_open
94 * on all the fds) and then mmap them. 94 * on all the fds) and then mmap them.
95 */ 95 */
96 err = perf_evlist__prepare_workload(evlist, &opts, argv); 96 err = perf_evlist__prepare_workload(evlist, &opts.target, argv,
97 false, false);
97 if (err < 0) { 98 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n"); 99 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_maps; 100 goto out_delete_maps;
@@ -142,7 +143,7 @@ int test__PERF_RECORD(void)
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 143 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) { 144 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 145 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_maps; 146 goto out_close_evlist;
146 } 147 }
147 148
148 /* 149 /*
@@ -305,6 +306,8 @@ found_exit:
305 } 306 }
306out_err: 307out_err:
307 perf_evlist__munmap(evlist); 308 perf_evlist__munmap(evlist);
309out_close_evlist:
310 perf_evlist__close(evlist);
308out_delete_maps: 311out_delete_maps:
309 perf_evlist__delete_maps(evlist); 312 perf_evlist__delete_maps(evlist);
310out_delete_evlist: 313out_delete_evlist:
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
new file mode 100644
index 000000000000..2e41e2d32ccc
--- /dev/null
+++ b/tools/perf/tests/sw-clock.c
@@ -0,0 +1,119 @@
1#include <unistd.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <sys/mman.h>
5
6#include "tests.h"
7#include "util/evsel.h"
8#include "util/evlist.h"
9#include "util/cpumap.h"
10#include "util/thread_map.h"
11
12#define NR_LOOPS 1000000
13
14/*
15 * This test will open software clock events (cpu-clock, task-clock)
16 * then check their frequency -> period conversion has no artifact of
17 * setting period to 1 forcefully.
18 */
19static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
20{
21 int i, err = -1;
22 volatile int tmp = 0;
23 u64 total_periods = 0;
24 int nr_samples = 0;
25 union perf_event *event;
26 struct perf_evsel *evsel;
27 struct perf_evlist *evlist;
28 struct perf_event_attr attr = {
29 .type = PERF_TYPE_SOFTWARE,
30 .config = clock_id,
31 .sample_type = PERF_SAMPLE_PERIOD,
32 .exclude_kernel = 1,
33 .disabled = 1,
34 .freq = 1,
35 };
36
37 attr.sample_freq = 10000;
38
39 evlist = perf_evlist__new();
40 if (evlist == NULL) {
41 pr_debug("perf_evlist__new\n");
42 return -1;
43 }
44
45 evsel = perf_evsel__new(&attr, 0);
46 if (evsel == NULL) {
47 pr_debug("perf_evsel__new\n");
48 goto out_free_evlist;
49 }
50 perf_evlist__add(evlist, evsel);
51
52 evlist->cpus = cpu_map__dummy_new();
53 evlist->threads = thread_map__new_by_tid(getpid());
54 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps;
58 }
59
60 perf_evlist__open(evlist);
61
62 err = perf_evlist__mmap(evlist, 128, true);
63 if (err < 0) {
64 pr_debug("failed to mmap event: %d (%s)\n", errno,
65 strerror(errno));
66 goto out_close_evlist;
67 }
68
69 perf_evlist__enable(evlist);
70
71 /* collect samples */
72 for (i = 0; i < NR_LOOPS; i++)
73 tmp++;
74
75 perf_evlist__disable(evlist);
76
77 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
78 struct perf_sample sample;
79
80 if (event->header.type != PERF_RECORD_SAMPLE)
81 continue;
82
83 err = perf_evlist__parse_sample(evlist, event, &sample);
84 if (err < 0) {
85 pr_debug("Error during parse sample\n");
86 goto out_unmap_evlist;
87 }
88
89 total_periods += sample.period;
90 nr_samples++;
91 }
92
93 if ((u64) nr_samples == total_periods) {
94 pr_debug("All (%d) samples have period value of 1!\n",
95 nr_samples);
96 err = -1;
97 }
98
99out_unmap_evlist:
100 perf_evlist__munmap(evlist);
101out_close_evlist:
102 perf_evlist__close(evlist);
103out_delete_maps:
104 perf_evlist__delete_maps(evlist);
105out_free_evlist:
106 perf_evlist__delete(evlist);
107 return err;
108}
109
110int test__sw_clock_freq(void)
111{
112 int ret;
113
114 ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK);
115 if (!ret)
116 ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK);
117
118 return ret;
119}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
new file mode 100644
index 000000000000..28fe5894b061
--- /dev/null
+++ b/tools/perf/tests/task-exit.c
@@ -0,0 +1,123 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "tests.h"
6
7#include <signal.h>
8
9static int exited;
10static int nr_exit;
11
12static void sig_handler(int sig)
13{
14 exited = 1;
15
16 if (sig == SIGUSR1)
17 nr_exit = -1;
18}
19
20/*
21 * This test will start a workload that does nothing then it checks
22 * if the number of exit event reported by the kernel is 1 or not
23 * in order to check the kernel returns correct number of event.
24 */
25int test__task_exit(void)
26{
27 int err = -1;
28 union perf_event *event;
29 struct perf_evsel *evsel;
30 struct perf_evlist *evlist;
31 struct perf_target target = {
32 .uid = UINT_MAX,
33 .uses_mmap = true,
34 };
35 const char *argv[] = { "true", NULL };
36
37 signal(SIGCHLD, sig_handler);
38 signal(SIGUSR1, sig_handler);
39
40 evlist = perf_evlist__new();
41 if (evlist == NULL) {
42 pr_debug("perf_evlist__new\n");
43 return -1;
44 }
45 /*
46 * We need at least one evsel in the evlist, use the default
47 * one: "cycles".
48 */
49 err = perf_evlist__add_default(evlist);
50 if (err < 0) {
51 pr_debug("Not enough memory to create evsel\n");
52 goto out_free_evlist;
53 }
54
55 /*
56 * Create maps of threads and cpus to monitor. In this case
57 * we start with all threads and cpus (-1, -1) but then in
58 * perf_evlist__prepare_workload we'll fill in the only thread
59 * we're monitoring, the one forked there.
60 */
61 evlist->cpus = cpu_map__dummy_new();
62 evlist->threads = thread_map__new_by_tid(-1);
63 if (!evlist->cpus || !evlist->threads) {
64 err = -ENOMEM;
65 pr_debug("Not enough memory to create thread/cpu maps\n");
66 goto out_delete_maps;
67 }
68
69 err = perf_evlist__prepare_workload(evlist, &target, argv, false, true);
70 if (err < 0) {
71 pr_debug("Couldn't run the workload!\n");
72 goto out_delete_maps;
73 }
74
75 evsel = perf_evlist__first(evlist);
76 evsel->attr.task = 1;
77 evsel->attr.sample_freq = 0;
78 evsel->attr.inherit = 0;
79 evsel->attr.watermark = 0;
80 evsel->attr.wakeup_events = 1;
81 evsel->attr.exclude_kernel = 1;
82
83 err = perf_evlist__open(evlist);
84 if (err < 0) {
85 pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
86 goto out_delete_maps;
87 }
88
89 if (perf_evlist__mmap(evlist, 128, true) < 0) {
90 pr_debug("failed to mmap events: %d (%s)\n", errno,
91 strerror(errno));
92 goto out_close_evlist;
93 }
94
95 perf_evlist__start_workload(evlist);
96
97retry:
98 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
99 if (event->header.type != PERF_RECORD_EXIT)
100 continue;
101
102 nr_exit++;
103 }
104
105 if (!exited || !nr_exit) {
106 poll(evlist->pollfd, evlist->nr_fds, -1);
107 goto retry;
108 }
109
110 if (nr_exit != 1) {
111 pr_debug("received %d EXIT records\n", nr_exit);
112 err = -1;
113 }
114
115 perf_evlist__munmap(evlist);
116out_close_evlist:
117 perf_evlist__close(evlist);
118out_delete_maps:
119 perf_evlist__delete_maps(evlist);
120out_free_evlist:
121 perf_evlist__delete(evlist);
122 return err;
123}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 5de0be1ff4b6..dd7feae2d37b 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -23,5 +23,9 @@ int test__dso_data(void);
23int test__parse_events(void); 23int test__parse_events(void);
24int test__hists_link(void); 24int test__hists_link(void);
25int test__python_use(void); 25int test__python_use(void);
26int test__bp_signal(void);
27int test__bp_signal_overflow(void);
28int test__task_exit(void);
29int test__sw_clock_freq(void);
26 30
27#endif /* TESTS_H */ 31#endif /* TESTS_H */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 7dca1555c610..f56247a03a22 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -8,15 +8,20 @@
8#include "../../util/hist.h" 8#include "../../util/hist.h"
9#include "../../util/sort.h" 9#include "../../util/sort.h"
10#include "../../util/symbol.h" 10#include "../../util/symbol.h"
11#include "../../util/evsel.h"
11#include <pthread.h> 12#include <pthread.h>
12#include <newt.h> 13#include <newt.h>
13 14
14struct browser_disasm_line { 15struct browser_disasm_line {
15 struct rb_node rb_node; 16 struct rb_node rb_node;
16 double percent;
17 u32 idx; 17 u32 idx;
18 int idx_asm; 18 int idx_asm;
19 int jump_sources; 19 int jump_sources;
20 /*
21 * actual length of this array is saved on the nr_events field
22 * of the struct annotate_browser
23 */
24 double percent[1];
20}; 25};
21 26
22static struct annotate_browser_opt { 27static struct annotate_browser_opt {
@@ -33,8 +38,9 @@ struct annotate_browser {
33 struct ui_browser b; 38 struct ui_browser b;
34 struct rb_root entries; 39 struct rb_root entries;
35 struct rb_node *curr_hot; 40 struct rb_node *curr_hot;
36 struct disasm_line *selection; 41 struct disasm_line *selection;
37 struct disasm_line **offsets; 42 struct disasm_line **offsets;
43 int nr_events;
38 u64 start; 44 u64 start;
39 int nr_asm_entries; 45 int nr_asm_entries;
40 int nr_entries; 46 int nr_entries;
@@ -94,14 +100,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
94 (!current_entry || (browser->use_navkeypressed && 100 (!current_entry || (browser->use_navkeypressed &&
95 !browser->navkeypressed))); 101 !browser->navkeypressed)));
96 int width = browser->width, printed; 102 int width = browser->width, printed;
103 int i, pcnt_width = 7 * ab->nr_events;
104 double percent_max = 0.0;
97 char bf[256]; 105 char bf[256];
98 106
99 if (dl->offset != -1 && bdl->percent != 0.0) { 107 for (i = 0; i < ab->nr_events; i++) {
100 ui_browser__set_percent_color(browser, bdl->percent, current_entry); 108 if (bdl->percent[i] > percent_max)
101 slsmg_printf("%6.2f ", bdl->percent); 109 percent_max = bdl->percent[i];
110 }
111
112 if (dl->offset != -1 && percent_max != 0.0) {
113 for (i = 0; i < ab->nr_events; i++) {
114 ui_browser__set_percent_color(browser, bdl->percent[i],
115 current_entry);
116 slsmg_printf("%6.2f ", bdl->percent[i]);
117 }
102 } else { 118 } else {
103 ui_browser__set_percent_color(browser, 0, current_entry); 119 ui_browser__set_percent_color(browser, 0, current_entry);
104 slsmg_write_nstring(" ", 7); 120 slsmg_write_nstring(" ", pcnt_width);
105 } 121 }
106 122
107 SLsmg_write_char(' '); 123 SLsmg_write_char(' ');
@@ -111,12 +127,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
111 width += 1; 127 width += 1;
112 128
113 if (!*dl->line) 129 if (!*dl->line)
114 slsmg_write_nstring(" ", width - 7); 130 slsmg_write_nstring(" ", width - pcnt_width);
115 else if (dl->offset == -1) { 131 else if (dl->offset == -1) {
116 printed = scnprintf(bf, sizeof(bf), "%*s ", 132 printed = scnprintf(bf, sizeof(bf), "%*s ",
117 ab->addr_width, " "); 133 ab->addr_width, " ");
118 slsmg_write_nstring(bf, printed); 134 slsmg_write_nstring(bf, printed);
119 slsmg_write_nstring(dl->line, width - printed - 6); 135 slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
120 } else { 136 } else {
121 u64 addr = dl->offset; 137 u64 addr = dl->offset;
122 int color = -1; 138 int color = -1;
@@ -175,7 +191,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
175 } 191 }
176 192
177 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 193 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
178 slsmg_write_nstring(bf, width - 10 - printed); 194 slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
179 } 195 }
180 196
181 if (current_entry) 197 if (current_entry)
@@ -200,6 +216,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
200 unsigned int from, to; 216 unsigned int from, to;
201 struct map_symbol *ms = ab->b.priv; 217 struct map_symbol *ms = ab->b.priv;
202 struct symbol *sym = ms->sym; 218 struct symbol *sym = ms->sym;
219 u8 pcnt_width = 7;
203 220
204 /* PLT symbols contain external offsets */ 221 /* PLT symbols contain external offsets */
205 if (strstr(sym->name, "@plt")) 222 if (strstr(sym->name, "@plt"))
@@ -223,57 +240,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
223 to = (u64)btarget->idx; 240 to = (u64)btarget->idx;
224 } 241 }
225 242
243 pcnt_width *= ab->nr_events;
244
226 ui_browser__set_color(browser, HE_COLORSET_CODE); 245 ui_browser__set_color(browser, HE_COLORSET_CODE);
227 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); 246 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
247 from, to);
228} 248}
229 249
230static unsigned int annotate_browser__refresh(struct ui_browser *browser) 250static unsigned int annotate_browser__refresh(struct ui_browser *browser)
231{ 251{
252 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
232 int ret = ui_browser__list_head_refresh(browser); 253 int ret = ui_browser__list_head_refresh(browser);
254 int pcnt_width;
255
256 pcnt_width = 7 * ab->nr_events;
233 257
234 if (annotate_browser__opts.jump_arrows) 258 if (annotate_browser__opts.jump_arrows)
235 annotate_browser__draw_current_jump(browser); 259 annotate_browser__draw_current_jump(browser);
236 260
237 ui_browser__set_color(browser, HE_COLORSET_NORMAL); 261 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
238 __ui_browser__vline(browser, 7, 0, browser->height - 1); 262 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
239 return ret; 263 return ret;
240} 264}
241 265
242static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) 266static int disasm__cmp(struct browser_disasm_line *a,
267 struct browser_disasm_line *b, int nr_pcnt)
243{ 268{
244 double percent = 0.0; 269 int i;
245
246 if (dl->offset != -1) {
247 int len = sym->end - sym->start;
248 unsigned int hits = 0;
249 struct annotation *notes = symbol__annotation(sym);
250 struct source_line *src_line = notes->src->lines;
251 struct sym_hist *h = annotation__histogram(notes, evidx);
252 s64 offset = dl->offset;
253 struct disasm_line *next;
254 270
255 next = disasm__get_next_ip_line(&notes->src->source, dl); 271 for (i = 0; i < nr_pcnt; i++) {
256 while (offset < (s64)len && 272 if (a->percent[i] == b->percent[i])
257 (next == NULL || offset < next->offset)) { 273 continue;
258 if (src_line) { 274 return a->percent[i] < b->percent[i];
259 percent += src_line[offset].percent;
260 } else
261 hits += h->addr[offset];
262
263 ++offset;
264 }
265 /*
266 * If the percentage wasn't already calculated in
267 * symbol__get_source_line, do it now:
268 */
269 if (src_line == NULL && h->sum)
270 percent = 100.0 * hits / h->sum;
271 } 275 }
272 276 return 0;
273 return percent;
274} 277}
275 278
276static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) 279static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
280 int nr_events)
277{ 281{
278 struct rb_node **p = &root->rb_node; 282 struct rb_node **p = &root->rb_node;
279 struct rb_node *parent = NULL; 283 struct rb_node *parent = NULL;
@@ -282,7 +286,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l
282 while (*p != NULL) { 286 while (*p != NULL) {
283 parent = *p; 287 parent = *p;
284 l = rb_entry(parent, struct browser_disasm_line, rb_node); 288 l = rb_entry(parent, struct browser_disasm_line, rb_node);
285 if (bdl->percent < l->percent) 289
290 if (disasm__cmp(bdl, l, nr_events))
286 p = &(*p)->rb_left; 291 p = &(*p)->rb_left;
287 else 292 else
288 p = &(*p)->rb_right; 293 p = &(*p)->rb_right;
@@ -331,12 +336,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
331} 336}
332 337
333static void annotate_browser__calc_percent(struct annotate_browser *browser, 338static void annotate_browser__calc_percent(struct annotate_browser *browser,
334 int evidx) 339 struct perf_evsel *evsel)
335{ 340{
336 struct map_symbol *ms = browser->b.priv; 341 struct map_symbol *ms = browser->b.priv;
337 struct symbol *sym = ms->sym; 342 struct symbol *sym = ms->sym;
338 struct annotation *notes = symbol__annotation(sym); 343 struct annotation *notes = symbol__annotation(sym);
339 struct disasm_line *pos; 344 struct disasm_line *pos, *next;
345 s64 len = symbol__size(sym);
340 346
341 browser->entries = RB_ROOT; 347 browser->entries = RB_ROOT;
342 348
@@ -344,12 +350,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
344 350
345 list_for_each_entry(pos, &notes->src->source, node) { 351 list_for_each_entry(pos, &notes->src->source, node) {
346 struct browser_disasm_line *bpos = disasm_line__browser(pos); 352 struct browser_disasm_line *bpos = disasm_line__browser(pos);
347 bpos->percent = disasm_line__calc_percent(pos, sym, evidx); 353 const char *path = NULL;
348 if (bpos->percent < 0.01) { 354 double max_percent = 0.0;
355 int i;
356
357 if (pos->offset == -1) {
358 RB_CLEAR_NODE(&bpos->rb_node);
359 continue;
360 }
361
362 next = disasm__get_next_ip_line(&notes->src->source, pos);
363
364 for (i = 0; i < browser->nr_events; i++) {
365 bpos->percent[i] = disasm__calc_percent(notes,
366 evsel->idx + i,
367 pos->offset,
368 next ? next->offset : len,
369 &path);
370
371 if (max_percent < bpos->percent[i])
372 max_percent = bpos->percent[i];
373 }
374
375 if (max_percent < 0.01) {
349 RB_CLEAR_NODE(&bpos->rb_node); 376 RB_CLEAR_NODE(&bpos->rb_node);
350 continue; 377 continue;
351 } 378 }
352 disasm_rb_tree__insert(&browser->entries, bpos); 379 disasm_rb_tree__insert(&browser->entries, bpos,
380 browser->nr_events);
353 } 381 }
354 pthread_mutex_unlock(&notes->lock); 382 pthread_mutex_unlock(&notes->lock);
355 383
@@ -401,7 +429,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
401 browser->b.nr_entries = browser->nr_asm_entries; 429 browser->b.nr_entries = browser->nr_asm_entries;
402} 430}
403 431
404static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, 432static bool annotate_browser__callq(struct annotate_browser *browser,
433 struct perf_evsel *evsel,
405 struct hist_browser_timer *hbt) 434 struct hist_browser_timer *hbt)
406{ 435{
407 struct map_symbol *ms = browser->b.priv; 436 struct map_symbol *ms = browser->b.priv;
@@ -432,7 +461,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
432 } 461 }
433 462
434 pthread_mutex_unlock(&notes->lock); 463 pthread_mutex_unlock(&notes->lock);
435 symbol__tui_annotate(target, ms->map, evidx, hbt); 464 symbol__tui_annotate(target, ms->map, evsel, hbt);
436 ui_browser__show_title(&browser->b, sym->name); 465 ui_browser__show_title(&browser->b, sym->name);
437 return true; 466 return true;
438} 467}
@@ -615,7 +644,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
615 browser->addr_width += browser->jumps_width + 1; 644 browser->addr_width += browser->jumps_width + 1;
616} 645}
617 646
618static int annotate_browser__run(struct annotate_browser *browser, int evidx, 647static int annotate_browser__run(struct annotate_browser *browser,
648 struct perf_evsel *evsel,
619 struct hist_browser_timer *hbt) 649 struct hist_browser_timer *hbt)
620{ 650{
621 struct rb_node *nd = NULL; 651 struct rb_node *nd = NULL;
@@ -628,7 +658,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
628 if (ui_browser__show(&browser->b, sym->name, help) < 0) 658 if (ui_browser__show(&browser->b, sym->name, help) < 0)
629 return -1; 659 return -1;
630 660
631 annotate_browser__calc_percent(browser, evidx); 661 annotate_browser__calc_percent(browser, evsel);
632 662
633 if (browser->curr_hot) { 663 if (browser->curr_hot) {
634 annotate_browser__set_rb_top(browser, browser->curr_hot); 664 annotate_browser__set_rb_top(browser, browser->curr_hot);
@@ -641,7 +671,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
641 key = ui_browser__run(&browser->b, delay_secs); 671 key = ui_browser__run(&browser->b, delay_secs);
642 672
643 if (delay_secs != 0) { 673 if (delay_secs != 0) {
644 annotate_browser__calc_percent(browser, evidx); 674 annotate_browser__calc_percent(browser, evsel);
645 /* 675 /*
646 * Current line focus got out of the list of most active 676 * Current line focus got out of the list of most active
647 * lines, NULL it so that if TAB|UNTAB is pressed, we 677 * lines, NULL it so that if TAB|UNTAB is pressed, we
@@ -657,7 +687,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
657 hbt->timer(hbt->arg); 687 hbt->timer(hbt->arg);
658 688
659 if (delay_secs != 0) 689 if (delay_secs != 0)
660 symbol__annotate_decay_histogram(sym, evidx); 690 symbol__annotate_decay_histogram(sym, evsel->idx);
661 continue; 691 continue;
662 case K_TAB: 692 case K_TAB:
663 if (nd != NULL) { 693 if (nd != NULL) {
@@ -754,7 +784,7 @@ show_help:
754 goto show_sup_ins; 784 goto show_sup_ins;
755 goto out; 785 goto out;
756 } else if (!(annotate_browser__jump(browser) || 786 } else if (!(annotate_browser__jump(browser) ||
757 annotate_browser__callq(browser, evidx, hbt))) { 787 annotate_browser__callq(browser, evsel, hbt))) {
758show_sup_ins: 788show_sup_ins:
759 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 789 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
760 } 790 }
@@ -776,10 +806,10 @@ out:
776 return key; 806 return key;
777} 807}
778 808
779int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 809int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
780 struct hist_browser_timer *hbt) 810 struct hist_browser_timer *hbt)
781{ 811{
782 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt); 812 return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
783} 813}
784 814
785static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 815static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
@@ -826,7 +856,8 @@ static inline int width_jumps(int n)
826 return 1; 856 return 1;
827} 857}
828 858
829int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 859int symbol__tui_annotate(struct symbol *sym, struct map *map,
860 struct perf_evsel *evsel,
830 struct hist_browser_timer *hbt) 861 struct hist_browser_timer *hbt)
831{ 862{
832 struct disasm_line *pos, *n; 863 struct disasm_line *pos, *n;
@@ -847,6 +878,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
847 }, 878 },
848 }; 879 };
849 int ret = -1; 880 int ret = -1;
881 int nr_pcnt = 1;
882 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
850 883
851 if (sym == NULL) 884 if (sym == NULL)
852 return -1; 885 return -1;
@@ -862,7 +895,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
862 return -1; 895 return -1;
863 } 896 }
864 897
865 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { 898 if (perf_evsel__is_group_event(evsel)) {
899 nr_pcnt = evsel->nr_members;
900 sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
901 }
902
903 if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
866 ui__error("%s", ui_helpline__last_msg); 904 ui__error("%s", ui_helpline__last_msg);
867 goto out_free_offsets; 905 goto out_free_offsets;
868 } 906 }
@@ -900,6 +938,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
900 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); 938 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
901 browser.max_addr_width = hex_width(sym->end); 939 browser.max_addr_width = hex_width(sym->end);
902 browser.jumps_width = width_jumps(browser.max_jump_sources); 940 browser.jumps_width = width_jumps(browser.max_jump_sources);
941 browser.nr_events = nr_pcnt;
903 browser.b.nr_entries = browser.nr_entries; 942 browser.b.nr_entries = browser.nr_entries;
904 browser.b.entries = &notes->src->source, 943 browser.b.entries = &notes->src->source,
905 browser.b.width += 18; /* Percentage */ 944 browser.b.width += 18; /* Percentage */
@@ -909,7 +948,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
909 948
910 annotate_browser__update_addr_width(&browser); 949 annotate_browser__update_addr_width(&browser);
911 950
912 ret = annotate_browser__run(&browser, evidx, hbt); 951 ret = annotate_browser__run(&browser, evsel, hbt);
913 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 952 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
914 list_del(&pos->node); 953 list_del(&pos->node);
915 disasm_line__free(pos); 954 disasm_line__free(pos);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index aa22704047d6..a5843fd6ab51 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1193,7 +1193,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1193 char buf[512]; 1193 char buf[512];
1194 size_t buflen = sizeof(buf); 1194 size_t buflen = sizeof(buf);
1195 1195
1196 if (symbol_conf.event_group && evsel->nr_members > 1) { 1196 if (perf_evsel__is_group_event(evsel)) {
1197 struct perf_evsel *pos; 1197 struct perf_evsel *pos;
1198 1198
1199 perf_evsel__group_desc(evsel, buf, buflen); 1199 perf_evsel__group_desc(evsel, buf, buflen);
@@ -1599,7 +1599,7 @@ do_annotate:
1599 * Don't let this be freed, say, by hists__decay_entry. 1599 * Don't let this be freed, say, by hists__decay_entry.
1600 */ 1600 */
1601 he->used = true; 1601 he->used = true;
1602 err = hist_entry__tui_annotate(he, evsel->idx, hbt); 1602 err = hist_entry__tui_annotate(he, evsel, hbt);
1603 he->used = false; 1603 he->used = false;
1604 /* 1604 /*
1605 * offer option to annotate the other branch source or target 1605 * offer option to annotate the other branch source or target
@@ -1709,7 +1709,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1710 HE_COLORSET_NORMAL); 1710 HE_COLORSET_NORMAL);
1711 1711
1712 if (symbol_conf.event_group && evsel->nr_members > 1) { 1712 if (perf_evsel__is_group_event(evsel)) {
1713 struct perf_evsel *pos; 1713 struct perf_evsel *pos;
1714 1714
1715 ev_name = perf_evsel__group_name(evsel); 1715 ev_name = perf_evsel__group_name(evsel);
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index 7d8dc581a545..f538794615db 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -1,6 +1,7 @@
1#include "gtk.h" 1#include "gtk.h"
2#include "util/debug.h" 2#include "util/debug.h"
3#include "util/annotate.h" 3#include "util/annotate.h"
4#include "util/evsel.h"
4#include "ui/helpline.h" 5#include "ui/helpline.h"
5 6
6 7
@@ -32,7 +33,7 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
32 return 0; 33 return 0;
33 34
34 symhist = annotation__histogram(symbol__annotation(sym), evidx); 35 symhist = annotation__histogram(symbol__annotation(sym), evidx);
35 if (!symhist->addr[dl->offset]) 36 if (!symbol_conf.event_group && !symhist->addr[dl->offset])
36 return 0; 37 return 0;
37 38
38 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; 39 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
@@ -85,7 +86,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
85} 86}
86 87
87static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, 88static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
88 struct map *map, int evidx, 89 struct map *map, struct perf_evsel *evsel,
89 struct hist_browser_timer *hbt __maybe_unused) 90 struct hist_browser_timer *hbt __maybe_unused)
90{ 91{
91 struct disasm_line *pos, *n; 92 struct disasm_line *pos, *n;
@@ -118,10 +119,24 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
118 119
119 list_for_each_entry(pos, &notes->src->source, node) { 120 list_for_each_entry(pos, &notes->src->source, node) {
120 GtkTreeIter iter; 121 GtkTreeIter iter;
122 int ret = 0;
121 123
122 gtk_list_store_append(store, &iter); 124 gtk_list_store_append(store, &iter);
123 125
124 if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) 126 if (perf_evsel__is_group_event(evsel)) {
127 for (i = 0; i < evsel->nr_members; i++) {
128 ret += perf_gtk__get_percent(s + ret,
129 sizeof(s) - ret,
130 sym, pos,
131 evsel->idx + i);
132 ret += scnprintf(s + ret, sizeof(s) - ret, " ");
133 }
134 } else {
135 ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
136 evsel->idx);
137 }
138
139 if (ret)
125 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); 140 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
126 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) 141 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
127 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); 142 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
@@ -139,7 +154,8 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
139 return 0; 154 return 0;
140} 155}
141 156
142int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, 157int symbol__gtk_annotate(struct symbol *sym, struct map *map,
158 struct perf_evsel *evsel,
143 struct hist_browser_timer *hbt) 159 struct hist_browser_timer *hbt)
144{ 160{
145 GtkWidget *window; 161 GtkWidget *window;
@@ -206,7 +222,7 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
206 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, 222 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
207 tab_label); 223 tab_label);
208 224
209 perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); 225 perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt);
210 return 0; 226 return 0;
211} 227}
212 228
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 1e764a8ad259..6f259b3d14e2 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -32,21 +32,18 @@ static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
32 int ret; 32 int ret;
33 double percent = 0.0; 33 double percent = 0.0;
34 struct hists *hists = he->hists; 34 struct hists *hists = he->hists;
35 struct perf_evsel *evsel = hists_to_evsel(hists);
35 36
36 if (hists->stats.total_period) 37 if (hists->stats.total_period)
37 percent = 100.0 * get_field(he) / hists->stats.total_period; 38 percent = 100.0 * get_field(he) / hists->stats.total_period;
38 39
39 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); 40 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
40 41
41 if (symbol_conf.event_group) { 42 if (perf_evsel__is_group_event(evsel)) {
42 int prev_idx, idx_delta; 43 int prev_idx, idx_delta;
43 struct perf_evsel *evsel = hists_to_evsel(hists);
44 struct hist_entry *pair; 44 struct hist_entry *pair;
45 int nr_members = evsel->nr_members; 45 int nr_members = evsel->nr_members;
46 46
47 if (nr_members <= 1)
48 return ret;
49
50 prev_idx = perf_evsel__group_idx(evsel); 47 prev_idx = perf_evsel__group_idx(evsel);
51 48
52 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 49 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index d671e63aa351..4bf91b09d62d 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -16,6 +16,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
16{ 16{
17 int ret; 17 int ret;
18 struct hists *hists = he->hists; 18 struct hists *hists = he->hists;
19 struct perf_evsel *evsel = hists_to_evsel(hists);
19 20
20 if (fmt_percent) { 21 if (fmt_percent) {
21 double percent = 0.0; 22 double percent = 0.0;
@@ -28,15 +29,11 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
28 } else 29 } else
29 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); 30 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
30 31
31 if (symbol_conf.event_group) { 32 if (perf_evsel__is_group_event(evsel)) {
32 int prev_idx, idx_delta; 33 int prev_idx, idx_delta;
33 struct perf_evsel *evsel = hists_to_evsel(hists);
34 struct hist_entry *pair; 34 struct hist_entry *pair;
35 int nr_members = evsel->nr_members; 35 int nr_members = evsel->nr_members;
36 36
37 if (nr_members <= 1)
38 return ret;
39
40 prev_idx = perf_evsel__group_idx(evsel); 37 prev_idx = perf_evsel__group_idx(evsel);
41 38
42 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 39 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d33fe937e6f1..d102716c43a1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -14,6 +14,7 @@
14#include "symbol.h" 14#include "symbol.h"
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include "evsel.h"
17#include <pthread.h> 18#include <pthread.h>
18#include <linux/bitops.h> 19#include <linux/bitops.h>
19 20
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
602 return NULL; 603 return NULL;
603} 604}
604 605
606double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
607 s64 end, const char **path)
608{
609 struct source_line *src_line = notes->src->lines;
610 double percent = 0.0;
611
612 if (src_line) {
613 size_t sizeof_src_line = sizeof(*src_line) +
614 sizeof(src_line->p) * (src_line->nr_pcnt - 1);
615
616 while (offset < end) {
617 src_line = (void *)notes->src->lines +
618 (sizeof_src_line * offset);
619
620 if (*path == NULL)
621 *path = src_line->path;
622
623 percent += src_line->p[evidx].percent;
624 offset++;
625 }
626 } else {
627 struct sym_hist *h = annotation__histogram(notes, evidx);
628 unsigned int hits = 0;
629
630 while (offset < end)
631 hits += h->addr[offset++];
632
633 if (h->sum)
634 percent = 100.0 * hits / h->sum;
635 }
636
637 return percent;
638}
639
605static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 640static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
606 int evidx, u64 len, int min_pcnt, int printed, 641 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
607 int max_lines, struct disasm_line *queue) 642 int max_lines, struct disasm_line *queue)
608{ 643{
609 static const char *prev_line; 644 static const char *prev_line;
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
611 646
612 if (dl->offset != -1) { 647 if (dl->offset != -1) {
613 const char *path = NULL; 648 const char *path = NULL;
614 unsigned int hits = 0; 649 double percent, max_percent = 0.0;
615 double percent = 0.0; 650 double *ppercents = &percent;
651 int i, nr_percent = 1;
616 const char *color; 652 const char *color;
617 struct annotation *notes = symbol__annotation(sym); 653 struct annotation *notes = symbol__annotation(sym);
618 struct source_line *src_line = notes->src->lines;
619 struct sym_hist *h = annotation__histogram(notes, evidx);
620 s64 offset = dl->offset; 654 s64 offset = dl->offset;
621 const u64 addr = start + offset; 655 const u64 addr = start + offset;
622 struct disasm_line *next; 656 struct disasm_line *next;
623 657
624 next = disasm__get_next_ip_line(&notes->src->source, dl); 658 next = disasm__get_next_ip_line(&notes->src->source, dl);
625 659
626 while (offset < (s64)len && 660 if (perf_evsel__is_group_event(evsel)) {
627 (next == NULL || offset < next->offset)) { 661 nr_percent = evsel->nr_members;
628 if (src_line) { 662 ppercents = calloc(nr_percent, sizeof(double));
629 if (path == NULL) 663 if (ppercents == NULL)
630 path = src_line[offset].path; 664 return -1;
631 percent += src_line[offset].percent;
632 } else
633 hits += h->addr[offset];
634
635 ++offset;
636 } 665 }
637 666
638 if (src_line == NULL && h->sum) 667 for (i = 0; i < nr_percent; i++) {
639 percent = 100.0 * hits / h->sum; 668 percent = disasm__calc_percent(notes,
669 notes->src->lines ? i : evsel->idx + i,
670 offset,
671 next ? next->offset : (s64) len,
672 &path);
673
674 ppercents[i] = percent;
675 if (percent > max_percent)
676 max_percent = percent;
677 }
640 678
641 if (percent < min_pcnt) 679 if (max_percent < min_pcnt)
642 return -1; 680 return -1;
643 681
644 if (max_lines && printed >= max_lines) 682 if (max_lines && printed >= max_lines)
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
648 list_for_each_entry_from(queue, &notes->src->source, node) { 686 list_for_each_entry_from(queue, &notes->src->source, node) {
649 if (queue == dl) 687 if (queue == dl)
650 break; 688 break;
651 disasm_line__print(queue, sym, start, evidx, len, 689 disasm_line__print(queue, sym, start, evsel, len,
652 0, 0, 1, NULL); 690 0, 0, 1, NULL);
653 } 691 }
654 } 692 }
655 693
656 color = get_percent_color(percent); 694 color = get_percent_color(max_percent);
657 695
658 /* 696 /*
659 * Also color the filename and line if needed, with 697 * Also color the filename and line if needed, with
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
669 } 707 }
670 } 708 }
671 709
672 color_fprintf(stdout, color, " %7.2f", percent); 710 for (i = 0; i < nr_percent; i++) {
711 percent = ppercents[i];
712 color = get_percent_color(percent);
713 color_fprintf(stdout, color, " %7.2f", percent);
714 }
715
673 printf(" : "); 716 printf(" : ");
674 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 717 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
675 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 718 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
719
720 if (ppercents != &percent)
721 free(ppercents);
722
676 } else if (max_lines && printed >= max_lines) 723 } else if (max_lines && printed >= max_lines)
677 return 1; 724 return 1;
678 else { 725 else {
726 int width = 8;
727
679 if (queue) 728 if (queue)
680 return -1; 729 return -1;
681 730
731 if (perf_evsel__is_group_event(evsel))
732 width *= evsel->nr_members;
733
682 if (!*dl->line) 734 if (!*dl->line)
683 printf(" :\n"); 735 printf(" %*s:\n", width, " ");
684 else 736 else
685 printf(" : %s\n", dl->line); 737 printf(" %*s: %s\n", width, " ", dl->line);
686 } 738 }
687 739
688 return 0; 740 return 0;
689} 741}
690 742
743/*
744 * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
745 * which looks like following
746 *
747 * 0000000000415500 <_init>:
748 * 415500: sub $0x8,%rsp
749 * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8>
750 * 41550b: test %rax,%rax
751 * 41550e: je 415515 <_init+0x15>
752 * 415510: callq 416e70 <__gmon_start__@plt>
753 * 415515: add $0x8,%rsp
754 * 415519: retq
755 *
756 * it will be parsed and saved into struct disasm_line as
757 * <offset> <name> <ops.raw>
758 *
759 * The offset will be a relative offset from the start of the symbol and -1
760 * means that it's not a disassembly line so should be treated differently.
761 * The ops.raw part will be parsed further according to type of the instruction.
762 */
691static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 763static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
692 FILE *file, size_t privsize) 764 FILE *file, size_t privsize)
693{ 765{
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
858 struct source_line *iter; 930 struct source_line *iter;
859 struct rb_node **p = &root->rb_node; 931 struct rb_node **p = &root->rb_node;
860 struct rb_node *parent = NULL; 932 struct rb_node *parent = NULL;
861 int ret; 933 int i, ret;
862 934
863 while (*p != NULL) { 935 while (*p != NULL) {
864 parent = *p; 936 parent = *p;
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
866 938
867 ret = strcmp(iter->path, src_line->path); 939 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) { 940 if (ret == 0) {
869 iter->percent_sum += src_line->percent; 941 for (i = 0; i < src_line->nr_pcnt; i++)
942 iter->p[i].percent_sum += src_line->p[i].percent;
870 return; 943 return;
871 } 944 }
872 945
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
876 p = &(*p)->rb_right; 949 p = &(*p)->rb_right;
877 } 950 }
878 951
879 src_line->percent_sum = src_line->percent; 952 for (i = 0; i < src_line->nr_pcnt; i++)
953 src_line->p[i].percent_sum = src_line->p[i].percent;
880 954
881 rb_link_node(&src_line->node, parent, p); 955 rb_link_node(&src_line->node, parent, p);
882 rb_insert_color(&src_line->node, root); 956 rb_insert_color(&src_line->node, root);
883} 957}
884 958
959static int cmp_source_line(struct source_line *a, struct source_line *b)
960{
961 int i;
962
963 for (i = 0; i < a->nr_pcnt; i++) {
964 if (a->p[i].percent_sum == b->p[i].percent_sum)
965 continue;
966 return a->p[i].percent_sum > b->p[i].percent_sum;
967 }
968
969 return 0;
970}
971
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line) 972static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{ 973{
887 struct source_line *iter; 974 struct source_line *iter;
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l
892 parent = *p; 979 parent = *p;
893 iter = rb_entry(parent, struct source_line, node); 980 iter = rb_entry(parent, struct source_line, node);
894 981
895 if (src_line->percent_sum > iter->percent_sum) 982 if (cmp_source_line(src_line, iter))
896 p = &(*p)->rb_left; 983 p = &(*p)->rb_left;
897 else 984 else
898 p = &(*p)->rb_right; 985 p = &(*p)->rb_right;
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len)
924{ 1011{
925 struct annotation *notes = symbol__annotation(sym); 1012 struct annotation *notes = symbol__annotation(sym);
926 struct source_line *src_line = notes->src->lines; 1013 struct source_line *src_line = notes->src->lines;
1014 size_t sizeof_src_line;
927 int i; 1015 int i;
928 1016
929 for (i = 0; i < len; i++) 1017 sizeof_src_line = sizeof(*src_line) +
930 free(src_line[i].path); 1018 (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
1019
1020 for (i = 0; i < len; i++) {
1021 free(src_line->path);
1022 src_line = (void *)src_line + sizeof_src_line;
1023 }
931 1024
932 free(src_line); 1025 free(notes->src->lines);
933 notes->src->lines = NULL; 1026 notes->src->lines = NULL;
934} 1027}
935 1028
936/* Get the filename:line for the colored entries */ 1029/* Get the filename:line for the colored entries */
937static int symbol__get_source_line(struct symbol *sym, struct map *map, 1030static int symbol__get_source_line(struct symbol *sym, struct map *map,
938 int evidx, struct rb_root *root, int len, 1031 struct perf_evsel *evsel,
1032 struct rb_root *root, int len,
939 const char *filename) 1033 const char *filename)
940{ 1034{
941 u64 start; 1035 u64 start;
942 int i; 1036 int i, k;
1037 int evidx = evsel->idx;
943 char cmd[PATH_MAX * 2]; 1038 char cmd[PATH_MAX * 2];
944 struct source_line *src_line; 1039 struct source_line *src_line;
945 struct annotation *notes = symbol__annotation(sym); 1040 struct annotation *notes = symbol__annotation(sym);
946 struct sym_hist *h = annotation__histogram(notes, evidx); 1041 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT; 1042 struct rb_root tmp_root = RB_ROOT;
1043 int nr_pcnt = 1;
1044 u64 h_sum = h->sum;
1045 size_t sizeof_src_line = sizeof(struct source_line);
1046
1047 if (perf_evsel__is_group_event(evsel)) {
1048 for (i = 1; i < evsel->nr_members; i++) {
1049 h = annotation__histogram(notes, evidx + i);
1050 h_sum += h->sum;
1051 }
1052 nr_pcnt = evsel->nr_members;
1053 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
1054 }
948 1055
949 if (!h->sum) 1056 if (!h_sum)
950 return 0; 1057 return 0;
951 1058
952 src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); 1059 src_line = notes->src->lines = calloc(len, sizeof_src_line);
953 if (!notes->src->lines) 1060 if (!notes->src->lines)
954 return -1; 1061 return -1;
955 1062
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
960 size_t line_len; 1067 size_t line_len;
961 u64 offset; 1068 u64 offset;
962 FILE *fp; 1069 FILE *fp;
1070 double percent_max = 0.0;
963 1071
964 src_line[i].percent = 100.0 * h->addr[i] / h->sum; 1072 src_line->nr_pcnt = nr_pcnt;
965 if (src_line[i].percent <= 0.5) 1073
966 continue; 1074 for (k = 0; k < nr_pcnt; k++) {
1075 h = annotation__histogram(notes, evidx + k);
1076 src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
1077
1078 if (src_line->p[k].percent > percent_max)
1079 percent_max = src_line->p[k].percent;
1080 }
1081
1082 if (percent_max <= 0.5)
1083 goto next;
967 1084
968 offset = start + i; 1085 offset = start + i;
969 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1086 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
970 fp = popen(cmd, "r"); 1087 fp = popen(cmd, "r");
971 if (!fp) 1088 if (!fp)
972 continue; 1089 goto next;
973 1090
974 if (getline(&path, &line_len, fp) < 0 || !line_len) 1091 if (getline(&path, &line_len, fp) < 0 || !line_len)
975 goto next; 1092 goto next_close;
976 1093
977 src_line[i].path = malloc(sizeof(char) * line_len + 1); 1094 src_line->path = malloc(sizeof(char) * line_len + 1);
978 if (!src_line[i].path) 1095 if (!src_line->path)
979 goto next; 1096 goto next_close;
980 1097
981 strcpy(src_line[i].path, path); 1098 strcpy(src_line->path, path);
982 insert_source_line(&tmp_root, &src_line[i]); 1099 insert_source_line(&tmp_root, src_line);
983 1100
984 next: 1101 next_close:
985 pclose(fp); 1102 pclose(fp);
1103 next:
1104 src_line = (void *)src_line + sizeof_src_line;
986 } 1105 }
987 1106
988 resort_source_line(root, &tmp_root); 1107 resort_source_line(root, &tmp_root);
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename)
1004 1123
1005 node = rb_first(root); 1124 node = rb_first(root);
1006 while (node) { 1125 while (node) {
1007 double percent; 1126 double percent, percent_max = 0.0;
1008 const char *color; 1127 const char *color;
1009 char *path; 1128 char *path;
1129 int i;
1010 1130
1011 src_line = rb_entry(node, struct source_line, node); 1131 src_line = rb_entry(node, struct source_line, node);
1012 percent = src_line->percent_sum; 1132 for (i = 0; i < src_line->nr_pcnt; i++) {
1013 color = get_percent_color(percent); 1133 percent = src_line->p[i].percent_sum;
1134 color = get_percent_color(percent);
1135 color_fprintf(stdout, color, " %7.2f", percent);
1136
1137 if (percent > percent_max)
1138 percent_max = percent;
1139 }
1140
1014 path = src_line->path; 1141 path = src_line->path;
1142 color = get_percent_color(percent_max);
1143 color_fprintf(stdout, color, " %s", path);
1015 1144
1016 color_fprintf(stdout, color, " %7.2f %s", percent, path);
1017 node = rb_next(node); 1145 node = rb_next(node);
1018 } 1146 }
1019} 1147}
1020 1148
1021static void symbol__annotate_hits(struct symbol *sym, int evidx) 1149static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
1022{ 1150{
1023 struct annotation *notes = symbol__annotation(sym); 1151 struct annotation *notes = symbol__annotation(sym);
1024 struct sym_hist *h = annotation__histogram(notes, evidx); 1152 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
1025 u64 len = symbol__size(sym), offset; 1153 u64 len = symbol__size(sym), offset;
1026 1154
1027 for (offset = 0; offset < len; ++offset) 1155 for (offset = 0; offset < len; ++offset)
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
1031 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 1159 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
1032} 1160}
1033 1161
1034int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 1162int symbol__annotate_printf(struct symbol *sym, struct map *map,
1035 bool full_paths, int min_pcnt, int max_lines, 1163 struct perf_evsel *evsel, bool full_paths,
1036 int context) 1164 int min_pcnt, int max_lines, int context)
1037{ 1165{
1038 struct dso *dso = map->dso; 1166 struct dso *dso = map->dso;
1039 char *filename; 1167 char *filename;
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1044 int printed = 2, queue_len = 0; 1172 int printed = 2, queue_len = 0;
1045 int more = 0; 1173 int more = 0;
1046 u64 len; 1174 u64 len;
1175 int width = 8;
1176 int namelen;
1047 1177
1048 filename = strdup(dso->long_name); 1178 filename = strdup(dso->long_name);
1049 if (!filename) 1179 if (!filename)
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1055 d_filename = basename(filename); 1185 d_filename = basename(filename);
1056 1186
1057 len = symbol__size(sym); 1187 len = symbol__size(sym);
1188 namelen = strlen(d_filename);
1189
1190 if (perf_evsel__is_group_event(evsel))
1191 width *= evsel->nr_members;
1058 1192
1059 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 1193 printf(" %-*.*s| Source code & Disassembly of %s\n",
1060 printf("------------------------------------------------\n"); 1194 width, width, "Percent", d_filename);
1195 printf("-%-*.*s-------------------------------------\n",
1196 width+namelen, width+namelen, graph_dotted_line);
1061 1197
1062 if (verbose) 1198 if (verbose)
1063 symbol__annotate_hits(sym, evidx); 1199 symbol__annotate_hits(sym, evsel);
1064 1200
1065 list_for_each_entry(pos, &notes->src->source, node) { 1201 list_for_each_entry(pos, &notes->src->source, node) {
1066 if (context && queue == NULL) { 1202 if (context && queue == NULL) {
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
1068 queue_len = 0; 1204 queue_len = 0;
1069 } 1205 }
1070 1206
1071 switch (disasm_line__print(pos, sym, start, evidx, len, 1207 switch (disasm_line__print(pos, sym, start, evsel, len,
1072 min_pcnt, printed, max_lines, 1208 min_pcnt, printed, max_lines,
1073 queue)) { 1209 queue)) {
1074 case 0: 1210 case 0:
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
1163 return printed; 1299 return printed;
1164} 1300}
1165 1301
1166int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1302int symbol__tty_annotate(struct symbol *sym, struct map *map,
1167 bool print_lines, bool full_paths, int min_pcnt, 1303 struct perf_evsel *evsel, bool print_lines,
1168 int max_lines) 1304 bool full_paths, int min_pcnt, int max_lines)
1169{ 1305{
1170 struct dso *dso = map->dso; 1306 struct dso *dso = map->dso;
1171 const char *filename = dso->long_name; 1307 const char *filename = dso->long_name;
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
1178 len = symbol__size(sym); 1314 len = symbol__size(sym);
1179 1315
1180 if (print_lines) { 1316 if (print_lines) {
1181 symbol__get_source_line(sym, map, evidx, &source_line, 1317 symbol__get_source_line(sym, map, evsel, &source_line,
1182 len, filename); 1318 len, filename);
1183 print_summary(&source_line, filename); 1319 print_summary(&source_line, filename);
1184 } 1320 }
1185 1321
1186 symbol__annotate_printf(sym, map, evidx, full_paths, 1322 symbol__annotate_printf(sym, map, evsel, full_paths,
1187 min_pcnt, max_lines, 0); 1323 min_pcnt, max_lines, 0);
1188 if (print_lines) 1324 if (print_lines)
1189 symbol__free_source_line(sym, len); 1325 symbol__free_source_line(sym, len);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c422440fe611..6f3c16f01ab4 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -50,6 +50,8 @@ bool ins__is_jump(const struct ins *ins);
50bool ins__is_call(const struct ins *ins); 50bool ins__is_call(const struct ins *ins);
51int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); 51int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
52 52
53struct annotation;
54
53struct disasm_line { 55struct disasm_line {
54 struct list_head node; 56 struct list_head node;
55 s64 offset; 57 s64 offset;
@@ -68,17 +70,24 @@ void disasm_line__free(struct disasm_line *dl);
68struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); 70struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
69int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); 71int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
70size_t disasm__fprintf(struct list_head *head, FILE *fp); 72size_t disasm__fprintf(struct list_head *head, FILE *fp);
73double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
74 s64 end, const char **path);
71 75
72struct sym_hist { 76struct sym_hist {
73 u64 sum; 77 u64 sum;
74 u64 addr[0]; 78 u64 addr[0];
75}; 79};
76 80
77struct source_line { 81struct source_line_percent {
78 struct rb_node node;
79 double percent; 82 double percent;
80 double percent_sum; 83 double percent_sum;
84};
85
86struct source_line {
87 struct rb_node node;
81 char *path; 88 char *path;
89 int nr_pcnt;
90 struct source_line_percent p[1];
82}; 91};
83 92
84/** struct annotated_source - symbols with hits have this attached as in sannotation 93/** struct annotated_source - symbols with hits have this attached as in sannotation
@@ -130,47 +139,49 @@ void symbol__annotate_zero_histograms(struct symbol *sym);
130 139
131int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 140int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
132int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 141int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
133int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, 142int symbol__annotate_printf(struct symbol *sym, struct map *map,
134 bool full_paths, int min_pcnt, int max_lines, 143 struct perf_evsel *evsel, bool full_paths,
135 int context); 144 int min_pcnt, int max_lines, int context);
136void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 145void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
137void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 146void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
138void disasm__purge(struct list_head *head); 147void disasm__purge(struct list_head *head);
139 148
140int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 149int symbol__tty_annotate(struct symbol *sym, struct map *map,
141 bool print_lines, bool full_paths, int min_pcnt, 150 struct perf_evsel *evsel, bool print_lines,
142 int max_lines); 151 bool full_paths, int min_pcnt, int max_lines);
143 152
144#ifdef NEWT_SUPPORT 153#ifdef NEWT_SUPPORT
145int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 154int symbol__tui_annotate(struct symbol *sym, struct map *map,
155 struct perf_evsel *evsel,
146 struct hist_browser_timer *hbt); 156 struct hist_browser_timer *hbt);
147#else 157#else
148static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 158static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
149 struct map *map __maybe_unused, 159 struct map *map __maybe_unused,
150 int evidx __maybe_unused, 160 struct perf_evsel *evsel __maybe_unused,
151 struct hist_browser_timer *hbt 161 struct hist_browser_timer *hbt
152 __maybe_unused) 162 __maybe_unused)
153{ 163{
154 return 0; 164 return 0;
155} 165}
156#endif 166#endif
157 167
158#ifdef GTK2_SUPPORT 168#ifdef GTK2_SUPPORT
159int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, 169int symbol__gtk_annotate(struct symbol *sym, struct map *map,
170 struct perf_evsel *evsel,
160 struct hist_browser_timer *hbt); 171 struct hist_browser_timer *hbt);
161 172
162static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, 173static inline int hist_entry__gtk_annotate(struct hist_entry *he,
174 struct perf_evsel *evsel,
163 struct hist_browser_timer *hbt) 175 struct hist_browser_timer *hbt)
164{ 176{
165 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); 177 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
166} 178}
167 179
168void perf_gtk__show_annotations(void); 180void perf_gtk__show_annotations(void);
169#else 181#else
170static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, 182static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
171 int evidx __maybe_unused, 183 struct perf_evsel *evsel __maybe_unused,
172 struct hist_browser_timer *hbt 184 struct hist_browser_timer *hbt __maybe_unused)
173 __maybe_unused)
174{ 185{
175 return 0; 186 return 0;
176} 187}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
deleted file mode 100644
index 68f3e87ec57f..000000000000
--- a/tools/perf/util/debugfs.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4const char *debugfs_find_mountpoint(void);
5int debugfs_valid_mountpoint(const char *debugfs);
6char *debugfs_mount(const char *mountpoint);
7void debugfs_set_path(const char *mountpoint);
8
9extern char debugfs_mountpoint[];
10extern char tracing_events_path[];
11
12#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c8be0fbc5145..f7c727801aab 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 "debugfs.h" 10#include <lk/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"
@@ -38,13 +38,12 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
38 evlist->workload.pid = -1; 38 evlist->workload.pid = -1;
39} 39}
40 40
41struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 41struct perf_evlist *perf_evlist__new(void)
42 struct thread_map *threads)
43{ 42{
44 struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 43 struct perf_evlist *evlist = zalloc(sizeof(*evlist));
45 44
46 if (evlist != NULL) 45 if (evlist != NULL)
47 perf_evlist__init(evlist, cpus, threads); 46 perf_evlist__init(evlist, NULL, NULL);
48 47
49 return evlist; 48 return evlist;
50} 49}
@@ -228,12 +227,14 @@ void perf_evlist__disable(struct perf_evlist *evlist)
228{ 227{
229 int cpu, thread; 228 int cpu, thread;
230 struct perf_evsel *pos; 229 struct perf_evsel *pos;
230 int nr_cpus = cpu_map__nr(evlist->cpus);
231 int nr_threads = thread_map__nr(evlist->threads);
231 232
232 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 233 for (cpu = 0; cpu < nr_cpus; cpu++) {
233 list_for_each_entry(pos, &evlist->entries, node) { 234 list_for_each_entry(pos, &evlist->entries, node) {
234 if (!perf_evsel__is_group_leader(pos)) 235 if (!perf_evsel__is_group_leader(pos))
235 continue; 236 continue;
236 for (thread = 0; thread < evlist->threads->nr; thread++) 237 for (thread = 0; thread < nr_threads; thread++)
237 ioctl(FD(pos, cpu, thread), 238 ioctl(FD(pos, cpu, thread),
238 PERF_EVENT_IOC_DISABLE, 0); 239 PERF_EVENT_IOC_DISABLE, 0);
239 } 240 }
@@ -244,12 +245,14 @@ void perf_evlist__enable(struct perf_evlist *evlist)
244{ 245{
245 int cpu, thread; 246 int cpu, thread;
246 struct perf_evsel *pos; 247 struct perf_evsel *pos;
248 int nr_cpus = cpu_map__nr(evlist->cpus);
249 int nr_threads = thread_map__nr(evlist->threads);
247 250
248 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 251 for (cpu = 0; cpu < nr_cpus; cpu++) {
249 list_for_each_entry(pos, &evlist->entries, node) { 252 list_for_each_entry(pos, &evlist->entries, node) {
250 if (!perf_evsel__is_group_leader(pos)) 253 if (!perf_evsel__is_group_leader(pos))
251 continue; 254 continue;
252 for (thread = 0; thread < evlist->threads->nr; thread++) 255 for (thread = 0; thread < nr_threads; thread++)
253 ioctl(FD(pos, cpu, thread), 256 ioctl(FD(pos, cpu, thread),
254 PERF_EVENT_IOC_ENABLE, 0); 257 PERF_EVENT_IOC_ENABLE, 0);
255 } 258 }
@@ -258,7 +261,9 @@ void perf_evlist__enable(struct perf_evlist *evlist)
258 261
259static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 262static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
260{ 263{
261 int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; 264 int nr_cpus = cpu_map__nr(evlist->cpus);
265 int nr_threads = thread_map__nr(evlist->threads);
266 int nfds = nr_cpus * nr_threads * evlist->nr_entries;
262 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 267 evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
263 return evlist->pollfd != NULL ? 0 : -ENOMEM; 268 return evlist->pollfd != NULL ? 0 : -ENOMEM;
264} 269}
@@ -417,7 +422,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
417{ 422{
418 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 423 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
419 if (cpu_map__all(evlist->cpus)) 424 if (cpu_map__all(evlist->cpus))
420 evlist->nr_mmaps = evlist->threads->nr; 425 evlist->nr_mmaps = thread_map__nr(evlist->threads);
421 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 426 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
422 return evlist->mmap != NULL ? 0 : -ENOMEM; 427 return evlist->mmap != NULL ? 0 : -ENOMEM;
423} 428}
@@ -442,11 +447,13 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
442{ 447{
443 struct perf_evsel *evsel; 448 struct perf_evsel *evsel;
444 int cpu, thread; 449 int cpu, thread;
450 int nr_cpus = cpu_map__nr(evlist->cpus);
451 int nr_threads = thread_map__nr(evlist->threads);
445 452
446 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 453 for (cpu = 0; cpu < nr_cpus; cpu++) {
447 int output = -1; 454 int output = -1;
448 455
449 for (thread = 0; thread < evlist->threads->nr; thread++) { 456 for (thread = 0; thread < nr_threads; thread++) {
450 list_for_each_entry(evsel, &evlist->entries, node) { 457 list_for_each_entry(evsel, &evlist->entries, node) {
451 int fd = FD(evsel, cpu, thread); 458 int fd = FD(evsel, cpu, thread);
452 459
@@ -470,7 +477,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
470 return 0; 477 return 0;
471 478
472out_unmap: 479out_unmap:
473 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 480 for (cpu = 0; cpu < nr_cpus; cpu++) {
474 if (evlist->mmap[cpu].base != NULL) { 481 if (evlist->mmap[cpu].base != NULL) {
475 munmap(evlist->mmap[cpu].base, evlist->mmap_len); 482 munmap(evlist->mmap[cpu].base, evlist->mmap_len);
476 evlist->mmap[cpu].base = NULL; 483 evlist->mmap[cpu].base = NULL;
@@ -483,8 +490,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
483{ 490{
484 struct perf_evsel *evsel; 491 struct perf_evsel *evsel;
485 int thread; 492 int thread;
493 int nr_threads = thread_map__nr(evlist->threads);
486 494
487 for (thread = 0; thread < evlist->threads->nr; thread++) { 495 for (thread = 0; thread < nr_threads; thread++) {
488 int output = -1; 496 int output = -1;
489 497
490 list_for_each_entry(evsel, &evlist->entries, node) { 498 list_for_each_entry(evsel, &evlist->entries, node) {
@@ -509,7 +517,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
509 return 0; 517 return 0;
510 518
511out_unmap: 519out_unmap:
512 for (thread = 0; thread < evlist->threads->nr; thread++) { 520 for (thread = 0; thread < nr_threads; thread++) {
513 if (evlist->mmap[thread].base != NULL) { 521 if (evlist->mmap[thread].base != NULL) {
514 munmap(evlist->mmap[thread].base, evlist->mmap_len); 522 munmap(evlist->mmap[thread].base, evlist->mmap_len);
515 evlist->mmap[thread].base = NULL; 523 evlist->mmap[thread].base = NULL;
@@ -610,7 +618,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
610 struct perf_evsel *evsel; 618 struct perf_evsel *evsel;
611 int err = 0; 619 int err = 0;
612 const int ncpus = cpu_map__nr(evlist->cpus), 620 const int ncpus = cpu_map__nr(evlist->cpus),
613 nthreads = evlist->threads->nr; 621 nthreads = thread_map__nr(evlist->threads);
614 622
615 list_for_each_entry(evsel, &evlist->entries, node) { 623 list_for_each_entry(evsel, &evlist->entries, node) {
616 if (evsel->filter == NULL) 624 if (evsel->filter == NULL)
@@ -629,7 +637,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
629 struct perf_evsel *evsel; 637 struct perf_evsel *evsel;
630 int err = 0; 638 int err = 0;
631 const int ncpus = cpu_map__nr(evlist->cpus), 639 const int ncpus = cpu_map__nr(evlist->cpus),
632 nthreads = evlist->threads->nr; 640 nthreads = thread_map__nr(evlist->threads);
633 641
634 list_for_each_entry(evsel, &evlist->entries, node) { 642 list_for_each_entry(evsel, &evlist->entries, node) {
635 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); 643 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
@@ -712,10 +720,20 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
712 evlist->selected = evsel; 720 evlist->selected = evsel;
713} 721}
714 722
723void perf_evlist__close(struct perf_evlist *evlist)
724{
725 struct perf_evsel *evsel;
726 int ncpus = cpu_map__nr(evlist->cpus);
727 int nthreads = thread_map__nr(evlist->threads);
728
729 list_for_each_entry_reverse(evsel, &evlist->entries, node)
730 perf_evsel__close(evsel, ncpus, nthreads);
731}
732
715int perf_evlist__open(struct perf_evlist *evlist) 733int perf_evlist__open(struct perf_evlist *evlist)
716{ 734{
717 struct perf_evsel *evsel; 735 struct perf_evsel *evsel;
718 int err, ncpus, nthreads; 736 int err;
719 737
720 list_for_each_entry(evsel, &evlist->entries, node) { 738 list_for_each_entry(evsel, &evlist->entries, node) {
721 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 739 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
@@ -725,19 +743,15 @@ int perf_evlist__open(struct perf_evlist *evlist)
725 743
726 return 0; 744 return 0;
727out_err: 745out_err:
728 ncpus = evlist->cpus ? evlist->cpus->nr : 1; 746 perf_evlist__close(evlist);
729 nthreads = evlist->threads ? evlist->threads->nr : 1;
730
731 list_for_each_entry_reverse(evsel, &evlist->entries, node)
732 perf_evsel__close(evsel, ncpus, nthreads);
733
734 errno = -err; 747 errno = -err;
735 return err; 748 return err;
736} 749}
737 750
738int perf_evlist__prepare_workload(struct perf_evlist *evlist, 751int perf_evlist__prepare_workload(struct perf_evlist *evlist,
739 struct perf_record_opts *opts, 752 struct perf_target *target,
740 const char *argv[]) 753 const char *argv[], bool pipe_output,
754 bool want_signal)
741{ 755{
742 int child_ready_pipe[2], go_pipe[2]; 756 int child_ready_pipe[2], go_pipe[2];
743 char bf; 757 char bf;
@@ -759,7 +773,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
759 } 773 }
760 774
761 if (!evlist->workload.pid) { 775 if (!evlist->workload.pid) {
762 if (opts->pipe_output) 776 if (pipe_output)
763 dup2(2, 1); 777 dup2(2, 1);
764 778
765 close(child_ready_pipe[0]); 779 close(child_ready_pipe[0]);
@@ -787,11 +801,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
787 execvp(argv[0], (char **)argv); 801 execvp(argv[0], (char **)argv);
788 802
789 perror(argv[0]); 803 perror(argv[0]);
790 kill(getppid(), SIGUSR1); 804 if (want_signal)
805 kill(getppid(), SIGUSR1);
791 exit(-1); 806 exit(-1);
792 } 807 }
793 808
794 if (perf_target__none(&opts->target)) 809 if (perf_target__none(target))
795 evlist->threads->map[0] = evlist->workload.pid; 810 evlist->threads->map[0] = evlist->workload.pid;
796 811
797 close(child_ready_pipe[1]); 812 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 2dd07bd60b4f..0583d36252be 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,8 +49,7 @@ struct perf_evsel_str_handler {
49 void *handler; 49 void *handler;
50}; 50};
51 51
52struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, 52struct perf_evlist *perf_evlist__new(void);
53 struct thread_map *threads);
54void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 53void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
55 struct thread_map *threads); 54 struct thread_map *threads);
56void perf_evlist__exit(struct perf_evlist *evlist); 55void perf_evlist__exit(struct perf_evlist *evlist);
@@ -82,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
82union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 81union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
83 82
84int perf_evlist__open(struct perf_evlist *evlist); 83int perf_evlist__open(struct perf_evlist *evlist);
84void perf_evlist__close(struct perf_evlist *evlist);
85 85
86void perf_evlist__config(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
87 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
88 88
89int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int perf_evlist__prepare_workload(struct perf_evlist *evlist,
90 struct perf_record_opts *opts, 90 struct perf_target *target,
91 const char *argv[]); 91 const char *argv[], bool pipe_output,
92 bool want_signal);
92int perf_evlist__start_workload(struct perf_evlist *evlist); 93int perf_evlist__start_workload(struct perf_evlist *evlist);
93 94
94int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 95int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9c82f98f26de..1adb824610f0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -10,7 +10,7 @@
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include "asm/bug.h" 12#include "asm/bug.h"
13#include "debugfs.h" 13#include <lk/debugfs.h>
14#include "event-parse.h" 14#include "event-parse.h"
15#include "evsel.h" 15#include "evsel.h"
16#include "evlist.h" 16#include "evlist.h"
@@ -633,6 +633,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
633 return 0; 633 return 0;
634} 634}
635 635
636void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
637{
638 memset(evsel->counts, 0, (sizeof(*evsel->counts) +
639 (ncpus * sizeof(struct perf_counts_values))));
640}
641
636int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 642int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
637{ 643{
638 evsel->counts = zalloc((sizeof(*evsel->counts) + 644 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -673,9 +679,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
673void perf_evsel__exit(struct perf_evsel *evsel) 679void perf_evsel__exit(struct perf_evsel *evsel)
674{ 680{
675 assert(list_empty(&evsel->node)); 681 assert(list_empty(&evsel->node));
676 xyarray__delete(evsel->fd); 682 perf_evsel__free_fd(evsel);
677 xyarray__delete(evsel->sample_id); 683 perf_evsel__free_id(evsel);
678 free(evsel->id);
679} 684}
680 685
681void perf_evsel__delete(struct perf_evsel *evsel) 686void perf_evsel__delete(struct perf_evsel *evsel)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 52021c3087df..3f156ccc1acb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -9,6 +9,7 @@
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h" 11#include "hist.h"
12#include "symbol.h"
12 13
13struct perf_counts_values { 14struct perf_counts_values {
14 union { 15 union {
@@ -120,6 +121,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
120int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
121int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 122int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 123int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
124void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
123void perf_evsel__free_fd(struct perf_evsel *evsel); 125void perf_evsel__free_fd(struct perf_evsel *evsel);
124void perf_evsel__free_id(struct perf_evsel *evsel); 126void perf_evsel__free_id(struct perf_evsel *evsel);
125void perf_evsel__free_counts(struct perf_evsel *evsel); 127void perf_evsel__free_counts(struct perf_evsel *evsel);
@@ -246,11 +248,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
246 return list_entry(evsel->node.next, struct perf_evsel, node); 248 return list_entry(evsel->node.next, struct perf_evsel, node);
247} 249}
248 250
251/**
252 * perf_evsel__is_group_leader - Return whether given evsel is a leader event
253 *
254 * @evsel - evsel selector to be tested
255 *
256 * Return %true if @evsel is a group leader or a stand-alone event
257 */
249static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) 258static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
250{ 259{
251 return evsel->leader == evsel; 260 return evsel->leader == evsel;
252} 261}
253 262
263/**
264 * perf_evsel__is_group_event - Return whether given evsel is a group event
265 *
266 * @evsel - evsel selector to be tested
267 *
268 * Return %true iff event group view is enabled and @evsel is a actual group
269 * leader which has other members in the group
270 */
271static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel)
272{
273 if (!symbol_conf.event_group)
274 return false;
275
276 return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1;
277}
278
254struct perf_attr_details { 279struct perf_attr_details {
255 bool freq; 280 bool freq;
256 bool verbose; 281 bool verbose;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f4bfd79ef6a7..a9b7349f7c5f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2789,7 +2789,7 @@ int perf_session__read_header(struct perf_session *session, int fd)
2789 u64 f_id; 2789 u64 f_id;
2790 int nr_attrs, nr_ids, i, j; 2790 int nr_attrs, nr_ids, i, j;
2791 2791
2792 session->evlist = perf_evlist__new(NULL, NULL); 2792 session->evlist = perf_evlist__new();
2793 if (session->evlist == NULL) 2793 if (session->evlist == NULL)
2794 return -ENOMEM; 2794 return -ENOMEM;
2795 2795
@@ -2940,7 +2940,7 @@ int perf_event__process_attr(union perf_event *event,
2940 struct perf_evlist *evlist = *pevlist; 2940 struct perf_evlist *evlist = *pevlist;
2941 2941
2942 if (evlist == NULL) { 2942 if (evlist == NULL) {
2943 *pevlist = evlist = perf_evlist__new(NULL, NULL); 2943 *pevlist = evlist = perf_evlist__new();
2944 if (evlist == NULL) 2944 if (evlist == NULL)
2945 return -ENOMEM; 2945 return -ENOMEM;
2946 } 2946 }
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 226a4ae2f936..848331377bdb 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -177,7 +177,7 @@ struct hist_browser_timer {
177 177
178#ifdef NEWT_SUPPORT 178#ifdef NEWT_SUPPORT
179#include "../ui/keysyms.h" 179#include "../ui/keysyms.h"
180int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 180int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
181 struct hist_browser_timer *hbt); 181 struct hist_browser_timer *hbt);
182 182
183int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 183int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
@@ -196,7 +196,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
196 196
197static inline int hist_entry__tui_annotate(struct hist_entry *self 197static inline int hist_entry__tui_annotate(struct hist_entry *self
198 __maybe_unused, 198 __maybe_unused,
199 int evidx __maybe_unused, 199 struct perf_evsel *evsel
200 __maybe_unused,
200 struct hist_browser_timer *hbt 201 struct hist_browser_timer *hbt
201 __maybe_unused) 202 __maybe_unused)
202{ 203{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index efdb38e65a92..c5e3b123782b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1003,6 +1003,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1003 return 0; 1003 return 0;
1004} 1004}
1005 1005
1006static void machine__remove_thread(struct machine *machine, struct thread *th)
1007{
1008 machine->last_match = NULL;
1009 rb_erase(&th->rb_node, &machine->threads);
1010 /*
1011 * We may have references to this thread, for instance in some hist_entry
1012 * instances, so just move them to a separate list.
1013 */
1014 list_add_tail(&th->node, &machine->dead_threads);
1015}
1016
1006int machine__process_exit_event(struct machine *machine, union perf_event *event) 1017int machine__process_exit_event(struct machine *machine, union perf_event *event)
1007{ 1018{
1008 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1019 struct thread *thread = machine__find_thread(machine, event->fork.tid);
@@ -1039,17 +1050,6 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1039 return ret; 1050 return ret;
1040} 1051}
1041 1052
1042void machine__remove_thread(struct machine *machine, struct thread *th)
1043{
1044 machine->last_match = NULL;
1045 rb_erase(&th->rb_node, &machine->threads);
1046 /*
1047 * We may have references to this thread, for instance in some hist_entry
1048 * instances, so just move them to a separate list.
1049 */
1050 list_add_tail(&th->node, &machine->dead_threads);
1051}
1052
1053static bool symbol__match_parent_regex(struct symbol *sym) 1053static bool symbol__match_parent_regex(struct symbol *sym)
1054{ 1054{
1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 5ac5892f2326..e0b2c00b2e75 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -97,7 +97,6 @@ static inline bool machine__is_host(struct machine *machine)
97} 97}
98 98
99struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 99struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
100void machine__remove_thread(struct machine *machine, struct thread *th);
101 100
102size_t machine__fprintf(struct machine *machine, FILE *fp); 101size_t machine__fprintf(struct machine *machine, FILE *fp);
103 102
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c84f48cf9678..6c8bb0fb189b 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 "debugfs.h" 13#include <lk/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"
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 49a256e6e0a2..aa04bf9c9ad7 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 "debugfs.h" 43#include <lk/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"
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 64536a993f4a..f75ae1b9900c 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -15,7 +15,6 @@ util/thread_map.c
15util/util.c 15util/util.c
16util/xyarray.c 16util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/debugfs.c
19util/rblist.c 18util/rblist.c
20util/strlist.c 19util/strlist.c
21util/sysfs.c 20util/sysfs.c
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index bd85280bb6e8..ab265c2cfab3 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1365,18 +1365,6 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1365 return machine__fprintf(&session->machines.host, fp); 1365 return machine__fprintf(&session->machines.host, fp);
1366} 1366}
1367 1367
1368void perf_session__remove_thread(struct perf_session *session,
1369 struct thread *th)
1370{
1371 /*
1372 * FIXME: This one makes no sense, we need to remove the thread from
1373 * the machine it belongs to, perf_session can have many machines, so
1374 * doing it always on ->machines.host is wrong. Fix when auditing all
1375 * the 'perf kvm' code.
1376 */
1377 machine__remove_thread(&session->machines.host, th);
1378}
1379
1380struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1368struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1381 unsigned int type) 1369 unsigned int type)
1382{ 1370{
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index b5c0847edfa9..6b51d47acdba 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -72,7 +72,6 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
72int perf_session__create_kernel_maps(struct perf_session *self); 72int perf_session__create_kernel_maps(struct perf_session *self);
73 73
74void perf_session__set_id_hdr_size(struct perf_session *session); 74void perf_session__set_id_hdr_size(struct perf_session *session);
75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
76 75
77static inline 76static inline
78struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 77struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 73d510269784..6b0ed322907e 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -24,6 +24,7 @@ cflags += getenv('CFLAGS', '').split()
24build_lib = getenv('PYTHON_EXTBUILD_LIB') 24build_lib = getenv('PYTHON_EXTBUILD_LIB')
25build_tmp = getenv('PYTHON_EXTBUILD_TMP') 25build_tmp = getenv('PYTHON_EXTBUILD_TMP')
26libtraceevent = getenv('LIBTRACEEVENT') 26libtraceevent = getenv('LIBTRACEEVENT')
27liblk = getenv('LIBLK')
27 28
28ext_sources = [f.strip() for f in file('util/python-ext-sources') 29ext_sources = [f.strip() for f in file('util/python-ext-sources')
29 if len(f.strip()) > 0 and f[0] != '#'] 30 if len(f.strip()) > 0 and f[0] != '#']
@@ -32,7 +33,7 @@ perf = Extension('perf',
32 sources = ext_sources, 33 sources = ext_sources,
33 include_dirs = ['util/include'], 34 include_dirs = ['util/include'],
34 extra_compile_args = cflags, 35 extra_compile_args = cflags,
35 extra_objects = [libtraceevent], 36 extra_objects = [libtraceevent, liblk],
36 ) 37 )
37 38
38setup(name='perf', 39setup(name='perf',
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index f718df8a3c59..0cd8b3108084 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -21,4 +21,9 @@ void thread_map__delete(struct thread_map *threads);
21 21
22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
23 23
24static inline int thread_map__nr(struct thread_map *threads)
25{
26 return threads ? threads->nr : 1;
27}
28
24#endif /* __PERF_THREAD_MAP_H */ 29#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index a8d81c35ef66..5729f434c5b1 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,35 +38,14 @@
38 38
39#include "../perf.h" 39#include "../perf.h"
40#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h" 41#include <lk/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43 43
44#define VERSION "0.5" 44#define VERSION "0.5"
45 45
46#define TRACE_CTRL "tracing_on"
47#define TRACE "trace"
48#define AVAILABLE "available_tracers"
49#define CURRENT "current_tracer"
50#define ITER_CTRL "trace_options"
51#define MAX_LATENCY "tracing_max_latency"
52
53unsigned int page_size;
54
55static const char *output_file = "trace.info"; 46static const char *output_file = "trace.info";
56static int output_fd; 47static int output_fd;
57 48
58struct event_list {
59 struct event_list *next;
60 const char *event;
61};
62
63struct events {
64 struct events *sibling;
65 struct events *children;
66 struct events *next;
67 char *name;
68};
69
70 49
71static void *malloc_or_die(unsigned int size) 50static void *malloc_or_die(unsigned int size)
72{ 51{
@@ -80,7 +59,7 @@ static void *malloc_or_die(unsigned int size)
80 59
81static const char *find_debugfs(void) 60static const char *find_debugfs(void)
82{ 61{
83 const char *path = debugfs_mount(NULL); 62 const char *path = perf_debugfs_mount(NULL);
84 63
85 if (!path) 64 if (!path)
86 die("Your kernel not support debugfs filesystem"); 65 die("Your kernel not support debugfs filesystem");
@@ -131,17 +110,10 @@ static void put_tracing_file(char *file)
131 free(file); 110 free(file);
132} 111}
133 112
134static ssize_t calc_data_size;
135
136static ssize_t write_or_die(const void *buf, size_t len) 113static ssize_t write_or_die(const void *buf, size_t len)
137{ 114{
138 int ret; 115 int ret;
139 116
140 if (calc_data_size) {
141 calc_data_size += len;
142 return len;
143 }
144
145 ret = write(output_fd, buf, len); 117 ret = write(output_fd, buf, len);
146 if (ret < 0) 118 if (ret < 0)
147 die("writing to '%s'", output_file); 119 die("writing to '%s'", output_file);
@@ -457,7 +429,6 @@ static void tracing_data_header(void)
457 write_or_die(buf, 1); 429 write_or_die(buf, 1);
458 430
459 /* save page_size */ 431 /* save page_size */
460 page_size = sysconf(_SC_PAGESIZE);
461 write_or_die(&page_size, 4); 432 write_or_die(&page_size, 4);
462} 433}
463 434
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 3aabcd687cd5..4454835a9ebc 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -183,43 +183,6 @@ void event_format__print(struct event_format *event,
183 trace_seq_do_printf(&s); 183 trace_seq_do_printf(&s);
184} 184}
185 185
186void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
187{
188 int type = trace_parse_common_type(pevent, data);
189 struct event_format *event = pevent_find_event(pevent, type);
190
191 if (!event) {
192 warning("ug! no event found for type %d", type);
193 return;
194 }
195
196 event_format__print(event, cpu, data, size);
197}
198
199void print_event(struct pevent *pevent, int cpu, void *data, int size,
200 unsigned long long nsecs, char *comm)
201{
202 struct pevent_record record;
203 struct trace_seq s;
204 int pid;
205
206 pevent->latency_format = latency_format;
207
208 record.ts = nsecs;
209 record.cpu = cpu;
210 record.size = size;
211 record.data = data;
212 pid = pevent_data_pid(pevent, &record);
213
214 if (!pevent_pid_is_registered(pevent, pid))
215 pevent_register_comm(pevent, comm, pid);
216
217 trace_seq_init(&s);
218 pevent_print_event(pevent, &s, &record);
219 trace_seq_do_printf(&s);
220 printf("\n");
221}
222
223void parse_proc_kallsyms(struct pevent *pevent, 186void parse_proc_kallsyms(struct pevent *pevent,
224 char *file, unsigned int size __maybe_unused) 187 char *file, unsigned int size __maybe_unused)
225{ 188{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 3741572696af..7cb24635adf2 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -41,8 +41,6 @@
41 41
42static int input_fd; 42static int input_fd;
43 43
44static int read_page;
45
46int file_bigendian; 44int file_bigendian;
47int host_bigendian; 45int host_bigendian;
48static int long_size; 46static int long_size;
@@ -287,205 +285,6 @@ static void read_event_files(struct pevent *pevent)
287 } 285 }
288} 286}
289 287
290struct cpu_data {
291 unsigned long long offset;
292 unsigned long long size;
293 unsigned long long timestamp;
294 struct pevent_record *next;
295 char *page;
296 int cpu;
297 int index;
298 int page_size;
299};
300
301static struct cpu_data *cpu_data;
302
303static void update_cpu_data_index(int cpu)
304{
305 cpu_data[cpu].offset += page_size;
306 cpu_data[cpu].size -= page_size;
307 cpu_data[cpu].index = 0;
308}
309
310static void get_next_page(int cpu)
311{
312 off_t save_seek;
313 off_t ret;
314
315 if (!cpu_data[cpu].page)
316 return;
317
318 if (read_page) {
319 if (cpu_data[cpu].size <= page_size) {
320 free(cpu_data[cpu].page);
321 cpu_data[cpu].page = NULL;
322 return;
323 }
324
325 update_cpu_data_index(cpu);
326
327 /* other parts of the code may expect the pointer to not move */
328 save_seek = lseek(input_fd, 0, SEEK_CUR);
329
330 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
331 if (ret == (off_t)-1)
332 die("failed to lseek");
333 ret = read(input_fd, cpu_data[cpu].page, page_size);
334 if (ret < 0)
335 die("failed to read page");
336
337 /* reset the file pointer back */
338 lseek(input_fd, save_seek, SEEK_SET);
339
340 return;
341 }
342
343 munmap(cpu_data[cpu].page, page_size);
344 cpu_data[cpu].page = NULL;
345
346 if (cpu_data[cpu].size <= page_size)
347 return;
348
349 update_cpu_data_index(cpu);
350
351 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
352 input_fd, cpu_data[cpu].offset);
353 if (cpu_data[cpu].page == MAP_FAILED)
354 die("failed to mmap cpu %d at offset 0x%llx",
355 cpu, cpu_data[cpu].offset);
356}
357
358static unsigned int type_len4host(unsigned int type_len_ts)
359{
360 if (file_bigendian)
361 return (type_len_ts >> 27) & ((1 << 5) - 1);
362 else
363 return type_len_ts & ((1 << 5) - 1);
364}
365
366static unsigned int ts4host(unsigned int type_len_ts)
367{
368 if (file_bigendian)
369 return type_len_ts & ((1 << 27) - 1);
370 else
371 return type_len_ts >> 5;
372}
373
374static int calc_index(void *ptr, int cpu)
375{
376 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
377}
378
379struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
380{
381 struct pevent_record *data;
382 void *page = cpu_data[cpu].page;
383 int idx = cpu_data[cpu].index;
384 void *ptr = page + idx;
385 unsigned long long extend;
386 unsigned int type_len_ts;
387 unsigned int type_len;
388 unsigned int delta;
389 unsigned int length = 0;
390
391 if (cpu_data[cpu].next)
392 return cpu_data[cpu].next;
393
394 if (!page)
395 return NULL;
396
397 if (!idx) {
398 /* FIXME: handle header page */
399 if (header_page_ts_size != 8)
400 die("expected a long long type for timestamp");
401 cpu_data[cpu].timestamp = data2host8(pevent, ptr);
402 ptr += 8;
403 switch (header_page_size_size) {
404 case 4:
405 cpu_data[cpu].page_size = data2host4(pevent, ptr);
406 ptr += 4;
407 break;
408 case 8:
409 cpu_data[cpu].page_size = data2host8(pevent, ptr);
410 ptr += 8;
411 break;
412 default:
413 die("bad long size");
414 }
415 ptr = cpu_data[cpu].page + header_page_data_offset;
416 }
417
418read_again:
419 idx = calc_index(ptr, cpu);
420
421 if (idx >= cpu_data[cpu].page_size) {
422 get_next_page(cpu);
423 return trace_peek_data(pevent, cpu);
424 }
425
426 type_len_ts = data2host4(pevent, ptr);
427 ptr += 4;
428
429 type_len = type_len4host(type_len_ts);
430 delta = ts4host(type_len_ts);
431
432 switch (type_len) {
433 case RINGBUF_TYPE_PADDING:
434 if (!delta)
435 die("error, hit unexpected end of page");
436 length = data2host4(pevent, ptr);
437 ptr += 4;
438 length *= 4;
439 ptr += length;
440 goto read_again;
441
442 case RINGBUF_TYPE_TIME_EXTEND:
443 extend = data2host4(pevent, ptr);
444 ptr += 4;
445 extend <<= TS_SHIFT;
446 extend += delta;
447 cpu_data[cpu].timestamp += extend;
448 goto read_again;
449
450 case RINGBUF_TYPE_TIME_STAMP:
451 ptr += 12;
452 break;
453 case 0:
454 length = data2host4(pevent, ptr);
455 ptr += 4;
456 die("here! length=%d", length);
457 break;
458 default:
459 length = type_len * 4;
460 break;
461 }
462
463 cpu_data[cpu].timestamp += delta;
464
465 data = malloc_or_die(sizeof(*data));
466 memset(data, 0, sizeof(*data));
467
468 data->ts = cpu_data[cpu].timestamp;
469 data->size = length;
470 data->data = ptr;
471 ptr += length;
472
473 cpu_data[cpu].index = calc_index(ptr, cpu);
474 cpu_data[cpu].next = data;
475
476 return data;
477}
478
479struct pevent_record *trace_read_data(struct pevent *pevent, int cpu)
480{
481 struct pevent_record *data;
482
483 data = trace_peek_data(pevent, cpu);
484 cpu_data[cpu].next = NULL;
485
486 return data;
487}
488
489ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 288ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
490{ 289{
491 char buf[BUFSIZ]; 290 char buf[BUFSIZ];
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a55fd37ffea1..28ccde8ba20f 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -30,13 +30,9 @@ enum {
30int bigendian(void); 30int bigendian(void);
31 31
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 32struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
33void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
34void event_format__print(struct event_format *event, 33void event_format__print(struct event_format *event,
35 int cpu, void *data, int size); 34 int cpu, void *data, int size);
36 35
37void print_event(struct pevent *pevent, int cpu, void *data, int size,
38 unsigned long long nsecs, char *comm);
39
40int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); 36int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
41int parse_event_file(struct pevent *pevent, 37int parse_event_file(struct pevent *pevent,
42 char *buf, unsigned long size, char *sys); 38 char *buf, unsigned long size, char *sys);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 805d1f52c5b4..59d868add275 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,8 @@ bool test_attr__enabled;
17bool perf_host = true; 17bool perf_host = true;
18bool perf_guest = false; 18bool perf_guest = false;
19 19
20char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
21
20void event_attr_init(struct perf_event_attr *attr) 22void event_attr_init(struct perf_event_attr *attr)
21{ 23{
22 if (!perf_host) 24 if (!perf_host)
@@ -242,3 +244,28 @@ void get_term_dimensions(struct winsize *ws)
242 ws->ws_row = 25; 244 ws->ws_row = 25;
243 ws->ws_col = 80; 245 ws->ws_col = 80;
244} 246}
247
248static void set_tracing_events_path(const char *mountpoint)
249{
250 snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
251 mountpoint, "tracing/events");
252}
253
254const char *perf_debugfs_mount(const char *mountpoint)
255{
256 const char *mnt;
257
258 mnt = debugfs_mount(mountpoint);
259 if (!mnt)
260 return NULL;
261
262 set_tracing_events_path(mnt);
263
264 return mnt;
265}
266
267void perf_debugfs_set_path(const char *mntpt)
268{
269 snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
270 set_tracing_events_path(mntpt);
271}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 09b4c26b71aa..6a0781c3a573 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -73,10 +73,14 @@
73#include <linux/magic.h> 73#include <linux/magic.h>
74#include "types.h" 74#include "types.h"
75#include <sys/ttydefaults.h> 75#include <sys/ttydefaults.h>
76#include <lk/debugfs.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;
79extern char buildid_dir[]; 80extern char buildid_dir[];
81extern char tracing_events_path[];
82extern void perf_debugfs_set_path(const char *mountpoint);
83const char *perf_debugfs_mount(const char *mountpoint);
80 84
81/* On most systems <limits.h> would have given us this, but 85/* On most systems <limits.h> would have given us this, but
82 * not on some systems (e.g. GNU/Hurd). 86 * not on some systems (e.g. GNU/Hurd).
@@ -274,5 +278,4 @@ extern unsigned int page_size;
274 278
275struct winsize; 279struct winsize;
276void get_term_dimensions(struct winsize *ws); 280void get_term_dimensions(struct winsize *ws);
277 281#endif /* GIT_COMPAT_UTIL_H */
278#endif
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 2964b96aa55f..f03e681f8891 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -1,3 +1,4 @@
1ifneq ($(O),)
1ifeq ($(origin O), command line) 2ifeq ($(origin O), command line)
2 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) 3 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
3 ABSOLUTE_O := $(shell cd $(O) ; pwd) 4 ABSOLUTE_O := $(shell cd $(O) ; pwd)
@@ -7,9 +8,10 @@ ifeq ($(objtree),)
7 objtree := $(O) 8 objtree := $(O)
8endif 9endif
9endif 10endif
11endif
10 12
11ifneq ($(OUTPUT),)
12# check that the output directory actually exists 13# check that the output directory actually exists
14ifneq ($(OUTPUT),)
13OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) 15OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
14$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) 16$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
15endif 17endif
@@ -70,7 +72,7 @@ ifndef V
70 QUIET_BISON = @echo ' ' BISON $@; 72 QUIET_BISON = @echo ' ' BISON $@;
71 73
72 descend = \ 74 descend = \
73 @echo ' ' DESCEND $(1); \ 75 +@echo ' ' DESCEND $(1); \
74 mkdir -p $(OUTPUT)$(1) && \ 76 mkdir -p $(OUTPUT)$(1) && \
75 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) 77 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
76endif 78endif
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
index 8e30e5c40f8a..24e9ddd93fa4 100644
--- a/tools/vm/Makefile
+++ b/tools/vm/Makefile
@@ -1,11 +1,22 @@
1# Makefile for vm tools 1# Makefile for vm tools
2#
3TARGETS=page-types slabinfo
4
5LK_DIR = ../lib/lk
6LIBLK = $(LK_DIR)/liblk.a
2 7
3CC = $(CROSS_COMPILE)gcc 8CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall -Wextra 9CFLAGS = -Wall -Wextra -I../lib/
10LDFLAGS = $(LIBLK)
11
12$(TARGETS): liblk
13
14liblk:
15 make -C $(LK_DIR)
5 16
6all: page-types slabinfo
7%: %.c 17%: %.c
8 $(CC) $(CFLAGS) -o $@ $^ 18 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
9 19
10clean: 20clean:
11 $(RM) page-types slabinfo 21 $(RM) page-types slabinfo
22 make -C ../lib/lk clean
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index b76edf2f8333..71c9c2511ee7 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 39#include <lk/debugfs.h>
40 40
41#ifndef MAX_PATH 41#ifndef MAX_PATH
42# define MAX_PATH 256 42# define MAX_PATH 256
@@ -178,7 +178,7 @@ static int kpageflags_fd;
178static int opt_hwpoison; 178static int opt_hwpoison;
179static int opt_unpoison; 179static int opt_unpoison;
180 180
181static char hwpoison_debug_fs[MAX_PATH+1]; 181static char *hwpoison_debug_fs;
182static int hwpoison_inject_fd; 182static int hwpoison_inject_fd;
183static int hwpoison_forget_fd; 183static int hwpoison_forget_fd;
184 184
@@ -458,81 +458,6 @@ static uint64_t kpageflags_flags(uint64_t flags)
458 return flags; 458 return flags;
459} 459}
460 460
461/* verify that a mountpoint is actually a debugfs instance */
462static int debugfs_valid_mountpoint(const char *debugfs)
463{
464 struct statfs st_fs;
465
466 if (statfs(debugfs, &st_fs) < 0)
467 return -ENOENT;
468 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
469 return -ENOENT;
470
471 return 0;
472}
473
474/* find the path to the mounted debugfs */
475static const char *debugfs_find_mountpoint(void)
476{
477 const char *const *ptr;
478 char type[100];
479 FILE *fp;
480
481 ptr = debugfs_known_mountpoints;
482 while (*ptr) {
483 if (debugfs_valid_mountpoint(*ptr) == 0) {
484 strcpy(hwpoison_debug_fs, *ptr);
485 return hwpoison_debug_fs;
486 }
487 ptr++;
488 }
489
490 /* give up and parse /proc/mounts */
491 fp = fopen("/proc/mounts", "r");
492 if (fp == NULL)
493 perror("Can't open /proc/mounts for read");
494
495 while (fscanf(fp, "%*s %"
496 STR(MAX_PATH)
497 "s %99s %*s %*d %*d\n",
498 hwpoison_debug_fs, type) == 2) {
499 if (strcmp(type, "debugfs") == 0)
500 break;
501 }
502 fclose(fp);
503
504 if (strcmp(type, "debugfs") != 0)
505 return NULL;
506
507 return hwpoison_debug_fs;
508}
509
510/* mount the debugfs somewhere if it's not mounted */
511
512static void debugfs_mount(void)
513{
514 const char *const *ptr;
515
516 /* see if it's already mounted */
517 if (debugfs_find_mountpoint())
518 return;
519
520 ptr = debugfs_known_mountpoints;
521 while (*ptr) {
522 if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
523 /* save the mountpoint */
524 strcpy(hwpoison_debug_fs, *ptr);
525 break;
526 }
527 ptr++;
528 }
529
530 if (*ptr == NULL) {
531 perror("mount debugfs");
532 exit(EXIT_FAILURE);
533 }
534}
535
536/* 461/*
537 * page actions 462 * page actions
538 */ 463 */
@@ -541,7 +466,11 @@ static void prepare_hwpoison_fd(void)
541{ 466{
542 char buf[MAX_PATH + 1]; 467 char buf[MAX_PATH + 1];
543 468
544 debugfs_mount(); 469 hwpoison_debug_fs = debugfs_mount(NULL);
470 if (!hwpoison_debug_fs) {
471 perror("mount debugfs");
472 exit(EXIT_FAILURE);
473 }
545 474
546 if (opt_hwpoison && !hwpoison_inject_fd) { 475 if (opt_hwpoison && !hwpoison_inject_fd) {
547 snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", 476 snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",