aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 10:41:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 10:41:01 -0400
commite0972916e8fe943f342b0dd1c9d43dbf5bc261c2 (patch)
tree690c436f1f9b839c4ba34d17ab3efa63b97a2dce /tools
parent1f889ec62c3f0d8913f3c32f9aff2a1e15099346 (diff)
parent5ac2b5c2721501a8f5c5e1cd4116cbc31ace6886 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "Features: - Add "uretprobes" - an optimization to uprobes, like kretprobes are an optimization to kprobes. "perf probe -x file sym%return" now works like kretprobes. By Oleg Nesterov. - Introduce per core aggregation in 'perf stat', from Stephane Eranian. - Add memory profiling via PEBS, from Stephane Eranian. - Event group view for 'annotate' in --stdio, --tui and --gtk, from Namhyung Kim. - Add support for AMD NB and L2I "uncore" counters, by Jacob Shin. - Add Ivy Bridge-EP uncore support, by Zheng Yan - IBM zEnterprise EC12 oprofile support patchlet from Robert Richter. - Add perf test entries for checking breakpoint overflow signal handler issues, from Jiri Olsa. - Add perf test entry for for checking number of EXIT events, from Namhyung Kim. - Add perf test entries for checking --cpu in record and stat, from Jiri Olsa. - Introduce perf stat --repeat forever, from Frederik Deweerdt. - Add --no-demangle to report/top, from Namhyung Kim. - PowerPC fixes plus a couple of cleanups/optimizations in uprobes and trace_uprobes, by Oleg Nesterov. Various fixes and refactorings: - Fix dependency of the python binding wrt libtraceevent, from Naohiro Aota. - Simplify some perf_evlist methods and to allow 'stat' to share code with 'record' and 'trace', by Arnaldo Carvalho de Melo. - Remove dead code in related to libtraceevent integration, from Namhyung Kim. - Revert "perf sched: Handle PERF_RECORD_EXIT events" to get 'perf sched lat' back working, by Arnaldo Carvalho de Melo - We don't use Newt anymore, just plain libslang, by Arnaldo Carvalho de Melo. - Kill a bunch of die() calls, from Namhyung Kim. - Fix build on non-glibc systems due to libio.h absence, from Cody P Schafer. - Remove some perf_session and tracing dead code, from David Ahern. - Honor parallel jobs, fix from Borislav Petkov - Introduce tools/lib/lk library, initially just removing duplication among tools/perf and tools/vm. from Borislav Petkov ... and many more I missed to list, see the shortlog and git log for more details." * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (136 commits) perf/x86/intel/P4: Robistify P4 PMU types perf/x86/amd: Fix AMD NB and L2I "uncore" support perf/x86/amd: Remove old-style NB counter support from perf_event_amd.c perf/x86: Check all MSRs before passing hw check perf/x86/amd: Add support for AMD NB and L2I "uncore" counters perf/x86/intel: Add Ivy Bridge-EP uncore support perf/x86/intel: Fix SNB-EP CBO and PCU uncore PMU filter management perf/x86: Avoid kfree() in CPU_{STARTING,DYING} uprobes/perf: Avoid perf_trace_buf_prepare/submit if ->perf_events is empty uprobes/tracing: Don't pass addr=ip to perf_trace_buf_submit() uprobes/tracing: Change create_trace_uprobe() to support uretprobes uprobes/tracing: Make seq_printf() code uretprobe-friendly uprobes/tracing: Make register_uprobe_event() paths uretprobe-friendly uprobes/tracing: Make uprobe_{trace,perf}_print() uretprobe-friendly uprobes/tracing: Introduce is_ret_probe() and uretprobe_dispatcher() uprobes/tracing: Introduce uprobe_{trace,perf}_print() helpers uprobes/tracing: Generalize struct uprobe_trace_entry_head uprobes/tracing: Kill the pointless local_save_flags/preempt_count calls uprobes/tracing: Kill the pointless seq_print_ip_sym() call uprobes/tracing: Kill the pointless task_pt_regs() calls ...
Diffstat (limited to 'tools')
-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-mem.txt48
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt6
-rw-r--r--tools/perf/Documentation/perf-stat.txt12
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile61
-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.c25
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-mem.c242
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/builtin-record.c15
-rw-r--r--tools/perf/builtin-report.c150
-rw-r--r--tools/perf/builtin-sched.c1
-rw-r--r--tools/perf/builtin-stat.c398
-rw-r--r--tools/perf/builtin-top.c9
-rw-r--r--tools/perf/builtin-trace.c28
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt15
-rw-r--r--tools/perf/config/feature-tests.mak12
-rw-r--r--tools/perf/perf.c12
-rw-r--r--tools/perf/perf.h1
-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.c6
-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/browser.c9
-rw-r--r--tools/perf/ui/browser.h1
-rw-r--r--tools/perf/ui/browsers/annotate.c158
-rw-r--r--tools/perf/ui/browsers/hists.c7
-rw-r--r--tools/perf/ui/browsers/map.c60
-rw-r--r--tools/perf/ui/browsers/scripts.c1
-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/ui/tui/setup.c21
-rw-r--r--tools/perf/ui/ui.h2
-rw-r--r--tools/perf/util/annotate.c262
-rw-r--r--tools/perf/util/annotate.h51
-rw-r--r--tools/perf/util/cpumap.c86
-rw-r--r--tools/perf/util/cpumap.h12
-rw-r--r--tools/perf/util/debugfs.h12
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c32
-rw-r--r--tools/perf/util/evsel.h25
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/hist.c110
-rw-r--r--tools/perf/util/hist.h28
-rw-r--r--tools/perf/util/machine.c64
-rw-r--r--tools/perf/util/machine.h4
-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.c20
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/sort.c414
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/symbol-elf.c9
-rw-r--r--tools/perf/util/symbol.c1
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread_map.h5
-rw-r--r--tools/perf/util/trace-event-info.c380
-rw-r--r--tools/perf/util/trace-event-parse.c37
-rw-r--r--tools/perf/util/trace-event-read.c473
-rw-r--r--tools/perf/util/trace-event.h6
-rw-r--r--tools/perf/util/util.c27
-rw-r--r--tools/perf/util/util.h9
-rw-r--r--tools/scripts/Makefile.include6
-rw-r--r--tools/vm/Makefile17
-rw-r--r--tools/vm/page-types.c85
99 files changed, 3243 insertions, 1222 deletions
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-mem.txt b/tools/perf/Documentation/perf-mem.txt
new file mode 100644
index 000000000000..888d51137fbe
--- /dev/null
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -0,0 +1,48 @@
1perf-mem(1)
2===========
3
4NAME
5----
6perf-mem - Profile memory accesses
7
8SYNOPSIS
9--------
10[verse]
11'perf mem' [<options>] (record [<command>] | report)
12
13DESCRIPTION
14-----------
15"perf mem -t <TYPE> record" runs a command and gathers memory operation data
16from it, into perf.data. Perf record options are accepted and are passed through.
17
18"perf mem -t <TYPE> report" displays the result. It invokes perf report with the
19right set of options to display a memory access profile.
20
21OPTIONS
22-------
23<command>...::
24 Any command you can specify in a shell.
25
26-t::
27--type=::
28 Select the memory operation type: load or store (default: load)
29
30-D::
31--dump-raw-samples=::
32 Dump the raw decoded samples on the screen in a format that is easy to parse with
33 one sample per line.
34
35-x::
36--field-separator::
37 Specify the field separator used when dump raw samples (-D option). By default,
38 The separator is the space character.
39
40-C::
41--cpu-list::
42 Restrict dump of raw samples to those provided via this option. Note that the same
43 option can be passed in record mode. It will be interpreted the same way as perf
44 record.
45
46SEE ALSO
47--------
48linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 938e8904f64d..d4da111ef53d 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -182,6 +182,12 @@ is enabled for all the sampling events. The sampled branch type is the same for
182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 182The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
183Note that this feature may not be available on all processors. 183Note that this feature may not be available on all processors.
184 184
185-W::
186--weight::
187Enable weightened sampling. An additional weight is recorded per sample and can be
188displayed with the weight and local_weight sort keys. This currently works for TSX
189abort events and some memory events in precise mode on modern Intel CPUs.
190
185SEE ALSO 191SEE ALSO
186-------- 192--------
187linkperf:perf-stat[1], linkperf:perf-list[1] 193linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 02284a0067f0..7d5f4f38aa52 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -59,7 +59,7 @@ OPTIONS
59--sort=:: 59--sort=::
60 Sort histogram entries by given key(s) - multiple keys can be specified 60 Sort histogram entries by given key(s) - multiple keys can be specified
61 in CSV format. Following sort keys are available: 61 in CSV format. Following sort keys are available:
62 pid, comm, dso, symbol, parent, cpu, srcline. 62 pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight.
63 63
64 Each key has following meaning: 64 Each key has following meaning:
65 65
@@ -206,6 +206,10 @@ OPTIONS
206--group:: 206--group::
207 Show event group information together. 207 Show event group information together.
208 208
209--demangle::
210 Demangle symbol names to human readable form. It's enabled by default,
211 disable with --no-demangle.
212
209SEE ALSO 213SEE ALSO
210-------- 214--------
211linkperf:perf-stat[1], linkperf:perf-annotate[1] 215linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index faf4f4feebcc..2fe87fb558f0 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::
@@ -119,13 +119,19 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m
119 Print count deltas every N milliseconds (minimum: 100ms) 119 Print count deltas every N milliseconds (minimum: 100ms)
120 example: perf stat -I 1000 -e cycles -a sleep 5 120 example: perf stat -I 1000 -e cycles -a sleep 5
121 121
122--aggr-socket:: 122--per-socket::
123Aggregate counts per processor socket for system-wide mode measurements. This 123Aggregate counts per processor socket for system-wide mode measurements. This
124is a useful mode to detect imbalance between sockets. To enable this mode, 124is a useful mode to detect imbalance between sockets. To enable this mode,
125use --aggr-socket in addition to -a. (system-wide). The output includes the 125use --per-socket in addition to -a. (system-wide). The output includes the
126socket number and the number of online processors on that socket. This is 126socket number and the number of online processors on that socket. This is
127useful to gauge the amount of aggregation. 127useful to gauge the amount of aggregation.
128 128
129--per-core::
130Aggregate counts per physical processor for system-wide mode measurements. This
131is a useful mode to detect imbalance between physical cores. To enable this mode,
132use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor.
134
129EXAMPLES 135EXAMPLES
130-------- 136--------
131 137
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index a414bc95fd52..9f1a2fe54757 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
112 112
113-s:: 113-s::
114--sort:: 114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight.
116 116
117-n:: 117-n::
118--show-nr-samples:: 118--show-nr-samples::
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..b0f164b133d9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -35,7 +35,9 @@ include config/utilities.mak
35# 35#
36# Define WERROR=0 to disable treating any warnings as errors. 36# Define WERROR=0 to disable treating any warnings as errors.
37# 37#
38# Define NO_NEWT if you do not want TUI support. 38# Define NO_NEWT if you do not want TUI support. (deprecated)
39#
40# Define NO_SLANG if you do not want TUI support.
39# 41#
40# Define NO_GTK2 if you do not want GTK+ GUI support. 42# Define NO_GTK2 if you do not want GTK+ GUI support.
41# 43#
@@ -104,6 +106,10 @@ ifdef PARSER_DEBUG
104 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG 106 PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
105endif 107endif
106 108
109ifdef NO_NEWT
110 NO_SLANG=1
111endif
112
107CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) 113CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
108EXTLIBS = -lpthread -lrt -lelf -lm 114EXTLIBS = -lpthread -lrt -lelf -lm
109ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 115ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
@@ -215,6 +221,7 @@ BASIC_CFLAGS = \
215 -Iutil \ 221 -Iutil \
216 -I. \ 222 -I. \
217 -I$(TRACE_EVENT_DIR) \ 223 -I$(TRACE_EVENT_DIR) \
224 -I../lib/ \
218 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 225 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
219 226
220BASIC_LDFLAGS = 227BASIC_LDFLAGS =
@@ -240,19 +247,28 @@ SCRIPT_SH += perf-archive.sh
240grep-libs = $(filter -l%,$(1)) 247grep-libs = $(filter -l%,$(1))
241strip-libs = $(filter-out -l%,$(1)) 248strip-libs = $(filter-out -l%,$(1))
242 249
250LK_DIR = ../lib/lk/
243TRACE_EVENT_DIR = ../lib/traceevent/ 251TRACE_EVENT_DIR = ../lib/traceevent/
244 252
253LK_PATH=$(LK_DIR)
254
245ifneq ($(OUTPUT),) 255ifneq ($(OUTPUT),)
246 TE_PATH=$(OUTPUT) 256 TE_PATH=$(OUTPUT)
257ifneq ($(subdir),)
258 LK_PATH=$(OUTPUT)$(LK_DIR)
259else
260 LK_PATH=$(OUTPUT)
261endif
247else 262else
248 TE_PATH=$(TRACE_EVENT_DIR) 263 TE_PATH=$(TRACE_EVENT_DIR)
249endif 264endif
250 265
251LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 266LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
252TE_LIB := -L$(TE_PATH) -ltraceevent
253
254export LIBTRACEEVENT 267export LIBTRACEEVENT
255 268
269LIBLK = $(LK_PATH)liblk.a
270export LIBLK
271
256# python extension build directories 272# python extension build directories
257PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 273PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
258PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ 274PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -262,7 +278,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
262python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 278python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
263 279
264PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 280PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
265PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py 281PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT)
266 282
267$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 283$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
268 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 284 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
@@ -355,7 +371,6 @@ LIB_H += util/cache.h
355LIB_H += util/callchain.h 371LIB_H += util/callchain.h
356LIB_H += util/build-id.h 372LIB_H += util/build-id.h
357LIB_H += util/debug.h 373LIB_H += util/debug.h
358LIB_H += util/debugfs.h
359LIB_H += util/sysfs.h 374LIB_H += util/sysfs.h
360LIB_H += util/pmu.h 375LIB_H += util/pmu.h
361LIB_H += util/event.h 376LIB_H += util/event.h
@@ -416,7 +431,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
416LIB_OBJS += $(OUTPUT)util/build-id.o 431LIB_OBJS += $(OUTPUT)util/build-id.o
417LIB_OBJS += $(OUTPUT)util/config.o 432LIB_OBJS += $(OUTPUT)util/config.o
418LIB_OBJS += $(OUTPUT)util/ctype.o 433LIB_OBJS += $(OUTPUT)util/ctype.o
419LIB_OBJS += $(OUTPUT)util/debugfs.o
420LIB_OBJS += $(OUTPUT)util/sysfs.o 434LIB_OBJS += $(OUTPUT)util/sysfs.o
421LIB_OBJS += $(OUTPUT)util/pmu.o 435LIB_OBJS += $(OUTPUT)util/pmu.o
422LIB_OBJS += $(OUTPUT)util/environment.o 436LIB_OBJS += $(OUTPUT)util/environment.o
@@ -503,6 +517,10 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
503LIB_OBJS += $(OUTPUT)tests/pmu.o 517LIB_OBJS += $(OUTPUT)tests/pmu.o
504LIB_OBJS += $(OUTPUT)tests/hists_link.o 518LIB_OBJS += $(OUTPUT)tests/hists_link.o
505LIB_OBJS += $(OUTPUT)tests/python-use.o 519LIB_OBJS += $(OUTPUT)tests/python-use.o
520LIB_OBJS += $(OUTPUT)tests/bp_signal.o
521LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
522LIB_OBJS += $(OUTPUT)tests/task-exit.o
523LIB_OBJS += $(OUTPUT)tests/sw-clock.o
506 524
507BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 525BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
508BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 526BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -535,8 +553,9 @@ BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
535BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 553BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
536BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 554BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
537BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 555BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
556BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
538 557
539PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 558PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
540 559
541# 560#
542# Platform specific tweaks 561# Platform specific tweaks
@@ -667,15 +686,15 @@ ifndef NO_LIBAUDIT
667 endif 686 endif
668endif 687endif
669 688
670ifndef NO_NEWT 689ifndef NO_SLANG
671 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 690 FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
672 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y) 691 ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
673 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 692 msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
674 else 693 else
675 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 694 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
676 BASIC_CFLAGS += -I/usr/include/slang 695 BASIC_CFLAGS += -I/usr/include/slang
677 BASIC_CFLAGS += -DNEWT_SUPPORT 696 BASIC_CFLAGS += -DSLANG_SUPPORT
678 EXTLIBS += -lnewt -lslang 697 EXTLIBS += -lslang
679 LIB_OBJS += $(OUTPUT)ui/browser.o 698 LIB_OBJS += $(OUTPUT)ui/browser.o
680 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 699 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
681 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 700 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
@@ -1051,6 +1070,18 @@ $(LIBTRACEEVENT):
1051$(LIBTRACEEVENT)-clean: 1070$(LIBTRACEEVENT)-clean:
1052 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean 1071 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1053 1072
1073# if subdir is set, we've been called from above so target has been built
1074# already
1075$(LIBLK):
1076ifeq ($(subdir),)
1077 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
1078endif
1079
1080$(LIBLK)-clean:
1081ifeq ($(subdir),)
1082 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
1083endif
1084
1054help: 1085help:
1055 @echo 'Perf make targets:' 1086 @echo 'Perf make targets:'
1056 @echo ' doc - make *all* documentation (see below)' 1087 @echo ' doc - make *all* documentation (see below)'
@@ -1171,7 +1202,7 @@ $(INSTALL_DOC_TARGETS):
1171 1202
1172### Cleaning rules 1203### Cleaning rules
1173 1204
1174clean: $(LIBTRACEEVENT)-clean 1205clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
1175 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 1206 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1176 $(RM) $(ALL_PROGRAMS) perf 1207 $(RM) $(ALL_PROGRAMS) perf
1177 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 1208 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
@@ -1181,6 +1212,6 @@ clean: $(LIBTRACEEVENT)-clean
1181 $(RM) $(OUTPUT)util/*-flex* 1212 $(RM) $(OUTPUT)util/*-flex*
1182 $(python-clean) 1213 $(python-clean)
1183 1214
1184.PHONY: all install clean strip $(LIBTRACEEVENT) 1215.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
1185.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 1216.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 1217.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..db491e9a812b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -63,7 +63,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
63 return 0; 63 return 0;
64 } 64 }
65 65
66 he = __hists__add_entry(&evsel->hists, al, NULL, 1); 66 he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1);
67 if (he == NULL) 67 if (he == NULL)
68 return -ENOMEM; 68 return -ENOMEM;
69 69
@@ -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-diff.c b/tools/perf/builtin-diff.c
index d207a97a2db1..2d0462d89a97 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -231,9 +231,10 @@ int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
231} 231}
232 232
233static int hists__add_entry(struct hists *self, 233static int hists__add_entry(struct hists *self,
234 struct addr_location *al, u64 period) 234 struct addr_location *al, u64 period,
235 u64 weight)
235{ 236{
236 if (__hists__add_entry(self, al, NULL, period) != NULL) 237 if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
237 return 0; 238 return 0;
238 return -ENOMEM; 239 return -ENOMEM;
239} 240}
@@ -255,7 +256,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
255 if (al.filtered) 256 if (al.filtered)
256 return 0; 257 return 0;
257 258
258 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 259 if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
259 pr_warning("problem incrementing symbol period, skipping event\n"); 260 pr_warning("problem incrementing symbol period, skipping event\n");
260 return -1; 261 return -1;
261 } 262 }
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-mem.c b/tools/perf/builtin-mem.c
new file mode 100644
index 000000000000..a8ff6d264e50
--- /dev/null
+++ b/tools/perf/builtin-mem.c
@@ -0,0 +1,242 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/parse-options.h"
5#include "util/trace-event.h"
6#include "util/tool.h"
7#include "util/session.h"
8
9#define MEM_OPERATION_LOAD "load"
10#define MEM_OPERATION_STORE "store"
11
12static const char *mem_operation = MEM_OPERATION_LOAD;
13
14struct perf_mem {
15 struct perf_tool tool;
16 char const *input_name;
17 symbol_filter_t annotate_init;
18 bool hide_unresolved;
19 bool dump_raw;
20 const char *cpu_list;
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22};
23
24static const char * const mem_usage[] = {
25 "perf mem [<options>] {record <command> |report}",
26 NULL
27};
28
29static int __cmd_record(int argc, const char **argv)
30{
31 int rec_argc, i = 0, j;
32 const char **rec_argv;
33 char event[64];
34 int ret;
35
36 rec_argc = argc + 4;
37 rec_argv = calloc(rec_argc + 1, sizeof(char *));
38 if (!rec_argv)
39 return -1;
40
41 rec_argv[i++] = strdup("record");
42 if (!strcmp(mem_operation, MEM_OPERATION_LOAD))
43 rec_argv[i++] = strdup("-W");
44 rec_argv[i++] = strdup("-d");
45 rec_argv[i++] = strdup("-e");
46
47 if (strcmp(mem_operation, MEM_OPERATION_LOAD))
48 sprintf(event, "cpu/mem-stores/pp");
49 else
50 sprintf(event, "cpu/mem-loads/pp");
51
52 rec_argv[i++] = strdup(event);
53 for (j = 1; j < argc; j++, i++)
54 rec_argv[i] = argv[j];
55
56 ret = cmd_record(i, rec_argv, NULL);
57 free(rec_argv);
58 return ret;
59}
60
61static int
62dump_raw_samples(struct perf_tool *tool,
63 union perf_event *event,
64 struct perf_sample *sample,
65 struct perf_evsel *evsel __maybe_unused,
66 struct machine *machine)
67{
68 struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
69 struct addr_location al;
70 const char *fmt;
71
72 if (perf_event__preprocess_sample(event, machine, &al, sample,
73 mem->annotate_init) < 0) {
74 fprintf(stderr, "problem processing %d event, skipping it.\n",
75 event->header.type);
76 return -1;
77 }
78
79 if (al.filtered || (mem->hide_unresolved && al.sym == NULL))
80 return 0;
81
82 if (al.map != NULL)
83 al.map->dso->hit = 1;
84
85 if (symbol_conf.field_sep) {
86 fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64
87 "%s0x%"PRIx64"%s%s:%s\n";
88 } else {
89 fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
90 "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n";
91 symbol_conf.field_sep = " ";
92 }
93
94 printf(fmt,
95 sample->pid,
96 symbol_conf.field_sep,
97 sample->tid,
98 symbol_conf.field_sep,
99 event->ip.ip,
100 symbol_conf.field_sep,
101 sample->addr,
102 symbol_conf.field_sep,
103 sample->weight,
104 symbol_conf.field_sep,
105 sample->data_src,
106 symbol_conf.field_sep,
107 al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
108 al.sym ? al.sym->name : "???");
109
110 return 0;
111}
112
113static int process_sample_event(struct perf_tool *tool,
114 union perf_event *event,
115 struct perf_sample *sample,
116 struct perf_evsel *evsel,
117 struct machine *machine)
118{
119 return dump_raw_samples(tool, event, sample, evsel, machine);
120}
121
122static int report_raw_events(struct perf_mem *mem)
123{
124 int err = -EINVAL;
125 int ret;
126 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
127 0, false, &mem->tool);
128
129 if (session == NULL)
130 return -ENOMEM;
131
132 if (mem->cpu_list) {
133 ret = perf_session__cpu_bitmap(session, mem->cpu_list,
134 mem->cpu_bitmap);
135 if (ret)
136 goto out_delete;
137 }
138
139 if (symbol__init() < 0)
140 return -1;
141
142 printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
143
144 err = perf_session__process_events(session, &mem->tool);
145 if (err)
146 return err;
147
148 return 0;
149
150out_delete:
151 perf_session__delete(session);
152 return err;
153}
154
155static int report_events(int argc, const char **argv, struct perf_mem *mem)
156{
157 const char **rep_argv;
158 int ret, i = 0, j, rep_argc;
159
160 if (mem->dump_raw)
161 return report_raw_events(mem);
162
163 rep_argc = argc + 3;
164 rep_argv = calloc(rep_argc + 1, sizeof(char *));
165 if (!rep_argv)
166 return -1;
167
168 rep_argv[i++] = strdup("report");
169 rep_argv[i++] = strdup("--mem-mode");
170 rep_argv[i++] = strdup("-n"); /* display number of samples */
171
172 /*
173 * there is no weight (cost) associated with stores, so don't print
174 * the column
175 */
176 if (strcmp(mem_operation, MEM_OPERATION_LOAD))
177 rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr,"
178 "dso_daddr,tlb,locked");
179
180 for (j = 1; j < argc; j++, i++)
181 rep_argv[i] = argv[j];
182
183 ret = cmd_report(i, rep_argv, NULL);
184 free(rep_argv);
185 return ret;
186}
187
188int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
189{
190 struct stat st;
191 struct perf_mem mem = {
192 .tool = {
193 .sample = process_sample_event,
194 .mmap = perf_event__process_mmap,
195 .comm = perf_event__process_comm,
196 .lost = perf_event__process_lost,
197 .fork = perf_event__process_fork,
198 .build_id = perf_event__process_build_id,
199 .ordered_samples = true,
200 },
201 .input_name = "perf.data",
202 };
203 const struct option mem_options[] = {
204 OPT_STRING('t', "type", &mem_operation,
205 "type", "memory operations(load/store)"),
206 OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
207 "dump raw samples in ASCII"),
208 OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
209 "Only display entries resolved to a symbol"),
210 OPT_STRING('i', "input", &input_name, "file",
211 "input file name"),
212 OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
213 "list of cpus to profile"),
214 OPT_STRING('x', "field-separator", &symbol_conf.field_sep,
215 "separator",
216 "separator for columns, no spaces will be added"
217 " between columns '.' is reserved."),
218 OPT_END()
219 };
220
221 argc = parse_options(argc, argv, mem_options, mem_usage,
222 PARSE_OPT_STOP_AT_NON_OPTION);
223
224 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
225 usage_with_options(mem_usage, mem_options);
226
227 if (!mem.input_name || !strlen(mem.input_name)) {
228 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
229 mem.input_name = "-";
230 else
231 mem.input_name = "perf.data";
232 }
233
234 if (!strncmp(argv[0], "rec", 3))
235 return __cmd_record(argc, argv);
236 else if (!strncmp(argv[0], "rep", 3))
237 return report_events(argc, argv, &mem);
238 else
239 usage_with_options(mem_usage, mem_options);
240
241 return 0;
242}
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..cdf58ecc04b1 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,8 +5,6 @@
5 * (or a CPU, or a PID) into the perf.data output file - for 5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report. 6 * later analysis via perf report.
7 */ 7 */
8#define _FILE_OFFSET_BITS 64
9
10#include "builtin.h" 8#include "builtin.h"
11 9
12#include "perf.h" 10#include "perf.h"
@@ -474,7 +472,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
474 } 472 }
475 473
476 if (forks) { 474 if (forks) {
477 err = perf_evlist__prepare_workload(evsel_list, opts, argv); 475 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
476 argv, opts->pipe_output,
477 true);
478 if (err < 0) { 478 if (err < 0) {
479 pr_err("Couldn't run the workload!\n"); 479 pr_err("Couldn't run the workload!\n");
480 goto out_delete_session; 480 goto out_delete_session;
@@ -953,6 +953,8 @@ const struct option record_options[] = {
953 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack, 953 OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
954 "branch filter mask", "branch stack filter modes", 954 "branch filter mask", "branch stack filter modes",
955 parse_branch_stack), 955 parse_branch_stack),
956 OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
957 "sample by weight (on special events only)"),
956 OPT_END() 958 OPT_END()
957}; 959};
958 960
@@ -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..bd0ca81eeaca 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"
@@ -47,6 +46,7 @@ struct perf_report {
47 bool show_full_info; 46 bool show_full_info;
48 bool show_threads; 47 bool show_threads;
49 bool inverted_callchain; 48 bool inverted_callchain;
49 bool mem_mode;
50 struct perf_read_values show_threads_values; 50 struct perf_read_values show_threads_values;
51 const char *pretty_printing_style; 51 const char *pretty_printing_style;
52 symbol_filter_t annotate_init; 52 symbol_filter_t annotate_init;
@@ -65,6 +65,99 @@ static int perf_report_config(const char *var, const char *value, void *cb)
65 return perf_default_config(var, value, cb); 65 return perf_default_config(var, value, cb);
66} 66}
67 67
68static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
69 struct addr_location *al,
70 struct perf_sample *sample,
71 struct perf_evsel *evsel,
72 struct machine *machine,
73 union perf_event *event)
74{
75 struct perf_report *rep = container_of(tool, struct perf_report, tool);
76 struct symbol *parent = NULL;
77 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
78 int err = 0;
79 struct hist_entry *he;
80 struct mem_info *mi, *mx;
81 uint64_t cost;
82
83 if ((sort__has_parent || symbol_conf.use_callchain) &&
84 sample->callchain) {
85 err = machine__resolve_callchain(machine, evsel, al->thread,
86 sample, &parent);
87 if (err)
88 return err;
89 }
90
91 mi = machine__resolve_mem(machine, al->thread, sample, cpumode);
92 if (!mi)
93 return -ENOMEM;
94
95 if (rep->hide_unresolved && !al->sym)
96 return 0;
97
98 cost = sample->weight;
99 if (!cost)
100 cost = 1;
101
102 /*
103 * must pass period=weight in order to get the correct
104 * sorting from hists__collapse_resort() which is solely
105 * based on periods. We want sorting be done on nr_events * weight
106 * and this is indirectly achieved by passing period=weight here
107 * and the he_stat__add_period() function.
108 */
109 he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost);
110 if (!he)
111 return -ENOMEM;
112
113 /*
114 * In the TUI browser, we are doing integrated annotation,
115 * so we don't allocate the extra space needed because the stdio
116 * code will not use it.
117 */
118 if (sort__has_sym && he->ms.sym && use_browser > 0) {
119 struct annotation *notes = symbol__annotation(he->ms.sym);
120
121 assert(evsel != NULL);
122
123 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
124 goto out;
125
126 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
127 if (err)
128 goto out;
129 }
130
131 if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
132 struct annotation *notes;
133
134 mx = he->mem_info;
135
136 notes = symbol__annotation(mx->daddr.sym);
137 if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
138 goto out;
139
140 err = symbol__inc_addr_samples(mx->daddr.sym,
141 mx->daddr.map,
142 evsel->idx,
143 mx->daddr.al_addr);
144 if (err)
145 goto out;
146 }
147
148 evsel->hists.stats.total_period += cost;
149 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
150 err = 0;
151
152 if (symbol_conf.use_callchain) {
153 err = callchain_append(he->callchain,
154 &callchain_cursor,
155 sample->period);
156 }
157out:
158 return err;
159}
160
68static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 161static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
69 struct addr_location *al, 162 struct addr_location *al,
70 struct perf_sample *sample, 163 struct perf_sample *sample,
@@ -99,7 +192,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
99 * and not events sampled. Thus we use a pseudo period of 1. 192 * and not events sampled. Thus we use a pseudo period of 1.
100 */ 193 */
101 he = __hists__add_branch_entry(&evsel->hists, al, parent, 194 he = __hists__add_branch_entry(&evsel->hists, al, parent,
102 &bi[i], 1); 195 &bi[i], 1, 1);
103 if (he) { 196 if (he) {
104 struct annotation *notes; 197 struct annotation *notes;
105 err = -ENOMEM; 198 err = -ENOMEM;
@@ -157,7 +250,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
157 return err; 250 return err;
158 } 251 }
159 252
160 he = __hists__add_entry(&evsel->hists, al, parent, sample->period); 253 he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
254 sample->weight);
161 if (he == NULL) 255 if (he == NULL)
162 return -ENOMEM; 256 return -ENOMEM;
163 257
@@ -169,7 +263,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
169 return err; 263 return err;
170 } 264 }
171 /* 265 /*
172 * Only in the newt browser we are doing integrated annotation, 266 * Only in the TUI browser we are doing integrated annotation,
173 * so we don't allocated the extra space needed because the stdio 267 * so we don't allocated the extra space needed because the stdio
174 * code will not use it. 268 * code will not use it.
175 */ 269 */
@@ -220,6 +314,12 @@ static int process_sample_event(struct perf_tool *tool,
220 pr_debug("problem adding lbr entry, skipping event\n"); 314 pr_debug("problem adding lbr entry, skipping event\n");
221 return -1; 315 return -1;
222 } 316 }
317 } else if (rep->mem_mode == 1) {
318 if (perf_report__add_mem_hist_entry(tool, &al, sample,
319 evsel, machine, event)) {
320 pr_debug("problem adding mem entry, skipping event\n");
321 return -1;
322 }
223 } else { 323 } else {
224 if (al.map != NULL) 324 if (al.map != NULL)
225 al.map->dso->hit = 1; 325 al.map->dso->hit = 1;
@@ -303,7 +403,8 @@ static void sig_handler(int sig __maybe_unused)
303 session_done = 1; 403 session_done = 1;
304} 404}
305 405
306static size_t hists__fprintf_nr_sample_events(struct hists *self, 406static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
407 struct hists *self,
307 const char *evname, FILE *fp) 408 const char *evname, FILE *fp)
308{ 409{
309 size_t ret; 410 size_t ret;
@@ -314,7 +415,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
314 char buf[512]; 415 char buf[512];
315 size_t size = sizeof(buf); 416 size_t size = sizeof(buf);
316 417
317 if (symbol_conf.event_group && evsel->nr_members > 1) { 418 if (perf_evsel__is_group_event(evsel)) {
318 struct perf_evsel *pos; 419 struct perf_evsel *pos;
319 420
320 perf_evsel__group_desc(evsel, buf, size); 421 perf_evsel__group_desc(evsel, buf, size);
@@ -331,7 +432,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
331 if (evname != NULL) 432 if (evname != NULL)
332 ret += fprintf(fp, " of event '%s'", evname); 433 ret += fprintf(fp, " of event '%s'", evname);
333 434
334 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 435 if (rep->mem_mode) {
436 ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
437 ret += fprintf(fp, "\n# Sort order : %s", sort_order);
438 } else
439 ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
335 return ret + fprintf(fp, "\n#\n"); 440 return ret + fprintf(fp, "\n#\n");
336} 441}
337 442
@@ -349,7 +454,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
349 !perf_evsel__is_group_leader(pos)) 454 !perf_evsel__is_group_leader(pos))
350 continue; 455 continue;
351 456
352 hists__fprintf_nr_sample_events(hists, evname, stdout); 457 hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
353 hists__fprintf(hists, true, 0, 0, stdout); 458 hists__fprintf(hists, true, 0, 0, stdout);
354 fprintf(stdout, "\n\n"); 459 fprintf(stdout, "\n\n");
355 } 460 }
@@ -645,7 +750,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
645 "Use the stdio interface"), 750 "Use the stdio interface"),
646 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 751 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
647 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 752 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
648 " dso_to, dso_from, symbol_to, symbol_from, mispredict"), 753 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
754 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
755 "snoop, locked"),
649 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 756 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
650 "Show sample percentage for different cpu modes"), 757 "Show sample percentage for different cpu modes"),
651 OPT_STRING('p', "parent", &parent_pattern, "regex", 758 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -693,6 +800,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
693 "use branch records for histogram filling", parse_branch_mode), 800 "use branch records for histogram filling", parse_branch_mode),
694 OPT_STRING(0, "objdump", &objdump_path, "path", 801 OPT_STRING(0, "objdump", &objdump_path, "path",
695 "objdump binary to use for disassembly and annotations"), 802 "objdump binary to use for disassembly and annotations"),
803 OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
804 "Disable symbol demangling"),
805 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
696 OPT_END() 806 OPT_END()
697 }; 807 };
698 808
@@ -750,12 +860,24 @@ repeat:
750 "dso_to,symbol_to"; 860 "dso_to,symbol_to";
751 861
752 } 862 }
863 if (report.mem_mode) {
864 if (sort__branch_mode == 1) {
865 fprintf(stderr, "branch and mem mode incompatible\n");
866 goto error;
867 }
868 /*
869 * if no sort_order is provided, then specify
870 * branch-mode specific order
871 */
872 if (sort_order == default_sort_order)
873 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
874 }
753 875
754 if (setup_sorting() < 0) 876 if (setup_sorting() < 0)
755 usage_with_options(report_usage, options); 877 usage_with_options(report_usage, options);
756 878
757 /* 879 /*
758 * Only in the newt browser we are doing integrated annotation, 880 * Only in the TUI browser we are doing integrated annotation,
759 * so don't allocate extra space that won't be used in the stdio 881 * so don't allocate extra space that won't be used in the stdio
760 * implementation. 882 * implementation.
761 */ 883 */
@@ -815,6 +937,14 @@ repeat:
815 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout); 937 sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
816 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout); 938 sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
817 } else { 939 } else {
940 if (report.mem_mode) {
941 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
942 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
943 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
944 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
945 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
946 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
947 }
818 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout); 948 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
819 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); 949 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
820 } 950 }
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 138229439a93..2da2a6ca22bf 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1671,7 +1671,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1671 .sample = perf_sched__process_tracepoint_sample, 1671 .sample = perf_sched__process_tracepoint_sample,
1672 .comm = perf_event__process_comm, 1672 .comm = perf_event__process_comm,
1673 .lost = perf_event__process_lost, 1673 .lost = perf_event__process_lost,
1674 .exit = perf_event__process_exit,
1675 .fork = perf_event__process_fork, 1674 .fork = perf_event__process_fork,
1676 .ordered_samples = true, 1675 .ordered_samples = true,
1677 }, 1676 },
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 99848761f573..7e910bab1097 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -68,7 +68,7 @@
68static void print_stat(int argc, const char **argv); 68static void print_stat(int argc, const char **argv);
69static void print_counter_aggr(struct perf_evsel *counter, char *prefix); 69static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix); 70static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr_socket(char *prefix); 71static void print_aggr(char *prefix);
72 72
73static struct perf_evlist *evsel_list; 73static struct perf_evlist *evsel_list;
74 74
@@ -76,11 +76,17 @@ static struct perf_target target = {
76 .uid = UINT_MAX, 76 .uid = UINT_MAX,
77}; 77};
78 78
79enum aggr_mode {
80 AGGR_NONE,
81 AGGR_GLOBAL,
82 AGGR_SOCKET,
83 AGGR_CORE,
84};
85
79static int run_count = 1; 86static int run_count = 1;
80static bool no_inherit = false; 87static bool no_inherit = false;
81static bool scale = true; 88static bool scale = true;
82static bool no_aggr = false; 89static enum aggr_mode aggr_mode = AGGR_GLOBAL;
83static bool aggr_socket = false;
84static pid_t child_pid = -1; 90static pid_t child_pid = -1;
85static bool null_run = false; 91static bool null_run = false;
86static int detailed_run = 0; 92static int detailed_run = 0;
@@ -94,8 +100,10 @@ static const char *pre_cmd = NULL;
94static const char *post_cmd = NULL; 100static const char *post_cmd = NULL;
95static bool sync_run = false; 101static bool sync_run = false;
96static unsigned int interval = 0; 102static unsigned int interval = 0;
103static bool forever = false;
97static struct timespec ref_time; 104static struct timespec ref_time;
98static struct cpu_map *sock_map; 105static struct cpu_map *aggr_map;
106static int (*aggr_get_id)(struct cpu_map *m, int cpu);
99 107
100static volatile int done = 0; 108static volatile int done = 0;
101 109
@@ -125,6 +133,11 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
125 return perf_evsel__cpus(evsel)->nr; 133 return perf_evsel__cpus(evsel)->nr;
126} 134}
127 135
136static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
137{
138 memset(evsel->priv, 0, sizeof(struct perf_stat));
139}
140
128static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 141static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
129{ 142{
130 evsel->priv = zalloc(sizeof(struct perf_stat)); 143 evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -160,6 +173,35 @@ static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
160 evsel->prev_raw_counts = NULL; 173 evsel->prev_raw_counts = NULL;
161} 174}
162 175
176static void perf_evlist__free_stats(struct perf_evlist *evlist)
177{
178 struct perf_evsel *evsel;
179
180 list_for_each_entry(evsel, &evlist->entries, node) {
181 perf_evsel__free_stat_priv(evsel);
182 perf_evsel__free_counts(evsel);
183 perf_evsel__free_prev_raw_counts(evsel);
184 }
185}
186
187static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
188{
189 struct perf_evsel *evsel;
190
191 list_for_each_entry(evsel, &evlist->entries, node) {
192 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
193 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
194 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
195 goto out_free;
196 }
197
198 return 0;
199
200out_free:
201 perf_evlist__free_stats(evlist);
202 return -1;
203}
204
163static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 205static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
164static struct stats runtime_cycles_stats[MAX_NR_CPUS]; 206static struct stats runtime_cycles_stats[MAX_NR_CPUS];
165static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; 207static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
@@ -173,6 +215,29 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
173static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 215static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
174static struct stats walltime_nsecs_stats; 216static struct stats walltime_nsecs_stats;
175 217
218static void perf_stat__reset_stats(struct perf_evlist *evlist)
219{
220 struct perf_evsel *evsel;
221
222 list_for_each_entry(evsel, &evlist->entries, node) {
223 perf_evsel__reset_stat_priv(evsel);
224 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
225 }
226
227 memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
228 memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
229 memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
230 memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats));
231 memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats));
232 memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats));
233 memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats));
234 memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats));
235 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
236 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
237 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
238 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
239}
240
176static int create_perf_stat_counter(struct perf_evsel *evsel) 241static int create_perf_stat_counter(struct perf_evsel *evsel)
177{ 242{
178 struct perf_event_attr *attr = &evsel->attr; 243 struct perf_event_attr *attr = &evsel->attr;
@@ -249,7 +314,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
249 int i; 314 int i;
250 315
251 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), 316 if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
252 evsel_list->threads->nr, scale) < 0) 317 thread_map__nr(evsel_list->threads), scale) < 0)
253 return -1; 318 return -1;
254 319
255 for (i = 0; i < 3; i++) 320 for (i = 0; i < 3; i++)
@@ -297,56 +362,68 @@ static void print_interval(void)
297 struct timespec ts, rs; 362 struct timespec ts, rs;
298 char prefix[64]; 363 char prefix[64];
299 364
300 if (no_aggr) { 365 if (aggr_mode == AGGR_GLOBAL) {
301 list_for_each_entry(counter, &evsel_list->entries, node) { 366 list_for_each_entry(counter, &evsel_list->entries, node) {
302 ps = counter->priv; 367 ps = counter->priv;
303 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 368 memset(ps->res_stats, 0, sizeof(ps->res_stats));
304 read_counter(counter); 369 read_counter_aggr(counter);
305 } 370 }
306 } else { 371 } else {
307 list_for_each_entry(counter, &evsel_list->entries, node) { 372 list_for_each_entry(counter, &evsel_list->entries, node) {
308 ps = counter->priv; 373 ps = counter->priv;
309 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 374 memset(ps->res_stats, 0, sizeof(ps->res_stats));
310 read_counter_aggr(counter); 375 read_counter(counter);
311 } 376 }
312 } 377 }
378
313 clock_gettime(CLOCK_MONOTONIC, &ts); 379 clock_gettime(CLOCK_MONOTONIC, &ts);
314 diff_timespec(&rs, &ts, &ref_time); 380 diff_timespec(&rs, &ts, &ref_time);
315 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); 381 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
316 382
317 if (num_print_interval == 0 && !csv_output) { 383 if (num_print_interval == 0 && !csv_output) {
318 if (aggr_socket) 384 switch (aggr_mode) {
385 case AGGR_SOCKET:
319 fprintf(output, "# time socket cpus counts events\n"); 386 fprintf(output, "# time socket cpus counts events\n");
320 else if (no_aggr) 387 break;
388 case AGGR_CORE:
389 fprintf(output, "# time core cpus counts events\n");
390 break;
391 case AGGR_NONE:
321 fprintf(output, "# time CPU counts events\n"); 392 fprintf(output, "# time CPU counts events\n");
322 else 393 break;
394 case AGGR_GLOBAL:
395 default:
323 fprintf(output, "# time counts events\n"); 396 fprintf(output, "# time counts events\n");
397 }
324 } 398 }
325 399
326 if (++num_print_interval == 25) 400 if (++num_print_interval == 25)
327 num_print_interval = 0; 401 num_print_interval = 0;
328 402
329 if (aggr_socket) 403 switch (aggr_mode) {
330 print_aggr_socket(prefix); 404 case AGGR_CORE:
331 else if (no_aggr) { 405 case AGGR_SOCKET:
406 print_aggr(prefix);
407 break;
408 case AGGR_NONE:
332 list_for_each_entry(counter, &evsel_list->entries, node) 409 list_for_each_entry(counter, &evsel_list->entries, node)
333 print_counter(counter, prefix); 410 print_counter(counter, prefix);
334 } else { 411 break;
412 case AGGR_GLOBAL:
413 default:
335 list_for_each_entry(counter, &evsel_list->entries, node) 414 list_for_each_entry(counter, &evsel_list->entries, node)
336 print_counter_aggr(counter, prefix); 415 print_counter_aggr(counter, prefix);
337 } 416 }
338} 417}
339 418
340static int __run_perf_stat(int argc __maybe_unused, const char **argv) 419static int __run_perf_stat(int argc, const char **argv)
341{ 420{
342 char msg[512]; 421 char msg[512];
343 unsigned long long t0, t1; 422 unsigned long long t0, t1;
344 struct perf_evsel *counter; 423 struct perf_evsel *counter;
345 struct timespec ts; 424 struct timespec ts;
346 int status = 0; 425 int status = 0;
347 int child_ready_pipe[2], go_pipe[2];
348 const bool forks = (argc > 0); 426 const bool forks = (argc > 0);
349 char buf;
350 427
351 if (interval) { 428 if (interval) {
352 ts.tv_sec = interval / 1000; 429 ts.tv_sec = interval / 1000;
@@ -356,61 +433,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
356 ts.tv_nsec = 0; 433 ts.tv_nsec = 0;
357 } 434 }
358 435
359 if (aggr_socket
360 && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
361 perror("cannot build socket map");
362 return -1;
363 }
364
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) { 436 if (forks) {
371 if ((child_pid = fork()) < 0) 437 if (perf_evlist__prepare_workload(evsel_list, &target, argv,
372 perror("failed to fork"); 438 false, false) < 0) {
373 439 perror("failed to prepare workload");
374 if (!child_pid) { 440 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 } 441 }
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 } 442 }
415 443
416 if (group) 444 if (group)
@@ -457,7 +485,8 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
457 clock_gettime(CLOCK_MONOTONIC, &ref_time); 485 clock_gettime(CLOCK_MONOTONIC, &ref_time);
458 486
459 if (forks) { 487 if (forks) {
460 close(go_pipe[1]); 488 perf_evlist__start_workload(evsel_list);
489
461 if (interval) { 490 if (interval) {
462 while (!waitpid(child_pid, &status, WNOHANG)) { 491 while (!waitpid(child_pid, &status, WNOHANG)) {
463 nanosleep(&ts, NULL); 492 nanosleep(&ts, NULL);
@@ -479,16 +508,16 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
479 508
480 update_stats(&walltime_nsecs_stats, t1 - t0); 509 update_stats(&walltime_nsecs_stats, t1 - t0);
481 510
482 if (no_aggr) { 511 if (aggr_mode == AGGR_GLOBAL) {
483 list_for_each_entry(counter, &evsel_list->entries, node) { 512 list_for_each_entry(counter, &evsel_list->entries, node) {
484 read_counter(counter); 513 read_counter_aggr(counter);
485 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 514 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
515 thread_map__nr(evsel_list->threads));
486 } 516 }
487 } else { 517 } else {
488 list_for_each_entry(counter, &evsel_list->entries, node) { 518 list_for_each_entry(counter, &evsel_list->entries, node) {
489 read_counter_aggr(counter); 519 read_counter(counter);
490 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 520 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
491 evsel_list->threads->nr);
492 } 521 }
493 } 522 }
494 523
@@ -542,26 +571,47 @@ static void print_noise(struct perf_evsel *evsel, double avg)
542 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 571 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
543} 572}
544 573
545static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 574static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
546{ 575{
547 double msecs = avg / 1e6; 576 switch (aggr_mode) {
548 char cpustr[16] = { '\0', }; 577 case AGGR_CORE:
549 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; 578 fprintf(output, "S%d-C%*d%s%*d%s",
550 579 cpu_map__id_to_socket(id),
551 if (aggr_socket) 580 csv_output ? 0 : -8,
552 sprintf(cpustr, "S%*d%s%*d%s", 581 cpu_map__id_to_cpu(id),
582 csv_sep,
583 csv_output ? 0 : 4,
584 nr,
585 csv_sep);
586 break;
587 case AGGR_SOCKET:
588 fprintf(output, "S%*d%s%*d%s",
553 csv_output ? 0 : -5, 589 csv_output ? 0 : -5,
554 cpu, 590 id,
555 csv_sep, 591 csv_sep,
556 csv_output ? 0 : 4, 592 csv_output ? 0 : 4,
557 nr, 593 nr,
558 csv_sep); 594 csv_sep);
559 else if (no_aggr) 595 break;
560 sprintf(cpustr, "CPU%*d%s", 596 case AGGR_NONE:
597 fprintf(output, "CPU%*d%s",
561 csv_output ? 0 : -4, 598 csv_output ? 0 : -4,
562 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 599 perf_evsel__cpus(evsel)->map[id], csv_sep);
600 break;
601 case AGGR_GLOBAL:
602 default:
603 break;
604 }
605}
606
607static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
608{
609 double msecs = avg / 1e6;
610 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
611
612 aggr_printout(evsel, cpu, nr);
563 613
564 fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); 614 fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel));
565 615
566 if (evsel->cgrp) 616 if (evsel->cgrp)
567 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 617 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -758,32 +808,21 @@ static void print_ll_cache_misses(int cpu,
758static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 808static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
759{ 809{
760 double total, ratio = 0.0; 810 double total, ratio = 0.0;
761 char cpustr[16] = { '\0', };
762 const char *fmt; 811 const char *fmt;
763 812
764 if (csv_output) 813 if (csv_output)
765 fmt = "%s%.0f%s%s"; 814 fmt = "%.0f%s%s";
766 else if (big_num) 815 else if (big_num)
767 fmt = "%s%'18.0f%s%-25s"; 816 fmt = "%'18.0f%s%-25s";
768 else 817 else
769 fmt = "%s%18.0f%s%-25s"; 818 fmt = "%18.0f%s%-25s";
770 819
771 if (aggr_socket) 820 aggr_printout(evsel, cpu, nr);
772 sprintf(cpustr, "S%*d%s%*d%s", 821
773 csv_output ? 0 : -5, 822 if (aggr_mode == AGGR_GLOBAL)
774 cpu,
775 csv_sep,
776 csv_output ? 0 : 4,
777 nr,
778 csv_sep);
779 else if (no_aggr)
780 sprintf(cpustr, "CPU%*d%s",
781 csv_output ? 0 : -4,
782 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
783 else
784 cpu = 0; 823 cpu = 0;
785 824
786 fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); 825 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel));
787 826
788 if (evsel->cgrp) 827 if (evsel->cgrp)
789 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 828 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -882,23 +921,23 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
882 } 921 }
883} 922}
884 923
885static void print_aggr_socket(char *prefix) 924static void print_aggr(char *prefix)
886{ 925{
887 struct perf_evsel *counter; 926 struct perf_evsel *counter;
927 int cpu, s, s2, id, nr;
888 u64 ena, run, val; 928 u64 ena, run, val;
889 int cpu, s, s2, sock, nr;
890 929
891 if (!sock_map) 930 if (!(aggr_map || aggr_get_id))
892 return; 931 return;
893 932
894 for (s = 0; s < sock_map->nr; s++) { 933 for (s = 0; s < aggr_map->nr; s++) {
895 sock = cpu_map__socket(sock_map, s); 934 id = aggr_map->map[s];
896 list_for_each_entry(counter, &evsel_list->entries, node) { 935 list_for_each_entry(counter, &evsel_list->entries, node) {
897 val = ena = run = 0; 936 val = ena = run = 0;
898 nr = 0; 937 nr = 0;
899 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 938 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
900 s2 = cpu_map__get_socket(evsel_list->cpus, cpu); 939 s2 = aggr_get_id(evsel_list->cpus, cpu);
901 if (s2 != sock) 940 if (s2 != id)
902 continue; 941 continue;
903 val += counter->counts->cpu[cpu].val; 942 val += counter->counts->cpu[cpu].val;
904 ena += counter->counts->cpu[cpu].ena; 943 ena += counter->counts->cpu[cpu].ena;
@@ -909,18 +948,15 @@ static void print_aggr_socket(char *prefix)
909 fprintf(output, "%s", prefix); 948 fprintf(output, "%s", prefix);
910 949
911 if (run == 0 || ena == 0) { 950 if (run == 0 || ena == 0) {
912 fprintf(output, "S%*d%s%*d%s%*s%s%*s", 951 aggr_printout(counter, cpu, nr);
913 csv_output ? 0 : -5, 952
914 s, 953 fprintf(output, "%*s%s%*s",
915 csv_sep,
916 csv_output ? 0 : 4,
917 nr,
918 csv_sep,
919 csv_output ? 0 : 18, 954 csv_output ? 0 : 18,
920 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 955 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
921 csv_sep, 956 csv_sep,
922 csv_output ? 0 : -24, 957 csv_output ? 0 : -24,
923 perf_evsel__name(counter)); 958 perf_evsel__name(counter));
959
924 if (counter->cgrp) 960 if (counter->cgrp)
925 fprintf(output, "%s%s", 961 fprintf(output, "%s%s",
926 csv_sep, counter->cgrp->name); 962 csv_sep, counter->cgrp->name);
@@ -930,9 +966,9 @@ static void print_aggr_socket(char *prefix)
930 } 966 }
931 967
932 if (nsec_counter(counter)) 968 if (nsec_counter(counter))
933 nsec_printout(sock, nr, counter, val); 969 nsec_printout(id, nr, counter, val);
934 else 970 else
935 abs_printout(sock, nr, counter, val); 971 abs_printout(id, nr, counter, val);
936 972
937 if (!csv_output) { 973 if (!csv_output) {
938 print_noise(counter, 1.0); 974 print_noise(counter, 1.0);
@@ -1073,14 +1109,21 @@ static void print_stat(int argc, const char **argv)
1073 fprintf(output, ":\n\n"); 1109 fprintf(output, ":\n\n");
1074 } 1110 }
1075 1111
1076 if (aggr_socket) 1112 switch (aggr_mode) {
1077 print_aggr_socket(NULL); 1113 case AGGR_CORE:
1078 else if (no_aggr) { 1114 case AGGR_SOCKET:
1079 list_for_each_entry(counter, &evsel_list->entries, node) 1115 print_aggr(NULL);
1080 print_counter(counter, NULL); 1116 break;
1081 } else { 1117 case AGGR_GLOBAL:
1082 list_for_each_entry(counter, &evsel_list->entries, node) 1118 list_for_each_entry(counter, &evsel_list->entries, node)
1083 print_counter_aggr(counter, NULL); 1119 print_counter_aggr(counter, NULL);
1120 break;
1121 case AGGR_NONE:
1122 list_for_each_entry(counter, &evsel_list->entries, node)
1123 print_counter(counter, NULL);
1124 break;
1125 default:
1126 break;
1084 } 1127 }
1085 1128
1086 if (!csv_output) { 1129 if (!csv_output) {
@@ -1126,6 +1169,32 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
1126 return 0; 1169 return 0;
1127} 1170}
1128 1171
1172static int perf_stat_init_aggr_mode(void)
1173{
1174 switch (aggr_mode) {
1175 case AGGR_SOCKET:
1176 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
1177 perror("cannot build socket map");
1178 return -1;
1179 }
1180 aggr_get_id = cpu_map__get_socket;
1181 break;
1182 case AGGR_CORE:
1183 if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) {
1184 perror("cannot build core map");
1185 return -1;
1186 }
1187 aggr_get_id = cpu_map__get_core;
1188 break;
1189 case AGGR_NONE:
1190 case AGGR_GLOBAL:
1191 default:
1192 break;
1193 }
1194 return 0;
1195}
1196
1197
1129/* 1198/*
1130 * Add default attributes, if there were no attributes specified or 1199 * Add default attributes, if there were no attributes specified or
1131 * if -d/--detailed, -d -d or -d -d -d is used: 1200 * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1296,7 +1365,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1296 OPT_INCR('v', "verbose", &verbose, 1365 OPT_INCR('v', "verbose", &verbose,
1297 "be more verbose (show counter open errors, etc)"), 1366 "be more verbose (show counter open errors, etc)"),
1298 OPT_INTEGER('r', "repeat", &run_count, 1367 OPT_INTEGER('r', "repeat", &run_count,
1299 "repeat command and print average + stddev (max: 100)"), 1368 "repeat command and print average + stddev (max: 100, forever: 0)"),
1300 OPT_BOOLEAN('n', "null", &null_run, 1369 OPT_BOOLEAN('n', "null", &null_run,
1301 "null run - dont start any counters"), 1370 "null run - dont start any counters"),
1302 OPT_INCR('d', "detailed", &detailed_run, 1371 OPT_INCR('d', "detailed", &detailed_run,
@@ -1308,7 +1377,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1308 stat__set_big_num), 1377 stat__set_big_num),
1309 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1378 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1310 "list of cpus to monitor in system-wide"), 1379 "list of cpus to monitor in system-wide"),
1311 OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), 1380 OPT_SET_UINT('A', "no-aggr", &aggr_mode,
1381 "disable CPU count aggregation", AGGR_NONE),
1312 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1382 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1313 "print counts with custom separator"), 1383 "print counts with custom separator"),
1314 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1384 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -1323,20 +1393,22 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1323 "command to run after to the measured command"), 1393 "command to run after to the measured command"),
1324 OPT_UINTEGER('I', "interval-print", &interval, 1394 OPT_UINTEGER('I', "interval-print", &interval,
1325 "print counts at regular interval in ms (>= 100)"), 1395 "print counts at regular interval in ms (>= 100)"),
1326 OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"), 1396 OPT_SET_UINT(0, "per-socket", &aggr_mode,
1397 "aggregate counts per processor socket", AGGR_SOCKET),
1398 OPT_SET_UINT(0, "per-core", &aggr_mode,
1399 "aggregate counts per physical processor core", AGGR_CORE),
1327 OPT_END() 1400 OPT_END()
1328 }; 1401 };
1329 const char * const stat_usage[] = { 1402 const char * const stat_usage[] = {
1330 "perf stat [<options>] [<command>]", 1403 "perf stat [<options>] [<command>]",
1331 NULL 1404 NULL
1332 }; 1405 };
1333 struct perf_evsel *pos;
1334 int status = -ENOMEM, run_idx; 1406 int status = -ENOMEM, run_idx;
1335 const char *mode; 1407 const char *mode;
1336 1408
1337 setlocale(LC_ALL, ""); 1409 setlocale(LC_ALL, "");
1338 1410
1339 evsel_list = perf_evlist__new(NULL, NULL); 1411 evsel_list = perf_evlist__new();
1340 if (evsel_list == NULL) 1412 if (evsel_list == NULL)
1341 return -ENOMEM; 1413 return -ENOMEM;
1342 1414
@@ -1399,23 +1471,21 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1399 1471
1400 if (!argc && !perf_target__has_task(&target)) 1472 if (!argc && !perf_target__has_task(&target))
1401 usage_with_options(stat_usage, options); 1473 usage_with_options(stat_usage, options);
1402 if (run_count <= 0) 1474 if (run_count < 0) {
1403 usage_with_options(stat_usage, options); 1475 usage_with_options(stat_usage, options);
1476 } else if (run_count == 0) {
1477 forever = true;
1478 run_count = 1;
1479 }
1404 1480
1405 /* no_aggr, cgroup are for system-wide only */ 1481 /* no_aggr, cgroup are for system-wide only */
1406 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1482 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups)
1483 && !perf_target__has_cpu(&target)) {
1407 fprintf(stderr, "both cgroup and no-aggregation " 1484 fprintf(stderr, "both cgroup and no-aggregation "
1408 "modes only available in system-wide mode\n"); 1485 "modes only available in system-wide mode\n");
1409 1486
1410 usage_with_options(stat_usage, options); 1487 usage_with_options(stat_usage, options);
1411 } 1488 return -1;
1412
1413 if (aggr_socket) {
1414 if (!perf_target__has_cpu(&target)) {
1415 fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
1416 usage_with_options(stat_usage, options);
1417 }
1418 no_aggr = true;
1419 } 1489 }
1420 1490
1421 if (add_default_attributes()) 1491 if (add_default_attributes())
@@ -1438,17 +1508,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1438 return -1; 1508 return -1;
1439 } 1509 }
1440 1510
1441 list_for_each_entry(pos, &evsel_list->entries, node) { 1511 if (perf_evlist__alloc_stats(evsel_list, interval))
1442 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1512 goto out_free_maps;
1443 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1513
1444 goto out_free_fd; 1514 if (perf_stat_init_aggr_mode())
1445 } 1515 goto out;
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 1516
1453 /* 1517 /*
1454 * We dont want to block the signals - that would cause 1518 * We dont want to block the signals - that would cause
@@ -1457,28 +1521,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1457 * task, but being ignored by perf stat itself: 1521 * task, but being ignored by perf stat itself:
1458 */ 1522 */
1459 atexit(sig_atexit); 1523 atexit(sig_atexit);
1460 signal(SIGINT, skip_signal); 1524 if (!forever)
1525 signal(SIGINT, skip_signal);
1461 signal(SIGCHLD, skip_signal); 1526 signal(SIGCHLD, skip_signal);
1462 signal(SIGALRM, skip_signal); 1527 signal(SIGALRM, skip_signal);
1463 signal(SIGABRT, skip_signal); 1528 signal(SIGABRT, skip_signal);
1464 1529
1465 status = 0; 1530 status = 0;
1466 for (run_idx = 0; run_idx < run_count; run_idx++) { 1531 for (run_idx = 0; forever || run_idx < run_count; run_idx++) {
1467 if (run_count != 1 && verbose) 1532 if (run_count != 1 && verbose)
1468 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1533 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1469 run_idx + 1); 1534 run_idx + 1);
1470 1535
1471 status = run_perf_stat(argc, argv); 1536 status = run_perf_stat(argc, argv);
1537 if (forever && status != -1) {
1538 print_stat(argc, argv);
1539 perf_stat__reset_stats(evsel_list);
1540 }
1472 } 1541 }
1473 1542
1474 if (status != -1 && !interval) 1543 if (!forever && status != -1 && !interval)
1475 print_stat(argc, argv); 1544 print_stat(argc, argv);
1476out_free_fd: 1545
1477 list_for_each_entry(pos, &evsel_list->entries, node) { 1546 perf_evlist__free_stats(evsel_list);
1478 perf_evsel__free_stat_priv(pos); 1547out_free_maps:
1479 perf_evsel__free_counts(pos);
1480 perf_evsel__free_prev_raw_counts(pos);
1481 }
1482 perf_evlist__delete_maps(evsel_list); 1548 perf_evlist__delete_maps(evsel_list);
1483out: 1549out:
1484 perf_evlist__delete(evsel_list); 1550 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 72f6eb7b4173..67bdb9f14ad6 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);
@@ -251,7 +251,8 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
251{ 251{
252 struct hist_entry *he; 252 struct hist_entry *he;
253 253
254 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period); 254 he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
255 sample->weight);
255 if (he == NULL) 256 if (he == NULL)
256 return NULL; 257 return NULL;
257 258
@@ -1088,7 +1089,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1088 OPT_INCR('v', "verbose", &verbose, 1089 OPT_INCR('v', "verbose", &verbose,
1089 "be more verbose (show counter open errors, etc)"), 1090 "be more verbose (show counter open errors, etc)"),
1090 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1091 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1091 "sort by key(s): pid, comm, dso, symbol, parent"), 1092 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
1092 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1093 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1093 "Show a column with the number of samples"), 1094 "Show a column with the number of samples"),
1094 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, 1095 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
@@ -1116,7 +1117,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1116 NULL 1117 NULL
1117 }; 1118 };
1118 1119
1119 top.evlist = perf_evlist__new(NULL, NULL); 1120 top.evlist = perf_evlist__new();
1120 if (top.evlist == NULL) 1121 if (top.evlist == NULL)
1121 return -ENOMEM; 1122 return -ENOMEM;
1122 1123
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/builtin.h b/tools/perf/builtin.h
index 08143bd854c7..b210d62907e4 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -36,6 +36,7 @@ extern int cmd_kvm(int argc, const char **argv, const char *prefix);
36extern int cmd_test(int argc, const char **argv, const char *prefix); 36extern int cmd_test(int argc, const char **argv, const char *prefix);
37extern int cmd_trace(int argc, const char **argv, const char *prefix); 37extern int cmd_trace(int argc, const char **argv, const char *prefix);
38extern int cmd_inject(int argc, const char **argv, const char *prefix); 38extern int cmd_inject(int argc, const char **argv, const char *prefix);
39extern int cmd_mem(int argc, const char **argv, const char *prefix);
39 40
40extern int find_scripts(char **scripts_array, char **scripts_path_array); 41extern int find_scripts(char **scripts_array, char **scripts_path_array);
41#endif 42#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 3e86bbd8c2d5..0906fc401c52 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -10,17 +10,18 @@ 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-mem mainporcelain common
18perf-probe mainporcelain full
15perf-record mainporcelain common 19perf-record mainporcelain common
16perf-report mainporcelain common 20perf-report mainporcelain common
21perf-sched mainporcelain common
22perf-script mainporcelain common
17perf-stat mainporcelain common 23perf-stat mainporcelain common
24perf-test mainporcelain common
18perf-timechart mainporcelain common 25perf-timechart mainporcelain common
19perf-top mainporcelain common 26perf-top mainporcelain common
20perf-trace mainporcelain common 27perf-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/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index b4eabb44e381..708fb8e9822a 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -61,15 +61,13 @@ int main(void)
61} 61}
62endef 62endef
63 63
64ifndef NO_NEWT 64ifndef NO_SLANG
65define SOURCE_NEWT 65define SOURCE_SLANG
66#include <newt.h> 66#include <slang.h>
67 67
68int main(void) 68int main(void)
69{ 69{
70 newtInit(); 70 return SLsmg_init_smg();
71 newtCls();
72 return newtFinished();
73} 71}
74endef 72endef
75endif 73endif
@@ -235,4 +233,4 @@ int main(void)
235 numa_available(); 233 numa_available();
236 return 0; 234 return 0;
237} 235}
238endef \ No newline at end of file 236endef
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 095b88207cd3..85e1aed95204 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[] =
@@ -60,6 +60,7 @@ static struct cmd_struct commands[] = {
60 { "trace", cmd_trace, 0 }, 60 { "trace", cmd_trace, 0 },
61#endif 61#endif
62 { "inject", cmd_inject, 0 }, 62 { "inject", cmd_inject, 0 },
63 { "mem", cmd_mem, 0 },
63}; 64};
64 65
65struct pager_config { 66struct pager_config {
@@ -193,13 +194,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
193 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 194 fprintf(stderr, "No directory given for --debugfs-dir.\n");
194 usage(perf_usage_string); 195 usage(perf_usage_string);
195 } 196 }
196 debugfs_set_path((*argv)[1]); 197 perf_debugfs_set_path((*argv)[1]);
197 if (envchanged) 198 if (envchanged)
198 *envchanged = 1; 199 *envchanged = 1;
199 (*argv)++; 200 (*argv)++;
200 (*argc)--; 201 (*argc)--;
201 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { 202 } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
202 debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); 203 perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
203 fprintf(stderr, "dir: %s\n", debugfs_mountpoint); 204 fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
204 if (envchanged) 205 if (envchanged)
205 *envchanged = 1; 206 *envchanged = 1;
@@ -461,7 +462,7 @@ int main(int argc, const char **argv)
461 if (!cmd) 462 if (!cmd)
462 cmd = "perf-help"; 463 cmd = "perf-help";
463 /* get debugfs mount point from /proc/mounts */ 464 /* get debugfs mount point from /proc/mounts */
464 debugfs_mount(NULL); 465 perf_debugfs_mount(NULL);
465 /* 466 /*
466 * "perf-xxxx" is the same as "perf xxxx", but we obviously: 467 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
467 * 468 *
@@ -517,9 +518,8 @@ int main(int argc, const char **argv)
517 518
518 while (1) { 519 while (1) {
519 static int done_help; 520 static int done_help;
520 static int was_alias; 521 int was_alias = run_argv(&argc, &argv);
521 522
522 was_alias = run_argv(&argc, &argv);
523 if (errno != ENOENT) 523 if (errno != ENOENT)
524 break; 524 break;
525 525
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 74659ecf93e0..32bd102c32b6 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -218,6 +218,7 @@ struct perf_record_opts {
218 bool pipe_output; 218 bool pipe_output;
219 bool raw_samples; 219 bool raw_samples;
220 bool sample_address; 220 bool sample_address;
221 bool sample_weight;
221 bool sample_time; 222 bool sample_time;
222 bool period; 223 bool period;
223 unsigned int freq; 224 unsigned int freq;
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..89085a9615e2 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -223,7 +223,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
223 &sample, 0) < 0) 223 &sample, 0) < 0)
224 goto out; 224 goto out;
225 225
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
227 if (he == NULL) 227 if (he == NULL)
228 goto out; 228 goto out;
229 229
@@ -247,7 +247,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
247 &sample, 0) < 0) 247 &sample, 0) < 0)
248 goto out; 248 goto out;
249 249
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1); 250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
251 if (he == NULL) 251 if (he == NULL)
252 goto out; 252 goto out;
253 253
@@ -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/browser.c b/tools/perf/ui/browser.c
index 809ea4632a34..bbc782e364b0 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -2,7 +2,6 @@
2#include "../cache.h" 2#include "../cache.h"
3#include "../../perf.h" 3#include "../../perf.h"
4#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
6#include "ui.h" 5#include "ui.h"
7#include "util.h" 6#include "util.h"
8#include <linux/compiler.h> 7#include <linux/compiler.h>
@@ -234,7 +233,7 @@ void ui_browser__reset_index(struct ui_browser *browser)
234void __ui_browser__show_title(struct ui_browser *browser, const char *title) 233void __ui_browser__show_title(struct ui_browser *browser, const char *title)
235{ 234{
236 SLsmg_gotorc(0, 0); 235 SLsmg_gotorc(0, 0);
237 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 236 ui_browser__set_color(browser, HE_COLORSET_ROOT);
238 slsmg_write_nstring(title, browser->width + 1); 237 slsmg_write_nstring(title, browser->width + 1);
239} 238}
240 239
@@ -514,6 +513,12 @@ static struct ui_browser_colorset {
514 .bg = "default", 513 .bg = "default",
515 }, 514 },
516 { 515 {
516 .colorset = HE_COLORSET_ROOT,
517 .name = "root",
518 .fg = "white",
519 .bg = "blue",
520 },
521 {
517 .name = NULL, 522 .name = NULL,
518 } 523 }
519}; 524};
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index af70314605e5..404ff66a3e36 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -11,6 +11,7 @@
11#define HE_COLORSET_SELECTED 53 11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54 12#define HE_COLORSET_CODE 54
13#define HE_COLORSET_ADDR 55 13#define HE_COLORSET_ADDR 55
14#define HE_COLORSET_ROOT 56
14 15
15struct ui_browser { 16struct ui_browser {
16 u64 index, top_idx; 17 u64 index, top_idx;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 7dca1555c610..cc64d3f7fc36 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -8,15 +8,19 @@
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 13
14struct browser_disasm_line { 14struct browser_disasm_line {
15 struct rb_node rb_node; 15 struct rb_node rb_node;
16 double percent;
17 u32 idx; 16 u32 idx;
18 int idx_asm; 17 int idx_asm;
19 int jump_sources; 18 int jump_sources;
19 /*
20 * actual length of this array is saved on the nr_events field
21 * of the struct annotate_browser
22 */
23 double percent[1];
20}; 24};
21 25
22static struct annotate_browser_opt { 26static struct annotate_browser_opt {
@@ -33,8 +37,9 @@ struct annotate_browser {
33 struct ui_browser b; 37 struct ui_browser b;
34 struct rb_root entries; 38 struct rb_root entries;
35 struct rb_node *curr_hot; 39 struct rb_node *curr_hot;
36 struct disasm_line *selection; 40 struct disasm_line *selection;
37 struct disasm_line **offsets; 41 struct disasm_line **offsets;
42 int nr_events;
38 u64 start; 43 u64 start;
39 int nr_asm_entries; 44 int nr_asm_entries;
40 int nr_entries; 45 int nr_entries;
@@ -94,14 +99,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
94 (!current_entry || (browser->use_navkeypressed && 99 (!current_entry || (browser->use_navkeypressed &&
95 !browser->navkeypressed))); 100 !browser->navkeypressed)));
96 int width = browser->width, printed; 101 int width = browser->width, printed;
102 int i, pcnt_width = 7 * ab->nr_events;
103 double percent_max = 0.0;
97 char bf[256]; 104 char bf[256];
98 105
99 if (dl->offset != -1 && bdl->percent != 0.0) { 106 for (i = 0; i < ab->nr_events; i++) {
100 ui_browser__set_percent_color(browser, bdl->percent, current_entry); 107 if (bdl->percent[i] > percent_max)
101 slsmg_printf("%6.2f ", bdl->percent); 108 percent_max = bdl->percent[i];
109 }
110
111 if (dl->offset != -1 && percent_max != 0.0) {
112 for (i = 0; i < ab->nr_events; i++) {
113 ui_browser__set_percent_color(browser, bdl->percent[i],
114 current_entry);
115 slsmg_printf("%6.2f ", bdl->percent[i]);
116 }
102 } else { 117 } else {
103 ui_browser__set_percent_color(browser, 0, current_entry); 118 ui_browser__set_percent_color(browser, 0, current_entry);
104 slsmg_write_nstring(" ", 7); 119 slsmg_write_nstring(" ", pcnt_width);
105 } 120 }
106 121
107 SLsmg_write_char(' '); 122 SLsmg_write_char(' ');
@@ -111,12 +126,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
111 width += 1; 126 width += 1;
112 127
113 if (!*dl->line) 128 if (!*dl->line)
114 slsmg_write_nstring(" ", width - 7); 129 slsmg_write_nstring(" ", width - pcnt_width);
115 else if (dl->offset == -1) { 130 else if (dl->offset == -1) {
116 printed = scnprintf(bf, sizeof(bf), "%*s ", 131 printed = scnprintf(bf, sizeof(bf), "%*s ",
117 ab->addr_width, " "); 132 ab->addr_width, " ");
118 slsmg_write_nstring(bf, printed); 133 slsmg_write_nstring(bf, printed);
119 slsmg_write_nstring(dl->line, width - printed - 6); 134 slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
120 } else { 135 } else {
121 u64 addr = dl->offset; 136 u64 addr = dl->offset;
122 int color = -1; 137 int color = -1;
@@ -175,7 +190,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
175 } 190 }
176 191
177 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); 192 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
178 slsmg_write_nstring(bf, width - 10 - printed); 193 slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
179 } 194 }
180 195
181 if (current_entry) 196 if (current_entry)
@@ -200,6 +215,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
200 unsigned int from, to; 215 unsigned int from, to;
201 struct map_symbol *ms = ab->b.priv; 216 struct map_symbol *ms = ab->b.priv;
202 struct symbol *sym = ms->sym; 217 struct symbol *sym = ms->sym;
218 u8 pcnt_width = 7;
203 219
204 /* PLT symbols contain external offsets */ 220 /* PLT symbols contain external offsets */
205 if (strstr(sym->name, "@plt")) 221 if (strstr(sym->name, "@plt"))
@@ -223,57 +239,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
223 to = (u64)btarget->idx; 239 to = (u64)btarget->idx;
224 } 240 }
225 241
242 pcnt_width *= ab->nr_events;
243
226 ui_browser__set_color(browser, HE_COLORSET_CODE); 244 ui_browser__set_color(browser, HE_COLORSET_CODE);
227 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); 245 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
246 from, to);
228} 247}
229 248
230static unsigned int annotate_browser__refresh(struct ui_browser *browser) 249static unsigned int annotate_browser__refresh(struct ui_browser *browser)
231{ 250{
251 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
232 int ret = ui_browser__list_head_refresh(browser); 252 int ret = ui_browser__list_head_refresh(browser);
253 int pcnt_width;
254
255 pcnt_width = 7 * ab->nr_events;
233 256
234 if (annotate_browser__opts.jump_arrows) 257 if (annotate_browser__opts.jump_arrows)
235 annotate_browser__draw_current_jump(browser); 258 annotate_browser__draw_current_jump(browser);
236 259
237 ui_browser__set_color(browser, HE_COLORSET_NORMAL); 260 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
238 __ui_browser__vline(browser, 7, 0, browser->height - 1); 261 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
239 return ret; 262 return ret;
240} 263}
241 264
242static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) 265static int disasm__cmp(struct browser_disasm_line *a,
266 struct browser_disasm_line *b, int nr_pcnt)
243{ 267{
244 double percent = 0.0; 268 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 269
255 next = disasm__get_next_ip_line(&notes->src->source, dl); 270 for (i = 0; i < nr_pcnt; i++) {
256 while (offset < (s64)len && 271 if (a->percent[i] == b->percent[i])
257 (next == NULL || offset < next->offset)) { 272 continue;
258 if (src_line) { 273 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 } 274 }
272 275 return 0;
273 return percent;
274} 276}
275 277
276static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) 278static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
279 int nr_events)
277{ 280{
278 struct rb_node **p = &root->rb_node; 281 struct rb_node **p = &root->rb_node;
279 struct rb_node *parent = NULL; 282 struct rb_node *parent = NULL;
@@ -282,7 +285,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l
282 while (*p != NULL) { 285 while (*p != NULL) {
283 parent = *p; 286 parent = *p;
284 l = rb_entry(parent, struct browser_disasm_line, rb_node); 287 l = rb_entry(parent, struct browser_disasm_line, rb_node);
285 if (bdl->percent < l->percent) 288
289 if (disasm__cmp(bdl, l, nr_events))
286 p = &(*p)->rb_left; 290 p = &(*p)->rb_left;
287 else 291 else
288 p = &(*p)->rb_right; 292 p = &(*p)->rb_right;
@@ -331,12 +335,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
331} 335}
332 336
333static void annotate_browser__calc_percent(struct annotate_browser *browser, 337static void annotate_browser__calc_percent(struct annotate_browser *browser,
334 int evidx) 338 struct perf_evsel *evsel)
335{ 339{
336 struct map_symbol *ms = browser->b.priv; 340 struct map_symbol *ms = browser->b.priv;
337 struct symbol *sym = ms->sym; 341 struct symbol *sym = ms->sym;
338 struct annotation *notes = symbol__annotation(sym); 342 struct annotation *notes = symbol__annotation(sym);
339 struct disasm_line *pos; 343 struct disasm_line *pos, *next;
344 s64 len = symbol__size(sym);
340 345
341 browser->entries = RB_ROOT; 346 browser->entries = RB_ROOT;
342 347
@@ -344,12 +349,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
344 349
345 list_for_each_entry(pos, &notes->src->source, node) { 350 list_for_each_entry(pos, &notes->src->source, node) {
346 struct browser_disasm_line *bpos = disasm_line__browser(pos); 351 struct browser_disasm_line *bpos = disasm_line__browser(pos);
347 bpos->percent = disasm_line__calc_percent(pos, sym, evidx); 352 const char *path = NULL;
348 if (bpos->percent < 0.01) { 353 double max_percent = 0.0;
354 int i;
355
356 if (pos->offset == -1) {
357 RB_CLEAR_NODE(&bpos->rb_node);
358 continue;
359 }
360
361 next = disasm__get_next_ip_line(&notes->src->source, pos);
362
363 for (i = 0; i < browser->nr_events; i++) {
364 bpos->percent[i] = disasm__calc_percent(notes,
365 evsel->idx + i,
366 pos->offset,
367 next ? next->offset : len,
368 &path);
369
370 if (max_percent < bpos->percent[i])
371 max_percent = bpos->percent[i];
372 }
373
374 if (max_percent < 0.01) {
349 RB_CLEAR_NODE(&bpos->rb_node); 375 RB_CLEAR_NODE(&bpos->rb_node);
350 continue; 376 continue;
351 } 377 }
352 disasm_rb_tree__insert(&browser->entries, bpos); 378 disasm_rb_tree__insert(&browser->entries, bpos,
379 browser->nr_events);
353 } 380 }
354 pthread_mutex_unlock(&notes->lock); 381 pthread_mutex_unlock(&notes->lock);
355 382
@@ -401,7 +428,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
401 browser->b.nr_entries = browser->nr_asm_entries; 428 browser->b.nr_entries = browser->nr_asm_entries;
402} 429}
403 430
404static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, 431static bool annotate_browser__callq(struct annotate_browser *browser,
432 struct perf_evsel *evsel,
405 struct hist_browser_timer *hbt) 433 struct hist_browser_timer *hbt)
406{ 434{
407 struct map_symbol *ms = browser->b.priv; 435 struct map_symbol *ms = browser->b.priv;
@@ -432,7 +460,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
432 } 460 }
433 461
434 pthread_mutex_unlock(&notes->lock); 462 pthread_mutex_unlock(&notes->lock);
435 symbol__tui_annotate(target, ms->map, evidx, hbt); 463 symbol__tui_annotate(target, ms->map, evsel, hbt);
436 ui_browser__show_title(&browser->b, sym->name); 464 ui_browser__show_title(&browser->b, sym->name);
437 return true; 465 return true;
438} 466}
@@ -615,7 +643,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
615 browser->addr_width += browser->jumps_width + 1; 643 browser->addr_width += browser->jumps_width + 1;
616} 644}
617 645
618static int annotate_browser__run(struct annotate_browser *browser, int evidx, 646static int annotate_browser__run(struct annotate_browser *browser,
647 struct perf_evsel *evsel,
619 struct hist_browser_timer *hbt) 648 struct hist_browser_timer *hbt)
620{ 649{
621 struct rb_node *nd = NULL; 650 struct rb_node *nd = NULL;
@@ -628,7 +657,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
628 if (ui_browser__show(&browser->b, sym->name, help) < 0) 657 if (ui_browser__show(&browser->b, sym->name, help) < 0)
629 return -1; 658 return -1;
630 659
631 annotate_browser__calc_percent(browser, evidx); 660 annotate_browser__calc_percent(browser, evsel);
632 661
633 if (browser->curr_hot) { 662 if (browser->curr_hot) {
634 annotate_browser__set_rb_top(browser, browser->curr_hot); 663 annotate_browser__set_rb_top(browser, browser->curr_hot);
@@ -641,7 +670,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
641 key = ui_browser__run(&browser->b, delay_secs); 670 key = ui_browser__run(&browser->b, delay_secs);
642 671
643 if (delay_secs != 0) { 672 if (delay_secs != 0) {
644 annotate_browser__calc_percent(browser, evidx); 673 annotate_browser__calc_percent(browser, evsel);
645 /* 674 /*
646 * Current line focus got out of the list of most active 675 * Current line focus got out of the list of most active
647 * lines, NULL it so that if TAB|UNTAB is pressed, we 676 * lines, NULL it so that if TAB|UNTAB is pressed, we
@@ -657,7 +686,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
657 hbt->timer(hbt->arg); 686 hbt->timer(hbt->arg);
658 687
659 if (delay_secs != 0) 688 if (delay_secs != 0)
660 symbol__annotate_decay_histogram(sym, evidx); 689 symbol__annotate_decay_histogram(sym, evsel->idx);
661 continue; 690 continue;
662 case K_TAB: 691 case K_TAB:
663 if (nd != NULL) { 692 if (nd != NULL) {
@@ -754,7 +783,7 @@ show_help:
754 goto show_sup_ins; 783 goto show_sup_ins;
755 goto out; 784 goto out;
756 } else if (!(annotate_browser__jump(browser) || 785 } else if (!(annotate_browser__jump(browser) ||
757 annotate_browser__callq(browser, evidx, hbt))) { 786 annotate_browser__callq(browser, evsel, hbt))) {
758show_sup_ins: 787show_sup_ins:
759 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 788 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
760 } 789 }
@@ -776,10 +805,10 @@ out:
776 return key; 805 return key;
777} 806}
778 807
779int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 808int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
780 struct hist_browser_timer *hbt) 809 struct hist_browser_timer *hbt)
781{ 810{
782 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt); 811 return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
783} 812}
784 813
785static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 814static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
@@ -826,7 +855,8 @@ static inline int width_jumps(int n)
826 return 1; 855 return 1;
827} 856}
828 857
829int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 858int symbol__tui_annotate(struct symbol *sym, struct map *map,
859 struct perf_evsel *evsel,
830 struct hist_browser_timer *hbt) 860 struct hist_browser_timer *hbt)
831{ 861{
832 struct disasm_line *pos, *n; 862 struct disasm_line *pos, *n;
@@ -847,6 +877,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
847 }, 877 },
848 }; 878 };
849 int ret = -1; 879 int ret = -1;
880 int nr_pcnt = 1;
881 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
850 882
851 if (sym == NULL) 883 if (sym == NULL)
852 return -1; 884 return -1;
@@ -862,7 +894,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
862 return -1; 894 return -1;
863 } 895 }
864 896
865 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { 897 if (perf_evsel__is_group_event(evsel)) {
898 nr_pcnt = evsel->nr_members;
899 sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
900 }
901
902 if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
866 ui__error("%s", ui_helpline__last_msg); 903 ui__error("%s", ui_helpline__last_msg);
867 goto out_free_offsets; 904 goto out_free_offsets;
868 } 905 }
@@ -900,6 +937,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); 937 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
901 browser.max_addr_width = hex_width(sym->end); 938 browser.max_addr_width = hex_width(sym->end);
902 browser.jumps_width = width_jumps(browser.max_jump_sources); 939 browser.jumps_width = width_jumps(browser.max_jump_sources);
940 browser.nr_events = nr_pcnt;
903 browser.b.nr_entries = browser.nr_entries; 941 browser.b.nr_entries = browser.nr_entries;
904 browser.b.entries = &notes->src->source, 942 browser.b.entries = &notes->src->source,
905 browser.b.width += 18; /* Percentage */ 943 browser.b.width += 18; /* Percentage */
@@ -909,7 +947,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
909 947
910 annotate_browser__update_addr_width(&browser); 948 annotate_browser__update_addr_width(&browser);
911 949
912 ret = annotate_browser__run(&browser, evidx, hbt); 950 ret = annotate_browser__run(&browser, evsel, hbt);
913 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 951 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
914 list_del(&pos->node); 952 list_del(&pos->node);
915 disasm_line__free(pos); 953 disasm_line__free(pos);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index aa22704047d6..d88a2d0acb6d 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2,7 +2,6 @@
2#include "../libslang.h" 2#include "../libslang.h"
3#include <stdlib.h> 3#include <stdlib.h>
4#include <string.h> 4#include <string.h>
5#include <newt.h>
6#include <linux/rbtree.h> 5#include <linux/rbtree.h>
7 6
8#include "../../util/evsel.h" 7#include "../../util/evsel.h"
@@ -1193,7 +1192,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1193 char buf[512]; 1192 char buf[512];
1194 size_t buflen = sizeof(buf); 1193 size_t buflen = sizeof(buf);
1195 1194
1196 if (symbol_conf.event_group && evsel->nr_members > 1) { 1195 if (perf_evsel__is_group_event(evsel)) {
1197 struct perf_evsel *pos; 1196 struct perf_evsel *pos;
1198 1197
1199 perf_evsel__group_desc(evsel, buf, buflen); 1198 perf_evsel__group_desc(evsel, buf, buflen);
@@ -1599,7 +1598,7 @@ do_annotate:
1599 * Don't let this be freed, say, by hists__decay_entry. 1598 * Don't let this be freed, say, by hists__decay_entry.
1600 */ 1599 */
1601 he->used = true; 1600 he->used = true;
1602 err = hist_entry__tui_annotate(he, evsel->idx, hbt); 1601 err = hist_entry__tui_annotate(he, evsel, hbt);
1603 he->used = false; 1602 he->used = false;
1604 /* 1603 /*
1605 * offer option to annotate the other branch source or target 1604 * offer option to annotate the other branch source or target
@@ -1709,7 +1708,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1708 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1710 HE_COLORSET_NORMAL); 1709 HE_COLORSET_NORMAL);
1711 1710
1712 if (symbol_conf.event_group && evsel->nr_members > 1) { 1711 if (perf_evsel__is_group_event(evsel)) {
1713 struct perf_evsel *pos; 1712 struct perf_evsel *pos;
1714 1713
1715 ev_name = perf_evsel__group_name(evsel); 1714 ev_name = perf_evsel__group_name(evsel);
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 98851d55a53e..95c7cfb8f2c6 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,6 +1,5 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
4#include <inttypes.h> 3#include <inttypes.h>
5#include <sys/ttydefaults.h> 4#include <sys/ttydefaults.h>
6#include <string.h> 5#include <string.h>
@@ -10,41 +9,9 @@
10#include "../../util/symbol.h" 9#include "../../util/symbol.h"
11#include "../browser.h" 10#include "../browser.h"
12#include "../helpline.h" 11#include "../helpline.h"
12#include "../keysyms.h"
13#include "map.h" 13#include "map.h"
14 14
15static int ui_entry__read(const char *title, char *bf, size_t size, int width)
16{
17 struct newtExitStruct es;
18 newtComponent form, entry;
19 const char *result;
20 int err = -1;
21
22 newtCenteredWindow(width, 1, title);
23 form = newtForm(NULL, NULL, 0);
24 if (form == NULL)
25 return -1;
26
27 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
28 if (entry == NULL)
29 goto out_free_form;
30
31 newtFormAddComponent(form, entry);
32 newtFormAddHotKey(form, NEWT_KEY_ENTER);
33 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
34 newtFormAddHotKey(form, NEWT_KEY_LEFT);
35 newtFormAddHotKey(form, CTRL('c'));
36 newtFormRun(form, &es);
37
38 if (result != NULL) {
39 strncpy(bf, result, size);
40 err = 0;
41 }
42out_free_form:
43 newtPopWindow();
44 newtFormDestroy(form);
45 return err;
46}
47
48struct map_browser { 15struct map_browser {
49 struct ui_browser b; 16 struct ui_browser b;
50 struct map *map; 17 struct map *map;
@@ -78,10 +45,11 @@ static int map_browser__search(struct map_browser *self)
78{ 45{
79 char target[512]; 46 char target[512];
80 struct symbol *sym; 47 struct symbol *sym;
81 int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40); 48 int err = ui_browser__input_window("Search by name/addr",
82 49 "Prefix with 0x to search by address",
83 if (err) 50 target, "ENTER: OK, ESC: Cancel", 0);
84 return err; 51 if (err != K_ENTER)
52 return -1;
85 53
86 if (target[0] == '0' && tolower(target[1]) == 'x') { 54 if (target[0] == '0' && tolower(target[1]) == 'x') {
87 u64 addr = strtoull(target, NULL, 16); 55 u64 addr = strtoull(target, NULL, 16);
@@ -112,12 +80,20 @@ static int map_browser__run(struct map_browser *self)
112 while (1) { 80 while (1) {
113 key = ui_browser__run(&self->b, 0); 81 key = ui_browser__run(&self->b, 0);
114 82
115 if (verbose && key == '/') 83 switch (key) {
116 map_browser__search(self); 84 case '/':
117 else 85 if (verbose)
86 map_browser__search(self);
87 default:
118 break; 88 break;
89 case K_LEFT:
90 case K_ESC:
91 case 'q':
92 case CTRL('c'):
93 goto out;
94 }
119 } 95 }
120 96out:
121 ui_browser__hide(&self->b); 97 ui_browser__hide(&self->b);
122 return key; 98 return key;
123} 99}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index cbbd44b0d93e..12f009e61e94 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -1,5 +1,4 @@
1#include <elf.h> 1#include <elf.h>
2#include <newt.h>
3#include <inttypes.h> 2#include <inttypes.h>
4#include <sys/ttydefaults.h> 3#include <sys/ttydefaults.h>
5#include <string.h> 4#include <string.h>
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/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 81efa192e86c..b9401482d110 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -1,4 +1,3 @@
1#include <newt.h>
2#include <signal.h> 1#include <signal.h>
3#include <stdbool.h> 2#include <stdbool.h>
4 3
@@ -88,13 +87,6 @@ int ui__getch(int delay_secs)
88 return SLkp_getkey(); 87 return SLkp_getkey();
89} 88}
90 89
91static void newt_suspend(void *d __maybe_unused)
92{
93 newtSuspend();
94 raise(SIGTSTP);
95 newtResume();
96}
97
98static void ui__signal(int sig) 90static void ui__signal(int sig)
99{ 91{
100 ui__exit(false); 92 ui__exit(false);
@@ -106,7 +98,17 @@ int ui__init(void)
106{ 98{
107 int err; 99 int err;
108 100
109 newtInit(); 101 SLutf8_enable(-1);
102 SLtt_get_terminfo();
103 SLtt_get_screen_size();
104
105 err = SLsmg_init_smg();
106 if (err < 0)
107 goto out;
108 err = SLang_init_tty(0, 0, 0);
109 if (err < 0)
110 goto out;
111
110 err = SLkp_init(); 112 err = SLkp_init();
111 if (err < 0) { 113 if (err < 0) {
112 pr_err("TUI initialization failed.\n"); 114 pr_err("TUI initialization failed.\n");
@@ -115,7 +117,6 @@ int ui__init(void)
115 117
116 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); 118 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
117 119
118 newtSetSuspendCallback(newt_suspend, NULL);
119 ui_helpline__init(); 120 ui_helpline__init();
120 ui_browser__init(); 121 ui_browser__init();
121 ui_progress__init(); 122 ui_progress__init();
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index d86359c99907..70cb0d4eb8aa 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -12,7 +12,7 @@ extern int use_browser;
12void setup_browser(bool fallback_to_pager); 12void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok); 13void exit_browser(bool wait_for_ok);
14 14
15#ifdef NEWT_SUPPORT 15#ifdef SLANG_SUPPORT
16int ui__init(void); 16int ui__init(void);
17void ui__exit(bool wait_for_ok); 17void ui__exit(bool wait_for_ok);
18#else 18#else
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..af755156d278 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 SLANG_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/cpumap.c b/tools/perf/util/cpumap.c
index f817046e22b1..beb8cf9f9976 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -4,6 +4,7 @@
4#include "cpumap.h" 4#include "cpumap.h"
5#include <assert.h> 5#include <assert.h>
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h>
7 8
8static struct cpu_map *cpu_map__default_new(void) 9static struct cpu_map *cpu_map__default_new(void)
9{ 10{
@@ -219,7 +220,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
219 if (!mnt) 220 if (!mnt)
220 return -1; 221 return -1;
221 222
222 sprintf(path, 223 snprintf(path, PATH_MAX,
223 "%s/devices/system/cpu/cpu%d/topology/physical_package_id", 224 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
224 mnt, cpu); 225 mnt, cpu);
225 226
@@ -231,27 +232,88 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
231 return ret == 1 ? cpu : -1; 232 return ret == 1 ? cpu : -1;
232} 233}
233 234
234int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) 235static int cmp_ids(const void *a, const void *b)
235{ 236{
236 struct cpu_map *sock; 237 return *(int *)a - *(int *)b;
238}
239
240static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
241 int (*f)(struct cpu_map *map, int cpu))
242{
243 struct cpu_map *c;
237 int nr = cpus->nr; 244 int nr = cpus->nr;
238 int cpu, s1, s2; 245 int cpu, s1, s2;
239 246
240 sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); 247 /* allocate as much as possible */
241 if (!sock) 248 c = calloc(1, sizeof(*c) + nr * sizeof(int));
249 if (!c)
242 return -1; 250 return -1;
243 251
244 for (cpu = 0; cpu < nr; cpu++) { 252 for (cpu = 0; cpu < nr; cpu++) {
245 s1 = cpu_map__get_socket(cpus, cpu); 253 s1 = f(cpus, cpu);
246 for (s2 = 0; s2 < sock->nr; s2++) { 254 for (s2 = 0; s2 < c->nr; s2++) {
247 if (s1 == sock->map[s2]) 255 if (s1 == c->map[s2])
248 break; 256 break;
249 } 257 }
250 if (s2 == sock->nr) { 258 if (s2 == c->nr) {
251 sock->map[sock->nr] = s1; 259 c->map[c->nr] = s1;
252 sock->nr++; 260 c->nr++;
253 } 261 }
254 } 262 }
255 *sockp = sock; 263 /* ensure we process id in increasing order */
264 qsort(c->map, c->nr, sizeof(int), cmp_ids);
265
266 *res = c;
256 return 0; 267 return 0;
257} 268}
269
270int cpu_map__get_core(struct cpu_map *map, int idx)
271{
272 FILE *fp;
273 const char *mnt;
274 char path[PATH_MAX];
275 int cpu, ret, s;
276
277 if (idx > map->nr)
278 return -1;
279
280 cpu = map->map[idx];
281
282 mnt = sysfs_find_mountpoint();
283 if (!mnt)
284 return -1;
285
286 snprintf(path, PATH_MAX,
287 "%s/devices/system/cpu/cpu%d/topology/core_id",
288 mnt, cpu);
289
290 fp = fopen(path, "r");
291 if (!fp)
292 return -1;
293 ret = fscanf(fp, "%d", &cpu);
294 fclose(fp);
295 if (ret != 1)
296 return -1;
297
298 s = cpu_map__get_socket(map, idx);
299 if (s == -1)
300 return -1;
301
302 /*
303 * encode socket in upper 16 bits
304 * core_id is relative to socket, and
305 * we need a global id. So we combine
306 * socket+ core id
307 */
308 return (s << 16) | (cpu & 0xffff);
309}
310
311int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
312{
313 return cpu_map__build_map(cpus, sockp, cpu_map__get_socket);
314}
315
316int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 161b00756a12..9bed02e5fb3d 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -15,7 +15,9 @@ void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx); 17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__get_core(struct cpu_map *map, int idx);
18int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); 19int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
20int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
19 21
20static inline int cpu_map__socket(struct cpu_map *sock, int s) 22static inline int cpu_map__socket(struct cpu_map *sock, int s)
21{ 23{
@@ -24,6 +26,16 @@ static inline int cpu_map__socket(struct cpu_map *sock, int s)
24 return sock->map[s]; 26 return sock->map[s];
25} 27}
26 28
29static inline int cpu_map__id_to_socket(int id)
30{
31 return id >> 16;
32}
33
34static inline int cpu_map__id_to_cpu(int id)
35{
36 return id & 0xffff;
37}
38
27static inline int cpu_map__nr(const struct cpu_map *map) 39static inline int cpu_map__nr(const struct cpu_map *map)
28{ 40{
29 return map ? map->nr : 1; 41 return map ? map->nr : 1;
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/event.h b/tools/perf/util/event.h
index 0d573ff4771a..181389535c0c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -88,8 +88,10 @@ struct perf_sample {
88 u64 id; 88 u64 id;
89 u64 stream_id; 89 u64 stream_id;
90 u64 period; 90 u64 period;
91 u64 weight;
91 u32 cpu; 92 u32 cpu;
92 u32 raw_size; 93 u32 raw_size;
94 u64 data_src;
93 void *raw_data; 95 void *raw_data;
94 struct ip_callchain *callchain; 96 struct ip_callchain *callchain;
95 struct branch_stack *branch_stack; 97 struct branch_stack *branch_stack;
@@ -97,6 +99,13 @@ struct perf_sample {
97 struct stack_dump user_stack; 99 struct stack_dump user_stack;
98}; 100};
99 101
102#define PERF_MEM_DATA_SRC_NONE \
103 (PERF_MEM_S(OP, NA) |\
104 PERF_MEM_S(LVL, NA) |\
105 PERF_MEM_S(SNOOP, NA) |\
106 PERF_MEM_S(LOCK, NA) |\
107 PERF_MEM_S(TLB, NA))
108
100struct build_id_event { 109struct build_id_event {
101 struct perf_event_header header; 110 struct perf_event_header header;
102 pid_t pid; 111 pid_t pid;
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..07b1a3ad3e24 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"
@@ -554,6 +554,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
554 perf_evsel__set_sample_bit(evsel, CPU); 554 perf_evsel__set_sample_bit(evsel, CPU);
555 } 555 }
556 556
557 if (opts->sample_address)
558 attr->sample_type |= PERF_SAMPLE_DATA_SRC;
559
557 if (opts->no_delay) { 560 if (opts->no_delay) {
558 attr->watermark = 0; 561 attr->watermark = 0;
559 attr->wakeup_events = 1; 562 attr->wakeup_events = 1;
@@ -563,6 +566,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
563 attr->branch_sample_type = opts->branch_stack; 566 attr->branch_sample_type = opts->branch_stack;
564 } 567 }
565 568
569 if (opts->sample_weight)
570 attr->sample_type |= PERF_SAMPLE_WEIGHT;
571
566 attr->mmap = track; 572 attr->mmap = track;
567 attr->comm = track; 573 attr->comm = track;
568 574
@@ -633,6 +639,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
633 return 0; 639 return 0;
634} 640}
635 641
642void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
643{
644 memset(evsel->counts, 0, (sizeof(*evsel->counts) +
645 (ncpus * sizeof(struct perf_counts_values))));
646}
647
636int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 648int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
637{ 649{
638 evsel->counts = zalloc((sizeof(*evsel->counts) + 650 evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -673,9 +685,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
673void perf_evsel__exit(struct perf_evsel *evsel) 685void perf_evsel__exit(struct perf_evsel *evsel)
674{ 686{
675 assert(list_empty(&evsel->node)); 687 assert(list_empty(&evsel->node));
676 xyarray__delete(evsel->fd); 688 perf_evsel__free_fd(evsel);
677 xyarray__delete(evsel->sample_id); 689 perf_evsel__free_id(evsel);
678 free(evsel->id);
679} 690}
680 691
681void perf_evsel__delete(struct perf_evsel *evsel) 692void perf_evsel__delete(struct perf_evsel *evsel)
@@ -1012,6 +1023,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1012 data->cpu = data->pid = data->tid = -1; 1023 data->cpu = data->pid = data->tid = -1;
1013 data->stream_id = data->id = data->time = -1ULL; 1024 data->stream_id = data->id = data->time = -1ULL;
1014 data->period = 1; 1025 data->period = 1;
1026 data->weight = 0;
1015 1027
1016 if (event->header.type != PERF_RECORD_SAMPLE) { 1028 if (event->header.type != PERF_RECORD_SAMPLE) {
1017 if (!evsel->attr.sample_id_all) 1029 if (!evsel->attr.sample_id_all)
@@ -1162,6 +1174,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1162 } 1174 }
1163 } 1175 }
1164 1176
1177 data->weight = 0;
1178 if (type & PERF_SAMPLE_WEIGHT) {
1179 data->weight = *array;
1180 array++;
1181 }
1182
1183 data->data_src = PERF_MEM_DATA_SRC_NONE;
1184 if (type & PERF_SAMPLE_DATA_SRC) {
1185 data->data_src = *array;
1186 array++;
1187 }
1188
1165 return 0; 1189 return 0;
1166} 1190}
1167 1191
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..326068a593a5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,5 +1,3 @@
1#define _FILE_OFFSET_BITS 64
2
3#include "util.h" 1#include "util.h"
4#include <sys/types.h> 2#include <sys/types.h>
5#include <byteswap.h> 3#include <byteswap.h>
@@ -1672,8 +1670,8 @@ static int process_tracing_data(struct perf_file_section *section __maybe_unused
1672 struct perf_header *ph __maybe_unused, 1670 struct perf_header *ph __maybe_unused,
1673 int fd, void *data) 1671 int fd, void *data)
1674{ 1672{
1675 trace_report(fd, data, false); 1673 ssize_t ret = trace_report(fd, data, false);
1676 return 0; 1674 return ret < 0 ? -1 : 0;
1677} 1675}
1678 1676
1679static int process_build_id(struct perf_file_section *section, 1677static int process_build_id(struct perf_file_section *section,
@@ -2752,6 +2750,11 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
2752 if (evsel->tp_format) 2750 if (evsel->tp_format)
2753 return 0; 2751 return 0;
2754 2752
2753 if (pevent == NULL) {
2754 pr_debug("broken or missing trace data\n");
2755 return -1;
2756 }
2757
2755 event = pevent_find_event(pevent, evsel->attr.config); 2758 event = pevent_find_event(pevent, evsel->attr.config);
2756 if (event == NULL) 2759 if (event == NULL)
2757 return -1; 2760 return -1;
@@ -2789,7 +2792,7 @@ int perf_session__read_header(struct perf_session *session, int fd)
2789 u64 f_id; 2792 u64 f_id;
2790 int nr_attrs, nr_ids, i, j; 2793 int nr_attrs, nr_ids, i, j;
2791 2794
2792 session->evlist = perf_evlist__new(NULL, NULL); 2795 session->evlist = perf_evlist__new();
2793 if (session->evlist == NULL) 2796 if (session->evlist == NULL)
2794 return -ENOMEM; 2797 return -ENOMEM;
2795 2798
@@ -2940,7 +2943,7 @@ int perf_event__process_attr(union perf_event *event,
2940 struct perf_evlist *evlist = *pevlist; 2943 struct perf_evlist *evlist = *pevlist;
2941 2944
2942 if (evlist == NULL) { 2945 if (evlist == NULL) {
2943 *pevlist = evlist = perf_evlist__new(NULL, NULL); 2946 *pevlist = evlist = perf_evlist__new();
2944 if (evlist == NULL) 2947 if (evlist == NULL)
2945 return -ENOMEM; 2948 return -ENOMEM;
2946 } 2949 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f855941bebea..6b32721f829a 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -67,12 +67,16 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
67void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 67void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
68{ 68{
69 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 69 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
70 int symlen;
70 u16 len; 71 u16 len;
71 72
72 if (h->ms.sym) 73 if (h->ms.sym)
73 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 74 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
74 else 75 else {
76 symlen = unresolved_col_width + 4 + 2;
77 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
75 hists__set_unres_dso_col_len(hists, HISTC_DSO); 78 hists__set_unres_dso_col_len(hists, HISTC_DSO);
79 }
76 80
77 len = thread__comm_len(h->thread); 81 len = thread__comm_len(h->thread);
78 if (hists__new_col_len(hists, HISTC_COMM, len)) 82 if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -87,7 +91,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
87 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); 91 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
88 92
89 if (h->branch_info) { 93 if (h->branch_info) {
90 int symlen;
91 /* 94 /*
92 * +4 accounts for '[x] ' priv level info 95 * +4 accounts for '[x] ' priv level info
93 * +2 account of 0x prefix on raw addresses 96 * +2 account of 0x prefix on raw addresses
@@ -116,6 +119,42 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
116 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 119 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
117 } 120 }
118 } 121 }
122
123 if (h->mem_info) {
124 /*
125 * +4 accounts for '[x] ' priv level info
126 * +2 account of 0x prefix on raw addresses
127 */
128 if (h->mem_info->daddr.sym) {
129 symlen = (int)h->mem_info->daddr.sym->namelen + 4
130 + unresolved_col_width + 2;
131 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
132 symlen);
133 } else {
134 symlen = unresolved_col_width + 4 + 2;
135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
136 symlen);
137 }
138 if (h->mem_info->daddr.map) {
139 symlen = dso__name_len(h->mem_info->daddr.map->dso);
140 hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
141 symlen);
142 } else {
143 symlen = unresolved_col_width + 4 + 2;
144 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
145 }
146 } else {
147 symlen = unresolved_col_width + 4 + 2;
148 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
149 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
150 }
151
152 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
153 hists__new_col_len(hists, HISTC_MEM_TLB, 22);
154 hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
155 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
156 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
157 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
119} 158}
120 159
121void hists__output_recalc_col_len(struct hists *hists, int max_rows) 160void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -155,9 +194,12 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
155 } 194 }
156} 195}
157 196
158static void he_stat__add_period(struct he_stat *he_stat, u64 period) 197static void he_stat__add_period(struct he_stat *he_stat, u64 period,
198 u64 weight)
159{ 199{
200
160 he_stat->period += period; 201 he_stat->period += period;
202 he_stat->weight += weight;
161 he_stat->nr_events += 1; 203 he_stat->nr_events += 1;
162} 204}
163 205
@@ -169,12 +211,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
169 dest->period_guest_sys += src->period_guest_sys; 211 dest->period_guest_sys += src->period_guest_sys;
170 dest->period_guest_us += src->period_guest_us; 212 dest->period_guest_us += src->period_guest_us;
171 dest->nr_events += src->nr_events; 213 dest->nr_events += src->nr_events;
214 dest->weight += src->weight;
172} 215}
173 216
174static void hist_entry__decay(struct hist_entry *he) 217static void hist_entry__decay(struct hist_entry *he)
175{ 218{
176 he->stat.period = (he->stat.period * 7) / 8; 219 he->stat.period = (he->stat.period * 7) / 8;
177 he->stat.nr_events = (he->stat.nr_events * 7) / 8; 220 he->stat.nr_events = (he->stat.nr_events * 7) / 8;
221 /* XXX need decay for weight too? */
178} 222}
179 223
180static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 224static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@@ -239,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists,
239static struct hist_entry *hist_entry__new(struct hist_entry *template) 283static struct hist_entry *hist_entry__new(struct hist_entry *template)
240{ 284{
241 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 285 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
242 struct hist_entry *he = malloc(sizeof(*he) + callchain_size); 286 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size);
243 287
244 if (he != NULL) { 288 if (he != NULL) {
245 *he = *template; 289 *he = *template;
@@ -254,6 +298,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
254 he->branch_info->to.map->referenced = true; 298 he->branch_info->to.map->referenced = true;
255 } 299 }
256 300
301 if (he->mem_info) {
302 if (he->mem_info->iaddr.map)
303 he->mem_info->iaddr.map->referenced = true;
304 if (he->mem_info->daddr.map)
305 he->mem_info->daddr.map->referenced = true;
306 }
307
257 if (symbol_conf.use_callchain) 308 if (symbol_conf.use_callchain)
258 callchain_init(he->callchain); 309 callchain_init(he->callchain);
259 310
@@ -282,7 +333,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
282static struct hist_entry *add_hist_entry(struct hists *hists, 333static struct hist_entry *add_hist_entry(struct hists *hists,
283 struct hist_entry *entry, 334 struct hist_entry *entry,
284 struct addr_location *al, 335 struct addr_location *al,
285 u64 period) 336 u64 period,
337 u64 weight)
286{ 338{
287 struct rb_node **p; 339 struct rb_node **p;
288 struct rb_node *parent = NULL; 340 struct rb_node *parent = NULL;
@@ -306,7 +358,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
306 cmp = hist_entry__cmp(he, entry); 358 cmp = hist_entry__cmp(he, entry);
307 359
308 if (!cmp) { 360 if (!cmp) {
309 he_stat__add_period(&he->stat, period); 361 he_stat__add_period(&he->stat, period, weight);
310 362
311 /* If the map of an existing hist_entry has 363 /* If the map of an existing hist_entry has
312 * become out-of-date due to an exec() or 364 * become out-of-date due to an exec() or
@@ -341,11 +393,42 @@ out_unlock:
341 return he; 393 return he;
342} 394}
343 395
396struct hist_entry *__hists__add_mem_entry(struct hists *self,
397 struct addr_location *al,
398 struct symbol *sym_parent,
399 struct mem_info *mi,
400 u64 period,
401 u64 weight)
402{
403 struct hist_entry entry = {
404 .thread = al->thread,
405 .ms = {
406 .map = al->map,
407 .sym = al->sym,
408 },
409 .stat = {
410 .period = period,
411 .weight = weight,
412 .nr_events = 1,
413 },
414 .cpu = al->cpu,
415 .ip = al->addr,
416 .level = al->level,
417 .parent = sym_parent,
418 .filtered = symbol__parent_filter(sym_parent),
419 .hists = self,
420 .mem_info = mi,
421 .branch_info = NULL,
422 };
423 return add_hist_entry(self, &entry, al, period, weight);
424}
425
344struct hist_entry *__hists__add_branch_entry(struct hists *self, 426struct hist_entry *__hists__add_branch_entry(struct hists *self,
345 struct addr_location *al, 427 struct addr_location *al,
346 struct symbol *sym_parent, 428 struct symbol *sym_parent,
347 struct branch_info *bi, 429 struct branch_info *bi,
348 u64 period) 430 u64 period,
431 u64 weight)
349{ 432{
350 struct hist_entry entry = { 433 struct hist_entry entry = {
351 .thread = al->thread, 434 .thread = al->thread,
@@ -359,19 +442,22 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
359 .stat = { 442 .stat = {
360 .period = period, 443 .period = period,
361 .nr_events = 1, 444 .nr_events = 1,
445 .weight = weight,
362 }, 446 },
363 .parent = sym_parent, 447 .parent = sym_parent,
364 .filtered = symbol__parent_filter(sym_parent), 448 .filtered = symbol__parent_filter(sym_parent),
365 .branch_info = bi, 449 .branch_info = bi,
366 .hists = self, 450 .hists = self,
451 .mem_info = NULL,
367 }; 452 };
368 453
369 return add_hist_entry(self, &entry, al, period); 454 return add_hist_entry(self, &entry, al, period, weight);
370} 455}
371 456
372struct hist_entry *__hists__add_entry(struct hists *self, 457struct hist_entry *__hists__add_entry(struct hists *self,
373 struct addr_location *al, 458 struct addr_location *al,
374 struct symbol *sym_parent, u64 period) 459 struct symbol *sym_parent, u64 period,
460 u64 weight)
375{ 461{
376 struct hist_entry entry = { 462 struct hist_entry entry = {
377 .thread = al->thread, 463 .thread = al->thread,
@@ -385,13 +471,16 @@ struct hist_entry *__hists__add_entry(struct hists *self,
385 .stat = { 471 .stat = {
386 .period = period, 472 .period = period,
387 .nr_events = 1, 473 .nr_events = 1,
474 .weight = weight,
388 }, 475 },
389 .parent = sym_parent, 476 .parent = sym_parent,
390 .filtered = symbol__parent_filter(sym_parent), 477 .filtered = symbol__parent_filter(sym_parent),
391 .hists = self, 478 .hists = self,
479 .branch_info = NULL,
480 .mem_info = NULL,
392 }; 481 };
393 482
394 return add_hist_entry(self, &entry, al, period); 483 return add_hist_entry(self, &entry, al, period, weight);
395} 484}
396 485
397int64_t 486int64_t
@@ -431,6 +520,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
431void hist_entry__free(struct hist_entry *he) 520void hist_entry__free(struct hist_entry *he)
432{ 521{
433 free(he->branch_info); 522 free(he->branch_info);
523 free(he->mem_info);
434 free(he); 524 free(he);
435} 525}
436 526
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 226a4ae2f936..14c2fe20aa62 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -49,6 +49,14 @@ enum hist_column {
49 HISTC_DSO_FROM, 49 HISTC_DSO_FROM,
50 HISTC_DSO_TO, 50 HISTC_DSO_TO,
51 HISTC_SRCLINE, 51 HISTC_SRCLINE,
52 HISTC_LOCAL_WEIGHT,
53 HISTC_GLOBAL_WEIGHT,
54 HISTC_MEM_DADDR_SYMBOL,
55 HISTC_MEM_DADDR_DSO,
56 HISTC_MEM_LOCKED,
57 HISTC_MEM_TLB,
58 HISTC_MEM_LVL,
59 HISTC_MEM_SNOOP,
52 HISTC_NR_COLS, /* Last entry */ 60 HISTC_NR_COLS, /* Last entry */
53}; 61};
54 62
@@ -73,7 +81,8 @@ struct hists {
73 81
74struct hist_entry *__hists__add_entry(struct hists *self, 82struct hist_entry *__hists__add_entry(struct hists *self,
75 struct addr_location *al, 83 struct addr_location *al,
76 struct symbol *parent, u64 period); 84 struct symbol *parent, u64 period,
85 u64 weight);
77int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 86int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
78int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 87int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
79int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 88int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
@@ -84,7 +93,15 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al, 93 struct addr_location *al,
85 struct symbol *sym_parent, 94 struct symbol *sym_parent,
86 struct branch_info *bi, 95 struct branch_info *bi,
87 u64 period); 96 u64 period,
97 u64 weight);
98
99struct hist_entry *__hists__add_mem_entry(struct hists *self,
100 struct addr_location *al,
101 struct symbol *sym_parent,
102 struct mem_info *mi,
103 u64 period,
104 u64 weight);
88 105
89void hists__output_resort(struct hists *self); 106void hists__output_resort(struct hists *self);
90void hists__output_resort_threaded(struct hists *hists); 107void hists__output_resort_threaded(struct hists *hists);
@@ -175,9 +192,9 @@ struct hist_browser_timer {
175 int refresh; 192 int refresh;
176}; 193};
177 194
178#ifdef NEWT_SUPPORT 195#ifdef SLANG_SUPPORT
179#include "../ui/keysyms.h" 196#include "../ui/keysyms.h"
180int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 197int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
181 struct hist_browser_timer *hbt); 198 struct hist_browser_timer *hbt);
182 199
183int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 200int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
@@ -196,7 +213,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
196 213
197static inline int hist_entry__tui_annotate(struct hist_entry *self 214static inline int hist_entry__tui_annotate(struct hist_entry *self
198 __maybe_unused, 215 __maybe_unused,
199 int evidx __maybe_unused, 216 struct perf_evsel *evsel
217 __maybe_unused,
200 struct hist_browser_timer *hbt 218 struct hist_browser_timer *hbt
201 __maybe_unused) 219 __maybe_unused)
202{ 220{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index efdb38e65a92..b2ecad6ec46b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -955,6 +955,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
956 struct thread *thread; 956 struct thread *thread;
957 struct map *map; 957 struct map *map;
958 enum map_type type;
958 int ret = 0; 959 int ret = 0;
959 960
960 if (dump_trace) 961 if (dump_trace)
@@ -971,10 +972,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
971 thread = machine__findnew_thread(machine, event->mmap.pid); 972 thread = machine__findnew_thread(machine, event->mmap.pid);
972 if (thread == NULL) 973 if (thread == NULL)
973 goto out_problem; 974 goto out_problem;
975
976 if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
977 type = MAP__VARIABLE;
978 else
979 type = MAP__FUNCTION;
980
974 map = map__new(&machine->user_dsos, event->mmap.start, 981 map = map__new(&machine->user_dsos, event->mmap.start,
975 event->mmap.len, event->mmap.pgoff, 982 event->mmap.len, event->mmap.pgoff,
976 event->mmap.pid, event->mmap.filename, 983 event->mmap.pid, event->mmap.filename,
977 MAP__FUNCTION); 984 type);
985
978 if (map == NULL) 986 if (map == NULL)
979 goto out_problem; 987 goto out_problem;
980 988
@@ -1003,6 +1011,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1003 return 0; 1011 return 0;
1004} 1012}
1005 1013
1014static void machine__remove_thread(struct machine *machine, struct thread *th)
1015{
1016 machine->last_match = NULL;
1017 rb_erase(&th->rb_node, &machine->threads);
1018 /*
1019 * We may have references to this thread, for instance in some hist_entry
1020 * instances, so just move them to a separate list.
1021 */
1022 list_add_tail(&th->node, &machine->dead_threads);
1023}
1024
1006int machine__process_exit_event(struct machine *machine, union perf_event *event) 1025int machine__process_exit_event(struct machine *machine, union perf_event *event)
1007{ 1026{
1008 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1027 struct thread *thread = machine__find_thread(machine, event->fork.tid);
@@ -1039,17 +1058,6 @@ int machine__process_event(struct machine *machine, union perf_event *event)
1039 return ret; 1058 return ret;
1040} 1059}
1041 1060
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) 1061static bool symbol__match_parent_regex(struct symbol *sym)
1054{ 1062{
1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 1063 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -1097,6 +1105,38 @@ found:
1097 ams->map = al.map; 1105 ams->map = al.map;
1098} 1106}
1099 1107
1108static void ip__resolve_data(struct machine *machine, struct thread *thread,
1109 u8 m, struct addr_map_symbol *ams, u64 addr)
1110{
1111 struct addr_location al;
1112
1113 memset(&al, 0, sizeof(al));
1114
1115 thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al,
1116 NULL);
1117 ams->addr = addr;
1118 ams->al_addr = al.addr;
1119 ams->sym = al.sym;
1120 ams->map = al.map;
1121}
1122
1123struct mem_info *machine__resolve_mem(struct machine *machine,
1124 struct thread *thr,
1125 struct perf_sample *sample,
1126 u8 cpumode)
1127{
1128 struct mem_info *mi = zalloc(sizeof(*mi));
1129
1130 if (!mi)
1131 return NULL;
1132
1133 ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
1134 ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
1135 mi->data_src.val = sample->data_src;
1136
1137 return mi;
1138}
1139
1100struct branch_info *machine__resolve_bstack(struct machine *machine, 1140struct branch_info *machine__resolve_bstack(struct machine *machine,
1101 struct thread *thr, 1141 struct thread *thr,
1102 struct branch_stack *bs) 1142 struct branch_stack *bs)
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 5ac5892f2326..77940680f1fc 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -76,6 +76,9 @@ void machine__delete(struct machine *machine);
76struct branch_info *machine__resolve_bstack(struct machine *machine, 76struct branch_info *machine__resolve_bstack(struct machine *machine,
77 struct thread *thread, 77 struct thread *thread,
78 struct branch_stack *bs); 78 struct branch_stack *bs);
79struct mem_info *machine__resolve_mem(struct machine *machine,
80 struct thread *thread,
81 struct perf_sample *sample, u8 cpumode);
79int machine__resolve_callchain(struct machine *machine, 82int machine__resolve_callchain(struct machine *machine,
80 struct perf_evsel *evsel, 83 struct perf_evsel *evsel,
81 struct thread *thread, 84 struct thread *thread,
@@ -97,7 +100,6 @@ static inline bool machine__is_host(struct machine *machine)
97} 100}
98 101
99struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
100void machine__remove_thread(struct machine *machine, struct thread *th);
101 103
102size_t machine__fprintf(struct machine *machine, FILE *fp); 104size_t machine__fprintf(struct machine *machine, FILE *fp);
103 105
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..cf1fe01b7e89 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,3 @@
1#define _FILE_OFFSET_BITS 64
2
3#include <linux/kernel.h> 1#include <linux/kernel.h>
4 2
5#include <byteswap.h> 3#include <byteswap.h>
@@ -800,6 +798,12 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
800 798
801 if (sample_type & PERF_SAMPLE_STACK_USER) 799 if (sample_type & PERF_SAMPLE_STACK_USER)
802 stack_user__printf(&sample->user_stack); 800 stack_user__printf(&sample->user_stack);
801
802 if (sample_type & PERF_SAMPLE_WEIGHT)
803 printf("... weight: %" PRIu64 "\n", sample->weight);
804
805 if (sample_type & PERF_SAMPLE_DATA_SRC)
806 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
803} 807}
804 808
805static struct machine * 809static struct machine *
@@ -1365,18 +1369,6 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1365 return machine__fprintf(&session->machines.host, fp); 1369 return machine__fprintf(&session->machines.host, fp);
1366} 1370}
1367 1371
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, 1372struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1381 unsigned int type) 1373 unsigned int type)
1382{ 1374{
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/sort.c b/tools/perf/util/sort.c
index d41926cb9e3f..5f52d492590c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -198,11 +198,19 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
198 } 198 }
199 199
200 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 200 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
201 if (sym) 201 if (sym && map) {
202 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 202 if (map->type == MAP__VARIABLE) {
203 width - ret, 203 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
204 sym->name); 204 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
205 else { 205 ip - map->unmap_ip(map, sym->start));
206 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
207 width - ret, "");
208 } else {
209 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
210 width - ret,
211 sym->name);
212 }
213 } else {
206 size_t len = BITS_PER_LONG / 4; 214 size_t len = BITS_PER_LONG / 4;
207 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 215 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
208 len, ip); 216 len, ip);
@@ -457,6 +465,304 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
457 return repsep_snprintf(bf, size, "%-*s", width, out); 465 return repsep_snprintf(bf, size, "%-*s", width, out);
458} 466}
459 467
468/* --sort daddr_sym */
469static int64_t
470sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
471{
472 uint64_t l = 0, r = 0;
473
474 if (left->mem_info)
475 l = left->mem_info->daddr.addr;
476 if (right->mem_info)
477 r = right->mem_info->daddr.addr;
478
479 return (int64_t)(r - l);
480}
481
482static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
483 size_t size, unsigned int width)
484{
485 uint64_t addr = 0;
486 struct map *map = NULL;
487 struct symbol *sym = NULL;
488
489 if (self->mem_info) {
490 addr = self->mem_info->daddr.addr;
491 map = self->mem_info->daddr.map;
492 sym = self->mem_info->daddr.sym;
493 }
494 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
495 width);
496}
497
498static int64_t
499sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
500{
501 struct map *map_l = NULL;
502 struct map *map_r = NULL;
503
504 if (left->mem_info)
505 map_l = left->mem_info->daddr.map;
506 if (right->mem_info)
507 map_r = right->mem_info->daddr.map;
508
509 return _sort__dso_cmp(map_l, map_r);
510}
511
512static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
513 size_t size, unsigned int width)
514{
515 struct map *map = NULL;
516
517 if (self->mem_info)
518 map = self->mem_info->daddr.map;
519
520 return _hist_entry__dso_snprintf(map, bf, size, width);
521}
522
523static int64_t
524sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
525{
526 union perf_mem_data_src data_src_l;
527 union perf_mem_data_src data_src_r;
528
529 if (left->mem_info)
530 data_src_l = left->mem_info->data_src;
531 else
532 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
533
534 if (right->mem_info)
535 data_src_r = right->mem_info->data_src;
536 else
537 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
538
539 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
540}
541
542static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
543 size_t size, unsigned int width)
544{
545 const char *out;
546 u64 mask = PERF_MEM_LOCK_NA;
547
548 if (self->mem_info)
549 mask = self->mem_info->data_src.mem_lock;
550
551 if (mask & PERF_MEM_LOCK_NA)
552 out = "N/A";
553 else if (mask & PERF_MEM_LOCK_LOCKED)
554 out = "Yes";
555 else
556 out = "No";
557
558 return repsep_snprintf(bf, size, "%-*s", width, out);
559}
560
561static int64_t
562sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
563{
564 union perf_mem_data_src data_src_l;
565 union perf_mem_data_src data_src_r;
566
567 if (left->mem_info)
568 data_src_l = left->mem_info->data_src;
569 else
570 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
571
572 if (right->mem_info)
573 data_src_r = right->mem_info->data_src;
574 else
575 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
576
577 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
578}
579
580static const char * const tlb_access[] = {
581 "N/A",
582 "HIT",
583 "MISS",
584 "L1",
585 "L2",
586 "Walker",
587 "Fault",
588};
589#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
590
591static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
592 size_t size, unsigned int width)
593{
594 char out[64];
595 size_t sz = sizeof(out) - 1; /* -1 for null termination */
596 size_t l = 0, i;
597 u64 m = PERF_MEM_TLB_NA;
598 u64 hit, miss;
599
600 out[0] = '\0';
601
602 if (self->mem_info)
603 m = self->mem_info->data_src.mem_dtlb;
604
605 hit = m & PERF_MEM_TLB_HIT;
606 miss = m & PERF_MEM_TLB_MISS;
607
608 /* already taken care of */
609 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
610
611 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
612 if (!(m & 0x1))
613 continue;
614 if (l) {
615 strcat(out, " or ");
616 l += 4;
617 }
618 strncat(out, tlb_access[i], sz - l);
619 l += strlen(tlb_access[i]);
620 }
621 if (*out == '\0')
622 strcpy(out, "N/A");
623 if (hit)
624 strncat(out, " hit", sz - l);
625 if (miss)
626 strncat(out, " miss", sz - l);
627
628 return repsep_snprintf(bf, size, "%-*s", width, out);
629}
630
631static int64_t
632sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
633{
634 union perf_mem_data_src data_src_l;
635 union perf_mem_data_src data_src_r;
636
637 if (left->mem_info)
638 data_src_l = left->mem_info->data_src;
639 else
640 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
641
642 if (right->mem_info)
643 data_src_r = right->mem_info->data_src;
644 else
645 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
646
647 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
648}
649
650static const char * const mem_lvl[] = {
651 "N/A",
652 "HIT",
653 "MISS",
654 "L1",
655 "LFB",
656 "L2",
657 "L3",
658 "Local RAM",
659 "Remote RAM (1 hop)",
660 "Remote RAM (2 hops)",
661 "Remote Cache (1 hop)",
662 "Remote Cache (2 hops)",
663 "I/O",
664 "Uncached",
665};
666#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
667
668static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
669 size_t size, unsigned int width)
670{
671 char out[64];
672 size_t sz = sizeof(out) - 1; /* -1 for null termination */
673 size_t i, l = 0;
674 u64 m = PERF_MEM_LVL_NA;
675 u64 hit, miss;
676
677 if (self->mem_info)
678 m = self->mem_info->data_src.mem_lvl;
679
680 out[0] = '\0';
681
682 hit = m & PERF_MEM_LVL_HIT;
683 miss = m & PERF_MEM_LVL_MISS;
684
685 /* already taken care of */
686 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
687
688 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
689 if (!(m & 0x1))
690 continue;
691 if (l) {
692 strcat(out, " or ");
693 l += 4;
694 }
695 strncat(out, mem_lvl[i], sz - l);
696 l += strlen(mem_lvl[i]);
697 }
698 if (*out == '\0')
699 strcpy(out, "N/A");
700 if (hit)
701 strncat(out, " hit", sz - l);
702 if (miss)
703 strncat(out, " miss", sz - l);
704
705 return repsep_snprintf(bf, size, "%-*s", width, out);
706}
707
708static int64_t
709sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
710{
711 union perf_mem_data_src data_src_l;
712 union perf_mem_data_src data_src_r;
713
714 if (left->mem_info)
715 data_src_l = left->mem_info->data_src;
716 else
717 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
718
719 if (right->mem_info)
720 data_src_r = right->mem_info->data_src;
721 else
722 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
723
724 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
725}
726
727static const char * const snoop_access[] = {
728 "N/A",
729 "None",
730 "Miss",
731 "Hit",
732 "HitM",
733};
734#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
735
736static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
737 size_t size, unsigned int width)
738{
739 char out[64];
740 size_t sz = sizeof(out) - 1; /* -1 for null termination */
741 size_t i, l = 0;
742 u64 m = PERF_MEM_SNOOP_NA;
743
744 out[0] = '\0';
745
746 if (self->mem_info)
747 m = self->mem_info->data_src.mem_snoop;
748
749 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
750 if (!(m & 0x1))
751 continue;
752 if (l) {
753 strcat(out, " or ");
754 l += 4;
755 }
756 strncat(out, snoop_access[i], sz - l);
757 l += strlen(snoop_access[i]);
758 }
759
760 if (*out == '\0')
761 strcpy(out, "N/A");
762
763 return repsep_snprintf(bf, size, "%-*s", width, out);
764}
765
460struct sort_entry sort_mispredict = { 766struct sort_entry sort_mispredict = {
461 .se_header = "Branch Mispredicted", 767 .se_header = "Branch Mispredicted",
462 .se_cmp = sort__mispredict_cmp, 768 .se_cmp = sort__mispredict_cmp,
@@ -464,6 +770,91 @@ struct sort_entry sort_mispredict = {
464 .se_width_idx = HISTC_MISPREDICT, 770 .se_width_idx = HISTC_MISPREDICT,
465}; 771};
466 772
773static u64 he_weight(struct hist_entry *he)
774{
775 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
776}
777
778static int64_t
779sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
780{
781 return he_weight(left) - he_weight(right);
782}
783
784static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
785 size_t size, unsigned int width)
786{
787 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
788}
789
790struct sort_entry sort_local_weight = {
791 .se_header = "Local Weight",
792 .se_cmp = sort__local_weight_cmp,
793 .se_snprintf = hist_entry__local_weight_snprintf,
794 .se_width_idx = HISTC_LOCAL_WEIGHT,
795};
796
797static int64_t
798sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
799{
800 return left->stat.weight - right->stat.weight;
801}
802
803static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
804 size_t size, unsigned int width)
805{
806 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
807}
808
809struct sort_entry sort_global_weight = {
810 .se_header = "Weight",
811 .se_cmp = sort__global_weight_cmp,
812 .se_snprintf = hist_entry__global_weight_snprintf,
813 .se_width_idx = HISTC_GLOBAL_WEIGHT,
814};
815
816struct sort_entry sort_mem_daddr_sym = {
817 .se_header = "Data Symbol",
818 .se_cmp = sort__daddr_cmp,
819 .se_snprintf = hist_entry__daddr_snprintf,
820 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
821};
822
823struct sort_entry sort_mem_daddr_dso = {
824 .se_header = "Data Object",
825 .se_cmp = sort__dso_daddr_cmp,
826 .se_snprintf = hist_entry__dso_daddr_snprintf,
827 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
828};
829
830struct sort_entry sort_mem_locked = {
831 .se_header = "Locked",
832 .se_cmp = sort__locked_cmp,
833 .se_snprintf = hist_entry__locked_snprintf,
834 .se_width_idx = HISTC_MEM_LOCKED,
835};
836
837struct sort_entry sort_mem_tlb = {
838 .se_header = "TLB access",
839 .se_cmp = sort__tlb_cmp,
840 .se_snprintf = hist_entry__tlb_snprintf,
841 .se_width_idx = HISTC_MEM_TLB,
842};
843
844struct sort_entry sort_mem_lvl = {
845 .se_header = "Memory access",
846 .se_cmp = sort__lvl_cmp,
847 .se_snprintf = hist_entry__lvl_snprintf,
848 .se_width_idx = HISTC_MEM_LVL,
849};
850
851struct sort_entry sort_mem_snoop = {
852 .se_header = "Snoop",
853 .se_cmp = sort__snoop_cmp,
854 .se_snprintf = hist_entry__snoop_snprintf,
855 .se_width_idx = HISTC_MEM_SNOOP,
856};
857
467struct sort_dimension { 858struct sort_dimension {
468 const char *name; 859 const char *name;
469 struct sort_entry *entry; 860 struct sort_entry *entry;
@@ -480,6 +871,14 @@ static struct sort_dimension common_sort_dimensions[] = {
480 DIM(SORT_PARENT, "parent", sort_parent), 871 DIM(SORT_PARENT, "parent", sort_parent),
481 DIM(SORT_CPU, "cpu", sort_cpu), 872 DIM(SORT_CPU, "cpu", sort_cpu),
482 DIM(SORT_SRCLINE, "srcline", sort_srcline), 873 DIM(SORT_SRCLINE, "srcline", sort_srcline),
874 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
875 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
876 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
877 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
878 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
879 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
880 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
881 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
483}; 882};
484 883
485#undef DIM 884#undef DIM
@@ -516,7 +915,10 @@ int sort_dimension__add(const char *tok)
516 return -EINVAL; 915 return -EINVAL;
517 } 916 }
518 sort__has_parent = 1; 917 sort__has_parent = 1;
519 } else if (sd->entry == &sort_sym) { 918 } else if (sd->entry == &sort_sym ||
919 sd->entry == &sort_sym_from ||
920 sd->entry == &sort_sym_to ||
921 sd->entry == &sort_mem_daddr_sym) {
520 sort__has_sym = 1; 922 sort__has_sym = 1;
521 } 923 }
522 924
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b13e56f6ccbe..f24bdf64238c 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,6 +49,7 @@ struct he_stat {
49 u64 period_us; 49 u64 period_us;
50 u64 period_guest_sys; 50 u64 period_guest_sys;
51 u64 period_guest_us; 51 u64 period_guest_us;
52 u64 weight;
52 u32 nr_events; 53 u32 nr_events;
53}; 54};
54 55
@@ -100,7 +101,8 @@ struct hist_entry {
100 struct rb_root sorted_chain; 101 struct rb_root sorted_chain;
101 struct branch_info *branch_info; 102 struct branch_info *branch_info;
102 struct hists *hists; 103 struct hists *hists;
103 struct callchain_root callchain[0]; 104 struct mem_info *mem_info;
105 struct callchain_root callchain[0]; /* must be last member */
104}; 106};
105 107
106static inline bool hist_entry__has_pairs(struct hist_entry *he) 108static inline bool hist_entry__has_pairs(struct hist_entry *he)
@@ -130,6 +132,14 @@ enum sort_type {
130 SORT_PARENT, 132 SORT_PARENT,
131 SORT_CPU, 133 SORT_CPU,
132 SORT_SRCLINE, 134 SORT_SRCLINE,
135 SORT_LOCAL_WEIGHT,
136 SORT_GLOBAL_WEIGHT,
137 SORT_MEM_DADDR_SYMBOL,
138 SORT_MEM_DADDR_DSO,
139 SORT_MEM_LOCKED,
140 SORT_MEM_TLB,
141 SORT_MEM_LVL,
142 SORT_MEM_SNOOP,
133 143
134 /* branch stack specific sort keys */ 144 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK, 145 __SORT_BRANCH_STACK,
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 54efcb5659ac..4b12bf850325 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -806,9 +806,12 @@ int dso__load_sym(struct dso *dso, struct map *map,
806 * DWARF DW_compile_unit has this, but we don't always have access 806 * DWARF DW_compile_unit has this, but we don't always have access
807 * to it... 807 * to it...
808 */ 808 */
809 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 809 if (symbol_conf.demangle) {
810 if (demangled != NULL) 810 demangled = bfd_demangle(NULL, elf_name,
811 elf_name = demangled; 811 DMGL_PARAMS | DMGL_ANSI);
812 if (demangled != NULL)
813 elf_name = demangled;
814 }
812new_symbol: 815new_symbol:
813 f = symbol__new(sym.st_value, sym.st_size, 816 f = symbol__new(sym.st_value, sym.st_size,
814 GELF_ST_BIND(sym.st_info), elf_name); 817 GELF_ST_BIND(sym.st_info), elf_name);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e6432d85b43d..8cf3b5426a9a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -36,6 +36,7 @@ struct symbol_conf symbol_conf = {
36 .use_modules = true, 36 .use_modules = true,
37 .try_vmlinux_path = true, 37 .try_vmlinux_path = true,
38 .annotate_src = true, 38 .annotate_src = true,
39 .demangle = true,
39 .symfs = "", 40 .symfs = "",
40}; 41};
41 42
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b62ca37c4b77..5f720dc076da 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -97,7 +97,8 @@ struct symbol_conf {
97 kptr_restrict, 97 kptr_restrict,
98 annotate_asm_raw, 98 annotate_asm_raw,
99 annotate_src, 99 annotate_src,
100 event_group; 100 event_group,
101 demangle;
101 const char *vmlinux_name, 102 const char *vmlinux_name,
102 *kallsyms_name, 103 *kallsyms_name,
103 *source_prefix, 104 *source_prefix,
@@ -155,6 +156,12 @@ struct branch_info {
155 struct branch_flags flags; 156 struct branch_flags flags;
156}; 157};
157 158
159struct mem_info {
160 struct addr_map_symbol iaddr;
161 struct addr_map_symbol daddr;
162 union perf_mem_data_src data_src;
163};
164
158struct addr_location { 165struct addr_location {
159 struct thread *thread; 166 struct thread *thread;
160 struct map *map; 167 struct map *map;
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..3917eb9a8479 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,52 +38,20 @@
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";
56static int output_fd; 46static int output_fd;
57 47
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
71static void *malloc_or_die(unsigned int size)
72{
73 void *data;
74
75 data = malloc(size);
76 if (!data)
77 die("malloc");
78 return data;
79}
80 48
81static const char *find_debugfs(void) 49static const char *find_debugfs(void)
82{ 50{
83 const char *path = debugfs_mount(NULL); 51 const char *path = perf_debugfs_mount(NULL);
84 52
85 if (!path) 53 if (!path)
86 die("Your kernel not support debugfs filesystem"); 54 pr_debug("Your kernel does not support the debugfs filesystem");
87 55
88 return path; 56 return path;
89} 57}
@@ -102,8 +70,12 @@ static const char *find_tracing_dir(void)
102 return tracing; 70 return tracing;
103 71
104 debugfs = find_debugfs(); 72 debugfs = find_debugfs();
73 if (!debugfs)
74 return NULL;
105 75
106 tracing = malloc_or_die(strlen(debugfs) + 9); 76 tracing = malloc(strlen(debugfs) + 9);
77 if (!tracing)
78 return NULL;
107 79
108 sprintf(tracing, "%s/tracing", debugfs); 80 sprintf(tracing, "%s/tracing", debugfs);
109 81
@@ -120,7 +92,9 @@ static char *get_tracing_file(const char *name)
120 if (!tracing) 92 if (!tracing)
121 return NULL; 93 return NULL;
122 94
123 file = malloc_or_die(strlen(tracing) + strlen(name) + 2); 95 file = malloc(strlen(tracing) + strlen(name) + 2);
96 if (!file)
97 return NULL;
124 98
125 sprintf(file, "%s/%s", tracing, name); 99 sprintf(file, "%s/%s", tracing, name);
126 return file; 100 return file;
@@ -131,24 +105,6 @@ static void put_tracing_file(char *file)
131 free(file); 105 free(file);
132} 106}
133 107
134static ssize_t calc_data_size;
135
136static ssize_t write_or_die(const void *buf, size_t len)
137{
138 int ret;
139
140 if (calc_data_size) {
141 calc_data_size += len;
142 return len;
143 }
144
145 ret = write(output_fd, buf, len);
146 if (ret < 0)
147 die("writing to '%s'", output_file);
148
149 return ret;
150}
151
152int bigendian(void) 108int bigendian(void)
153{ 109{
154 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 110 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -159,59 +115,106 @@ int bigendian(void)
159} 115}
160 116
161/* unfortunately, you can not stat debugfs or proc files for size */ 117/* unfortunately, you can not stat debugfs or proc files for size */
162static void record_file(const char *file, size_t hdr_sz) 118static int record_file(const char *file, ssize_t hdr_sz)
163{ 119{
164 unsigned long long size = 0; 120 unsigned long long size = 0;
165 char buf[BUFSIZ], *sizep; 121 char buf[BUFSIZ], *sizep;
166 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); 122 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
167 int r, fd; 123 int r, fd;
124 int err = -EIO;
168 125
169 fd = open(file, O_RDONLY); 126 fd = open(file, O_RDONLY);
170 if (fd < 0) 127 if (fd < 0) {
171 die("Can't read '%s'", file); 128 pr_debug("Can't read '%s'", file);
129 return -errno;
130 }
172 131
173 /* put in zeros for file size, then fill true size later */ 132 /* put in zeros for file size, then fill true size later */
174 if (hdr_sz) 133 if (hdr_sz) {
175 write_or_die(&size, hdr_sz); 134 if (write(output_fd, &size, hdr_sz) != hdr_sz)
135 goto out;
136 }
176 137
177 do { 138 do {
178 r = read(fd, buf, BUFSIZ); 139 r = read(fd, buf, BUFSIZ);
179 if (r > 0) { 140 if (r > 0) {
180 size += r; 141 size += r;
181 write_or_die(buf, r); 142 if (write(output_fd, buf, r) != r)
143 goto out;
182 } 144 }
183 } while (r > 0); 145 } while (r > 0);
184 close(fd);
185 146
186 /* ugh, handle big-endian hdr_size == 4 */ 147 /* ugh, handle big-endian hdr_size == 4 */
187 sizep = (char*)&size; 148 sizep = (char*)&size;
188 if (bigendian()) 149 if (bigendian())
189 sizep += sizeof(u64) - hdr_sz; 150 sizep += sizeof(u64) - hdr_sz;
190 151
191 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 152 if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
192 die("writing to %s", output_file); 153 pr_debug("writing file size failed\n");
154 goto out;
155 }
156
157 err = 0;
158out:
159 close(fd);
160 return err;
193} 161}
194 162
195static void read_header_files(void) 163static int read_header_files(void)
196{ 164{
197 char *path; 165 char *path;
198 struct stat st; 166 struct stat st;
167 int err = -EIO;
199 168
200 path = get_tracing_file("events/header_page"); 169 path = get_tracing_file("events/header_page");
201 if (stat(path, &st) < 0) 170 if (!path) {
202 die("can't read '%s'", path); 171 pr_debug("can't get tracing/events/header_page");
172 return -ENOMEM;
173 }
174
175 if (stat(path, &st) < 0) {
176 pr_debug("can't read '%s'", path);
177 goto out;
178 }
179
180 if (write(output_fd, "header_page", 12) != 12) {
181 pr_debug("can't write header_page\n");
182 goto out;
183 }
184
185 if (record_file(path, 8) < 0) {
186 pr_debug("can't record header_page file\n");
187 goto out;
188 }
203 189
204 write_or_die("header_page", 12);
205 record_file(path, 8);
206 put_tracing_file(path); 190 put_tracing_file(path);
207 191
208 path = get_tracing_file("events/header_event"); 192 path = get_tracing_file("events/header_event");
209 if (stat(path, &st) < 0) 193 if (!path) {
210 die("can't read '%s'", path); 194 pr_debug("can't get tracing/events/header_event");
195 err = -ENOMEM;
196 goto out;
197 }
198
199 if (stat(path, &st) < 0) {
200 pr_debug("can't read '%s'", path);
201 goto out;
202 }
211 203
212 write_or_die("header_event", 13); 204 if (write(output_fd, "header_event", 13) != 13) {
213 record_file(path, 8); 205 pr_debug("can't write header_event\n");
206 goto out;
207 }
208
209 if (record_file(path, 8) < 0) {
210 pr_debug("can't record header_event file\n");
211 goto out;
212 }
213
214 err = 0;
215out:
214 put_tracing_file(path); 216 put_tracing_file(path);
217 return err;
215} 218}
216 219
217static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 220static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -225,7 +228,7 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
225 return false; 228 return false;
226} 229}
227 230
228static void copy_event_system(const char *sys, struct tracepoint_path *tps) 231static int copy_event_system(const char *sys, struct tracepoint_path *tps)
229{ 232{
230 struct dirent *dent; 233 struct dirent *dent;
231 struct stat st; 234 struct stat st;
@@ -233,10 +236,13 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
233 DIR *dir; 236 DIR *dir;
234 int count = 0; 237 int count = 0;
235 int ret; 238 int ret;
239 int err;
236 240
237 dir = opendir(sys); 241 dir = opendir(sys);
238 if (!dir) 242 if (!dir) {
239 die("can't read directory '%s'", sys); 243 pr_debug("can't read directory '%s'", sys);
244 return -errno;
245 }
240 246
241 while ((dent = readdir(dir))) { 247 while ((dent = readdir(dir))) {
242 if (dent->d_type != DT_DIR || 248 if (dent->d_type != DT_DIR ||
@@ -244,7 +250,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
244 strcmp(dent->d_name, "..") == 0 || 250 strcmp(dent->d_name, "..") == 0 ||
245 !name_in_tp_list(dent->d_name, tps)) 251 !name_in_tp_list(dent->d_name, tps))
246 continue; 252 continue;
247 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 253 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
254 if (!format) {
255 err = -ENOMEM;
256 goto out;
257 }
248 sprintf(format, "%s/%s/format", sys, dent->d_name); 258 sprintf(format, "%s/%s/format", sys, dent->d_name);
249 ret = stat(format, &st); 259 ret = stat(format, &st);
250 free(format); 260 free(format);
@@ -253,7 +263,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
253 count++; 263 count++;
254 } 264 }
255 265
256 write_or_die(&count, 4); 266 if (write(output_fd, &count, 4) != 4) {
267 err = -EIO;
268 pr_debug("can't write count\n");
269 goto out;
270 }
257 271
258 rewinddir(dir); 272 rewinddir(dir);
259 while ((dent = readdir(dir))) { 273 while ((dent = readdir(dir))) {
@@ -262,27 +276,45 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
262 strcmp(dent->d_name, "..") == 0 || 276 strcmp(dent->d_name, "..") == 0 ||
263 !name_in_tp_list(dent->d_name, tps)) 277 !name_in_tp_list(dent->d_name, tps))
264 continue; 278 continue;
265 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 279 format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
280 if (!format) {
281 err = -ENOMEM;
282 goto out;
283 }
266 sprintf(format, "%s/%s/format", sys, dent->d_name); 284 sprintf(format, "%s/%s/format", sys, dent->d_name);
267 ret = stat(format, &st); 285 ret = stat(format, &st);
268 286
269 if (ret >= 0) 287 if (ret >= 0) {
270 record_file(format, 8); 288 err = record_file(format, 8);
271 289 if (err) {
290 free(format);
291 goto out;
292 }
293 }
272 free(format); 294 free(format);
273 } 295 }
296 err = 0;
297out:
274 closedir(dir); 298 closedir(dir);
299 return err;
275} 300}
276 301
277static void read_ftrace_files(struct tracepoint_path *tps) 302static int read_ftrace_files(struct tracepoint_path *tps)
278{ 303{
279 char *path; 304 char *path;
305 int ret;
280 306
281 path = get_tracing_file("events/ftrace"); 307 path = get_tracing_file("events/ftrace");
308 if (!path) {
309 pr_debug("can't get tracing/events/ftrace");
310 return -ENOMEM;
311 }
282 312
283 copy_event_system(path, tps); 313 ret = copy_event_system(path, tps);
284 314
285 put_tracing_file(path); 315 put_tracing_file(path);
316
317 return ret;
286} 318}
287 319
288static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 320static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -296,7 +328,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
296 return false; 328 return false;
297} 329}
298 330
299static void read_event_files(struct tracepoint_path *tps) 331static int read_event_files(struct tracepoint_path *tps)
300{ 332{
301 struct dirent *dent; 333 struct dirent *dent;
302 struct stat st; 334 struct stat st;
@@ -305,12 +337,20 @@ static void read_event_files(struct tracepoint_path *tps)
305 DIR *dir; 337 DIR *dir;
306 int count = 0; 338 int count = 0;
307 int ret; 339 int ret;
340 int err;
308 341
309 path = get_tracing_file("events"); 342 path = get_tracing_file("events");
343 if (!path) {
344 pr_debug("can't get tracing/events");
345 return -ENOMEM;
346 }
310 347
311 dir = opendir(path); 348 dir = opendir(path);
312 if (!dir) 349 if (!dir) {
313 die("can't read directory '%s'", path); 350 err = -errno;
351 pr_debug("can't read directory '%s'", path);
352 goto out;
353 }
314 354
315 while ((dent = readdir(dir))) { 355 while ((dent = readdir(dir))) {
316 if (dent->d_type != DT_DIR || 356 if (dent->d_type != DT_DIR ||
@@ -322,7 +362,11 @@ static void read_event_files(struct tracepoint_path *tps)
322 count++; 362 count++;
323 } 363 }
324 364
325 write_or_die(&count, 4); 365 if (write(output_fd, &count, 4) != 4) {
366 err = -EIO;
367 pr_debug("can't write count\n");
368 goto out;
369 }
326 370
327 rewinddir(dir); 371 rewinddir(dir);
328 while ((dent = readdir(dir))) { 372 while ((dent = readdir(dir))) {
@@ -332,56 +376,90 @@ static void read_event_files(struct tracepoint_path *tps)
332 strcmp(dent->d_name, "ftrace") == 0 || 376 strcmp(dent->d_name, "ftrace") == 0 ||
333 !system_in_tp_list(dent->d_name, tps)) 377 !system_in_tp_list(dent->d_name, tps))
334 continue; 378 continue;
335 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 379 sys = malloc(strlen(path) + strlen(dent->d_name) + 2);
380 if (!sys) {
381 err = -ENOMEM;
382 goto out;
383 }
336 sprintf(sys, "%s/%s", path, dent->d_name); 384 sprintf(sys, "%s/%s", path, dent->d_name);
337 ret = stat(sys, &st); 385 ret = stat(sys, &st);
338 if (ret >= 0) { 386 if (ret >= 0) {
339 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 387 ssize_t size = strlen(dent->d_name) + 1;
340 copy_event_system(sys, tps); 388
389 if (write(output_fd, dent->d_name, size) != size ||
390 copy_event_system(sys, tps) < 0) {
391 err = -EIO;
392 free(sys);
393 goto out;
394 }
341 } 395 }
342 free(sys); 396 free(sys);
343 } 397 }
344 398 err = 0;
399out:
345 closedir(dir); 400 closedir(dir);
346 put_tracing_file(path); 401 put_tracing_file(path);
402
403 return err;
347} 404}
348 405
349static void read_proc_kallsyms(void) 406static int read_proc_kallsyms(void)
350{ 407{
351 unsigned int size; 408 unsigned int size;
352 const char *path = "/proc/kallsyms"; 409 const char *path = "/proc/kallsyms";
353 struct stat st; 410 struct stat st;
354 int ret; 411 int ret, err = 0;
355 412
356 ret = stat(path, &st); 413 ret = stat(path, &st);
357 if (ret < 0) { 414 if (ret < 0) {
358 /* not found */ 415 /* not found */
359 size = 0; 416 size = 0;
360 write_or_die(&size, 4); 417 if (write(output_fd, &size, 4) != 4)
361 return; 418 err = -EIO;
419 return err;
362 } 420 }
363 record_file(path, 4); 421 return record_file(path, 4);
364} 422}
365 423
366static void read_ftrace_printk(void) 424static int read_ftrace_printk(void)
367{ 425{
368 unsigned int size; 426 unsigned int size;
369 char *path; 427 char *path;
370 struct stat st; 428 struct stat st;
371 int ret; 429 int ret, err = 0;
372 430
373 path = get_tracing_file("printk_formats"); 431 path = get_tracing_file("printk_formats");
432 if (!path) {
433 pr_debug("can't get tracing/printk_formats");
434 return -ENOMEM;
435 }
436
374 ret = stat(path, &st); 437 ret = stat(path, &st);
375 if (ret < 0) { 438 if (ret < 0) {
376 /* not found */ 439 /* not found */
377 size = 0; 440 size = 0;
378 write_or_die(&size, 4); 441 if (write(output_fd, &size, 4) != 4)
442 err = -EIO;
379 goto out; 443 goto out;
380 } 444 }
381 record_file(path, 4); 445 err = record_file(path, 4);
382 446
383out: 447out:
384 put_tracing_file(path); 448 put_tracing_file(path);
449 return err;
450}
451
452static void
453put_tracepoints_path(struct tracepoint_path *tps)
454{
455 while (tps) {
456 struct tracepoint_path *t = tps;
457
458 tps = tps->next;
459 free(t->name);
460 free(t->system);
461 free(t);
462 }
385} 463}
386 464
387static struct tracepoint_path * 465static struct tracepoint_path *
@@ -396,27 +474,17 @@ get_tracepoints_path(struct list_head *pattrs)
396 continue; 474 continue;
397 ++nr_tracepoints; 475 ++nr_tracepoints;
398 ppath->next = tracepoint_id_to_path(pos->attr.config); 476 ppath->next = tracepoint_id_to_path(pos->attr.config);
399 if (!ppath->next) 477 if (!ppath->next) {
400 die("%s\n", "No memory to alloc tracepoints list"); 478 pr_debug("No memory to alloc tracepoints list\n");
479 put_tracepoints_path(&path);
480 return NULL;
481 }
401 ppath = ppath->next; 482 ppath = ppath->next;
402 } 483 }
403 484
404 return nr_tracepoints > 0 ? path.next : NULL; 485 return nr_tracepoints > 0 ? path.next : NULL;
405} 486}
406 487
407static void
408put_tracepoints_path(struct tracepoint_path *tps)
409{
410 while (tps) {
411 struct tracepoint_path *t = tps;
412
413 tps = tps->next;
414 free(t->name);
415 free(t->system);
416 free(t);
417 }
418}
419
420bool have_tracepoints(struct list_head *pattrs) 488bool have_tracepoints(struct list_head *pattrs)
421{ 489{
422 struct perf_evsel *pos; 490 struct perf_evsel *pos;
@@ -428,9 +496,10 @@ bool have_tracepoints(struct list_head *pattrs)
428 return false; 496 return false;
429} 497}
430 498
431static void tracing_data_header(void) 499static int tracing_data_header(void)
432{ 500{
433 char buf[20]; 501 char buf[20];
502 ssize_t size;
434 503
435 /* just guessing this is someone's birthday.. ;) */ 504 /* just guessing this is someone's birthday.. ;) */
436 buf[0] = 23; 505 buf[0] = 23;
@@ -438,9 +507,12 @@ static void tracing_data_header(void)
438 buf[2] = 68; 507 buf[2] = 68;
439 memcpy(buf + 3, "tracing", 7); 508 memcpy(buf + 3, "tracing", 7);
440 509
441 write_or_die(buf, 10); 510 if (write(output_fd, buf, 10) != 10)
511 return -1;
442 512
443 write_or_die(VERSION, strlen(VERSION) + 1); 513 size = strlen(VERSION) + 1;
514 if (write(output_fd, VERSION, size) != size)
515 return -1;
444 516
445 /* save endian */ 517 /* save endian */
446 if (bigendian()) 518 if (bigendian())
@@ -450,15 +522,19 @@ static void tracing_data_header(void)
450 522
451 read_trace_init(buf[0], buf[0]); 523 read_trace_init(buf[0], buf[0]);
452 524
453 write_or_die(buf, 1); 525 if (write(output_fd, buf, 1) != 1)
526 return -1;
454 527
455 /* save size of long */ 528 /* save size of long */
456 buf[0] = sizeof(long); 529 buf[0] = sizeof(long);
457 write_or_die(buf, 1); 530 if (write(output_fd, buf, 1) != 1)
531 return -1;
458 532
459 /* save page_size */ 533 /* save page_size */
460 page_size = sysconf(_SC_PAGESIZE); 534 if (write(output_fd, &page_size, 4) != 4)
461 write_or_die(&page_size, 4); 535 return -1;
536
537 return 0;
462} 538}
463 539
464struct tracing_data *tracing_data_get(struct list_head *pattrs, 540struct tracing_data *tracing_data_get(struct list_head *pattrs,
@@ -466,6 +542,7 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
466{ 542{
467 struct tracepoint_path *tps; 543 struct tracepoint_path *tps;
468 struct tracing_data *tdata; 544 struct tracing_data *tdata;
545 int err;
469 546
470 output_fd = fd; 547 output_fd = fd;
471 548
@@ -473,7 +550,10 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
473 if (!tps) 550 if (!tps)
474 return NULL; 551 return NULL;
475 552
476 tdata = malloc_or_die(sizeof(*tdata)); 553 tdata = malloc(sizeof(*tdata));
554 if (!tdata)
555 return NULL;
556
477 tdata->temp = temp; 557 tdata->temp = temp;
478 tdata->size = 0; 558 tdata->size = 0;
479 559
@@ -482,12 +562,16 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
482 562
483 snprintf(tdata->temp_file, sizeof(tdata->temp_file), 563 snprintf(tdata->temp_file, sizeof(tdata->temp_file),
484 "/tmp/perf-XXXXXX"); 564 "/tmp/perf-XXXXXX");
485 if (!mkstemp(tdata->temp_file)) 565 if (!mkstemp(tdata->temp_file)) {
486 die("Can't make temp file"); 566 pr_debug("Can't make temp file");
567 return NULL;
568 }
487 569
488 temp_fd = open(tdata->temp_file, O_RDWR); 570 temp_fd = open(tdata->temp_file, O_RDWR);
489 if (temp_fd < 0) 571 if (temp_fd < 0) {
490 die("Can't read '%s'", tdata->temp_file); 572 pr_debug("Can't read '%s'", tdata->temp_file);
573 return NULL;
574 }
491 575
492 /* 576 /*
493 * Set the temp file the default output, so all the 577 * Set the temp file the default output, so all the
@@ -496,13 +580,24 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
496 output_fd = temp_fd; 580 output_fd = temp_fd;
497 } 581 }
498 582
499 tracing_data_header(); 583 err = tracing_data_header();
500 read_header_files(); 584 if (err)
501 read_ftrace_files(tps); 585 goto out;
502 read_event_files(tps); 586 err = read_header_files();
503 read_proc_kallsyms(); 587 if (err)
504 read_ftrace_printk(); 588 goto out;
589 err = read_ftrace_files(tps);
590 if (err)
591 goto out;
592 err = read_event_files(tps);
593 if (err)
594 goto out;
595 err = read_proc_kallsyms();
596 if (err)
597 goto out;
598 err = read_ftrace_printk();
505 599
600out:
506 /* 601 /*
507 * All tracing data are stored by now, we can restore 602 * All tracing data are stored by now, we can restore
508 * the default output file in case we used temp file. 603 * the default output file in case we used temp file.
@@ -513,22 +608,31 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
513 output_fd = fd; 608 output_fd = fd;
514 } 609 }
515 610
611 if (err) {
612 free(tdata);
613 tdata = NULL;
614 }
615
516 put_tracepoints_path(tps); 616 put_tracepoints_path(tps);
517 return tdata; 617 return tdata;
518} 618}
519 619
520void tracing_data_put(struct tracing_data *tdata) 620int tracing_data_put(struct tracing_data *tdata)
521{ 621{
622 int err = 0;
623
522 if (tdata->temp) { 624 if (tdata->temp) {
523 record_file(tdata->temp_file, 0); 625 err = record_file(tdata->temp_file, 0);
524 unlink(tdata->temp_file); 626 unlink(tdata->temp_file);
525 } 627 }
526 628
527 free(tdata); 629 free(tdata);
630 return err;
528} 631}
529 632
530int read_tracing_data(int fd, struct list_head *pattrs) 633int read_tracing_data(int fd, struct list_head *pattrs)
531{ 634{
635 int err;
532 struct tracing_data *tdata; 636 struct tracing_data *tdata;
533 637
534 /* 638 /*
@@ -539,6 +643,6 @@ int read_tracing_data(int fd, struct list_head *pattrs)
539 if (!tdata) 643 if (!tdata)
540 return -ENOMEM; 644 return -ENOMEM;
541 645
542 tracing_data_put(tdata); 646 err = tracing_data_put(tdata);
543 return 0; 647 return err;
544} 648}
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..af215c0d2379 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,8 +18,6 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _FILE_OFFSET_BITS 64
22
23#include <dirent.h> 21#include <dirent.h>
24#include <stdio.h> 22#include <stdio.h>
25#include <stdlib.h> 23#include <stdlib.h>
@@ -41,26 +39,14 @@
41 39
42static int input_fd; 40static int input_fd;
43 41
44static int read_page;
45
46int file_bigendian; 42int file_bigendian;
47int host_bigendian; 43int host_bigendian;
48static int long_size; 44static int long_size;
49 45
50static ssize_t calc_data_size; 46static ssize_t trace_data_size;
51static bool repipe; 47static bool repipe;
52 48
53static void *malloc_or_die(int size) 49static int __do_read(int fd, void *buf, int size)
54{
55 void *ret;
56
57 ret = malloc(size);
58 if (!ret)
59 die("malloc");
60 return ret;
61}
62
63static int do_read(int fd, void *buf, int size)
64{ 50{
65 int rsize = size; 51 int rsize = size;
66 52
@@ -73,8 +59,10 @@ static int do_read(int fd, void *buf, int size)
73 if (repipe) { 59 if (repipe) {
74 int retw = write(STDOUT_FILENO, buf, ret); 60 int retw = write(STDOUT_FILENO, buf, ret);
75 61
76 if (retw <= 0 || retw != ret) 62 if (retw <= 0 || retw != ret) {
77 die("repiping input file"); 63 pr_debug("repiping input file");
64 return -1;
65 }
78 } 66 }
79 67
80 size -= ret; 68 size -= ret;
@@ -84,17 +72,18 @@ static int do_read(int fd, void *buf, int size)
84 return rsize; 72 return rsize;
85} 73}
86 74
87static int read_or_die(void *data, int size) 75static int do_read(void *data, int size)
88{ 76{
89 int r; 77 int r;
90 78
91 r = do_read(input_fd, data, size); 79 r = __do_read(input_fd, data, size);
92 if (r <= 0) 80 if (r <= 0) {
93 die("reading input file (size expected=%d received=%d)", 81 pr_debug("reading input file (size expected=%d received=%d)",
94 size, r); 82 size, r);
83 return -1;
84 }
95 85
96 if (calc_data_size) 86 trace_data_size += r;
97 calc_data_size += r;
98 87
99 return r; 88 return r;
100} 89}
@@ -107,7 +96,7 @@ static void skip(int size)
107 96
108 while (size) { 97 while (size) {
109 r = size > BUFSIZ ? BUFSIZ : size; 98 r = size > BUFSIZ ? BUFSIZ : size;
110 read_or_die(buf, r); 99 do_read(buf, r);
111 size -= r; 100 size -= r;
112 }; 101 };
113} 102}
@@ -116,7 +105,8 @@ static unsigned int read4(struct pevent *pevent)
116{ 105{
117 unsigned int data; 106 unsigned int data;
118 107
119 read_or_die(&data, 4); 108 if (do_read(&data, 4) < 0)
109 return 0;
120 return __data2host4(pevent, data); 110 return __data2host4(pevent, data);
121} 111}
122 112
@@ -124,7 +114,8 @@ static unsigned long long read8(struct pevent *pevent)
124{ 114{
125 unsigned long long data; 115 unsigned long long data;
126 116
127 read_or_die(&data, 8); 117 if (do_read(&data, 8) < 0)
118 return 0;
128 return __data2host8(pevent, data); 119 return __data2host8(pevent, data);
129} 120}
130 121
@@ -138,17 +129,23 @@ static char *read_string(void)
138 129
139 for (;;) { 130 for (;;) {
140 r = read(input_fd, &c, 1); 131 r = read(input_fd, &c, 1);
141 if (r < 0) 132 if (r < 0) {
142 die("reading input file"); 133 pr_debug("reading input file");
134 goto out;
135 }
143 136
144 if (!r) 137 if (!r) {
145 die("no data"); 138 pr_debug("no data");
139 goto out;
140 }
146 141
147 if (repipe) { 142 if (repipe) {
148 int retw = write(STDOUT_FILENO, &c, 1); 143 int retw = write(STDOUT_FILENO, &c, 1);
149 144
150 if (retw <= 0 || retw != r) 145 if (retw <= 0 || retw != r) {
151 die("repiping input file string"); 146 pr_debug("repiping input file string");
147 goto out;
148 }
152 } 149 }
153 150
154 buf[size++] = c; 151 buf[size++] = c;
@@ -157,60 +154,79 @@ static char *read_string(void)
157 break; 154 break;
158 } 155 }
159 156
160 if (calc_data_size) 157 trace_data_size += size;
161 calc_data_size += size;
162
163 str = malloc_or_die(size);
164 memcpy(str, buf, size);
165 158
159 str = malloc(size);
160 if (str)
161 memcpy(str, buf, size);
162out:
166 return str; 163 return str;
167} 164}
168 165
169static void read_proc_kallsyms(struct pevent *pevent) 166static int read_proc_kallsyms(struct pevent *pevent)
170{ 167{
171 unsigned int size; 168 unsigned int size;
172 char *buf; 169 char *buf;
173 170
174 size = read4(pevent); 171 size = read4(pevent);
175 if (!size) 172 if (!size)
176 return; 173 return 0;
174
175 buf = malloc(size + 1);
176 if (buf == NULL)
177 return -1;
177 178
178 buf = malloc_or_die(size + 1); 179 if (do_read(buf, size) < 0) {
179 read_or_die(buf, size); 180 free(buf);
181 return -1;
182 }
180 buf[size] = '\0'; 183 buf[size] = '\0';
181 184
182 parse_proc_kallsyms(pevent, buf, size); 185 parse_proc_kallsyms(pevent, buf, size);
183 186
184 free(buf); 187 free(buf);
188 return 0;
185} 189}
186 190
187static void read_ftrace_printk(struct pevent *pevent) 191static int read_ftrace_printk(struct pevent *pevent)
188{ 192{
189 unsigned int size; 193 unsigned int size;
190 char *buf; 194 char *buf;
191 195
196 /* it can have 0 size */
192 size = read4(pevent); 197 size = read4(pevent);
193 if (!size) 198 if (!size)
194 return; 199 return 0;
200
201 buf = malloc(size);
202 if (buf == NULL)
203 return -1;
195 204
196 buf = malloc_or_die(size); 205 if (do_read(buf, size) < 0) {
197 read_or_die(buf, size); 206 free(buf);
207 return -1;
208 }
198 209
199 parse_ftrace_printk(pevent, buf, size); 210 parse_ftrace_printk(pevent, buf, size);
200 211
201 free(buf); 212 free(buf);
213 return 0;
202} 214}
203 215
204static void read_header_files(struct pevent *pevent) 216static int read_header_files(struct pevent *pevent)
205{ 217{
206 unsigned long long size; 218 unsigned long long size;
207 char *header_event; 219 char *header_event;
208 char buf[BUFSIZ]; 220 char buf[BUFSIZ];
221 int ret = 0;
209 222
210 read_or_die(buf, 12); 223 if (do_read(buf, 12) < 0)
224 return -1;
211 225
212 if (memcmp(buf, "header_page", 12) != 0) 226 if (memcmp(buf, "header_page", 12) != 0) {
213 die("did not read header page"); 227 pr_debug("did not read header page");
228 return -1;
229 }
214 230
215 size = read8(pevent); 231 size = read8(pevent);
216 skip(size); 232 skip(size);
@@ -221,269 +237,107 @@ static void read_header_files(struct pevent *pevent)
221 */ 237 */
222 long_size = header_page_size_size; 238 long_size = header_page_size_size;
223 239
224 read_or_die(buf, 13); 240 if (do_read(buf, 13) < 0)
225 if (memcmp(buf, "header_event", 13) != 0) 241 return -1;
226 die("did not read header event"); 242
243 if (memcmp(buf, "header_event", 13) != 0) {
244 pr_debug("did not read header event");
245 return -1;
246 }
227 247
228 size = read8(pevent); 248 size = read8(pevent);
229 header_event = malloc_or_die(size); 249 header_event = malloc(size);
230 read_or_die(header_event, size); 250 if (header_event == NULL)
251 return -1;
252
253 if (do_read(header_event, size) < 0)
254 ret = -1;
255
231 free(header_event); 256 free(header_event);
257 return ret;
232} 258}
233 259
234static void read_ftrace_file(struct pevent *pevent, unsigned long long size) 260static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
235{ 261{
236 char *buf; 262 char *buf;
237 263
238 buf = malloc_or_die(size); 264 buf = malloc(size);
239 read_or_die(buf, size); 265 if (buf == NULL)
266 return -1;
267
268 if (do_read(buf, size) < 0) {
269 free(buf);
270 return -1;
271 }
272
240 parse_ftrace_file(pevent, buf, size); 273 parse_ftrace_file(pevent, buf, size);
241 free(buf); 274 free(buf);
275 return 0;
242} 276}
243 277
244static void read_event_file(struct pevent *pevent, char *sys, 278static int read_event_file(struct pevent *pevent, char *sys,
245 unsigned long long size) 279 unsigned long long size)
246{ 280{
247 char *buf; 281 char *buf;
248 282
249 buf = malloc_or_die(size); 283 buf = malloc(size);
250 read_or_die(buf, size); 284 if (buf == NULL)
285 return -1;
286
287 if (do_read(buf, size) < 0) {
288 free(buf);
289 return -1;
290 }
291
251 parse_event_file(pevent, buf, size, sys); 292 parse_event_file(pevent, buf, size, sys);
252 free(buf); 293 free(buf);
294 return 0;
253} 295}
254 296
255static void read_ftrace_files(struct pevent *pevent) 297static int read_ftrace_files(struct pevent *pevent)
256{ 298{
257 unsigned long long size; 299 unsigned long long size;
258 int count; 300 int count;
259 int i; 301 int i;
302 int ret;
260 303
261 count = read4(pevent); 304 count = read4(pevent);
262 305
263 for (i = 0; i < count; i++) { 306 for (i = 0; i < count; i++) {
264 size = read8(pevent); 307 size = read8(pevent);
265 read_ftrace_file(pevent, size); 308 ret = read_ftrace_file(pevent, size);
309 if (ret)
310 return ret;
266 } 311 }
312 return 0;
267} 313}
268 314
269static void read_event_files(struct pevent *pevent) 315static int read_event_files(struct pevent *pevent)
270{ 316{
271 unsigned long long size; 317 unsigned long long size;
272 char *sys; 318 char *sys;
273 int systems; 319 int systems;
274 int count; 320 int count;
275 int i,x; 321 int i,x;
322 int ret;
276 323
277 systems = read4(pevent); 324 systems = read4(pevent);
278 325
279 for (i = 0; i < systems; i++) { 326 for (i = 0; i < systems; i++) {
280 sys = read_string(); 327 sys = read_string();
328 if (sys == NULL)
329 return -1;
281 330
282 count = read4(pevent); 331 count = read4(pevent);
332
283 for (x=0; x < count; x++) { 333 for (x=0; x < count; x++) {
284 size = read8(pevent); 334 size = read8(pevent);
285 read_event_file(pevent, sys, size); 335 ret = read_event_file(pevent, sys, size);
336 if (ret)
337 return ret;
286 } 338 }
287 } 339 }
288} 340 return 0;
289
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} 341}
488 342
489ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 343ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
@@ -494,58 +348,85 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
494 int show_version = 0; 348 int show_version = 0;
495 int show_funcs = 0; 349 int show_funcs = 0;
496 int show_printk = 0; 350 int show_printk = 0;
497 ssize_t size; 351 ssize_t size = -1;
352 struct pevent *pevent;
353 int err;
498 354
499 calc_data_size = 1; 355 *ppevent = NULL;
500 repipe = __repipe;
501 356
357 repipe = __repipe;
502 input_fd = fd; 358 input_fd = fd;
503 359
504 read_or_die(buf, 3); 360 if (do_read(buf, 3) < 0)
505 if (memcmp(buf, test, 3) != 0) 361 return -1;
506 die("no trace data in the file"); 362 if (memcmp(buf, test, 3) != 0) {
363 pr_debug("no trace data in the file");
364 return -1;
365 }
507 366
508 read_or_die(buf, 7); 367 if (do_read(buf, 7) < 0)
509 if (memcmp(buf, "tracing", 7) != 0) 368 return -1;
510 die("not a trace file (missing 'tracing' tag)"); 369 if (memcmp(buf, "tracing", 7) != 0) {
370 pr_debug("not a trace file (missing 'tracing' tag)");
371 return -1;
372 }
511 373
512 version = read_string(); 374 version = read_string();
375 if (version == NULL)
376 return -1;
513 if (show_version) 377 if (show_version)
514 printf("version = %s\n", version); 378 printf("version = %s\n", version);
515 free(version); 379 free(version);
516 380
517 read_or_die(buf, 1); 381 if (do_read(buf, 1) < 0)
382 return -1;
518 file_bigendian = buf[0]; 383 file_bigendian = buf[0];
519 host_bigendian = bigendian(); 384 host_bigendian = bigendian();
520 385
521 *ppevent = read_trace_init(file_bigendian, host_bigendian); 386 pevent = read_trace_init(file_bigendian, host_bigendian);
522 if (*ppevent == NULL) 387 if (pevent == NULL) {
523 die("read_trace_init failed"); 388 pr_debug("read_trace_init failed");
389 goto out;
390 }
524 391
525 read_or_die(buf, 1); 392 if (do_read(buf, 1) < 0)
393 goto out;
526 long_size = buf[0]; 394 long_size = buf[0];
527 395
528 page_size = read4(*ppevent); 396 page_size = read4(pevent);
529 397 if (!page_size)
530 read_header_files(*ppevent); 398 goto out;
531 399
532 read_ftrace_files(*ppevent); 400 err = read_header_files(pevent);
533 read_event_files(*ppevent); 401 if (err)
534 read_proc_kallsyms(*ppevent); 402 goto out;
535 read_ftrace_printk(*ppevent); 403 err = read_ftrace_files(pevent);
536 404 if (err)
537 size = calc_data_size - 1; 405 goto out;
538 calc_data_size = 0; 406 err = read_event_files(pevent);
407 if (err)
408 goto out;
409 err = read_proc_kallsyms(pevent);
410 if (err)
411 goto out;
412 err = read_ftrace_printk(pevent);
413 if (err)
414 goto out;
415
416 size = trace_data_size;
539 repipe = false; 417 repipe = false;
540 418
541 if (show_funcs) { 419 if (show_funcs) {
542 pevent_print_funcs(*ppevent); 420 pevent_print_funcs(pevent);
543 return size; 421 } else if (show_printk) {
544 } 422 pevent_print_printk(pevent);
545 if (show_printk) {
546 pevent_print_printk(*ppevent);
547 return size;
548 } 423 }
549 424
425 *ppevent = pevent;
426 pevent = NULL;
427
428out:
429 if (pevent)
430 pevent_free(pevent);
550 return size; 431 return size;
551} 432}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a55fd37ffea1..1978c398ad87 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);
@@ -72,7 +68,7 @@ struct tracing_data {
72 68
73struct tracing_data *tracing_data_get(struct list_head *pattrs, 69struct tracing_data *tracing_data_get(struct list_head *pattrs,
74 int fd, bool temp); 70 int fd, bool temp);
75void tracing_data_put(struct tracing_data *tdata); 71int tracing_data_put(struct tracing_data *tdata);
76 72
77 73
78struct addr_location; 74struct addr_location;
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..a45710b70a55 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -1,8 +1,6 @@
1#ifndef GIT_COMPAT_UTIL_H 1#ifndef GIT_COMPAT_UTIL_H
2#define GIT_COMPAT_UTIL_H 2#define GIT_COMPAT_UTIL_H
3 3
4#define _FILE_OFFSET_BITS 64
5
6#ifndef FLEX_ARRAY 4#ifndef FLEX_ARRAY
7/* 5/*
8 * See if our compiler is known to support flexible array members. 6 * See if our compiler is known to support flexible array members.
@@ -73,10 +71,14 @@
73#include <linux/magic.h> 71#include <linux/magic.h>
74#include "types.h" 72#include "types.h"
75#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <lk/debugfs.h>
76 75
77extern const char *graph_line; 76extern const char *graph_line;
78extern const char *graph_dotted_line; 77extern const char *graph_dotted_line;
79extern char buildid_dir[]; 78extern char buildid_dir[];
79extern char tracing_events_path[];
80extern void perf_debugfs_set_path(const char *mountpoint);
81const char *perf_debugfs_mount(const char *mountpoint);
80 82
81/* On most systems <limits.h> would have given us this, but 83/* On most systems <limits.h> would have given us this, but
82 * not on some systems (e.g. GNU/Hurd). 84 * not on some systems (e.g. GNU/Hurd).
@@ -274,5 +276,4 @@ extern unsigned int page_size;
274 276
275struct winsize; 277struct winsize;
276void get_term_dimensions(struct winsize *ws); 278void get_term_dimensions(struct winsize *ws);
277 279#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",