aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-01-25 05:33:41 -0500
committerIngo Molnar <mingo@kernel.org>2013-01-25 05:34:00 -0500
commita2d28d0c198b65fac28ea6212f5f8edc77b29c27 (patch)
tree130c1b4464f1eb685e56ff2ce122e3e36bb52e88
parent203e04c16330c880538588e932743f404ee4fd66 (diff)
parent2ae828786c65ab8f587647bd0f22f8fe00f1f238 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: . Allow skipping problematic entries in 'perf test'. . Fix some namespace problems in the event parsing routines. . Add 'perf test' entry to make sure the python binding doesn't have linking problems. . Adjust 'perf test' attr tests verbosity levels. . Make tools/perf build with GNU make v3.80, fix from Al Cooper. . Do missing feature fallbacks in just one place, removing duplicated code in multiple tools. . Fix some memory leaks, from David Ahern. . Fix segfault when drawing out-of-bounds jumps, from Frederik Deweerdt. . Allow of casting an array of char to string in 'perf probe', from Hyeoncheol Lee. . Add support for wildcard in tracepoint system name, from Jiri Olsa. . Update FSF postal address to be URL's, from Jon Stanley. . Add anonymous huge page recognition, from Joshua Zhu. . Remove some needless feature test checks, from Namhyung Kim. . Multiple improvements to the sort routines, from Namhyung Kim. . Fix warning on '>=' operator in libtraceevent, from Namhyung Kim. . Use ARRAY_SIZE instead of reinventing it in 'perf script' and 'perf kmem', from Sasha Levin. . Remove some redundant checks, from Sasha Levin. . Test correct variable after allocation in libtraceevent, fix from Sasha Levin. . Mark branch_info maps as referenced, fix from Stephane Eranian. . Fix PMU format parsing test failure, from Sukadev Bhattiprolu. . Fix possible (unlikely) buffer overflow, from Thomas Jarosch. . Multiple 'perf script' fixes, from Tom Zanussi. . Add missing field in PERF_RECORD_SAMPLE documentation, from Vince Weaver. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/uapi/linux/perf_event.h3
-rw-r--r--kernel/events/uprobes.c3
-rw-r--r--tools/lib/traceevent/event-parse.c10
-rw-r--r--tools/lib/traceevent/event-parse.h3
-rw-r--r--tools/lib/traceevent/event-utils.h3
-rw-r--r--tools/lib/traceevent/parse-filter.c3
-rw-r--r--tools/lib/traceevent/parse-utils.c19
-rw-r--r--tools/lib/traceevent/trace-seq.c3
-rw-r--r--tools/perf/Documentation/perf-report.txt38
-rw-r--r--tools/perf/Documentation/perf-script-python.txt2
-rw-r--r--tools/perf/Documentation/perf-test.txt4
-rw-r--r--tools/perf/Makefile17
-rw-r--r--tools/perf/builtin-bench.c2
-rw-r--r--tools/perf/builtin-diff.c92
-rw-r--r--tools/perf/builtin-kmem.c10
-rw-r--r--tools/perf/builtin-kvm.c3
-rw-r--r--tools/perf/builtin-record.c127
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/builtin-sched.c6
-rw-r--r--tools/perf/builtin-script.c17
-rw-r--r--tools/perf/builtin-stat.c46
-rw-r--r--tools/perf/builtin-top.c106
-rw-r--r--tools/perf/config/utilities.mak6
-rw-r--r--tools/perf/perf.c32
-rw-r--r--tools/perf/perf.h6
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report3
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/tests/attr.c4
-rw-r--r--tools/perf/tests/attr.py27
-rw-r--r--tools/perf/tests/attr/test-record-group12
-rw-r--r--tools/perf/tests/builtin-test.c40
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_link.c499
-rw-r--r--tools/perf/tests/parse-events.c98
-rw-r--r--tools/perf/tests/pmu.c11
-rw-r--r--tools/perf/tests/python-use.c23
-rw-r--r--tools/perf/tests/tests.h8
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c3
-rw-r--r--tools/perf/ui/browser.c4
-rw-r--r--tools/perf/ui/browsers/annotate.c33
-rw-r--r--tools/perf/ui/gtk/browser.c227
-rw-r--r--tools/perf/ui/gtk/gtk.h9
-rw-r--r--tools/perf/ui/gtk/hists.c226
-rw-r--r--tools/perf/ui/stdio/hist.c6
-rw-r--r--tools/perf/ui/util.c11
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN4
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/evsel.c108
-rw-r--r--tools/perf/util/evsel.h6
-rw-r--r--tools/perf/util/header.c75
-rw-r--r--tools/perf/util/hist.c79
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/intlist.c36
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c64
-rw-r--r--tools/perf/util/machine.h32
-rw-r--r--tools/perf/util/map.c3
-rw-r--r--tools/perf/util/parse-events.c87
-rw-r--r--tools/perf/util/parse-events.h21
-rw-r--r--tools/perf/util/parse-events.y64
-rw-r--r--tools/perf/util/pmu.c46
-rw-r--r--tools/perf/util/pmu.h15
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/python.c9
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c75
-rw-r--r--tools/perf/util/session.h30
-rw-r--r--tools/perf/util/sort.c230
-rw-r--r--tools/perf/util/sort.h8
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/symbol-elf.c3
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c14
-rw-r--r--tools/perf/util/symbol.h2
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/util.c24
-rw-r--r--tools/perf/util/util.h4
81 files changed, 1816 insertions, 1202 deletions
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 4f63c05d27c9..9fa9c622a7f4 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -579,7 +579,8 @@ enum perf_event_type {
579 * { u32 size; 579 * { u32 size;
580 * char data[size];}&& PERF_SAMPLE_RAW 580 * char data[size];}&& PERF_SAMPLE_RAW
581 * 581 *
582 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK 582 * { u64 nr;
583 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
583 * 584 *
584 * { u64 abi; # enum perf_sample_regs_abi 585 * { u64 abi; # enum perf_sample_regs_abi
585 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER 586 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index dea7acfbb071..30ea9a4f4ab4 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -901,8 +901,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
901 } 901 }
902 902
903 mutex_unlock(uprobes_hash(inode)); 903 mutex_unlock(uprobes_hash(inode));
904 if (uprobe) 904 put_uprobe(uprobe);
905 put_uprobe(uprobe);
906} 905}
907 906
908static struct rb_node * 907static struct rb_node *
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 5a824e355d04..bb8b3db0e583 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 * 19 *
@@ -1463,7 +1462,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1463 if (read_expect_type(EVENT_ITEM, &token)) 1462 if (read_expect_type(EVENT_ITEM, &token))
1464 goto fail; 1463 goto fail;
1465 1464
1466 /* add signed type */ 1465 if (strtoul(token, NULL, 0))
1466 field->flags |= FIELD_IS_SIGNED;
1467 1467
1468 free_token(token); 1468 free_token(token);
1469 if (read_expected(EVENT_OP, ";") < 0) 1469 if (read_expected(EVENT_OP, ";") < 0)
@@ -1785,6 +1785,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
1785 strcmp(token, "/") == 0 || 1785 strcmp(token, "/") == 0 ||
1786 strcmp(token, "<") == 0 || 1786 strcmp(token, "<") == 0 ||
1787 strcmp(token, ">") == 0 || 1787 strcmp(token, ">") == 0 ||
1788 strcmp(token, "<=") == 0 ||
1789 strcmp(token, ">=") == 0 ||
1788 strcmp(token, "==") == 0 || 1790 strcmp(token, "==") == 0 ||
1789 strcmp(token, "!=") == 0) { 1791 strcmp(token, "!=") == 0) {
1790 1792
@@ -2481,7 +2483,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char **
2481 2483
2482 free_token(token); 2484 free_token(token);
2483 arg = alloc_arg(); 2485 arg = alloc_arg();
2484 if (!field) { 2486 if (!arg) {
2485 do_warning("%s: not enough memory!", __func__); 2487 do_warning("%s: not enough memory!", __func__);
2486 *tok = NULL; 2488 *tok = NULL;
2487 return EVENT_ERROR; 2489 return EVENT_ERROR;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 24a4bbabc5d5..7be7e89533e4 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
index bc075006966e..e76c9acb92cd 100644
--- a/tools/lib/traceevent/event-utils.h
+++ b/tools/lib/traceevent/event-utils.h
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 5ea4326ad11f..2500e75583fc 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
index f023a133abb6..bba701cf10e6 100644
--- a/tools/lib/traceevent/parse-utils.c
+++ b/tools/lib/traceevent/parse-utils.c
@@ -1,3 +1,22 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
1#include <stdio.h> 20#include <stdio.h>
2#include <stdlib.h> 21#include <stdlib.h>
3#include <string.h> 22#include <string.h>
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index b1ccc923e8a5..a57db805136a 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index f4d91bebd59d..848a0dcb6dfd 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,11 +57,44 @@ OPTIONS
57 57
58-s:: 58-s::
59--sort=:: 59--sort=::
60 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 60 Sort histogram entries by given key(s) - multiple keys can be specified
61 in CSV format. Following sort keys are available:
62 pid, comm, dso, symbol, parent, cpu, srcline.
63
64 Each key has following meaning:
65
66 - comm: command (name) of the task which can be read via /proc/<pid>/comm
67 - pid: command and tid of the task
68 - dso: name of library or module executed at the time of sample
69 - symbol: name of function executed at the time of sample
70 - parent: name of function matched to the parent regex filter. Unmatched
71 entries are displayed as "[other]".
72 - cpu: cpu number the task ran at the time of sample
73 - srcline: filename and line number executed at the time of sample. The
74 DWARF debuggin info must be provided.
75
76 By default, comm, dso and symbol keys are used.
77 (i.e. --sort comm,dso,symbol)
78
79 If --branch-stack option is used, following sort keys are also
80 available:
81 dso_from, dso_to, symbol_from, symbol_to, mispredict.
82
83 - dso_from: name of library or module branched from
84 - dso_to: name of library or module branched to
85 - symbol_from: name of function branched from
86 - symbol_to: name of function branched to
87 - mispredict: "N" for predicted branch, "Y" for mispredicted branch
88
89 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
90 and symbol_to, see '--branch-stack'.
61 91
62-p:: 92-p::
63--parent=<regex>:: 93--parent=<regex>::
64 regex filter to identify parent, see: '--sort parent' 94 A regex filter to identify parent. The parent is a caller of this
95 function and searched through the callchain, thus it requires callchain
96 information recorded. The pattern is in the exteneded regex format and
97 defaults to "\^sys_|^do_page_fault", see '--sort parent'.
65 98
66-x:: 99-x::
67--exclude-other:: 100--exclude-other::
@@ -74,7 +107,6 @@ OPTIONS
74 107
75-t:: 108-t::
76--field-separator=:: 109--field-separator=::
77
78 Use a special separator character and don't pad with spaces, replacing 110 Use a special separator character and don't pad with spaces, replacing
79 all occurrences of this separator in symbol names (and other output) 111 all occurrences of this separator in symbol names (and other output)
80 with a '.' character, that thus it's the only non valid separator. 112 with a '.' character, that thus it's the only non valid separator.
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index a4027f221a53..9f1f054b8432 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.:
336---- 336----
337root@tropicana:~# perf script -l 337root@tropicana:~# perf script -l
338List of available trace scripts: 338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency 339 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file 340 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity 341 rw-by-pid system-wide r/w activity
@@ -402,7 +401,6 @@ should show a new entry for your script:
402---- 401----
403root@tropicana:~# perf script -l 402root@tropicana:~# perf script -l
404List of available trace scripts: 403List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency 404 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file 405 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity 406 rw-by-pid system-wide r/w activity
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index b24ac40fcd58..d1d3e5121f89 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -23,6 +23,10 @@ from 'perf test list'.
23 23
24OPTIONS 24OPTIONS
25------- 25-------
26-s::
27--skip::
28 Tests to skip (comma separater numeric list).
29
26-v:: 30-v::
27--verbose:: 31--verbose::
28 Be more verbose. 32 Be more verbose.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2cbaad83a6e2..a84021abb3fe 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -50,7 +50,6 @@ include config/utilities.mak
50 50
51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
53-include $(OUTPUT)PERF-VERSION-FILE
54 53
55uname_M := $(shell uname -m 2>/dev/null || echo not) 54uname_M := $(shell uname -m 2>/dev/null || echo not)
56 55
@@ -487,6 +486,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
487LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 486LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
488LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 487LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
489LIB_OBJS += $(OUTPUT)tests/pmu.o 488LIB_OBJS += $(OUTPUT)tests/pmu.o
489LIB_OBJS += $(OUTPUT)tests/hists_link.o
490LIB_OBJS += $(OUTPUT)tests/python-use.o
490 491
491BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 492BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
492BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 493BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -532,9 +533,6 @@ ifneq ($(MAKECMDGOALS),tags)
532# because maintaining the nesting to match is a pain. If 533# because maintaining the nesting to match is a pain. If
533# we had "elif" things would have been much nicer... 534# we had "elif" things would have been much nicer...
534 535
535-include config.mak.autogen
536-include config.mak
537
538ifdef NO_LIBELF 536ifdef NO_LIBELF
539 NO_DWARF := 1 537 NO_DWARF := 1
540 NO_DEMANGLE := 1 538 NO_DEMANGLE := 1
@@ -686,6 +684,7 @@ ifndef NO_GTK2
686 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) 684 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
687 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) 685 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
688 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o 686 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
687 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
689 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o 688 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
690 LIB_OBJS += $(OUTPUT)ui/gtk/util.o 689 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
691 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o 690 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
@@ -887,7 +886,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
887 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf 886 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
888 887
889$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 888$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
890 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 889 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
891 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 890 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
892 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 891 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
893 892
@@ -951,7 +950,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
951 950
952$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS 951$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
953 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 952 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
954 '-DBINDIR="$(bindir_SQ)"' \ 953 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
954 $<
955
956$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
957 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
958 -DPYTHONPATH='"$(OUTPUT)python"' \
959 -DPYTHON='"$(PYTHON_WORD)"' \
955 $< 960 $<
956 961
957$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 962$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index cae9a5fd2ecf..afd1255a632f 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -159,6 +159,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
159 printf("# Running %s/%s benchmark...\n", 159 printf("# Running %s/%s benchmark...\n",
160 subsys->name, 160 subsys->name,
161 suites[i].name); 161 suites[i].name);
162 fflush(stdout);
162 163
163 argv[1] = suites[i].name; 164 argv[1] = suites[i].name;
164 suites[i].fn(1, argv, NULL); 165 suites[i].fn(1, argv, NULL);
@@ -225,6 +226,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
225 printf("# Running %s/%s benchmark...\n", 226 printf("# Running %s/%s benchmark...\n",
226 subsystems[i].name, 227 subsystems[i].name,
227 subsystems[i].suites[j].name); 228 subsystems[i].suites[j].name);
229 fflush(stdout);
228 status = subsystems[i].suites[j].fn(argc - 1, 230 status = subsystems[i].suites[j].fn(argc - 1,
229 argv + 1, prefix); 231 argv + 1, prefix);
230 goto end; 232 goto end;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index b2e7d39f099b..4af0b580b046 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -275,43 +275,6 @@ static struct perf_tool tool = {
275 .ordering_requires_timestamps = true, 275 .ordering_requires_timestamps = true,
276}; 276};
277 277
278static void insert_hist_entry_by_name(struct rb_root *root,
279 struct hist_entry *he)
280{
281 struct rb_node **p = &root->rb_node;
282 struct rb_node *parent = NULL;
283 struct hist_entry *iter;
284
285 while (*p != NULL) {
286 parent = *p;
287 iter = rb_entry(parent, struct hist_entry, rb_node);
288 if (hist_entry__cmp(he, iter) < 0)
289 p = &(*p)->rb_left;
290 else
291 p = &(*p)->rb_right;
292 }
293
294 rb_link_node(&he->rb_node, parent, p);
295 rb_insert_color(&he->rb_node, root);
296}
297
298static void hists__name_resort(struct hists *self)
299{
300 struct rb_root tmp = RB_ROOT;
301 struct rb_node *next = rb_first(&self->entries);
302
303 while (next != NULL) {
304 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
305
306 next = rb_next(&n->rb_node);
307
308 rb_erase(&n->rb_node, &self->entries);
309 insert_hist_entry_by_name(&tmp, n);
310 }
311
312 self->entries = tmp;
313}
314
315static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 278static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
316 struct perf_evlist *evlist) 279 struct perf_evlist *evlist)
317{ 280{
@@ -324,30 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
324 return NULL; 287 return NULL;
325} 288}
326 289
327static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) 290static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
328{ 291{
329 struct perf_evsel *evsel; 292 struct perf_evsel *evsel;
330 293
331 list_for_each_entry(evsel, &evlist->entries, node) { 294 list_for_each_entry(evsel, &evlist->entries, node) {
332 struct hists *hists = &evsel->hists; 295 struct hists *hists = &evsel->hists;
333 296
334 hists__output_resort(hists); 297 hists__collapse_resort(hists);
335
336 if (name)
337 hists__name_resort(hists);
338 } 298 }
339} 299}
340 300
341static void hists__baseline_only(struct hists *hists) 301static void hists__baseline_only(struct hists *hists)
342{ 302{
343 struct rb_node *next = rb_first(&hists->entries); 303 struct rb_root *root;
304 struct rb_node *next;
305
306 if (sort__need_collapse)
307 root = &hists->entries_collapsed;
308 else
309 root = hists->entries_in;
344 310
311 next = rb_first(root);
345 while (next != NULL) { 312 while (next != NULL) {
346 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 313 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
347 314
348 next = rb_next(&he->rb_node); 315 next = rb_next(&he->rb_node_in);
349 if (!hist_entry__next_pair(he)) { 316 if (!hist_entry__next_pair(he)) {
350 rb_erase(&he->rb_node, &hists->entries); 317 rb_erase(&he->rb_node_in, root);
351 hist_entry__free(he); 318 hist_entry__free(he);
352 } 319 }
353 } 320 }
@@ -447,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
447 414
448static void hists__compute_resort(struct hists *hists) 415static void hists__compute_resort(struct hists *hists)
449{ 416{
450 struct rb_root tmp = RB_ROOT; 417 struct rb_root *root;
451 struct rb_node *next = rb_first(&hists->entries); 418 struct rb_node *next;
419
420 if (sort__need_collapse)
421 root = &hists->entries_collapsed;
422 else
423 root = hists->entries_in;
424
425 hists->entries = RB_ROOT;
426 next = rb_first(root);
427
428 hists->nr_entries = 0;
429 hists->stats.total_period = 0;
430 hists__reset_col_len(hists);
452 431
453 while (next != NULL) { 432 while (next != NULL) {
454 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 433 struct hist_entry *he;
455 434
456 next = rb_next(&he->rb_node); 435 he = rb_entry(next, struct hist_entry, rb_node_in);
436 next = rb_next(&he->rb_node_in);
457 437
458 rb_erase(&he->rb_node, &hists->entries); 438 insert_hist_entry_by_compute(&hists->entries, he, compute);
459 insert_hist_entry_by_compute(&tmp, he, compute); 439 hists__inc_nr_entries(hists, he);
460 } 440 }
461
462 hists->entries = tmp;
463} 441}
464 442
465static void hists__process(struct hists *old, struct hists *new) 443static void hists__process(struct hists *old, struct hists *new)
@@ -474,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new)
474 if (sort_compute) { 452 if (sort_compute) {
475 hists__precompute(new); 453 hists__precompute(new);
476 hists__compute_resort(new); 454 hists__compute_resort(new);
455 } else {
456 hists__output_resort(new);
477 } 457 }
478 458
479 hists__fprintf(new, true, 0, 0, stdout); 459 hists__fprintf(new, true, 0, 0, stdout);
@@ -505,8 +485,8 @@ static int __cmd_diff(void)
505 evlist_old = older->evlist; 485 evlist_old = older->evlist;
506 evlist_new = newer->evlist; 486 evlist_new = newer->evlist;
507 487
508 perf_evlist__resort_hists(evlist_old, true); 488 perf_evlist__collapse_resort(evlist_old);
509 perf_evlist__resort_hists(evlist_new, false); 489 perf_evlist__collapse_resort(evlist_new);
510 490
511 list_for_each_entry(evsel, &evlist_new->entries, node) { 491 list_for_each_entry(evsel, &evlist_new->entries, node) {
512 struct perf_evsel *evsel_old; 492 struct perf_evsel *evsel_old;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0b4b796167be..c746108c5d48 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -340,7 +340,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
340 int n_lines, int is_caller) 340 int n_lines, int is_caller)
341{ 341{
342 struct rb_node *next; 342 struct rb_node *next;
343 struct machine *machine; 343 struct machine *machine = &session->machines.host;
344 344
345 printf("%.102s\n", graph_dotted_line); 345 printf("%.102s\n", graph_dotted_line);
346 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 346 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +349,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
349 349
350 next = rb_first(root); 350 next = rb_first(root);
351 351
352 machine = perf_session__find_host_machine(session);
353 if (!machine) {
354 pr_err("__print_result: couldn't find kernel information\n");
355 return;
356 }
357 while (next && n_lines--) { 352 while (next && n_lines--) {
358 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 353 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
359 node); 354 node);
@@ -614,8 +609,7 @@ static struct sort_dimension *avail_sorts[] = {
614 &pingpong_sort_dimension, 609 &pingpong_sort_dimension,
615}; 610};
616 611
617#define NUM_AVAIL_SORTS \ 612#define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts))
618 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
619 613
620static int sort_dimension__add(const char *tok, struct list_head *list) 614static int sort_dimension__add(const char *tok, struct list_head *list)
621{ 615{
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index ca3f80ebc100..37a769d7f9fe 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -973,8 +973,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
973 973
974int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 974int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
975{ 975{
976 const char *file_name; 976 const char *file_name = NULL;
977
978 const struct option kvm_options[] = { 977 const struct option kvm_options[] = {
979 OPT_STRING('i', "input", &file_name, "file", 978 OPT_STRING('i', "input", &file_name, "file",
980 "Input file name"), 979 "Input file name"),
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 028de726b832..2ac690cad411 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -224,6 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
224 224
225static int perf_record__open(struct perf_record *rec) 225static int perf_record__open(struct perf_record *rec)
226{ 226{
227 char msg[512];
227 struct perf_evsel *pos; 228 struct perf_evsel *pos;
228 struct perf_evlist *evlist = rec->evlist; 229 struct perf_evlist *evlist = rec->evlist;
229 struct perf_session *session = rec->session; 230 struct perf_session *session = rec->session;
@@ -233,114 +234,18 @@ static int perf_record__open(struct perf_record *rec)
233 perf_evlist__config(evlist, opts); 234 perf_evlist__config(evlist, opts);
234 235
235 list_for_each_entry(pos, &evlist->entries, node) { 236 list_for_each_entry(pos, &evlist->entries, node) {
236 struct perf_event_attr *attr = &pos->attr;
237 /*
238 * Check if parse_single_tracepoint_event has already asked for
239 * PERF_SAMPLE_TIME.
240 *
241 * XXX this is kludgy but short term fix for problems introduced by
242 * eac23d1c that broke 'perf script' by having different sample_types
243 * when using multiple tracepoint events when we use a perf binary
244 * that tries to use sample_id_all on an older kernel.
245 *
246 * We need to move counter creation to perf_session, support
247 * different sample_types, etc.
248 */
249 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
250
251fallback_missing_features:
252 if (opts->exclude_guest_missing)
253 attr->exclude_guest = attr->exclude_host = 0;
254retry_sample_id:
255 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
256try_again: 237try_again:
257 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 238 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
258 int err = errno; 239 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
259
260 if (err == EPERM || err == EACCES) {
261 ui__error_paranoid();
262 rc = -err;
263 goto out;
264 } else if (err == ENODEV && opts->target.cpu_list) {
265 pr_err("No such device - did you specify"
266 " an out-of-range profile CPU?\n");
267 rc = -err;
268 goto out;
269 } else if (err == EINVAL) {
270 if (!opts->exclude_guest_missing &&
271 (attr->exclude_guest || attr->exclude_host)) {
272 pr_debug("Old kernel, cannot exclude "
273 "guest or host samples.\n");
274 opts->exclude_guest_missing = true;
275 goto fallback_missing_features;
276 } else if (!opts->sample_id_all_missing) {
277 /*
278 * Old kernel, no attr->sample_id_type_all field
279 */
280 opts->sample_id_all_missing = true;
281 if (!opts->sample_time && !opts->raw_samples && !time_needed)
282 perf_evsel__reset_sample_bit(pos, TIME);
283
284 goto retry_sample_id;
285 }
286 }
287
288 /*
289 * If it's cycles then fall back to hrtimer
290 * based cpu-clock-tick sw counter, which
291 * is always available even if no PMU support.
292 *
293 * PPC returns ENXIO until 2.6.37 (behavior changed
294 * with commit b0a873e).
295 */
296 if ((err == ENOENT || err == ENXIO)
297 && attr->type == PERF_TYPE_HARDWARE
298 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
299
300 if (verbose) 240 if (verbose)
301 ui__warning("The cycles event is not supported, " 241 ui__warning("%s\n", msg);
302 "trying to fall back to cpu-clock-ticks\n");
303 attr->type = PERF_TYPE_SOFTWARE;
304 attr->config = PERF_COUNT_SW_CPU_CLOCK;
305 if (pos->name) {
306 free(pos->name);
307 pos->name = NULL;
308 }
309 goto try_again; 242 goto try_again;
310 } 243 }
311 244
312 if (err == ENOENT) { 245 rc = -errno;
313 ui__error("The %s event is not supported.\n", 246 perf_evsel__open_strerror(pos, &opts->target,
314 perf_evsel__name(pos)); 247 errno, msg, sizeof(msg));
315 rc = -err; 248 ui__error("%s\n", msg);
316 goto out;
317 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
318 ui__error("\'precise\' request may not be supported. "
319 "Try removing 'p' modifier\n");
320 rc = -err;
321 goto out;
322 }
323
324 printf("\n");
325 error("sys_perf_event_open() syscall returned with %d "
326 "(%s) for event %s. /bin/dmesg may provide "
327 "additional information.\n",
328 err, strerror(err), perf_evsel__name(pos));
329
330#if defined(__i386__) || defined(__x86_64__)
331 if (attr->type == PERF_TYPE_HARDWARE &&
332 err == EOPNOTSUPP) {
333 pr_err("No hardware sampling interrupt available."
334 " No APIC? If so then you can boot the kernel"
335 " with the \"lapic\" boot parameter to"
336 " force-enable it.\n");
337 rc = -err;
338 goto out;
339 }
340#endif
341
342 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
343 rc = -err;
344 goto out; 249 goto out;
345 } 250 }
346 } 251 }
@@ -423,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
423{ 328{
424 int err; 329 int err;
425 struct perf_tool *tool = data; 330 struct perf_tool *tool = data;
426
427 if (machine__is_host(machine))
428 return;
429
430 /* 331 /*
431 *As for guest kernel when processing subcommand record&report, 332 *As for guest kernel when processing subcommand record&report,
432 *we arrange module mmap prior to guest kernel mmap and trigger 333 *we arrange module mmap prior to guest kernel mmap and trigger
@@ -611,12 +512,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
611 512
612 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 513 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
613 514
614 machine = perf_session__find_host_machine(session); 515 machine = &session->machines.host;
615 if (!machine) {
616 pr_err("Couldn't find native kernel information.\n");
617 err = -1;
618 goto out_delete_session;
619 }
620 516
621 if (opts->pipe_output) { 517 if (opts->pipe_output) {
622 err = perf_event__synthesize_attrs(tool, session, 518 err = perf_event__synthesize_attrs(tool, session,
@@ -669,9 +565,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
669 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 565 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
670 "Check /proc/modules permission or run as root.\n"); 566 "Check /proc/modules permission or run as root.\n");
671 567
672 if (perf_guest) 568 if (perf_guest) {
673 perf_session__process_machines(session, tool, 569 machines__process_guests(&session->machines,
674 perf_event__synthesize_guest_os); 570 perf_event__synthesize_guest_os, tool);
571 }
675 572
676 if (!opts->target.system_wide) 573 if (!opts->target.system_wide)
677 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 574 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 5134acf1c39a..47a864478543 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -372,7 +372,7 @@ static int __cmd_report(struct perf_report *rep)
372 if (ret) 372 if (ret)
373 goto out_delete; 373 goto out_delete;
374 374
375 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; 375 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
376 kernel_kmap = map__kmap(kernel_map); 376 kernel_kmap = map__kmap(kernel_map);
377 if (kernel_map == NULL || 377 if (kernel_map == NULL ||
378 (kernel_map->dso->hit && 378 (kernel_map->dso->hit &&
@@ -595,8 +595,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
595 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 595 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
596 "Use the stdio interface"), 596 "Use the stdio interface"),
597 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 597 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
598 "sort by key(s): pid, comm, dso, symbol, parent, dso_to," 598 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
599 " dso_from, symbol_to, symbol_from, mispredict"), 599 " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
600 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 600 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
601 "Show sample percentage for different cpu modes"), 601 "Show sample percentage for different cpu modes"),
602 OPT_STRING('p', "parent", &parent_pattern, "regex", 602 OPT_STRING('p', "parent", &parent_pattern, "regex",
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index cc28b85dabd5..138229439a93 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1475 goto out_delete; 1475 goto out_delete;
1476 } 1476 }
1477 1477
1478 sched->nr_events = session->hists.stats.nr_events[0]; 1478 sched->nr_events = session->stats.nr_events[0];
1479 sched->nr_lost_events = session->hists.stats.total_lost; 1479 sched->nr_lost_events = session->stats.total_lost;
1480 sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1480 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1481 } 1481 }
1482 1482
1483 if (destroy) 1483 if (destroy)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b363e7b292b2..92d4658f56fb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
692 const char *arg, int unset __maybe_unused) 692 const char *arg, int unset __maybe_unused)
693{ 693{
694 char *tok; 694 char *tok;
695 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 695 int i, imax = ARRAY_SIZE(all_output_options);
696 int j; 696 int j;
697 int rc = 0; 697 int rc = 0;
698 char *str = strdup(arg); 698 char *str = strdup(arg);
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix)
909 return NULL; 909 return NULL;
910} 910}
911 911
912static char *ltrim(char *str)
913{
914 int len = strlen(str);
915
916 while (len && isspace(*str)) {
917 len--;
918 str++;
919 }
920
921 return str;
922}
923
924static int read_script_info(struct script_desc *desc, const char *filename) 912static int read_script_info(struct script_desc *desc, const char *filename)
925{ 913{
926 char line[BUFSIZ], *p; 914 char line[BUFSIZ], *p;
@@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1487 return -1; 1475 return -1;
1488 } 1476 }
1489 1477
1490 perf_session__fprintf_info(session, stdout, show_full_info); 1478 if (!script_name && !generate_script_lang)
1479 perf_session__fprintf_info(session, stdout, show_full_info);
1491 1480
1492 if (!no_callchain) 1481 if (!no_callchain)
1493 symbol_conf.use_callchain = true; 1482 symbol_conf.use_callchain = true;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c12655af2b88..1c2ac148a7d5 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -132,8 +132,6 @@ static struct stats walltime_nsecs_stats;
132static int create_perf_stat_counter(struct perf_evsel *evsel) 132static int create_perf_stat_counter(struct perf_evsel *evsel)
133{ 133{
134 struct perf_event_attr *attr = &evsel->attr; 134 struct perf_event_attr *attr = &evsel->attr;
135 bool exclude_guest_missing = false;
136 int ret;
137 135
138 if (scale) 136 if (scale)
139 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 137 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,16 +139,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
141 139
142 attr->inherit = !no_inherit; 140 attr->inherit = !no_inherit;
143 141
144retry: 142 if (perf_target__has_cpu(&target))
145 if (exclude_guest_missing) 143 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
146 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
147
148 if (perf_target__has_cpu(&target)) {
149 ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
150 if (ret)
151 goto check_ret;
152 return 0;
153 }
154 144
155 if (!perf_target__has_task(&target) && 145 if (!perf_target__has_task(&target) &&
156 perf_evsel__is_group_leader(evsel)) { 146 perf_evsel__is_group_leader(evsel)) {
@@ -158,21 +148,7 @@ retry:
158 attr->enable_on_exec = 1; 148 attr->enable_on_exec = 1;
159 } 149 }
160 150
161 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); 151 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
162 if (!ret)
163 return 0;
164 /* fall through */
165check_ret:
166 if (ret && errno == EINVAL) {
167 if (!exclude_guest_missing &&
168 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
169 pr_debug("Old kernel, cannot exclude "
170 "guest or host samples.\n");
171 exclude_guest_missing = true;
172 goto retry;
173 }
174 }
175 return ret;
176} 152}
177 153
178/* 154/*
@@ -271,6 +247,7 @@ static int read_counter(struct perf_evsel *counter)
271 247
272static int __run_perf_stat(int argc __maybe_unused, const char **argv) 248static int __run_perf_stat(int argc __maybe_unused, const char **argv)
273{ 249{
250 char msg[512];
274 unsigned long long t0, t1; 251 unsigned long long t0, t1;
275 struct perf_evsel *counter; 252 struct perf_evsel *counter;
276 int status = 0; 253 int status = 0;
@@ -348,20 +325,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
348 continue; 325 continue;
349 } 326 }
350 327
351 if (errno == EPERM || errno == EACCES) { 328 perf_evsel__open_strerror(counter, &target,
352 error("You may not have permission to collect %sstats.\n" 329 errno, msg, sizeof(msg));
353 "\t Consider tweaking" 330 ui__error("%s\n", msg);
354 " /proc/sys/kernel/perf_event_paranoid or running as root.", 331
355 target.system_wide ? "system-wide " : "");
356 } else {
357 error("open_counter returned with %d (%s). "
358 "/bin/dmesg may provide additional information.\n",
359 errno, strerror(errno));
360 }
361 if (child_pid != -1) 332 if (child_pid != -1)
362 kill(child_pid, SIGTERM); 333 kill(child_pid, SIGTERM);
363 334
364 pr_err("Not all events could be opened.\n");
365 return -1; 335 return -1;
366 } 336 }
367 counter->supported = true; 337 counter->supported = true;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b7d2ea62dbc6..7978c8117b7f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -68,28 +68,6 @@
68#include <linux/unistd.h> 68#include <linux/unistd.h>
69#include <linux/types.h> 69#include <linux/types.h>
70 70
71void get_term_dimensions(struct winsize *ws)
72{
73 char *s = getenv("LINES");
74
75 if (s != NULL) {
76 ws->ws_row = atoi(s);
77 s = getenv("COLUMNS");
78 if (s != NULL) {
79 ws->ws_col = atoi(s);
80 if (ws->ws_row && ws->ws_col)
81 return;
82 }
83 }
84#ifdef TIOCGWINSZ
85 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
86 ws->ws_row && ws->ws_col)
87 return;
88#endif
89 ws->ws_row = 25;
90 ws->ws_col = 80;
91}
92
93static void perf_top__update_print_entries(struct perf_top *top) 71static void perf_top__update_print_entries(struct perf_top *top)
94{ 72{
95 if (top->print_entries > 9) 73 if (top->print_entries > 9)
@@ -716,7 +694,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
716 static struct intlist *seen; 694 static struct intlist *seen;
717 695
718 if (!seen) 696 if (!seen)
719 seen = intlist__new(); 697 seen = intlist__new(NULL);
720 698
721 if (!intlist__has_entry(seen, event->ip.pid)) { 699 if (!intlist__has_entry(seen, event->ip.pid)) {
722 pr_err("Can't find guest [%d]'s kernel information\n", 700 pr_err("Can't find guest [%d]'s kernel information\n",
@@ -728,7 +706,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
728 706
729 if (!machine) { 707 if (!machine) {
730 pr_err("%u unprocessable samples recorded.\n", 708 pr_err("%u unprocessable samples recorded.\n",
731 top->session->hists.stats.nr_unprocessable_samples++); 709 top->session->stats.nr_unprocessable_samples++);
732 return; 710 return;
733 } 711 }
734 712
@@ -847,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
847 ++top->us_samples; 825 ++top->us_samples;
848 if (top->hide_user_symbols) 826 if (top->hide_user_symbols)
849 continue; 827 continue;
850 machine = perf_session__find_host_machine(session); 828 machine = &session->machines.host;
851 break; 829 break;
852 case PERF_RECORD_MISC_KERNEL: 830 case PERF_RECORD_MISC_KERNEL:
853 ++top->kernel_samples; 831 ++top->kernel_samples;
854 if (top->hide_kernel_symbols) 832 if (top->hide_kernel_symbols)
855 continue; 833 continue;
856 machine = perf_session__find_host_machine(session); 834 machine = &session->machines.host;
857 break; 835 break;
858 case PERF_RECORD_MISC_GUEST_KERNEL: 836 case PERF_RECORD_MISC_GUEST_KERNEL:
859 ++top->guest_kernel_samples; 837 ++top->guest_kernel_samples;
@@ -878,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
878 hists__inc_nr_events(&evsel->hists, event->header.type); 856 hists__inc_nr_events(&evsel->hists, event->header.type);
879 machine__process_event(machine, event); 857 machine__process_event(machine, event);
880 } else 858 } else
881 ++session->hists.stats.nr_unknown_events; 859 ++session->stats.nr_unknown_events;
882 } 860 }
883} 861}
884 862
@@ -892,6 +870,7 @@ static void perf_top__mmap_read(struct perf_top *top)
892 870
893static void perf_top__start_counters(struct perf_top *top) 871static void perf_top__start_counters(struct perf_top *top)
894{ 872{
873 char msg[512];
895 struct perf_evsel *counter; 874 struct perf_evsel *counter;
896 struct perf_evlist *evlist = top->evlist; 875 struct perf_evlist *evlist = top->evlist;
897 struct perf_record_opts *opts = &top->record_opts; 876 struct perf_record_opts *opts = &top->record_opts;
@@ -899,77 +878,18 @@ static void perf_top__start_counters(struct perf_top *top)
899 perf_evlist__config(evlist, opts); 878 perf_evlist__config(evlist, opts);
900 879
901 list_for_each_entry(counter, &evlist->entries, node) { 880 list_for_each_entry(counter, &evlist->entries, node) {
902 struct perf_event_attr *attr = &counter->attr;
903
904fallback_missing_features:
905 if (top->exclude_guest_missing)
906 attr->exclude_guest = attr->exclude_host = 0;
907retry_sample_id:
908 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
909try_again: 881try_again:
910 if (perf_evsel__open(counter, top->evlist->cpus, 882 if (perf_evsel__open(counter, top->evlist->cpus,
911 top->evlist->threads) < 0) { 883 top->evlist->threads) < 0) {
912 int err = errno; 884 if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
913
914 if (err == EPERM || err == EACCES) {
915 ui__error_paranoid();
916 goto out_err;
917 } else if (err == EINVAL) {
918 if (!top->exclude_guest_missing &&
919 (attr->exclude_guest || attr->exclude_host)) {
920 pr_debug("Old kernel, cannot exclude "
921 "guest or host samples.\n");
922 top->exclude_guest_missing = true;
923 goto fallback_missing_features;
924 } else if (!top->sample_id_all_missing) {
925 /*
926 * Old kernel, no attr->sample_id_type_all field
927 */
928 top->sample_id_all_missing = true;
929 goto retry_sample_id;
930 }
931 }
932 /*
933 * If it's cycles then fall back to hrtimer
934 * based cpu-clock-tick sw counter, which
935 * is always available even if no PMU support:
936 */
937 if ((err == ENOENT || err == ENXIO) &&
938 (attr->type == PERF_TYPE_HARDWARE) &&
939 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
940
941 if (verbose) 885 if (verbose)
942 ui__warning("Cycles event not supported,\n" 886 ui__warning("%s\n", msg);
943 "trying to fall back to cpu-clock-ticks\n");
944
945 attr->type = PERF_TYPE_SOFTWARE;
946 attr->config = PERF_COUNT_SW_CPU_CLOCK;
947 if (counter->name) {
948 free(counter->name);
949 counter->name = NULL;
950 }
951 goto try_again; 887 goto try_again;
952 } 888 }
953 889
954 if (err == ENOENT) { 890 perf_evsel__open_strerror(counter, &opts->target,
955 ui__error("The %s event is not supported.\n", 891 errno, msg, sizeof(msg));
956 perf_evsel__name(counter)); 892 ui__error("%s\n", msg);
957 goto out_err;
958 } else if (err == EMFILE) {
959 ui__error("Too many events are opened.\n"
960 "Try again after reducing the number of events\n");
961 goto out_err;
962 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
963 ui__error("\'precise\' request may not be supported. "
964 "Try removing 'p' modifier\n");
965 goto out_err;
966 }
967
968 ui__error("The sys_perf_event_open() syscall "
969 "returned with %d (%s). /bin/dmesg "
970 "may provide additional information.\n"
971 "No CONFIG_PERF_EVENTS=y kernel support "
972 "configured?\n", err, strerror(err));
973 goto out_err; 893 goto out_err;
974 } 894 }
975 } 895 }
@@ -1024,10 +944,10 @@ static int __cmd_top(struct perf_top *top)
1024 if (perf_target__has_task(&opts->target)) 944 if (perf_target__has_task(&opts->target))
1025 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 945 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1026 perf_event__process, 946 perf_event__process,
1027 &top->session->host_machine); 947 &top->session->machines.host);
1028 else 948 else
1029 perf_event__synthesize_threads(&top->tool, perf_event__process, 949 perf_event__synthesize_threads(&top->tool, perf_event__process,
1030 &top->session->host_machine); 950 &top->session->machines.host);
1031 perf_top__start_counters(top); 951 perf_top__start_counters(top);
1032 top->session->evlist = top->evlist; 952 top->session->evlist = top->evlist;
1033 perf_session__set_id_hdr_size(top->session); 953 perf_session__set_id_hdr_size(top->session);
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index e5413125e6bb..8ef3bd30a549 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -13,7 +13,7 @@ newline := $(newline)
13# what should replace a newline when escaping 13# what should replace a newline when escaping
14# newlines; the default is a bizarre string. 14# newlines; the default is a bizarre string.
15# 15#
16nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) 16nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17 17
18# escape-nl 18# escape-nl
19# 19#
@@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1))
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) 173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174# 174#
175define get-executable-or-default 175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) 176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
177endef 177endef
178_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 0f661fbce6a8..095b88207cd3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -328,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
328 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) 328 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
329 return 0; 329 return 0;
330 330
331 status = 1;
331 /* Check for ENOSPC and EIO errors.. */ 332 /* Check for ENOSPC and EIO errors.. */
332 if (fflush(stdout)) 333 if (fflush(stdout)) {
333 die("write failure on standard output: %s", strerror(errno)); 334 fprintf(stderr, "write failure on standard output: %s", strerror(errno));
334 if (ferror(stdout)) 335 goto out;
335 die("unknown write failure on standard output"); 336 }
336 if (fclose(stdout)) 337 if (ferror(stdout)) {
337 die("close failed on standard output: %s", strerror(errno)); 338 fprintf(stderr, "unknown write failure on standard output");
338 return 0; 339 goto out;
340 }
341 if (fclose(stdout)) {
342 fprintf(stderr, "close failed on standard output: %s", strerror(errno));
343 goto out;
344 }
345 status = 0;
346out:
347 return status;
339} 348}
340 349
341static void handle_internal_command(int argc, const char **argv) 350static void handle_internal_command(int argc, const char **argv)
@@ -467,7 +476,8 @@ int main(int argc, const char **argv)
467 cmd += 5; 476 cmd += 5;
468 argv[0] = cmd; 477 argv[0] = cmd;
469 handle_internal_command(argc, argv); 478 handle_internal_command(argc, argv);
470 die("cannot handle %s internally", cmd); 479 fprintf(stderr, "cannot handle %s internally", cmd);
480 goto out;
471 } 481 }
472 482
473 /* Look for flags.. */ 483 /* Look for flags.. */
@@ -485,7 +495,7 @@ int main(int argc, const char **argv)
485 printf("\n usage: %s\n\n", perf_usage_string); 495 printf("\n usage: %s\n\n", perf_usage_string);
486 list_common_cmds_help(); 496 list_common_cmds_help();
487 printf("\n %s\n\n", perf_more_info_string); 497 printf("\n %s\n\n", perf_more_info_string);
488 exit(1); 498 goto out;
489 } 499 }
490 cmd = argv[0]; 500 cmd = argv[0];
491 501
@@ -517,7 +527,7 @@ int main(int argc, const char **argv)
517 fprintf(stderr, "Expansion of alias '%s' failed; " 527 fprintf(stderr, "Expansion of alias '%s' failed; "
518 "'%s' is not a perf-command\n", 528 "'%s' is not a perf-command\n",
519 cmd, argv[0]); 529 cmd, argv[0]);
520 exit(1); 530 goto out;
521 } 531 }
522 if (!done_help) { 532 if (!done_help) {
523 cmd = argv[0] = help_unknown_cmd(cmd); 533 cmd = argv[0] = help_unknown_cmd(cmd);
@@ -528,6 +538,6 @@ int main(int argc, const char **argv)
528 538
529 fprintf(stderr, "Failed to run command '%s': %s\n", 539 fprintf(stderr, "Failed to run command '%s': %s\n",
530 cmd, strerror(errno)); 540 cmd, strerror(errno));
531 541out:
532 return 1; 542 return 1;
533} 543}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 2c340e7da458..8f3bf388e414 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,10 +1,6 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4struct winsize;
5
6void get_term_dimensions(struct winsize *ws);
7
8#include <asm/unistd.h> 4#include <asm/unistd.h>
9 5
10#if defined(__i386__) 6#if defined(__i386__)
@@ -237,8 +233,6 @@ struct perf_record_opts {
237 bool raw_samples; 233 bool raw_samples;
238 bool sample_address; 234 bool sample_address;
239 bool sample_time; 235 bool sample_time;
240 bool sample_id_all_missing;
241 bool exclude_guest_missing;
242 bool period; 236 bool period;
243 unsigned int freq; 237 unsigned int freq;
244 unsigned int mmap_pages; 238 unsigned int mmap_pages;
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
deleted file mode 100644
index 8edda9078d5d..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
deleted file mode 100644
index 6d91411d248c..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
deleted file mode 100644
index a8eaff5119e0..000000000000
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ /dev/null
@@ -1,129 +0,0 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'} || 0;
75 my $exe = $$wqhash{'executed'} || 0;
76 my $comm = $$wqhash{'comm'} || "";
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'} || 0;
91 my $destroyed = $$wqhash{'destroyed'} || 0;
92 my $comm = $$wqhash{'comm'} || "";
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 25638a986257..f61dd3fb546b 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -33,8 +33,6 @@
33 33
34extern int verbose; 34extern int verbose;
35 35
36bool test_attr__enabled;
37
38static char *dir; 36static char *dir;
39 37
40void test_attr__init(void) 38void test_attr__init(void)
@@ -146,7 +144,7 @@ static int run_dir(const char *d, const char *perf)
146{ 144{
147 char cmd[3*PATH_MAX]; 145 char cmd[3*PATH_MAX];
148 146
149 snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s", 147 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
150 d, d, perf, verbose ? "-v" : ""); 148 d, d, perf, verbose ? "-v" : "");
151 149
152 return system(cmd); 150 return system(cmd);
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index e702b82dcb86..2f629ca485bc 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -68,7 +68,7 @@ class Event(dict):
68 self[key] = val 68 self[key] = val
69 69
70 def __init__(self, name, data, base): 70 def __init__(self, name, data, base):
71 log.info(" Event %s" % name); 71 log.debug(" Event %s" % name);
72 self.name = name; 72 self.name = name;
73 self.group = '' 73 self.group = ''
74 self.add(base) 74 self.add(base)
@@ -97,6 +97,14 @@ class Event(dict):
97 return False 97 return False
98 return True 98 return True
99 99
100 def diff(self, other):
101 for t in Event.terms:
102 if not self.has_key(t) or not other.has_key(t):
103 continue
104 if not self.compare_data(self[t], other[t]):
105 log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
106
107
100# Test file description needs to have following sections: 108# Test file description needs to have following sections:
101# [config] 109# [config]
102# - just single instance in file 110# - just single instance in file
@@ -113,7 +121,7 @@ class Test(object):
113 parser = ConfigParser.SafeConfigParser() 121 parser = ConfigParser.SafeConfigParser()
114 parser.read(path) 122 parser.read(path)
115 123
116 log.warning("running '%s'" % path) 124 log.debug("running '%s'" % path)
117 125
118 self.path = path 126 self.path = path
119 self.test_dir = options.test_dir 127 self.test_dir = options.test_dir
@@ -128,7 +136,7 @@ class Test(object):
128 136
129 self.expect = {} 137 self.expect = {}
130 self.result = {} 138 self.result = {}
131 log.info(" loading expected events"); 139 log.debug(" loading expected events");
132 self.load_events(path, self.expect) 140 self.load_events(path, self.expect)
133 141
134 def is_event(self, name): 142 def is_event(self, name):
@@ -164,7 +172,7 @@ class Test(object):
164 self.perf, self.command, tempdir, self.args) 172 self.perf, self.command, tempdir, self.args)
165 ret = os.WEXITSTATUS(os.system(cmd)) 173 ret = os.WEXITSTATUS(os.system(cmd))
166 174
167 log.info(" running '%s' ret %d " % (cmd, ret)) 175 log.warning(" running '%s' ret %d " % (cmd, ret))
168 176
169 if ret != int(self.ret): 177 if ret != int(self.ret):
170 raise Unsup(self) 178 raise Unsup(self)
@@ -172,7 +180,7 @@ class Test(object):
172 def compare(self, expect, result): 180 def compare(self, expect, result):
173 match = {} 181 match = {}
174 182
175 log.info(" compare"); 183 log.debug(" compare");
176 184
177 # For each expected event find all matching 185 # For each expected event find all matching
178 # events in result. Fail if there's not any. 186 # events in result. Fail if there's not any.
@@ -187,10 +195,11 @@ class Test(object):
187 else: 195 else:
188 log.debug(" ->FAIL"); 196 log.debug(" ->FAIL");
189 197
190 log.info(" match: [%s] matches %s" % (exp_name, str(exp_list))) 198 log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list)))
191 199
192 # we did not any matching event - fail 200 # we did not any matching event - fail
193 if (not exp_list): 201 if (not exp_list):
202 exp_event.diff(res_event)
194 raise Fail(self, 'match failure'); 203 raise Fail(self, 'match failure');
195 204
196 match[exp_name] = exp_list 205 match[exp_name] = exp_list
@@ -208,10 +217,10 @@ class Test(object):
208 if res_group not in match[group]: 217 if res_group not in match[group]:
209 raise Fail(self, 'group failure') 218 raise Fail(self, 'group failure')
210 219
211 log.info(" group: [%s] matches group leader %s" % 220 log.debug(" group: [%s] matches group leader %s" %
212 (exp_name, str(match[group]))) 221 (exp_name, str(match[group])))
213 222
214 log.info(" matched") 223 log.debug(" matched")
215 224
216 def resolve_groups(self, events): 225 def resolve_groups(self, events):
217 for name, event in events.items(): 226 for name, event in events.items():
@@ -233,7 +242,7 @@ class Test(object):
233 self.run_cmd(tempdir); 242 self.run_cmd(tempdir);
234 243
235 # load events expectation for the test 244 # load events expectation for the test
236 log.info(" loading result events"); 245 log.debug(" loading result events");
237 for f in glob.glob(tempdir + '/event*'): 246 for f in glob.glob(tempdir + '/event*'):
238 self.load_events(f, self.result); 247 self.load_events(f, self.result);
239 248
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
index 4d688a13fd2f..c5548d054aff 100644
--- a/tools/perf/tests/attr/test-record-group1
+++ b/tools/perf/tests/attr/test-record-group1
@@ -1,6 +1,6 @@
1[config] 1[config]
2command = record 2command = record
3args = -e '{cycles,instructions}' kill >/tmp/krava 2>&1 3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4 4
5[event-1:base-record] 5[event-1:base-record]
6fd=1 6fd=1
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 186f67535494..acb98e0e39f2 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -4,6 +4,7 @@
4 * Builtin regression testing command: ever growing number of sanity tests 4 * Builtin regression testing command: ever growing number of sanity tests
5 */ 5 */
6#include "builtin.h" 6#include "builtin.h"
7#include "intlist.h"
7#include "tests.h" 8#include "tests.h"
8#include "debug.h" 9#include "debug.h"
9#include "color.h" 10#include "color.h"
@@ -69,6 +70,14 @@ static struct test {
69 .func = test__attr, 70 .func = test__attr,
70 }, 71 },
71 { 72 {
73 .desc = "Test matching and linking mutliple hists",
74 .func = test__hists_link,
75 },
76 {
77 .desc = "Try 'use perf' in python, checking link problems",
78 .func = test__python_use,
79 },
80 {
72 .func = NULL, 81 .func = NULL,
73 }, 82 },
74}; 83};
@@ -97,7 +106,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
97 return false; 106 return false;
98} 107}
99 108
100static int __cmd_test(int argc, const char *argv[]) 109static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
101{ 110{
102 int i = 0; 111 int i = 0;
103 int width = 0; 112 int width = 0;
@@ -118,13 +127,28 @@ static int __cmd_test(int argc, const char *argv[])
118 continue; 127 continue;
119 128
120 pr_info("%2d: %-*s:", i, width, tests[curr].desc); 129 pr_info("%2d: %-*s:", i, width, tests[curr].desc);
130
131 if (intlist__find(skiplist, i)) {
132 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
133 continue;
134 }
135
121 pr_debug("\n--- start ---\n"); 136 pr_debug("\n--- start ---\n");
122 err = tests[curr].func(); 137 err = tests[curr].func();
123 pr_debug("---- end ----\n%s:", tests[curr].desc); 138 pr_debug("---- end ----\n%s:", tests[curr].desc);
124 if (err) 139
125 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 140 switch (err) {
126 else 141 case TEST_OK:
127 pr_info(" Ok\n"); 142 pr_info(" Ok\n");
143 break;
144 case TEST_SKIP:
145 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
146 break;
147 case TEST_FAIL:
148 default:
149 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
150 break;
151 }
128 } 152 }
129 153
130 return 0; 154 return 0;
@@ -152,11 +176,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
152 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 176 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
153 NULL, 177 NULL,
154 }; 178 };
179 const char *skip = NULL;
155 const struct option test_options[] = { 180 const struct option test_options[] = {
181 OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
156 OPT_INCR('v', "verbose", &verbose, 182 OPT_INCR('v', "verbose", &verbose,
157 "be more verbose (show symbol address, etc)"), 183 "be more verbose (show symbol address, etc)"),
158 OPT_END() 184 OPT_END()
159 }; 185 };
186 struct intlist *skiplist = NULL;
160 187
161 argc = parse_options(argc, argv, test_options, test_usage, 0); 188 argc = parse_options(argc, argv, test_options, test_usage, 0);
162 if (argc >= 1 && !strcmp(argv[0], "list")) 189 if (argc >= 1 && !strcmp(argv[0], "list"))
@@ -169,5 +196,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
169 if (symbol__init() < 0) 196 if (symbol__init() < 0)
170 return -1; 197 return -1;
171 198
172 return __cmd_test(argc, argv); 199 if (skip != NULL)
200 skiplist = intlist__new(skip);
201
202 return __cmd_test(argc, argv, skiplist);
173} 203}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index e61fc828a158..0fd99a9adb91 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
23 __perf_evsel__hw_cache_type_op_res_name(type, op, i, 23 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
24 name, sizeof(name)); 24 name, sizeof(name));
25 err = parse_events(evlist, name, 0); 25 err = parse_events(evlist, name);
26 if (err) 26 if (err)
27 ret = err; 27 ret = err;
28 } 28 }
@@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 for (i = 0; i < nr_names; ++i) { 72 for (i = 0; i < nr_names; ++i) {
73 err = parse_events(evlist, names[i], 0); 73 err = parse_events(evlist, names[i]);
74 if (err) { 74 if (err) {
75 pr_debug("failed to parse event '%s', err %d\n", 75 pr_debug("failed to parse event '%s', err %d\n",
76 names[i], err); 76 names[i], err);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
new file mode 100644
index 000000000000..0afd9223bde7
--- /dev/null
+++ b/tools/perf/tests/hists_link.c
@@ -0,0 +1,499 @@
1#include "perf.h"
2#include "tests.h"
3#include "debug.h"
4#include "symbol.h"
5#include "sort.h"
6#include "evsel.h"
7#include "evlist.h"
8#include "machine.h"
9#include "thread.h"
10#include "parse-events.h"
11
12static struct {
13 u32 pid;
14 const char *comm;
15} fake_threads[] = {
16 { 100, "perf" },
17 { 200, "perf" },
18 { 300, "bash" },
19};
20
21static struct {
22 u32 pid;
23 u64 start;
24 const char *filename;
25} fake_mmap_info[] = {
26 { 100, 0x40000, "perf" },
27 { 100, 0x50000, "libc" },
28 { 100, 0xf0000, "[kernel]" },
29 { 200, 0x40000, "perf" },
30 { 200, 0x50000, "libc" },
31 { 200, 0xf0000, "[kernel]" },
32 { 300, 0x40000, "bash" },
33 { 300, 0x50000, "libc" },
34 { 300, 0xf0000, "[kernel]" },
35};
36
37struct fake_sym {
38 u64 start;
39 u64 length;
40 const char *name;
41};
42
43static struct fake_sym perf_syms[] = {
44 { 700, 100, "main" },
45 { 800, 100, "run_command" },
46 { 900, 100, "cmd_record" },
47};
48
49static struct fake_sym bash_syms[] = {
50 { 700, 100, "main" },
51 { 800, 100, "xmalloc" },
52 { 900, 100, "xfree" },
53};
54
55static struct fake_sym libc_syms[] = {
56 { 700, 100, "malloc" },
57 { 800, 100, "free" },
58 { 900, 100, "realloc" },
59};
60
61static struct fake_sym kernel_syms[] = {
62 { 700, 100, "schedule" },
63 { 800, 100, "page_fault" },
64 { 900, 100, "sys_perf_event_open" },
65};
66
67static struct {
68 const char *dso_name;
69 struct fake_sym *syms;
70 size_t nr_syms;
71} fake_symbols[] = {
72 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
73 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
74 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
75 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
76};
77
78static struct machine *setup_fake_machine(struct machines *machines)
79{
80 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
81 size_t i;
82
83 if (machine == NULL) {
84 pr_debug("Not enough memory for machine setup\n");
85 return NULL;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread;
90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid);
92 if (thread == NULL)
93 goto out;
94
95 thread__set_comm(thread, fake_threads[i].comm);
96 }
97
98 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
99 union perf_event fake_mmap_event = {
100 .mmap = {
101 .header = { .misc = PERF_RECORD_MISC_USER, },
102 .pid = fake_mmap_info[i].pid,
103 .start = fake_mmap_info[i].start,
104 .len = 0x1000ULL,
105 .pgoff = 0ULL,
106 },
107 };
108
109 strcpy(fake_mmap_event.mmap.filename,
110 fake_mmap_info[i].filename);
111
112 machine__process_mmap_event(machine, &fake_mmap_event);
113 }
114
115 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
116 size_t k;
117 struct dso *dso;
118
119 dso = __dsos__findnew(&machine->user_dsos,
120 fake_symbols[i].dso_name);
121 if (dso == NULL)
122 goto out;
123
124 /* emulate dso__load() */
125 dso__set_loaded(dso, MAP__FUNCTION);
126
127 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
128 struct symbol *sym;
129 struct fake_sym *fsym = &fake_symbols[i].syms[k];
130
131 sym = symbol__new(fsym->start, fsym->length,
132 STB_GLOBAL, fsym->name);
133 if (sym == NULL)
134 goto out;
135
136 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
137 }
138 }
139
140 return machine;
141
142out:
143 pr_debug("Not enough memory for machine setup\n");
144 machine__delete_threads(machine);
145 machine__delete(machine);
146 return NULL;
147}
148
149struct sample {
150 u32 pid;
151 u64 ip;
152 struct thread *thread;
153 struct map *map;
154 struct symbol *sym;
155};
156
157static struct sample fake_common_samples[] = {
158 /* perf [kernel] schedule() */
159 { .pid = 100, .ip = 0xf0000 + 700, },
160 /* perf [perf] main() */
161 { .pid = 200, .ip = 0x40000 + 700, },
162 /* perf [perf] cmd_record() */
163 { .pid = 200, .ip = 0x40000 + 900, },
164 /* bash [bash] xmalloc() */
165 { .pid = 300, .ip = 0x40000 + 800, },
166 /* bash [libc] malloc() */
167 { .pid = 300, .ip = 0x50000 + 700, },
168};
169
170static struct sample fake_samples[][5] = {
171 {
172 /* perf [perf] run_command() */
173 { .pid = 100, .ip = 0x40000 + 800, },
174 /* perf [libc] malloc() */
175 { .pid = 100, .ip = 0x50000 + 700, },
176 /* perf [kernel] page_fault() */
177 { .pid = 100, .ip = 0xf0000 + 800, },
178 /* perf [kernel] sys_perf_event_open() */
179 { .pid = 200, .ip = 0xf0000 + 900, },
180 /* bash [libc] free() */
181 { .pid = 300, .ip = 0x50000 + 800, },
182 },
183 {
184 /* perf [libc] free() */
185 { .pid = 200, .ip = 0x50000 + 800, },
186 /* bash [libc] malloc() */
187 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */
188 /* bash [bash] xfee() */
189 { .pid = 300, .ip = 0x40000 + 900, },
190 /* bash [libc] realloc() */
191 { .pid = 300, .ip = 0x50000 + 900, },
192 /* bash [kernel] page_fault() */
193 { .pid = 300, .ip = 0xf0000 + 800, },
194 },
195};
196
197static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
198{
199 struct perf_evsel *evsel;
200 struct addr_location al;
201 struct hist_entry *he;
202 struct perf_sample sample = { .cpu = 0, };
203 size_t i = 0, k;
204
205 /*
206 * each evsel will have 10 samples - 5 common and 5 distinct.
207 * However the second evsel also has a collapsed entry for
208 * "bash [libc] malloc" so total 9 entries will be in the tree.
209 */
210 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = {
213 .ip = {
214 .header = {
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 },
220 };
221
222 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample, 0) < 0)
224 goto out;
225
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
227 if (he == NULL)
228 goto out;
229
230 fake_common_samples[k].thread = al.thread;
231 fake_common_samples[k].map = al.map;
232 fake_common_samples[k].sym = al.sym;
233 }
234
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = {
237 .ip = {
238 .header = {
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 },
244 };
245
246 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample, 0) < 0)
248 goto out;
249
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
251 if (he == NULL)
252 goto out;
253
254 fake_samples[i][k].thread = al.thread;
255 fake_samples[i][k].map = al.map;
256 fake_samples[i][k].sym = al.sym;
257 }
258 i++;
259 }
260
261 return 0;
262
263out:
264 pr_debug("Not enough memory for adding a hist entry\n");
265 return -1;
266}
267
268static int find_sample(struct sample *samples, size_t nr_samples,
269 struct thread *t, struct map *m, struct symbol *s)
270{
271 while (nr_samples--) {
272 if (samples->thread == t && samples->map == m &&
273 samples->sym == s)
274 return 1;
275 samples++;
276 }
277 return 0;
278}
279
280static int __validate_match(struct hists *hists)
281{
282 size_t count = 0;
283 struct rb_root *root;
284 struct rb_node *node;
285
286 /*
287 * Only entries from fake_common_samples should have a pair.
288 */
289 if (sort__need_collapse)
290 root = &hists->entries_collapsed;
291 else
292 root = hists->entries_in;
293
294 node = rb_first(root);
295 while (node) {
296 struct hist_entry *he;
297
298 he = rb_entry(node, struct hist_entry, rb_node_in);
299
300 if (hist_entry__has_pairs(he)) {
301 if (find_sample(fake_common_samples,
302 ARRAY_SIZE(fake_common_samples),
303 he->thread, he->ms.map, he->ms.sym)) {
304 count++;
305 } else {
306 pr_debug("Can't find the matched entry\n");
307 return -1;
308 }
309 }
310
311 node = rb_next(node);
312 }
313
314 if (count != ARRAY_SIZE(fake_common_samples)) {
315 pr_debug("Invalid count for matched entries: %zd of %zd\n",
316 count, ARRAY_SIZE(fake_common_samples));
317 return -1;
318 }
319
320 return 0;
321}
322
323static int validate_match(struct hists *leader, struct hists *other)
324{
325 return __validate_match(leader) || __validate_match(other);
326}
327
328static int __validate_link(struct hists *hists, int idx)
329{
330 size_t count = 0;
331 size_t count_pair = 0;
332 size_t count_dummy = 0;
333 struct rb_root *root;
334 struct rb_node *node;
335
336 /*
337 * Leader hists (idx = 0) will have dummy entries from other,
338 * and some entries will have no pair. However every entry
339 * in other hists should have (dummy) pair.
340 */
341 if (sort__need_collapse)
342 root = &hists->entries_collapsed;
343 else
344 root = hists->entries_in;
345
346 node = rb_first(root);
347 while (node) {
348 struct hist_entry *he;
349
350 he = rb_entry(node, struct hist_entry, rb_node_in);
351
352 if (hist_entry__has_pairs(he)) {
353 if (!find_sample(fake_common_samples,
354 ARRAY_SIZE(fake_common_samples),
355 he->thread, he->ms.map, he->ms.sym) &&
356 !find_sample(fake_samples[idx],
357 ARRAY_SIZE(fake_samples[idx]),
358 he->thread, he->ms.map, he->ms.sym)) {
359 count_dummy++;
360 }
361 count_pair++;
362 } else if (idx) {
363 pr_debug("A entry from the other hists should have pair\n");
364 return -1;
365 }
366
367 count++;
368 node = rb_next(node);
369 }
370
371 /*
372 * Note that we have a entry collapsed in the other (idx = 1) hists.
373 */
374 if (idx == 0) {
375 if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
376 pr_debug("Invalid count of dummy entries: %zd of %zd\n",
377 count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
378 return -1;
379 }
380 if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
381 pr_debug("Invalid count of total leader entries: %zd of %zd\n",
382 count, count_pair + ARRAY_SIZE(fake_samples[0]));
383 return -1;
384 }
385 } else {
386 if (count != count_pair) {
387 pr_debug("Invalid count of total other entries: %zd of %zd\n",
388 count, count_pair);
389 return -1;
390 }
391 if (count_dummy > 0) {
392 pr_debug("Other hists should not have dummy entries: %zd\n",
393 count_dummy);
394 return -1;
395 }
396 }
397
398 return 0;
399}
400
401static int validate_link(struct hists *leader, struct hists *other)
402{
403 return __validate_link(leader, 0) || __validate_link(other, 1);
404}
405
406static void print_hists(struct hists *hists)
407{
408 int i = 0;
409 struct rb_root *root;
410 struct rb_node *node;
411
412 if (sort__need_collapse)
413 root = &hists->entries_collapsed;
414 else
415 root = hists->entries_in;
416
417 pr_info("----- %s --------\n", __func__);
418 node = rb_first(root);
419 while (node) {
420 struct hist_entry *he;
421
422 he = rb_entry(node, struct hist_entry, rb_node_in);
423
424 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
425 i, he->thread->comm, he->ms.map->dso->short_name,
426 he->ms.sym->name, he->stat.period);
427
428 i++;
429 node = rb_next(node);
430 }
431}
432
433int test__hists_link(void)
434{
435 int err = -1;
436 struct machines machines;
437 struct machine *machine = NULL;
438 struct perf_evsel *evsel, *first;
439 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
440
441 if (evlist == NULL)
442 return -ENOMEM;
443
444 err = parse_events(evlist, "cpu-clock");
445 if (err)
446 goto out;
447 err = parse_events(evlist, "task-clock");
448 if (err)
449 goto out;
450
451 /* default sort order (comm,dso,sym) will be used */
452 setup_sorting(NULL, NULL);
453
454 machines__init(&machines);
455
456 /* setup threads/dso/map/symbols also */
457 machine = setup_fake_machine(&machines);
458 if (!machine)
459 goto out;
460
461 if (verbose > 1)
462 machine__fprintf(machine, stderr);
463
464 /* process sample events */
465 err = add_hist_entries(evlist, machine);
466 if (err < 0)
467 goto out;
468
469 list_for_each_entry(evsel, &evlist->entries, node) {
470 hists__collapse_resort(&evsel->hists);
471
472 if (verbose > 2)
473 print_hists(&evsel->hists);
474 }
475
476 first = perf_evlist__first(evlist);
477 evsel = perf_evlist__last(evlist);
478
479 /* match common entries */
480 hists__match(&first->hists, &evsel->hists);
481 err = validate_match(&first->hists, &evsel->hists);
482 if (err)
483 goto out;
484
485 /* link common and/or dummy entries */
486 hists__link(&first->hists, &evsel->hists);
487 err = validate_link(&first->hists, &evsel->hists);
488 if (err)
489 goto out;
490
491 err = 0;
492
493out:
494 /* tear down everything */
495 perf_evlist__delete(evlist);
496 machines__exit(&machines);
497
498 return err;
499}
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 294ffddfbf42..20acaff295d2 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,6 +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 "tests.h" 7#include "tests.h"
7#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
8 9
@@ -463,10 +464,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
463 464
464static int test__checkterms_simple(struct list_head *terms) 465static int test__checkterms_simple(struct list_head *terms)
465{ 466{
466 struct parse_events__term *term; 467 struct parse_events_term *term;
467 468
468 /* config=10 */ 469 /* config=10 */
469 term = list_entry(terms->next, struct parse_events__term, list); 470 term = list_entry(terms->next, struct parse_events_term, list);
470 TEST_ASSERT_VAL("wrong type term", 471 TEST_ASSERT_VAL("wrong type term",
471 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); 472 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
472 TEST_ASSERT_VAL("wrong type val", 473 TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +476,7 @@ static int test__checkterms_simple(struct list_head *terms)
475 TEST_ASSERT_VAL("wrong config", !term->config); 476 TEST_ASSERT_VAL("wrong config", !term->config);
476 477
477 /* config1 */ 478 /* config1 */
478 term = list_entry(term->list.next, struct parse_events__term, list); 479 term = list_entry(term->list.next, struct parse_events_term, list);
479 TEST_ASSERT_VAL("wrong type term", 480 TEST_ASSERT_VAL("wrong type term",
480 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); 481 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
481 TEST_ASSERT_VAL("wrong type val", 482 TEST_ASSERT_VAL("wrong type val",
@@ -484,7 +485,7 @@ static int test__checkterms_simple(struct list_head *terms)
484 TEST_ASSERT_VAL("wrong config", !term->config); 485 TEST_ASSERT_VAL("wrong config", !term->config);
485 486
486 /* config2=3 */ 487 /* config2=3 */
487 term = list_entry(term->list.next, struct parse_events__term, list); 488 term = list_entry(term->list.next, struct parse_events_term, list);
488 TEST_ASSERT_VAL("wrong type term", 489 TEST_ASSERT_VAL("wrong type term",
489 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); 490 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
490 TEST_ASSERT_VAL("wrong type val", 491 TEST_ASSERT_VAL("wrong type val",
@@ -493,7 +494,7 @@ static int test__checkterms_simple(struct list_head *terms)
493 TEST_ASSERT_VAL("wrong config", !term->config); 494 TEST_ASSERT_VAL("wrong config", !term->config);
494 495
495 /* umask=1*/ 496 /* umask=1*/
496 term = list_entry(term->list.next, struct parse_events__term, list); 497 term = list_entry(term->list.next, struct parse_events_term, list);
497 TEST_ASSERT_VAL("wrong type term", 498 TEST_ASSERT_VAL("wrong type term",
498 term->type_term == PARSE_EVENTS__TERM_TYPE_USER); 499 term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
499 TEST_ASSERT_VAL("wrong type val", 500 TEST_ASSERT_VAL("wrong type val",
@@ -782,13 +783,70 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
782 return 0; 783 return 0;
783} 784}
784 785
785struct test__event_st { 786static int count_tracepoints(void)
787{
788 char events_path[PATH_MAX];
789 struct dirent *events_ent;
790 DIR *events_dir;
791 int cnt = 0;
792
793 scnprintf(events_path, PATH_MAX, "%s/tracing/events",
794 debugfs_find_mountpoint());
795
796 events_dir = opendir(events_path);
797
798 TEST_ASSERT_VAL("Can't open events dir", events_dir);
799
800 while ((events_ent = readdir(events_dir))) {
801 char sys_path[PATH_MAX];
802 struct dirent *sys_ent;
803 DIR *sys_dir;
804
805 if (!strcmp(events_ent->d_name, ".")
806 || !strcmp(events_ent->d_name, "..")
807 || !strcmp(events_ent->d_name, "enable")
808 || !strcmp(events_ent->d_name, "header_event")
809 || !strcmp(events_ent->d_name, "header_page"))
810 continue;
811
812 scnprintf(sys_path, PATH_MAX, "%s/%s",
813 events_path, events_ent->d_name);
814
815 sys_dir = opendir(sys_path);
816 TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
817
818 while ((sys_ent = readdir(sys_dir))) {
819 if (!strcmp(sys_ent->d_name, ".")
820 || !strcmp(sys_ent->d_name, "..")
821 || !strcmp(sys_ent->d_name, "enable")
822 || !strcmp(sys_ent->d_name, "filter"))
823 continue;
824
825 cnt++;
826 }
827
828 closedir(sys_dir);
829 }
830
831 closedir(events_dir);
832 return cnt;
833}
834
835static int test__all_tracepoints(struct perf_evlist *evlist)
836{
837 TEST_ASSERT_VAL("wrong events count",
838 count_tracepoints() == evlist->nr_entries);
839
840 return test__checkevent_tracepoint_multi(evlist);
841}
842
843struct evlist_test {
786 const char *name; 844 const char *name;
787 __u32 type; 845 __u32 type;
788 int (*check)(struct perf_evlist *evlist); 846 int (*check)(struct perf_evlist *evlist);
789}; 847};
790 848
791static struct test__event_st test__events[] = { 849static struct evlist_test test__events[] = {
792 [0] = { 850 [0] = {
793 .name = "syscalls:sys_enter_open", 851 .name = "syscalls:sys_enter_open",
794 .check = test__checkevent_tracepoint, 852 .check = test__checkevent_tracepoint,
@@ -921,9 +979,13 @@ static struct test__event_st test__events[] = {
921 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 979 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
922 .check = test__group5, 980 .check = test__group5,
923 }, 981 },
982 [33] = {
983 .name = "*:*",
984 .check = test__all_tracepoints,
985 },
924}; 986};
925 987
926static struct test__event_st test__events_pmu[] = { 988static struct evlist_test test__events_pmu[] = {
927 [0] = { 989 [0] = {
928 .name = "cpu/config=10,config1,config2=3,period=1000/u", 990 .name = "cpu/config=10,config1,config2=3,period=1000/u",
929 .check = test__checkevent_pmu, 991 .check = test__checkevent_pmu,
@@ -934,20 +996,20 @@ static struct test__event_st test__events_pmu[] = {
934 }, 996 },
935}; 997};
936 998
937struct test__term { 999struct terms_test {
938 const char *str; 1000 const char *str;
939 __u32 type; 1001 __u32 type;
940 int (*check)(struct list_head *terms); 1002 int (*check)(struct list_head *terms);
941}; 1003};
942 1004
943static struct test__term test__terms[] = { 1005static struct terms_test test__terms[] = {
944 [0] = { 1006 [0] = {
945 .str = "config=10,config1,config2=3,umask=1", 1007 .str = "config=10,config1,config2=3,umask=1",
946 .check = test__checkterms_simple, 1008 .check = test__checkterms_simple,
947 }, 1009 },
948}; 1010};
949 1011
950static int test_event(struct test__event_st *e) 1012static int test_event(struct evlist_test *e)
951{ 1013{
952 struct perf_evlist *evlist; 1014 struct perf_evlist *evlist;
953 int ret; 1015 int ret;
@@ -956,7 +1018,7 @@ static int test_event(struct test__event_st *e)
956 if (evlist == NULL) 1018 if (evlist == NULL)
957 return -ENOMEM; 1019 return -ENOMEM;
958 1020
959 ret = parse_events(evlist, e->name, 0); 1021 ret = parse_events(evlist, e->name);
960 if (ret) { 1022 if (ret) {
961 pr_debug("failed to parse event '%s', err %d\n", 1023 pr_debug("failed to parse event '%s', err %d\n",
962 e->name, ret); 1024 e->name, ret);
@@ -969,13 +1031,13 @@ static int test_event(struct test__event_st *e)
969 return ret; 1031 return ret;
970} 1032}
971 1033
972static int test_events(struct test__event_st *events, unsigned cnt) 1034static int test_events(struct evlist_test *events, unsigned cnt)
973{ 1035{
974 int ret1, ret2 = 0; 1036 int ret1, ret2 = 0;
975 unsigned i; 1037 unsigned i;
976 1038
977 for (i = 0; i < cnt; i++) { 1039 for (i = 0; i < cnt; i++) {
978 struct test__event_st *e = &events[i]; 1040 struct evlist_test *e = &events[i];
979 1041
980 pr_debug("running test %d '%s'\n", i, e->name); 1042 pr_debug("running test %d '%s'\n", i, e->name);
981 ret1 = test_event(e); 1043 ret1 = test_event(e);
@@ -986,7 +1048,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
986 return ret2; 1048 return ret2;
987} 1049}
988 1050
989static int test_term(struct test__term *t) 1051static int test_term(struct terms_test *t)
990{ 1052{
991 struct list_head *terms; 1053 struct list_head *terms;
992 int ret; 1054 int ret;
@@ -1010,13 +1072,13 @@ static int test_term(struct test__term *t)
1010 return ret; 1072 return ret;
1011} 1073}
1012 1074
1013static int test_terms(struct test__term *terms, unsigned cnt) 1075static int test_terms(struct terms_test *terms, unsigned cnt)
1014{ 1076{
1015 int ret = 0; 1077 int ret = 0;
1016 unsigned i; 1078 unsigned i;
1017 1079
1018 for (i = 0; i < cnt; i++) { 1080 for (i = 0; i < cnt; i++) {
1019 struct test__term *t = &terms[i]; 1081 struct terms_test *t = &terms[i];
1020 1082
1021 pr_debug("running test %d '%s'\n", i, t->str); 1083 pr_debug("running test %d '%s'\n", i, t->str);
1022 ret = test_term(t); 1084 ret = test_term(t);
@@ -1067,7 +1129,7 @@ static int test_pmu_events(void)
1067 1129
1068 while (!ret && (ent = readdir(dir))) { 1130 while (!ret && (ent = readdir(dir))) {
1069#define MAX_NAME 100 1131#define MAX_NAME 100
1070 struct test__event_st e; 1132 struct evlist_test e;
1071 char name[MAX_NAME]; 1133 char name[MAX_NAME];
1072 1134
1073 if (!strcmp(ent->d_name, ".") || 1135 if (!strcmp(ent->d_name, ".") ||
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index a5f379863b8f..12b322fa3475 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -19,10 +19,8 @@ static struct test_format {
19 { "krava23", "config2:28-29,38\n", }, 19 { "krava23", "config2:28-29,38\n", },
20}; 20};
21 21
22#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
23
24/* Simulated users input. */ 22/* Simulated users input. */
25static struct parse_events__term test_terms[] = { 23static struct parse_events_term test_terms[] = {
26 { 24 {
27 .config = (char *) "krava01", 25 .config = (char *) "krava01",
28 .val.num = 15, 26 .val.num = 15,
@@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = {
78 .type_term = PARSE_EVENTS__TERM_TYPE_USER, 76 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
79 }, 77 },
80}; 78};
81#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
82 79
83/* 80/*
84 * Prepare format directory data, exported by kernel 81 * Prepare format directory data, exported by kernel
@@ -93,7 +90,7 @@ static char *test_format_dir_get(void)
93 if (!mkdtemp(dir)) 90 if (!mkdtemp(dir))
94 return NULL; 91 return NULL;
95 92
96 for (i = 0; i < TEST_FORMATS_CNT; i++) { 93 for (i = 0; i < ARRAY_SIZE(test_formats); i++) {
97 static char name[PATH_MAX]; 94 static char name[PATH_MAX];
98 struct test_format *format = &test_formats[i]; 95 struct test_format *format = &test_formats[i];
99 FILE *file; 96 FILE *file;
@@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void)
130 static LIST_HEAD(terms); 127 static LIST_HEAD(terms);
131 unsigned int i; 128 unsigned int i;
132 129
133 for (i = 0; i < TERMS_CNT; i++) 130 for (i = 0; i < ARRAY_SIZE(test_terms); i++)
134 list_add_tail(&test_terms[i].list, &terms); 131 list_add_tail(&test_terms[i].list, &terms);
135 132
136 return &terms; 133 return &terms;
137} 134}
138 135
139#undef TERMS_CNT
140
141int test__pmu(void) 136int test__pmu(void)
142{ 137{
143 char *format = test_format_dir_get(); 138 char *format = test_format_dir_get();
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
new file mode 100644
index 000000000000..7760277c6def
--- /dev/null
+++ b/tools/perf/tests/python-use.c
@@ -0,0 +1,23 @@
1/*
2 * Just test if we can load the python binding.
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include "tests.h"
8
9extern int verbose;
10
11int test__python_use(void)
12{
13 char *cmd;
14 int ret;
15
16 if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s",
17 PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0)
18 return -1;
19
20 ret = system(cmd) ? -1 : 0;
21 free(cmd);
22 return ret;
23}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0fd94657960e..5de0be1ff4b6 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,12 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4enum {
5 TEST_OK = 0,
6 TEST_FAIL = -1,
7 TEST_SKIP = -2,
8};
9
4/* Tests */ 10/* Tests */
5int test__vmlinux_matches_kallsyms(void); 11int test__vmlinux_matches_kallsyms(void);
6int test__open_syscall_event(void); 12int test__open_syscall_event(void);
@@ -15,5 +21,7 @@ int test__pmu(void);
15int test__attr(void); 21int test__attr(void);
16int test__dso_data(void); 22int test__dso_data(void);
17int test__parse_events(void); 23int test__parse_events(void);
24int test__hists_link(void);
25int test__python_use(void);
18 26
19#endif /* TESTS_H */ 27#endif /* TESTS_H */
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 0d1cdbee2f59..a1a8442829b4 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void)
101 */ 101 */
102 if (machine__load_vmlinux_path(&vmlinux, type, 102 if (machine__load_vmlinux_path(&vmlinux, type,
103 vmlinux_matches_kallsyms_filter) <= 0) { 103 vmlinux_matches_kallsyms_filter) <= 0) {
104 pr_debug("machine__load_vmlinux_path "); 104 pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
105 err = TEST_SKIP;
105 goto out; 106 goto out;
106 } 107 }
107 108
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 4aeb7d5df939..588bcb2d008b 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -471,7 +471,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
471 return row; 471 return row;
472} 472}
473 473
474static struct ui_browser__colorset { 474static struct ui_browser_colorset {
475 const char *name, *fg, *bg; 475 const char *name, *fg, *bg;
476 int colorset; 476 int colorset;
477} ui_browser__colorsets[] = { 477} ui_browser__colorsets[] = {
@@ -706,7 +706,7 @@ void ui_browser__init(void)
706 perf_config(ui_browser__color_config, NULL); 706 perf_config(ui_browser__color_config, NULL);
707 707
708 while (ui_browser__colorsets[i].name) { 708 while (ui_browser__colorsets[i].name) {
709 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 709 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
710 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 710 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
711 } 711 }
712 712
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 5dab3ca96980..7dca1555c610 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
182 ab->selection = dl; 182 ab->selection = dl;
183} 183}
184 184
185static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
186{
187 if (!dl || !dl->ins || !ins__is_jump(dl->ins)
188 || !disasm_line__has_offset(dl)
189 || dl->ops.target.offset >= symbol__size(sym))
190 return false;
191
192 return true;
193}
194
185static void annotate_browser__draw_current_jump(struct ui_browser *browser) 195static void annotate_browser__draw_current_jump(struct ui_browser *browser)
186{ 196{
187 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 197 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -195,8 +205,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
195 if (strstr(sym->name, "@plt")) 205 if (strstr(sym->name, "@plt"))
196 return; 206 return;
197 207
198 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || 208 if (!disasm_line__is_valid_jump(cursor, sym))
199 !disasm_line__has_offset(cursor))
200 return; 209 return;
201 210
202 target = ab->offsets[cursor->ops.target.offset]; 211 target = ab->offsets[cursor->ops.target.offset];
@@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
788 struct disasm_line *dl = browser->offsets[offset], *dlt; 797 struct disasm_line *dl = browser->offsets[offset], *dlt;
789 struct browser_disasm_line *bdlt; 798 struct browser_disasm_line *bdlt;
790 799
791 if (!dl || !dl->ins || !ins__is_jump(dl->ins) || 800 if (!disasm_line__is_valid_jump(dl, sym))
792 !disasm_line__has_offset(dl))
793 continue; 801 continue;
794 802
795 if (dl->ops.target.offset >= size) {
796 ui__error("jump to after symbol!\n"
797 "size: %zx, jump target: %" PRIx64,
798 size, dl->ops.target.offset);
799 continue;
800 }
801
802 dlt = browser->offsets[dl->ops.target.offset]; 803 dlt = browser->offsets[dl->ops.target.offset];
803 /* 804 /*
804 * FIXME: Oops, no jump target? Buggy disassembler? Or do we 805 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -921,11 +922,11 @@ out_free_offsets:
921 922
922#define ANNOTATE_CFG(n) \ 923#define ANNOTATE_CFG(n) \
923 { .name = #n, .value = &annotate_browser__opts.n, } 924 { .name = #n, .value = &annotate_browser__opts.n, }
924 925
925/* 926/*
926 * Keep the entries sorted, they are bsearch'ed 927 * Keep the entries sorted, they are bsearch'ed
927 */ 928 */
928static struct annotate__config { 929static struct annotate_config {
929 const char *name; 930 const char *name;
930 bool *value; 931 bool *value;
931} annotate__configs[] = { 932} annotate__configs[] = {
@@ -939,7 +940,7 @@ static struct annotate__config {
939 940
940static int annotate_config__cmp(const void *name, const void *cfgp) 941static int annotate_config__cmp(const void *name, const void *cfgp)
941{ 942{
942 const struct annotate__config *cfg = cfgp; 943 const struct annotate_config *cfg = cfgp;
943 944
944 return strcmp(name, cfg->name); 945 return strcmp(name, cfg->name);
945} 946}
@@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
947static int annotate__config(const char *var, const char *value, 948static int annotate__config(const char *var, const char *value,
948 void *data __maybe_unused) 949 void *data __maybe_unused)
949{ 950{
950 struct annotate__config *cfg; 951 struct annotate_config *cfg;
951 const char *name; 952 const char *name;
952 953
953 if (prefixcmp(var, "annotate.") != 0) 954 if (prefixcmp(var, "annotate.") != 0)
@@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value,
955 956
956 name = var + 9; 957 name = var + 9;
957 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 958 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
958 sizeof(struct annotate__config), annotate_config__cmp); 959 sizeof(struct annotate_config), annotate_config__cmp);
959 960
960 if (cfg == NULL) 961 if (cfg == NULL)
961 return -1; 962 return -1;
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index e59ba337f494..c95012cdb438 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -8,15 +8,13 @@
8 8
9#include <signal.h> 9#include <signal.h>
10 10
11#define MAX_COLUMNS 32 11void perf_gtk__signal(int sig)
12
13static void perf_gtk__signal(int sig)
14{ 12{
15 perf_gtk__exit(false); 13 perf_gtk__exit(false);
16 psignal(sig, "perf"); 14 psignal(sig, "perf");
17} 15}
18 16
19static void perf_gtk__resize_window(GtkWidget *window) 17void perf_gtk__resize_window(GtkWidget *window)
20{ 18{
21 GdkRectangle rect; 19 GdkRectangle rect;
22 GdkScreen *screen; 20 GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
36 gtk_window_resize(GTK_WINDOW(window), width, height); 34 gtk_window_resize(GTK_WINDOW(window), width, height);
37} 35}
38 36
39static const char *perf_gtk__get_percent_color(double percent) 37const char *perf_gtk__get_percent_color(double percent)
40{ 38{
41 if (percent >= MIN_RED) 39 if (percent >= MIN_RED)
42 return "<span fgcolor='red'>"; 40 return "<span fgcolor='red'>";
@@ -45,147 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
45 return NULL; 43 return NULL;
46} 44}
47 45
48#define HPP__COLOR_FN(_name, _field) \
49static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
50 struct hist_entry *he) \
51{ \
52 struct hists *hists = he->hists; \
53 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
54 const char *markup; \
55 int ret = 0; \
56 \
57 markup = perf_gtk__get_percent_color(percent); \
58 if (markup) \
59 ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
60 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
61 if (markup) \
62 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
63 \
64 return ret; \
65}
66
67HPP__COLOR_FN(overhead, period)
68HPP__COLOR_FN(overhead_sys, period_sys)
69HPP__COLOR_FN(overhead_us, period_us)
70HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
71HPP__COLOR_FN(overhead_guest_us, period_guest_us)
72
73#undef HPP__COLOR_FN
74
75void perf_gtk__init_hpp(void)
76{
77 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
78
79 perf_hpp__init();
80
81 perf_hpp__format[PERF_HPP__OVERHEAD].color =
82 perf_gtk__hpp_color_overhead;
83 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
84 perf_gtk__hpp_color_overhead_sys;
85 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
86 perf_gtk__hpp_color_overhead_us;
87 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
88 perf_gtk__hpp_color_overhead_guest_sys;
89 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
90 perf_gtk__hpp_color_overhead_guest_us;
91}
92
93static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
94{
95 struct perf_hpp_fmt *fmt;
96 GType col_types[MAX_COLUMNS];
97 GtkCellRenderer *renderer;
98 struct sort_entry *se;
99 GtkListStore *store;
100 struct rb_node *nd;
101 GtkWidget *view;
102 int col_idx;
103 int nr_cols;
104 char s[512];
105
106 struct perf_hpp hpp = {
107 .buf = s,
108 .size = sizeof(s),
109 };
110
111 nr_cols = 0;
112
113 perf_hpp__for_each_format(fmt)
114 col_types[nr_cols++] = G_TYPE_STRING;
115
116 list_for_each_entry(se, &hist_entry__sort_list, list) {
117 if (se->elide)
118 continue;
119
120 col_types[nr_cols++] = G_TYPE_STRING;
121 }
122
123 store = gtk_list_store_newv(nr_cols, col_types);
124
125 view = gtk_tree_view_new();
126
127 renderer = gtk_cell_renderer_text_new();
128
129 col_idx = 0;
130
131 perf_hpp__for_each_format(fmt) {
132 fmt->header(&hpp);
133 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
134 -1, s,
135 renderer, "markup",
136 col_idx++, NULL);
137 }
138
139 list_for_each_entry(se, &hist_entry__sort_list, list) {
140 if (se->elide)
141 continue;
142
143 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
144 -1, se->se_header,
145 renderer, "text",
146 col_idx++, NULL);
147 }
148
149 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
150
151 g_object_unref(GTK_TREE_MODEL(store));
152
153 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
154 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
155 GtkTreeIter iter;
156
157 if (h->filtered)
158 continue;
159
160 gtk_list_store_append(store, &iter);
161
162 col_idx = 0;
163
164 perf_hpp__for_each_format(fmt) {
165 if (fmt->color)
166 fmt->color(&hpp, h);
167 else
168 fmt->entry(&hpp, h);
169
170 gtk_list_store_set(store, &iter, col_idx++, s, -1);
171 }
172
173 list_for_each_entry(se, &hist_entry__sort_list, list) {
174 if (se->elide)
175 continue;
176
177 se->se_snprintf(h, s, ARRAY_SIZE(s),
178 hists__col_len(hists, se->se_width_idx));
179
180 gtk_list_store_set(store, &iter, col_idx++, s, -1);
181 }
182 }
183
184 gtk_container_add(GTK_CONTAINER(window), view);
185}
186
187#ifdef HAVE_GTK_INFO_BAR 46#ifdef HAVE_GTK_INFO_BAR
188static GtkWidget *perf_gtk__setup_info_bar(void) 47GtkWidget *perf_gtk__setup_info_bar(void)
189{ 48{
190 GtkWidget *info_bar; 49 GtkWidget *info_bar;
191 GtkWidget *label; 50 GtkWidget *label;
@@ -212,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
212} 71}
213#endif 72#endif
214 73
215static GtkWidget *perf_gtk__setup_statusbar(void) 74GtkWidget *perf_gtk__setup_statusbar(void)
216{ 75{
217 GtkWidget *stbar; 76 GtkWidget *stbar;
218 unsigned ctxid; 77 unsigned ctxid;
@@ -226,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
226 85
227 return stbar; 86 return stbar;
228} 87}
229
230int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
231 const char *help,
232 struct hist_browser_timer *hbt __maybe_unused)
233{
234 struct perf_evsel *pos;
235 GtkWidget *vbox;
236 GtkWidget *notebook;
237 GtkWidget *info_bar;
238 GtkWidget *statbar;
239 GtkWidget *window;
240
241 signal(SIGSEGV, perf_gtk__signal);
242 signal(SIGFPE, perf_gtk__signal);
243 signal(SIGINT, perf_gtk__signal);
244 signal(SIGQUIT, perf_gtk__signal);
245 signal(SIGTERM, perf_gtk__signal);
246
247 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
248
249 gtk_window_set_title(GTK_WINDOW(window), "perf report");
250
251 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
252
253 pgctx = perf_gtk__activate_context(window);
254 if (!pgctx)
255 return -1;
256
257 vbox = gtk_vbox_new(FALSE, 0);
258
259 notebook = gtk_notebook_new();
260
261 list_for_each_entry(pos, &evlist->entries, node) {
262 struct hists *hists = &pos->hists;
263 const char *evname = perf_evsel__name(pos);
264 GtkWidget *scrolled_window;
265 GtkWidget *tab_label;
266
267 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
268
269 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
270 GTK_POLICY_AUTOMATIC,
271 GTK_POLICY_AUTOMATIC);
272
273 perf_gtk__show_hists(scrolled_window, hists);
274
275 tab_label = gtk_label_new(evname);
276
277 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
278 }
279
280 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
281
282 info_bar = perf_gtk__setup_info_bar();
283 if (info_bar)
284 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
285
286 statbar = perf_gtk__setup_statusbar();
287 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
288
289 gtk_container_add(GTK_CONTAINER(window), vbox);
290
291 gtk_widget_show_all(window);
292
293 perf_gtk__resize_window(window);
294
295 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
296
297 ui_helpline__push(help);
298
299 gtk_main();
300
301 perf_gtk__deactivate_context(&pgctx);
302
303 return 0;
304}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 856320e2cc05..5d3693754828 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -33,7 +33,14 @@ void perf_gtk__init_helpline(void);
33void perf_gtk__init_progress(void); 33void perf_gtk__init_progress(void);
34void perf_gtk__init_hpp(void); 34void perf_gtk__init_hpp(void);
35 35
36#ifndef HAVE_GTK_INFO_BAR 36void perf_gtk__signal(int sig);
37void perf_gtk__resize_window(GtkWidget *window);
38const char *perf_gtk__get_percent_color(double percent);
39GtkWidget *perf_gtk__setup_statusbar(void);
40
41#ifdef HAVE_GTK_INFO_BAR
42GtkWidget *perf_gtk__setup_info_bar(void);
43#else
37static inline GtkWidget *perf_gtk__setup_info_bar(void) 44static inline GtkWidget *perf_gtk__setup_info_bar(void)
38{ 45{
39 return NULL; 46 return NULL;
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644
index 000000000000..c03da79d524f
--- /dev/null
+++ b/tools/perf/ui/gtk/hists.c
@@ -0,0 +1,226 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "../helpline.h"
7#include "gtk.h"
8
9#define MAX_COLUMNS 32
10
11#define HPP__COLOR_FN(_name, _field) \
12static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
13 struct hist_entry *he) \
14{ \
15 struct hists *hists = he->hists; \
16 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
17 const char *markup; \
18 int ret = 0; \
19 \
20 markup = perf_gtk__get_percent_color(percent); \
21 if (markup) \
22 ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
23 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
24 if (markup) \
25 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
26 \
27 return ret; \
28}
29
30HPP__COLOR_FN(overhead, period)
31HPP__COLOR_FN(overhead_sys, period_sys)
32HPP__COLOR_FN(overhead_us, period_us)
33HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
34HPP__COLOR_FN(overhead_guest_us, period_guest_us)
35
36#undef HPP__COLOR_FN
37
38
39void perf_gtk__init_hpp(void)
40{
41 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
42
43 perf_hpp__init();
44
45 perf_hpp__format[PERF_HPP__OVERHEAD].color =
46 perf_gtk__hpp_color_overhead;
47 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
48 perf_gtk__hpp_color_overhead_sys;
49 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
50 perf_gtk__hpp_color_overhead_us;
51 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
52 perf_gtk__hpp_color_overhead_guest_sys;
53 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
54 perf_gtk__hpp_color_overhead_guest_us;
55}
56
57static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
58{
59 struct perf_hpp_fmt *fmt;
60 GType col_types[MAX_COLUMNS];
61 GtkCellRenderer *renderer;
62 struct sort_entry *se;
63 GtkListStore *store;
64 struct rb_node *nd;
65 GtkWidget *view;
66 int col_idx;
67 int nr_cols;
68 char s[512];
69
70 struct perf_hpp hpp = {
71 .buf = s,
72 .size = sizeof(s),
73 };
74
75 nr_cols = 0;
76
77 perf_hpp__for_each_format(fmt)
78 col_types[nr_cols++] = G_TYPE_STRING;
79
80 list_for_each_entry(se, &hist_entry__sort_list, list) {
81 if (se->elide)
82 continue;
83
84 col_types[nr_cols++] = G_TYPE_STRING;
85 }
86
87 store = gtk_list_store_newv(nr_cols, col_types);
88
89 view = gtk_tree_view_new();
90
91 renderer = gtk_cell_renderer_text_new();
92
93 col_idx = 0;
94
95 perf_hpp__for_each_format(fmt) {
96 fmt->header(&hpp);
97
98 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
99 -1, s,
100 renderer, "markup",
101 col_idx++, NULL);
102 }
103
104 list_for_each_entry(se, &hist_entry__sort_list, list) {
105 if (se->elide)
106 continue;
107
108 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
109 -1, se->se_header,
110 renderer, "text",
111 col_idx++, NULL);
112 }
113
114 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
115
116 g_object_unref(GTK_TREE_MODEL(store));
117
118 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
119 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
120 GtkTreeIter iter;
121
122 if (h->filtered)
123 continue;
124
125 gtk_list_store_append(store, &iter);
126
127 col_idx = 0;
128
129 perf_hpp__for_each_format(fmt) {
130 if (fmt->color)
131 fmt->color(&hpp, h);
132 else
133 fmt->entry(&hpp, h);
134
135 gtk_list_store_set(store, &iter, col_idx++, s, -1);
136 }
137
138 list_for_each_entry(se, &hist_entry__sort_list, list) {
139 if (se->elide)
140 continue;
141
142 se->se_snprintf(h, s, ARRAY_SIZE(s),
143 hists__col_len(hists, se->se_width_idx));
144
145 gtk_list_store_set(store, &iter, col_idx++, s, -1);
146 }
147 }
148
149 gtk_container_add(GTK_CONTAINER(window), view);
150}
151
152int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
153 const char *help,
154 struct hist_browser_timer *hbt __maybe_unused)
155{
156 struct perf_evsel *pos;
157 GtkWidget *vbox;
158 GtkWidget *notebook;
159 GtkWidget *info_bar;
160 GtkWidget *statbar;
161 GtkWidget *window;
162
163 signal(SIGSEGV, perf_gtk__signal);
164 signal(SIGFPE, perf_gtk__signal);
165 signal(SIGINT, perf_gtk__signal);
166 signal(SIGQUIT, perf_gtk__signal);
167 signal(SIGTERM, perf_gtk__signal);
168
169 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
170
171 gtk_window_set_title(GTK_WINDOW(window), "perf report");
172
173 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
174
175 pgctx = perf_gtk__activate_context(window);
176 if (!pgctx)
177 return -1;
178
179 vbox = gtk_vbox_new(FALSE, 0);
180
181 notebook = gtk_notebook_new();
182
183 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
184
185 info_bar = perf_gtk__setup_info_bar();
186 if (info_bar)
187 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
188
189 statbar = perf_gtk__setup_statusbar();
190 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
191
192 gtk_container_add(GTK_CONTAINER(window), vbox);
193
194 list_for_each_entry(pos, &evlist->entries, node) {
195 struct hists *hists = &pos->hists;
196 const char *evname = perf_evsel__name(pos);
197 GtkWidget *scrolled_window;
198 GtkWidget *tab_label;
199
200 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
201
202 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
203 GTK_POLICY_AUTOMATIC,
204 GTK_POLICY_AUTOMATIC);
205
206 perf_gtk__show_hists(scrolled_window, hists);
207
208 tab_label = gtk_label_new(evname);
209
210 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
211 }
212
213 gtk_widget_show_all(window);
214
215 perf_gtk__resize_window(window);
216
217 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
218
219 ui_helpline__push(help);
220
221 gtk_main();
222
223 perf_gtk__deactivate_context(&pgctx);
224
225 return 0;
226}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 0eae3b2c32f2..f9798298e3e0 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -459,7 +459,7 @@ out:
459 return ret; 459 return ret;
460} 460}
461 461
462size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) 462size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
463{ 463{
464 int i; 464 int i;
465 size_t ret = 0; 465 size_t ret = 0;
@@ -467,7 +467,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
467 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 467 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
468 const char *name; 468 const char *name;
469 469
470 if (hists->stats.nr_events[i] == 0) 470 if (stats->nr_events[i] == 0)
471 continue; 471 continue;
472 472
473 name = perf_event__name(i); 473 name = perf_event__name(i);
@@ -475,7 +475,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
475 continue; 475 continue;
476 476
477 ret += fprintf(fp, "%16s events: %10d\n", name, 477 ret += fprintf(fp, "%16s events: %10d\n", name,
478 hists->stats.nr_events[i]); 478 stats->nr_events[i]);
479 } 479 }
480 480
481 return ret; 481 return ret;
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index 3014a7cd5271..e3e0a963d03a 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -52,17 +52,6 @@ int ui__warning(const char *format, ...)
52 return ret; 52 return ret;
53} 53}
54 54
55int ui__error_paranoid(void)
56{
57 return ui__error("Permission error - are you root?\n"
58 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
59 " -1 - Not paranoid at all\n"
60 " 0 - Disallow raw tracepoint access for unpriv\n"
61 " 1 - Disallow cpu events for unpriv\n"
62 " 2 - Disallow kernel profiling for unpriv\n");
63}
64
65
66/** 55/**
67 * perf_error__register - Register error logging functions 56 * perf_error__register - Register error logging functions
68 * @eops: The pointer to error logging function struct 57 * @eops: The pointer to error logging function struct
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 6aa34e5afdcf..055fef34b6f6 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
26 26
27if test -r $GVF 27if test -r $GVF
28then 28then
29 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) 29 VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
30else 30else
31 VC=unset 31 VC=unset
32fi 32fi
33test "$VN" = "$VC" || { 33test "$VN" = "$VC" || {
34 echo >&2 "PERF_VERSION = $VN" 34 echo >&2 "PERF_VERSION = $VN"
35 echo "PERF_VERSION = $VN" >$GVF 35 echo "#define PERF_VERSION \"$VN\"" >$GVF
36} 36}
37 37
38 38
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 6e2667fb8211..efbd98805ad0 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -16,6 +16,5 @@ void trace_event(union perf_event *event);
16 16
17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19int ui__error_paranoid(void);
20 19
21#endif /* __PERF_DEBUG_H */ 20#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7a2a3dc3ff03..e45332d08a58 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -22,6 +22,11 @@
22#include <linux/perf_event.h> 22#include <linux/perf_event.h>
23#include "perf_regs.h" 23#include "perf_regs.h"
24 24
25static struct {
26 bool sample_id_all;
27 bool exclude_guest;
28} perf_missing_features;
29
25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
26 31
27static int __perf_evsel__sample_size(u64 sample_type) 32static int __perf_evsel__sample_size(u64 sample_type)
@@ -463,7 +468,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
463 struct perf_event_attr *attr = &evsel->attr; 468 struct perf_event_attr *attr = &evsel->attr;
464 int track = !evsel->idx; /* only the first counter needs these */ 469 int track = !evsel->idx; /* only the first counter needs these */
465 470
466 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 471 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
467 attr->inherit = !opts->no_inherit; 472 attr->inherit = !opts->no_inherit;
468 473
469 perf_evsel__set_sample_bit(evsel, IP); 474 perf_evsel__set_sample_bit(evsel, IP);
@@ -513,7 +518,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
513 if (opts->period) 518 if (opts->period)
514 perf_evsel__set_sample_bit(evsel, PERIOD); 519 perf_evsel__set_sample_bit(evsel, PERIOD);
515 520
516 if (!opts->sample_id_all_missing && 521 if (!perf_missing_features.sample_id_all &&
517 (opts->sample_time || !opts->no_inherit || 522 (opts->sample_time || !opts->no_inherit ||
518 perf_target__has_cpu(&opts->target))) 523 perf_target__has_cpu(&opts->target)))
519 perf_evsel__set_sample_bit(evsel, TIME); 524 perf_evsel__set_sample_bit(evsel, TIME);
@@ -761,6 +766,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
761 pid = evsel->cgrp->fd; 766 pid = evsel->cgrp->fd;
762 } 767 }
763 768
769fallback_missing_features:
770 if (perf_missing_features.exclude_guest)
771 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
772retry_sample_id:
773 if (perf_missing_features.sample_id_all)
774 evsel->attr.sample_id_all = 0;
775
764 for (cpu = 0; cpu < cpus->nr; cpu++) { 776 for (cpu = 0; cpu < cpus->nr; cpu++) {
765 777
766 for (thread = 0; thread < threads->nr; thread++) { 778 for (thread = 0; thread < threads->nr; thread++) {
@@ -777,13 +789,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
777 group_fd, flags); 789 group_fd, flags);
778 if (FD(evsel, cpu, thread) < 0) { 790 if (FD(evsel, cpu, thread) < 0) {
779 err = -errno; 791 err = -errno;
780 goto out_close; 792 goto try_fallback;
781 } 793 }
782 } 794 }
783 } 795 }
784 796
785 return 0; 797 return 0;
786 798
799try_fallback:
800 if (err != -EINVAL || cpu > 0 || thread > 0)
801 goto out_close;
802
803 if (!perf_missing_features.exclude_guest &&
804 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
805 perf_missing_features.exclude_guest = true;
806 goto fallback_missing_features;
807 } else if (!perf_missing_features.sample_id_all) {
808 perf_missing_features.sample_id_all = true;
809 goto retry_sample_id;
810 }
811
787out_close: 812out_close:
788 do { 813 do {
789 while (--thread >= 0) { 814 while (--thread >= 0) {
@@ -1353,3 +1378,80 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1353 fputc('\n', fp); 1378 fputc('\n', fp);
1354 return ++printed; 1379 return ++printed;
1355} 1380}
1381
1382bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1383 char *msg, size_t msgsize)
1384{
1385 if ((err == ENOENT || err == ENXIO) &&
1386 evsel->attr.type == PERF_TYPE_HARDWARE &&
1387 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1388 /*
1389 * If it's cycles then fall back to hrtimer based
1390 * cpu-clock-tick sw counter, which is always available even if
1391 * no PMU support.
1392 *
1393 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
1394 * b0a873e).
1395 */
1396 scnprintf(msg, msgsize, "%s",
1397"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
1398
1399 evsel->attr.type = PERF_TYPE_SOFTWARE;
1400 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
1401
1402 free(evsel->name);
1403 evsel->name = NULL;
1404 return true;
1405 }
1406
1407 return false;
1408}
1409
1410int perf_evsel__open_strerror(struct perf_evsel *evsel,
1411 struct perf_target *target,
1412 int err, char *msg, size_t size)
1413{
1414 switch (err) {
1415 case EPERM:
1416 case EACCES:
1417 return scnprintf(msg, size, "%s",
1418 "You may not have permission to collect %sstats.\n"
1419 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1420 " -1 - Not paranoid at all\n"
1421 " 0 - Disallow raw tracepoint access for unpriv\n"
1422 " 1 - Disallow cpu events for unpriv\n"
1423 " 2 - Disallow kernel profiling for unpriv",
1424 target->system_wide ? "system-wide " : "");
1425 case ENOENT:
1426 return scnprintf(msg, size, "The %s event is not supported.",
1427 perf_evsel__name(evsel));
1428 case EMFILE:
1429 return scnprintf(msg, size, "%s",
1430 "Too many events are opened.\n"
1431 "Try again after reducing the number of events.");
1432 case ENODEV:
1433 if (target->cpu_list)
1434 return scnprintf(msg, size, "%s",
1435 "No such device - did you specify an out-of-range profile CPU?\n");
1436 break;
1437 case EOPNOTSUPP:
1438 if (evsel->attr.precise_ip)
1439 return scnprintf(msg, size, "%s",
1440 "\'precise\' request may not be supported. Try removing 'p' modifier.");
1441#if defined(__i386__) || defined(__x86_64__)
1442 if (evsel->attr.type == PERF_TYPE_HARDWARE)
1443 return scnprintf(msg, size, "%s",
1444 "No hardware sampling interrupt available.\n"
1445 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
1446#endif
1447 break;
1448 default:
1449 break;
1450 }
1451
1452 return scnprintf(msg, size,
1453 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n"
1454 "/bin/dmesg may provide additional information.\n"
1455 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
1456 err, strerror(err), perf_evsel__name(evsel));
1457}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 9cb8a0215711..c68d1b82e843 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -251,4 +251,10 @@ struct perf_attr_details {
251 251
252int perf_evsel__fprintf(struct perf_evsel *evsel, 252int perf_evsel__fprintf(struct perf_evsel *evsel,
253 struct perf_attr_details *details, FILE *fp); 253 struct perf_attr_details *details, FILE *fp);
254
255bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
256 char *msg, size_t msgsize);
257int perf_evsel__open_strerror(struct perf_evsel *evsel,
258 struct perf_target *target,
259 int err, char *msg, size_t size);
254#endif /* __PERF_EVSEL_H */ 260#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b7da4634a047..fccd69dbbbb9 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
148 u32 len; 148 u32 len;
149 char *buf; 149 char *buf;
150 150
151 sz = read(fd, &len, sizeof(len)); 151 sz = readn(fd, &len, sizeof(len));
152 if (sz < (ssize_t)sizeof(len)) 152 if (sz < (ssize_t)sizeof(len))
153 return NULL; 153 return NULL;
154 154
@@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
159 if (!buf) 159 if (!buf)
160 return NULL; 160 return NULL;
161 161
162 ret = read(fd, buf, len); 162 ret = readn(fd, buf, len);
163 if (ret == (ssize_t)len) { 163 if (ret == (ssize_t)len) {
164 /* 164 /*
165 * strings are padded by zeroes 165 * strings are padded by zeroes
@@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
287 struct perf_session *session = container_of(header, 287 struct perf_session *session = container_of(header,
288 struct perf_session, header); 288 struct perf_session, header);
289 struct rb_node *nd; 289 struct rb_node *nd;
290 int err = machine__write_buildid_table(&session->host_machine, fd); 290 int err = machine__write_buildid_table(&session->machines.host, fd);
291 291
292 if (err) 292 if (err)
293 return err; 293 return err;
294 294
295 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 295 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
296 struct machine *pos = rb_entry(nd, struct machine, rb_node); 296 struct machine *pos = rb_entry(nd, struct machine, rb_node);
297 err = machine__write_buildid_table(pos, fd); 297 err = machine__write_buildid_table(pos, fd);
298 if (err) 298 if (err)
@@ -448,9 +448,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
448 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 448 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
449 return -1; 449 return -1;
450 450
451 ret = machine__cache_build_ids(&session->host_machine, debugdir); 451 ret = machine__cache_build_ids(&session->machines.host, debugdir);
452 452
453 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 453 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
454 struct machine *pos = rb_entry(nd, struct machine, rb_node); 454 struct machine *pos = rb_entry(nd, struct machine, rb_node);
455 ret |= machine__cache_build_ids(pos, debugdir); 455 ret |= machine__cache_build_ids(pos, debugdir);
456 } 456 }
@@ -467,9 +467,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits)
467static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 467static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
468{ 468{
469 struct rb_node *nd; 469 struct rb_node *nd;
470 bool ret = machine__read_build_ids(&session->host_machine, with_hits); 470 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
471 471
472 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 472 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
473 struct machine *pos = rb_entry(nd, struct machine, rb_node); 473 struct machine *pos = rb_entry(nd, struct machine, rb_node);
474 ret |= machine__read_build_ids(pos, with_hits); 474 ret |= machine__read_build_ids(pos, with_hits);
475 } 475 }
@@ -1051,16 +1051,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1051 struct perf_pmu *pmu = NULL; 1051 struct perf_pmu *pmu = NULL;
1052 off_t offset = lseek(fd, 0, SEEK_CUR); 1052 off_t offset = lseek(fd, 0, SEEK_CUR);
1053 __u32 pmu_num = 0; 1053 __u32 pmu_num = 0;
1054 int ret;
1054 1055
1055 /* write real pmu_num later */ 1056 /* write real pmu_num later */
1056 do_write(fd, &pmu_num, sizeof(pmu_num)); 1057 ret = do_write(fd, &pmu_num, sizeof(pmu_num));
1058 if (ret < 0)
1059 return ret;
1057 1060
1058 while ((pmu = perf_pmu__scan(pmu))) { 1061 while ((pmu = perf_pmu__scan(pmu))) {
1059 if (!pmu->name) 1062 if (!pmu->name)
1060 continue; 1063 continue;
1061 pmu_num++; 1064 pmu_num++;
1062 do_write(fd, &pmu->type, sizeof(pmu->type)); 1065
1063 do_write_string(fd, pmu->name); 1066 ret = do_write(fd, &pmu->type, sizeof(pmu->type));
1067 if (ret < 0)
1068 return ret;
1069
1070 ret = do_write_string(fd, pmu->name);
1071 if (ret < 0)
1072 return ret;
1064 } 1073 }
1065 1074
1066 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 1075 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1209,14 +1218,14 @@ read_event_desc(struct perf_header *ph, int fd)
1209 size_t msz; 1218 size_t msz;
1210 1219
1211 /* number of events */ 1220 /* number of events */
1212 ret = read(fd, &nre, sizeof(nre)); 1221 ret = readn(fd, &nre, sizeof(nre));
1213 if (ret != (ssize_t)sizeof(nre)) 1222 if (ret != (ssize_t)sizeof(nre))
1214 goto error; 1223 goto error;
1215 1224
1216 if (ph->needs_swap) 1225 if (ph->needs_swap)
1217 nre = bswap_32(nre); 1226 nre = bswap_32(nre);
1218 1227
1219 ret = read(fd, &sz, sizeof(sz)); 1228 ret = readn(fd, &sz, sizeof(sz));
1220 if (ret != (ssize_t)sizeof(sz)) 1229 if (ret != (ssize_t)sizeof(sz))
1221 goto error; 1230 goto error;
1222 1231
@@ -1244,7 +1253,7 @@ read_event_desc(struct perf_header *ph, int fd)
1244 * must read entire on-file attr struct to 1253 * must read entire on-file attr struct to
1245 * sync up with layout. 1254 * sync up with layout.
1246 */ 1255 */
1247 ret = read(fd, buf, sz); 1256 ret = readn(fd, buf, sz);
1248 if (ret != (ssize_t)sz) 1257 if (ret != (ssize_t)sz)
1249 goto error; 1258 goto error;
1250 1259
@@ -1253,7 +1262,7 @@ read_event_desc(struct perf_header *ph, int fd)
1253 1262
1254 memcpy(&evsel->attr, buf, msz); 1263 memcpy(&evsel->attr, buf, msz);
1255 1264
1256 ret = read(fd, &nr, sizeof(nr)); 1265 ret = readn(fd, &nr, sizeof(nr));
1257 if (ret != (ssize_t)sizeof(nr)) 1266 if (ret != (ssize_t)sizeof(nr))
1258 goto error; 1267 goto error;
1259 1268
@@ -1274,7 +1283,7 @@ read_event_desc(struct perf_header *ph, int fd)
1274 evsel->id = id; 1283 evsel->id = id;
1275 1284
1276 for (j = 0 ; j < nr; j++) { 1285 for (j = 0 ; j < nr; j++) {
1277 ret = read(fd, id, sizeof(*id)); 1286 ret = readn(fd, id, sizeof(*id));
1278 if (ret != (ssize_t)sizeof(*id)) 1287 if (ret != (ssize_t)sizeof(*id))
1279 goto error; 1288 goto error;
1280 if (ph->needs_swap) 1289 if (ph->needs_swap)
@@ -1506,14 +1515,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1506 while (offset < limit) { 1515 while (offset < limit) {
1507 ssize_t len; 1516 ssize_t len;
1508 1517
1509 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 1518 if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1510 return -1; 1519 return -1;
1511 1520
1512 if (header->needs_swap) 1521 if (header->needs_swap)
1513 perf_event_header__bswap(&old_bev.header); 1522 perf_event_header__bswap(&old_bev.header);
1514 1523
1515 len = old_bev.header.size - sizeof(old_bev); 1524 len = old_bev.header.size - sizeof(old_bev);
1516 if (read(input, filename, len) != len) 1525 if (readn(input, filename, len) != len)
1517 return -1; 1526 return -1;
1518 1527
1519 bev.header = old_bev.header; 1528 bev.header = old_bev.header;
@@ -1548,14 +1557,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
1548 while (offset < limit) { 1557 while (offset < limit) {
1549 ssize_t len; 1558 ssize_t len;
1550 1559
1551 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 1560 if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
1552 goto out; 1561 goto out;
1553 1562
1554 if (header->needs_swap) 1563 if (header->needs_swap)
1555 perf_event_header__bswap(&bev.header); 1564 perf_event_header__bswap(&bev.header);
1556 1565
1557 len = bev.header.size - sizeof(bev); 1566 len = bev.header.size - sizeof(bev);
1558 if (read(input, filename, len) != len) 1567 if (readn(input, filename, len) != len)
1559 goto out; 1568 goto out;
1560 /* 1569 /*
1561 * The a1645ce1 changeset: 1570 * The a1645ce1 changeset:
@@ -1641,7 +1650,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1641 size_t ret; 1650 size_t ret;
1642 u32 nr; 1651 u32 nr;
1643 1652
1644 ret = read(fd, &nr, sizeof(nr)); 1653 ret = readn(fd, &nr, sizeof(nr));
1645 if (ret != sizeof(nr)) 1654 if (ret != sizeof(nr))
1646 return -1; 1655 return -1;
1647 1656
@@ -1650,7 +1659,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1650 1659
1651 ph->env.nr_cpus_online = nr; 1660 ph->env.nr_cpus_online = nr;
1652 1661
1653 ret = read(fd, &nr, sizeof(nr)); 1662 ret = readn(fd, &nr, sizeof(nr));
1654 if (ret != sizeof(nr)) 1663 if (ret != sizeof(nr))
1655 return -1; 1664 return -1;
1656 1665
@@ -1684,7 +1693,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1684 uint64_t mem; 1693 uint64_t mem;
1685 size_t ret; 1694 size_t ret;
1686 1695
1687 ret = read(fd, &mem, sizeof(mem)); 1696 ret = readn(fd, &mem, sizeof(mem));
1688 if (ret != sizeof(mem)) 1697 if (ret != sizeof(mem))
1689 return -1; 1698 return -1;
1690 1699
@@ -1756,7 +1765,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1756 u32 nr, i; 1765 u32 nr, i;
1757 struct strbuf sb; 1766 struct strbuf sb;
1758 1767
1759 ret = read(fd, &nr, sizeof(nr)); 1768 ret = readn(fd, &nr, sizeof(nr));
1760 if (ret != sizeof(nr)) 1769 if (ret != sizeof(nr))
1761 return -1; 1770 return -1;
1762 1771
@@ -1792,7 +1801,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1792 char *str; 1801 char *str;
1793 struct strbuf sb; 1802 struct strbuf sb;
1794 1803
1795 ret = read(fd, &nr, sizeof(nr)); 1804 ret = readn(fd, &nr, sizeof(nr));
1796 if (ret != sizeof(nr)) 1805 if (ret != sizeof(nr))
1797 return -1; 1806 return -1;
1798 1807
@@ -1813,7 +1822,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1813 } 1822 }
1814 ph->env.sibling_cores = strbuf_detach(&sb, NULL); 1823 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1815 1824
1816 ret = read(fd, &nr, sizeof(nr)); 1825 ret = readn(fd, &nr, sizeof(nr));
1817 if (ret != sizeof(nr)) 1826 if (ret != sizeof(nr))
1818 return -1; 1827 return -1;
1819 1828
@@ -1850,7 +1859,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1850 struct strbuf sb; 1859 struct strbuf sb;
1851 1860
1852 /* nr nodes */ 1861 /* nr nodes */
1853 ret = read(fd, &nr, sizeof(nr)); 1862 ret = readn(fd, &nr, sizeof(nr));
1854 if (ret != sizeof(nr)) 1863 if (ret != sizeof(nr))
1855 goto error; 1864 goto error;
1856 1865
@@ -1862,15 +1871,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1862 1871
1863 for (i = 0; i < nr; i++) { 1872 for (i = 0; i < nr; i++) {
1864 /* node number */ 1873 /* node number */
1865 ret = read(fd, &node, sizeof(node)); 1874 ret = readn(fd, &node, sizeof(node));
1866 if (ret != sizeof(node)) 1875 if (ret != sizeof(node))
1867 goto error; 1876 goto error;
1868 1877
1869 ret = read(fd, &mem_total, sizeof(u64)); 1878 ret = readn(fd, &mem_total, sizeof(u64));
1870 if (ret != sizeof(u64)) 1879 if (ret != sizeof(u64))
1871 goto error; 1880 goto error;
1872 1881
1873 ret = read(fd, &mem_free, sizeof(u64)); 1882 ret = readn(fd, &mem_free, sizeof(u64));
1874 if (ret != sizeof(u64)) 1883 if (ret != sizeof(u64))
1875 goto error; 1884 goto error;
1876 1885
@@ -1909,7 +1918,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1909 u32 type; 1918 u32 type;
1910 struct strbuf sb; 1919 struct strbuf sb;
1911 1920
1912 ret = read(fd, &pmu_num, sizeof(pmu_num)); 1921 ret = readn(fd, &pmu_num, sizeof(pmu_num));
1913 if (ret != sizeof(pmu_num)) 1922 if (ret != sizeof(pmu_num))
1914 return -1; 1923 return -1;
1915 1924
@@ -1925,7 +1934,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1925 strbuf_init(&sb, 128); 1934 strbuf_init(&sb, 128);
1926 1935
1927 while (pmu_num) { 1936 while (pmu_num) {
1928 if (read(fd, &type, sizeof(type)) != sizeof(type)) 1937 if (readn(fd, &type, sizeof(type)) != sizeof(type))
1929 goto error; 1938 goto error;
1930 if (ph->needs_swap) 1939 if (ph->needs_swap)
1931 type = bswap_32(type); 1940 type = bswap_32(type);
@@ -2912,7 +2921,7 @@ int perf_event__process_tracing_data(union perf_event *event,
2912 session->repipe); 2921 session->repipe);
2913 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 2922 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
2914 2923
2915 if (read(session->fd, buf, padding) < 0) 2924 if (readn(session->fd, buf, padding) < 0)
2916 die("reading input file"); 2925 die("reading input file");
2917 if (session->repipe) { 2926 if (session->repipe) {
2918 int retw = write(STDOUT_FILENO, buf, padding); 2927 int retw = write(STDOUT_FILENO, buf, padding);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 82df1b26f0d4..8170a3d11ffa 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -82,6 +82,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
82 hists__new_col_len(hists, HISTC_DSO, len); 82 hists__new_col_len(hists, HISTC_DSO, len);
83 } 83 }
84 84
85 if (h->parent)
86 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
87
85 if (h->branch_info) { 88 if (h->branch_info) {
86 int symlen; 89 int symlen;
87 /* 90 /*
@@ -242,6 +245,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
242 245
243 if (he->ms.map) 246 if (he->ms.map)
244 he->ms.map->referenced = true; 247 he->ms.map->referenced = true;
248
249 if (he->branch_info) {
250 if (he->branch_info->from.map)
251 he->branch_info->from.map->referenced = true;
252 if (he->branch_info->to.map)
253 he->branch_info->to.map->referenced = true;
254 }
255
245 if (symbol_conf.use_callchain) 256 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 257 callchain_init(he->callchain);
247 258
@@ -251,7 +262,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
251 return he; 262 return he;
252} 263}
253 264
254static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 265void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
255{ 266{
256 if (!h->filtered) { 267 if (!h->filtered) {
257 hists__calc_col_len(hists, h); 268 hists__calc_col_len(hists, h);
@@ -285,7 +296,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
285 parent = *p; 296 parent = *p;
286 he = rb_entry(parent, struct hist_entry, rb_node_in); 297 he = rb_entry(parent, struct hist_entry, rb_node_in);
287 298
288 cmp = hist_entry__cmp(entry, he); 299 /*
300 * Make sure that it receives arguments in a same order as
301 * hist_entry__collapse() so that we can use an appropriate
302 * function when searching an entry regardless which sort
303 * keys were used.
304 */
305 cmp = hist_entry__cmp(he, entry);
289 306
290 if (!cmp) { 307 if (!cmp) {
291 he_stat__add_period(&he->stat, period); 308 he_stat__add_period(&he->stat, period);
@@ -711,25 +728,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
711 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 728 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
712} 729}
713 730
731void events_stats__inc(struct events_stats *stats, u32 type)
732{
733 ++stats->nr_events[0];
734 ++stats->nr_events[type];
735}
736
714void hists__inc_nr_events(struct hists *hists, u32 type) 737void hists__inc_nr_events(struct hists *hists, u32 type)
715{ 738{
716 ++hists->stats.nr_events[0]; 739 events_stats__inc(&hists->stats, type);
717 ++hists->stats.nr_events[type];
718} 740}
719 741
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 742static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
721 struct hist_entry *pair) 743 struct hist_entry *pair)
722{ 744{
723 struct rb_node **p = &hists->entries.rb_node; 745 struct rb_root *root;
746 struct rb_node **p;
724 struct rb_node *parent = NULL; 747 struct rb_node *parent = NULL;
725 struct hist_entry *he; 748 struct hist_entry *he;
726 int cmp; 749 int cmp;
727 750
751 if (sort__need_collapse)
752 root = &hists->entries_collapsed;
753 else
754 root = hists->entries_in;
755
756 p = &root->rb_node;
757
728 while (*p != NULL) { 758 while (*p != NULL) {
729 parent = *p; 759 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node); 760 he = rb_entry(parent, struct hist_entry, rb_node_in);
731 761
732 cmp = hist_entry__cmp(pair, he); 762 cmp = hist_entry__collapse(he, pair);
733 763
734 if (!cmp) 764 if (!cmp)
735 goto out; 765 goto out;
@@ -744,8 +774,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
744 if (he) { 774 if (he) {
745 memset(&he->stat, 0, sizeof(he->stat)); 775 memset(&he->stat, 0, sizeof(he->stat));
746 he->hists = hists; 776 he->hists = hists;
747 rb_link_node(&he->rb_node, parent, p); 777 rb_link_node(&he->rb_node_in, parent, p);
748 rb_insert_color(&he->rb_node, &hists->entries); 778 rb_insert_color(&he->rb_node_in, root);
749 hists__inc_nr_entries(hists, he); 779 hists__inc_nr_entries(hists, he);
750 } 780 }
751out: 781out:
@@ -755,11 +785,16 @@ out:
755static struct hist_entry *hists__find_entry(struct hists *hists, 785static struct hist_entry *hists__find_entry(struct hists *hists,
756 struct hist_entry *he) 786 struct hist_entry *he)
757{ 787{
758 struct rb_node *n = hists->entries.rb_node; 788 struct rb_node *n;
789
790 if (sort__need_collapse)
791 n = hists->entries_collapsed.rb_node;
792 else
793 n = hists->entries_in->rb_node;
759 794
760 while (n) { 795 while (n) {
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 796 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
762 int64_t cmp = hist_entry__cmp(he, iter); 797 int64_t cmp = hist_entry__collapse(iter, he);
763 798
764 if (cmp < 0) 799 if (cmp < 0)
765 n = n->rb_left; 800 n = n->rb_left;
@@ -777,11 +812,17 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
777 */ 812 */
778void hists__match(struct hists *leader, struct hists *other) 813void hists__match(struct hists *leader, struct hists *other)
779{ 814{
815 struct rb_root *root;
780 struct rb_node *nd; 816 struct rb_node *nd;
781 struct hist_entry *pos, *pair; 817 struct hist_entry *pos, *pair;
782 818
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { 819 if (sort__need_collapse)
784 pos = rb_entry(nd, struct hist_entry, rb_node); 820 root = &leader->entries_collapsed;
821 else
822 root = leader->entries_in;
823
824 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
825 pos = rb_entry(nd, struct hist_entry, rb_node_in);
785 pair = hists__find_entry(other, pos); 826 pair = hists__find_entry(other, pos);
786 827
787 if (pair) 828 if (pair)
@@ -796,11 +837,17 @@ void hists__match(struct hists *leader, struct hists *other)
796 */ 837 */
797int hists__link(struct hists *leader, struct hists *other) 838int hists__link(struct hists *leader, struct hists *other)
798{ 839{
840 struct rb_root *root;
799 struct rb_node *nd; 841 struct rb_node *nd;
800 struct hist_entry *pos, *pair; 842 struct hist_entry *pos, *pair;
801 843
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { 844 if (sort__need_collapse)
803 pos = rb_entry(nd, struct hist_entry, rb_node); 845 root = &other->entries_collapsed;
846 else
847 root = other->entries_in;
848
849 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
850 pos = rb_entry(nd, struct hist_entry, rb_node_in);
804 851
805 if (!hist_entry__has_pairs(pos)) { 852 if (!hist_entry__has_pairs(pos)) {
806 pair = hists__add_dummy_entry(leader, pos); 853 pair = hists__add_dummy_entry(leader, pos);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 5b3b0075be64..38624686ee9a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
96 bool zap_kernel); 96 bool zap_kernel);
97void hists__output_recalc_col_len(struct hists *hists, int max_rows); 97void hists__output_recalc_col_len(struct hists *hists, int max_rows);
98 98
99void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
99void hists__inc_nr_events(struct hists *self, u32 type); 100void hists__inc_nr_events(struct hists *self, u32 type);
100size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 101void events_stats__inc(struct events_stats *stats, u32 type);
102size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
101 103
102size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 104size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
103 int max_cols, FILE *fp); 105 int max_cols, FILE *fp);
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index a55d8cf083c9..45cf10a562bd 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -14,6 +14,7 @@
14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) 15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) 16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
17 18
18#define for_each_set_bit(bit, addr, size) \ 19#define for_each_set_bit(bit, addr, size) \
19 for ((bit) = find_first_bit((addr), (size)); \ 20 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 9d0740024ba8..11a8d86f7fea 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
59 59
60struct int_node *intlist__find(struct intlist *ilist, int i) 60struct int_node *intlist__find(struct intlist *ilist, int i)
61{ 61{
62 struct int_node *node = NULL; 62 struct int_node *node;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 63 struct rb_node *rb_node;
64 64
65 if (ilist == NULL)
66 return NULL;
67
68 node = NULL;
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
65 if (rb_node) 70 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node); 71 node = container_of(rb_node, struct int_node, rb_node);
67 72
68 return node; 73 return node;
69} 74}
70 75
71struct intlist *intlist__new(void) 76static int intlist__parse_list(struct intlist *ilist, const char *s)
77{
78 char *sep;
79 int err;
80
81 do {
82 long value = strtol(s, &sep, 10);
83 err = -EINVAL;
84 if (*sep != ',' && *sep != '\0')
85 break;
86 err = intlist__add(ilist, value);
87 if (err)
88 break;
89 s = sep + 1;
90 } while (*sep != '\0');
91
92 return err;
93}
94
95struct intlist *intlist__new(const char *slist)
72{ 96{
73 struct intlist *ilist = malloc(sizeof(*ilist)); 97 struct intlist *ilist = malloc(sizeof(*ilist));
74 98
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
77 ilist->rblist.node_cmp = intlist__node_cmp; 101 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new; 102 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete; 103 ilist->rblist.node_delete = intlist__node_delete;
104
105 if (slist && intlist__parse_list(ilist, slist))
106 goto out_delete;
80 } 107 }
81 108
82 return ilist; 109 return ilist;
110out_delete:
111 intlist__delete(ilist);
112 return NULL;
83} 113}
84 114
85void intlist__delete(struct intlist *ilist) 115void intlist__delete(struct intlist *ilist)
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 6d63ab90db50..62351dad848f 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -15,7 +15,7 @@ struct intlist {
15 struct rblist rblist; 15 struct rblist rblist;
16}; 16};
17 17
18struct intlist *intlist__new(void); 18struct intlist *intlist__new(const char *slist);
19void intlist__delete(struct intlist *ilist); 19void intlist__delete(struct intlist *ilist);
20 20
21void intlist__remove(struct intlist *ilist, struct int_node *in); 21void intlist__remove(struct intlist *ilist, struct int_node *in);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 71fa90391fe4..efdb38e65a92 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -91,10 +91,22 @@ void machine__delete(struct machine *machine)
91 free(machine); 91 free(machine);
92} 92}
93 93
94struct machine *machines__add(struct rb_root *machines, pid_t pid, 94void machines__init(struct machines *machines)
95{
96 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT;
98}
99
100void machines__exit(struct machines *machines)
101{
102 machine__exit(&machines->host);
103 /* XXX exit guest */
104}
105
106struct machine *machines__add(struct machines *machines, pid_t pid,
95 const char *root_dir) 107 const char *root_dir)
96{ 108{
97 struct rb_node **p = &machines->rb_node; 109 struct rb_node **p = &machines->guests.rb_node;
98 struct rb_node *parent = NULL; 110 struct rb_node *parent = NULL;
99 struct machine *pos, *machine = malloc(sizeof(*machine)); 111 struct machine *pos, *machine = malloc(sizeof(*machine));
100 112
@@ -116,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
116 } 128 }
117 129
118 rb_link_node(&machine->rb_node, parent, p); 130 rb_link_node(&machine->rb_node, parent, p);
119 rb_insert_color(&machine->rb_node, machines); 131 rb_insert_color(&machine->rb_node, &machines->guests);
120 132
121 return machine; 133 return machine;
122} 134}
123 135
124struct machine *machines__find(struct rb_root *machines, pid_t pid) 136struct machine *machines__find(struct machines *machines, pid_t pid)
125{ 137{
126 struct rb_node **p = &machines->rb_node; 138 struct rb_node **p = &machines->guests.rb_node;
127 struct rb_node *parent = NULL; 139 struct rb_node *parent = NULL;
128 struct machine *machine; 140 struct machine *machine;
129 struct machine *default_machine = NULL; 141 struct machine *default_machine = NULL;
130 142
143 if (pid == HOST_KERNEL_ID)
144 return &machines->host;
145
131 while (*p != NULL) { 146 while (*p != NULL) {
132 parent = *p; 147 parent = *p;
133 machine = rb_entry(parent, struct machine, rb_node); 148 machine = rb_entry(parent, struct machine, rb_node);
@@ -144,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
144 return default_machine; 159 return default_machine;
145} 160}
146 161
147struct machine *machines__findnew(struct rb_root *machines, pid_t pid) 162struct machine *machines__findnew(struct machines *machines, pid_t pid)
148{ 163{
149 char path[PATH_MAX]; 164 char path[PATH_MAX];
150 const char *root_dir = ""; 165 const char *root_dir = "";
@@ -178,12 +193,12 @@ out:
178 return machine; 193 return machine;
179} 194}
180 195
181void machines__process(struct rb_root *machines, 196void machines__process_guests(struct machines *machines,
182 machine__process_t process, void *data) 197 machine__process_t process, void *data)
183{ 198{
184 struct rb_node *nd; 199 struct rb_node *nd;
185 200
186 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 201 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
187 struct machine *pos = rb_entry(nd, struct machine, rb_node); 202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
188 process(pos, data); 203 process(pos, data);
189 } 204 }
@@ -203,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
203 return bf; 218 return bf;
204} 219}
205 220
206void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) 221void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
207{ 222{
208 struct rb_node *node; 223 struct rb_node *node;
209 struct machine *machine; 224 struct machine *machine;
210 225
211 for (node = rb_first(machines); node; node = rb_next(node)) { 226 machines->host.id_hdr_size = id_hdr_size;
227
228 for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
212 machine = rb_entry(node, struct machine, rb_node); 229 machine = rb_entry(node, struct machine, rb_node);
213 machine->id_hdr_size = id_hdr_size; 230 machine->id_hdr_size = id_hdr_size;
214 } 231 }
@@ -313,12 +330,13 @@ struct map *machine__new_module(struct machine *machine, u64 start,
313 return map; 330 return map;
314} 331}
315 332
316size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 333size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
317{ 334{
318 struct rb_node *nd; 335 struct rb_node *nd;
319 size_t ret = 0; 336 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
337 __dsos__fprintf(&machines->host.user_dsos, fp);
320 338
321 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 339 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
322 struct machine *pos = rb_entry(nd, struct machine, rb_node); 340 struct machine *pos = rb_entry(nd, struct machine, rb_node);
323 ret += __dsos__fprintf(&pos->kernel_dsos, fp); 341 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
324 ret += __dsos__fprintf(&pos->user_dsos, fp); 342 ret += __dsos__fprintf(&pos->user_dsos, fp);
@@ -334,13 +352,13 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
334 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); 352 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
335} 353}
336 354
337size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, 355size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
338 bool (skip)(struct dso *dso, int parm), int parm) 356 bool (skip)(struct dso *dso, int parm), int parm)
339{ 357{
340 struct rb_node *nd; 358 struct rb_node *nd;
341 size_t ret = 0; 359 size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
342 360
343 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 361 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
344 struct machine *pos = rb_entry(nd, struct machine, rb_node); 362 struct machine *pos = rb_entry(nd, struct machine, rb_node);
345 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); 363 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
346 } 364 }
@@ -511,7 +529,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
511 } 529 }
512} 530}
513 531
514int machines__create_guest_kernel_maps(struct rb_root *machines) 532int machines__create_guest_kernel_maps(struct machines *machines)
515{ 533{
516 int ret = 0; 534 int ret = 0;
517 struct dirent **namelist = NULL; 535 struct dirent **namelist = NULL;
@@ -560,20 +578,22 @@ failure:
560 return ret; 578 return ret;
561} 579}
562 580
563void machines__destroy_guest_kernel_maps(struct rb_root *machines) 581void machines__destroy_kernel_maps(struct machines *machines)
564{ 582{
565 struct rb_node *next = rb_first(machines); 583 struct rb_node *next = rb_first(&machines->guests);
584
585 machine__destroy_kernel_maps(&machines->host);
566 586
567 while (next) { 587 while (next) {
568 struct machine *pos = rb_entry(next, struct machine, rb_node); 588 struct machine *pos = rb_entry(next, struct machine, rb_node);
569 589
570 next = rb_next(&pos->rb_node); 590 next = rb_next(&pos->rb_node);
571 rb_erase(&pos->rb_node, machines); 591 rb_erase(&pos->rb_node, &machines->guests);
572 machine__delete(pos); 592 machine__delete(pos);
573 } 593 }
574} 594}
575 595
576int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) 596int machines__create_kernel_maps(struct machines *machines, pid_t pid)
577{ 597{
578 struct machine *machine = machines__findnew(machines, pid); 598 struct machine *machine = machines__findnew(machines, pid);
579 599
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index e11236878ec1..5ac5892f2326 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -47,16 +47,24 @@ int machine__process_event(struct machine *machine, union perf_event *event);
47 47
48typedef void (*machine__process_t)(struct machine *machine, void *data); 48typedef void (*machine__process_t)(struct machine *machine, void *data);
49 49
50void machines__process(struct rb_root *machines, 50struct machines {
51 machine__process_t process, void *data); 51 struct machine host;
52 struct rb_root guests;
53};
54
55void machines__init(struct machines *machines);
56void machines__exit(struct machines *machines);
57
58void machines__process_guests(struct machines *machines,
59 machine__process_t process, void *data);
52 60
53struct machine *machines__add(struct rb_root *machines, pid_t pid, 61struct machine *machines__add(struct machines *machines, pid_t pid,
54 const char *root_dir); 62 const char *root_dir);
55struct machine *machines__find_host(struct rb_root *machines); 63struct machine *machines__find_host(struct machines *machines);
56struct machine *machines__find(struct rb_root *machines, pid_t pid); 64struct machine *machines__find(struct machines *machines, pid_t pid);
57struct machine *machines__findnew(struct rb_root *machines, pid_t pid); 65struct machine *machines__findnew(struct machines *machines, pid_t pid);
58 66
59void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); 67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
60char *machine__mmap_name(struct machine *machine, char *bf, size_t size); 68char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
61 69
62int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 70int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
@@ -132,17 +140,17 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
132 140
133size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 141size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
134 bool (skip)(struct dso *dso, int parm), int parm); 142 bool (skip)(struct dso *dso, int parm), int parm);
135size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); 143size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
136size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, 144size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
137 bool (skip)(struct dso *dso, int parm), int parm); 145 bool (skip)(struct dso *dso, int parm), int parm);
138 146
139void machine__destroy_kernel_maps(struct machine *machine); 147void machine__destroy_kernel_maps(struct machine *machine);
140int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); 148int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
141int machine__create_kernel_maps(struct machine *machine); 149int machine__create_kernel_maps(struct machine *machine);
142 150
143int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); 151int machines__create_kernel_maps(struct machines *machines, pid_t pid);
144int machines__create_guest_kernel_maps(struct rb_root *machines); 152int machines__create_guest_kernel_maps(struct machines *machines);
145void machines__destroy_guest_kernel_maps(struct rb_root *machines); 153void machines__destroy_kernel_maps(struct machines *machines);
146 154
147size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 155size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
148 156
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0328d45c4f2a..ff94425779a2 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -19,7 +19,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
19 19
20static inline int is_anon_memory(const char *filename) 20static inline int is_anon_memory(const char *filename)
21{ 21{
22 return strcmp(filename, "//anon") == 0; 22 return !strcmp(filename, "//anon") ||
23 !strcmp(filename, "/anon_hugepage (deleted)");
23} 24}
24 25
25static inline int is_no_dso_memory(const char *filename) 26static inline int is_no_dso_memory(const char *filename)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d8d53bec17e..02f6421f03a0 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
380 return 0; 380 return 0;
381} 381}
382 382
383static int add_tracepoint_multi(struct list_head **list, int *idx, 383static int add_tracepoint_multi_event(struct list_head **list, int *idx,
384 char *sys_name, char *evt_name) 384 char *sys_name, char *evt_name)
385{ 385{
386 char evt_path[MAXPATHLEN]; 386 char evt_path[MAXPATHLEN];
387 struct dirent *evt_ent; 387 struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
409 } 409 }
410 410
411 closedir(evt_dir);
412 return ret;
413}
414
415static int add_tracepoint_event(struct list_head **list, int *idx,
416 char *sys_name, char *evt_name)
417{
418 return strpbrk(evt_name, "*?") ?
419 add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
420 add_tracepoint(list, idx, sys_name, evt_name);
421}
422
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
424 char *sys_name, char *evt_name)
425{
426 struct dirent *events_ent;
427 DIR *events_dir;
428 int ret = 0;
429
430 events_dir = opendir(tracing_events_path);
431 if (!events_dir) {
432 perror("Can't open event dir");
433 return -1;
434 }
435
436 while (!ret && (events_ent = readdir(events_dir))) {
437 if (!strcmp(events_ent->d_name, ".")
438 || !strcmp(events_ent->d_name, "..")
439 || !strcmp(events_ent->d_name, "enable")
440 || !strcmp(events_ent->d_name, "header_event")
441 || !strcmp(events_ent->d_name, "header_page"))
442 continue;
443
444 if (!strglobmatch(events_ent->d_name, sys_name))
445 continue;
446
447 ret = add_tracepoint_event(list, idx, events_ent->d_name,
448 evt_name);
449 }
450
451 closedir(events_dir);
411 return ret; 452 return ret;
412} 453}
413 454
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
420 if (ret) 461 if (ret)
421 return ret; 462 return ret;
422 463
423 return strpbrk(event, "*?") ? 464 if (strpbrk(sys, "*?"))
424 add_tracepoint_multi(list, idx, sys, event) : 465 return add_tracepoint_multi_sys(list, idx, sys, event);
425 add_tracepoint(list, idx, sys, event); 466 else
467 return add_tracepoint_event(list, idx, sys, event);
426} 468}
427 469
428static int 470static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
492} 534}
493 535
494static int config_term(struct perf_event_attr *attr, 536static int config_term(struct perf_event_attr *attr,
495 struct parse_events__term *term) 537 struct parse_events_term *term)
496{ 538{
497#define CHECK_TYPE_VAL(type) \ 539#define CHECK_TYPE_VAL(type) \
498do { \ 540do { \
@@ -537,7 +579,7 @@ do { \
537static int config_attr(struct perf_event_attr *attr, 579static int config_attr(struct perf_event_attr *attr,
538 struct list_head *head, int fail) 580 struct list_head *head, int fail)
539{ 581{
540 struct parse_events__term *term; 582 struct parse_events_term *term;
541 583
542 list_for_each_entry(term, head, list) 584 list_for_each_entry(term, head, list)
543 if (config_term(attr, term) && fail) 585 if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
563 return add_event(list, idx, &attr, NULL); 605 return add_event(list, idx, &attr, NULL);
564} 606}
565 607
566static int parse_events__is_name_term(struct parse_events__term *term) 608static int parse_events__is_name_term(struct parse_events_term *term)
567{ 609{
568 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 610 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
569} 611}
570 612
571static char *pmu_event_name(struct list_head *head_terms) 613static char *pmu_event_name(struct list_head *head_terms)
572{ 614{
573 struct parse_events__term *term; 615 struct parse_events_term *term;
574 616
575 list_for_each_entry(term, head_terms, list) 617 list_for_each_entry(term, head_terms, list)
576 if (parse_events__is_name_term(term)) 618 if (parse_events__is_name_term(term))
@@ -814,7 +856,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
814 */ 856 */
815int parse_events_terms(struct list_head *terms, const char *str) 857int parse_events_terms(struct list_head *terms, const char *str)
816{ 858{
817 struct parse_events_data__terms data = { 859 struct parse_events_terms data = {
818 .terms = NULL, 860 .terms = NULL,
819 }; 861 };
820 int ret; 862 int ret;
@@ -830,10 +872,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
830 return ret; 872 return ret;
831} 873}
832 874
833int parse_events(struct perf_evlist *evlist, const char *str, 875int parse_events(struct perf_evlist *evlist, const char *str)
834 int unset __maybe_unused)
835{ 876{
836 struct parse_events_data__events data = { 877 struct parse_events_evlist data = {
837 .list = LIST_HEAD_INIT(data.list), 878 .list = LIST_HEAD_INIT(data.list),
838 .idx = evlist->nr_entries, 879 .idx = evlist->nr_entries,
839 }; 880 };
@@ -858,7 +899,7 @@ int parse_events_option(const struct option *opt, const char *str,
858 int unset __maybe_unused) 899 int unset __maybe_unused)
859{ 900{
860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 901 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
861 int ret = parse_events(evlist, str, unset); 902 int ret = parse_events(evlist, str);
862 903
863 if (ret) { 904 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str); 905 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1162,16 @@ void print_events(const char *event_glob, bool name_only)
1121 print_tracepoint_events(NULL, NULL, name_only); 1162 print_tracepoint_events(NULL, NULL, name_only);
1122} 1163}
1123 1164
1124int parse_events__is_hardcoded_term(struct parse_events__term *term) 1165int parse_events__is_hardcoded_term(struct parse_events_term *term)
1125{ 1166{
1126 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 1167 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1127} 1168}
1128 1169
1129static int new_term(struct parse_events__term **_term, int type_val, 1170static int new_term(struct parse_events_term **_term, int type_val,
1130 int type_term, char *config, 1171 int type_term, char *config,
1131 char *str, u64 num) 1172 char *str, u64 num)
1132{ 1173{
1133 struct parse_events__term *term; 1174 struct parse_events_term *term;
1134 1175
1135 term = zalloc(sizeof(*term)); 1176 term = zalloc(sizeof(*term));
1136 if (!term) 1177 if (!term)
@@ -1156,21 +1197,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
1156 return 0; 1197 return 0;
1157} 1198}
1158 1199
1159int parse_events__term_num(struct parse_events__term **term, 1200int parse_events_term__num(struct parse_events_term **term,
1160 int type_term, char *config, u64 num) 1201 int type_term, char *config, u64 num)
1161{ 1202{
1162 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1203 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1163 config, NULL, num); 1204 config, NULL, num);
1164} 1205}
1165 1206
1166int parse_events__term_str(struct parse_events__term **term, 1207int parse_events_term__str(struct parse_events_term **term,
1167 int type_term, char *config, char *str) 1208 int type_term, char *config, char *str)
1168{ 1209{
1169 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1210 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1170 config, str, 0); 1211 config, str, 0);
1171} 1212}
1172 1213
1173int parse_events__term_sym_hw(struct parse_events__term **term, 1214int parse_events_term__sym_hw(struct parse_events_term **term,
1174 char *config, unsigned idx) 1215 char *config, unsigned idx)
1175{ 1216{
1176 struct event_symbol *sym; 1217 struct event_symbol *sym;
@@ -1188,8 +1229,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
1188 (char *) "event", (char *) sym->symbol, 0); 1229 (char *) "event", (char *) sym->symbol, 0);
1189} 1230}
1190 1231
1191int parse_events__term_clone(struct parse_events__term **new, 1232int parse_events_term__clone(struct parse_events_term **new,
1192 struct parse_events__term *term) 1233 struct parse_events_term *term)
1193{ 1234{
1194 return new_term(new, term->type_val, term->type_term, term->config, 1235 return new_term(new, term->type_val, term->type_term, term->config,
1195 term->val.str, term->val.num); 1236 term->val.str, term->val.num);
@@ -1197,7 +1238,7 @@ int parse_events__term_clone(struct parse_events__term **new,
1197 1238
1198void parse_events__free_terms(struct list_head *terms) 1239void parse_events__free_terms(struct list_head *terms)
1199{ 1240{
1200 struct parse_events__term *term, *h; 1241 struct parse_events_term *term, *h;
1201 1242
1202 list_for_each_entry_safe(term, h, terms, list) 1243 list_for_each_entry_safe(term, h, terms, list)
1203 free(term); 1244 free(term);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b7af80b8bdda..2cd2c42a69c5 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -29,8 +29,7 @@ const char *event_type(int type);
29 29
30extern int parse_events_option(const struct option *opt, const char *str, 30extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 31 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str, 32extern int parse_events(struct perf_evlist *evlist, const char *str);
33 int unset);
34extern int parse_events_terms(struct list_head *terms, const char *str); 33extern int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_filter(const struct option *opt, const char *str, int unset); 34extern int parse_filter(const struct option *opt, const char *str, int unset);
36 35
@@ -51,7 +50,7 @@ enum {
51 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 50 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
52}; 51};
53 52
54struct parse_events__term { 53struct parse_events_term {
55 char *config; 54 char *config;
56 union { 55 union {
57 char *str; 56 char *str;
@@ -62,24 +61,24 @@ struct parse_events__term {
62 struct list_head list; 61 struct list_head list;
63}; 62};
64 63
65struct parse_events_data__events { 64struct parse_events_evlist {
66 struct list_head list; 65 struct list_head list;
67 int idx; 66 int idx;
68}; 67};
69 68
70struct parse_events_data__terms { 69struct parse_events_terms {
71 struct list_head *terms; 70 struct list_head *terms;
72}; 71};
73 72
74int parse_events__is_hardcoded_term(struct parse_events__term *term); 73int parse_events__is_hardcoded_term(struct parse_events_term *term);
75int parse_events__term_num(struct parse_events__term **_term, 74int parse_events_term__num(struct parse_events_term **_term,
76 int type_term, char *config, u64 num); 75 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 76int parse_events_term__str(struct parse_events_term **_term,
78 int type_term, char *config, char *str); 77 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term, 78int parse_events_term__sym_hw(struct parse_events_term **term,
80 char *config, unsigned idx); 79 char *config, unsigned idx);
81int parse_events__term_clone(struct parse_events__term **new, 80int parse_events_term__clone(struct parse_events_term **new,
82 struct parse_events__term *term); 81 struct parse_events_term *term);
83void parse_events__free_terms(struct list_head *terms); 82void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 83int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 84int parse_events__modifier_group(struct list_head *list, char *event_mod);
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 0f9914ae6bac..9d43c86176ff 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -68,7 +68,7 @@ do { \
68 char *str; 68 char *str;
69 u64 num; 69 u64 num;
70 struct list_head *head; 70 struct list_head *head;
71 struct parse_events__term *term; 71 struct parse_events_term *term;
72} 72}
73%% 73%%
74 74
@@ -79,7 +79,7 @@ PE_START_TERMS start_terms
79 79
80start_events: groups 80start_events: groups
81{ 81{
82 struct parse_events_data__events *data = _data; 82 struct parse_events_evlist *data = _data;
83 83
84 parse_events_update_lists($1, &data->list); 84 parse_events_update_lists($1, &data->list);
85} 85}
@@ -186,7 +186,7 @@ event_def: event_pmu |
186event_pmu: 186event_pmu:
187PE_NAME '/' event_config '/' 187PE_NAME '/' event_config '/'
188{ 188{
189 struct parse_events_data__events *data = _data; 189 struct parse_events_evlist *data = _data;
190 struct list_head *list = NULL; 190 struct list_head *list = NULL;
191 191
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +202,7 @@ PE_VALUE_SYM_SW
202event_legacy_symbol: 202event_legacy_symbol:
203value_sym '/' event_config '/' 203value_sym '/' event_config '/'
204{ 204{
205 struct parse_events_data__events *data = _data; 205 struct parse_events_evlist *data = _data;
206 struct list_head *list = NULL; 206 struct list_head *list = NULL;
207 int type = $1 >> 16; 207 int type = $1 >> 16;
208 int config = $1 & 255; 208 int config = $1 & 255;
@@ -215,7 +215,7 @@ value_sym '/' event_config '/'
215| 215|
216value_sym sep_slash_dc 216value_sym sep_slash_dc
217{ 217{
218 struct parse_events_data__events *data = _data; 218 struct parse_events_evlist *data = _data;
219 struct list_head *list = NULL; 219 struct list_head *list = NULL;
220 int type = $1 >> 16; 220 int type = $1 >> 16;
221 int config = $1 & 255; 221 int config = $1 & 255;
@@ -228,7 +228,7 @@ value_sym sep_slash_dc
228event_legacy_cache: 228event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{ 230{
231 struct parse_events_data__events *data = _data; 231 struct parse_events_evlist *data = _data;
232 struct list_head *list = NULL; 232 struct list_head *list = NULL;
233 233
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +237,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
237| 237|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{ 239{
240 struct parse_events_data__events *data = _data; 240 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 241 struct list_head *list = NULL;
242 242
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
246| 246|
247PE_NAME_CACHE_TYPE 247PE_NAME_CACHE_TYPE
248{ 248{
249 struct parse_events_data__events *data = _data; 249 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 250 struct list_head *list = NULL;
251 251
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +256,7 @@ PE_NAME_CACHE_TYPE
256event_legacy_mem: 256event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{ 258{
259 struct parse_events_data__events *data = _data; 259 struct parse_events_evlist *data = _data;
260 struct list_head *list = NULL; 260 struct list_head *list = NULL;
261 261
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +266,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
266| 266|
267PE_PREFIX_MEM PE_VALUE sep_dc 267PE_PREFIX_MEM PE_VALUE sep_dc
268{ 268{
269 struct parse_events_data__events *data = _data; 269 struct parse_events_evlist *data = _data;
270 struct list_head *list = NULL; 270 struct list_head *list = NULL;
271 271
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +277,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
277event_legacy_tracepoint: 277event_legacy_tracepoint:
278PE_NAME ':' PE_NAME 278PE_NAME ':' PE_NAME
279{ 279{
280 struct parse_events_data__events *data = _data; 280 struct parse_events_evlist *data = _data;
281 struct list_head *list = NULL; 281 struct list_head *list = NULL;
282 282
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +287,7 @@ PE_NAME ':' PE_NAME
287event_legacy_numeric: 287event_legacy_numeric:
288PE_VALUE ':' PE_VALUE 288PE_VALUE ':' PE_VALUE
289{ 289{
290 struct parse_events_data__events *data = _data; 290 struct parse_events_evlist *data = _data;
291 struct list_head *list = NULL; 291 struct list_head *list = NULL;
292 292
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +297,7 @@ PE_VALUE ':' PE_VALUE
297event_legacy_raw: 297event_legacy_raw:
298PE_RAW 298PE_RAW
299{ 299{
300 struct parse_events_data__events *data = _data; 300 struct parse_events_evlist *data = _data;
301 struct list_head *list = NULL; 301 struct list_head *list = NULL;
302 302
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 303 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +307,7 @@ PE_RAW
307 307
308start_terms: event_config 308start_terms: event_config
309{ 309{
310 struct parse_events_data__terms *data = _data; 310 struct parse_events_terms *data = _data;
311 data->terms = $1; 311 data->terms = $1;
312} 312}
313 313
@@ -315,7 +315,7 @@ event_config:
315event_config ',' event_term 315event_config ',' event_term
316{ 316{
317 struct list_head *head = $1; 317 struct list_head *head = $1;
318 struct parse_events__term *term = $3; 318 struct parse_events_term *term = $3;
319 319
320 ABORT_ON(!head); 320 ABORT_ON(!head);
321 list_add_tail(&term->list, head); 321 list_add_tail(&term->list, head);
@@ -325,7 +325,7 @@ event_config ',' event_term
325event_term 325event_term
326{ 326{
327 struct list_head *head = malloc(sizeof(*head)); 327 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1; 328 struct parse_events_term *term = $1;
329 329
330 ABORT_ON(!head); 330 ABORT_ON(!head);
331 INIT_LIST_HEAD(head); 331 INIT_LIST_HEAD(head);
@@ -336,70 +336,70 @@ event_term
336event_term: 336event_term:
337PE_NAME '=' PE_NAME 337PE_NAME '=' PE_NAME
338{ 338{
339 struct parse_events__term *term; 339 struct parse_events_term *term;
340 340
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, 341 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3)); 342 $1, $3));
343 $$ = term; 343 $$ = term;
344} 344}
345| 345|
346PE_NAME '=' PE_VALUE 346PE_NAME '=' PE_VALUE
347{ 347{
348 struct parse_events__term *term; 348 struct parse_events_term *term;
349 349
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 350 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3)); 351 $1, $3));
352 $$ = term; 352 $$ = term;
353} 353}
354| 354|
355PE_NAME '=' PE_VALUE_SYM_HW 355PE_NAME '=' PE_VALUE_SYM_HW
356{ 356{
357 struct parse_events__term *term; 357 struct parse_events_term *term;
358 int config = $3 & 255; 358 int config = $3 & 255;
359 359
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); 360 ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
361 $$ = term; 361 $$ = term;
362} 362}
363| 363|
364PE_NAME 364PE_NAME
365{ 365{
366 struct parse_events__term *term; 366 struct parse_events_term *term;
367 367
368 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 368 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
369 $1, 1)); 369 $1, 1));
370 $$ = term; 370 $$ = term;
371} 371}
372| 372|
373PE_VALUE_SYM_HW 373PE_VALUE_SYM_HW
374{ 374{
375 struct parse_events__term *term; 375 struct parse_events_term *term;
376 int config = $1 & 255; 376 int config = $1 & 255;
377 377
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); 378 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
379 $$ = term; 379 $$ = term;
380} 380}
381| 381|
382PE_TERM '=' PE_NAME 382PE_TERM '=' PE_NAME
383{ 383{
384 struct parse_events__term *term; 384 struct parse_events_term *term;
385 385
386 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); 386 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
387 $$ = term; 387 $$ = term;
388} 388}
389| 389|
390PE_TERM '=' PE_VALUE 390PE_TERM '=' PE_VALUE
391{ 391{
392 struct parse_events__term *term; 392 struct parse_events_term *term;
393 393
394 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); 394 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
395 $$ = term; 395 $$ = term;
396} 396}
397| 397|
398PE_TERM 398PE_TERM
399{ 399{
400 struct parse_events__term *term; 400 struct parse_events_term *term;
401 401
402 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); 402 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
403 $$ = term; 403 $$ = term;
404} 404}
405 405
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 9bdc60c6f138..4c6f9c490a8d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,4 +1,3 @@
1
2#include <linux/list.h> 1#include <linux/list.h>
3#include <sys/types.h> 2#include <sys/types.h>
4#include <sys/stat.h> 3#include <sys/stat.h>
@@ -11,6 +10,19 @@
11#include "parse-events.h" 10#include "parse-events.h"
12#include "cpumap.h" 11#include "cpumap.h"
13 12
13struct perf_pmu_alias {
14 char *name;
15 struct list_head terms;
16 struct list_head list;
17};
18
19struct perf_pmu_format {
20 char *name;
21 int value;
22 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
23 struct list_head list;
24};
25
14#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 26#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15 27
16int perf_pmu_parse(struct list_head *list, char *name); 28int perf_pmu_parse(struct list_head *list, char *name);
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
85 97
86static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 98static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87{ 99{
88 struct perf_pmu__alias *alias; 100 struct perf_pmu_alias *alias;
89 char buf[256]; 101 char buf[256];
90 int ret; 102 int ret;
91 103
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
172 return 0; 184 return 0;
173} 185}
174 186
175static int pmu_alias_terms(struct perf_pmu__alias *alias, 187static int pmu_alias_terms(struct perf_pmu_alias *alias,
176 struct list_head *terms) 188 struct list_head *terms)
177{ 189{
178 struct parse_events__term *term, *clone; 190 struct parse_events_term *term, *clone;
179 LIST_HEAD(list); 191 LIST_HEAD(list);
180 int ret; 192 int ret;
181 193
182 list_for_each_entry(term, &alias->terms, list) { 194 list_for_each_entry(term, &alias->terms, list) {
183 ret = parse_events__term_clone(&clone, term); 195 ret = parse_events_term__clone(&clone, term);
184 if (ret) { 196 if (ret) {
185 parse_events__free_terms(&list); 197 parse_events__free_terms(&list);
186 return ret; 198 return ret;
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
360 return pmu_lookup(name); 372 return pmu_lookup(name);
361} 373}
362 374
363static struct perf_pmu__format* 375static struct perf_pmu_format *
364pmu_find_format(struct list_head *formats, char *name) 376pmu_find_format(struct list_head *formats, char *name)
365{ 377{
366 struct perf_pmu__format *format; 378 struct perf_pmu_format *format;
367 379
368 list_for_each_entry(format, formats, list) 380 list_for_each_entry(format, formats, list)
369 if (!strcmp(format->name, name)) 381 if (!strcmp(format->name, name))
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
403 */ 415 */
404static int pmu_config_term(struct list_head *formats, 416static int pmu_config_term(struct list_head *formats,
405 struct perf_event_attr *attr, 417 struct perf_event_attr *attr,
406 struct parse_events__term *term) 418 struct parse_events_term *term)
407{ 419{
408 struct perf_pmu__format *format; 420 struct perf_pmu_format *format;
409 __u64 *vp; 421 __u64 *vp;
410 422
411 /* 423 /*
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats,
450 struct perf_event_attr *attr, 462 struct perf_event_attr *attr,
451 struct list_head *head_terms) 463 struct list_head *head_terms)
452{ 464{
453 struct parse_events__term *term; 465 struct parse_events_term *term;
454 466
455 list_for_each_entry(term, head_terms, list) 467 list_for_each_entry(term, head_terms, list)
456 if (pmu_config_term(formats, attr, term)) 468 if (pmu_config_term(formats, attr, term))
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
471 return perf_pmu__config_terms(&pmu->format, attr, head_terms); 483 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
472} 484}
473 485
474static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 486static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
475 struct parse_events__term *term) 487 struct parse_events_term *term)
476{ 488{
477 struct perf_pmu__alias *alias; 489 struct perf_pmu_alias *alias;
478 char *name; 490 char *name;
479 491
480 if (parse_events__is_hardcoded_term(term)) 492 if (parse_events__is_hardcoded_term(term))
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
507 */ 519 */
508int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 520int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
509{ 521{
510 struct parse_events__term *term, *h; 522 struct parse_events_term *term, *h;
511 struct perf_pmu__alias *alias; 523 struct perf_pmu_alias *alias;
512 int ret; 524 int ret;
513 525
514 list_for_each_entry_safe(term, h, head_terms, list) { 526 list_for_each_entry_safe(term, h, head_terms, list) {
@@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
527int perf_pmu__new_format(struct list_head *list, char *name, 539int perf_pmu__new_format(struct list_head *list, char *name,
528 int config, unsigned long *bits) 540 int config, unsigned long *bits)
529{ 541{
530 struct perf_pmu__format *format; 542 struct perf_pmu_format *format;
531 543
532 format = zalloc(sizeof(*format)); 544 format = zalloc(sizeof(*format));
533 if (!format) 545 if (!format)
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
548 if (!to) 560 if (!to)
549 to = from; 561 to = from;
550 562
551 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 563 memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
552 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
553 set_bit(b, bits); 565 set_bit(b, bits);
554} 566}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index a313ed76a49a..32fe55b659fa 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -12,19 +12,6 @@ enum {
12 12
13#define PERF_PMU_FORMAT_BITS 64 13#define PERF_PMU_FORMAT_BITS 64
14 14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu__alias {
23 char *name;
24 struct list_head terms;
25 struct list_head list;
26};
27
28struct perf_pmu { 15struct perf_pmu {
29 char *name; 16 char *name;
30 __u32 type; 17 __u32 type;
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats,
42 struct list_head *head_terms); 29 struct list_head *head_terms);
43int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 30int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
44struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 31struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
45 struct list_head *head_terms); 32 struct list_head *head_terms);
46int perf_pmu_wrap(void); 33int perf_pmu_wrap(void);
47void perf_pmu_error(struct list_head *list, char *name, char const *msg); 34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
48 35
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1daf5c14e751..be0329394d56 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
413 dwarf_diename(vr_die), dwarf_diename(&type)); 413 dwarf_diename(vr_die), dwarf_diename(&type));
414 return -EINVAL; 414 return -EINVAL;
415 } 415 }
416 if (die_get_real_type(&type, &type) == NULL) {
417 pr_warning("Failed to get a type"
418 " information.\n");
419 return -ENOENT;
420 }
416 if (ret == DW_TAG_pointer_type) { 421 if (ret == DW_TAG_pointer_type) {
417 if (die_get_real_type(&type, &type) == NULL) {
418 pr_warning("Failed to get a type"
419 " information.\n");
420 return -ENOENT;
421 }
422 while (*ref_ptr) 422 while (*ref_ptr)
423 ref_ptr = &(*ref_ptr)->next; 423 ref_ptr = &(*ref_ptr)->next;
424 /* Add new reference with offset +0 */ 424 /* Add new reference with offset +0 */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index a2657fd96837..925e0c3e6d91 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1045,3 +1045,12 @@ error:
1045 if (PyErr_Occurred()) 1045 if (PyErr_Occurred())
1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); 1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1047} 1047}
1048
1049/*
1050 * Dummy, to avoid dragging all the test_attr infrastructure in the python
1051 * binding.
1052 */
1053void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
1054 int fd, int group_fd, unsigned long flags)
1055{
1056}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index f80605eb1855..eacec859f299 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
292 ns = nsecs - s * NSECS_PER_SEC; 292 ns = nsecs - s * NSECS_PER_SEC;
293 293
294 scripting_context->event_data = data; 294 scripting_context->event_data = data;
295 scripting_context->pevent = evsel->tp_format->pevent;
295 296
296 ENTER; 297 ENTER;
297 SAVETMPS; 298 SAVETMPS;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 14683dfca2ee..e87aa5d9696b 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
265 ns = nsecs - s * NSECS_PER_SEC; 265 ns = nsecs - s * NSECS_PER_SEC;
266 266
267 scripting_context->event_data = data; 267 scripting_context->event_data = data;
268 scripting_context->pevent = evsel->tp_format->pevent;
268 269
269 context = PyCObject_FromVoidPtr(scripting_context, NULL); 270 context = PyCObject_FromVoidPtr(scripting_context, NULL);
270 271
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 76d6e257b8a4..bd85280bb6e8 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -86,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
86{ 86{
87 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 87 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
88 88
89 session->host_machine.id_hdr_size = id_hdr_size;
90 machines__set_id_hdr_size(&session->machines, id_hdr_size); 89 machines__set_id_hdr_size(&session->machines, id_hdr_size);
91} 90}
92 91
93int perf_session__create_kernel_maps(struct perf_session *self) 92int perf_session__create_kernel_maps(struct perf_session *self)
94{ 93{
95 int ret = machine__create_kernel_maps(&self->host_machine); 94 int ret = machine__create_kernel_maps(&self->machines.host);
96 95
97 if (ret >= 0) 96 if (ret >= 0)
98 ret = machines__create_guest_kernel_maps(&self->machines); 97 ret = machines__create_guest_kernel_maps(&self->machines);
@@ -101,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
101 100
102static void perf_session__destroy_kernel_maps(struct perf_session *self) 101static void perf_session__destroy_kernel_maps(struct perf_session *self)
103{ 102{
104 machine__destroy_kernel_maps(&self->host_machine); 103 machines__destroy_kernel_maps(&self->machines);
105 machines__destroy_guest_kernel_maps(&self->machines);
106} 104}
107 105
108struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
@@ -127,13 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
127 goto out; 125 goto out;
128 126
129 memcpy(self->filename, filename, len); 127 memcpy(self->filename, filename, len);
130 self->machines = RB_ROOT;
131 self->repipe = repipe; 128 self->repipe = repipe;
132 INIT_LIST_HEAD(&self->ordered_samples.samples); 129 INIT_LIST_HEAD(&self->ordered_samples.samples);
133 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 130 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
134 INIT_LIST_HEAD(&self->ordered_samples.to_free); 131 INIT_LIST_HEAD(&self->ordered_samples.to_free);
135 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 132 machines__init(&self->machines);
136 hists__init(&self->hists);
137 133
138 if (mode == O_RDONLY) { 134 if (mode == O_RDONLY) {
139 if (perf_session__open(self, force) < 0) 135 if (perf_session__open(self, force) < 0)
@@ -163,12 +159,12 @@ out_delete:
163 159
164static void perf_session__delete_dead_threads(struct perf_session *session) 160static void perf_session__delete_dead_threads(struct perf_session *session)
165{ 161{
166 machine__delete_dead_threads(&session->host_machine); 162 machine__delete_dead_threads(&session->machines.host);
167} 163}
168 164
169static void perf_session__delete_threads(struct perf_session *session) 165static void perf_session__delete_threads(struct perf_session *session)
170{ 166{
171 machine__delete_threads(&session->host_machine); 167 machine__delete_threads(&session->machines.host);
172} 168}
173 169
174static void perf_session_env__delete(struct perf_session_env *env) 170static void perf_session_env__delete(struct perf_session_env *env)
@@ -193,7 +189,7 @@ void perf_session__delete(struct perf_session *self)
193 perf_session__delete_dead_threads(self); 189 perf_session__delete_dead_threads(self);
194 perf_session__delete_threads(self); 190 perf_session__delete_threads(self);
195 perf_session_env__delete(&self->header.env); 191 perf_session_env__delete(&self->header.env);
196 machine__exit(&self->host_machine); 192 machines__exit(&self->machines);
197 close(self->fd); 193 close(self->fd);
198 free(self); 194 free(self);
199 vdso__exit(); 195 vdso__exit();
@@ -825,7 +821,7 @@ static struct machine *
825 return perf_session__findnew_machine(session, pid); 821 return perf_session__findnew_machine(session, pid);
826 } 822 }
827 823
828 return perf_session__find_host_machine(session); 824 return &session->machines.host;
829} 825}
830 826
831static int perf_session_deliver_event(struct perf_session *session, 827static int perf_session_deliver_event(struct perf_session *session,
@@ -863,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
863 case PERF_RECORD_SAMPLE: 859 case PERF_RECORD_SAMPLE:
864 dump_sample(evsel, event, sample); 860 dump_sample(evsel, event, sample);
865 if (evsel == NULL) { 861 if (evsel == NULL) {
866 ++session->hists.stats.nr_unknown_id; 862 ++session->stats.nr_unknown_id;
867 return 0; 863 return 0;
868 } 864 }
869 if (machine == NULL) { 865 if (machine == NULL) {
870 ++session->hists.stats.nr_unprocessable_samples; 866 ++session->stats.nr_unprocessable_samples;
871 return 0; 867 return 0;
872 } 868 }
873 return tool->sample(tool, event, sample, evsel, machine); 869 return tool->sample(tool, event, sample, evsel, machine);
@@ -881,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
881 return tool->exit(tool, event, sample, machine); 877 return tool->exit(tool, event, sample, machine);
882 case PERF_RECORD_LOST: 878 case PERF_RECORD_LOST:
883 if (tool->lost == perf_event__process_lost) 879 if (tool->lost == perf_event__process_lost)
884 session->hists.stats.total_lost += event->lost.lost; 880 session->stats.total_lost += event->lost.lost;
885 return tool->lost(tool, event, sample, machine); 881 return tool->lost(tool, event, sample, machine);
886 case PERF_RECORD_READ: 882 case PERF_RECORD_READ:
887 return tool->read(tool, event, sample, evsel, machine); 883 return tool->read(tool, event, sample, evsel, machine);
@@ -890,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
890 case PERF_RECORD_UNTHROTTLE: 886 case PERF_RECORD_UNTHROTTLE:
891 return tool->unthrottle(tool, event, sample, machine); 887 return tool->unthrottle(tool, event, sample, machine);
892 default: 888 default:
893 ++session->hists.stats.nr_unknown_events; 889 ++session->stats.nr_unknown_events;
894 return -1; 890 return -1;
895 } 891 }
896} 892}
@@ -904,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
904 900
905 if (!ip_callchain__valid(sample->callchain, event)) { 901 if (!ip_callchain__valid(sample->callchain, event)) {
906 pr_debug("call-chain problem with event, skipping it.\n"); 902 pr_debug("call-chain problem with event, skipping it.\n");
907 ++session->hists.stats.nr_invalid_chains; 903 ++session->stats.nr_invalid_chains;
908 session->hists.stats.total_invalid_chains += sample->period; 904 session->stats.total_invalid_chains += sample->period;
909 return -EINVAL; 905 return -EINVAL;
910 } 906 }
911 return 0; 907 return 0;
@@ -963,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
963 if (event->header.type >= PERF_RECORD_HEADER_MAX) 959 if (event->header.type >= PERF_RECORD_HEADER_MAX)
964 return -EINVAL; 960 return -EINVAL;
965 961
966 hists__inc_nr_events(&session->hists, event->header.type); 962 events_stats__inc(&session->stats, event->header.type);
967 963
968 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 964 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
969 return perf_session__process_user_event(session, event, tool, file_offset); 965 return perf_session__process_user_event(session, event, tool, file_offset);
@@ -999,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
999 995
1000struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 996struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1001{ 997{
1002 return machine__findnew_thread(&session->host_machine, pid); 998 return machine__findnew_thread(&session->machines.host, pid);
1003} 999}
1004 1000
1005static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1001static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1018,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1018 const struct perf_tool *tool) 1014 const struct perf_tool *tool)
1019{ 1015{
1020 if (tool->lost == perf_event__process_lost && 1016 if (tool->lost == perf_event__process_lost &&
1021 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 1017 session->stats.nr_events[PERF_RECORD_LOST] != 0) {
1022 ui__warning("Processed %d events and lost %d chunks!\n\n" 1018 ui__warning("Processed %d events and lost %d chunks!\n\n"
1023 "Check IO/CPU overload!\n\n", 1019 "Check IO/CPU overload!\n\n",
1024 session->hists.stats.nr_events[0], 1020 session->stats.nr_events[0],
1025 session->hists.stats.nr_events[PERF_RECORD_LOST]); 1021 session->stats.nr_events[PERF_RECORD_LOST]);
1026 } 1022 }
1027 1023
1028 if (session->hists.stats.nr_unknown_events != 0) { 1024 if (session->stats.nr_unknown_events != 0) {
1029 ui__warning("Found %u unknown events!\n\n" 1025 ui__warning("Found %u unknown events!\n\n"
1030 "Is this an older tool processing a perf.data " 1026 "Is this an older tool processing a perf.data "
1031 "file generated by a more recent tool?\n\n" 1027 "file generated by a more recent tool?\n\n"
1032 "If that is not the case, consider " 1028 "If that is not the case, consider "
1033 "reporting to linux-kernel@vger.kernel.org.\n\n", 1029 "reporting to linux-kernel@vger.kernel.org.\n\n",
1034 session->hists.stats.nr_unknown_events); 1030 session->stats.nr_unknown_events);
1035 } 1031 }
1036 1032
1037 if (session->hists.stats.nr_unknown_id != 0) { 1033 if (session->stats.nr_unknown_id != 0) {
1038 ui__warning("%u samples with id not present in the header\n", 1034 ui__warning("%u samples with id not present in the header\n",
1039 session->hists.stats.nr_unknown_id); 1035 session->stats.nr_unknown_id);
1040 } 1036 }
1041 1037
1042 if (session->hists.stats.nr_invalid_chains != 0) { 1038 if (session->stats.nr_invalid_chains != 0) {
1043 ui__warning("Found invalid callchains!\n\n" 1039 ui__warning("Found invalid callchains!\n\n"
1044 "%u out of %u events were discarded for this reason.\n\n" 1040 "%u out of %u events were discarded for this reason.\n\n"
1045 "Consider reporting to linux-kernel@vger.kernel.org.\n\n", 1041 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1046 session->hists.stats.nr_invalid_chains, 1042 session->stats.nr_invalid_chains,
1047 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1043 session->stats.nr_events[PERF_RECORD_SAMPLE]);
1048 } 1044 }
1049 1045
1050 if (session->hists.stats.nr_unprocessable_samples != 0) { 1046 if (session->stats.nr_unprocessable_samples != 0) {
1051 ui__warning("%u unprocessable samples recorded.\n" 1047 ui__warning("%u unprocessable samples recorded.\n"
1052 "Do you have a KVM guest running and not using 'perf kvm'?\n", 1048 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1053 session->hists.stats.nr_unprocessable_samples); 1049 session->stats.nr_unprocessable_samples);
1054 } 1050 }
1055} 1051}
1056 1052
@@ -1336,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1336 1332
1337size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1333size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1338{ 1334{
1339 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + 1335 return machines__fprintf_dsos(&self->machines, fp);
1340 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1341 machines__fprintf_dsos(&self->machines, fp);
1342} 1336}
1343 1337
1344size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1338size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1345 bool (skip)(struct dso *dso, int parm), int parm) 1339 bool (skip)(struct dso *dso, int parm), int parm)
1346{ 1340{
1347 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); 1341 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1348 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1349} 1342}
1350 1343
1351size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1344size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1353,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1353 struct perf_evsel *pos; 1346 struct perf_evsel *pos;
1354 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1347 size_t ret = fprintf(fp, "Aggregated stats:\n");
1355 1348
1356 ret += hists__fprintf_nr_events(&session->hists, fp); 1349 ret += events_stats__fprintf(&session->stats, fp);
1357 1350
1358 list_for_each_entry(pos, &session->evlist->entries, node) { 1351 list_for_each_entry(pos, &session->evlist->entries, node) {
1359 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1352 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1360 ret += hists__fprintf_nr_events(&pos->hists, fp); 1353 ret += events_stats__fprintf(&pos->hists.stats, fp);
1361 } 1354 }
1362 1355
1363 return ret; 1356 return ret;
@@ -1369,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1369 * FIXME: Here we have to actually print all the machines in this 1362 * FIXME: Here we have to actually print all the machines in this
1370 * session, not just the host... 1363 * session, not just the host...
1371 */ 1364 */
1372 return machine__fprintf(&session->host_machine, fp); 1365 return machine__fprintf(&session->machines.host, fp);
1373} 1366}
1374 1367
1375void perf_session__remove_thread(struct perf_session *session, 1368void perf_session__remove_thread(struct perf_session *session,
@@ -1378,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
1378 /* 1371 /*
1379 * FIXME: This one makes no sense, we need to remove the thread from 1372 * FIXME: This one makes no sense, we need to remove the thread from
1380 * the machine it belongs to, perf_session can have many machines, so 1373 * the machine it belongs to, perf_session can have many machines, so
1381 * doing it always on ->host_machine is wrong. Fix when auditing all 1374 * doing it always on ->machines.host is wrong. Fix when auditing all
1382 * the 'perf kvm' code. 1375 * the 'perf kvm' code.
1383 */ 1376 */
1384 machine__remove_thread(&session->host_machine, th); 1377 machine__remove_thread(&session->machines.host, th);
1385} 1378}
1386 1379
1387struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1380struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 8c2302504199..b5c0847edfa9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,15 +30,10 @@ struct ordered_samples {
30struct perf_session { 30struct perf_session {
31 struct perf_header header; 31 struct perf_header header;
32 unsigned long size; 32 unsigned long size;
33 struct machine host_machine; 33 struct machines machines;
34 struct rb_root machines;
35 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
36 struct pevent *pevent; 35 struct pevent *pevent;
37 /* 36 struct events_stats stats;
38 * FIXME: Need to split this up further, we need global
39 * stats + per event stats.
40 */
41 struct hists hists;
42 int fd; 37 int fd;
43 bool fd_pipe; 38 bool fd_pipe;
44 bool repipe; 39 bool repipe;
@@ -53,7 +48,7 @@ struct perf_tool;
53struct perf_session *perf_session__new(const char *filename, int mode, 48struct perf_session *perf_session__new(const char *filename, int mode,
54 bool force, bool repipe, 49 bool force, bool repipe,
55 struct perf_tool *tool); 50 struct perf_tool *tool);
56void perf_session__delete(struct perf_session *self); 51void perf_session__delete(struct perf_session *session);
57 52
58void perf_event_header__bswap(struct perf_event_header *self); 53void perf_event_header__bswap(struct perf_event_header *self);
59 54
@@ -80,36 +75,17 @@ void perf_session__set_id_hdr_size(struct perf_session *session);
80void perf_session__remove_thread(struct perf_session *self, struct thread *th); 75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
81 76
82static inline 77static inline
83struct machine *perf_session__find_host_machine(struct perf_session *self)
84{
85 return &self->host_machine;
86}
87
88static inline
89struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 78struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
90{ 79{
91 if (pid == HOST_KERNEL_ID)
92 return &self->host_machine;
93 return machines__find(&self->machines, pid); 80 return machines__find(&self->machines, pid);
94} 81}
95 82
96static inline 83static inline
97struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 84struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
98{ 85{
99 if (pid == HOST_KERNEL_ID)
100 return &self->host_machine;
101 return machines__findnew(&self->machines, pid); 86 return machines__findnew(&self->machines, pid);
102} 87}
103 88
104static inline
105void perf_session__process_machines(struct perf_session *self,
106 struct perf_tool *tool,
107 machine__process_t process)
108{
109 process(&self->host_machine, tool);
110 return machines__process(&self->machines, process, tool);
111}
112
113struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 89struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
114size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 90size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
115 91
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32d..7ad62393aa88 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width) 61 size_t size, unsigned int width)
62{ 62{
63 return repsep_snprintf(bf, size, "%*s:%5d", width, 63 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
64 self->thread->comm ?: "", self->thread->pid); 64 self->thread->comm ?: "", self->thread->pid);
65} 65}
66 66
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 98}
99 99
100struct sort_entry sort_comm = {
101 .se_header = "Command",
102 .se_cmp = sort__comm_cmp,
103 .se_collapse = sort__comm_collapse,
104 .se_snprintf = hist_entry__comm_snprintf,
105 .se_width_idx = HISTC_COMM,
106};
107
108/* --sort dso */
109
100static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 110static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
101{ 111{
102 struct dso *dso_l = map_l ? map_l->dso : NULL; 112 struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,22 +127,38 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
117 return strcmp(dso_name_l, dso_name_r); 127 return strcmp(dso_name_l, dso_name_r);
118} 128}
119 129
120struct sort_entry sort_comm = {
121 .se_header = "Command",
122 .se_cmp = sort__comm_cmp,
123 .se_collapse = sort__comm_collapse,
124 .se_snprintf = hist_entry__comm_snprintf,
125 .se_width_idx = HISTC_COMM,
126};
127
128/* --sort dso */
129
130static int64_t 130static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132{ 132{
133 return _sort__dso_cmp(left->ms.map, right->ms.map); 133 return _sort__dso_cmp(left->ms.map, right->ms.map);
134} 134}
135 135
136static int _hist_entry__dso_snprintf(struct map *map, char *bf,
137 size_t size, unsigned int width)
138{
139 if (map && map->dso) {
140 const char *dso_name = !verbose ? map->dso->short_name :
141 map->dso->long_name;
142 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
143 }
144
145 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
146}
147
148static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
149 size_t size, unsigned int width)
150{
151 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
152}
153
154struct sort_entry sort_dso = {
155 .se_header = "Shared Object",
156 .se_cmp = sort__dso_cmp,
157 .se_snprintf = hist_entry__dso_snprintf,
158 .se_width_idx = HISTC_DSO,
159};
160
161/* --sort symbol */
136 162
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, 163static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r) 164 u64 ip_l, u64 ip_r)
@@ -143,35 +169,35 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
143 if (sym_l == sym_r) 169 if (sym_l == sym_r)
144 return 0; 170 return 0;
145 171
146 if (sym_l) 172 ip_l = sym_l->start;
147 ip_l = sym_l->start; 173 ip_r = sym_r->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150 174
151 return (int64_t)(ip_r - ip_l); 175 return (int64_t)(ip_r - ip_l);
152} 176}
153 177
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 178static int64_t
155 size_t size, unsigned int width) 179sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
156{ 180{
157 if (map && map->dso) { 181 u64 ip_l, ip_r;
158 const char *dso_name = !verbose ? map->dso->short_name :
159 map->dso->long_name;
160 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
161 }
162 182
163 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 183 if (!left->ms.sym && !right->ms.sym)
164} 184 return right->level - left->level;
165 185
166static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 186 if (!left->ms.sym || !right->ms.sym)
167 size_t size, unsigned int width) 187 return cmp_null(left->ms.sym, right->ms.sym);
168{ 188
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 189 if (left->ms.sym == right->ms.sym)
190 return 0;
191
192 ip_l = left->ms.sym->start;
193 ip_r = right->ms.sym->start;
194
195 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
170} 196}
171 197
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 198static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
173 u64 ip, char level, char *bf, size_t size, 199 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused) 200 unsigned int width)
175{ 201{
176 size_t ret = 0; 202 size_t ret = 0;
177 203
@@ -197,43 +223,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
197 return ret; 223 return ret;
198} 224}
199 225
200
201struct sort_entry sort_dso = {
202 .se_header = "Shared Object",
203 .se_cmp = sort__dso_cmp,
204 .se_snprintf = hist_entry__dso_snprintf,
205 .se_width_idx = HISTC_DSO,
206};
207
208static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 226static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size, 227 size_t size, unsigned int width)
210 unsigned int width __maybe_unused)
211{ 228{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 229 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width); 230 self->level, bf, size, width);
214} 231}
215 232
216/* --sort symbol */
217static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{
220 u64 ip_l, ip_r;
221
222 if (!left->ms.sym && !right->ms.sym)
223 return right->level - left->level;
224
225 if (!left->ms.sym || !right->ms.sym)
226 return cmp_null(left->ms.sym, right->ms.sym);
227
228 if (left->ms.sym == right->ms.sym)
229 return 0;
230
231 ip_l = left->ms.sym->start;
232 ip_r = right->ms.sym->start;
233
234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
235}
236
237struct sort_entry sort_sym = { 233struct sort_entry sort_sym = {
238 .se_header = "Symbol", 234 .se_header = "Symbol",
239 .se_cmp = sort__sym_cmp, 235 .se_cmp = sort__sym_cmp,
@@ -335,7 +331,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 331static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width) 332 size_t size, unsigned int width)
337{ 333{
338 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 334 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
339} 335}
340 336
341struct sort_entry sort_cpu = { 337struct sort_entry sort_cpu = {
@@ -345,6 +341,8 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 341 .se_width_idx = HISTC_CPU,
346}; 342};
347 343
344/* sort keys for branch stacks */
345
348static int64_t 346static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 347sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 348{
@@ -359,13 +357,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
359 bf, size, width); 357 bf, size, width);
360} 358}
361 359
362struct sort_entry sort_dso_from = {
363 .se_header = "Source Shared Object",
364 .se_cmp = sort__dso_from_cmp,
365 .se_snprintf = hist_entry__dso_from_snprintf,
366 .se_width_idx = HISTC_DSO_FROM,
367};
368
369static int64_t 360static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 361sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{ 362{
@@ -406,8 +397,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
406} 397}
407 398
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 399static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size, 400 size_t size, unsigned int width)
410 unsigned int width __maybe_unused)
411{ 401{
412 struct addr_map_symbol *from = &self->branch_info->from; 402 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 403 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +406,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
416} 406}
417 407
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 408static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size, 409 size_t size, unsigned int width)
420 unsigned int width __maybe_unused)
421{ 410{
422 struct addr_map_symbol *to = &self->branch_info->to; 411 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 412 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +414,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
425 414
426} 415}
427 416
417struct sort_entry sort_dso_from = {
418 .se_header = "Source Shared Object",
419 .se_cmp = sort__dso_from_cmp,
420 .se_snprintf = hist_entry__dso_from_snprintf,
421 .se_width_idx = HISTC_DSO_FROM,
422};
423
428struct sort_entry sort_dso_to = { 424struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object", 425 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp, 426 .se_cmp = sort__dso_to_cmp,
@@ -484,30 +480,40 @@ struct sort_dimension {
484 480
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 481#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486 482
487static struct sort_dimension sort_dimensions[] = { 483static struct sort_dimension common_sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 484 DIM(SORT_PID, "pid", sort_thread),
489 DIM(SORT_COMM, "comm", sort_comm), 485 DIM(SORT_COMM, "comm", sort_comm),
490 DIM(SORT_DSO, "dso", sort_dso), 486 DIM(SORT_DSO, "dso", sort_dso),
491 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
492 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
493 DIM(SORT_SYM, "symbol", sort_sym), 487 DIM(SORT_SYM, "symbol", sort_sym),
494 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
495 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
496 DIM(SORT_PARENT, "parent", sort_parent), 488 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu), 489 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline), 490 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 491};
501 492
493#undef DIM
494
495#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
496
497static struct sort_dimension bstack_sort_dimensions[] = {
498 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
499 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
500 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
501 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
502 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
503};
504
505#undef DIM
506
502int sort_dimension__add(const char *tok) 507int sort_dimension__add(const char *tok)
503{ 508{
504 unsigned int i; 509 unsigned int i;
505 510
506 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 511 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
507 struct sort_dimension *sd = &sort_dimensions[i]; 512 struct sort_dimension *sd = &common_sort_dimensions[i];
508 513
509 if (strncasecmp(tok, sd->name, strlen(tok))) 514 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 515 continue;
516
511 if (sd->entry == &sort_parent) { 517 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 518 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 519 if (ret) {
@@ -518,9 +524,7 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 524 return -EINVAL;
519 } 525 }
520 sort__has_parent = 1; 526 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym || 527 } else if (sd->entry == &sort_sym) {
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1; 528 sort__has_sym = 1;
525 } 529 }
526 530
@@ -530,36 +534,42 @@ int sort_dimension__add(const char *tok)
530 if (sd->entry->se_collapse) 534 if (sd->entry->se_collapse)
531 sort__need_collapse = 1; 535 sort__need_collapse = 1;
532 536
533 if (list_empty(&hist_entry__sort_list)) { 537 if (list_empty(&hist_entry__sort_list))
534 if (!strcmp(sd->name, "pid")) 538 sort__first_dimension = i;
535 sort__first_dimension = SORT_PID;
536 else if (!strcmp(sd->name, "comm"))
537 sort__first_dimension = SORT_COMM;
538 else if (!strcmp(sd->name, "dso"))
539 sort__first_dimension = SORT_DSO;
540 else if (!strcmp(sd->name, "symbol"))
541 sort__first_dimension = SORT_SYM;
542 else if (!strcmp(sd->name, "parent"))
543 sort__first_dimension = SORT_PARENT;
544 else if (!strcmp(sd->name, "cpu"))
545 sort__first_dimension = SORT_CPU;
546 else if (!strcmp(sd->name, "symbol_from"))
547 sort__first_dimension = SORT_SYM_FROM;
548 else if (!strcmp(sd->name, "symbol_to"))
549 sort__first_dimension = SORT_SYM_TO;
550 else if (!strcmp(sd->name, "dso_from"))
551 sort__first_dimension = SORT_DSO_FROM;
552 else if (!strcmp(sd->name, "dso_to"))
553 sort__first_dimension = SORT_DSO_TO;
554 else if (!strcmp(sd->name, "mispredict"))
555 sort__first_dimension = SORT_MISPREDICT;
556 }
557 539
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 540 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
559 sd->taken = 1; 541 sd->taken = 1;
560 542
561 return 0; 543 return 0;
562 } 544 }
545
546 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
547 struct sort_dimension *sd = &bstack_sort_dimensions[i];
548
549 if (strncasecmp(tok, sd->name, strlen(tok)))
550 continue;
551
552 if (sort__branch_mode != 1)
553 return -EINVAL;
554
555 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
556 sort__has_sym = 1;
557
558 if (sd->taken)
559 return 0;
560
561 if (sd->entry->se_collapse)
562 sort__need_collapse = 1;
563
564 if (list_empty(&hist_entry__sort_list))
565 sort__first_dimension = i + __SORT_BRANCH_STACK;
566
567 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
568 sd->taken = 1;
569
570 return 0;
571 }
572
563 return -ESRCH; 573 return -ESRCH;
564} 574}
565 575
@@ -569,7 +579,11 @@ void setup_sorting(const char * const usagestr[], const struct option *opts)
569 579
570 for (tok = strtok_r(str, ", ", &tmp); 580 for (tok = strtok_r(str, ", ", &tmp);
571 tok; tok = strtok_r(NULL, ", ", &tmp)) { 581 tok; tok = strtok_r(NULL, ", ", &tmp)) {
572 if (sort_dimension__add(tok) < 0) { 582 int ret = sort_dimension__add(tok);
583 if (ret == -EINVAL) {
584 error("Invalid --sort key: `%s'", tok);
585 usage_with_options(usagestr, opts);
586 } else if (ret == -ESRCH) {
573 error("Unknown --sort key: `%s'", tok); 587 error("Unknown --sort key: `%s'", tok);
574 usage_with_options(usagestr, opts); 588 usage_with_options(usagestr, opts);
575 } 589 }
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index a1c0d56b6885..e994ad3e9897 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -122,18 +122,22 @@ static inline void hist_entry__add_pair(struct hist_entry *he,
122} 122}
123 123
124enum sort_type { 124enum sort_type {
125 /* common sort keys */
125 SORT_PID, 126 SORT_PID,
126 SORT_COMM, 127 SORT_COMM,
127 SORT_DSO, 128 SORT_DSO,
128 SORT_SYM, 129 SORT_SYM,
129 SORT_PARENT, 130 SORT_PARENT,
130 SORT_CPU, 131 SORT_CPU,
131 SORT_DSO_FROM, 132 SORT_SRCLINE,
133
134 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK,
136 SORT_DSO_FROM = __SORT_BRANCH_STACK,
132 SORT_DSO_TO, 137 SORT_DSO_TO,
133 SORT_SYM_FROM, 138 SORT_SYM_FROM,
134 SORT_SYM_TO, 139 SORT_SYM_TO,
135 SORT_MISPREDICT, 140 SORT_MISPREDICT,
136 SORT_SRCLINE,
137}; 141};
138 142
139/* 143/*
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 346707df04b9..29c7b2cb2521 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to)
332} 332}
333 333
334/** 334/**
335 * ltrim - Removes leading whitespace from @s.
336 * @s: The string to be stripped.
337 *
338 * Return pointer to the first non-whitespace character in @s.
339 */
340char *ltrim(char *s)
341{
342 int len = strlen(s);
343
344 while (len && isspace(*s)) {
345 len--;
346 s++;
347 }
348
349 return s;
350}
351
352/**
335 * rtrim - Removes trailing whitespace from @s. 353 * rtrim - Removes trailing whitespace from @s.
336 * @s: The string to be stripped. 354 * @s: The string to be stripped.
337 * 355 *
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index f63557b59c06..54efcb5659ac 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1,6 +1,3 @@
1#include <libelf.h>
2#include <gelf.h>
3#include <elf.h>
4#include <fcntl.h> 1#include <fcntl.h>
5#include <stdio.h> 2#include <stdio.h>
6#include <errno.h> 3#include <errno.h>
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 259f8f2ea9c9..a7390cde63bc 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,6 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2 2
3#include <elf.h>
4#include <stdio.h> 3#include <stdio.h>
5#include <fcntl.h> 4#include <fcntl.h>
6#include <string.h> 5#include <string.h>
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 2960284d6ae1..e6432d85b43d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -768,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
768 else 768 else
769 machine = NULL; 769 machine = NULL;
770 770
771 name = malloc(PATH_MAX);
772 if (!name)
773 return -1;
774
775 dso->adjust_symbols = 0; 771 dso->adjust_symbols = 0;
776 772
777 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 773 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -795,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
795 if (machine) 791 if (machine)
796 root_dir = machine->root_dir; 792 root_dir = machine->root_dir;
797 793
794 name = malloc(PATH_MAX);
795 if (!name)
796 return -1;
797
798 /* Iterate over candidate debug images. 798 /* Iterate over candidate debug images.
799 * Keep track of "interesting" ones (those which have a symtab, dynsym, 799 * Keep track of "interesting" ones (those which have a symtab, dynsym,
800 * and/or opd section) for processing. 800 * and/or opd section) for processing.
@@ -923,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
923 filename = dso__build_id_filename(dso, NULL, 0); 923 filename = dso__build_id_filename(dso, NULL, 0);
924 if (filename != NULL) { 924 if (filename != NULL) {
925 err = dso__load_vmlinux(dso, map, filename, filter); 925 err = dso__load_vmlinux(dso, map, filename, filter);
926 if (err > 0) 926 if (err > 0) {
927 dso->lname_alloc = 1;
927 goto out; 928 goto out;
929 }
928 free(filename); 930 free(filename);
929 } 931 }
930 932
@@ -932,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
932 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 934 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
933 if (err > 0) { 935 if (err > 0) {
934 dso__set_long_name(dso, strdup(vmlinux_path[i])); 936 dso__set_long_name(dso, strdup(vmlinux_path[i]));
937 dso->lname_alloc = 1;
935 break; 938 break;
936 } 939 }
937 } 940 }
@@ -971,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
971 if (err > 0) { 974 if (err > 0) {
972 dso__set_long_name(dso, 975 dso__set_long_name(dso,
973 strdup(symbol_conf.vmlinux_name)); 976 strdup(symbol_conf.vmlinux_name));
977 dso->lname_alloc = 1;
974 goto out_fixup; 978 goto out_fixup;
975 } 979 }
976 return err; 980 return err;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ec7b2405c377..d97377ac2f16 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -16,8 +16,8 @@
16#ifdef LIBELF_SUPPORT 16#ifdef LIBELF_SUPPORT
17#include <libelf.h> 17#include <libelf.h>
18#include <gelf.h> 18#include <gelf.h>
19#include <elf.h>
20#endif 19#endif
20#include <elf.h>
21 21
22#include "dso.h" 22#include "dso.h"
23 23
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
index 48c6902e749f..f71e9eafe15a 100644
--- a/tools/perf/util/sysfs.c
+++ b/tools/perf/util/sysfs.c
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
8}; 8};
9 9
10static int sysfs_found; 10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX]; 11char sysfs_mountpoint[PATH_MAX + 1];
12 12
13static int sysfs_valid_mountpoint(const char *sysfs) 13static int sysfs_valid_mountpoint(const char *sysfs)
14{ 14{
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 927c229c2d9a..7ebf357dc9e1 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -29,8 +29,6 @@ struct perf_top {
29 bool sort_has_symbols; 29 bool sort_has_symbols;
30 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
31 bool vmlinux_warned; 31 bool vmlinux_warned;
32 bool sample_id_all_missing;
33 bool exclude_guest_missing;
34 bool dump_symtab; 32 bool dump_symtab;
35 struct hist_entry *sym_filter_entry; 33 struct hist_entry *sym_filter_entry;
36 struct perf_evsel *sym_evsel; 34 struct perf_evsel *sym_evsel;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 5906e8426cc7..805d1f52c5b4 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -12,6 +12,8 @@
12 */ 12 */
13unsigned int page_size; 13unsigned int page_size;
14 14
15bool test_attr__enabled;
16
15bool perf_host = true; 17bool perf_host = true;
16bool perf_guest = false; 18bool perf_guest = false;
17 19
@@ -218,3 +220,25 @@ void dump_stack(void)
218#else 220#else
219void dump_stack(void) {} 221void dump_stack(void) {}
220#endif 222#endif
223
224void get_term_dimensions(struct winsize *ws)
225{
226 char *s = getenv("LINES");
227
228 if (s != NULL) {
229 ws->ws_row = atoi(s);
230 s = getenv("COLUMNS");
231 if (s != NULL) {
232 ws->ws_col = atoi(s);
233 if (ws->ws_row && ws->ws_col)
234 return;
235 }
236 }
237#ifdef TIOCGWINSZ
238 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
239 ws->ws_row && ws->ws_col)
240 return;
241#endif
242 ws->ws_row = 25;
243 ws->ws_col = 80;
244}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c2330918110c..09b4c26b71aa 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n)
265size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val); 266int hex2u64(const char *ptr, u64 *val);
267 267
268char *ltrim(char *s);
268char *rtrim(char *s); 269char *rtrim(char *s);
269 270
270void dump_stack(void); 271void dump_stack(void);
271 272
272extern unsigned int page_size; 273extern unsigned int page_size;
273 274
275struct winsize;
276void get_term_dimensions(struct winsize *ws);
277
274#endif 278#endif