aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-19 20:49:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-19 20:49:41 -0500
commit8f55cea410dbc56114bb71a3742032070c8108d0 (patch)
tree59605f0ee961274b22f91add33f5c32459471a83 /tools
parentb7133a9a103655cda254987a3c0975fd9d8c443f (diff)
parente259514eef764a5286873618e34c560ecb6cff13 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf changes from Ingo Molnar: "There are lots of improvements, the biggest changes are: Main kernel side changes: - Improve uprobes performance by adding 'pre-filtering' support, by Oleg Nesterov. - Make some POWER7 events available in sysfs, equivalent to what was done on x86, from Sukadev Bhattiprolu. - tracing updates by Steve Rostedt - mostly misc fixes and smaller improvements. - Use perf/event tracing to report PCI Express advanced errors, by Tony Luck. - Enable northbridge performance counters on AMD family 15h, by Jacob Shin. - This tracing commit: tracing: Remove the extra 4 bytes of padding in events changes the ABI. All involved parties (PowerTop in particular) seem to agree that it's safe to do now with the introduction of libtraceevent, but the devil is in the details ... Main tooling side changes: - Add 'event group view', from Namyung Kim: To use it, 'perf record' should group events when recording. And then perf report parses the saved group relation from file header and prints them together if --group option is provided. You can use the 'perf evlist' command to see event group information: $ perf record -e '{ref-cycles,cycles}' noploop 1 [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.385 MB perf.data (~16807 samples) ] $ perf evlist --group {ref-cycles,cycles} With this example, default perf report will show you each event separately. You can use --group option to enable event group view: $ perf report --group ... # group: {ref-cycles,cycles} # ======== # Samples: 7K of event 'anon group { ref-cycles, cycles }' # Event count (approx.): 6876107743 # # Overhead Command Shared Object Symbol # ................ ....... ................. .......................... 99.84% 99.76% noploop noploop [.] main 0.07% 0.00% noploop ld-2.15.so [.] strcmp 0.03% 0.00% noploop [kernel.kallsyms] [k] timerqueue_del 0.03% 0.03% noploop [kernel.kallsyms] [k] sched_clock_cpu 0.02% 0.00% noploop [kernel.kallsyms] [k] account_user_time 0.01% 0.00% noploop [kernel.kallsyms] [k] __alloc_pages_nodemask 0.00% 0.00% noploop [kernel.kallsyms] [k] native_write_msr_safe 0.00% 0.11% noploop [kernel.kallsyms] [k] _raw_spin_lock 0.00% 0.06% noploop [kernel.kallsyms] [k] find_get_page 0.00% 0.02% noploop [kernel.kallsyms] [k] rcu_check_callbacks 0.00% 0.02% noploop [kernel.kallsyms] [k] __current_kernel_time As you can see the Overhead column now contains both of ref-cycles and cycles and header line shows group information also - 'anon group { ref-cycles, cycles }'. The output is sorted by period of group leader first. - Initial GTK+ annotate browser, from Namhyung Kim. - Add option for runtime switching perf data file in perf report, just press 's' and a menu with the valid files found in the current directory will be presented, from Feng Tang. - Add support to display whole group data for raw columns, from Jiri Olsa. - Add per processor socket count aggregation in perf stat, from Stephane Eranian. - Add interval printing in 'perf stat', from Stephane Eranian. - 'perf test' improvements - Add support for wildcards in tracepoint system name, from Jiri Olsa. - Add anonymous huge page recognition, from Joshua Zhu. - perf build-id cache now can show DSOs present in a perf.data file that are not in the cache, to integrate with build-id servers being put in place by organizations such as Fedora. - perf top now shares more of the evsel config/creation routines with 'record', paving the way for further integration like 'top' snapshots, etc. - perf top now supports DWARF callchains. - Fix mmap limitations on 32-bit, fix from David Miller. - 'perf bench numa mem' NUMA performance measurement suite - ... and lots of fixes, performance improvements, cleanups and other improvements I failed to list - see the shortlog and git log for details." * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (270 commits) perf/x86/amd: Enable northbridge performance counters on AMD family 15h perf/hwbp: Fix cleanup in case of kzalloc failure perf tools: Fix build with bison 2.3 and older. perf tools: Limit unwind support to x86 archs perf annotate: Make it to be able to skip unannotatable symbols perf gtk/annotate: Fail early if it can't annotate perf gtk/annotate: Show source lines with gray color perf gtk/annotate: Support multiple event annotation perf ui/gtk: Implement basic GTK2 annotation browser perf annotate: Fix warning message on a missing vmlinux perf buildid-cache: Add --update option uprobes/perf: Avoid uprobe_apply() whenever possible uprobes/perf: Teach trace_uprobe/perf code to use UPROBE_HANDLER_REMOVE uprobes/perf: Teach trace_uprobe/perf code to pre-filter uprobes/perf: Teach trace_uprobe/perf code to track the active perf_event's uprobes: Introduce uprobe_apply() perf: Introduce hw_perf_event->tp_target and ->tp_list uprobes/perf: Always increment trace_uprobe->nhit uprobes/tracing: Kill uprobe_trace_consumer, embed uprobe_consumer into trace_uprobe uprobes/tracing: Introduce is_trace_uprobe_enabled() ...
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile2
-rw-r--r--tools/lib/traceevent/event-parse.c49
-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/Makefile4
-rw-r--r--tools/perf/Documentation/perf-annotate.txt7
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt7
-rw-r--r--tools/perf/Documentation/perf-diff.txt4
-rw-r--r--tools/perf/Documentation/perf-evlist.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-script-python.txt2
-rw-r--r--tools/perf/Documentation/perf-stat.txt11
-rw-r--r--tools/perf/Documentation/perf-test.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Makefile104
-rw-r--r--tools/perf/arch/common.c1
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/numa.c1731
-rw-r--r--tools/perf/builtin-annotate.c30
-rw-r--r--tools/perf/builtin-bench.c19
-rw-r--r--tools/perf/builtin-buildid-cache.c96
-rw-r--r--tools/perf/builtin-buildid-list.c21
-rw-r--r--tools/perf/builtin-diff.c205
-rw-r--r--tools/perf/builtin-evlist.c88
-rw-r--r--tools/perf/builtin-kmem.c16
-rw-r--r--tools/perf/builtin-kvm.c3
-rw-r--r--tools/perf/builtin-record.c168
-rw-r--r--tools/perf/builtin-report.c93
-rw-r--r--tools/perf/builtin-sched.c6
-rw-r--r--tools/perf/builtin-script.c17
-rw-r--r--tools/perf/builtin-stat.c328
-rw-r--r--tools/perf/builtin-top.c372
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/config/feature-tests.mak11
-rw-r--r--tools/perf/config/utilities.mak6
-rw-r--r--tools/perf/perf.c32
-rw-r--r--tools/perf/perf.h32
-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/rwtop.pl6
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/tests/attr.c9
-rw-r--r--tools/perf/tests/attr.py27
-rw-r--r--tools/perf/tests/attr/base-record2
-rw-r--r--tools/perf/tests/attr/test-record-group2
-rw-r--r--tools/perf/tests/attr/test-record-group14
-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.c500
-rw-r--r--tools/perf/tests/mmap-basic.c40
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c19
-rw-r--r--tools/perf/tests/open-syscall.c17
-rw-r--r--tools/perf/tests/parse-events.c324
-rw-r--r--tools/perf/tests/perf-record.c20
-rw-r--r--tools/perf/tests/pmu.c11
-rw-r--r--tools/perf/tests/python-use.c23
-rw-r--r--tools/perf/tests/tests.h11
-rw-r--r--tools/perf/tests/util.c30
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c7
-rw-r--r--tools/perf/ui/browser.c6
-rw-r--r--tools/perf/ui/browsers/annotate.c33
-rw-r--r--tools/perf/ui/browsers/hists.c341
-rw-r--r--tools/perf/ui/gtk/annotate.c229
-rw-r--r--tools/perf/ui/gtk/browser.c235
-rw-r--r--tools/perf/ui/gtk/gtk.h10
-rw-r--r--tools/perf/ui/gtk/helpline.c23
-rw-r--r--tools/perf/ui/gtk/hists.c312
-rw-r--r--tools/perf/ui/helpline.c12
-rw-r--r--tools/perf/ui/helpline.h22
-rw-r--r--tools/perf/ui/hist.c481
-rw-r--r--tools/perf/ui/keysyms.h1
-rw-r--r--tools/perf/ui/setup.c3
-rw-r--r--tools/perf/ui/stdio/hist.c25
-rw-r--r--tools/perf/ui/tui/helpline.c29
-rw-r--r--tools/perf/ui/util.c1
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN4
-rw-r--r--tools/perf/util/annotate.c2
-rw-r--r--tools/perf/util/annotate.h24
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/cpumap.c54
-rw-r--r--tools/perf/util/cpumap.h9
-rw-r--r--tools/perf/util/debug.c28
-rw-r--r--tools/perf/util/debug.h34
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/evlist.c31
-rw-r--r--tools/perf/util/evlist.h34
-rw-r--r--tools/perf/util/evsel.c370
-rw-r--r--tools/perf/util/evsel.h50
-rw-r--r--tools/perf/util/header.c266
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c142
-rw-r--r--tools/perf/util/hist.h26
-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.c784
-rw-r--r--tools/perf/util/machine.h41
-rw-r--r--tools/perf/util/map.c121
-rw-r--r--tools/perf/util/map.h24
-rw-r--r--tools/perf/util/parse-events.c96
-rw-r--r--tools/perf/util/parse-events.h22
-rw-r--r--tools/perf/util/parse-events.y75
-rw-r--r--tools/perf/util/pmu.c46
-rw-r--r--tools/perf/util/pmu.h15
-rw-r--r--tools/perf/util/pmu.y1
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/python-ext-sources1
-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.c325
-rw-r--r--tools/perf/util/session.h35
-rw-r--r--tools/perf/util/sort.c245
-rw-r--r--tools/perf/util/sort.h15
-rw-r--r--tools/perf/util/string.c18
-rw-r--r--tools/perf/util/strlist.c54
-rw-r--r--tools/perf/util/strlist.h42
-rw-r--r--tools/perf/util/symbol-elf.c14
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c536
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/thread.c20
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/top.c22
-rw-r--r--tools/perf/util/top.h10
-rw-r--r--tools/perf/util/util.c24
-rw-r--r--tools/perf/util/util.h4
134 files changed, 7159 insertions, 3142 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 1f9a529fe544..798fa0ef048e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -15,7 +15,7 @@ help:
15 @echo ' x86_energy_perf_policy - Intel energy policy tool' 15 @echo ' x86_energy_perf_policy - Intel energy policy tool'
16 @echo '' 16 @echo ''
17 @echo 'You can do:' 17 @echo 'You can do:'
18 @echo ' $$ make -C tools/<tool>_install' 18 @echo ' $$ make -C tools/ <tool>_install'
19 @echo '' 19 @echo ''
20 @echo ' from the kernel command line to build and install one of' 20 @echo ' from the kernel command line to build and install one of'
21 @echo ' the tools above' 21 @echo ' the tools above'
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 5a824e355d04..82b0606dcb8a 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 *
@@ -1224,6 +1223,34 @@ static int field_is_long(struct format_field *field)
1224 return 0; 1223 return 0;
1225} 1224}
1226 1225
1226static unsigned int type_size(const char *name)
1227{
1228 /* This covers all FIELD_IS_STRING types. */
1229 static struct {
1230 const char *type;
1231 unsigned int size;
1232 } table[] = {
1233 { "u8", 1 },
1234 { "u16", 2 },
1235 { "u32", 4 },
1236 { "u64", 8 },
1237 { "s8", 1 },
1238 { "s16", 2 },
1239 { "s32", 4 },
1240 { "s64", 8 },
1241 { "char", 1 },
1242 { },
1243 };
1244 int i;
1245
1246 for (i = 0; table[i].type; i++) {
1247 if (!strcmp(table[i].type, name))
1248 return table[i].size;
1249 }
1250
1251 return 0;
1252}
1253
1227static int event_read_fields(struct event_format *event, struct format_field **fields) 1254static int event_read_fields(struct event_format *event, struct format_field **fields)
1228{ 1255{
1229 struct format_field *field = NULL; 1256 struct format_field *field = NULL;
@@ -1233,6 +1260,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1233 int count = 0; 1260 int count = 0;
1234 1261
1235 do { 1262 do {
1263 unsigned int size_dynamic = 0;
1264
1236 type = read_token(&token); 1265 type = read_token(&token);
1237 if (type == EVENT_NEWLINE) { 1266 if (type == EVENT_NEWLINE) {
1238 free_token(token); 1267 free_token(token);
@@ -1391,6 +1420,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1391 field->type = new_type; 1420 field->type = new_type;
1392 strcat(field->type, " "); 1421 strcat(field->type, " ");
1393 strcat(field->type, field->name); 1422 strcat(field->type, field->name);
1423 size_dynamic = type_size(field->name);
1394 free_token(field->name); 1424 free_token(field->name);
1395 strcat(field->type, brackets); 1425 strcat(field->type, brackets);
1396 field->name = token; 1426 field->name = token;
@@ -1463,7 +1493,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1463 if (read_expect_type(EVENT_ITEM, &token)) 1493 if (read_expect_type(EVENT_ITEM, &token))
1464 goto fail; 1494 goto fail;
1465 1495
1466 /* add signed type */ 1496 if (strtoul(token, NULL, 0))
1497 field->flags |= FIELD_IS_SIGNED;
1467 1498
1468 free_token(token); 1499 free_token(token);
1469 if (read_expected(EVENT_OP, ";") < 0) 1500 if (read_expected(EVENT_OP, ";") < 0)
@@ -1478,10 +1509,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1478 if (field->flags & FIELD_IS_ARRAY) { 1509 if (field->flags & FIELD_IS_ARRAY) {
1479 if (field->arraylen) 1510 if (field->arraylen)
1480 field->elementsize = field->size / field->arraylen; 1511 field->elementsize = field->size / field->arraylen;
1512 else if (field->flags & FIELD_IS_DYNAMIC)
1513 field->elementsize = size_dynamic;
1481 else if (field->flags & FIELD_IS_STRING) 1514 else if (field->flags & FIELD_IS_STRING)
1482 field->elementsize = 1; 1515 field->elementsize = 1;
1483 else 1516 else if (field->flags & FIELD_IS_LONG)
1484 field->elementsize = event->pevent->long_size; 1517 field->elementsize = event->pevent ?
1518 event->pevent->long_size :
1519 sizeof(long);
1485 } else 1520 } else
1486 field->elementsize = field->size; 1521 field->elementsize = field->size;
1487 1522
@@ -1785,6 +1820,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
1785 strcmp(token, "/") == 0 || 1820 strcmp(token, "/") == 0 ||
1786 strcmp(token, "<") == 0 || 1821 strcmp(token, "<") == 0 ||
1787 strcmp(token, ">") == 0 || 1822 strcmp(token, ">") == 0 ||
1823 strcmp(token, "<=") == 0 ||
1824 strcmp(token, ">=") == 0 ||
1788 strcmp(token, "==") == 0 || 1825 strcmp(token, "==") == 0 ||
1789 strcmp(token, "!=") == 0) { 1826 strcmp(token, "!=") == 0) {
1790 1827
@@ -2481,7 +2518,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char **
2481 2518
2482 free_token(token); 2519 free_token(token);
2483 arg = alloc_arg(); 2520 arg = alloc_arg();
2484 if (!field) { 2521 if (!arg) {
2485 do_warning("%s: not enough memory!", __func__); 2522 do_warning("%s: not enough memory!", __func__);
2486 *tok = NULL; 2523 *tok = NULL;
2487 return EVENT_ERROR; 2524 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/Makefile b/tools/perf/Documentation/Makefile
index ef6d22e879eb..eb30044a922a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -222,10 +222,14 @@ install-pdf: pdf
222#install-html: html 222#install-html: html
223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
224 224
225ifneq ($(MAKECMDGOALS),clean)
226ifneq ($(MAKECMDGOALS),tags)
225$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 227$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
226 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE 228 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
227 229
228-include $(OUTPUT)PERF-VERSION-FILE 230-include $(OUTPUT)PERF-VERSION-FILE
231endif
232endif
229 233
230# 234#
231# Determine "include::" file references in asciidoc files. 235# Determine "include::" file references in asciidoc files.
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c8ffd9fd5c6a..5ad07ef417f0 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -61,11 +61,13 @@ OPTIONS
61 61
62--stdio:: Use the stdio interface. 62--stdio:: Use the stdio interface.
63 63
64--tui:: Use the TUI interface Use of --tui requires a tty, if one is not 64--tui:: Use the TUI interface. Use of --tui requires a tty, if one is not
65 present, as when piping to other commands, the stdio interface is 65 present, as when piping to other commands, the stdio interface is
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69--gtk:: Use the GTK interface.
70
69-C:: 71-C::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 72--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 73 be provided as a comma-separated list with no space: 0,1. Ranges of
@@ -88,6 +90,9 @@ OPTIONS
88--objdump=<path>:: 90--objdump=<path>::
89 Path to objdump binary. 91 Path to objdump binary.
90 92
93--skip-missing::
94 Skip symbols that cannot be annotated.
95
91SEE ALSO 96SEE ALSO
92-------- 97--------
93linkperf:perf-record[1], linkperf:perf-report[1] 98linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index c1057701a7dc..e9a8349a7172 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -24,6 +24,13 @@ OPTIONS
24-r:: 24-r::
25--remove=:: 25--remove=::
26 Remove specified file from the cache. 26 Remove specified file from the cache.
27-M::
28--missing=::
29 List missing build ids in the cache for the specified file.
30-u::
31--update::
32 Update specified file of the cache. It can be used to update kallsyms
33 kernel dso to vmlinux in order to support annotation.
27-v:: 34-v::
28--verbose:: 35--verbose::
29 Be more verbose. 36 Be more verbose.
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 194f37d635df..5b3123d5721f 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -22,10 +22,6 @@ specified perf.data files.
22 22
23OPTIONS 23OPTIONS
24------- 24-------
25-M::
26--displacement::
27 Show position displacement relative to baseline.
28
29-D:: 25-D::
30--dump-raw-trace:: 26--dump-raw-trace::
31 Dump raw trace in ASCII. 27 Dump raw trace in ASCII.
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 15217345c2fa..1ceb3700ffbb 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -28,6 +28,10 @@ OPTIONS
28--verbose=:: 28--verbose=::
29 Show all fields. 29 Show all fields.
30 30
31-g::
32--group::
33 Show event group information.
34
31SEE ALSO 35SEE ALSO
32-------- 36--------
33linkperf:perf-record[1], linkperf:perf-list[1], 37linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index f4d91bebd59d..02284a0067f0 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.
@@ -171,6 +203,9 @@ OPTIONS
171--objdump=<path>:: 203--objdump=<path>::
172 Path to objdump binary. 204 Path to objdump binary.
173 205
206--group::
207 Show event group information together.
208
174SEE ALSO 209SEE ALSO
175-------- 210--------
176linkperf:perf-stat[1], linkperf:perf-annotate[1] 211linkperf:perf-stat[1], linkperf:perf-annotate[1]
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-stat.txt b/tools/perf/Documentation/perf-stat.txt
index cf0c3107e06e..faf4f4feebcc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -114,6 +114,17 @@ with it. --append may be used here. Examples:
114 114
115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage 115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
116 116
117-I msecs::
118--interval-print msecs::
119 Print count deltas every N milliseconds (minimum: 100ms)
120 example: perf stat -I 1000 -e cycles -a sleep 5
121
122--aggr-socket::
123Aggregate counts per processor socket for system-wide mode measurements. This
124is a useful mode to detect imbalance between sockets. To enable this mode,
125use --aggr-socket in addition to -a. (system-wide). The output includes the
126socket number and the number of online processors on that socket. This is
127useful to gauge the amount of aggregation.
117 128
118EXAMPLES 129EXAMPLES
119-------- 130--------
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/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 5b80d84d6b4a..a414bc95fd52 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -60,7 +60,7 @@ Default is to monitor all CPUS.
60 60
61-i:: 61-i::
62--inherit:: 62--inherit::
63 Child tasks inherit counters, only makes sens with -p option. 63 Child tasks do not inherit counters.
64 64
65-k <path>:: 65-k <path>::
66--vmlinux=<path>:: 66--vmlinux=<path>::
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 8ab05e543ef4..a2108ca1cc17 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,10 +47,11 @@ include config/utilities.mak
47# backtrace post unwind. 47# backtrace post unwind.
48# 48#
49# Define NO_BACKTRACE if you do not want stack backtrace debug feature 49# Define NO_BACKTRACE if you do not want stack backtrace debug feature
50#
51# Define NO_LIBNUMA if you do not want numa perf benchmark
50 52
51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 53$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 54 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
53-include $(OUTPUT)PERF-VERSION-FILE
54 55
55uname_M := $(shell uname -m 2>/dev/null || echo not) 56uname_M := $(shell uname -m 2>/dev/null || echo not)
56 57
@@ -148,13 +149,25 @@ RM = rm -f
148MKDIR = mkdir 149MKDIR = mkdir
149FIND = find 150FIND = find
150INSTALL = install 151INSTALL = install
152FLEX = flex
153BISON= bison
151 154
152# sparse is architecture-neutral, which means that we need to tell it 155# sparse is architecture-neutral, which means that we need to tell it
153# explicitly what architecture to check for. Fix this up for yours.. 156# explicitly what architecture to check for. Fix this up for yours..
154SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 157SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
155 158
159ifneq ($(MAKECMDGOALS),clean)
160ifneq ($(MAKECMDGOALS),tags)
156-include config/feature-tests.mak 161-include config/feature-tests.mak
157 162
163ifeq ($(call get-executable,$(FLEX)),)
164 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
165endif
166
167ifeq ($(call get-executable,$(BISON)),)
168 dummy := $(error Error: $(BISON) is missing on this system, please install it)
169endif
170
158ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) 171ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
159 CFLAGS := $(CFLAGS) -fstack-protector-all 172 CFLAGS := $(CFLAGS) -fstack-protector-all
160endif 173endif
@@ -206,6 +219,8 @@ ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
206 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) 219 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
207 BASIC_CFLAGS += -I. 220 BASIC_CFLAGS += -I.
208endif 221endif
222endif # MAKECMDGOALS != tags
223endif # MAKECMDGOALS != clean
209 224
210# Guard against environment variables 225# Guard against environment variables
211BUILTIN_OBJS = 226BUILTIN_OBJS =
@@ -230,11 +245,19 @@ endif
230LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 245LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
231TE_LIB := -L$(TE_PATH) -ltraceevent 246TE_LIB := -L$(TE_PATH) -ltraceevent
232 247
248export LIBTRACEEVENT
249
250# python extension build directories
251PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
252PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
253PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
254export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
255
256python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
257
233PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 258PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
234PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py 259PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
235 260
236export LIBTRACEEVENT
237
238$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 261$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
239 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 262 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
240 --quiet build_ext; \ 263 --quiet build_ext; \
@@ -269,20 +292,17 @@ endif
269 292
270export PERL_PATH 293export PERL_PATH
271 294
272FLEX = flex
273BISON= bison
274
275$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 295$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
276 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 296 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
277 297
278$(OUTPUT)util/parse-events-bison.c: util/parse-events.y 298$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
279 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c 299 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
280 300
281$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c 301$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
282 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 302 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
283 303
284$(OUTPUT)util/pmu-bison.c: util/pmu.y 304$(OUTPUT)util/pmu-bison.c: util/pmu.y
285 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c 305 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
286 306
287$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 307$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
288$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 308$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
@@ -378,8 +398,11 @@ LIB_H += util/rblist.h
378LIB_H += util/intlist.h 398LIB_H += util/intlist.h
379LIB_H += util/perf_regs.h 399LIB_H += util/perf_regs.h
380LIB_H += util/unwind.h 400LIB_H += util/unwind.h
381LIB_H += ui/helpline.h
382LIB_H += util/vdso.h 401LIB_H += util/vdso.h
402LIB_H += ui/helpline.h
403LIB_H += ui/progress.h
404LIB_H += ui/util.h
405LIB_H += ui/ui.h
383 406
384LIB_OBJS += $(OUTPUT)util/abspath.o 407LIB_OBJS += $(OUTPUT)util/abspath.o
385LIB_OBJS += $(OUTPUT)util/alias.o 408LIB_OBJS += $(OUTPUT)util/alias.o
@@ -453,6 +476,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
453LIB_OBJS += $(OUTPUT)ui/setup.o 476LIB_OBJS += $(OUTPUT)ui/setup.o
454LIB_OBJS += $(OUTPUT)ui/helpline.o 477LIB_OBJS += $(OUTPUT)ui/helpline.o
455LIB_OBJS += $(OUTPUT)ui/progress.o 478LIB_OBJS += $(OUTPUT)ui/progress.o
479LIB_OBJS += $(OUTPUT)ui/util.o
456LIB_OBJS += $(OUTPUT)ui/hist.o 480LIB_OBJS += $(OUTPUT)ui/hist.o
457LIB_OBJS += $(OUTPUT)ui/stdio/hist.o 481LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
458 482
@@ -471,7 +495,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
471LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 495LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
472LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 496LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
473LIB_OBJS += $(OUTPUT)tests/pmu.o 497LIB_OBJS += $(OUTPUT)tests/pmu.o
474LIB_OBJS += $(OUTPUT)tests/util.o 498LIB_OBJS += $(OUTPUT)tests/hists_link.o
499LIB_OBJS += $(OUTPUT)tests/python-use.o
475 500
476BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 501BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
477BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 502BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -510,14 +535,13 @@ PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
510# 535#
511# Platform specific tweaks 536# Platform specific tweaks
512# 537#
538ifneq ($(MAKECMDGOALS),clean)
539ifneq ($(MAKECMDGOALS),tags)
513 540
514# We choose to avoid "if .. else if .. else .. endif endif" 541# We choose to avoid "if .. else if .. else .. endif endif"
515# because maintaining the nesting to match is a pain. If 542# because maintaining the nesting to match is a pain. If
516# we had "elif" things would have been much nicer... 543# we had "elif" things would have been much nicer...
517 544
518-include config.mak.autogen
519-include config.mak
520
521ifdef NO_LIBELF 545ifdef NO_LIBELF
522 NO_DWARF := 1 546 NO_DWARF := 1
523 NO_DEMANGLE := 1 547 NO_DEMANGLE := 1
@@ -557,6 +581,11 @@ else
557endif # SOURCE_LIBELF 581endif # SOURCE_LIBELF
558endif # NO_LIBELF 582endif # NO_LIBELF
559 583
584# There's only x86 (both 32 and 64) support for CFI unwind so far
585ifneq ($(ARCH),x86)
586 NO_LIBUNWIND := 1
587endif
588
560ifndef NO_LIBUNWIND 589ifndef NO_LIBUNWIND
561# for linking with debug library, run like: 590# for linking with debug library, run like:
562# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ 591# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
@@ -646,7 +675,6 @@ ifndef NO_NEWT
646 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 675 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
647 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 676 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
648 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 677 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
649 LIB_OBJS += $(OUTPUT)ui/util.o
650 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 678 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
651 LIB_OBJS += $(OUTPUT)ui/tui/util.o 679 LIB_OBJS += $(OUTPUT)ui/tui/util.o
652 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 680 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
@@ -655,9 +683,6 @@ ifndef NO_NEWT
655 LIB_H += ui/browsers/map.h 683 LIB_H += ui/browsers/map.h
656 LIB_H += ui/keysyms.h 684 LIB_H += ui/keysyms.h
657 LIB_H += ui/libslang.h 685 LIB_H += ui/libslang.h
658 LIB_H += ui/progress.h
659 LIB_H += ui/util.h
660 LIB_H += ui/ui.h
661 endif 686 endif
662endif 687endif
663 688
@@ -673,14 +698,12 @@ ifndef NO_GTK2
673 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) 698 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
674 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) 699 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
675 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o 700 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
701 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
676 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o 702 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
677 LIB_OBJS += $(OUTPUT)ui/gtk/util.o 703 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
678 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o 704 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
679 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o 705 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
680 # Make sure that it'd be included only once. 706 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
681 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
682 LIB_OBJS += $(OUTPUT)ui/util.o
683 endif
684 endif 707 endif
685endif 708endif
686 709
@@ -707,7 +730,7 @@ disable-python = $(eval $(disable-python_code))
707define disable-python_code 730define disable-python_code
708 BASIC_CFLAGS += -DNO_LIBPYTHON 731 BASIC_CFLAGS += -DNO_LIBPYTHON
709 $(if $(1),$(warning No $(1) was found)) 732 $(if $(1),$(warning No $(1) was found))
710 $(warning Python support won't be built) 733 $(warning Python support will not be built)
711endef 734endef
712 735
713override PYTHON := \ 736override PYTHON := \
@@ -715,19 +738,10 @@ override PYTHON := \
715 738
716ifndef PYTHON 739ifndef PYTHON
717 $(call disable-python,python interpreter) 740 $(call disable-python,python interpreter)
718 python-clean :=
719else 741else
720 742
721 PYTHON_WORD := $(call shell-wordify,$(PYTHON)) 743 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
722 744
723 # python extension build directories
724 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
725 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
726 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
727 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
728
729 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
730
731 ifdef NO_LIBPYTHON 745 ifdef NO_LIBPYTHON
732 $(call disable-python) 746 $(call disable-python)
733 else 747 else
@@ -839,10 +853,24 @@ ifndef NO_BACKTRACE
839 endif 853 endif
840endif 854endif
841 855
856ifndef NO_LIBNUMA
857 FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma
858 ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
859 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
860 else
861 BASIC_CFLAGS += -DLIBNUMA_SUPPORT
862 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
863 EXTLIBS += -lnuma
864 endif
865endif
866
842ifdef ASCIIDOC8 867ifdef ASCIIDOC8
843 export ASCIIDOC8 868 export ASCIIDOC8
844endif 869endif
845 870
871endif # MAKECMDGOALS != tags
872endif # MAKECMDGOALS != clean
873
846# Shell quote (do not use $(call) to accommodate ancient setups); 874# Shell quote (do not use $(call) to accommodate ancient setups);
847 875
848ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 876ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
@@ -884,7 +912,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
884 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf 912 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
885 913
886$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 914$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
887 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 915 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
888 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 916 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
889 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 917 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
890 918
@@ -948,7 +976,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
948 976
949$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS 977$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
950 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 978 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
951 '-DBINDIR="$(bindir_SQ)"' \ 979 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
980 $<
981
982$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
983 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
984 -DPYTHONPATH='"$(OUTPUT)python"' \
985 -DPYTHON='"$(PYTHON_WORD)"' \
952 $< 986 $<
953 987
954$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 988$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
@@ -1099,7 +1133,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
1099endif 1133endif
1100perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 1134perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1101 1135
1102install: all try-install-man 1136install-bin: all
1103 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1137 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1104 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 1138 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1105 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1139 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1120,6 +1154,8 @@ install: all try-install-man
1120 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 1154 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1121 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 1155 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1122 1156
1157install: install-bin try-install-man
1158
1123install-python_ext: 1159install-python_ext:
1124 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 1160 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1125 1161
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index 3e975cb6232e..aacef07ebf31 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -155,6 +155,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
155 if (lookup_path(buf)) 155 if (lookup_path(buf))
156 goto out; 156 goto out;
157 free(buf); 157 free(buf);
158 buf = NULL;
158 } 159 }
159 160
160 if (!strcmp(arch, "arm")) 161 if (!strcmp(arch, "arm"))
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 8f89998eeaf4..a5223e6a7b43 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -1,6 +1,7 @@
1#ifndef BENCH_H 1#ifndef BENCH_H
2#define BENCH_H 2#define BENCH_H
3 3
4extern int bench_numa(int argc, const char **argv, const char *prefix);
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 5extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 6extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, 7extern int bench_mem_memcpy(int argc, const char **argv,
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
new file mode 100644
index 000000000000..30d1c3225b46
--- /dev/null
+++ b/tools/perf/bench/numa.c
@@ -0,0 +1,1731 @@
1/*
2 * numa.c
3 *
4 * numa: Simulate NUMA-sensitive workload and measure their NUMA performance
5 */
6
7#include "../perf.h"
8#include "../builtin.h"
9#include "../util/util.h"
10#include "../util/parse-options.h"
11
12#include "bench.h"
13
14#include <errno.h>
15#include <sched.h>
16#include <stdio.h>
17#include <assert.h>
18#include <malloc.h>
19#include <signal.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <pthread.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/wait.h>
27#include <sys/prctl.h>
28#include <sys/types.h>
29
30#include <numa.h>
31#include <numaif.h>
32
33/*
34 * Regular printout to the terminal, supressed if -q is specified:
35 */
36#define tprintf(x...) do { if (g && g->p.show_details >= 0) printf(x); } while (0)
37
38/*
39 * Debug printf:
40 */
41#define dprintf(x...) do { if (g && g->p.show_details >= 1) printf(x); } while (0)
42
43struct thread_data {
44 int curr_cpu;
45 cpu_set_t bind_cpumask;
46 int bind_node;
47 u8 *process_data;
48 int process_nr;
49 int thread_nr;
50 int task_nr;
51 unsigned int loops_done;
52 u64 val;
53 u64 runtime_ns;
54 pthread_mutex_t *process_lock;
55};
56
57/* Parameters set by options: */
58
59struct params {
60 /* Startup synchronization: */
61 bool serialize_startup;
62
63 /* Task hierarchy: */
64 int nr_proc;
65 int nr_threads;
66
67 /* Working set sizes: */
68 const char *mb_global_str;
69 const char *mb_proc_str;
70 const char *mb_proc_locked_str;
71 const char *mb_thread_str;
72
73 double mb_global;
74 double mb_proc;
75 double mb_proc_locked;
76 double mb_thread;
77
78 /* Access patterns to the working set: */
79 bool data_reads;
80 bool data_writes;
81 bool data_backwards;
82 bool data_zero_memset;
83 bool data_rand_walk;
84 u32 nr_loops;
85 u32 nr_secs;
86 u32 sleep_usecs;
87
88 /* Working set initialization: */
89 bool init_zero;
90 bool init_random;
91 bool init_cpu0;
92
93 /* Misc options: */
94 int show_details;
95 int run_all;
96 int thp;
97
98 long bytes_global;
99 long bytes_process;
100 long bytes_process_locked;
101 long bytes_thread;
102
103 int nr_tasks;
104 bool show_quiet;
105
106 bool show_convergence;
107 bool measure_convergence;
108
109 int perturb_secs;
110 int nr_cpus;
111 int nr_nodes;
112
113 /* Affinity options -C and -N: */
114 char *cpu_list_str;
115 char *node_list_str;
116};
117
118
119/* Global, read-writable area, accessible to all processes and threads: */
120
121struct global_info {
122 u8 *data;
123
124 pthread_mutex_t startup_mutex;
125 int nr_tasks_started;
126
127 pthread_mutex_t startup_done_mutex;
128
129 pthread_mutex_t start_work_mutex;
130 int nr_tasks_working;
131
132 pthread_mutex_t stop_work_mutex;
133 u64 bytes_done;
134
135 struct thread_data *threads;
136
137 /* Convergence latency measurement: */
138 bool all_converged;
139 bool stop_work;
140
141 int print_once;
142
143 struct params p;
144};
145
146static struct global_info *g = NULL;
147
148static int parse_cpus_opt(const struct option *opt, const char *arg, int unset);
149static int parse_nodes_opt(const struct option *opt, const char *arg, int unset);
150
151struct params p0;
152
153static const struct option options[] = {
154 OPT_INTEGER('p', "nr_proc" , &p0.nr_proc, "number of processes"),
155 OPT_INTEGER('t', "nr_threads" , &p0.nr_threads, "number of threads per process"),
156
157 OPT_STRING('G', "mb_global" , &p0.mb_global_str, "MB", "global memory (MBs)"),
158 OPT_STRING('P', "mb_proc" , &p0.mb_proc_str, "MB", "process memory (MBs)"),
159 OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"),
160 OPT_STRING('T', "mb_thread" , &p0.mb_thread_str, "MB", "thread memory (MBs)"),
161
162 OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run"),
163 OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run"),
164 OPT_UINTEGER('u', "usleep" , &p0.sleep_usecs, "usecs to sleep per loop iteration"),
165
166 OPT_BOOLEAN('R', "data_reads" , &p0.data_reads, "access the data via writes (can be mixed with -W)"),
167 OPT_BOOLEAN('W', "data_writes" , &p0.data_writes, "access the data via writes (can be mixed with -R)"),
168 OPT_BOOLEAN('B', "data_backwards", &p0.data_backwards, "access the data backwards as well"),
169 OPT_BOOLEAN('Z', "data_zero_memset", &p0.data_zero_memset,"access the data via glibc bzero only"),
170 OPT_BOOLEAN('r', "data_rand_walk", &p0.data_rand_walk, "access the data with random (32bit LFSR) walk"),
171
172
173 OPT_BOOLEAN('z', "init_zero" , &p0.init_zero, "bzero the initial allocations"),
174 OPT_BOOLEAN('I', "init_random" , &p0.init_random, "randomize the contents of the initial allocations"),
175 OPT_BOOLEAN('0', "init_cpu0" , &p0.init_cpu0, "do the initial allocations on CPU#0"),
176 OPT_INTEGER('x', "perturb_secs", &p0.perturb_secs, "perturb thread 0/0 every X secs, to test convergence stability"),
177
178 OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
179 OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"),
180 OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
181 OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
182 OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
183 OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "bzero the initial allocations"),
184 OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
185
186 /* Special option string parsing callbacks: */
187 OPT_CALLBACK('C', "cpus", NULL, "cpu[,cpu2,...cpuN]",
188 "bind the first N tasks to these specific cpus (the rest is unbound)",
189 parse_cpus_opt),
190 OPT_CALLBACK('M', "memnodes", NULL, "node[,node2,...nodeN]",
191 "bind the first N tasks to these specific memory nodes (the rest is unbound)",
192 parse_nodes_opt),
193 OPT_END()
194};
195
196static const char * const bench_numa_usage[] = {
197 "perf bench numa <options>",
198 NULL
199};
200
201static const char * const numa_usage[] = {
202 "perf bench numa mem [<options>]",
203 NULL
204};
205
206static cpu_set_t bind_to_cpu(int target_cpu)
207{
208 cpu_set_t orig_mask, mask;
209 int ret;
210
211 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
212 BUG_ON(ret);
213
214 CPU_ZERO(&mask);
215
216 if (target_cpu == -1) {
217 int cpu;
218
219 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
220 CPU_SET(cpu, &mask);
221 } else {
222 BUG_ON(target_cpu < 0 || target_cpu >= g->p.nr_cpus);
223 CPU_SET(target_cpu, &mask);
224 }
225
226 ret = sched_setaffinity(0, sizeof(mask), &mask);
227 BUG_ON(ret);
228
229 return orig_mask;
230}
231
232static cpu_set_t bind_to_node(int target_node)
233{
234 int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
235 cpu_set_t orig_mask, mask;
236 int cpu;
237 int ret;
238
239 BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
240 BUG_ON(!cpus_per_node);
241
242 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
243 BUG_ON(ret);
244
245 CPU_ZERO(&mask);
246
247 if (target_node == -1) {
248 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
249 CPU_SET(cpu, &mask);
250 } else {
251 int cpu_start = (target_node + 0) * cpus_per_node;
252 int cpu_stop = (target_node + 1) * cpus_per_node;
253
254 BUG_ON(cpu_stop > g->p.nr_cpus);
255
256 for (cpu = cpu_start; cpu < cpu_stop; cpu++)
257 CPU_SET(cpu, &mask);
258 }
259
260 ret = sched_setaffinity(0, sizeof(mask), &mask);
261 BUG_ON(ret);
262
263 return orig_mask;
264}
265
266static void bind_to_cpumask(cpu_set_t mask)
267{
268 int ret;
269
270 ret = sched_setaffinity(0, sizeof(mask), &mask);
271 BUG_ON(ret);
272}
273
274static void mempol_restore(void)
275{
276 int ret;
277
278 ret = set_mempolicy(MPOL_DEFAULT, NULL, g->p.nr_nodes-1);
279
280 BUG_ON(ret);
281}
282
283static void bind_to_memnode(int node)
284{
285 unsigned long nodemask;
286 int ret;
287
288 if (node == -1)
289 return;
290
291 BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask));
292 nodemask = 1L << node;
293
294 ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
295 dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret);
296
297 BUG_ON(ret);
298}
299
300#define HPSIZE (2*1024*1024)
301
302#define set_taskname(fmt...) \
303do { \
304 char name[20]; \
305 \
306 snprintf(name, 20, fmt); \
307 prctl(PR_SET_NAME, name); \
308} while (0)
309
310static u8 *alloc_data(ssize_t bytes0, int map_flags,
311 int init_zero, int init_cpu0, int thp, int init_random)
312{
313 cpu_set_t orig_mask;
314 ssize_t bytes;
315 u8 *buf;
316 int ret;
317
318 if (!bytes0)
319 return NULL;
320
321 /* Allocate and initialize all memory on CPU#0: */
322 if (init_cpu0) {
323 orig_mask = bind_to_node(0);
324 bind_to_memnode(0);
325 }
326
327 bytes = bytes0 + HPSIZE;
328
329 buf = (void *)mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|map_flags, -1, 0);
330 BUG_ON(buf == (void *)-1);
331
332 if (map_flags == MAP_PRIVATE) {
333 if (thp > 0) {
334 ret = madvise(buf, bytes, MADV_HUGEPAGE);
335 if (ret && !g->print_once) {
336 g->print_once = 1;
337 printf("WARNING: Could not enable THP - do: 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'\n");
338 }
339 }
340 if (thp < 0) {
341 ret = madvise(buf, bytes, MADV_NOHUGEPAGE);
342 if (ret && !g->print_once) {
343 g->print_once = 1;
344 printf("WARNING: Could not disable THP: run a CONFIG_TRANSPARENT_HUGEPAGE kernel?\n");
345 }
346 }
347 }
348
349 if (init_zero) {
350 bzero(buf, bytes);
351 } else {
352 /* Initialize random contents, different in each word: */
353 if (init_random) {
354 u64 *wbuf = (void *)buf;
355 long off = rand();
356 long i;
357
358 for (i = 0; i < bytes/8; i++)
359 wbuf[i] = i + off;
360 }
361 }
362
363 /* Align to 2MB boundary: */
364 buf = (void *)(((unsigned long)buf + HPSIZE-1) & ~(HPSIZE-1));
365
366 /* Restore affinity: */
367 if (init_cpu0) {
368 bind_to_cpumask(orig_mask);
369 mempol_restore();
370 }
371
372 return buf;
373}
374
375static void free_data(void *data, ssize_t bytes)
376{
377 int ret;
378
379 if (!data)
380 return;
381
382 ret = munmap(data, bytes);
383 BUG_ON(ret);
384}
385
386/*
387 * Create a shared memory buffer that can be shared between processes, zeroed:
388 */
389static void * zalloc_shared_data(ssize_t bytes)
390{
391 return alloc_data(bytes, MAP_SHARED, 1, g->p.init_cpu0, g->p.thp, g->p.init_random);
392}
393
394/*
395 * Create a shared memory buffer that can be shared between processes:
396 */
397static void * setup_shared_data(ssize_t bytes)
398{
399 return alloc_data(bytes, MAP_SHARED, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
400}
401
402/*
403 * Allocate process-local memory - this will either be shared between
404 * threads of this process, or only be accessed by this thread:
405 */
406static void * setup_private_data(ssize_t bytes)
407{
408 return alloc_data(bytes, MAP_PRIVATE, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
409}
410
411/*
412 * Return a process-shared (global) mutex:
413 */
414static void init_global_mutex(pthread_mutex_t *mutex)
415{
416 pthread_mutexattr_t attr;
417
418 pthread_mutexattr_init(&attr);
419 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
420 pthread_mutex_init(mutex, &attr);
421}
422
423static int parse_cpu_list(const char *arg)
424{
425 p0.cpu_list_str = strdup(arg);
426
427 dprintf("got CPU list: {%s}\n", p0.cpu_list_str);
428
429 return 0;
430}
431
432static void parse_setup_cpu_list(void)
433{
434 struct thread_data *td;
435 char *str0, *str;
436 int t;
437
438 if (!g->p.cpu_list_str)
439 return;
440
441 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
442
443 str0 = str = strdup(g->p.cpu_list_str);
444 t = 0;
445
446 BUG_ON(!str);
447
448 tprintf("# binding tasks to CPUs:\n");
449 tprintf("# ");
450
451 while (true) {
452 int bind_cpu, bind_cpu_0, bind_cpu_1;
453 char *tok, *tok_end, *tok_step, *tok_len, *tok_mul;
454 int bind_len;
455 int step;
456 int mul;
457
458 tok = strsep(&str, ",");
459 if (!tok)
460 break;
461
462 tok_end = strstr(tok, "-");
463
464 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
465 if (!tok_end) {
466 /* Single CPU specified: */
467 bind_cpu_0 = bind_cpu_1 = atol(tok);
468 } else {
469 /* CPU range specified (for example: "5-11"): */
470 bind_cpu_0 = atol(tok);
471 bind_cpu_1 = atol(tok_end + 1);
472 }
473
474 step = 1;
475 tok_step = strstr(tok, "#");
476 if (tok_step) {
477 step = atol(tok_step + 1);
478 BUG_ON(step <= 0 || step >= g->p.nr_cpus);
479 }
480
481 /*
482 * Mask length.
483 * Eg: "--cpus 8_4-16#4" means: '--cpus 8_4,12_4,16_4',
484 * where the _4 means the next 4 CPUs are allowed.
485 */
486 bind_len = 1;
487 tok_len = strstr(tok, "_");
488 if (tok_len) {
489 bind_len = atol(tok_len + 1);
490 BUG_ON(bind_len <= 0 || bind_len > g->p.nr_cpus);
491 }
492
493 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
494 mul = 1;
495 tok_mul = strstr(tok, "x");
496 if (tok_mul) {
497 mul = atol(tok_mul + 1);
498 BUG_ON(mul <= 0);
499 }
500
501 dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
502
503 BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus);
504 BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus);
505 BUG_ON(bind_cpu_0 > bind_cpu_1);
506
507 for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
508 int i;
509
510 for (i = 0; i < mul; i++) {
511 int cpu;
512
513 if (t >= g->p.nr_tasks) {
514 printf("\n# NOTE: ignoring bind CPUs starting at CPU#%d\n #", bind_cpu);
515 goto out;
516 }
517 td = g->threads + t;
518
519 if (t)
520 tprintf(",");
521 if (bind_len > 1) {
522 tprintf("%2d/%d", bind_cpu, bind_len);
523 } else {
524 tprintf("%2d", bind_cpu);
525 }
526
527 CPU_ZERO(&td->bind_cpumask);
528 for (cpu = bind_cpu; cpu < bind_cpu+bind_len; cpu++) {
529 BUG_ON(cpu < 0 || cpu >= g->p.nr_cpus);
530 CPU_SET(cpu, &td->bind_cpumask);
531 }
532 t++;
533 }
534 }
535 }
536out:
537
538 tprintf("\n");
539
540 if (t < g->p.nr_tasks)
541 printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
542
543 free(str0);
544}
545
546static int parse_cpus_opt(const struct option *opt __maybe_unused,
547 const char *arg, int unset __maybe_unused)
548{
549 if (!arg)
550 return -1;
551
552 return parse_cpu_list(arg);
553}
554
555static int parse_node_list(const char *arg)
556{
557 p0.node_list_str = strdup(arg);
558
559 dprintf("got NODE list: {%s}\n", p0.node_list_str);
560
561 return 0;
562}
563
564static void parse_setup_node_list(void)
565{
566 struct thread_data *td;
567 char *str0, *str;
568 int t;
569
570 if (!g->p.node_list_str)
571 return;
572
573 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
574
575 str0 = str = strdup(g->p.node_list_str);
576 t = 0;
577
578 BUG_ON(!str);
579
580 tprintf("# binding tasks to NODEs:\n");
581 tprintf("# ");
582
583 while (true) {
584 int bind_node, bind_node_0, bind_node_1;
585 char *tok, *tok_end, *tok_step, *tok_mul;
586 int step;
587 int mul;
588
589 tok = strsep(&str, ",");
590 if (!tok)
591 break;
592
593 tok_end = strstr(tok, "-");
594
595 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
596 if (!tok_end) {
597 /* Single NODE specified: */
598 bind_node_0 = bind_node_1 = atol(tok);
599 } else {
600 /* NODE range specified (for example: "5-11"): */
601 bind_node_0 = atol(tok);
602 bind_node_1 = atol(tok_end + 1);
603 }
604
605 step = 1;
606 tok_step = strstr(tok, "#");
607 if (tok_step) {
608 step = atol(tok_step + 1);
609 BUG_ON(step <= 0 || step >= g->p.nr_nodes);
610 }
611
612 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
613 mul = 1;
614 tok_mul = strstr(tok, "x");
615 if (tok_mul) {
616 mul = atol(tok_mul + 1);
617 BUG_ON(mul <= 0);
618 }
619
620 dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
621
622 BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes);
623 BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes);
624 BUG_ON(bind_node_0 > bind_node_1);
625
626 for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
627 int i;
628
629 for (i = 0; i < mul; i++) {
630 if (t >= g->p.nr_tasks) {
631 printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
632 goto out;
633 }
634 td = g->threads + t;
635
636 if (!t)
637 tprintf(" %2d", bind_node);
638 else
639 tprintf(",%2d", bind_node);
640
641 td->bind_node = bind_node;
642 t++;
643 }
644 }
645 }
646out:
647
648 tprintf("\n");
649
650 if (t < g->p.nr_tasks)
651 printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
652
653 free(str0);
654}
655
656static int parse_nodes_opt(const struct option *opt __maybe_unused,
657 const char *arg, int unset __maybe_unused)
658{
659 if (!arg)
660 return -1;
661
662 return parse_node_list(arg);
663
664 return 0;
665}
666
667#define BIT(x) (1ul << x)
668
669static inline uint32_t lfsr_32(uint32_t lfsr)
670{
671 const uint32_t taps = BIT(1) | BIT(5) | BIT(6) | BIT(31);
672 return (lfsr>>1) ^ ((0x0u - (lfsr & 0x1u)) & taps);
673}
674
675/*
676 * Make sure there's real data dependency to RAM (when read
677 * accesses are enabled), so the compiler, the CPU and the
678 * kernel (KSM, zero page, etc.) cannot optimize away RAM
679 * accesses:
680 */
681static inline u64 access_data(u64 *data __attribute__((unused)), u64 val)
682{
683 if (g->p.data_reads)
684 val += *data;
685 if (g->p.data_writes)
686 *data = val + 1;
687 return val;
688}
689
690/*
691 * The worker process does two types of work, a forwards going
692 * loop and a backwards going loop.
693 *
694 * We do this so that on multiprocessor systems we do not create
695 * a 'train' of processing, with highly synchronized processes,
696 * skewing the whole benchmark.
697 */
698static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val)
699{
700 long words = bytes/sizeof(u64);
701 u64 *data = (void *)__data;
702 long chunk_0, chunk_1;
703 u64 *d0, *d, *d1;
704 long off;
705 long i;
706
707 BUG_ON(!data && words);
708 BUG_ON(data && !words);
709
710 if (!data)
711 return val;
712
713 /* Very simple memset() work variant: */
714 if (g->p.data_zero_memset && !g->p.data_rand_walk) {
715 bzero(data, bytes);
716 return val;
717 }
718
719 /* Spread out by PID/TID nr and by loop nr: */
720 chunk_0 = words/nr_max;
721 chunk_1 = words/g->p.nr_loops;
722 off = nr*chunk_0 + loop*chunk_1;
723
724 while (off >= words)
725 off -= words;
726
727 if (g->p.data_rand_walk) {
728 u32 lfsr = nr + loop + val;
729 int j;
730
731 for (i = 0; i < words/1024; i++) {
732 long start, end;
733
734 lfsr = lfsr_32(lfsr);
735
736 start = lfsr % words;
737 end = min(start + 1024, words-1);
738
739 if (g->p.data_zero_memset) {
740 bzero(data + start, (end-start) * sizeof(u64));
741 } else {
742 for (j = start; j < end; j++)
743 val = access_data(data + j, val);
744 }
745 }
746 } else if (!g->p.data_backwards || (nr + loop) & 1) {
747
748 d0 = data + off;
749 d = data + off + 1;
750 d1 = data + words;
751
752 /* Process data forwards: */
753 for (;;) {
754 if (unlikely(d >= d1))
755 d = data;
756 if (unlikely(d == d0))
757 break;
758
759 val = access_data(d, val);
760
761 d++;
762 }
763 } else {
764 /* Process data backwards: */
765
766 d0 = data + off;
767 d = data + off - 1;
768 d1 = data + words;
769
770 /* Process data forwards: */
771 for (;;) {
772 if (unlikely(d < data))
773 d = data + words-1;
774 if (unlikely(d == d0))
775 break;
776
777 val = access_data(d, val);
778
779 d--;
780 }
781 }
782
783 return val;
784}
785
786static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
787{
788 unsigned int cpu;
789
790 cpu = sched_getcpu();
791
792 g->threads[task_nr].curr_cpu = cpu;
793 prctl(0, bytes_worked);
794}
795
796#define MAX_NR_NODES 64
797
798/*
799 * Count the number of nodes a process's threads
800 * are spread out on.
801 *
802 * A count of 1 means that the process is compressed
803 * to a single node. A count of g->p.nr_nodes means it's
804 * spread out on the whole system.
805 */
806static int count_process_nodes(int process_nr)
807{
808 char node_present[MAX_NR_NODES] = { 0, };
809 int nodes;
810 int n, t;
811
812 for (t = 0; t < g->p.nr_threads; t++) {
813 struct thread_data *td;
814 int task_nr;
815 int node;
816
817 task_nr = process_nr*g->p.nr_threads + t;
818 td = g->threads + task_nr;
819
820 node = numa_node_of_cpu(td->curr_cpu);
821 node_present[node] = 1;
822 }
823
824 nodes = 0;
825
826 for (n = 0; n < MAX_NR_NODES; n++)
827 nodes += node_present[n];
828
829 return nodes;
830}
831
832/*
833 * Count the number of distinct process-threads a node contains.
834 *
835 * A count of 1 means that the node contains only a single
836 * process. If all nodes on the system contain at most one
837 * process then we are well-converged.
838 */
839static int count_node_processes(int node)
840{
841 int processes = 0;
842 int t, p;
843
844 for (p = 0; p < g->p.nr_proc; p++) {
845 for (t = 0; t < g->p.nr_threads; t++) {
846 struct thread_data *td;
847 int task_nr;
848 int n;
849
850 task_nr = p*g->p.nr_threads + t;
851 td = g->threads + task_nr;
852
853 n = numa_node_of_cpu(td->curr_cpu);
854 if (n == node) {
855 processes++;
856 break;
857 }
858 }
859 }
860
861 return processes;
862}
863
864static void calc_convergence_compression(int *strong)
865{
866 unsigned int nodes_min, nodes_max;
867 int p;
868
869 nodes_min = -1;
870 nodes_max = 0;
871
872 for (p = 0; p < g->p.nr_proc; p++) {
873 unsigned int nodes = count_process_nodes(p);
874
875 nodes_min = min(nodes, nodes_min);
876 nodes_max = max(nodes, nodes_max);
877 }
878
879 /* Strong convergence: all threads compress on a single node: */
880 if (nodes_min == 1 && nodes_max == 1) {
881 *strong = 1;
882 } else {
883 *strong = 0;
884 tprintf(" {%d-%d}", nodes_min, nodes_max);
885 }
886}
887
888static void calc_convergence(double runtime_ns_max, double *convergence)
889{
890 unsigned int loops_done_min, loops_done_max;
891 int process_groups;
892 int nodes[MAX_NR_NODES];
893 int distance;
894 int nr_min;
895 int nr_max;
896 int strong;
897 int sum;
898 int nr;
899 int node;
900 int cpu;
901 int t;
902
903 if (!g->p.show_convergence && !g->p.measure_convergence)
904 return;
905
906 for (node = 0; node < g->p.nr_nodes; node++)
907 nodes[node] = 0;
908
909 loops_done_min = -1;
910 loops_done_max = 0;
911
912 for (t = 0; t < g->p.nr_tasks; t++) {
913 struct thread_data *td = g->threads + t;
914 unsigned int loops_done;
915
916 cpu = td->curr_cpu;
917
918 /* Not all threads have written it yet: */
919 if (cpu < 0)
920 continue;
921
922 node = numa_node_of_cpu(cpu);
923
924 nodes[node]++;
925
926 loops_done = td->loops_done;
927 loops_done_min = min(loops_done, loops_done_min);
928 loops_done_max = max(loops_done, loops_done_max);
929 }
930
931 nr_max = 0;
932 nr_min = g->p.nr_tasks;
933 sum = 0;
934
935 for (node = 0; node < g->p.nr_nodes; node++) {
936 nr = nodes[node];
937 nr_min = min(nr, nr_min);
938 nr_max = max(nr, nr_max);
939 sum += nr;
940 }
941 BUG_ON(nr_min > nr_max);
942
943 BUG_ON(sum > g->p.nr_tasks);
944
945 if (0 && (sum < g->p.nr_tasks))
946 return;
947
948 /*
949 * Count the number of distinct process groups present
950 * on nodes - when we are converged this will decrease
951 * to g->p.nr_proc:
952 */
953 process_groups = 0;
954
955 for (node = 0; node < g->p.nr_nodes; node++) {
956 int processes = count_node_processes(node);
957
958 nr = nodes[node];
959 tprintf(" %2d/%-2d", nr, processes);
960
961 process_groups += processes;
962 }
963
964 distance = nr_max - nr_min;
965
966 tprintf(" [%2d/%-2d]", distance, process_groups);
967
968 tprintf(" l:%3d-%-3d (%3d)",
969 loops_done_min, loops_done_max, loops_done_max-loops_done_min);
970
971 if (loops_done_min && loops_done_max) {
972 double skew = 1.0 - (double)loops_done_min/loops_done_max;
973
974 tprintf(" [%4.1f%%]", skew * 100.0);
975 }
976
977 calc_convergence_compression(&strong);
978
979 if (strong && process_groups == g->p.nr_proc) {
980 if (!*convergence) {
981 *convergence = runtime_ns_max;
982 tprintf(" (%6.1fs converged)\n", *convergence/1e9);
983 if (g->p.measure_convergence) {
984 g->all_converged = true;
985 g->stop_work = true;
986 }
987 }
988 } else {
989 if (*convergence) {
990 tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9);
991 *convergence = 0;
992 }
993 tprintf("\n");
994 }
995}
996
997static void show_summary(double runtime_ns_max, int l, double *convergence)
998{
999 tprintf("\r # %5.1f%% [%.1f mins]",
1000 (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0);
1001
1002 calc_convergence(runtime_ns_max, convergence);
1003
1004 if (g->p.show_details >= 0)
1005 fflush(stdout);
1006}
1007
1008static void *worker_thread(void *__tdata)
1009{
1010 struct thread_data *td = __tdata;
1011 struct timeval start0, start, stop, diff;
1012 int process_nr = td->process_nr;
1013 int thread_nr = td->thread_nr;
1014 unsigned long last_perturbance;
1015 int task_nr = td->task_nr;
1016 int details = g->p.show_details;
1017 int first_task, last_task;
1018 double convergence = 0;
1019 u64 val = td->val;
1020 double runtime_ns_max;
1021 u8 *global_data;
1022 u8 *process_data;
1023 u8 *thread_data;
1024 u64 bytes_done;
1025 long work_done;
1026 u32 l;
1027
1028 bind_to_cpumask(td->bind_cpumask);
1029 bind_to_memnode(td->bind_node);
1030
1031 set_taskname("thread %d/%d", process_nr, thread_nr);
1032
1033 global_data = g->data;
1034 process_data = td->process_data;
1035 thread_data = setup_private_data(g->p.bytes_thread);
1036
1037 bytes_done = 0;
1038
1039 last_task = 0;
1040 if (process_nr == g->p.nr_proc-1 && thread_nr == g->p.nr_threads-1)
1041 last_task = 1;
1042
1043 first_task = 0;
1044 if (process_nr == 0 && thread_nr == 0)
1045 first_task = 1;
1046
1047 if (details >= 2) {
1048 printf("# thread %2d / %2d global mem: %p, process mem: %p, thread mem: %p\n",
1049 process_nr, thread_nr, global_data, process_data, thread_data);
1050 }
1051
1052 if (g->p.serialize_startup) {
1053 pthread_mutex_lock(&g->startup_mutex);
1054 g->nr_tasks_started++;
1055 pthread_mutex_unlock(&g->startup_mutex);
1056
1057 /* Here we will wait for the main process to start us all at once: */
1058 pthread_mutex_lock(&g->start_work_mutex);
1059 g->nr_tasks_working++;
1060
1061 /* Last one wake the main process: */
1062 if (g->nr_tasks_working == g->p.nr_tasks)
1063 pthread_mutex_unlock(&g->startup_done_mutex);
1064
1065 pthread_mutex_unlock(&g->start_work_mutex);
1066 }
1067
1068 gettimeofday(&start0, NULL);
1069
1070 start = stop = start0;
1071 last_perturbance = start.tv_sec;
1072
1073 for (l = 0; l < g->p.nr_loops; l++) {
1074 start = stop;
1075
1076 if (g->stop_work)
1077 break;
1078
1079 val += do_work(global_data, g->p.bytes_global, process_nr, g->p.nr_proc, l, val);
1080 val += do_work(process_data, g->p.bytes_process, thread_nr, g->p.nr_threads, l, val);
1081 val += do_work(thread_data, g->p.bytes_thread, 0, 1, l, val);
1082
1083 if (g->p.sleep_usecs) {
1084 pthread_mutex_lock(td->process_lock);
1085 usleep(g->p.sleep_usecs);
1086 pthread_mutex_unlock(td->process_lock);
1087 }
1088 /*
1089 * Amount of work to be done under a process-global lock:
1090 */
1091 if (g->p.bytes_process_locked) {
1092 pthread_mutex_lock(td->process_lock);
1093 val += do_work(process_data, g->p.bytes_process_locked, thread_nr, g->p.nr_threads, l, val);
1094 pthread_mutex_unlock(td->process_lock);
1095 }
1096
1097 work_done = g->p.bytes_global + g->p.bytes_process +
1098 g->p.bytes_process_locked + g->p.bytes_thread;
1099
1100 update_curr_cpu(task_nr, work_done);
1101 bytes_done += work_done;
1102
1103 if (details < 0 && !g->p.perturb_secs && !g->p.measure_convergence && !g->p.nr_secs)
1104 continue;
1105
1106 td->loops_done = l;
1107
1108 gettimeofday(&stop, NULL);
1109
1110 /* Check whether our max runtime timed out: */
1111 if (g->p.nr_secs) {
1112 timersub(&stop, &start0, &diff);
1113 if (diff.tv_sec >= g->p.nr_secs) {
1114 g->stop_work = true;
1115 break;
1116 }
1117 }
1118
1119 /* Update the summary at most once per second: */
1120 if (start.tv_sec == stop.tv_sec)
1121 continue;
1122
1123 /*
1124 * Perturb the first task's equilibrium every g->p.perturb_secs seconds,
1125 * by migrating to CPU#0:
1126 */
1127 if (first_task && g->p.perturb_secs && (int)(stop.tv_sec - last_perturbance) >= g->p.perturb_secs) {
1128 cpu_set_t orig_mask;
1129 int target_cpu;
1130 int this_cpu;
1131
1132 last_perturbance = stop.tv_sec;
1133
1134 /*
1135 * Depending on where we are running, move into
1136 * the other half of the system, to create some
1137 * real disturbance:
1138 */
1139 this_cpu = g->threads[task_nr].curr_cpu;
1140 if (this_cpu < g->p.nr_cpus/2)
1141 target_cpu = g->p.nr_cpus-1;
1142 else
1143 target_cpu = 0;
1144
1145 orig_mask = bind_to_cpu(target_cpu);
1146
1147 /* Here we are running on the target CPU already */
1148 if (details >= 1)
1149 printf(" (injecting perturbalance, moved to CPU#%d)\n", target_cpu);
1150
1151 bind_to_cpumask(orig_mask);
1152 }
1153
1154 if (details >= 3) {
1155 timersub(&stop, &start, &diff);
1156 runtime_ns_max = diff.tv_sec * 1000000000;
1157 runtime_ns_max += diff.tv_usec * 1000;
1158
1159 if (details >= 0) {
1160 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n",
1161 process_nr, thread_nr, runtime_ns_max / bytes_done, val);
1162 }
1163 fflush(stdout);
1164 }
1165 if (!last_task)
1166 continue;
1167
1168 timersub(&stop, &start0, &diff);
1169 runtime_ns_max = diff.tv_sec * 1000000000ULL;
1170 runtime_ns_max += diff.tv_usec * 1000ULL;
1171
1172 show_summary(runtime_ns_max, l, &convergence);
1173 }
1174
1175 gettimeofday(&stop, NULL);
1176 timersub(&stop, &start0, &diff);
1177 td->runtime_ns = diff.tv_sec * 1000000000ULL;
1178 td->runtime_ns += diff.tv_usec * 1000ULL;
1179
1180 free_data(thread_data, g->p.bytes_thread);
1181
1182 pthread_mutex_lock(&g->stop_work_mutex);
1183 g->bytes_done += bytes_done;
1184 pthread_mutex_unlock(&g->stop_work_mutex);
1185
1186 return NULL;
1187}
1188
1189/*
1190 * A worker process starts a couple of threads:
1191 */
1192static void worker_process(int process_nr)
1193{
1194 pthread_mutex_t process_lock;
1195 struct thread_data *td;
1196 pthread_t *pthreads;
1197 u8 *process_data;
1198 int task_nr;
1199 int ret;
1200 int t;
1201
1202 pthread_mutex_init(&process_lock, NULL);
1203 set_taskname("process %d", process_nr);
1204
1205 /*
1206 * Pick up the memory policy and the CPU binding of our first thread,
1207 * so that we initialize memory accordingly:
1208 */
1209 task_nr = process_nr*g->p.nr_threads;
1210 td = g->threads + task_nr;
1211
1212 bind_to_memnode(td->bind_node);
1213 bind_to_cpumask(td->bind_cpumask);
1214
1215 pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t));
1216 process_data = setup_private_data(g->p.bytes_process);
1217
1218 if (g->p.show_details >= 3) {
1219 printf(" # process %2d global mem: %p, process mem: %p\n",
1220 process_nr, g->data, process_data);
1221 }
1222
1223 for (t = 0; t < g->p.nr_threads; t++) {
1224 task_nr = process_nr*g->p.nr_threads + t;
1225 td = g->threads + task_nr;
1226
1227 td->process_data = process_data;
1228 td->process_nr = process_nr;
1229 td->thread_nr = t;
1230 td->task_nr = task_nr;
1231 td->val = rand();
1232 td->curr_cpu = -1;
1233 td->process_lock = &process_lock;
1234
1235 ret = pthread_create(pthreads + t, NULL, worker_thread, td);
1236 BUG_ON(ret);
1237 }
1238
1239 for (t = 0; t < g->p.nr_threads; t++) {
1240 ret = pthread_join(pthreads[t], NULL);
1241 BUG_ON(ret);
1242 }
1243
1244 free_data(process_data, g->p.bytes_process);
1245 free(pthreads);
1246}
1247
1248static void print_summary(void)
1249{
1250 if (g->p.show_details < 0)
1251 return;
1252
1253 printf("\n ###\n");
1254 printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
1255 g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
1256 printf(" # %5dx %5ldMB global shared mem operations\n",
1257 g->p.nr_loops, g->p.bytes_global/1024/1024);
1258 printf(" # %5dx %5ldMB process shared mem operations\n",
1259 g->p.nr_loops, g->p.bytes_process/1024/1024);
1260 printf(" # %5dx %5ldMB thread local mem operations\n",
1261 g->p.nr_loops, g->p.bytes_thread/1024/1024);
1262
1263 printf(" ###\n");
1264
1265 printf("\n ###\n"); fflush(stdout);
1266}
1267
1268static void init_thread_data(void)
1269{
1270 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1271 int t;
1272
1273 g->threads = zalloc_shared_data(size);
1274
1275 for (t = 0; t < g->p.nr_tasks; t++) {
1276 struct thread_data *td = g->threads + t;
1277 int cpu;
1278
1279 /* Allow all nodes by default: */
1280 td->bind_node = -1;
1281
1282 /* Allow all CPUs by default: */
1283 CPU_ZERO(&td->bind_cpumask);
1284 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
1285 CPU_SET(cpu, &td->bind_cpumask);
1286 }
1287}
1288
1289static void deinit_thread_data(void)
1290{
1291 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1292
1293 free_data(g->threads, size);
1294}
1295
1296static int init(void)
1297{
1298 g = (void *)alloc_data(sizeof(*g), MAP_SHARED, 1, 0, 0 /* THP */, 0);
1299
1300 /* Copy over options: */
1301 g->p = p0;
1302
1303 g->p.nr_cpus = numa_num_configured_cpus();
1304
1305 g->p.nr_nodes = numa_max_node() + 1;
1306
1307 /* char array in count_process_nodes(): */
1308 BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0);
1309
1310 if (g->p.show_quiet && !g->p.show_details)
1311 g->p.show_details = -1;
1312
1313 /* Some memory should be specified: */
1314 if (!g->p.mb_global_str && !g->p.mb_proc_str && !g->p.mb_thread_str)
1315 return -1;
1316
1317 if (g->p.mb_global_str) {
1318 g->p.mb_global = atof(g->p.mb_global_str);
1319 BUG_ON(g->p.mb_global < 0);
1320 }
1321
1322 if (g->p.mb_proc_str) {
1323 g->p.mb_proc = atof(g->p.mb_proc_str);
1324 BUG_ON(g->p.mb_proc < 0);
1325 }
1326
1327 if (g->p.mb_proc_locked_str) {
1328 g->p.mb_proc_locked = atof(g->p.mb_proc_locked_str);
1329 BUG_ON(g->p.mb_proc_locked < 0);
1330 BUG_ON(g->p.mb_proc_locked > g->p.mb_proc);
1331 }
1332
1333 if (g->p.mb_thread_str) {
1334 g->p.mb_thread = atof(g->p.mb_thread_str);
1335 BUG_ON(g->p.mb_thread < 0);
1336 }
1337
1338 BUG_ON(g->p.nr_threads <= 0);
1339 BUG_ON(g->p.nr_proc <= 0);
1340
1341 g->p.nr_tasks = g->p.nr_proc*g->p.nr_threads;
1342
1343 g->p.bytes_global = g->p.mb_global *1024L*1024L;
1344 g->p.bytes_process = g->p.mb_proc *1024L*1024L;
1345 g->p.bytes_process_locked = g->p.mb_proc_locked *1024L*1024L;
1346 g->p.bytes_thread = g->p.mb_thread *1024L*1024L;
1347
1348 g->data = setup_shared_data(g->p.bytes_global);
1349
1350 /* Startup serialization: */
1351 init_global_mutex(&g->start_work_mutex);
1352 init_global_mutex(&g->startup_mutex);
1353 init_global_mutex(&g->startup_done_mutex);
1354 init_global_mutex(&g->stop_work_mutex);
1355
1356 init_thread_data();
1357
1358 tprintf("#\n");
1359 parse_setup_cpu_list();
1360 parse_setup_node_list();
1361 tprintf("#\n");
1362
1363 print_summary();
1364
1365 return 0;
1366}
1367
1368static void deinit(void)
1369{
1370 free_data(g->data, g->p.bytes_global);
1371 g->data = NULL;
1372
1373 deinit_thread_data();
1374
1375 free_data(g, sizeof(*g));
1376 g = NULL;
1377}
1378
1379/*
1380 * Print a short or long result, depending on the verbosity setting:
1381 */
1382static void print_res(const char *name, double val,
1383 const char *txt_unit, const char *txt_short, const char *txt_long)
1384{
1385 if (!name)
1386 name = "main,";
1387
1388 if (g->p.show_quiet)
1389 printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short);
1390 else
1391 printf(" %14.3f %s\n", val, txt_long);
1392}
1393
1394static int __bench_numa(const char *name)
1395{
1396 struct timeval start, stop, diff;
1397 u64 runtime_ns_min, runtime_ns_sum;
1398 pid_t *pids, pid, wpid;
1399 double delta_runtime;
1400 double runtime_avg;
1401 double runtime_sec_max;
1402 double runtime_sec_min;
1403 int wait_stat;
1404 double bytes;
1405 int i, t;
1406
1407 if (init())
1408 return -1;
1409
1410 pids = zalloc(g->p.nr_proc * sizeof(*pids));
1411 pid = -1;
1412
1413 /* All threads try to acquire it, this way we can wait for them to start up: */
1414 pthread_mutex_lock(&g->start_work_mutex);
1415
1416 if (g->p.serialize_startup) {
1417 tprintf(" #\n");
1418 tprintf(" # Startup synchronization: ..."); fflush(stdout);
1419 }
1420
1421 gettimeofday(&start, NULL);
1422
1423 for (i = 0; i < g->p.nr_proc; i++) {
1424 pid = fork();
1425 dprintf(" # process %2d: PID %d\n", i, pid);
1426
1427 BUG_ON(pid < 0);
1428 if (!pid) {
1429 /* Child process: */
1430 worker_process(i);
1431
1432 exit(0);
1433 }
1434 pids[i] = pid;
1435
1436 }
1437 /* Wait for all the threads to start up: */
1438 while (g->nr_tasks_started != g->p.nr_tasks)
1439 usleep(1000);
1440
1441 BUG_ON(g->nr_tasks_started != g->p.nr_tasks);
1442
1443 if (g->p.serialize_startup) {
1444 double startup_sec;
1445
1446 pthread_mutex_lock(&g->startup_done_mutex);
1447
1448 /* This will start all threads: */
1449 pthread_mutex_unlock(&g->start_work_mutex);
1450
1451 /* This mutex is locked - the last started thread will wake us: */
1452 pthread_mutex_lock(&g->startup_done_mutex);
1453
1454 gettimeofday(&stop, NULL);
1455
1456 timersub(&stop, &start, &diff);
1457
1458 startup_sec = diff.tv_sec * 1000000000.0;
1459 startup_sec += diff.tv_usec * 1000.0;
1460 startup_sec /= 1e9;
1461
1462 tprintf(" threads initialized in %.6f seconds.\n", startup_sec);
1463 tprintf(" #\n");
1464
1465 start = stop;
1466 pthread_mutex_unlock(&g->startup_done_mutex);
1467 } else {
1468 gettimeofday(&start, NULL);
1469 }
1470
1471 /* Parent process: */
1472
1473
1474 for (i = 0; i < g->p.nr_proc; i++) {
1475 wpid = waitpid(pids[i], &wait_stat, 0);
1476 BUG_ON(wpid < 0);
1477 BUG_ON(!WIFEXITED(wait_stat));
1478
1479 }
1480
1481 runtime_ns_sum = 0;
1482 runtime_ns_min = -1LL;
1483
1484 for (t = 0; t < g->p.nr_tasks; t++) {
1485 u64 thread_runtime_ns = g->threads[t].runtime_ns;
1486
1487 runtime_ns_sum += thread_runtime_ns;
1488 runtime_ns_min = min(thread_runtime_ns, runtime_ns_min);
1489 }
1490
1491 gettimeofday(&stop, NULL);
1492 timersub(&stop, &start, &diff);
1493
1494 BUG_ON(bench_format != BENCH_FORMAT_DEFAULT);
1495
1496 tprintf("\n ###\n");
1497 tprintf("\n");
1498
1499 runtime_sec_max = diff.tv_sec * 1000000000.0;
1500 runtime_sec_max += diff.tv_usec * 1000.0;
1501 runtime_sec_max /= 1e9;
1502
1503 runtime_sec_min = runtime_ns_min/1e9;
1504
1505 bytes = g->bytes_done;
1506 runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9;
1507
1508 if (g->p.measure_convergence) {
1509 print_res(name, runtime_sec_max,
1510 "secs,", "NUMA-convergence-latency", "secs latency to NUMA-converge");
1511 }
1512
1513 print_res(name, runtime_sec_max,
1514 "secs,", "runtime-max/thread", "secs slowest (max) thread-runtime");
1515
1516 print_res(name, runtime_sec_min,
1517 "secs,", "runtime-min/thread", "secs fastest (min) thread-runtime");
1518
1519 print_res(name, runtime_avg,
1520 "secs,", "runtime-avg/thread", "secs average thread-runtime");
1521
1522 delta_runtime = (runtime_sec_max - runtime_sec_min)/2.0;
1523 print_res(name, delta_runtime / runtime_sec_max * 100.0,
1524 "%,", "spread-runtime/thread", "% difference between max/avg runtime");
1525
1526 print_res(name, bytes / g->p.nr_tasks / 1e9,
1527 "GB,", "data/thread", "GB data processed, per thread");
1528
1529 print_res(name, bytes / 1e9,
1530 "GB,", "data-total", "GB data processed, total");
1531
1532 print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks),
1533 "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime");
1534
1535 print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max,
1536 "GB/sec,", "thread-speed", "GB/sec/thread speed");
1537
1538 print_res(name, bytes / runtime_sec_max / 1e9,
1539 "GB/sec,", "total-speed", "GB/sec total speed");
1540
1541 free(pids);
1542
1543 deinit();
1544
1545 return 0;
1546}
1547
1548#define MAX_ARGS 50
1549
1550static int command_size(const char **argv)
1551{
1552 int size = 0;
1553
1554 while (*argv) {
1555 size++;
1556 argv++;
1557 }
1558
1559 BUG_ON(size >= MAX_ARGS);
1560
1561 return size;
1562}
1563
1564static void init_params(struct params *p, const char *name, int argc, const char **argv)
1565{
1566 int i;
1567
1568 printf("\n # Running %s \"perf bench numa", name);
1569
1570 for (i = 0; i < argc; i++)
1571 printf(" %s", argv[i]);
1572
1573 printf("\"\n");
1574
1575 memset(p, 0, sizeof(*p));
1576
1577 /* Initialize nonzero defaults: */
1578
1579 p->serialize_startup = 1;
1580 p->data_reads = true;
1581 p->data_writes = true;
1582 p->data_backwards = true;
1583 p->data_rand_walk = true;
1584 p->nr_loops = -1;
1585 p->init_random = true;
1586}
1587
1588static int run_bench_numa(const char *name, const char **argv)
1589{
1590 int argc = command_size(argv);
1591
1592 init_params(&p0, name, argc, argv);
1593 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1594 if (argc)
1595 goto err;
1596
1597 if (__bench_numa(name))
1598 goto err;
1599
1600 return 0;
1601
1602err:
1603 usage_with_options(numa_usage, options);
1604 return -1;
1605}
1606
1607#define OPT_BW_RAM "-s", "20", "-zZq", "--thp", " 1", "--no-data_rand_walk"
1608#define OPT_BW_RAM_NOTHP OPT_BW_RAM, "--thp", "-1"
1609
1610#define OPT_CONV "-s", "100", "-zZ0qcm", "--thp", " 1"
1611#define OPT_CONV_NOTHP OPT_CONV, "--thp", "-1"
1612
1613#define OPT_BW "-s", "20", "-zZ0q", "--thp", " 1"
1614#define OPT_BW_NOTHP OPT_BW, "--thp", "-1"
1615
1616/*
1617 * The built-in test-suite executed by "perf bench numa -a".
1618 *
1619 * (A minimum of 4 nodes and 16 GB of RAM is recommended.)
1620 */
1621static const char *tests[][MAX_ARGS] = {
1622 /* Basic single-stream NUMA bandwidth measurements: */
1623 { "RAM-bw-local,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1624 "-C" , "0", "-M", "0", OPT_BW_RAM },
1625 { "RAM-bw-local-NOTHP,",
1626 "mem", "-p", "1", "-t", "1", "-P", "1024",
1627 "-C" , "0", "-M", "0", OPT_BW_RAM_NOTHP },
1628 { "RAM-bw-remote,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1629 "-C" , "0", "-M", "1", OPT_BW_RAM },
1630
1631 /* 2-stream NUMA bandwidth measurements: */
1632 { "RAM-bw-local-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1633 "-C", "0,2", "-M", "0x2", OPT_BW_RAM },
1634 { "RAM-bw-remote-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1635 "-C", "0,2", "-M", "1x2", OPT_BW_RAM },
1636
1637 /* Cross-stream NUMA bandwidth measurement: */
1638 { "RAM-bw-cross,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1639 "-C", "0,8", "-M", "1,0", OPT_BW_RAM },
1640
1641 /* Convergence latency measurements: */
1642 { " 1x3-convergence,", "mem", "-p", "1", "-t", "3", "-P", "512", OPT_CONV },
1643 { " 1x4-convergence,", "mem", "-p", "1", "-t", "4", "-P", "512", OPT_CONV },
1644 { " 1x6-convergence,", "mem", "-p", "1", "-t", "6", "-P", "1020", OPT_CONV },
1645 { " 2x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1646 { " 3x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1647 { " 4x4-convergence,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV },
1648 { " 4x4-convergence-NOTHP,",
1649 "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1650 { " 4x6-convergence,", "mem", "-p", "4", "-t", "6", "-P", "1020", OPT_CONV },
1651 { " 4x8-convergence,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_CONV },
1652 { " 8x4-convergence,", "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV },
1653 { " 8x4-convergence-NOTHP,",
1654 "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1655 { " 3x1-convergence,", "mem", "-p", "3", "-t", "1", "-P", "512", OPT_CONV },
1656 { " 4x1-convergence,", "mem", "-p", "4", "-t", "1", "-P", "512", OPT_CONV },
1657 { " 8x1-convergence,", "mem", "-p", "8", "-t", "1", "-P", "512", OPT_CONV },
1658 { "16x1-convergence,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_CONV },
1659 { "32x1-convergence,", "mem", "-p", "32", "-t", "1", "-P", "128", OPT_CONV },
1660
1661 /* Various NUMA process/thread layout bandwidth measurements: */
1662 { " 2x1-bw-process,", "mem", "-p", "2", "-t", "1", "-P", "1024", OPT_BW },
1663 { " 3x1-bw-process,", "mem", "-p", "3", "-t", "1", "-P", "1024", OPT_BW },
1664 { " 4x1-bw-process,", "mem", "-p", "4", "-t", "1", "-P", "1024", OPT_BW },
1665 { " 8x1-bw-process,", "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW },
1666 { " 8x1-bw-process-NOTHP,",
1667 "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW_NOTHP },
1668 { "16x1-bw-process,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_BW },
1669
1670 { " 4x1-bw-thread,", "mem", "-p", "1", "-t", "4", "-T", "256", OPT_BW },
1671 { " 8x1-bw-thread,", "mem", "-p", "1", "-t", "8", "-T", "256", OPT_BW },
1672 { "16x1-bw-thread,", "mem", "-p", "1", "-t", "16", "-T", "128", OPT_BW },
1673 { "32x1-bw-thread,", "mem", "-p", "1", "-t", "32", "-T", "64", OPT_BW },
1674
1675 { " 2x3-bw-thread,", "mem", "-p", "2", "-t", "3", "-P", "512", OPT_BW },
1676 { " 4x4-bw-thread,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_BW },
1677 { " 4x6-bw-thread,", "mem", "-p", "4", "-t", "6", "-P", "512", OPT_BW },
1678 { " 4x8-bw-thread,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW },
1679 { " 4x8-bw-thread-NOTHP,",
1680 "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW_NOTHP },
1681 { " 3x3-bw-thread,", "mem", "-p", "3", "-t", "3", "-P", "512", OPT_BW },
1682 { " 5x5-bw-thread,", "mem", "-p", "5", "-t", "5", "-P", "512", OPT_BW },
1683
1684 { "2x16-bw-thread,", "mem", "-p", "2", "-t", "16", "-P", "512", OPT_BW },
1685 { "1x32-bw-thread,", "mem", "-p", "1", "-t", "32", "-P", "2048", OPT_BW },
1686
1687 { "numa02-bw,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW },
1688 { "numa02-bw-NOTHP,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW_NOTHP },
1689 { "numa01-bw-thread,", "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW },
1690 { "numa01-bw-thread-NOTHP,",
1691 "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW_NOTHP },
1692};
1693
1694static int bench_all(void)
1695{
1696 int nr = ARRAY_SIZE(tests);
1697 int ret;
1698 int i;
1699
1700 ret = system("echo ' #'; echo ' # Running test on: '$(uname -a); echo ' #'");
1701 BUG_ON(ret < 0);
1702
1703 for (i = 0; i < nr; i++) {
1704 if (run_bench_numa(tests[i][0], tests[i] + 1))
1705 return -1;
1706 }
1707
1708 printf("\n");
1709
1710 return 0;
1711}
1712
1713int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused)
1714{
1715 init_params(&p0, "main,", argc, argv);
1716 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1717 if (argc)
1718 goto err;
1719
1720 if (p0.run_all)
1721 return bench_all();
1722
1723 if (__bench_numa(NULL))
1724 goto err;
1725
1726 return 0;
1727
1728err:
1729 usage_with_options(numa_usage, options);
1730 return -1;
1731}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index dc870cf31b79..2e6961ea3184 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -34,9 +34,10 @@
34 34
35struct perf_annotate { 35struct perf_annotate {
36 struct perf_tool tool; 36 struct perf_tool tool;
37 bool force, use_tui, use_stdio; 37 bool force, use_tui, use_stdio, use_gtk;
38 bool full_paths; 38 bool full_paths;
39 bool print_line; 39 bool print_line;
40 bool skip_missing;
40 const char *sym_hist_filter; 41 const char *sym_hist_filter;
41 const char *cpu_list; 42 const char *cpu_list;
42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 43 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -138,9 +139,22 @@ find_next:
138 continue; 139 continue;
139 } 140 }
140 141
141 if (use_browser > 0) { 142 if (use_browser == 2) {
143 int ret;
144
145 ret = hist_entry__gtk_annotate(he, evidx, NULL);
146 if (!ret || !ann->skip_missing)
147 return;
148
149 /* skip missing symbols */
150 nd = rb_next(nd);
151 } else if (use_browser == 1) {
142 key = hist_entry__tui_annotate(he, evidx, NULL); 152 key = hist_entry__tui_annotate(he, evidx, NULL);
143 switch (key) { 153 switch (key) {
154 case -1:
155 if (!ann->skip_missing)
156 return;
157 /* fall through */
144 case K_RIGHT: 158 case K_RIGHT:
145 next = rb_next(nd); 159 next = rb_next(nd);
146 break; 160 break;
@@ -224,6 +238,10 @@ static int __cmd_annotate(struct perf_annotate *ann)
224 ui__error("The %s file has no samples!\n", session->filename); 238 ui__error("The %s file has no samples!\n", session->filename);
225 goto out_delete; 239 goto out_delete;
226 } 240 }
241
242 if (use_browser == 2)
243 perf_gtk__show_annotations();
244
227out_delete: 245out_delete:
228 /* 246 /*
229 * Speed up the exit process, for large files this can 247 * Speed up the exit process, for large files this can
@@ -270,6 +288,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
270 "be more verbose (show symbol address, etc)"), 288 "be more verbose (show symbol address, etc)"),
271 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 289 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
272 "dump raw trace in ASCII"), 290 "dump raw trace in ASCII"),
291 OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
273 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), 292 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
274 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), 293 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
275 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 294 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@@ -280,6 +299,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
280 "print matching source lines (may be slow)"), 299 "print matching source lines (may be slow)"),
281 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, 300 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
282 "Don't shorten the displayed pathnames"), 301 "Don't shorten the displayed pathnames"),
302 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
303 "Skip symbols that cannot be annotated"),
283 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), 304 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
284 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 305 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
285 "Look for files with symbols relative to this directory"), 306 "Look for files with symbols relative to this directory"),
@@ -300,6 +321,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
300 use_browser = 0; 321 use_browser = 0;
301 else if (annotate.use_tui) 322 else if (annotate.use_tui)
302 use_browser = 1; 323 use_browser = 1;
324 else if (annotate.use_gtk)
325 use_browser = 2;
303 326
304 setup_browser(true); 327 setup_browser(true);
305 328
@@ -309,7 +332,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
309 if (symbol__init() < 0) 332 if (symbol__init() < 0)
310 return -1; 333 return -1;
311 334
312 setup_sorting(annotate_usage, options); 335 if (setup_sorting() < 0)
336 usage_with_options(annotate_usage, options);
313 337
314 if (argc) { 338 if (argc) {
315 /* 339 /*
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index cae9a5fd2ecf..77298bf892b8 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -35,6 +35,18 @@ struct bench_suite {
35/* sentinel: easy for help */ 35/* sentinel: easy for help */
36#define suite_all { "all", "Test all benchmark suites", NULL } 36#define suite_all { "all", "Test all benchmark suites", NULL }
37 37
38#ifdef LIBNUMA_SUPPORT
39static struct bench_suite numa_suites[] = {
40 { "mem",
41 "Benchmark for NUMA workloads",
42 bench_numa },
43 suite_all,
44 { NULL,
45 NULL,
46 NULL }
47};
48#endif
49
38static struct bench_suite sched_suites[] = { 50static struct bench_suite sched_suites[] = {
39 { "messaging", 51 { "messaging",
40 "Benchmark for scheduler and IPC mechanisms", 52 "Benchmark for scheduler and IPC mechanisms",
@@ -68,6 +80,11 @@ struct bench_subsys {
68}; 80};
69 81
70static struct bench_subsys subsystems[] = { 82static struct bench_subsys subsystems[] = {
83#ifdef LIBNUMA_SUPPORT
84 { "numa",
85 "NUMA scheduling and MM behavior",
86 numa_suites },
87#endif
71 { "sched", 88 { "sched",
72 "scheduler and IPC mechanism", 89 "scheduler and IPC mechanism",
73 sched_suites }, 90 sched_suites },
@@ -159,6 +176,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
159 printf("# Running %s/%s benchmark...\n", 176 printf("# Running %s/%s benchmark...\n",
160 subsys->name, 177 subsys->name,
161 suites[i].name); 178 suites[i].name);
179 fflush(stdout);
162 180
163 argv[1] = suites[i].name; 181 argv[1] = suites[i].name;
164 suites[i].fn(1, argv, NULL); 182 suites[i].fn(1, argv, NULL);
@@ -225,6 +243,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
225 printf("# Running %s/%s benchmark...\n", 243 printf("# Running %s/%s benchmark...\n",
226 subsystems[i].name, 244 subsystems[i].name,
227 subsystems[i].suites[j].name); 245 subsystems[i].suites[j].name);
246 fflush(stdout);
228 status = subsystems[i].suites[j].fn(argc - 1, 247 status = subsystems[i].suites[j].fn(argc - 1,
229 argv + 1, prefix); 248 argv + 1, prefix);
230 goto end; 249 goto end;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index fae8b250b2ca..c96c8fa38243 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/strlist.h" 15#include "util/strlist.h"
16#include "util/build-id.h" 16#include "util/build-id.h"
17#include "util/session.h"
17#include "util/symbol.h" 18#include "util/symbol.h"
18 19
19static int build_id_cache__add_file(const char *filename, const char *debugdir) 20static int build_id_cache__add_file(const char *filename, const char *debugdir)
@@ -58,19 +59,89 @@ static int build_id_cache__remove_file(const char *filename,
58 return err; 59 return err;
59} 60}
60 61
62static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
63{
64 char filename[PATH_MAX];
65 u8 build_id[BUILD_ID_SIZE];
66
67 if (dso__build_id_filename(dso, filename, sizeof(filename)) &&
68 filename__read_build_id(filename, build_id,
69 sizeof(build_id)) != sizeof(build_id)) {
70 if (errno == ENOENT)
71 return false;
72
73 pr_warning("Problems with %s file, consider removing it from the cache\n",
74 filename);
75 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) {
76 pr_warning("Problems with %s file, consider removing it from the cache\n",
77 filename);
78 }
79
80 return true;
81}
82
83static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
84{
85 struct perf_session *session = perf_session__new(filename, O_RDONLY,
86 force, false, NULL);
87 if (session == NULL)
88 return -1;
89
90 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
91 perf_session__delete(session);
92
93 return 0;
94}
95
96static int build_id_cache__update_file(const char *filename,
97 const char *debugdir)
98{
99 u8 build_id[BUILD_ID_SIZE];
100 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
101
102 int err;
103
104 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
105 pr_debug("Couldn't read a build-id in %s\n", filename);
106 return -1;
107 }
108
109 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
110 err = build_id_cache__remove_s(sbuild_id, debugdir);
111 if (!err) {
112 err = build_id_cache__add_s(sbuild_id, debugdir, filename,
113 false, false);
114 }
115 if (verbose)
116 pr_info("Updating %s %s: %s\n", sbuild_id, filename,
117 err ? "FAIL" : "Ok");
118
119 return err;
120}
121
61int cmd_buildid_cache(int argc, const char **argv, 122int cmd_buildid_cache(int argc, const char **argv,
62 const char *prefix __maybe_unused) 123 const char *prefix __maybe_unused)
63{ 124{
64 struct strlist *list; 125 struct strlist *list;
65 struct str_node *pos; 126 struct str_node *pos;
127 int ret = 0;
128 bool force = false;
66 char debugdir[PATH_MAX]; 129 char debugdir[PATH_MAX];
67 char const *add_name_list_str = NULL, 130 char const *add_name_list_str = NULL,
68 *remove_name_list_str = NULL; 131 *remove_name_list_str = NULL,
132 *missing_filename = NULL,
133 *update_name_list_str = NULL;
134
69 const struct option buildid_cache_options[] = { 135 const struct option buildid_cache_options[] = {
70 OPT_STRING('a', "add", &add_name_list_str, 136 OPT_STRING('a', "add", &add_name_list_str,
71 "file list", "file(s) to add"), 137 "file list", "file(s) to add"),
72 OPT_STRING('r', "remove", &remove_name_list_str, "file list", 138 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
73 "file(s) to remove"), 139 "file(s) to remove"),
140 OPT_STRING('M', "missing", &missing_filename, "file",
141 "to find missing build ids in the cache"),
142 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
143 OPT_STRING('u', "update", &update_name_list_str, "file list",
144 "file(s) to update"),
74 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 145 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
75 OPT_END() 146 OPT_END()
76 }; 147 };
@@ -125,5 +196,26 @@ int cmd_buildid_cache(int argc, const char **argv,
125 } 196 }
126 } 197 }
127 198
128 return 0; 199 if (missing_filename)
200 ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
201
202 if (update_name_list_str) {
203 list = strlist__new(true, update_name_list_str);
204 if (list) {
205 strlist__for_each(pos, list)
206 if (build_id_cache__update_file(pos->s, debugdir)) {
207 if (errno == ENOENT) {
208 pr_debug("%s wasn't in the cache\n",
209 pos->s);
210 continue;
211 }
212 pr_warning("Couldn't update %s: %s\n",
213 pos->s, strerror(errno));
214 }
215
216 strlist__delete(list);
217 }
218 }
219
220 return ret;
129} 221}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index a82d99fec83e..e74366a13218 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -44,23 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
44 return fprintf(fp, "%s\n", sbuild_id); 44 return fprintf(fp, "%s\n", sbuild_id);
45} 45}
46 46
47static bool dso__skip_buildid(struct dso *dso, int with_hits)
48{
49 return with_hits && !dso->hit;
50}
51
47static int perf_session__list_build_ids(bool force, bool with_hits) 52static int perf_session__list_build_ids(bool force, bool with_hits)
48{ 53{
49 struct perf_session *session; 54 struct perf_session *session;
50 55
51 symbol__elf_init(); 56 symbol__elf_init();
52
53 session = perf_session__new(input_name, O_RDONLY, force, false,
54 &build_id__mark_dso_hit_ops);
55 if (session == NULL)
56 return -1;
57
58 /* 57 /*
59 * See if this is an ELF file first: 58 * See if this is an ELF file first:
60 */ 59 */
61 if (filename__fprintf_build_id(session->filename, stdout)) 60 if (filename__fprintf_build_id(input_name, stdout))
62 goto out; 61 goto out;
63 62
63 session = perf_session__new(input_name, O_RDONLY, force, false,
64 &build_id__mark_dso_hit_ops);
65 if (session == NULL)
66 return -1;
64 /* 67 /*
65 * in pipe-mode, the only way to get the buildids is to parse 68 * in pipe-mode, the only way to get the buildids is to parse
66 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 69 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
@@ -68,9 +71,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
68 if (with_hits || session->fd_pipe) 71 if (with_hits || session->fd_pipe)
69 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 72 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
70 73
71 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 74 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
72out:
73 perf_session__delete(session); 75 perf_session__delete(session);
76out:
74 return 0; 77 return 0;
75} 78}
76 79
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 93b852f8a5d5..d207a97a2db1 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old",
23 *input_new = "perf.data"; 23 *input_new = "perf.data";
24static char diff__default_sort_order[] = "dso,symbol"; 24static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 25static bool force;
26static bool show_displacement;
27static bool show_period; 26static bool show_period;
28static bool show_formula; 27static bool show_formula;
29static bool show_baseline_only; 28static bool show_baseline_only;
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str,
146 return -EINVAL; 145 return -EINVAL;
147} 146}
148 147
149static double get_period_percent(struct hist_entry *he, u64 period) 148double perf_diff__period_percent(struct hist_entry *he, u64 period)
150{ 149{
151 u64 total = he->hists->stats.total_period; 150 u64 total = he->hists->stats.total_period;
152 return (period * 100.0) / total; 151 return (period * 100.0) / total;
153} 152}
154 153
155double perf_diff__compute_delta(struct hist_entry *he) 154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
156{ 155{
157 struct hist_entry *pair = hist_entry__next_pair(he); 156 double new_percent = perf_diff__period_percent(he, he->stat.period);
158 double new_percent = get_period_percent(he, he->stat.period); 157 double old_percent = perf_diff__period_percent(pair, pair->stat.period);
159 double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
160 158
161 he->diff.period_ratio_delta = new_percent - old_percent; 159 he->diff.period_ratio_delta = new_percent - old_percent;
162 he->diff.computed = true; 160 he->diff.computed = true;
163 return he->diff.period_ratio_delta; 161 return he->diff.period_ratio_delta;
164} 162}
165 163
166double perf_diff__compute_ratio(struct hist_entry *he) 164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
167{ 165{
168 struct hist_entry *pair = hist_entry__next_pair(he);
169 double new_period = he->stat.period; 166 double new_period = he->stat.period;
170 double old_period = pair ? pair->stat.period : 0; 167 double old_period = pair->stat.period;
171 168
172 he->diff.computed = true; 169 he->diff.computed = true;
173 he->diff.period_ratio = pair ? (new_period / old_period) : 0; 170 he->diff.period_ratio = new_period / old_period;
174 return he->diff.period_ratio; 171 return he->diff.period_ratio;
175} 172}
176 173
177s64 perf_diff__compute_wdiff(struct hist_entry *he) 174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
178{ 175{
179 struct hist_entry *pair = hist_entry__next_pair(he);
180 u64 new_period = he->stat.period; 176 u64 new_period = he->stat.period;
181 u64 old_period = pair ? pair->stat.period : 0; 177 u64 old_period = pair->stat.period;
182 178
183 he->diff.computed = true; 179 he->diff.computed = true;
184 180 he->diff.wdiff = new_period * compute_wdiff_w2 -
185 if (!pair) 181 old_period * compute_wdiff_w1;
186 he->diff.wdiff = 0;
187 else
188 he->diff.wdiff = new_period * compute_wdiff_w2 -
189 old_period * compute_wdiff_w1;
190 182
191 return he->diff.wdiff; 183 return he->diff.wdiff;
192} 184}
193 185
194static int formula_delta(struct hist_entry *he, char *buf, size_t size) 186static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
187 char *buf, size_t size)
195{ 188{
196 struct hist_entry *pair = hist_entry__next_pair(he);
197
198 if (!pair)
199 return -1;
200
201 return scnprintf(buf, size, 189 return scnprintf(buf, size,
202 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 190 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
203 "(%" PRIu64 " * 100 / %" PRIu64 ")", 191 "(%" PRIu64 " * 100 / %" PRIu64 ")",
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size)
205 pair->stat.period, pair->hists->stats.total_period); 193 pair->stat.period, pair->hists->stats.total_period);
206} 194}
207 195
208static int formula_ratio(struct hist_entry *he, char *buf, size_t size) 196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size)
209{ 198{
210 struct hist_entry *pair = hist_entry__next_pair(he);
211 double new_period = he->stat.period; 199 double new_period = he->stat.period;
212 double old_period = pair ? pair->stat.period : 0; 200 double old_period = pair->stat.period;
213
214 if (!pair)
215 return -1;
216 201
217 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); 202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
218} 203}
219 204
220static int formula_wdiff(struct hist_entry *he, char *buf, size_t size) 205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size)
221{ 207{
222 struct hist_entry *pair = hist_entry__next_pair(he);
223 u64 new_period = he->stat.period; 208 u64 new_period = he->stat.period;
224 u64 old_period = pair ? pair->stat.period : 0; 209 u64 old_period = pair->stat.period;
225
226 if (!pair)
227 return -1;
228 210
229 return scnprintf(buf, size, 211 return scnprintf(buf, size,
230 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", 212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
231 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); 213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
232} 214}
233 215
234int perf_diff__formula(char *buf, size_t size, struct hist_entry *he) 216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size)
235{ 218{
236 switch (compute) { 219 switch (compute) {
237 case COMPUTE_DELTA: 220 case COMPUTE_DELTA:
238 return formula_delta(he, buf, size); 221 return formula_delta(he, pair, buf, size);
239 case COMPUTE_RATIO: 222 case COMPUTE_RATIO:
240 return formula_ratio(he, buf, size); 223 return formula_ratio(he, pair, buf, size);
241 case COMPUTE_WEIGHTED_DIFF: 224 case COMPUTE_WEIGHTED_DIFF:
242 return formula_wdiff(he, buf, size); 225 return formula_wdiff(he, pair, buf, size);
243 default: 226 default:
244 BUG_ON(1); 227 BUG_ON(1);
245 } 228 }
@@ -292,48 +275,6 @@ static struct perf_tool tool = {
292 .ordering_requires_timestamps = true, 275 .ordering_requires_timestamps = true,
293}; 276};
294 277
295static void insert_hist_entry_by_name(struct rb_root *root,
296 struct hist_entry *he)
297{
298 struct rb_node **p = &root->rb_node;
299 struct rb_node *parent = NULL;
300 struct hist_entry *iter;
301
302 while (*p != NULL) {
303 parent = *p;
304 iter = rb_entry(parent, struct hist_entry, rb_node);
305 if (hist_entry__cmp(he, iter) < 0)
306 p = &(*p)->rb_left;
307 else
308 p = &(*p)->rb_right;
309 }
310
311 rb_link_node(&he->rb_node, parent, p);
312 rb_insert_color(&he->rb_node, root);
313}
314
315static void hists__name_resort(struct hists *self, bool sort)
316{
317 unsigned long position = 1;
318 struct rb_root tmp = RB_ROOT;
319 struct rb_node *next = rb_first(&self->entries);
320
321 while (next != NULL) {
322 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
323
324 next = rb_next(&n->rb_node);
325 n->position = position++;
326
327 if (sort) {
328 rb_erase(&n->rb_node, &self->entries);
329 insert_hist_entry_by_name(&tmp, n);
330 }
331 }
332
333 if (sort)
334 self->entries = tmp;
335}
336
337static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 278static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
338 struct perf_evlist *evlist) 279 struct perf_evlist *evlist)
339{ 280{
@@ -346,34 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
346 return NULL; 287 return NULL;
347} 288}
348 289
349static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) 290static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
350{ 291{
351 struct perf_evsel *evsel; 292 struct perf_evsel *evsel;
352 293
353 list_for_each_entry(evsel, &evlist->entries, node) { 294 list_for_each_entry(evsel, &evlist->entries, node) {
354 struct hists *hists = &evsel->hists; 295 struct hists *hists = &evsel->hists;
355 296
356 hists__output_resort(hists); 297 hists__collapse_resort(hists);
357
358 /*
359 * The hists__name_resort only sets possition
360 * if name is false.
361 */
362 if (name || ((!name) && show_displacement))
363 hists__name_resort(hists, name);
364 } 298 }
365} 299}
366 300
367static void hists__baseline_only(struct hists *hists) 301static void hists__baseline_only(struct hists *hists)
368{ 302{
369 struct rb_node *next = rb_first(&hists->entries); 303 struct rb_root *root;
304 struct rb_node *next;
370 305
306 if (sort__need_collapse)
307 root = &hists->entries_collapsed;
308 else
309 root = hists->entries_in;
310
311 next = rb_first(root);
371 while (next != NULL) { 312 while (next != NULL) {
372 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);
373 314
374 next = rb_next(&he->rb_node); 315 next = rb_next(&he->rb_node_in);
375 if (!hist_entry__next_pair(he)) { 316 if (!hist_entry__next_pair(he)) {
376 rb_erase(&he->rb_node, &hists->entries); 317 rb_erase(&he->rb_node_in, root);
377 hist_entry__free(he); 318 hist_entry__free(he);
378 } 319 }
379 } 320 }
@@ -385,18 +326,21 @@ static void hists__precompute(struct hists *hists)
385 326
386 while (next != NULL) { 327 while (next != NULL) {
387 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 328 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
329 struct hist_entry *pair = hist_entry__next_pair(he);
388 330
389 next = rb_next(&he->rb_node); 331 next = rb_next(&he->rb_node);
332 if (!pair)
333 continue;
390 334
391 switch (compute) { 335 switch (compute) {
392 case COMPUTE_DELTA: 336 case COMPUTE_DELTA:
393 perf_diff__compute_delta(he); 337 perf_diff__compute_delta(he, pair);
394 break; 338 break;
395 case COMPUTE_RATIO: 339 case COMPUTE_RATIO:
396 perf_diff__compute_ratio(he); 340 perf_diff__compute_ratio(he, pair);
397 break; 341 break;
398 case COMPUTE_WEIGHTED_DIFF: 342 case COMPUTE_WEIGHTED_DIFF:
399 perf_diff__compute_wdiff(he); 343 perf_diff__compute_wdiff(he, pair);
400 break; 344 break;
401 default: 345 default:
402 BUG_ON(1); 346 BUG_ON(1);
@@ -470,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
470 414
471static void hists__compute_resort(struct hists *hists) 415static void hists__compute_resort(struct hists *hists)
472{ 416{
473 struct rb_root tmp = RB_ROOT; 417 struct rb_root *root;
474 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);
475 431
476 while (next != NULL) { 432 while (next != NULL) {
477 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node); 433 struct hist_entry *he;
478 434
479 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);
480 437
481 rb_erase(&he->rb_node, &hists->entries); 438 insert_hist_entry_by_compute(&hists->entries, he, compute);
482 insert_hist_entry_by_compute(&tmp, he, compute); 439 hists__inc_nr_entries(hists, he);
483 } 440 }
484
485 hists->entries = tmp;
486} 441}
487 442
488static void hists__process(struct hists *old, struct hists *new) 443static void hists__process(struct hists *old, struct hists *new)
@@ -497,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new)
497 if (sort_compute) { 452 if (sort_compute) {
498 hists__precompute(new); 453 hists__precompute(new);
499 hists__compute_resort(new); 454 hists__compute_resort(new);
455 } else {
456 hists__output_resort(new);
500 } 457 }
501 458
502 hists__fprintf(new, true, 0, 0, stdout); 459 hists__fprintf(new, true, 0, 0, stdout);
@@ -528,8 +485,8 @@ static int __cmd_diff(void)
528 evlist_old = older->evlist; 485 evlist_old = older->evlist;
529 evlist_new = newer->evlist; 486 evlist_new = newer->evlist;
530 487
531 perf_evlist__resort_hists(evlist_old, true); 488 perf_evlist__collapse_resort(evlist_old);
532 perf_evlist__resort_hists(evlist_new, false); 489 perf_evlist__collapse_resort(evlist_new);
533 490
534 list_for_each_entry(evsel, &evlist_new->entries, node) { 491 list_for_each_entry(evsel, &evlist_new->entries, node) {
535 struct perf_evsel *evsel_old; 492 struct perf_evsel *evsel_old;
@@ -562,8 +519,6 @@ static const char * const diff_usage[] = {
562static const struct option options[] = { 519static const struct option options[] = {
563 OPT_INCR('v', "verbose", &verbose, 520 OPT_INCR('v', "verbose", &verbose,
564 "be more verbose (show symbol address, etc)"), 521 "be more verbose (show symbol address, etc)"),
565 OPT_BOOLEAN('M', "displacement", &show_displacement,
566 "Show position displacement relative to baseline"),
567 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only, 522 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
568 "Show only items with match in baseline"), 523 "Show only items with match in baseline"),
569 OPT_CALLBACK('c', "compute", &compute, 524 OPT_CALLBACK('c', "compute", &compute,
@@ -597,40 +552,32 @@ static const struct option options[] = {
597 552
598static void ui_init(void) 553static void ui_init(void)
599{ 554{
600 perf_hpp__init();
601
602 /* No overhead column. */
603 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
604
605 /* 555 /*
606 * Display baseline/delta/ratio/displacement/ 556 * Display baseline/delta/ratio
607 * formula/periods columns. 557 * formula/periods columns.
608 */ 558 */
609 perf_hpp__column_enable(PERF_HPP__BASELINE, true); 559 perf_hpp__column_enable(PERF_HPP__BASELINE);
610 560
611 switch (compute) { 561 switch (compute) {
612 case COMPUTE_DELTA: 562 case COMPUTE_DELTA:
613 perf_hpp__column_enable(PERF_HPP__DELTA, true); 563 perf_hpp__column_enable(PERF_HPP__DELTA);
614 break; 564 break;
615 case COMPUTE_RATIO: 565 case COMPUTE_RATIO:
616 perf_hpp__column_enable(PERF_HPP__RATIO, true); 566 perf_hpp__column_enable(PERF_HPP__RATIO);
617 break; 567 break;
618 case COMPUTE_WEIGHTED_DIFF: 568 case COMPUTE_WEIGHTED_DIFF:
619 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true); 569 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
620 break; 570 break;
621 default: 571 default:
622 BUG_ON(1); 572 BUG_ON(1);
623 }; 573 };
624 574
625 if (show_displacement)
626 perf_hpp__column_enable(PERF_HPP__DISPL, true);
627
628 if (show_formula) 575 if (show_formula)
629 perf_hpp__column_enable(PERF_HPP__FORMULA, true); 576 perf_hpp__column_enable(PERF_HPP__FORMULA);
630 577
631 if (show_period) { 578 if (show_period) {
632 perf_hpp__column_enable(PERF_HPP__PERIOD, true); 579 perf_hpp__column_enable(PERF_HPP__PERIOD);
633 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true); 580 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
634 } 581 }
635} 582}
636 583
@@ -658,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
658 605
659 ui_init(); 606 ui_init();
660 607
661 setup_sorting(diff_usage, options); 608 if (setup_sorting() < 0)
609 usage_with_options(diff_usage, options);
610
662 setup_pager(); 611 setup_pager();
663 612
664 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); 613 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index c20f1dcfb7e2..05bd9dfe875c 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,39 +15,6 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18struct perf_attr_details {
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48
49#define if_print(field) __if_print(&first, #field, pos->attr.field)
50
51static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 18static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
52{ 19{
53 struct perf_session *session; 20 struct perf_session *session;
@@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
57 if (session == NULL) 24 if (session == NULL)
58 return -ENOMEM; 25 return -ENOMEM;
59 26
60 list_for_each_entry(pos, &session->evlist->entries, node) { 27 list_for_each_entry(pos, &session->evlist->entries, node)
61 bool first = true; 28 perf_evsel__fprintf(pos, details, stdout);
62
63 printf("%s", perf_evsel__name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
106 29
107 perf_session__delete(session); 30 perf_session__delete(session);
108 return 0; 31 return 0;
@@ -116,6 +39,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
116 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), 39 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
117 OPT_BOOLEAN('v', "verbose", &details.verbose, 40 OPT_BOOLEAN('v', "verbose", &details.verbose,
118 "Show all event attr details"), 41 "Show all event attr details"),
42 OPT_BOOLEAN('g', "group", &details.event_group,
43 "Show event group information"),
119 OPT_END() 44 OPT_END()
120 }; 45 };
121 const char * const evlist_usage[] = { 46 const char * const evlist_usage[] = {
@@ -127,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
127 if (argc) 52 if (argc)
128 usage_with_options(evlist_usage, options); 53 usage_with_options(evlist_usage, options);
129 54
55 if (details.event_group && (details.verbose || details.freq)) {
56 pr_err("--group option is not compatible with other options\n");
57 usage_with_options(evlist_usage, options);
58 }
59
130 return __cmd_evlist(input_name, &details); 60 return __cmd_evlist(input_name, &details);
131} 61}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0b4b796167be..46878daca5cc 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -17,6 +17,7 @@
17#include "util/debug.h" 17#include "util/debug.h"
18 18
19#include <linux/rbtree.h> 19#include <linux/rbtree.h>
20#include <linux/string.h>
20 21
21struct alloc_stat; 22struct alloc_stat;
22typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 23typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -340,7 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
340 int n_lines, int is_caller) 341 int n_lines, int is_caller)
341{ 342{
342 struct rb_node *next; 343 struct rb_node *next;
343 struct machine *machine; 344 struct machine *machine = &session->machines.host;
344 345
345 printf("%.102s\n", graph_dotted_line); 346 printf("%.102s\n", graph_dotted_line);
346 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 347 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
349 350
350 next = rb_first(root); 351 next = rb_first(root);
351 352
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--) { 353 while (next && n_lines--) {
358 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 354 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
359 node); 355 node);
@@ -614,8 +610,7 @@ static struct sort_dimension *avail_sorts[] = {
614 &pingpong_sort_dimension, 610 &pingpong_sort_dimension,
615}; 611};
616 612
617#define NUM_AVAIL_SORTS \ 613#define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts))
618 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
619 614
620static int sort_dimension__add(const char *tok, struct list_head *list) 615static int sort_dimension__add(const char *tok, struct list_head *list)
621{ 616{
@@ -624,12 +619,11 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
624 619
625 for (i = 0; i < NUM_AVAIL_SORTS; i++) { 620 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
626 if (!strcmp(avail_sorts[i]->name, tok)) { 621 if (!strcmp(avail_sorts[i]->name, tok)) {
627 sort = malloc(sizeof(*sort)); 622 sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i]));
628 if (!sort) { 623 if (!sort) {
629 pr_err("%s: malloc failed\n", __func__); 624 pr_err("%s: memdup failed\n", __func__);
630 return -1; 625 return -1;
631 } 626 }
632 memcpy(sort, avail_sorts[i], sizeof(*sort));
633 list_add_tail(&sort->list, list); 627 list_add_tail(&sort->list, list);
634 return 0; 628 return 0;
635 } 629 }
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 f3151d3c70ce..774c90713a53 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -224,130 +224,28 @@ 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;
230 struct perf_record_opts *opts = &rec->opts; 231 struct perf_record_opts *opts = &rec->opts;
231 int rc = 0; 232 int rc = 0;
232 233
233 /* 234 perf_evlist__config(evlist, opts);
234 * Set the evsel leader links before we configure attributes,
235 * since some might depend on this info.
236 */
237 if (opts->group)
238 perf_evlist__set_leader(evlist);
239
240 perf_evlist__config_attrs(evlist, opts);
241 235
242 list_for_each_entry(pos, &evlist->entries, node) { 236 list_for_each_entry(pos, &evlist->entries, node) {
243 struct perf_event_attr *attr = &pos->attr;
244 /*
245 * Check if parse_single_tracepoint_event has already asked for
246 * PERF_SAMPLE_TIME.
247 *
248 * XXX this is kludgy but short term fix for problems introduced by
249 * eac23d1c that broke 'perf script' by having different sample_types
250 * when using multiple tracepoint events when we use a perf binary
251 * that tries to use sample_id_all on an older kernel.
252 *
253 * We need to move counter creation to perf_session, support
254 * different sample_types, etc.
255 */
256 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
257
258fallback_missing_features:
259 if (opts->exclude_guest_missing)
260 attr->exclude_guest = attr->exclude_host = 0;
261retry_sample_id:
262 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
263try_again: 237try_again:
264 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 238 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
265 int err = errno; 239 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
266
267 if (err == EPERM || err == EACCES) {
268 ui__error_paranoid();
269 rc = -err;
270 goto out;
271 } else if (err == ENODEV && opts->target.cpu_list) {
272 pr_err("No such device - did you specify"
273 " an out-of-range profile CPU?\n");
274 rc = -err;
275 goto out;
276 } else if (err == EINVAL) {
277 if (!opts->exclude_guest_missing &&
278 (attr->exclude_guest || attr->exclude_host)) {
279 pr_debug("Old kernel, cannot exclude "
280 "guest or host samples.\n");
281 opts->exclude_guest_missing = true;
282 goto fallback_missing_features;
283 } else if (!opts->sample_id_all_missing) {
284 /*
285 * Old kernel, no attr->sample_id_type_all field
286 */
287 opts->sample_id_all_missing = true;
288 if (!opts->sample_time && !opts->raw_samples && !time_needed)
289 attr->sample_type &= ~PERF_SAMPLE_TIME;
290
291 goto retry_sample_id;
292 }
293 }
294
295 /*
296 * If it's cycles then fall back to hrtimer
297 * based cpu-clock-tick sw counter, which
298 * is always available even if no PMU support.
299 *
300 * PPC returns ENXIO until 2.6.37 (behavior changed
301 * with commit b0a873e).
302 */
303 if ((err == ENOENT || err == ENXIO)
304 && attr->type == PERF_TYPE_HARDWARE
305 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
306
307 if (verbose) 240 if (verbose)
308 ui__warning("The cycles event is not supported, " 241 ui__warning("%s\n", msg);
309 "trying to fall back to cpu-clock-ticks\n");
310 attr->type = PERF_TYPE_SOFTWARE;
311 attr->config = PERF_COUNT_SW_CPU_CLOCK;
312 if (pos->name) {
313 free(pos->name);
314 pos->name = NULL;
315 }
316 goto try_again; 242 goto try_again;
317 } 243 }
318 244
319 if (err == ENOENT) { 245 rc = -errno;
320 ui__error("The %s event is not supported.\n", 246 perf_evsel__open_strerror(pos, &opts->target,
321 perf_evsel__name(pos)); 247 errno, msg, sizeof(msg));
322 rc = -err; 248 ui__error("%s\n", msg);
323 goto out;
324 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
325 ui__error("\'precise\' request may not be supported. "
326 "Try removing 'p' modifier\n");
327 rc = -err;
328 goto out;
329 }
330
331 printf("\n");
332 error("sys_perf_event_open() syscall returned with %d "
333 "(%s) for event %s. /bin/dmesg may provide "
334 "additional information.\n",
335 err, strerror(err), perf_evsel__name(pos));
336
337#if defined(__i386__) || defined(__x86_64__)
338 if (attr->type == PERF_TYPE_HARDWARE &&
339 err == EOPNOTSUPP) {
340 pr_err("No hardware sampling interrupt available."
341 " No APIC? If so then you can boot the kernel"
342 " with the \"lapic\" boot parameter to"
343 " force-enable it.\n");
344 rc = -err;
345 goto out;
346 }
347#endif
348
349 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
350 rc = -err;
351 goto out; 249 goto out;
352 } 250 }
353 } 251 }
@@ -430,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
430{ 328{
431 int err; 329 int err;
432 struct perf_tool *tool = data; 330 struct perf_tool *tool = data;
433
434 if (machine__is_host(machine))
435 return;
436
437 /* 331 /*
438 *As for guest kernel when processing subcommand record&report, 332 *As for guest kernel when processing subcommand record&report,
439 *we arrange module mmap prior to guest kernel mmap and trigger 333 *we arrange module mmap prior to guest kernel mmap and trigger
@@ -592,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
592 goto out_delete_session; 486 goto out_delete_session;
593 } 487 }
594 488
489 if (!evsel_list->nr_groups)
490 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
491
595 /* 492 /*
596 * perf_session__delete(session) will be called at perf_record__exit() 493 * perf_session__delete(session) will be called at perf_record__exit()
597 */ 494 */
@@ -618,12 +515,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
618 515
619 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 516 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
620 517
621 machine = perf_session__find_host_machine(session); 518 machine = &session->machines.host;
622 if (!machine) {
623 pr_err("Couldn't find native kernel information.\n");
624 err = -1;
625 goto out_delete_session;
626 }
627 519
628 if (opts->pipe_output) { 520 if (opts->pipe_output) {
629 err = perf_event__synthesize_attrs(tool, session, 521 err = perf_event__synthesize_attrs(tool, session,
@@ -676,9 +568,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
676 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 568 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
677 "Check /proc/modules permission or run as root.\n"); 569 "Check /proc/modules permission or run as root.\n");
678 570
679 if (perf_guest) 571 if (perf_guest) {
680 perf_session__process_machines(session, tool, 572 machines__process_guests(&session->machines,
681 perf_event__synthesize_guest_os); 573 perf_event__synthesize_guest_os, tool);
574 }
682 575
683 if (!opts->target.system_wide) 576 if (!opts->target.system_wide)
684 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 577 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
@@ -875,11 +768,10 @@ static int get_stack_size(char *str, unsigned long *_size)
875} 768}
876#endif /* LIBUNWIND_SUPPORT */ 769#endif /* LIBUNWIND_SUPPORT */
877 770
878static int 771int record_parse_callchain_opt(const struct option *opt,
879parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, 772 const char *arg, int unset)
880 int unset)
881{ 773{
882 struct perf_record *rec = (struct perf_record *)opt->value; 774 struct perf_record_opts *opts = opt->value;
883 char *tok, *name, *saveptr = NULL; 775 char *tok, *name, *saveptr = NULL;
884 char *buf; 776 char *buf;
885 int ret = -1; 777 int ret = -1;
@@ -905,7 +797,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
905 /* Framepointer style */ 797 /* Framepointer style */
906 if (!strncmp(name, "fp", sizeof("fp"))) { 798 if (!strncmp(name, "fp", sizeof("fp"))) {
907 if (!strtok_r(NULL, ",", &saveptr)) { 799 if (!strtok_r(NULL, ",", &saveptr)) {
908 rec->opts.call_graph = CALLCHAIN_FP; 800 opts->call_graph = CALLCHAIN_FP;
909 ret = 0; 801 ret = 0;
910 } else 802 } else
911 pr_err("callchain: No more arguments " 803 pr_err("callchain: No more arguments "
@@ -918,20 +810,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
918 const unsigned long default_stack_dump_size = 8192; 810 const unsigned long default_stack_dump_size = 8192;
919 811
920 ret = 0; 812 ret = 0;
921 rec->opts.call_graph = CALLCHAIN_DWARF; 813 opts->call_graph = CALLCHAIN_DWARF;
922 rec->opts.stack_dump_size = default_stack_dump_size; 814 opts->stack_dump_size = default_stack_dump_size;
923 815
924 tok = strtok_r(NULL, ",", &saveptr); 816 tok = strtok_r(NULL, ",", &saveptr);
925 if (tok) { 817 if (tok) {
926 unsigned long size = 0; 818 unsigned long size = 0;
927 819
928 ret = get_stack_size(tok, &size); 820 ret = get_stack_size(tok, &size);
929 rec->opts.stack_dump_size = size; 821 opts->stack_dump_size = size;
930 } 822 }
931 823
932 if (!ret) 824 if (!ret)
933 pr_debug("callchain: stack dump size %d\n", 825 pr_debug("callchain: stack dump size %d\n",
934 rec->opts.stack_dump_size); 826 opts->stack_dump_size);
935#endif /* LIBUNWIND_SUPPORT */ 827#endif /* LIBUNWIND_SUPPORT */
936 } else { 828 } else {
937 pr_err("callchain: Unknown -g option " 829 pr_err("callchain: Unknown -g option "
@@ -944,7 +836,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
944 free(buf); 836 free(buf);
945 837
946 if (!ret) 838 if (!ret)
947 pr_debug("callchain: type %d\n", rec->opts.call_graph); 839 pr_debug("callchain: type %d\n", opts->call_graph);
948 840
949 return ret; 841 return ret;
950} 842}
@@ -982,9 +874,9 @@ static struct perf_record record = {
982#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 874#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
983 875
984#ifdef LIBUNWIND_SUPPORT 876#ifdef LIBUNWIND_SUPPORT
985static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 877const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
986#else 878#else
987static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; 879const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
988#endif 880#endif
989 881
990/* 882/*
@@ -1028,9 +920,9 @@ const struct option record_options[] = {
1028 "number of mmap data pages"), 920 "number of mmap data pages"),
1029 OPT_BOOLEAN(0, "group", &record.opts.group, 921 OPT_BOOLEAN(0, "group", &record.opts.group,
1030 "put the counters into a counter group"), 922 "put the counters into a counter group"),
1031 OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", 923 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
1032 callchain_help, &parse_callchain_opt, 924 "mode[,dump_size]", record_callchain_help,
1033 "fp"), 925 &record_parse_callchain_opt, "fp"),
1034 OPT_INCR('v', "verbose", &verbose, 926 OPT_INCR('v', "verbose", &verbose,
1035 "be more verbose (show counter open errors, etc)"), 927 "be more verbose (show counter open errors, etc)"),
1036 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 928 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index fc251005dd3d..96b5a7fee4bb 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -8,6 +8,7 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "util/util.h" 10#include "util/util.h"
11#include "util/cache.h"
11 12
12#include "util/annotate.h" 13#include "util/annotate.h"
13#include "util/color.h" 14#include "util/color.h"
@@ -54,6 +55,16 @@ struct perf_report {
54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 55 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
55}; 56};
56 57
58static int perf_report_config(const char *var, const char *value, void *cb)
59{
60 if (!strcmp(var, "report.group")) {
61 symbol_conf.event_group = perf_config_bool(var, value);
62 return 0;
63 }
64
65 return perf_default_config(var, value, cb);
66}
67
57static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 68static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
58 struct addr_location *al, 69 struct addr_location *al,
59 struct perf_sample *sample, 70 struct perf_sample *sample,
@@ -299,6 +310,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
299 char unit; 310 char unit;
300 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 311 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
301 u64 nr_events = self->stats.total_period; 312 u64 nr_events = self->stats.total_period;
313 struct perf_evsel *evsel = hists_to_evsel(self);
314 char buf[512];
315 size_t size = sizeof(buf);
316
317 if (symbol_conf.event_group && evsel->nr_members > 1) {
318 struct perf_evsel *pos;
319
320 perf_evsel__group_desc(evsel, buf, size);
321 evname = buf;
322
323 for_each_group_member(pos, evsel) {
324 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
325 nr_events += pos->hists.stats.total_period;
326 }
327 }
302 328
303 nr_samples = convert_unit(nr_samples, &unit); 329 nr_samples = convert_unit(nr_samples, &unit);
304 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); 330 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
@@ -319,6 +345,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
319 struct hists *hists = &pos->hists; 345 struct hists *hists = &pos->hists;
320 const char *evname = perf_evsel__name(pos); 346 const char *evname = perf_evsel__name(pos);
321 347
348 if (symbol_conf.event_group &&
349 !perf_evsel__is_group_leader(pos))
350 continue;
351
322 hists__fprintf_nr_sample_events(hists, evname, stdout); 352 hists__fprintf_nr_sample_events(hists, evname, stdout);
323 hists__fprintf(hists, true, 0, 0, stdout); 353 hists__fprintf(hists, true, 0, 0, stdout);
324 fprintf(stdout, "\n\n"); 354 fprintf(stdout, "\n\n");
@@ -372,7 +402,7 @@ static int __cmd_report(struct perf_report *rep)
372 if (ret) 402 if (ret)
373 goto out_delete; 403 goto out_delete;
374 404
375 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; 405 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
376 kernel_kmap = map__kmap(kernel_map); 406 kernel_kmap = map__kmap(kernel_map);
377 if (kernel_map == NULL || 407 if (kernel_map == NULL ||
378 (kernel_map->dso->hit && 408 (kernel_map->dso->hit &&
@@ -416,8 +446,16 @@ static int __cmd_report(struct perf_report *rep)
416 hists->symbol_filter_str = rep->symbol_filter_str; 446 hists->symbol_filter_str = rep->symbol_filter_str;
417 447
418 hists__collapse_resort(hists); 448 hists__collapse_resort(hists);
419 hists__output_resort(hists);
420 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 449 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
450
451 /* Non-group events are considered as leader */
452 if (symbol_conf.event_group &&
453 !perf_evsel__is_group_leader(pos)) {
454 struct hists *leader_hists = &pos->leader->hists;
455
456 hists__match(leader_hists, hists);
457 hists__link(leader_hists, hists);
458 }
421 } 459 }
422 460
423 if (nr_samples == 0) { 461 if (nr_samples == 0) {
@@ -425,11 +463,22 @@ static int __cmd_report(struct perf_report *rep)
425 goto out_delete; 463 goto out_delete;
426 } 464 }
427 465
466 list_for_each_entry(pos, &session->evlist->entries, node)
467 hists__output_resort(&pos->hists);
468
428 if (use_browser > 0) { 469 if (use_browser > 0) {
429 if (use_browser == 1) { 470 if (use_browser == 1) {
430 perf_evlist__tui_browse_hists(session->evlist, help, 471 ret = perf_evlist__tui_browse_hists(session->evlist,
431 NULL, 472 help,
432 &session->header.env); 473 NULL,
474 &session->header.env);
475 /*
476 * Usually "ret" is the last pressed key, and we only
477 * care if the key notifies us to switch data file.
478 */
479 if (ret != K_SWITCH_INPUT_DATA)
480 ret = 0;
481
433 } else if (use_browser == 2) { 482 } else if (use_browser == 2) {
434 perf_evlist__gtk_browse_hists(session->evlist, help, 483 perf_evlist__gtk_browse_hists(session->evlist, help,
435 NULL); 484 NULL);
@@ -595,8 +644,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
595 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 644 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
596 "Use the stdio interface"), 645 "Use the stdio interface"),
597 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 646 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
598 "sort by key(s): pid, comm, dso, symbol, parent, dso_to," 647 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
599 " dso_from, symbol_to, symbol_from, mispredict"), 648 " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
600 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 649 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
601 "Show sample percentage for different cpu modes"), 650 "Show sample percentage for different cpu modes"),
602 OPT_STRING('p', "parent", &parent_pattern, "regex", 651 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -638,6 +687,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
638 "Specify disassembler style (e.g. -M intel for intel syntax)"), 687 "Specify disassembler style (e.g. -M intel for intel syntax)"),
639 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 688 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
640 "Show a column with the sum of periods"), 689 "Show a column with the sum of periods"),
690 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
691 "Show event group information together"),
641 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", 692 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
642 "use branch records for histogram filling", parse_branch_mode), 693 "use branch records for histogram filling", parse_branch_mode),
643 OPT_STRING(0, "objdump", &objdump_path, "path", 694 OPT_STRING(0, "objdump", &objdump_path, "path",
@@ -645,6 +696,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
645 OPT_END() 696 OPT_END()
646 }; 697 };
647 698
699 perf_config(perf_report_config, NULL);
700
648 argc = parse_options(argc, argv, options, report_usage, 0); 701 argc = parse_options(argc, argv, options, report_usage, 0);
649 702
650 if (report.use_stdio) 703 if (report.use_stdio)
@@ -663,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
663 else 716 else
664 input_name = "perf.data"; 717 input_name = "perf.data";
665 } 718 }
719
720 if (strcmp(input_name, "-") != 0)
721 setup_browser(true);
722 else {
723 use_browser = 0;
724 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
725 perf_hpp__init();
726 }
727
728repeat:
666 session = perf_session__new(input_name, O_RDONLY, 729 session = perf_session__new(input_name, O_RDONLY,
667 report.force, false, &report.tool); 730 report.force, false, &report.tool);
668 if (session == NULL) 731 if (session == NULL)
@@ -688,14 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
688 751
689 } 752 }
690 753
691 if (strcmp(input_name, "-") != 0) 754 if (setup_sorting() < 0)
692 setup_browser(true); 755 usage_with_options(report_usage, options);
693 else {
694 use_browser = 0;
695 perf_hpp__init();
696 }
697
698 setup_sorting(report_usage, options);
699 756
700 /* 757 /*
701 * Only in the newt browser we are doing integrated annotation, 758 * Only in the newt browser we are doing integrated annotation,
@@ -763,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
763 } 820 }
764 821
765 ret = __cmd_report(&report); 822 ret = __cmd_report(&report);
823 if (ret == K_SWITCH_INPUT_DATA) {
824 perf_session__delete(session);
825 goto repeat;
826 } else
827 ret = 0;
828
766error: 829error:
767 perf_session__delete(session); 830 perf_session__delete(session);
768 return ret; 831 return ret;
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 c247faca7127..99848761f573 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -65,6 +65,11 @@
65#define CNTR_NOT_SUPPORTED "<not supported>" 65#define CNTR_NOT_SUPPORTED "<not supported>"
66#define CNTR_NOT_COUNTED "<not counted>" 66#define CNTR_NOT_COUNTED "<not counted>"
67 67
68static void print_stat(int argc, const char **argv);
69static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr_socket(char *prefix);
72
68static struct perf_evlist *evsel_list; 73static struct perf_evlist *evsel_list;
69 74
70static struct perf_target target = { 75static struct perf_target target = {
@@ -75,6 +80,7 @@ static int run_count = 1;
75static bool no_inherit = false; 80static bool no_inherit = false;
76static bool scale = true; 81static bool scale = true;
77static bool no_aggr = false; 82static bool no_aggr = false;
83static bool aggr_socket = false;
78static pid_t child_pid = -1; 84static pid_t child_pid = -1;
79static bool null_run = false; 85static bool null_run = false;
80static int detailed_run = 0; 86static int detailed_run = 0;
@@ -87,6 +93,9 @@ static FILE *output = NULL;
87static const char *pre_cmd = NULL; 93static const char *pre_cmd = NULL;
88static const char *post_cmd = NULL; 94static const char *post_cmd = NULL;
89static bool sync_run = false; 95static bool sync_run = false;
96static unsigned int interval = 0;
97static struct timespec ref_time;
98static struct cpu_map *sock_map;
90 99
91static volatile int done = 0; 100static volatile int done = 0;
92 101
@@ -94,6 +103,28 @@ struct perf_stat {
94 struct stats res_stats[3]; 103 struct stats res_stats[3];
95}; 104};
96 105
106static inline void diff_timespec(struct timespec *r, struct timespec *a,
107 struct timespec *b)
108{
109 r->tv_sec = a->tv_sec - b->tv_sec;
110 if (a->tv_nsec < b->tv_nsec) {
111 r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec;
112 r->tv_sec--;
113 } else {
114 r->tv_nsec = a->tv_nsec - b->tv_nsec ;
115 }
116}
117
118static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
119{
120 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
121}
122
123static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
124{
125 return perf_evsel__cpus(evsel)->nr;
126}
127
97static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 128static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
98{ 129{
99 evsel->priv = zalloc(sizeof(struct perf_stat)); 130 evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -106,14 +137,27 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
106 evsel->priv = NULL; 137 evsel->priv = NULL;
107} 138}
108 139
109static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) 140static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
110{ 141{
111 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; 142 void *addr;
143 size_t sz;
144
145 sz = sizeof(*evsel->counts) +
146 (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
147
148 addr = zalloc(sz);
149 if (!addr)
150 return -ENOMEM;
151
152 evsel->prev_raw_counts = addr;
153
154 return 0;
112} 155}
113 156
114static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) 157static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
115{ 158{
116 return perf_evsel__cpus(evsel)->nr; 159 free(evsel->prev_raw_counts);
160 evsel->prev_raw_counts = NULL;
117} 161}
118 162
119static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 163static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
@@ -132,8 +176,6 @@ static struct stats walltime_nsecs_stats;
132static int create_perf_stat_counter(struct perf_evsel *evsel) 176static int create_perf_stat_counter(struct perf_evsel *evsel)
133{ 177{
134 struct perf_event_attr *attr = &evsel->attr; 178 struct perf_event_attr *attr = &evsel->attr;
135 bool exclude_guest_missing = false;
136 int ret;
137 179
138 if (scale) 180 if (scale)
139 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 181 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,38 +183,16 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
141 183
142 attr->inherit = !no_inherit; 184 attr->inherit = !no_inherit;
143 185
144retry: 186 if (perf_target__has_cpu(&target))
145 if (exclude_guest_missing) 187 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 188
155 if (!perf_target__has_task(&target) && 189 if (!perf_target__has_task(&target) &&
156 !perf_evsel__is_group_member(evsel)) { 190 perf_evsel__is_group_leader(evsel)) {
157 attr->disabled = 1; 191 attr->disabled = 1;
158 attr->enable_on_exec = 1; 192 attr->enable_on_exec = 1;
159 } 193 }
160 194
161 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); 195 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} 196}
177 197
178/* 198/*
@@ -269,15 +289,79 @@ static int read_counter(struct perf_evsel *counter)
269 return 0; 289 return 0;
270} 290}
271 291
292static void print_interval(void)
293{
294 static int num_print_interval;
295 struct perf_evsel *counter;
296 struct perf_stat *ps;
297 struct timespec ts, rs;
298 char prefix[64];
299
300 if (no_aggr) {
301 list_for_each_entry(counter, &evsel_list->entries, node) {
302 ps = counter->priv;
303 memset(ps->res_stats, 0, sizeof(ps->res_stats));
304 read_counter(counter);
305 }
306 } else {
307 list_for_each_entry(counter, &evsel_list->entries, node) {
308 ps = counter->priv;
309 memset(ps->res_stats, 0, sizeof(ps->res_stats));
310 read_counter_aggr(counter);
311 }
312 }
313 clock_gettime(CLOCK_MONOTONIC, &ts);
314 diff_timespec(&rs, &ts, &ref_time);
315 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
316
317 if (num_print_interval == 0 && !csv_output) {
318 if (aggr_socket)
319 fprintf(output, "# time socket cpus counts events\n");
320 else if (no_aggr)
321 fprintf(output, "# time CPU counts events\n");
322 else
323 fprintf(output, "# time counts events\n");
324 }
325
326 if (++num_print_interval == 25)
327 num_print_interval = 0;
328
329 if (aggr_socket)
330 print_aggr_socket(prefix);
331 else if (no_aggr) {
332 list_for_each_entry(counter, &evsel_list->entries, node)
333 print_counter(counter, prefix);
334 } else {
335 list_for_each_entry(counter, &evsel_list->entries, node)
336 print_counter_aggr(counter, prefix);
337 }
338}
339
272static int __run_perf_stat(int argc __maybe_unused, const char **argv) 340static int __run_perf_stat(int argc __maybe_unused, const char **argv)
273{ 341{
342 char msg[512];
274 unsigned long long t0, t1; 343 unsigned long long t0, t1;
275 struct perf_evsel *counter; 344 struct perf_evsel *counter;
345 struct timespec ts;
276 int status = 0; 346 int status = 0;
277 int child_ready_pipe[2], go_pipe[2]; 347 int child_ready_pipe[2], go_pipe[2];
278 const bool forks = (argc > 0); 348 const bool forks = (argc > 0);
279 char buf; 349 char buf;
280 350
351 if (interval) {
352 ts.tv_sec = interval / 1000;
353 ts.tv_nsec = (interval % 1000) * 1000000;
354 } else {
355 ts.tv_sec = 1;
356 ts.tv_nsec = 0;
357 }
358
359 if (aggr_socket
360 && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
361 perror("cannot build socket map");
362 return -1;
363 }
364
281 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 365 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
282 perror("failed to create pipes"); 366 perror("failed to create pipes");
283 return -1; 367 return -1;
@@ -348,20 +432,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
348 continue; 432 continue;
349 } 433 }
350 434
351 if (errno == EPERM || errno == EACCES) { 435 perf_evsel__open_strerror(counter, &target,
352 error("You may not have permission to collect %sstats.\n" 436 errno, msg, sizeof(msg));
353 "\t Consider tweaking" 437 ui__error("%s\n", msg);
354 " /proc/sys/kernel/perf_event_paranoid or running as root.", 438
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) 439 if (child_pid != -1)
362 kill(child_pid, SIGTERM); 440 kill(child_pid, SIGTERM);
363 441
364 pr_err("Not all events could be opened.\n");
365 return -1; 442 return -1;
366 } 443 }
367 counter->supported = true; 444 counter->supported = true;
@@ -377,14 +454,25 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
377 * Enable counters and exec the command: 454 * Enable counters and exec the command:
378 */ 455 */
379 t0 = rdclock(); 456 t0 = rdclock();
457 clock_gettime(CLOCK_MONOTONIC, &ref_time);
380 458
381 if (forks) { 459 if (forks) {
382 close(go_pipe[1]); 460 close(go_pipe[1]);
461 if (interval) {
462 while (!waitpid(child_pid, &status, WNOHANG)) {
463 nanosleep(&ts, NULL);
464 print_interval();
465 }
466 }
383 wait(&status); 467 wait(&status);
384 if (WIFSIGNALED(status)) 468 if (WIFSIGNALED(status))
385 psignal(WTERMSIG(status), argv[0]); 469 psignal(WTERMSIG(status), argv[0]);
386 } else { 470 } else {
387 while(!done) sleep(1); 471 while (!done) {
472 nanosleep(&ts, NULL);
473 if (interval)
474 print_interval();
475 }
388 } 476 }
389 477
390 t1 = rdclock(); 478 t1 = rdclock();
@@ -454,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg)
454 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 542 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
455} 543}
456 544
457static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) 545static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
458{ 546{
459 double msecs = avg / 1e6; 547 double msecs = avg / 1e6;
460 char cpustr[16] = { '\0', }; 548 char cpustr[16] = { '\0', };
461 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; 549 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
462 550
463 if (no_aggr) 551 if (aggr_socket)
552 sprintf(cpustr, "S%*d%s%*d%s",
553 csv_output ? 0 : -5,
554 cpu,
555 csv_sep,
556 csv_output ? 0 : 4,
557 nr,
558 csv_sep);
559 else if (no_aggr)
464 sprintf(cpustr, "CPU%*d%s", 560 sprintf(cpustr, "CPU%*d%s",
465 csv_output ? 0 : -4, 561 csv_output ? 0 : -4,
466 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 562 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -470,7 +566,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
470 if (evsel->cgrp) 566 if (evsel->cgrp)
471 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 567 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
472 568
473 if (csv_output) 569 if (csv_output || interval)
474 return; 570 return;
475 571
476 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 572 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -659,7 +755,7 @@ static void print_ll_cache_misses(int cpu,
659 fprintf(output, " of all LL-cache hits "); 755 fprintf(output, " of all LL-cache hits ");
660} 756}
661 757
662static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 758static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
663{ 759{
664 double total, ratio = 0.0; 760 double total, ratio = 0.0;
665 char cpustr[16] = { '\0', }; 761 char cpustr[16] = { '\0', };
@@ -672,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
672 else 768 else
673 fmt = "%s%18.0f%s%-25s"; 769 fmt = "%s%18.0f%s%-25s";
674 770
675 if (no_aggr) 771 if (aggr_socket)
772 sprintf(cpustr, "S%*d%s%*d%s",
773 csv_output ? 0 : -5,
774 cpu,
775 csv_sep,
776 csv_output ? 0 : 4,
777 nr,
778 csv_sep);
779 else if (no_aggr)
676 sprintf(cpustr, "CPU%*d%s", 780 sprintf(cpustr, "CPU%*d%s",
677 csv_output ? 0 : -4, 781 csv_output ? 0 : -4,
678 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 782 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -684,12 +788,11 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
684 if (evsel->cgrp) 788 if (evsel->cgrp)
685 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 789 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
686 790
687 if (csv_output) 791 if (csv_output || interval)
688 return; 792 return;
689 793
690 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 794 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
691 total = avg_stats(&runtime_cycles_stats[cpu]); 795 total = avg_stats(&runtime_cycles_stats[cpu]);
692
693 if (total) 796 if (total)
694 ratio = avg / total; 797 ratio = avg / total;
695 798
@@ -779,16 +882,83 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
779 } 882 }
780} 883}
781 884
885static void print_aggr_socket(char *prefix)
886{
887 struct perf_evsel *counter;
888 u64 ena, run, val;
889 int cpu, s, s2, sock, nr;
890
891 if (!sock_map)
892 return;
893
894 for (s = 0; s < sock_map->nr; s++) {
895 sock = cpu_map__socket(sock_map, s);
896 list_for_each_entry(counter, &evsel_list->entries, node) {
897 val = ena = run = 0;
898 nr = 0;
899 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
900 s2 = cpu_map__get_socket(evsel_list->cpus, cpu);
901 if (s2 != sock)
902 continue;
903 val += counter->counts->cpu[cpu].val;
904 ena += counter->counts->cpu[cpu].ena;
905 run += counter->counts->cpu[cpu].run;
906 nr++;
907 }
908 if (prefix)
909 fprintf(output, "%s", prefix);
910
911 if (run == 0 || ena == 0) {
912 fprintf(output, "S%*d%s%*d%s%*s%s%*s",
913 csv_output ? 0 : -5,
914 s,
915 csv_sep,
916 csv_output ? 0 : 4,
917 nr,
918 csv_sep,
919 csv_output ? 0 : 18,
920 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
921 csv_sep,
922 csv_output ? 0 : -24,
923 perf_evsel__name(counter));
924 if (counter->cgrp)
925 fprintf(output, "%s%s",
926 csv_sep, counter->cgrp->name);
927
928 fputc('\n', output);
929 continue;
930 }
931
932 if (nsec_counter(counter))
933 nsec_printout(sock, nr, counter, val);
934 else
935 abs_printout(sock, nr, counter, val);
936
937 if (!csv_output) {
938 print_noise(counter, 1.0);
939
940 if (run != ena)
941 fprintf(output, " (%.2f%%)",
942 100.0 * run / ena);
943 }
944 fputc('\n', output);
945 }
946 }
947}
948
782/* 949/*
783 * Print out the results of a single counter: 950 * Print out the results of a single counter:
784 * aggregated counts in system-wide mode 951 * aggregated counts in system-wide mode
785 */ 952 */
786static void print_counter_aggr(struct perf_evsel *counter) 953static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
787{ 954{
788 struct perf_stat *ps = counter->priv; 955 struct perf_stat *ps = counter->priv;
789 double avg = avg_stats(&ps->res_stats[0]); 956 double avg = avg_stats(&ps->res_stats[0]);
790 int scaled = counter->counts->scaled; 957 int scaled = counter->counts->scaled;
791 958
959 if (prefix)
960 fprintf(output, "%s", prefix);
961
792 if (scaled == -1) { 962 if (scaled == -1) {
793 fprintf(output, "%*s%s%*s", 963 fprintf(output, "%*s%s%*s",
794 csv_output ? 0 : 18, 964 csv_output ? 0 : 18,
@@ -805,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
805 } 975 }
806 976
807 if (nsec_counter(counter)) 977 if (nsec_counter(counter))
808 nsec_printout(-1, counter, avg); 978 nsec_printout(-1, 0, counter, avg);
809 else 979 else
810 abs_printout(-1, counter, avg); 980 abs_printout(-1, 0, counter, avg);
811 981
812 print_noise(counter, avg); 982 print_noise(counter, avg);
813 983
@@ -831,7 +1001,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
831 * Print out the results of a single counter: 1001 * Print out the results of a single counter:
832 * does not use aggregated count in system-wide 1002 * does not use aggregated count in system-wide
833 */ 1003 */
834static void print_counter(struct perf_evsel *counter) 1004static void print_counter(struct perf_evsel *counter, char *prefix)
835{ 1005{
836 u64 ena, run, val; 1006 u64 ena, run, val;
837 int cpu; 1007 int cpu;
@@ -840,6 +1010,10 @@ static void print_counter(struct perf_evsel *counter)
840 val = counter->counts->cpu[cpu].val; 1010 val = counter->counts->cpu[cpu].val;
841 ena = counter->counts->cpu[cpu].ena; 1011 ena = counter->counts->cpu[cpu].ena;
842 run = counter->counts->cpu[cpu].run; 1012 run = counter->counts->cpu[cpu].run;
1013
1014 if (prefix)
1015 fprintf(output, "%s", prefix);
1016
843 if (run == 0 || ena == 0) { 1017 if (run == 0 || ena == 0) {
844 fprintf(output, "CPU%*d%s%*s%s%*s", 1018 fprintf(output, "CPU%*d%s%*s%s%*s",
845 csv_output ? 0 : -4, 1019 csv_output ? 0 : -4,
@@ -859,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter)
859 } 1033 }
860 1034
861 if (nsec_counter(counter)) 1035 if (nsec_counter(counter))
862 nsec_printout(cpu, counter, val); 1036 nsec_printout(cpu, 0, counter, val);
863 else 1037 else
864 abs_printout(cpu, counter, val); 1038 abs_printout(cpu, 0, counter, val);
865 1039
866 if (!csv_output) { 1040 if (!csv_output) {
867 print_noise(counter, 1.0); 1041 print_noise(counter, 1.0);
@@ -899,12 +1073,14 @@ static void print_stat(int argc, const char **argv)
899 fprintf(output, ":\n\n"); 1073 fprintf(output, ":\n\n");
900 } 1074 }
901 1075
902 if (no_aggr) { 1076 if (aggr_socket)
1077 print_aggr_socket(NULL);
1078 else if (no_aggr) {
903 list_for_each_entry(counter, &evsel_list->entries, node) 1079 list_for_each_entry(counter, &evsel_list->entries, node)
904 print_counter(counter); 1080 print_counter(counter, NULL);
905 } else { 1081 } else {
906 list_for_each_entry(counter, &evsel_list->entries, node) 1082 list_for_each_entry(counter, &evsel_list->entries, node)
907 print_counter_aggr(counter); 1083 print_counter_aggr(counter, NULL);
908 } 1084 }
909 1085
910 if (!csv_output) { 1086 if (!csv_output) {
@@ -925,7 +1101,7 @@ static volatile int signr = -1;
925 1101
926static void skip_signal(int signo) 1102static void skip_signal(int signo)
927{ 1103{
928 if(child_pid == -1) 1104 if ((child_pid == -1) || interval)
929 done = 1; 1105 done = 1;
930 1106
931 signr = signo; 1107 signr = signo;
@@ -1145,6 +1321,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1145 "command to run prior to the measured command"), 1321 "command to run prior to the measured command"),
1146 OPT_STRING(0, "post", &post_cmd, "command", 1322 OPT_STRING(0, "post", &post_cmd, "command",
1147 "command to run after to the measured command"), 1323 "command to run after to the measured command"),
1324 OPT_UINTEGER('I', "interval-print", &interval,
1325 "print counts at regular interval in ms (>= 100)"),
1326 OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"),
1148 OPT_END() 1327 OPT_END()
1149 }; 1328 };
1150 const char * const stat_usage[] = { 1329 const char * const stat_usage[] = {
@@ -1231,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1231 usage_with_options(stat_usage, options); 1410 usage_with_options(stat_usage, options);
1232 } 1411 }
1233 1412
1413 if (aggr_socket) {
1414 if (!perf_target__has_cpu(&target)) {
1415 fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
1416 usage_with_options(stat_usage, options);
1417 }
1418 no_aggr = true;
1419 }
1420
1234 if (add_default_attributes()) 1421 if (add_default_attributes())
1235 goto out; 1422 goto out;
1236 1423
@@ -1245,12 +1432,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1245 usage_with_options(stat_usage, options); 1432 usage_with_options(stat_usage, options);
1246 return -1; 1433 return -1;
1247 } 1434 }
1435 if (interval && interval < 100) {
1436 pr_err("print interval must be >= 100ms\n");
1437 usage_with_options(stat_usage, options);
1438 return -1;
1439 }
1248 1440
1249 list_for_each_entry(pos, &evsel_list->entries, node) { 1441 list_for_each_entry(pos, &evsel_list->entries, node) {
1250 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1442 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
1251 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1443 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
1252 goto out_free_fd; 1444 goto out_free_fd;
1253 } 1445 }
1446 if (interval) {
1447 list_for_each_entry(pos, &evsel_list->entries, node) {
1448 if (perf_evsel__alloc_prev_raw_counts(pos) < 0)
1449 goto out_free_fd;
1450 }
1451 }
1254 1452
1255 /* 1453 /*
1256 * We dont want to block the signals - that would cause 1454 * We dont want to block the signals - that would cause
@@ -1260,6 +1458,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1260 */ 1458 */
1261 atexit(sig_atexit); 1459 atexit(sig_atexit);
1262 signal(SIGINT, skip_signal); 1460 signal(SIGINT, skip_signal);
1461 signal(SIGCHLD, skip_signal);
1263 signal(SIGALRM, skip_signal); 1462 signal(SIGALRM, skip_signal);
1264 signal(SIGABRT, skip_signal); 1463 signal(SIGABRT, skip_signal);
1265 1464
@@ -1272,11 +1471,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1272 status = run_perf_stat(argc, argv); 1471 status = run_perf_stat(argc, argv);
1273 } 1472 }
1274 1473
1275 if (status != -1) 1474 if (status != -1 && !interval)
1276 print_stat(argc, argv); 1475 print_stat(argc, argv);
1277out_free_fd: 1476out_free_fd:
1278 list_for_each_entry(pos, &evsel_list->entries, node) 1477 list_for_each_entry(pos, &evsel_list->entries, node) {
1279 perf_evsel__free_stat_priv(pos); 1478 perf_evsel__free_stat_priv(pos);
1479 perf_evsel__free_counts(pos);
1480 perf_evsel__free_prev_raw_counts(pos);
1481 }
1280 perf_evlist__delete_maps(evsel_list); 1482 perf_evlist__delete_maps(evsel_list);
1281out: 1483out:
1282 perf_evlist__delete(evsel_list); 1484 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9ff3950cd4b..72f6eb7b4173 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -68,27 +68,7 @@
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) 71static volatile int done;
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 72
93static void perf_top__update_print_entries(struct perf_top *top) 73static void perf_top__update_print_entries(struct perf_top *top)
94{ 74{
@@ -453,8 +433,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
453 return 0; 433 return 0;
454} 434}
455 435
456static void perf_top__handle_keypress(struct perf_top *top, int c) 436static bool perf_top__handle_keypress(struct perf_top *top, int c)
457{ 437{
438 bool ret = true;
439
458 if (!perf_top__key_mapped(top, c)) { 440 if (!perf_top__key_mapped(top, c)) {
459 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 441 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
460 struct termios tc, save; 442 struct termios tc, save;
@@ -475,7 +457,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
475 457
476 tcsetattr(0, TCSAFLUSH, &save); 458 tcsetattr(0, TCSAFLUSH, &save);
477 if (!perf_top__key_mapped(top, c)) 459 if (!perf_top__key_mapped(top, c))
478 return; 460 return ret;
479 } 461 }
480 462
481 switch (c) { 463 switch (c) {
@@ -537,7 +519,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
537 printf("exiting.\n"); 519 printf("exiting.\n");
538 if (top->dump_symtab) 520 if (top->dump_symtab)
539 perf_session__fprintf_dsos(top->session, stderr); 521 perf_session__fprintf_dsos(top->session, stderr);
540 exit(0); 522 ret = false;
523 break;
541 case 's': 524 case 's':
542 perf_top__prompt_symbol(top, "Enter details symbol"); 525 perf_top__prompt_symbol(top, "Enter details symbol");
543 break; 526 break;
@@ -560,6 +543,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
560 default: 543 default:
561 break; 544 break;
562 } 545 }
546
547 return ret;
563} 548}
564 549
565static void perf_top__sort_new_samples(void *arg) 550static void perf_top__sort_new_samples(void *arg)
@@ -596,13 +581,12 @@ static void *display_thread_tui(void *arg)
596 * via --uid. 581 * via --uid.
597 */ 582 */
598 list_for_each_entry(pos, &top->evlist->entries, node) 583 list_for_each_entry(pos, &top->evlist->entries, node)
599 pos->hists.uid_filter_str = top->target.uid_str; 584 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
600 585
601 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 586 perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
602 &top->session->header.env); 587 &top->session->header.env);
603 588
604 exit_browser(0); 589 done = 1;
605 exit(0);
606 return NULL; 590 return NULL;
607} 591}
608 592
@@ -626,7 +610,7 @@ repeat:
626 /* trash return*/ 610 /* trash return*/
627 getc(stdin); 611 getc(stdin);
628 612
629 while (1) { 613 while (!done) {
630 perf_top__print_sym_table(top); 614 perf_top__print_sym_table(top);
631 /* 615 /*
632 * Either timeout expired or we got an EINTR due to SIGWINCH, 616 * Either timeout expired or we got an EINTR due to SIGWINCH,
@@ -640,15 +624,14 @@ repeat:
640 continue; 624 continue;
641 /* Fall trhu */ 625 /* Fall trhu */
642 default: 626 default:
643 goto process_hotkey; 627 c = getc(stdin);
628 tcsetattr(0, TCSAFLUSH, &save);
629
630 if (perf_top__handle_keypress(top, c))
631 goto repeat;
632 done = 1;
644 } 633 }
645 } 634 }
646process_hotkey:
647 c = getc(stdin);
648 tcsetattr(0, TCSAFLUSH, &save);
649
650 perf_top__handle_keypress(top, c);
651 goto repeat;
652 635
653 return NULL; 636 return NULL;
654} 637}
@@ -716,7 +699,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
716 static struct intlist *seen; 699 static struct intlist *seen;
717 700
718 if (!seen) 701 if (!seen)
719 seen = intlist__new(); 702 seen = intlist__new(NULL);
720 703
721 if (!intlist__has_entry(seen, event->ip.pid)) { 704 if (!intlist__has_entry(seen, event->ip.pid)) {
722 pr_err("Can't find guest [%d]'s kernel information\n", 705 pr_err("Can't find guest [%d]'s kernel information\n",
@@ -727,8 +710,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
727 } 710 }
728 711
729 if (!machine) { 712 if (!machine) {
730 pr_err("%u unprocessable samples recorded.", 713 pr_err("%u unprocessable samples recorded.\r",
731 top->session->hists.stats.nr_unprocessable_samples++); 714 top->session->stats.nr_unprocessable_samples++);
732 return; 715 return;
733 } 716 }
734 717
@@ -847,13 +830,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
847 ++top->us_samples; 830 ++top->us_samples;
848 if (top->hide_user_symbols) 831 if (top->hide_user_symbols)
849 continue; 832 continue;
850 machine = perf_session__find_host_machine(session); 833 machine = &session->machines.host;
851 break; 834 break;
852 case PERF_RECORD_MISC_KERNEL: 835 case PERF_RECORD_MISC_KERNEL:
853 ++top->kernel_samples; 836 ++top->kernel_samples;
854 if (top->hide_kernel_symbols) 837 if (top->hide_kernel_symbols)
855 continue; 838 continue;
856 machine = perf_session__find_host_machine(session); 839 machine = &session->machines.host;
857 break; 840 break;
858 case PERF_RECORD_MISC_GUEST_KERNEL: 841 case PERF_RECORD_MISC_GUEST_KERNEL:
859 ++top->guest_kernel_samples; 842 ++top->guest_kernel_samples;
@@ -878,7 +861,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
878 hists__inc_nr_events(&evsel->hists, event->header.type); 861 hists__inc_nr_events(&evsel->hists, event->header.type);
879 machine__process_event(machine, event); 862 machine__process_event(machine, event);
880 } else 863 } else
881 ++session->hists.stats.nr_unknown_events; 864 ++session->stats.nr_unknown_events;
882 } 865 }
883} 866}
884 867
@@ -890,123 +873,42 @@ static void perf_top__mmap_read(struct perf_top *top)
890 perf_top__mmap_read_idx(top, i); 873 perf_top__mmap_read_idx(top, i);
891} 874}
892 875
893static void perf_top__start_counters(struct perf_top *top) 876static int perf_top__start_counters(struct perf_top *top)
894{ 877{
878 char msg[512];
895 struct perf_evsel *counter; 879 struct perf_evsel *counter;
896 struct perf_evlist *evlist = top->evlist; 880 struct perf_evlist *evlist = top->evlist;
881 struct perf_record_opts *opts = &top->record_opts;
897 882
898 if (top->group) 883 perf_evlist__config(evlist, opts);
899 perf_evlist__set_leader(evlist);
900 884
901 list_for_each_entry(counter, &evlist->entries, node) { 885 list_for_each_entry(counter, &evlist->entries, node) {
902 struct perf_event_attr *attr = &counter->attr;
903
904 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
905
906 if (top->freq) {
907 attr->sample_type |= PERF_SAMPLE_PERIOD;
908 attr->freq = 1;
909 attr->sample_freq = top->freq;
910 }
911
912 if (evlist->nr_entries > 1) {
913 attr->sample_type |= PERF_SAMPLE_ID;
914 attr->read_format |= PERF_FORMAT_ID;
915 }
916
917 if (perf_target__has_cpu(&top->target))
918 attr->sample_type |= PERF_SAMPLE_CPU;
919
920 if (symbol_conf.use_callchain)
921 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
922
923 attr->mmap = 1;
924 attr->comm = 1;
925 attr->inherit = top->inherit;
926fallback_missing_features:
927 if (top->exclude_guest_missing)
928 attr->exclude_guest = attr->exclude_host = 0;
929retry_sample_id:
930 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
931try_again: 886try_again:
932 if (perf_evsel__open(counter, top->evlist->cpus, 887 if (perf_evsel__open(counter, top->evlist->cpus,
933 top->evlist->threads) < 0) { 888 top->evlist->threads) < 0) {
934 int err = errno; 889 if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
935
936 if (err == EPERM || err == EACCES) {
937 ui__error_paranoid();
938 goto out_err;
939 } else if (err == EINVAL) {
940 if (!top->exclude_guest_missing &&
941 (attr->exclude_guest || attr->exclude_host)) {
942 pr_debug("Old kernel, cannot exclude "
943 "guest or host samples.\n");
944 top->exclude_guest_missing = true;
945 goto fallback_missing_features;
946 } else if (!top->sample_id_all_missing) {
947 /*
948 * Old kernel, no attr->sample_id_type_all field
949 */
950 top->sample_id_all_missing = true;
951 goto retry_sample_id;
952 }
953 }
954 /*
955 * If it's cycles then fall back to hrtimer
956 * based cpu-clock-tick sw counter, which
957 * is always available even if no PMU support:
958 */
959 if ((err == ENOENT || err == ENXIO) &&
960 (attr->type == PERF_TYPE_HARDWARE) &&
961 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
962
963 if (verbose) 890 if (verbose)
964 ui__warning("Cycles event not supported,\n" 891 ui__warning("%s\n", msg);
965 "trying to fall back to cpu-clock-ticks\n");
966
967 attr->type = PERF_TYPE_SOFTWARE;
968 attr->config = PERF_COUNT_SW_CPU_CLOCK;
969 if (counter->name) {
970 free(counter->name);
971 counter->name = NULL;
972 }
973 goto try_again; 892 goto try_again;
974 } 893 }
975 894
976 if (err == ENOENT) { 895 perf_evsel__open_strerror(counter, &opts->target,
977 ui__error("The %s event is not supported.\n", 896 errno, msg, sizeof(msg));
978 perf_evsel__name(counter)); 897 ui__error("%s\n", msg);
979 goto out_err;
980 } else if (err == EMFILE) {
981 ui__error("Too many events are opened.\n"
982 "Try again after reducing the number of events\n");
983 goto out_err;
984 } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
985 ui__error("\'precise\' request may not be supported. "
986 "Try removing 'p' modifier\n");
987 goto out_err;
988 }
989
990 ui__error("The sys_perf_event_open() syscall "
991 "returned with %d (%s). /bin/dmesg "
992 "may provide additional information.\n"
993 "No CONFIG_PERF_EVENTS=y kernel support "
994 "configured?\n", err, strerror(err));
995 goto out_err; 898 goto out_err;
996 } 899 }
997 } 900 }
998 901
999 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 902 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
1000 ui__error("Failed to mmap with %d (%s)\n", 903 ui__error("Failed to mmap with %d (%s)\n",
1001 errno, strerror(errno)); 904 errno, strerror(errno));
1002 goto out_err; 905 goto out_err;
1003 } 906 }
1004 907
1005 return; 908 return 0;
1006 909
1007out_err: 910out_err:
1008 exit_browser(0); 911 return -1;
1009 exit(0);
1010} 912}
1011 913
1012static int perf_top__setup_sample_type(struct perf_top *top) 914static int perf_top__setup_sample_type(struct perf_top *top)
@@ -1016,7 +918,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
1016 ui__error("Selected -g but \"sym\" not present in --sort/-s."); 918 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
1017 return -EINVAL; 919 return -EINVAL;
1018 } 920 }
1019 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 921 } else if (callchain_param.mode != CHAIN_NONE) {
1020 if (callchain_register_param(&callchain_param) < 0) { 922 if (callchain_register_param(&callchain_param) < 0) {
1021 ui__error("Can't register callchain params.\n"); 923 ui__error("Can't register callchain params.\n");
1022 return -EINVAL; 924 return -EINVAL;
@@ -1028,6 +930,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
1028 930
1029static int __cmd_top(struct perf_top *top) 931static int __cmd_top(struct perf_top *top)
1030{ 932{
933 struct perf_record_opts *opts = &top->record_opts;
1031 pthread_t thread; 934 pthread_t thread;
1032 int ret; 935 int ret;
1033 /* 936 /*
@@ -1042,26 +945,42 @@ static int __cmd_top(struct perf_top *top)
1042 if (ret) 945 if (ret)
1043 goto out_delete; 946 goto out_delete;
1044 947
1045 if (perf_target__has_task(&top->target)) 948 if (perf_target__has_task(&opts->target))
1046 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 949 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1047 perf_event__process, 950 perf_event__process,
1048 &top->session->host_machine); 951 &top->session->machines.host);
1049 else 952 else
1050 perf_event__synthesize_threads(&top->tool, perf_event__process, 953 perf_event__synthesize_threads(&top->tool, perf_event__process,
1051 &top->session->host_machine); 954 &top->session->machines.host);
1052 perf_top__start_counters(top); 955
956 ret = perf_top__start_counters(top);
957 if (ret)
958 goto out_delete;
959
1053 top->session->evlist = top->evlist; 960 top->session->evlist = top->evlist;
1054 perf_session__set_id_hdr_size(top->session); 961 perf_session__set_id_hdr_size(top->session);
1055 962
963 /*
964 * When perf is starting the traced process, all the events (apart from
965 * group members) have enable_on_exec=1 set, so don't spoil it by
966 * prematurely enabling them.
967 *
968 * XXX 'top' still doesn't start workloads like record, trace, but should,
969 * so leave the check here.
970 */
971 if (!perf_target__none(&opts->target))
972 perf_evlist__enable(top->evlist);
973
1056 /* Wait for a minimal set of events before starting the snapshot */ 974 /* Wait for a minimal set of events before starting the snapshot */
1057 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 975 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1058 976
1059 perf_top__mmap_read(top); 977 perf_top__mmap_read(top);
1060 978
979 ret = -1;
1061 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 980 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1062 display_thread), top)) { 981 display_thread), top)) {
1063 ui__error("Could not create display thread.\n"); 982 ui__error("Could not create display thread.\n");
1064 exit(-1); 983 goto out_delete;
1065 } 984 }
1066 985
1067 if (top->realtime_prio) { 986 if (top->realtime_prio) {
@@ -1070,11 +989,11 @@ static int __cmd_top(struct perf_top *top)
1070 param.sched_priority = top->realtime_prio; 989 param.sched_priority = top->realtime_prio;
1071 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 990 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1072 ui__error("Could not set realtime priority.\n"); 991 ui__error("Could not set realtime priority.\n");
1073 exit(-1); 992 goto out_delete;
1074 } 993 }
1075 } 994 }
1076 995
1077 while (1) { 996 while (!done) {
1078 u64 hits = top->samples; 997 u64 hits = top->samples;
1079 998
1080 perf_top__mmap_read(top); 999 perf_top__mmap_read(top);
@@ -1083,126 +1002,67 @@ static int __cmd_top(struct perf_top *top)
1083 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 1002 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1084 } 1003 }
1085 1004
1005 ret = 0;
1086out_delete: 1006out_delete:
1087 perf_session__delete(top->session); 1007 perf_session__delete(top->session);
1088 top->session = NULL; 1008 top->session = NULL;
1089 1009
1090 return 0; 1010 return ret;
1091} 1011}
1092 1012
1093static int 1013static int
1094parse_callchain_opt(const struct option *opt, const char *arg, int unset) 1014parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1095{ 1015{
1096 struct perf_top *top = (struct perf_top *)opt->value;
1097 char *tok, *tok2;
1098 char *endptr;
1099
1100 /* 1016 /*
1101 * --no-call-graph 1017 * --no-call-graph
1102 */ 1018 */
1103 if (unset) { 1019 if (unset)
1104 top->dont_use_callchains = true;
1105 return 0; 1020 return 0;
1106 }
1107 1021
1108 symbol_conf.use_callchain = true; 1022 symbol_conf.use_callchain = true;
1109 1023
1110 if (!arg) 1024 return record_parse_callchain_opt(opt, arg, unset);
1111 return 0;
1112
1113 tok = strtok((char *)arg, ",");
1114 if (!tok)
1115 return -1;
1116
1117 /* get the output mode */
1118 if (!strncmp(tok, "graph", strlen(arg)))
1119 callchain_param.mode = CHAIN_GRAPH_ABS;
1120
1121 else if (!strncmp(tok, "flat", strlen(arg)))
1122 callchain_param.mode = CHAIN_FLAT;
1123
1124 else if (!strncmp(tok, "fractal", strlen(arg)))
1125 callchain_param.mode = CHAIN_GRAPH_REL;
1126
1127 else if (!strncmp(tok, "none", strlen(arg))) {
1128 callchain_param.mode = CHAIN_NONE;
1129 symbol_conf.use_callchain = false;
1130
1131 return 0;
1132 } else
1133 return -1;
1134
1135 /* get the min percentage */
1136 tok = strtok(NULL, ",");
1137 if (!tok)
1138 goto setup;
1139
1140 callchain_param.min_percent = strtod(tok, &endptr);
1141 if (tok == endptr)
1142 return -1;
1143
1144 /* get the print limit */
1145 tok2 = strtok(NULL, ",");
1146 if (!tok2)
1147 goto setup;
1148
1149 if (tok2[0] != 'c') {
1150 callchain_param.print_limit = strtod(tok2, &endptr);
1151 tok2 = strtok(NULL, ",");
1152 if (!tok2)
1153 goto setup;
1154 }
1155
1156 /* get the call chain order */
1157 if (!strcmp(tok2, "caller"))
1158 callchain_param.order = ORDER_CALLER;
1159 else if (!strcmp(tok2, "callee"))
1160 callchain_param.order = ORDER_CALLEE;
1161 else
1162 return -1;
1163setup:
1164 if (callchain_register_param(&callchain_param) < 0) {
1165 fprintf(stderr, "Can't register callchain params\n");
1166 return -1;
1167 }
1168 return 0;
1169} 1025}
1170 1026
1171int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1027int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1172{ 1028{
1173 struct perf_evsel *pos;
1174 int status; 1029 int status;
1175 char errbuf[BUFSIZ]; 1030 char errbuf[BUFSIZ];
1176 struct perf_top top = { 1031 struct perf_top top = {
1177 .count_filter = 5, 1032 .count_filter = 5,
1178 .delay_secs = 2, 1033 .delay_secs = 2,
1179 .freq = 4000, /* 4 KHz */ 1034 .record_opts = {
1180 .mmap_pages = 128, 1035 .mmap_pages = UINT_MAX,
1181 .sym_pcnt_filter = 5, 1036 .user_freq = UINT_MAX,
1182 .target = { 1037 .user_interval = ULLONG_MAX,
1183 .uses_mmap = true, 1038 .freq = 4000, /* 4 KHz */
1039 .target = {
1040 .uses_mmap = true,
1041 },
1184 }, 1042 },
1043 .sym_pcnt_filter = 5,
1185 }; 1044 };
1186 char callchain_default_opt[] = "fractal,0.5,callee"; 1045 struct perf_record_opts *opts = &top.record_opts;
1046 struct perf_target *target = &opts->target;
1187 const struct option options[] = { 1047 const struct option options[] = {
1188 OPT_CALLBACK('e', "event", &top.evlist, "event", 1048 OPT_CALLBACK('e', "event", &top.evlist, "event",
1189 "event selector. use 'perf list' to list available events", 1049 "event selector. use 'perf list' to list available events",
1190 parse_events_option), 1050 parse_events_option),
1191 OPT_INTEGER('c', "count", &top.default_interval, 1051 OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
1192 "event period to sample"), 1052 OPT_STRING('p', "pid", &target->pid, "pid",
1193 OPT_STRING('p', "pid", &top.target.pid, "pid",
1194 "profile events on existing process id"), 1053 "profile events on existing process id"),
1195 OPT_STRING('t', "tid", &top.target.tid, "tid", 1054 OPT_STRING('t', "tid", &target->tid, "tid",
1196 "profile events on existing thread id"), 1055 "profile events on existing thread id"),
1197 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, 1056 OPT_BOOLEAN('a', "all-cpus", &target->system_wide,
1198 "system-wide collection from all CPUs"), 1057 "system-wide collection from all CPUs"),
1199 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", 1058 OPT_STRING('C', "cpu", &target->cpu_list, "cpu",
1200 "list of cpus to monitor"), 1059 "list of cpus to monitor"),
1201 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1060 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1202 "file", "vmlinux pathname"), 1061 "file", "vmlinux pathname"),
1203 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1062 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1204 "hide kernel symbols"), 1063 "hide kernel symbols"),
1205 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), 1064 OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages,
1065 "number of mmap data pages"),
1206 OPT_INTEGER('r', "realtime", &top.realtime_prio, 1066 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1207 "collect data with this RT SCHED_FIFO priority"), 1067 "collect data with this RT SCHED_FIFO priority"),
1208 OPT_INTEGER('d', "delay", &top.delay_secs, 1068 OPT_INTEGER('d', "delay", &top.delay_secs,
@@ -1211,16 +1071,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1211 "dump the symbol table used for profiling"), 1071 "dump the symbol table used for profiling"),
1212 OPT_INTEGER('f', "count-filter", &top.count_filter, 1072 OPT_INTEGER('f', "count-filter", &top.count_filter,
1213 "only display functions with more events than this"), 1073 "only display functions with more events than this"),
1214 OPT_BOOLEAN('g', "group", &top.group, 1074 OPT_BOOLEAN('g', "group", &opts->group,
1215 "put the counters into a counter group"), 1075 "put the counters into a counter group"),
1216 OPT_BOOLEAN('i', "inherit", &top.inherit, 1076 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
1217 "child tasks inherit counters"), 1077 "child tasks do not inherit counters"),
1218 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", 1078 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1219 "symbol to annotate"), 1079 "symbol to annotate"),
1220 OPT_BOOLEAN('z', "zero", &top.zero, 1080 OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"),
1221 "zero history across updates"), 1081 OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"),
1222 OPT_INTEGER('F', "freq", &top.freq,
1223 "profile at this frequency"),
1224 OPT_INTEGER('E', "entries", &top.print_entries, 1082 OPT_INTEGER('E', "entries", &top.print_entries,
1225 "display this many functions"), 1083 "display this many functions"),
1226 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1084 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
@@ -1233,10 +1091,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1233 "sort by key(s): pid, comm, dso, symbol, parent"), 1091 "sort by key(s): pid, comm, dso, symbol, parent"),
1234 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1092 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1235 "Show a column with the number of samples"), 1093 "Show a column with the number of samples"),
1236 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", 1094 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1237 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " 1095 "mode[,dump_size]", record_callchain_help,
1238 "Default: fractal,0.5,callee", &parse_callchain_opt, 1096 &parse_callchain_opt, "fp"),
1239 callchain_default_opt),
1240 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1097 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1241 "Show a column with the sum of periods"), 1098 "Show a column with the sum of periods"),
1242 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1099 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1251,7 +1108,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1251 "Display raw encoding of assembly instructions (default)"), 1108 "Display raw encoding of assembly instructions (default)"),
1252 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1109 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1253 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1110 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1254 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), 1111 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1255 OPT_END() 1112 OPT_END()
1256 }; 1113 };
1257 const char * const top_usage[] = { 1114 const char * const top_usage[] = {
@@ -1272,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1272 if (sort_order == default_sort_order) 1129 if (sort_order == default_sort_order)
1273 sort_order = "dso,symbol"; 1130 sort_order = "dso,symbol";
1274 1131
1275 setup_sorting(top_usage, options); 1132 if (setup_sorting() < 0)
1133 usage_with_options(top_usage, options);
1276 1134
1277 if (top.use_stdio) 1135 if (top.use_stdio)
1278 use_browser = 0; 1136 use_browser = 0;
@@ -1281,33 +1139,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1281 1139
1282 setup_browser(false); 1140 setup_browser(false);
1283 1141
1284 status = perf_target__validate(&top.target); 1142 status = perf_target__validate(target);
1285 if (status) { 1143 if (status) {
1286 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1144 perf_target__strerror(target, status, errbuf, BUFSIZ);
1287 ui__warning("%s", errbuf); 1145 ui__warning("%s", errbuf);
1288 } 1146 }
1289 1147
1290 status = perf_target__parse_uid(&top.target); 1148 status = perf_target__parse_uid(target);
1291 if (status) { 1149 if (status) {
1292 int saved_errno = errno; 1150 int saved_errno = errno;
1293 1151
1294 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1152 perf_target__strerror(target, status, errbuf, BUFSIZ);
1295 ui__error("%s", errbuf); 1153 ui__error("%s", errbuf);
1296 1154
1297 status = -saved_errno; 1155 status = -saved_errno;
1298 goto out_delete_evlist; 1156 goto out_delete_evlist;
1299 } 1157 }
1300 1158
1301 if (perf_target__none(&top.target)) 1159 if (perf_target__none(target))
1302 top.target.system_wide = true; 1160 target->system_wide = true;
1303 1161
1304 if (perf_evlist__create_maps(top.evlist, &top.target) < 0) 1162 if (perf_evlist__create_maps(top.evlist, target) < 0)
1305 usage_with_options(top_usage, options); 1163 usage_with_options(top_usage, options);
1306 1164
1307 if (!top.evlist->nr_entries && 1165 if (!top.evlist->nr_entries &&
1308 perf_evlist__add_default(top.evlist) < 0) { 1166 perf_evlist__add_default(top.evlist) < 0) {
1309 ui__error("Not enough memory for event selector list\n"); 1167 ui__error("Not enough memory for event selector list\n");
1310 return -ENOMEM; 1168 goto out_delete_maps;
1311 } 1169 }
1312 1170
1313 symbol_conf.nr_events = top.evlist->nr_entries; 1171 symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1315,24 +1173,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1315 if (top.delay_secs < 1) 1173 if (top.delay_secs < 1)
1316 top.delay_secs = 1; 1174 top.delay_secs = 1;
1317 1175
1176 if (opts->user_interval != ULLONG_MAX)
1177 opts->default_interval = opts->user_interval;
1178 if (opts->user_freq != UINT_MAX)
1179 opts->freq = opts->user_freq;
1180
1318 /* 1181 /*
1319 * User specified count overrides default frequency. 1182 * User specified count overrides default frequency.
1320 */ 1183 */
1321 if (top.default_interval) 1184 if (opts->default_interval)
1322 top.freq = 0; 1185 opts->freq = 0;
1323 else if (top.freq) { 1186 else if (opts->freq) {
1324 top.default_interval = top.freq; 1187 opts->default_interval = opts->freq;
1325 } else { 1188 } else {
1326 ui__error("frequency and count are zero, aborting\n"); 1189 ui__error("frequency and count are zero, aborting\n");
1327 exit(EXIT_FAILURE); 1190 status = -EINVAL;
1328 } 1191 goto out_delete_maps;
1329
1330 list_for_each_entry(pos, &top.evlist->entries, node) {
1331 /*
1332 * Fill in the ones not specifically initialized via -c:
1333 */
1334 if (!pos->attr.sample_period)
1335 pos->attr.sample_period = top.default_interval;
1336 } 1192 }
1337 1193
1338 top.sym_evsel = perf_evlist__first(top.evlist); 1194 top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1365,6 +1221,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1365 1221
1366 status = __cmd_top(&top); 1222 status = __cmd_top(&top);
1367 1223
1224out_delete_maps:
1225 perf_evlist__delete_maps(top.evlist);
1368out_delete_evlist: 1226out_delete_evlist:
1369 perf_evlist__delete(top.evlist); 1227 perf_evlist__delete(top.evlist);
1370 1228
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 7932ffa29889..d222d7fc7e96 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
455 goto out_delete_evlist; 455 goto out_delete_evlist;
456 } 456 }
457 457
458 perf_evlist__config_attrs(evlist, &trace->opts); 458 perf_evlist__config(evlist, &trace->opts);
459 459
460 signal(SIGCHLD, sig_handler); 460 signal(SIGCHLD, sig_handler);
461 signal(SIGINT, sig_handler); 461 signal(SIGINT, sig_handler);
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index f5ac77485a4f..b4eabb44e381 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -225,3 +225,14 @@ int main(void)
225 return on_exit(NULL, NULL); 225 return on_exit(NULL, NULL);
226} 226}
227endef 227endef
228
229define SOURCE_LIBNUMA
230#include <numa.h>
231#include <numaif.h>
232
233int main(void)
234{
235 numa_available();
236 return 0;
237}
238endef \ No newline at end of file
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..c2206c87fc9f 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__)
@@ -107,32 +103,6 @@ void get_term_dimensions(struct winsize *ws);
107#include "util/types.h" 103#include "util/types.h"
108#include <stdbool.h> 104#include <stdbool.h>
109 105
110struct perf_mmap {
111 void *base;
112 int mask;
113 unsigned int prev;
114};
115
116static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
117{
118 struct perf_event_mmap_page *pc = mm->base;
119 int head = pc->data_head;
120 rmb();
121 return head;
122}
123
124static inline void perf_mmap__write_tail(struct perf_mmap *md,
125 unsigned long tail)
126{
127 struct perf_event_mmap_page *pc = md->base;
128
129 /*
130 * ensure all reads are done before we write the tail out.
131 */
132 /* mb(); */
133 pc->data_tail = tail;
134}
135
136/* 106/*
137 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 107 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
138 * counters in the current task. 108 * counters in the current task.
@@ -237,8 +207,6 @@ struct perf_record_opts {
237 bool raw_samples; 207 bool raw_samples;
238 bool sample_address; 208 bool sample_address;
239 bool sample_time; 209 bool sample_time;
240 bool sample_id_all_missing;
241 bool exclude_guest_missing;
242 bool period; 210 bool period;
243 unsigned int freq; 211 unsigned int freq;
244 unsigned int mmap_pages; 212 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/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl
index 4bb3ecd33472..8b20787021c1 100644
--- a/tools/perf/scripts/perl/rwtop.pl
+++ b/tools/perf/scripts/perl/rwtop.pl
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib"; 17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20use POSIX qw/SIGALRM SA_RESTART/;
20 21
21my $default_interval = 3; 22my $default_interval = 3;
22my $nlines = 20; 23my $nlines = 20;
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write
90 91
91sub trace_begin 92sub trace_begin
92{ 93{
93 $SIG{ALRM} = \&set_print_pending; 94 my $sa = POSIX::SigAction->new(\&set_print_pending);
95 $sa->flags(SA_RESTART);
96 $sa->safe(1);
97 POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
94 alarm 1; 98 alarm 1;
95} 99}
96 100
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..bdcceb886f77 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -19,6 +19,11 @@
19 * permissions. All the event text files are stored there. 19 * permissions. All the event text files are stored there.
20 */ 20 */
21 21
22/*
23 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
24 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
25 */
26#define __SANE_USERSPACE_TYPES__
22#include <stdlib.h> 27#include <stdlib.h>
23#include <stdio.h> 28#include <stdio.h>
24#include <inttypes.h> 29#include <inttypes.h>
@@ -33,8 +38,6 @@
33 38
34extern int verbose; 39extern int verbose;
35 40
36bool test_attr__enabled;
37
38static char *dir; 41static char *dir;
39 42
40void test_attr__init(void) 43void test_attr__init(void)
@@ -146,7 +149,7 @@ static int run_dir(const char *d, const char *perf)
146{ 149{
147 char cmd[3*PATH_MAX]; 150 char cmd[3*PATH_MAX];
148 151
149 snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s", 152 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
150 d, d, perf, verbose ? "-v" : ""); 153 d, d, perf, verbose ? "-v" : "");
151 154
152 return system(cmd); 155 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/base-record b/tools/perf/tests/attr/base-record
index f1485d8e6a0b..5bc3880f7be5 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -7,7 +7,7 @@ size=96
7config=0 7config=0
8sample_period=4000 8sample_period=4000
9sample_type=263 9sample_type=263
10read_format=7 10read_format=0
11disabled=1 11disabled=1
12inherit=1 12inherit=1
13pinned=0 13pinned=0
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
index a6599e9a19d3..57739cacdb2a 100644
--- a/tools/perf/tests/attr/test-record-group
+++ b/tools/perf/tests/attr/test-record-group
@@ -6,12 +6,14 @@ args = --group -e cycles,instructions kill >/dev/null 2>&1
6fd=1 6fd=1
7group_fd=-1 7group_fd=-1
8sample_type=327 8sample_type=327
9read_format=4
9 10
10[event-2:base-record] 11[event-2:base-record]
11fd=2 12fd=2
12group_fd=1 13group_fd=1
13config=1 14config=1
14sample_type=327 15sample_type=327
16read_format=4
15mmap=0 17mmap=0
16comm=0 18comm=0
17enable_on_exec=0 19enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
index 5a8359da38af..c5548d054aff 100644
--- a/tools/perf/tests/attr/test-record-group1
+++ b/tools/perf/tests/attr/test-record-group1
@@ -1,11 +1,12 @@
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
7group_fd=-1 7group_fd=-1
8sample_type=327 8sample_type=327
9read_format=4
9 10
10[event-2:base-record] 11[event-2:base-record]
11fd=2 12fd=2
@@ -13,6 +14,7 @@ group_fd=1
13type=0 14type=0
14config=1 15config=1
15sample_type=327 16sample_type=327
17read_format=4
16mmap=0 18mmap=0
17comm=0 19comm=0
18enable_on_exec=0 20enable_on_exec=0
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..1be64a6c5daf
--- /dev/null
+++ b/tools/perf/tests/hists_link.c
@@ -0,0 +1,500 @@
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 if (setup_sorting() < 0)
453 goto out;
454
455 machines__init(&machines);
456
457 /* setup threads/dso/map/symbols also */
458 machine = setup_fake_machine(&machines);
459 if (!machine)
460 goto out;
461
462 if (verbose > 1)
463 machine__fprintf(machine, stderr);
464
465 /* process sample events */
466 err = add_hist_entries(evlist, machine);
467 if (err < 0)
468 goto out;
469
470 list_for_each_entry(evsel, &evlist->entries, node) {
471 hists__collapse_resort(&evsel->hists);
472
473 if (verbose > 2)
474 print_hists(&evsel->hists);
475 }
476
477 first = perf_evlist__first(evlist);
478 evsel = perf_evlist__last(evlist);
479
480 /* match common entries */
481 hists__match(&first->hists, &evsel->hists);
482 err = validate_match(&first->hists, &evsel->hists);
483 if (err)
484 goto out;
485
486 /* link common and/or dummy entries */
487 hists__link(&first->hists, &evsel->hists);
488 err = validate_link(&first->hists, &evsel->hists);
489 if (err)
490 goto out;
491
492 err = 0;
493
494out:
495 /* tear down everything */
496 perf_evlist__delete(evlist);
497 machines__exit(&machines);
498
499 return err;
500}
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index e1746811e14b..cdd50755af51 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -22,36 +22,16 @@ int test__basic_mmap(void)
22 struct thread_map *threads; 22 struct thread_map *threads;
23 struct cpu_map *cpus; 23 struct cpu_map *cpus;
24 struct perf_evlist *evlist; 24 struct perf_evlist *evlist;
25 struct perf_event_attr attr = {
26 .type = PERF_TYPE_TRACEPOINT,
27 .read_format = PERF_FORMAT_ID,
28 .sample_type = PERF_SAMPLE_ID,
29 .watermark = 0,
30 };
31 cpu_set_t cpu_set; 25 cpu_set_t cpu_set;
32 const char *syscall_names[] = { "getsid", "getppid", "getpgrp", 26 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
33 "getpgid", }; 27 "getpgid", };
34 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, 28 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
35 (void*)getpgid }; 29 (void*)getpgid };
36#define nsyscalls ARRAY_SIZE(syscall_names) 30#define nsyscalls ARRAY_SIZE(syscall_names)
37 int ids[nsyscalls];
38 unsigned int nr_events[nsyscalls], 31 unsigned int nr_events[nsyscalls],
39 expected_nr_events[nsyscalls], i, j; 32 expected_nr_events[nsyscalls], i, j;
40 struct perf_evsel *evsels[nsyscalls], *evsel; 33 struct perf_evsel *evsels[nsyscalls], *evsel;
41 34
42 for (i = 0; i < nsyscalls; ++i) {
43 char name[64];
44
45 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
46 ids[i] = trace_event__id(name);
47 if (ids[i] < 0) {
48 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
49 return -1;
50 }
51 nr_events[i] = 0;
52 expected_nr_events[i] = random() % 257;
53 }
54
55 threads = thread_map__new(-1, getpid(), UINT_MAX); 35 threads = thread_map__new(-1, getpid(), UINT_MAX);
56 if (threads == NULL) { 36 if (threads == NULL) {
57 pr_debug("thread_map__new\n"); 37 pr_debug("thread_map__new\n");
@@ -79,18 +59,19 @@ int test__basic_mmap(void)
79 goto out_free_cpus; 59 goto out_free_cpus;
80 } 60 }
81 61
82 /* anonymous union fields, can't be initialized above */
83 attr.wakeup_events = 1;
84 attr.sample_period = 1;
85
86 for (i = 0; i < nsyscalls; ++i) { 62 for (i = 0; i < nsyscalls; ++i) {
87 attr.config = ids[i]; 63 char name[64];
88 evsels[i] = perf_evsel__new(&attr, i); 64
65 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
66 evsels[i] = perf_evsel__newtp("syscalls", name, i);
89 if (evsels[i] == NULL) { 67 if (evsels[i] == NULL) {
90 pr_debug("perf_evsel__new\n"); 68 pr_debug("perf_evsel__new\n");
91 goto out_free_evlist; 69 goto out_free_evlist;
92 } 70 }
93 71
72 evsels[i]->attr.wakeup_events = 1;
73 perf_evsel__set_sample_id(evsels[i]);
74
94 perf_evlist__add(evlist, evsels[i]); 75 perf_evlist__add(evlist, evsels[i]);
95 76
96 if (perf_evsel__open(evsels[i], cpus, threads) < 0) { 77 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
@@ -99,6 +80,9 @@ int test__basic_mmap(void)
99 strerror(errno)); 80 strerror(errno));
100 goto out_close_fd; 81 goto out_close_fd;
101 } 82 }
83
84 nr_events[i] = 0;
85 expected_nr_events[i] = 1 + rand() % 127;
102 } 86 }
103 87
104 if (perf_evlist__mmap(evlist, 128, true) < 0) { 88 if (perf_evlist__mmap(evlist, 128, true) < 0) {
@@ -128,6 +112,7 @@ int test__basic_mmap(void)
128 goto out_munmap; 112 goto out_munmap;
129 } 113 }
130 114
115 err = -1;
131 evsel = perf_evlist__id2evsel(evlist, sample.id); 116 evsel = perf_evlist__id2evsel(evlist, sample.id);
132 if (evsel == NULL) { 117 if (evsel == NULL) {
133 pr_debug("event with id %" PRIu64 118 pr_debug("event with id %" PRIu64
@@ -137,16 +122,17 @@ int test__basic_mmap(void)
137 nr_events[evsel->idx]++; 122 nr_events[evsel->idx]++;
138 } 123 }
139 124
125 err = 0;
140 list_for_each_entry(evsel, &evlist->entries, node) { 126 list_for_each_entry(evsel, &evlist->entries, node) {
141 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 127 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
142 pr_debug("expected %d %s events, got %d\n", 128 pr_debug("expected %d %s events, got %d\n",
143 expected_nr_events[evsel->idx], 129 expected_nr_events[evsel->idx],
144 perf_evsel__name(evsel), nr_events[evsel->idx]); 130 perf_evsel__name(evsel), nr_events[evsel->idx]);
131 err = -1;
145 goto out_munmap; 132 goto out_munmap;
146 } 133 }
147 } 134 }
148 135
149 err = 0;
150out_munmap: 136out_munmap:
151 perf_evlist__munmap(evlist); 137 perf_evlist__munmap(evlist);
152out_close_fd: 138out_close_fd:
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
index 31072aba0d54..b0657a9ccda6 100644
--- a/tools/perf/tests/open-syscall-all-cpus.c
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -7,20 +7,12 @@
7int test__open_syscall_event_on_all_cpus(void) 7int test__open_syscall_event_on_all_cpus(void)
8{ 8{
9 int err = -1, fd, cpu; 9 int err = -1, fd, cpu;
10 struct thread_map *threads;
11 struct cpu_map *cpus; 10 struct cpu_map *cpus;
12 struct perf_evsel *evsel; 11 struct perf_evsel *evsel;
13 struct perf_event_attr attr;
14 unsigned int nr_open_calls = 111, i; 12 unsigned int nr_open_calls = 111, i;
15 cpu_set_t cpu_set; 13 cpu_set_t cpu_set;
16 int id = trace_event__id("sys_enter_open"); 14 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
17 15
18 if (id < 0) {
19 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
20 return -1;
21 }
22
23 threads = thread_map__new(-1, getpid(), UINT_MAX);
24 if (threads == NULL) { 16 if (threads == NULL) {
25 pr_debug("thread_map__new\n"); 17 pr_debug("thread_map__new\n");
26 return -1; 18 return -1;
@@ -32,15 +24,11 @@ int test__open_syscall_event_on_all_cpus(void)
32 goto out_thread_map_delete; 24 goto out_thread_map_delete;
33 } 25 }
34 26
35
36 CPU_ZERO(&cpu_set); 27 CPU_ZERO(&cpu_set);
37 28
38 memset(&attr, 0, sizeof(attr)); 29 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
39 attr.type = PERF_TYPE_TRACEPOINT;
40 attr.config = id;
41 evsel = perf_evsel__new(&attr, 0);
42 if (evsel == NULL) { 30 if (evsel == NULL) {
43 pr_debug("perf_evsel__new\n"); 31 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
44 goto out_thread_map_delete; 32 goto out_thread_map_delete;
45 } 33 }
46 34
@@ -110,6 +98,7 @@ int test__open_syscall_event_on_all_cpus(void)
110 } 98 }
111 } 99 }
112 100
101 perf_evsel__free_counts(evsel);
113out_close_fd: 102out_close_fd:
114 perf_evsel__close_fd(evsel, 1, threads->nr); 103 perf_evsel__close_fd(evsel, 1, threads->nr);
115out_evsel_delete: 104out_evsel_delete:
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
index 98be8b518b4f..befc0671f95d 100644
--- a/tools/perf/tests/open-syscall.c
+++ b/tools/perf/tests/open-syscall.c
@@ -6,29 +6,18 @@
6int test__open_syscall_event(void) 6int test__open_syscall_event(void)
7{ 7{
8 int err = -1, fd; 8 int err = -1, fd;
9 struct thread_map *threads;
10 struct perf_evsel *evsel; 9 struct perf_evsel *evsel;
11 struct perf_event_attr attr;
12 unsigned int nr_open_calls = 111, i; 10 unsigned int nr_open_calls = 111, i;
13 int id = trace_event__id("sys_enter_open"); 11 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
14 12
15 if (id < 0) {
16 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
17 return -1;
18 }
19
20 threads = thread_map__new(-1, getpid(), UINT_MAX);
21 if (threads == NULL) { 13 if (threads == NULL) {
22 pr_debug("thread_map__new\n"); 14 pr_debug("thread_map__new\n");
23 return -1; 15 return -1;
24 } 16 }
25 17
26 memset(&attr, 0, sizeof(attr)); 18 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
27 attr.type = PERF_TYPE_TRACEPOINT;
28 attr.config = id;
29 evsel = perf_evsel__new(&attr, 0);
30 if (evsel == NULL) { 19 if (evsel == NULL) {
31 pr_debug("perf_evsel__new\n"); 20 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
32 goto out_thread_map_delete; 21 goto out_thread_map_delete;
33 } 22 }
34 23
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 32ee478905eb..c5636f36fe31 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
@@ -22,6 +23,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
22 struct perf_evsel *evsel = perf_evlist__first(evlist); 23 struct perf_evsel *evsel = perf_evlist__first(evlist);
23 24
24 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 25 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
26 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
25 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 27 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
26 TEST_ASSERT_VAL("wrong sample_type", 28 TEST_ASSERT_VAL("wrong sample_type",
27 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); 29 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
@@ -34,6 +36,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
34 struct perf_evsel *evsel; 36 struct perf_evsel *evsel;
35 37
36 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 38 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
39 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
37 40
38 list_for_each_entry(evsel, &evlist->entries, node) { 41 list_for_each_entry(evsel, &evlist->entries, node) {
39 TEST_ASSERT_VAL("wrong type", 42 TEST_ASSERT_VAL("wrong type",
@@ -463,10 +466,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
463 466
464static int test__checkterms_simple(struct list_head *terms) 467static int test__checkterms_simple(struct list_head *terms)
465{ 468{
466 struct parse_events__term *term; 469 struct parse_events_term *term;
467 470
468 /* config=10 */ 471 /* config=10 */
469 term = list_entry(terms->next, struct parse_events__term, list); 472 term = list_entry(terms->next, struct parse_events_term, list);
470 TEST_ASSERT_VAL("wrong type term", 473 TEST_ASSERT_VAL("wrong type term",
471 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); 474 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
472 TEST_ASSERT_VAL("wrong type val", 475 TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +478,7 @@ static int test__checkterms_simple(struct list_head *terms)
475 TEST_ASSERT_VAL("wrong config", !term->config); 478 TEST_ASSERT_VAL("wrong config", !term->config);
476 479
477 /* config1 */ 480 /* config1 */
478 term = list_entry(term->list.next, struct parse_events__term, list); 481 term = list_entry(term->list.next, struct parse_events_term, list);
479 TEST_ASSERT_VAL("wrong type term", 482 TEST_ASSERT_VAL("wrong type term",
480 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); 483 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
481 TEST_ASSERT_VAL("wrong type val", 484 TEST_ASSERT_VAL("wrong type val",
@@ -484,7 +487,7 @@ static int test__checkterms_simple(struct list_head *terms)
484 TEST_ASSERT_VAL("wrong config", !term->config); 487 TEST_ASSERT_VAL("wrong config", !term->config);
485 488
486 /* config2=3 */ 489 /* config2=3 */
487 term = list_entry(term->list.next, struct parse_events__term, list); 490 term = list_entry(term->list.next, struct parse_events_term, list);
488 TEST_ASSERT_VAL("wrong type term", 491 TEST_ASSERT_VAL("wrong type term",
489 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); 492 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
490 TEST_ASSERT_VAL("wrong type val", 493 TEST_ASSERT_VAL("wrong type val",
@@ -493,7 +496,7 @@ static int test__checkterms_simple(struct list_head *terms)
493 TEST_ASSERT_VAL("wrong config", !term->config); 496 TEST_ASSERT_VAL("wrong config", !term->config);
494 497
495 /* umask=1*/ 498 /* umask=1*/
496 term = list_entry(term->list.next, struct parse_events__term, list); 499 term = list_entry(term->list.next, struct parse_events_term, list);
497 TEST_ASSERT_VAL("wrong type term", 500 TEST_ASSERT_VAL("wrong type term",
498 term->type_term == PARSE_EVENTS__TERM_TYPE_USER); 501 term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
499 TEST_ASSERT_VAL("wrong type val", 502 TEST_ASSERT_VAL("wrong type val",
@@ -509,6 +512,7 @@ static int test__group1(struct perf_evlist *evlist)
509 struct perf_evsel *evsel, *leader; 512 struct perf_evsel *evsel, *leader;
510 513
511 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 514 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
515 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
512 516
513 /* instructions:k */ 517 /* instructions:k */
514 evsel = leader = perf_evlist__first(evlist); 518 evsel = leader = perf_evlist__first(evlist);
@@ -521,7 +525,9 @@ static int test__group1(struct perf_evlist *evlist)
521 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 525 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
522 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 526 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
523 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 527 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
524 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 528 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
529 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
530 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
525 531
526 /* cycles:upp */ 532 /* cycles:upp */
527 evsel = perf_evsel__next(evsel); 533 evsel = perf_evsel__next(evsel);
@@ -536,6 +542,7 @@ static int test__group1(struct perf_evlist *evlist)
536 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 542 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
537 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 543 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
538 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 544 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
545 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
539 546
540 return 0; 547 return 0;
541} 548}
@@ -545,6 +552,7 @@ static int test__group2(struct perf_evlist *evlist)
545 struct perf_evsel *evsel, *leader; 552 struct perf_evsel *evsel, *leader;
546 553
547 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); 554 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
555 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
548 556
549 /* faults + :ku modifier */ 557 /* faults + :ku modifier */
550 evsel = leader = perf_evlist__first(evlist); 558 evsel = leader = perf_evlist__first(evlist);
@@ -557,7 +565,9 @@ static int test__group2(struct perf_evlist *evlist)
557 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 565 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
558 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 566 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
559 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 567 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
560 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 568 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
570 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
561 571
562 /* cache-references + :u modifier */ 572 /* cache-references + :u modifier */
563 evsel = perf_evsel__next(evsel); 573 evsel = perf_evsel__next(evsel);
@@ -567,10 +577,11 @@ static int test__group2(struct perf_evlist *evlist)
567 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 577 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
568 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 578 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
569 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 579 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
570 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 580 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
571 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 581 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
572 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 582 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
573 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 583 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
584 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
574 585
575 /* cycles:k */ 586 /* cycles:k */
576 evsel = perf_evsel__next(evsel); 587 evsel = perf_evsel__next(evsel);
@@ -583,7 +594,7 @@ static int test__group2(struct perf_evlist *evlist)
583 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 594 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
584 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 595 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
585 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 596 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
586 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 597 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
587 598
588 return 0; 599 return 0;
589} 600}
@@ -593,6 +604,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
593 struct perf_evsel *evsel, *leader; 604 struct perf_evsel *evsel, *leader;
594 605
595 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 606 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
607 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
596 608
597 /* group1 syscalls:sys_enter_open:H */ 609 /* group1 syscalls:sys_enter_open:H */
598 evsel = leader = perf_evlist__first(evlist); 610 evsel = leader = perf_evlist__first(evlist);
@@ -606,9 +618,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
606 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 618 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
607 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 619 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
608 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 620 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
609 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 621 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
610 TEST_ASSERT_VAL("wrong group name", 622 TEST_ASSERT_VAL("wrong group name",
611 !strcmp(leader->group_name, "group1")); 623 !strcmp(leader->group_name, "group1"));
624 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
625 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
612 626
613 /* group1 cycles:kppp */ 627 /* group1 cycles:kppp */
614 evsel = perf_evsel__next(evsel); 628 evsel = perf_evsel__next(evsel);
@@ -624,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
624 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); 638 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
625 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 639 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
626 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 640 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
641 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
627 642
628 /* group2 cycles + G modifier */ 643 /* group2 cycles + G modifier */
629 evsel = leader = perf_evsel__next(evsel); 644 evsel = leader = perf_evsel__next(evsel);
@@ -636,9 +651,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
636 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 651 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
637 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 652 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
638 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 653 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
639 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 654 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
640 TEST_ASSERT_VAL("wrong group name", 655 TEST_ASSERT_VAL("wrong group name",
641 !strcmp(leader->group_name, "group2")); 656 !strcmp(leader->group_name, "group2"));
657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
642 659
643 /* group2 1:3 + G modifier */ 660 /* group2 1:3 + G modifier */
644 evsel = perf_evsel__next(evsel); 661 evsel = perf_evsel__next(evsel);
@@ -651,6 +668,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
651 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 668 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
652 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 669 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
653 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 670 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
671 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
654 672
655 /* instructions:u */ 673 /* instructions:u */
656 evsel = perf_evsel__next(evsel); 674 evsel = perf_evsel__next(evsel);
@@ -663,7 +681,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
663 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 681 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
664 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 682 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
665 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 683 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
666 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 684 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
667 685
668 return 0; 686 return 0;
669} 687}
@@ -673,6 +691,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
673 struct perf_evsel *evsel, *leader; 691 struct perf_evsel *evsel, *leader;
674 692
675 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 693 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
694 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
676 695
677 /* cycles:u + p */ 696 /* cycles:u + p */
678 evsel = leader = perf_evlist__first(evlist); 697 evsel = leader = perf_evlist__first(evlist);
@@ -687,7 +706,9 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
687 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 706 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
688 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); 707 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
689 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 708 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
690 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 709 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
710 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
711 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
691 712
692 /* instructions:kp + p */ 713 /* instructions:kp + p */
693 evsel = perf_evsel__next(evsel); 714 evsel = perf_evsel__next(evsel);
@@ -702,6 +723,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
702 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 723 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
703 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 724 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
704 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 725 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
726 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
705 727
706 return 0; 728 return 0;
707} 729}
@@ -711,6 +733,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
711 struct perf_evsel *evsel, *leader; 733 struct perf_evsel *evsel, *leader;
712 734
713 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 735 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
736 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
714 737
715 /* cycles + G */ 738 /* cycles + G */
716 evsel = leader = perf_evlist__first(evlist); 739 evsel = leader = perf_evlist__first(evlist);
@@ -724,7 +747,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
724 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 747 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
725 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 748 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
726 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 749 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
727 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 750 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
751 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
752 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
728 753
729 /* instructions + G */ 754 /* instructions + G */
730 evsel = perf_evsel__next(evsel); 755 evsel = perf_evsel__next(evsel);
@@ -738,6 +763,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
738 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 763 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
739 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 764 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
740 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 765 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
766 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
741 767
742 /* cycles:G */ 768 /* cycles:G */
743 evsel = leader = perf_evsel__next(evsel); 769 evsel = leader = perf_evsel__next(evsel);
@@ -751,7 +777,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
751 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 777 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
752 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 778 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
753 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 779 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
754 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 780 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
781 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
782 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
755 783
756 /* instructions:G */ 784 /* instructions:G */
757 evsel = perf_evsel__next(evsel); 785 evsel = perf_evsel__next(evsel);
@@ -765,6 +793,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
765 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 793 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
766 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 794 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
767 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 795 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
796 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
768 797
769 /* cycles */ 798 /* cycles */
770 evsel = perf_evsel__next(evsel); 799 evsel = perf_evsel__next(evsel);
@@ -777,18 +806,235 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
777 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 806 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
778 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 807 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
779 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 808 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
780 TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel)); 809 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
810
811 return 0;
812}
813
814static int test__group_gh1(struct perf_evlist *evlist)
815{
816 struct perf_evsel *evsel, *leader;
817
818 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
819 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
820
821 /* cycles + :H group modifier */
822 evsel = leader = perf_evlist__first(evlist);
823 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
824 TEST_ASSERT_VAL("wrong config",
825 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
826 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
827 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
828 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
829 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
830 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
831 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
832 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
833 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
834 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
835 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
836
837 /* cache-misses:G + :H group modifier */
838 evsel = perf_evsel__next(evsel);
839 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
840 TEST_ASSERT_VAL("wrong config",
841 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
842 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
843 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
844 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
845 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
846 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
847 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
848 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
849 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
850
851 return 0;
852}
853
854static int test__group_gh2(struct perf_evlist *evlist)
855{
856 struct perf_evsel *evsel, *leader;
857
858 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
859 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
860
861 /* cycles + :G group modifier */
862 evsel = leader = perf_evlist__first(evlist);
863 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
864 TEST_ASSERT_VAL("wrong config",
865 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
866 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
867 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
868 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
869 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
870 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
871 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
872 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
873 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
874 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
875 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
876
877 /* cache-misses:H + :G group modifier */
878 evsel = perf_evsel__next(evsel);
879 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
880 TEST_ASSERT_VAL("wrong config",
881 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
882 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
883 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
884 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
885 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
886 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
887 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
888 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
889 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
890
891 return 0;
892}
893
894static int test__group_gh3(struct perf_evlist *evlist)
895{
896 struct perf_evsel *evsel, *leader;
897
898 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
899 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
900
901 /* cycles:G + :u group modifier */
902 evsel = leader = perf_evlist__first(evlist);
903 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
904 TEST_ASSERT_VAL("wrong config",
905 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
906 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
907 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
908 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
909 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
910 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
911 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
912 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
913 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
914 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
915 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
916
917 /* cache-misses:H + :u group modifier */
918 evsel = perf_evsel__next(evsel);
919 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
920 TEST_ASSERT_VAL("wrong config",
921 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
922 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
923 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
924 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
925 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
926 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
927 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
928 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
929 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
930
931 return 0;
932}
933
934static int test__group_gh4(struct perf_evlist *evlist)
935{
936 struct perf_evsel *evsel, *leader;
937
938 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
939 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
940
941 /* cycles:G + :uG group modifier */
942 evsel = leader = perf_evlist__first(evlist);
943 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
944 TEST_ASSERT_VAL("wrong config",
945 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
946 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
947 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
948 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
949 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
950 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
951 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
952 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
953 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
954 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
955 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
956
957 /* cache-misses:H + :uG group modifier */
958 evsel = perf_evsel__next(evsel);
959 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
960 TEST_ASSERT_VAL("wrong config",
961 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
962 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
963 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
964 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
965 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
966 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
967 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
968 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
969 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
781 970
782 return 0; 971 return 0;
783} 972}
784 973
785struct test__event_st { 974static int count_tracepoints(void)
975{
976 char events_path[PATH_MAX];
977 struct dirent *events_ent;
978 DIR *events_dir;
979 int cnt = 0;
980
981 scnprintf(events_path, PATH_MAX, "%s/tracing/events",
982 debugfs_find_mountpoint());
983
984 events_dir = opendir(events_path);
985
986 TEST_ASSERT_VAL("Can't open events dir", events_dir);
987
988 while ((events_ent = readdir(events_dir))) {
989 char sys_path[PATH_MAX];
990 struct dirent *sys_ent;
991 DIR *sys_dir;
992
993 if (!strcmp(events_ent->d_name, ".")
994 || !strcmp(events_ent->d_name, "..")
995 || !strcmp(events_ent->d_name, "enable")
996 || !strcmp(events_ent->d_name, "header_event")
997 || !strcmp(events_ent->d_name, "header_page"))
998 continue;
999
1000 scnprintf(sys_path, PATH_MAX, "%s/%s",
1001 events_path, events_ent->d_name);
1002
1003 sys_dir = opendir(sys_path);
1004 TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
1005
1006 while ((sys_ent = readdir(sys_dir))) {
1007 if (!strcmp(sys_ent->d_name, ".")
1008 || !strcmp(sys_ent->d_name, "..")
1009 || !strcmp(sys_ent->d_name, "enable")
1010 || !strcmp(sys_ent->d_name, "filter"))
1011 continue;
1012
1013 cnt++;
1014 }
1015
1016 closedir(sys_dir);
1017 }
1018
1019 closedir(events_dir);
1020 return cnt;
1021}
1022
1023static int test__all_tracepoints(struct perf_evlist *evlist)
1024{
1025 TEST_ASSERT_VAL("wrong events count",
1026 count_tracepoints() == evlist->nr_entries);
1027
1028 return test__checkevent_tracepoint_multi(evlist);
1029}
1030
1031struct evlist_test {
786 const char *name; 1032 const char *name;
787 __u32 type; 1033 __u32 type;
788 int (*check)(struct perf_evlist *evlist); 1034 int (*check)(struct perf_evlist *evlist);
789}; 1035};
790 1036
791static struct test__event_st test__events[] = { 1037static struct evlist_test test__events[] = {
792 [0] = { 1038 [0] = {
793 .name = "syscalls:sys_enter_open", 1039 .name = "syscalls:sys_enter_open",
794 .check = test__checkevent_tracepoint, 1040 .check = test__checkevent_tracepoint,
@@ -921,9 +1167,29 @@ static struct test__event_st test__events[] = {
921 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 1167 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
922 .check = test__group5, 1168 .check = test__group5,
923 }, 1169 },
1170 [33] = {
1171 .name = "*:*",
1172 .check = test__all_tracepoints,
1173 },
1174 [34] = {
1175 .name = "{cycles,cache-misses:G}:H",
1176 .check = test__group_gh1,
1177 },
1178 [35] = {
1179 .name = "{cycles,cache-misses:H}:G",
1180 .check = test__group_gh2,
1181 },
1182 [36] = {
1183 .name = "{cycles:G,cache-misses:H}:u",
1184 .check = test__group_gh3,
1185 },
1186 [37] = {
1187 .name = "{cycles:G,cache-misses:H}:uG",
1188 .check = test__group_gh4,
1189 },
924}; 1190};
925 1191
926static struct test__event_st test__events_pmu[] = { 1192static struct evlist_test test__events_pmu[] = {
927 [0] = { 1193 [0] = {
928 .name = "cpu/config=10,config1,config2=3,period=1000/u", 1194 .name = "cpu/config=10,config1,config2=3,period=1000/u",
929 .check = test__checkevent_pmu, 1195 .check = test__checkevent_pmu,
@@ -934,20 +1200,20 @@ static struct test__event_st test__events_pmu[] = {
934 }, 1200 },
935}; 1201};
936 1202
937struct test__term { 1203struct terms_test {
938 const char *str; 1204 const char *str;
939 __u32 type; 1205 __u32 type;
940 int (*check)(struct list_head *terms); 1206 int (*check)(struct list_head *terms);
941}; 1207};
942 1208
943static struct test__term test__terms[] = { 1209static struct terms_test test__terms[] = {
944 [0] = { 1210 [0] = {
945 .str = "config=10,config1,config2=3,umask=1", 1211 .str = "config=10,config1,config2=3,umask=1",
946 .check = test__checkterms_simple, 1212 .check = test__checkterms_simple,
947 }, 1213 },
948}; 1214};
949 1215
950static int test_event(struct test__event_st *e) 1216static int test_event(struct evlist_test *e)
951{ 1217{
952 struct perf_evlist *evlist; 1218 struct perf_evlist *evlist;
953 int ret; 1219 int ret;
@@ -956,7 +1222,7 @@ static int test_event(struct test__event_st *e)
956 if (evlist == NULL) 1222 if (evlist == NULL)
957 return -ENOMEM; 1223 return -ENOMEM;
958 1224
959 ret = parse_events(evlist, e->name, 0); 1225 ret = parse_events(evlist, e->name);
960 if (ret) { 1226 if (ret) {
961 pr_debug("failed to parse event '%s', err %d\n", 1227 pr_debug("failed to parse event '%s', err %d\n",
962 e->name, ret); 1228 e->name, ret);
@@ -969,13 +1235,13 @@ static int test_event(struct test__event_st *e)
969 return ret; 1235 return ret;
970} 1236}
971 1237
972static int test_events(struct test__event_st *events, unsigned cnt) 1238static int test_events(struct evlist_test *events, unsigned cnt)
973{ 1239{
974 int ret1, ret2 = 0; 1240 int ret1, ret2 = 0;
975 unsigned i; 1241 unsigned i;
976 1242
977 for (i = 0; i < cnt; i++) { 1243 for (i = 0; i < cnt; i++) {
978 struct test__event_st *e = &events[i]; 1244 struct evlist_test *e = &events[i];
979 1245
980 pr_debug("running test %d '%s'\n", i, e->name); 1246 pr_debug("running test %d '%s'\n", i, e->name);
981 ret1 = test_event(e); 1247 ret1 = test_event(e);
@@ -986,7 +1252,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
986 return ret2; 1252 return ret2;
987} 1253}
988 1254
989static int test_term(struct test__term *t) 1255static int test_term(struct terms_test *t)
990{ 1256{
991 struct list_head *terms; 1257 struct list_head *terms;
992 int ret; 1258 int ret;
@@ -1010,13 +1276,13 @@ static int test_term(struct test__term *t)
1010 return ret; 1276 return ret;
1011} 1277}
1012 1278
1013static int test_terms(struct test__term *terms, unsigned cnt) 1279static int test_terms(struct terms_test *terms, unsigned cnt)
1014{ 1280{
1015 int ret = 0; 1281 int ret = 0;
1016 unsigned i; 1282 unsigned i;
1017 1283
1018 for (i = 0; i < cnt; i++) { 1284 for (i = 0; i < cnt; i++) {
1019 struct test__term *t = &terms[i]; 1285 struct terms_test *t = &terms[i];
1020 1286
1021 pr_debug("running test %d '%s'\n", i, t->str); 1287 pr_debug("running test %d '%s'\n", i, t->str);
1022 ret = test_term(t); 1288 ret = test_term(t);
@@ -1067,7 +1333,7 @@ static int test_pmu_events(void)
1067 1333
1068 while (!ret && (ent = readdir(dir))) { 1334 while (!ret && (ent = readdir(dir))) {
1069#define MAX_NAME 100 1335#define MAX_NAME 100
1070 struct test__event_st e; 1336 struct evlist_test e;
1071 char name[MAX_NAME]; 1337 char name[MAX_NAME];
1072 1338
1073 if (!strcmp(ent->d_name, ".") || 1339 if (!strcmp(ent->d_name, ".") ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 70e0d4421df8..1e8e5128d0da 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -96,22 +96,22 @@ int test__PERF_RECORD(void)
96 err = perf_evlist__prepare_workload(evlist, &opts, argv); 96 err = perf_evlist__prepare_workload(evlist, &opts, argv);
97 if (err < 0) { 97 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n"); 98 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_evlist; 99 goto out_delete_maps;
100 } 100 }
101 101
102 /* 102 /*
103 * Config the evsels, setting attr->comm on the first one, etc. 103 * Config the evsels, setting attr->comm on the first one, etc.
104 */ 104 */
105 evsel = perf_evlist__first(evlist); 105 evsel = perf_evlist__first(evlist);
106 evsel->attr.sample_type |= PERF_SAMPLE_CPU; 106 perf_evsel__set_sample_bit(evsel, CPU);
107 evsel->attr.sample_type |= PERF_SAMPLE_TID; 107 perf_evsel__set_sample_bit(evsel, TID);
108 evsel->attr.sample_type |= PERF_SAMPLE_TIME; 108 perf_evsel__set_sample_bit(evsel, TIME);
109 perf_evlist__config_attrs(evlist, &opts); 109 perf_evlist__config(evlist, &opts);
110 110
111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
112 if (err < 0) { 112 if (err < 0) {
113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
114 goto out_delete_evlist; 114 goto out_delete_maps;
115 } 115 }
116 116
117 cpu = err; 117 cpu = err;
@@ -121,7 +121,7 @@ int test__PERF_RECORD(void)
121 */ 121 */
122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
123 pr_debug("sched_setaffinity: %s\n", strerror(errno)); 123 pr_debug("sched_setaffinity: %s\n", strerror(errno));
124 goto out_delete_evlist; 124 goto out_delete_maps;
125 } 125 }
126 126
127 /* 127 /*
@@ -131,7 +131,7 @@ int test__PERF_RECORD(void)
131 err = perf_evlist__open(evlist); 131 err = perf_evlist__open(evlist);
132 if (err < 0) { 132 if (err < 0) {
133 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 133 pr_debug("perf_evlist__open: %s\n", strerror(errno));
134 goto out_delete_evlist; 134 goto out_delete_maps;
135 } 135 }
136 136
137 /* 137 /*
@@ -142,7 +142,7 @@ int test__PERF_RECORD(void)
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) { 143 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_evlist; 145 goto out_delete_maps;
146 } 146 }
147 147
148 /* 148 /*
@@ -305,6 +305,8 @@ found_exit:
305 } 305 }
306out_err: 306out_err:
307 perf_evlist__munmap(evlist); 307 perf_evlist__munmap(evlist);
308out_delete_maps:
309 perf_evlist__delete_maps(evlist);
308out_delete_evlist: 310out_delete_evlist:
309 perf_evlist__delete(evlist); 311 perf_evlist__delete(evlist);
310out: 312out:
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 fc121edab016..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,8 +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);
18 24int test__hists_link(void);
19/* Util */ 25int test__python_use(void);
20int trace_event__id(const char *evname);
21 26
22#endif /* TESTS_H */ 27#endif /* TESTS_H */
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
deleted file mode 100644
index 748f2e8f6961..000000000000
--- a/tools/perf/tests/util.c
+++ /dev/null
@@ -1,30 +0,0 @@
1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include "tests.h"
8#include "debugfs.h"
9
10int trace_event__id(const char *evname)
11{
12 char *filename;
13 int err = -1, fd;
14
15 if (asprintf(&filename,
16 "%s/syscalls/%s/id",
17 tracing_events_path, evname) < 0)
18 return -1;
19
20 fd = open(filename, O_RDONLY);
21 if (fd >= 0) {
22 char id[16];
23 if (read(fd, id, sizeof(id)) > 0)
24 err = atoi(id);
25 close(fd);
26 }
27
28 free(filename);
29 return err;
30}
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 0d1cdbee2f59..7b4c4d26d1ba 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -44,7 +44,7 @@ int test__vmlinux_matches_kallsyms(void)
44 */ 44 */
45 if (machine__create_kernel_maps(&kallsyms) < 0) { 45 if (machine__create_kernel_maps(&kallsyms) < 0) {
46 pr_debug("machine__create_kernel_maps "); 46 pr_debug("machine__create_kernel_maps ");
47 return -1; 47 goto out;
48 } 48 }
49 49
50 /* 50 /*
@@ -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
@@ -226,5 +227,7 @@ detour:
226 map__fprintf(pos, stderr); 227 map__fprintf(pos, stderr);
227 } 228 }
228out: 229out:
230 machine__exit(&kallsyms);
231 machine__exit(&vmlinux);
229 return err; 232 return err;
230} 233}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 4aeb7d5df939..809ea4632a34 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -273,6 +273,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused)
273{ 273{
274 pthread_mutex_lock(&ui__lock); 274 pthread_mutex_lock(&ui__lock);
275 ui_helpline__pop(); 275 ui_helpline__pop();
276 free(browser->helpline);
277 browser->helpline = NULL;
276 pthread_mutex_unlock(&ui__lock); 278 pthread_mutex_unlock(&ui__lock);
277} 279}
278 280
@@ -471,7 +473,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
471 return row; 473 return row;
472} 474}
473 475
474static struct ui_browser__colorset { 476static struct ui_browser_colorset {
475 const char *name, *fg, *bg; 477 const char *name, *fg, *bg;
476 int colorset; 478 int colorset;
477} ui_browser__colorsets[] = { 479} ui_browser__colorsets[] = {
@@ -706,7 +708,7 @@ void ui_browser__init(void)
706 perf_config(ui_browser__color_config, NULL); 708 perf_config(ui_browser__color_config, NULL);
707 709
708 while (ui_browser__colorsets[i].name) { 710 while (ui_browser__colorsets[i].name) {
709 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 711 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
710 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 712 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
711 } 713 }
712 714
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/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index ccc4bd161420..aa22704047d6 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -567,26 +567,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
567 return row - first_row; 567 return row - first_row;
568} 568}
569 569
570#define HPP__COLOR_FN(_name, _field) \ 570struct hpp_arg {
571static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ 571 struct ui_browser *b;
572 struct hist_entry *he) \ 572 char folded_sign;
573 bool current_entry;
574};
575
576static int __hpp__color_callchain(struct hpp_arg *arg)
577{
578 if (!symbol_conf.use_callchain)
579 return 0;
580
581 slsmg_printf("%c ", arg->folded_sign);
582 return 2;
583}
584
585static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
586 u64 (*get_field)(struct hist_entry *),
587 int (*callchain_cb)(struct hpp_arg *))
588{
589 int ret = 0;
590 double percent = 0.0;
591 struct hists *hists = he->hists;
592 struct hpp_arg *arg = hpp->ptr;
593
594 if (hists->stats.total_period)
595 percent = 100.0 * get_field(he) / hists->stats.total_period;
596
597 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
598
599 if (callchain_cb)
600 ret += callchain_cb(arg);
601
602 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
603 slsmg_printf("%s", hpp->buf);
604
605 if (symbol_conf.event_group) {
606 int prev_idx, idx_delta;
607 struct perf_evsel *evsel = hists_to_evsel(hists);
608 struct hist_entry *pair;
609 int nr_members = evsel->nr_members;
610
611 if (nr_members <= 1)
612 goto out;
613
614 prev_idx = perf_evsel__group_idx(evsel);
615
616 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
617 u64 period = get_field(pair);
618 u64 total = pair->hists->stats.total_period;
619
620 if (!total)
621 continue;
622
623 evsel = hists_to_evsel(pair->hists);
624 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
625
626 while (idx_delta--) {
627 /*
628 * zero-fill group members in the middle which
629 * have no sample
630 */
631 ui_browser__set_percent_color(arg->b, 0.0,
632 arg->current_entry);
633 ret += scnprintf(hpp->buf, hpp->size,
634 " %6.2f%%", 0.0);
635 slsmg_printf("%s", hpp->buf);
636 }
637
638 percent = 100.0 * period / total;
639 ui_browser__set_percent_color(arg->b, percent,
640 arg->current_entry);
641 ret += scnprintf(hpp->buf, hpp->size,
642 " %6.2f%%", percent);
643 slsmg_printf("%s", hpp->buf);
644
645 prev_idx = perf_evsel__group_idx(evsel);
646 }
647
648 idx_delta = nr_members - prev_idx - 1;
649
650 while (idx_delta--) {
651 /*
652 * zero-fill group members at last which have no sample
653 */
654 ui_browser__set_percent_color(arg->b, 0.0,
655 arg->current_entry);
656 ret += scnprintf(hpp->buf, hpp->size,
657 " %6.2f%%", 0.0);
658 slsmg_printf("%s", hpp->buf);
659 }
660 }
661out:
662 if (!arg->current_entry || !arg->b->navkeypressed)
663 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
664
665 return ret;
666}
667
668#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
669static u64 __hpp_get_##_field(struct hist_entry *he) \
670{ \
671 return he->stat._field; \
672} \
673 \
674static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
675 struct hist_entry *he) \
573{ \ 676{ \
574 struct hists *hists = he->hists; \ 677 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
575 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
576 *(double *)hpp->ptr = percent; \
577 return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
578} 678}
579 679
580HPP__COLOR_FN(overhead, period) 680__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
581HPP__COLOR_FN(overhead_sys, period_sys) 681__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
582HPP__COLOR_FN(overhead_us, period_us) 682__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
583HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) 683__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
584HPP__COLOR_FN(overhead_guest_us, period_guest_us) 684__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
585 685
586#undef HPP__COLOR_FN 686#undef __HPP_COLOR_PERCENT_FN
587 687
588void hist_browser__init_hpp(void) 688void hist_browser__init_hpp(void)
589{ 689{
690 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
691
590 perf_hpp__init(); 692 perf_hpp__init();
591 693
592 perf_hpp__format[PERF_HPP__OVERHEAD].color = 694 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -606,13 +708,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
606 unsigned short row) 708 unsigned short row)
607{ 709{
608 char s[256]; 710 char s[256];
609 double percent; 711 int printed = 0;
610 int i, printed = 0;
611 int width = browser->b.width; 712 int width = browser->b.width;
612 char folded_sign = ' '; 713 char folded_sign = ' ';
613 bool current_entry = ui_browser__is_current_entry(&browser->b, row); 714 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
614 off_t row_offset = entry->row_offset; 715 off_t row_offset = entry->row_offset;
615 bool first = true; 716 bool first = true;
717 struct perf_hpp_fmt *fmt;
616 718
617 if (current_entry) { 719 if (current_entry) {
618 browser->he_selection = entry; 720 browser->he_selection = entry;
@@ -625,41 +727,30 @@ static int hist_browser__show_entry(struct hist_browser *browser,
625 } 727 }
626 728
627 if (row_offset == 0) { 729 if (row_offset == 0) {
730 struct hpp_arg arg = {
731 .b = &browser->b,
732 .folded_sign = folded_sign,
733 .current_entry = current_entry,
734 };
628 struct perf_hpp hpp = { 735 struct perf_hpp hpp = {
629 .buf = s, 736 .buf = s,
630 .size = sizeof(s), 737 .size = sizeof(s),
738 .ptr = &arg,
631 }; 739 };
632 740
633 ui_browser__gotorc(&browser->b, row, 0); 741 ui_browser__gotorc(&browser->b, row, 0);
634 742
635 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 743 perf_hpp__for_each_format(fmt) {
636 if (!perf_hpp__format[i].cond)
637 continue;
638
639 if (!first) { 744 if (!first) {
640 slsmg_printf(" "); 745 slsmg_printf(" ");
641 width -= 2; 746 width -= 2;
642 } 747 }
643 first = false; 748 first = false;
644 749
645 if (perf_hpp__format[i].color) { 750 if (fmt->color) {
646 hpp.ptr = &percent; 751 width -= fmt->color(&hpp, entry);
647 /* It will set percent for us. See HPP__COLOR_FN above. */
648 width -= perf_hpp__format[i].color(&hpp, entry);
649
650 ui_browser__set_percent_color(&browser->b, percent, current_entry);
651
652 if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
653 slsmg_printf("%c ", folded_sign);
654 width -= 2;
655 }
656
657 slsmg_printf("%s", s);
658
659 if (!current_entry || !browser->b.navkeypressed)
660 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
661 } else { 752 } else {
662 width -= perf_hpp__format[i].entry(&hpp, entry); 753 width -= fmt->entry(&hpp, entry);
663 slsmg_printf("%s", s); 754 slsmg_printf("%s", s);
664 } 755 }
665 } 756 }
@@ -1098,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1098 const struct thread *thread = hists->thread_filter; 1189 const struct thread *thread = hists->thread_filter;
1099 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1190 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1100 u64 nr_events = hists->stats.total_period; 1191 u64 nr_events = hists->stats.total_period;
1192 struct perf_evsel *evsel = hists_to_evsel(hists);
1193 char buf[512];
1194 size_t buflen = sizeof(buf);
1195
1196 if (symbol_conf.event_group && evsel->nr_members > 1) {
1197 struct perf_evsel *pos;
1198
1199 perf_evsel__group_desc(evsel, buf, buflen);
1200 ev_name = buf;
1201
1202 for_each_group_member(pos, evsel) {
1203 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1204 nr_events += pos->hists.stats.total_period;
1205 }
1206 }
1101 1207
1102 nr_samples = convert_unit(nr_samples, &unit); 1208 nr_samples = convert_unit(nr_samples, &unit);
1103 printed = scnprintf(bf, size, 1209 printed = scnprintf(bf, size,
@@ -1135,6 +1241,96 @@ static inline bool is_report_browser(void *timer)
1135 return timer == NULL; 1241 return timer == NULL;
1136} 1242}
1137 1243
1244/*
1245 * Only runtime switching of perf data file will make "input_name" point
1246 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1247 * whether we need to call free() for current "input_name" during the switch.
1248 */
1249static bool is_input_name_malloced = false;
1250
1251static int switch_data_file(void)
1252{
1253 char *pwd, *options[32], *abs_path[32], *tmp;
1254 DIR *pwd_dir;
1255 int nr_options = 0, choice = -1, ret = -1;
1256 struct dirent *dent;
1257
1258 pwd = getenv("PWD");
1259 if (!pwd)
1260 return ret;
1261
1262 pwd_dir = opendir(pwd);
1263 if (!pwd_dir)
1264 return ret;
1265
1266 memset(options, 0, sizeof(options));
1267 memset(options, 0, sizeof(abs_path));
1268
1269 while ((dent = readdir(pwd_dir))) {
1270 char path[PATH_MAX];
1271 u64 magic;
1272 char *name = dent->d_name;
1273 FILE *file;
1274
1275 if (!(dent->d_type == DT_REG))
1276 continue;
1277
1278 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1279
1280 file = fopen(path, "r");
1281 if (!file)
1282 continue;
1283
1284 if (fread(&magic, 1, 8, file) < 8)
1285 goto close_file_and_continue;
1286
1287 if (is_perf_magic(magic)) {
1288 options[nr_options] = strdup(name);
1289 if (!options[nr_options])
1290 goto close_file_and_continue;
1291
1292 abs_path[nr_options] = strdup(path);
1293 if (!abs_path[nr_options]) {
1294 free(options[nr_options]);
1295 ui__warning("Can't search all data files due to memory shortage.\n");
1296 fclose(file);
1297 break;
1298 }
1299
1300 nr_options++;
1301 }
1302
1303close_file_and_continue:
1304 fclose(file);
1305 if (nr_options >= 32) {
1306 ui__warning("Too many perf data files in PWD!\n"
1307 "Only the first 32 files will be listed.\n");
1308 break;
1309 }
1310 }
1311 closedir(pwd_dir);
1312
1313 if (nr_options) {
1314 choice = ui__popup_menu(nr_options, options);
1315 if (choice < nr_options && choice >= 0) {
1316 tmp = strdup(abs_path[choice]);
1317 if (tmp) {
1318 if (is_input_name_malloced)
1319 free((void *)input_name);
1320 input_name = tmp;
1321 is_input_name_malloced = true;
1322 ret = 0;
1323 } else
1324 ui__warning("Data switch failed due to memory shortage!\n");
1325 }
1326 }
1327
1328 free_popup_options(options, nr_options);
1329 free_popup_options(abs_path, nr_options);
1330 return ret;
1331}
1332
1333
1138static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1334static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1139 const char *helpline, const char *ev_name, 1335 const char *helpline, const char *ev_name,
1140 bool left_exits, 1336 bool left_exits,
@@ -1169,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1169 int choice = 0, 1365 int choice = 0,
1170 annotate = -2, zoom_dso = -2, zoom_thread = -2, 1366 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1171 annotate_f = -2, annotate_t = -2, browse_map = -2; 1367 annotate_f = -2, annotate_t = -2, browse_map = -2;
1172 int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; 1368 int scripts_comm = -2, scripts_symbol = -2,
1369 scripts_all = -2, switch_data = -2;
1173 1370
1174 nr_options = 0; 1371 nr_options = 0;
1175 1372
@@ -1226,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1226 if (is_report_browser(hbt)) 1423 if (is_report_browser(hbt))
1227 goto do_scripts; 1424 goto do_scripts;
1228 continue; 1425 continue;
1426 case 's':
1427 if (is_report_browser(hbt))
1428 goto do_data_switch;
1429 continue;
1229 case K_F1: 1430 case K_F1:
1230 case 'h': 1431 case 'h':
1231 case '?': 1432 case '?':
@@ -1245,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1245 "d Zoom into current DSO\n" 1446 "d Zoom into current DSO\n"
1246 "t Zoom into current Thread\n" 1447 "t Zoom into current Thread\n"
1247 "r Run available scripts('perf report' only)\n" 1448 "r Run available scripts('perf report' only)\n"
1449 "s Switch to another data file in PWD ('perf report' only)\n"
1248 "P Print histograms to perf.hist.N\n" 1450 "P Print histograms to perf.hist.N\n"
1249 "V Verbose (DSO names in callchains, etc)\n" 1451 "V Verbose (DSO names in callchains, etc)\n"
1250 "/ Filter symbol by name"); 1452 "/ Filter symbol by name");
@@ -1352,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1352 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) 1554 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1353 scripts_all = nr_options++; 1555 scripts_all = nr_options++;
1354 1556
1557 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1558 "Switch to another data file in PWD") > 0)
1559 switch_data = nr_options++;
1355add_exit_option: 1560add_exit_option:
1356 options[nr_options++] = (char *)"Exit"; 1561 options[nr_options++] = (char *)"Exit";
1357retry_popup_menu: 1562retry_popup_menu:
@@ -1462,6 +1667,16 @@ do_scripts:
1462 1667
1463 script_browse(script_opt); 1668 script_browse(script_opt);
1464 } 1669 }
1670 /* Switch to another data file */
1671 else if (choice == switch_data) {
1672do_data_switch:
1673 if (!switch_data_file()) {
1674 key = K_SWITCH_INPUT_DATA;
1675 break;
1676 } else
1677 ui__warning("Won't switch the data files due to\n"
1678 "no valid data file get selected!\n");
1679 }
1465 } 1680 }
1466out_free_stack: 1681out_free_stack:
1467 pstack__delete(fstack); 1682 pstack__delete(fstack);
@@ -1494,6 +1709,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1494 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1495 HE_COLORSET_NORMAL); 1710 HE_COLORSET_NORMAL);
1496 1711
1712 if (symbol_conf.event_group && evsel->nr_members > 1) {
1713 struct perf_evsel *pos;
1714
1715 ev_name = perf_evsel__group_name(evsel);
1716
1717 for_each_group_member(pos, evsel) {
1718 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1719 }
1720 }
1721
1497 nr_events = convert_unit(nr_events, &unit); 1722 nr_events = convert_unit(nr_events, &unit);
1498 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1723 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1499 unit, unit == ' ' ? "" : " ", ev_name); 1724 unit, unit == ' ' ? "" : " ", ev_name);
@@ -1578,6 +1803,7 @@ browse_hists:
1578 "Do you really want to exit?")) 1803 "Do you really want to exit?"))
1579 continue; 1804 continue;
1580 /* Fall thru */ 1805 /* Fall thru */
1806 case K_SWITCH_INPUT_DATA:
1581 case 'q': 1807 case 'q':
1582 case CTRL('c'): 1808 case CTRL('c'):
1583 goto out; 1809 goto out;
@@ -1604,8 +1830,19 @@ out:
1604 return key; 1830 return key;
1605} 1831}
1606 1832
1833static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1834 void *entry)
1835{
1836 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1837
1838 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1839 return true;
1840
1841 return false;
1842}
1843
1607static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1844static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1608 const char *help, 1845 int nr_entries, const char *help,
1609 struct hist_browser_timer *hbt, 1846 struct hist_browser_timer *hbt,
1610 struct perf_session_env *env) 1847 struct perf_session_env *env)
1611{ 1848{
@@ -1616,7 +1853,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1616 .refresh = ui_browser__list_head_refresh, 1853 .refresh = ui_browser__list_head_refresh,
1617 .seek = ui_browser__list_head_seek, 1854 .seek = ui_browser__list_head_seek,
1618 .write = perf_evsel_menu__write, 1855 .write = perf_evsel_menu__write,
1619 .nr_entries = evlist->nr_entries, 1856 .filter = filter_group_entries,
1857 .nr_entries = nr_entries,
1620 .priv = evlist, 1858 .priv = evlist,
1621 }, 1859 },
1622 .env = env, 1860 .env = env,
@@ -1632,20 +1870,37 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1632 menu.b.width = line_len; 1870 menu.b.width = line_len;
1633 } 1871 }
1634 1872
1635 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt); 1873 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
1636} 1874}
1637 1875
1638int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 1876int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1639 struct hist_browser_timer *hbt, 1877 struct hist_browser_timer *hbt,
1640 struct perf_session_env *env) 1878 struct perf_session_env *env)
1641{ 1879{
1642 if (evlist->nr_entries == 1) { 1880 int nr_entries = evlist->nr_entries;
1881
1882single_entry:
1883 if (nr_entries == 1) {
1643 struct perf_evsel *first = list_entry(evlist->entries.next, 1884 struct perf_evsel *first = list_entry(evlist->entries.next,
1644 struct perf_evsel, node); 1885 struct perf_evsel, node);
1645 const char *ev_name = perf_evsel__name(first); 1886 const char *ev_name = perf_evsel__name(first);
1646 return perf_evsel__hists_browse(first, evlist->nr_entries, help, 1887
1888 return perf_evsel__hists_browse(first, nr_entries, help,
1647 ev_name, false, hbt, env); 1889 ev_name, false, hbt, env);
1648 } 1890 }
1649 1891
1650 return __perf_evlist__tui_browse_hists(evlist, help, hbt, env); 1892 if (symbol_conf.event_group) {
1893 struct perf_evsel *pos;
1894
1895 nr_entries = 0;
1896 list_for_each_entry(pos, &evlist->entries, node)
1897 if (perf_evsel__is_group_leader(pos))
1898 nr_entries++;
1899
1900 if (nr_entries == 1)
1901 goto single_entry;
1902 }
1903
1904 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1905 hbt, env);
1651} 1906}
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
new file mode 100644
index 000000000000..7d8dc581a545
--- /dev/null
+++ b/tools/perf/ui/gtk/annotate.c
@@ -0,0 +1,229 @@
1#include "gtk.h"
2#include "util/debug.h"
3#include "util/annotate.h"
4#include "ui/helpline.h"
5
6
7enum {
8 ANN_COL__PERCENT,
9 ANN_COL__OFFSET,
10 ANN_COL__LINE,
11
12 MAX_ANN_COLS
13};
14
15static const char *const col_names[] = {
16 "Overhead",
17 "Offset",
18 "Line"
19};
20
21static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
22 struct disasm_line *dl, int evidx)
23{
24 struct sym_hist *symhist;
25 double percent = 0.0;
26 const char *markup;
27 int ret = 0;
28
29 strcpy(buf, "");
30
31 if (dl->offset == (s64) -1)
32 return 0;
33
34 symhist = annotation__histogram(symbol__annotation(sym), evidx);
35 if (!symhist->addr[dl->offset])
36 return 0;
37
38 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
39
40 markup = perf_gtk__get_percent_color(percent);
41 if (markup)
42 ret += scnprintf(buf, size, "%s", markup);
43 ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
44 if (markup)
45 ret += scnprintf(buf + ret, size - ret, "</span>");
46
47 return ret;
48}
49
50static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
51 struct map *map, struct disasm_line *dl)
52{
53 u64 start = map__rip_2objdump(map, sym->start);
54
55 strcpy(buf, "");
56
57 if (dl->offset == (s64) -1)
58 return 0;
59
60 return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
61}
62
63static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
64{
65 int ret = 0;
66 char *line = g_markup_escape_text(dl->line, -1);
67 const char *markup = "<span fgcolor='gray'>";
68
69 strcpy(buf, "");
70
71 if (!line)
72 return 0;
73
74 if (dl->offset != (s64) -1)
75 markup = NULL;
76
77 if (markup)
78 ret += scnprintf(buf, size, "%s", markup);
79 ret += scnprintf(buf + ret, size - ret, "%s", line);
80 if (markup)
81 ret += scnprintf(buf + ret, size - ret, "</span>");
82
83 g_free(line);
84 return ret;
85}
86
87static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
88 struct map *map, int evidx,
89 struct hist_browser_timer *hbt __maybe_unused)
90{
91 struct disasm_line *pos, *n;
92 struct annotation *notes;
93 GType col_types[MAX_ANN_COLS];
94 GtkCellRenderer *renderer;
95 GtkListStore *store;
96 GtkWidget *view;
97 int i;
98 char s[512];
99
100 notes = symbol__annotation(sym);
101
102 for (i = 0; i < MAX_ANN_COLS; i++) {
103 col_types[i] = G_TYPE_STRING;
104 }
105 store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
106
107 view = gtk_tree_view_new();
108 renderer = gtk_cell_renderer_text_new();
109
110 for (i = 0; i < MAX_ANN_COLS; i++) {
111 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
112 -1, col_names[i], renderer, "markup",
113 i, NULL);
114 }
115
116 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
117 g_object_unref(GTK_TREE_MODEL(store));
118
119 list_for_each_entry(pos, &notes->src->source, node) {
120 GtkTreeIter iter;
121
122 gtk_list_store_append(store, &iter);
123
124 if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx))
125 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
126 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
127 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
128 if (perf_gtk__get_line(s, sizeof(s), pos))
129 gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
130 }
131
132 gtk_container_add(GTK_CONTAINER(window), view);
133
134 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
135 list_del(&pos->node);
136 disasm_line__free(pos);
137 }
138
139 return 0;
140}
141
142int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
143 struct hist_browser_timer *hbt)
144{
145 GtkWidget *window;
146 GtkWidget *notebook;
147 GtkWidget *scrolled_window;
148 GtkWidget *tab_label;
149
150 if (map->dso->annotate_warned)
151 return -1;
152
153 if (symbol__annotate(sym, map, 0) < 0) {
154 ui__error("%s", ui_helpline__current);
155 return -1;
156 }
157
158 if (perf_gtk__is_active_context(pgctx)) {
159 window = pgctx->main_window;
160 notebook = pgctx->notebook;
161 } else {
162 GtkWidget *vbox;
163 GtkWidget *infobar;
164 GtkWidget *statbar;
165
166 signal(SIGSEGV, perf_gtk__signal);
167 signal(SIGFPE, perf_gtk__signal);
168 signal(SIGINT, perf_gtk__signal);
169 signal(SIGQUIT, perf_gtk__signal);
170 signal(SIGTERM, perf_gtk__signal);
171
172 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
173 gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
174
175 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
176
177 pgctx = perf_gtk__activate_context(window);
178 if (!pgctx)
179 return -1;
180
181 vbox = gtk_vbox_new(FALSE, 0);
182 notebook = gtk_notebook_new();
183 pgctx->notebook = notebook;
184
185 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
186
187 infobar = perf_gtk__setup_info_bar();
188 if (infobar) {
189 gtk_box_pack_start(GTK_BOX(vbox), infobar,
190 FALSE, FALSE, 0);
191 }
192
193 statbar = perf_gtk__setup_statusbar();
194 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
195
196 gtk_container_add(GTK_CONTAINER(window), vbox);
197 }
198
199 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
200 tab_label = gtk_label_new(sym->name);
201
202 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
203 GTK_POLICY_AUTOMATIC,
204 GTK_POLICY_AUTOMATIC);
205
206 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
207 tab_label);
208
209 perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt);
210 return 0;
211}
212
213void perf_gtk__show_annotations(void)
214{
215 GtkWidget *window;
216
217 if (!perf_gtk__is_active_context(pgctx))
218 return;
219
220 window = pgctx->main_window;
221 gtk_widget_show_all(window);
222
223 perf_gtk__resize_window(window);
224 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
225
226 gtk_main();
227
228 perf_gtk__deactivate_context(&pgctx);
229}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 253b6219a39e..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,155 +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__init();
78
79 perf_hpp__format[PERF_HPP__OVERHEAD].color =
80 perf_gtk__hpp_color_overhead;
81 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
82 perf_gtk__hpp_color_overhead_sys;
83 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
84 perf_gtk__hpp_color_overhead_us;
85 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
86 perf_gtk__hpp_color_overhead_guest_sys;
87 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
88 perf_gtk__hpp_color_overhead_guest_us;
89}
90
91static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
92{
93 GType col_types[MAX_COLUMNS];
94 GtkCellRenderer *renderer;
95 struct sort_entry *se;
96 GtkListStore *store;
97 struct rb_node *nd;
98 GtkWidget *view;
99 int i, col_idx;
100 int nr_cols;
101 char s[512];
102
103 struct perf_hpp hpp = {
104 .buf = s,
105 .size = sizeof(s),
106 };
107
108 nr_cols = 0;
109
110 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
111 if (!perf_hpp__format[i].cond)
112 continue;
113
114 col_types[nr_cols++] = G_TYPE_STRING;
115 }
116
117 list_for_each_entry(se, &hist_entry__sort_list, list) {
118 if (se->elide)
119 continue;
120
121 col_types[nr_cols++] = G_TYPE_STRING;
122 }
123
124 store = gtk_list_store_newv(nr_cols, col_types);
125
126 view = gtk_tree_view_new();
127
128 renderer = gtk_cell_renderer_text_new();
129
130 col_idx = 0;
131
132 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
133 if (!perf_hpp__format[i].cond)
134 continue;
135
136 perf_hpp__format[i].header(&hpp);
137
138 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
139 -1, s,
140 renderer, "markup",
141 col_idx++, NULL);
142 }
143
144 list_for_each_entry(se, &hist_entry__sort_list, list) {
145 if (se->elide)
146 continue;
147
148 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
149 -1, se->se_header,
150 renderer, "text",
151 col_idx++, NULL);
152 }
153
154 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
155
156 g_object_unref(GTK_TREE_MODEL(store));
157
158 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
159 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
160 GtkTreeIter iter;
161
162 if (h->filtered)
163 continue;
164
165 gtk_list_store_append(store, &iter);
166
167 col_idx = 0;
168
169 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
170 if (!perf_hpp__format[i].cond)
171 continue;
172
173 if (perf_hpp__format[i].color)
174 perf_hpp__format[i].color(&hpp, h);
175 else
176 perf_hpp__format[i].entry(&hpp, h);
177
178 gtk_list_store_set(store, &iter, col_idx++, s, -1);
179 }
180
181 list_for_each_entry(se, &hist_entry__sort_list, list) {
182 if (se->elide)
183 continue;
184
185 se->se_snprintf(h, s, ARRAY_SIZE(s),
186 hists__col_len(hists, se->se_width_idx));
187
188 gtk_list_store_set(store, &iter, col_idx++, s, -1);
189 }
190 }
191
192 gtk_container_add(GTK_CONTAINER(window), view);
193}
194
195#ifdef HAVE_GTK_INFO_BAR 46#ifdef HAVE_GTK_INFO_BAR
196static GtkWidget *perf_gtk__setup_info_bar(void) 47GtkWidget *perf_gtk__setup_info_bar(void)
197{ 48{
198 GtkWidget *info_bar; 49 GtkWidget *info_bar;
199 GtkWidget *label; 50 GtkWidget *label;
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
220} 71}
221#endif 72#endif
222 73
223static GtkWidget *perf_gtk__setup_statusbar(void) 74GtkWidget *perf_gtk__setup_statusbar(void)
224{ 75{
225 GtkWidget *stbar; 76 GtkWidget *stbar;
226 unsigned ctxid; 77 unsigned ctxid;
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
234 85
235 return stbar; 86 return stbar;
236} 87}
237
238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
239 const char *help,
240 struct hist_browser_timer *hbt __maybe_unused)
241{
242 struct perf_evsel *pos;
243 GtkWidget *vbox;
244 GtkWidget *notebook;
245 GtkWidget *info_bar;
246 GtkWidget *statbar;
247 GtkWidget *window;
248
249 signal(SIGSEGV, perf_gtk__signal);
250 signal(SIGFPE, perf_gtk__signal);
251 signal(SIGINT, perf_gtk__signal);
252 signal(SIGQUIT, perf_gtk__signal);
253 signal(SIGTERM, perf_gtk__signal);
254
255 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
256
257 gtk_window_set_title(GTK_WINDOW(window), "perf report");
258
259 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
260
261 pgctx = perf_gtk__activate_context(window);
262 if (!pgctx)
263 return -1;
264
265 vbox = gtk_vbox_new(FALSE, 0);
266
267 notebook = gtk_notebook_new();
268
269 list_for_each_entry(pos, &evlist->entries, node) {
270 struct hists *hists = &pos->hists;
271 const char *evname = perf_evsel__name(pos);
272 GtkWidget *scrolled_window;
273 GtkWidget *tab_label;
274
275 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
276
277 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
278 GTK_POLICY_AUTOMATIC,
279 GTK_POLICY_AUTOMATIC);
280
281 perf_gtk__show_hists(scrolled_window, hists);
282
283 tab_label = gtk_label_new(evname);
284
285 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
286 }
287
288 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
289
290 info_bar = perf_gtk__setup_info_bar();
291 if (info_bar)
292 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
293
294 statbar = perf_gtk__setup_statusbar();
295 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
296
297 gtk_container_add(GTK_CONTAINER(window), vbox);
298
299 gtk_widget_show_all(window);
300
301 perf_gtk__resize_window(window);
302
303 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
304
305 ui_helpline__push(help);
306
307 gtk_main();
308
309 perf_gtk__deactivate_context(&pgctx);
310
311 return 0;
312}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 856320e2cc05..3d96785ef155 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,7 @@
10 10
11struct perf_gtk_context { 11struct perf_gtk_context {
12 GtkWidget *main_window; 12 GtkWidget *main_window;
13 GtkWidget *notebook;
13 14
14#ifdef HAVE_GTK_INFO_BAR 15#ifdef HAVE_GTK_INFO_BAR
15 GtkWidget *info_bar; 16 GtkWidget *info_bar;
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void);
33void perf_gtk__init_progress(void); 34void perf_gtk__init_progress(void);
34void perf_gtk__init_hpp(void); 35void perf_gtk__init_hpp(void);
35 36
36#ifndef HAVE_GTK_INFO_BAR 37void perf_gtk__signal(int sig);
38void perf_gtk__resize_window(GtkWidget *window);
39const char *perf_gtk__get_percent_color(double percent);
40GtkWidget *perf_gtk__setup_statusbar(void);
41
42#ifdef HAVE_GTK_INFO_BAR
43GtkWidget *perf_gtk__setup_info_bar(void);
44#else
37static inline GtkWidget *perf_gtk__setup_info_bar(void) 45static inline GtkWidget *perf_gtk__setup_info_bar(void)
38{ 46{
39 return NULL; 47 return NULL;
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
index 5db4432ff12a..3388cbd12186 100644
--- a/tools/perf/ui/gtk/helpline.c
+++ b/tools/perf/ui/gtk/helpline.c
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg)
24 pgctx->statbar_ctx_id, msg); 24 pgctx->statbar_ctx_id, msg);
25} 25}
26 26
27static struct ui_helpline gtk_helpline_fns = { 27static int gtk_helpline_show(const char *fmt, va_list ap)
28 .pop = gtk_helpline_pop,
29 .push = gtk_helpline_push,
30};
31
32void perf_gtk__init_helpline(void)
33{
34 helpline_fns = &gtk_helpline_fns;
35}
36
37int perf_gtk__show_helpline(const char *fmt, va_list ap)
38{ 28{
39 int ret; 29 int ret;
40 char *ptr; 30 char *ptr;
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap)
54 44
55 return ret; 45 return ret;
56} 46}
47
48static struct ui_helpline gtk_helpline_fns = {
49 .pop = gtk_helpline_pop,
50 .push = gtk_helpline_push,
51 .show = gtk_helpline_show,
52};
53
54void perf_gtk__init_helpline(void)
55{
56 helpline_fns = &gtk_helpline_fns;
57}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644
index 000000000000..1e764a8ad259
--- /dev/null
+++ b/tools/perf/ui/gtk/hists.c
@@ -0,0 +1,312 @@
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
11static int __percent_color_snprintf(char *buf, size_t size, double percent)
12{
13 int ret = 0;
14 const char *markup;
15
16 markup = perf_gtk__get_percent_color(percent);
17 if (markup)
18 ret += scnprintf(buf, size, markup);
19
20 ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
21
22 if (markup)
23 ret += scnprintf(buf + ret, size - ret, "</span>");
24
25 return ret;
26}
27
28
29static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
30 u64 (*get_field)(struct hist_entry *))
31{
32 int ret;
33 double percent = 0.0;
34 struct hists *hists = he->hists;
35
36 if (hists->stats.total_period)
37 percent = 100.0 * get_field(he) / hists->stats.total_period;
38
39 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
40
41 if (symbol_conf.event_group) {
42 int prev_idx, idx_delta;
43 struct perf_evsel *evsel = hists_to_evsel(hists);
44 struct hist_entry *pair;
45 int nr_members = evsel->nr_members;
46
47 if (nr_members <= 1)
48 return ret;
49
50 prev_idx = perf_evsel__group_idx(evsel);
51
52 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
53 u64 period = get_field(pair);
54 u64 total = pair->hists->stats.total_period;
55
56 evsel = hists_to_evsel(pair->hists);
57 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
58
59 while (idx_delta--) {
60 /*
61 * zero-fill group members in the middle which
62 * have no sample
63 */
64 ret += __percent_color_snprintf(hpp->buf + ret,
65 hpp->size - ret,
66 0.0);
67 }
68
69 percent = 100.0 * period / total;
70 ret += __percent_color_snprintf(hpp->buf + ret,
71 hpp->size - ret,
72 percent);
73
74 prev_idx = perf_evsel__group_idx(evsel);
75 }
76
77 idx_delta = nr_members - prev_idx - 1;
78
79 while (idx_delta--) {
80 /*
81 * zero-fill group members at last which have no sample
82 */
83 ret += __percent_color_snprintf(hpp->buf + ret,
84 hpp->size - ret,
85 0.0);
86 }
87 }
88 return ret;
89}
90
91#define __HPP_COLOR_PERCENT_FN(_type, _field) \
92static u64 he_get_##_field(struct hist_entry *he) \
93{ \
94 return he->stat._field; \
95} \
96 \
97static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \
98 struct hist_entry *he) \
99{ \
100 return __hpp__color_fmt(hpp, he, he_get_##_field); \
101}
102
103__HPP_COLOR_PERCENT_FN(overhead, period)
104__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
105__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
106__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
107__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
108
109#undef __HPP_COLOR_PERCENT_FN
110
111
112void perf_gtk__init_hpp(void)
113{
114 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
115
116 perf_hpp__init();
117
118 perf_hpp__format[PERF_HPP__OVERHEAD].color =
119 perf_gtk__hpp_color_overhead;
120 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
121 perf_gtk__hpp_color_overhead_sys;
122 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
123 perf_gtk__hpp_color_overhead_us;
124 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
125 perf_gtk__hpp_color_overhead_guest_sys;
126 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
127 perf_gtk__hpp_color_overhead_guest_us;
128}
129
130static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
131{
132 struct perf_hpp_fmt *fmt;
133 GType col_types[MAX_COLUMNS];
134 GtkCellRenderer *renderer;
135 struct sort_entry *se;
136 GtkListStore *store;
137 struct rb_node *nd;
138 GtkWidget *view;
139 int col_idx;
140 int nr_cols;
141 char s[512];
142
143 struct perf_hpp hpp = {
144 .buf = s,
145 .size = sizeof(s),
146 .ptr = hists_to_evsel(hists),
147 };
148
149 nr_cols = 0;
150
151 perf_hpp__for_each_format(fmt)
152 col_types[nr_cols++] = G_TYPE_STRING;
153
154 list_for_each_entry(se, &hist_entry__sort_list, list) {
155 if (se->elide)
156 continue;
157
158 col_types[nr_cols++] = G_TYPE_STRING;
159 }
160
161 store = gtk_list_store_newv(nr_cols, col_types);
162
163 view = gtk_tree_view_new();
164
165 renderer = gtk_cell_renderer_text_new();
166
167 col_idx = 0;
168
169 perf_hpp__for_each_format(fmt) {
170 fmt->header(&hpp);
171
172 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
173 -1, ltrim(s),
174 renderer, "markup",
175 col_idx++, NULL);
176 }
177
178 list_for_each_entry(se, &hist_entry__sort_list, list) {
179 if (se->elide)
180 continue;
181
182 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
183 -1, se->se_header,
184 renderer, "text",
185 col_idx++, NULL);
186 }
187
188 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
189
190 g_object_unref(GTK_TREE_MODEL(store));
191
192 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
193 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
194 GtkTreeIter iter;
195
196 if (h->filtered)
197 continue;
198
199 gtk_list_store_append(store, &iter);
200
201 col_idx = 0;
202
203 perf_hpp__for_each_format(fmt) {
204 if (fmt->color)
205 fmt->color(&hpp, h);
206 else
207 fmt->entry(&hpp, h);
208
209 gtk_list_store_set(store, &iter, col_idx++, s, -1);
210 }
211
212 list_for_each_entry(se, &hist_entry__sort_list, list) {
213 if (se->elide)
214 continue;
215
216 se->se_snprintf(h, s, ARRAY_SIZE(s),
217 hists__col_len(hists, se->se_width_idx));
218
219 gtk_list_store_set(store, &iter, col_idx++, s, -1);
220 }
221 }
222
223 gtk_container_add(GTK_CONTAINER(window), view);
224}
225
226int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
227 const char *help,
228 struct hist_browser_timer *hbt __maybe_unused)
229{
230 struct perf_evsel *pos;
231 GtkWidget *vbox;
232 GtkWidget *notebook;
233 GtkWidget *info_bar;
234 GtkWidget *statbar;
235 GtkWidget *window;
236
237 signal(SIGSEGV, perf_gtk__signal);
238 signal(SIGFPE, perf_gtk__signal);
239 signal(SIGINT, perf_gtk__signal);
240 signal(SIGQUIT, perf_gtk__signal);
241 signal(SIGTERM, perf_gtk__signal);
242
243 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
244
245 gtk_window_set_title(GTK_WINDOW(window), "perf report");
246
247 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
248
249 pgctx = perf_gtk__activate_context(window);
250 if (!pgctx)
251 return -1;
252
253 vbox = gtk_vbox_new(FALSE, 0);
254
255 notebook = gtk_notebook_new();
256
257 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
258
259 info_bar = perf_gtk__setup_info_bar();
260 if (info_bar)
261 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
262
263 statbar = perf_gtk__setup_statusbar();
264 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
265
266 gtk_container_add(GTK_CONTAINER(window), vbox);
267
268 list_for_each_entry(pos, &evlist->entries, node) {
269 struct hists *hists = &pos->hists;
270 const char *evname = perf_evsel__name(pos);
271 GtkWidget *scrolled_window;
272 GtkWidget *tab_label;
273 char buf[512];
274 size_t size = sizeof(buf);
275
276 if (symbol_conf.event_group) {
277 if (!perf_evsel__is_group_leader(pos))
278 continue;
279
280 if (pos->nr_members > 1) {
281 perf_evsel__group_desc(pos, buf, size);
282 evname = buf;
283 }
284 }
285
286 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
287
288 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
289 GTK_POLICY_AUTOMATIC,
290 GTK_POLICY_AUTOMATIC);
291
292 perf_gtk__show_hists(scrolled_window, hists);
293
294 tab_label = gtk_label_new(evname);
295
296 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
297 }
298
299 gtk_widget_show_all(window);
300
301 perf_gtk__resize_window(window);
302
303 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
304
305 ui_helpline__push(help);
306
307 gtk_main();
308
309 perf_gtk__deactivate_context(&pgctx);
310
311 return 0;
312}
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
index a49bcf3c190b..700fb3cfa1c7 100644
--- a/tools/perf/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused)
16{ 16{
17} 17}
18 18
19static int nop_helpline__show(const char *fmt __maybe_unused,
20 va_list ap __maybe_unused)
21{
22 return 0;
23}
24
19static struct ui_helpline default_helpline_fns = { 25static struct ui_helpline default_helpline_fns = {
20 .pop = nop_helpline__pop, 26 .pop = nop_helpline__pop,
21 .push = nop_helpline__push, 27 .push = nop_helpline__push,
28 .show = nop_helpline__show,
22}; 29};
23 30
24struct ui_helpline *helpline_fns = &default_helpline_fns; 31struct ui_helpline *helpline_fns = &default_helpline_fns;
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg)
59 ui_helpline__pop(); 66 ui_helpline__pop();
60 ui_helpline__push(msg); 67 ui_helpline__push(msg);
61} 68}
69
70int ui_helpline__vshow(const char *fmt, va_list ap)
71{
72 return helpline_fns->show(fmt, ap);
73}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
index baa28a4d16b9..46181f4fc07e 100644
--- a/tools/perf/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
@@ -9,6 +9,7 @@
9struct ui_helpline { 9struct ui_helpline {
10 void (*pop)(void); 10 void (*pop)(void);
11 void (*push)(const char *msg); 11 void (*push)(const char *msg);
12 int (*show)(const char *fmt, va_list ap);
12}; 13};
13 14
14extern struct ui_helpline *helpline_fns; 15extern struct ui_helpline *helpline_fns;
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg);
20void ui_helpline__vpush(const char *fmt, va_list ap); 21void ui_helpline__vpush(const char *fmt, va_list ap);
21void ui_helpline__fpush(const char *fmt, ...); 22void ui_helpline__fpush(const char *fmt, ...);
22void ui_helpline__puts(const char *msg); 23void ui_helpline__puts(const char *msg);
24int ui_helpline__vshow(const char *fmt, va_list ap);
23 25
24extern char ui_helpline__current[512]; 26extern char ui_helpline__current[512];
25
26#ifdef NEWT_SUPPORT
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap);
29#else
30static inline int ui_helpline__show_help(const char *format __maybe_unused,
31 va_list ap __maybe_unused)
32{
33 return 0;
34}
35#endif /* NEWT_SUPPORT */
36
37#ifdef GTK2_SUPPORT
38int perf_gtk__show_helpline(const char *format, va_list ap);
39#else
40static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
41 va_list ap __maybe_unused)
42{
43 return 0;
44}
45#endif /* GTK2_SUPPORT */
46 28
47#endif /* _PERF_UI_HELPLINE_H_ */ 29#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index aa84130024d5..d671e63aa351 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -3,151 +3,163 @@
3#include "../util/hist.h" 3#include "../util/hist.h"
4#include "../util/util.h" 4#include "../util/util.h"
5#include "../util/sort.h" 5#include "../util/sort.h"
6 6#include "../util/evsel.h"
7 7
8/* hist period print (hpp) functions */ 8/* hist period print (hpp) functions */
9static int hpp__header_overhead(struct perf_hpp *hpp)
10{
11 return scnprintf(hpp->buf, hpp->size, "Overhead");
12}
13
14static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
15{
16 return 8;
17}
18
19static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
20{
21 struct hists *hists = he->hists;
22 double percent = 100.0 * he->stat.period / hists->stats.total_period;
23 9
24 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 10typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
25}
26 11
27static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) 12static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
13 u64 (*get_field)(struct hist_entry *),
14 const char *fmt, hpp_snprint_fn print_fn,
15 bool fmt_percent)
28{ 16{
17 int ret;
29 struct hists *hists = he->hists; 18 struct hists *hists = he->hists;
30 double percent = 100.0 * he->stat.period / hists->stats.total_period;
31 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32
33 return scnprintf(hpp->buf, hpp->size, fmt, percent);
34}
35 19
36static int hpp__header_overhead_sys(struct perf_hpp *hpp) 20 if (fmt_percent) {
37{ 21 double percent = 0.0;
38 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
39
40 return scnprintf(hpp->buf, hpp->size, fmt, "sys");
41}
42 22
43static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) 23 if (hists->stats.total_period)
44{ 24 percent = 100.0 * get_field(he) /
45 return 7; 25 hists->stats.total_period;
46}
47 26
48static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 27 ret = print_fn(hpp->buf, hpp->size, fmt, percent);
49{ 28 } else
50 struct hists *hists = he->hists; 29 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
51 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52 30
53 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 31 if (symbol_conf.event_group) {
54} 32 int prev_idx, idx_delta;
33 struct perf_evsel *evsel = hists_to_evsel(hists);
34 struct hist_entry *pair;
35 int nr_members = evsel->nr_members;
55 36
56static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 37 if (nr_members <= 1)
57{ 38 return ret;
58 struct hists *hists = he->hists;
59 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61 39
62 return scnprintf(hpp->buf, hpp->size, fmt, percent); 40 prev_idx = perf_evsel__group_idx(evsel);
63}
64 41
65static int hpp__header_overhead_us(struct perf_hpp *hpp) 42 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
66{ 43 u64 period = get_field(pair);
67 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 44 u64 total = pair->hists->stats.total_period;
68 45
69 return scnprintf(hpp->buf, hpp->size, fmt, "user"); 46 if (!total)
70} 47 continue;
71 48
72static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) 49 evsel = hists_to_evsel(pair->hists);
73{ 50 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
74 return 7;
75}
76 51
77static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 52 while (idx_delta--) {
78{ 53 /*
79 struct hists *hists = he->hists; 54 * zero-fill group members in the middle which
80 double percent = 100.0 * he->stat.period_us / hists->stats.total_period; 55 * have no sample
56 */
57 ret += print_fn(hpp->buf + ret, hpp->size - ret,
58 fmt, 0);
59 }
81 60
82 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 61 if (fmt_percent)
83} 62 ret += print_fn(hpp->buf + ret, hpp->size - ret,
63 fmt, 100.0 * period / total);
64 else
65 ret += print_fn(hpp->buf + ret, hpp->size - ret,
66 fmt, period);
84 67
85static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) 68 prev_idx = perf_evsel__group_idx(evsel);
86{ 69 }
87 struct hists *hists = he->hists;
88 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90
91 return scnprintf(hpp->buf, hpp->size, fmt, percent);
92}
93
94static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
95{
96 return scnprintf(hpp->buf, hpp->size, "guest sys");
97}
98
99static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
100{
101 return 9;
102}
103
104static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
105 struct hist_entry *he)
106{
107 struct hists *hists = he->hists;
108 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109
110 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
111}
112
113static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
114 struct hist_entry *he)
115{
116 struct hists *hists = he->hists;
117 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119
120 return scnprintf(hpp->buf, hpp->size, fmt, percent);
121}
122
123static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
124{
125 return scnprintf(hpp->buf, hpp->size, "guest usr");
126}
127 70
128static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) 71 idx_delta = nr_members - prev_idx - 1;
129{
130 return 9;
131}
132 72
133static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, 73 while (idx_delta--) {
134 struct hist_entry *he) 74 /*
135{ 75 * zero-fill group members at last which have no sample
136 struct hists *hists = he->hists; 76 */
137 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 77 ret += print_fn(hpp->buf + ret, hpp->size - ret,
138 78 fmt, 0);
139 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 79 }
80 }
81 return ret;
140} 82}
141 83
142static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, 84#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
143 struct hist_entry *he) 85static int hpp__header_##_type(struct perf_hpp *hpp) \
144{ 86{ \
145 struct hists *hists = he->hists; 87 int len = _min_width; \
146 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 88 \
147 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; 89 if (symbol_conf.event_group) { \
90 struct perf_evsel *evsel = hpp->ptr; \
91 \
92 len = max(len, evsel->nr_members * _unit_width); \
93 } \
94 return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
95}
96
97#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
98static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
99{ \
100 int len = _min_width; \
101 \
102 if (symbol_conf.event_group) { \
103 struct perf_evsel *evsel = hpp->ptr; \
104 \
105 len = max(len, evsel->nr_members * _unit_width); \
106 } \
107 return len; \
108}
109
110#define __HPP_COLOR_PERCENT_FN(_type, _field) \
111static u64 he_get_##_field(struct hist_entry *he) \
112{ \
113 return he->stat._field; \
114} \
115 \
116static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
117{ \
118 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
119 (hpp_snprint_fn)percent_color_snprintf, true); \
120}
121
122#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
123static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
124{ \
125 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
126 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
127 scnprintf, true); \
128}
129
130#define __HPP_ENTRY_RAW_FN(_type, _field) \
131static u64 he_get_raw_##_field(struct hist_entry *he) \
132{ \
133 return he->stat._field; \
134} \
135 \
136static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
137{ \
138 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
139 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
140}
141
142#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
143__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
144__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
145__HPP_COLOR_PERCENT_FN(_type, _field) \
146__HPP_ENTRY_PERCENT_FN(_type, _field)
147
148#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
149__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
150__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
151__HPP_ENTRY_RAW_FN(_type, _field)
152
153
154HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
155HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
156HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
157HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
158HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
159
160HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
161HPP_RAW_FNS(period, "Period", period, 12, 12)
148 162
149 return scnprintf(hpp->buf, hpp->size, fmt, percent);
150}
151 163
152static int hpp__header_baseline(struct perf_hpp *hpp) 164static int hpp__header_baseline(struct perf_hpp *hpp)
153{ 165{
@@ -179,7 +191,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179{ 191{
180 double percent = baseline_percent(he); 192 double percent = baseline_percent(he);
181 193
182 if (hist_entry__has_pairs(he)) 194 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
183 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 195 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
184 else 196 else
185 return scnprintf(hpp->buf, hpp->size, " "); 197 return scnprintf(hpp->buf, hpp->size, " ");
@@ -196,44 +208,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
196 return scnprintf(hpp->buf, hpp->size, " "); 208 return scnprintf(hpp->buf, hpp->size, " ");
197} 209}
198 210
199static int hpp__header_samples(struct perf_hpp *hpp)
200{
201 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
202
203 return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
204}
205
206static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
207{
208 return 11;
209}
210
211static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
212{
213 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
214
215 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
216}
217
218static int hpp__header_period(struct perf_hpp *hpp)
219{
220 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
221
222 return scnprintf(hpp->buf, hpp->size, fmt, "Period");
223}
224
225static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
226{
227 return 12;
228}
229
230static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
231{
232 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
233
234 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
235}
236
237static int hpp__header_period_baseline(struct perf_hpp *hpp) 211static int hpp__header_period_baseline(struct perf_hpp *hpp)
238{ 212{
239 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 213 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
@@ -254,6 +228,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h
254 228
255 return scnprintf(hpp->buf, hpp->size, fmt, period); 229 return scnprintf(hpp->buf, hpp->size, fmt, period);
256} 230}
231
257static int hpp__header_delta(struct perf_hpp *hpp) 232static int hpp__header_delta(struct perf_hpp *hpp)
258{ 233{
259 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 234 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
@@ -268,14 +243,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
268 243
269static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 244static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
270{ 245{
246 struct hist_entry *pair = hist_entry__next_pair(he);
271 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 247 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
272 char buf[32] = " "; 248 char buf[32] = " ";
273 double diff; 249 double diff = 0.0;
274 250
275 if (he->diff.computed) 251 if (pair) {
276 diff = he->diff.period_ratio_delta; 252 if (he->diff.computed)
277 else 253 diff = he->diff.period_ratio_delta;
278 diff = perf_diff__compute_delta(he); 254 else
255 diff = perf_diff__compute_delta(he, pair);
256 } else
257 diff = perf_diff__period_percent(he, he->stat.period);
279 258
280 if (fabs(diff) >= 0.01) 259 if (fabs(diff) >= 0.01)
281 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 260 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
@@ -297,14 +276,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
297 276
298static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) 277static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
299{ 278{
279 struct hist_entry *pair = hist_entry__next_pair(he);
300 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 280 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
301 char buf[32] = " "; 281 char buf[32] = " ";
302 double ratio; 282 double ratio = 0.0;
303 283
304 if (he->diff.computed) 284 if (pair) {
305 ratio = he->diff.period_ratio; 285 if (he->diff.computed)
306 else 286 ratio = he->diff.period_ratio;
307 ratio = perf_diff__compute_ratio(he); 287 else
288 ratio = perf_diff__compute_ratio(he, pair);
289 }
308 290
309 if (ratio > 0.0) 291 if (ratio > 0.0)
310 scnprintf(buf, sizeof(buf), "%+14.6F", ratio); 292 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
@@ -326,14 +308,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
326 308
327static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) 309static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
328{ 310{
311 struct hist_entry *pair = hist_entry__next_pair(he);
329 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; 312 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
330 char buf[32] = " "; 313 char buf[32] = " ";
331 s64 wdiff; 314 s64 wdiff = 0;
332 315
333 if (he->diff.computed) 316 if (pair) {
334 wdiff = he->diff.wdiff; 317 if (he->diff.computed)
335 else 318 wdiff = he->diff.wdiff;
336 wdiff = perf_diff__compute_wdiff(he); 319 else
320 wdiff = perf_diff__compute_wdiff(he, pair);
321 }
337 322
338 if (wdiff != 0) 323 if (wdiff != 0)
339 scnprintf(buf, sizeof(buf), "%14ld", wdiff); 324 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
@@ -341,30 +326,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
341 return scnprintf(hpp->buf, hpp->size, fmt, buf); 326 return scnprintf(hpp->buf, hpp->size, fmt, buf);
342} 327}
343 328
344static int hpp__header_displ(struct perf_hpp *hpp)
345{
346 return scnprintf(hpp->buf, hpp->size, "Displ.");
347}
348
349static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
350{
351 return 6;
352}
353
354static int hpp__entry_displ(struct perf_hpp *hpp,
355 struct hist_entry *he)
356{
357 struct hist_entry *pair = hist_entry__next_pair(he);
358 long displacement = pair ? pair->position - he->position : 0;
359 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
360 char buf[32] = " ";
361
362 if (displacement)
363 scnprintf(buf, sizeof(buf), "%+4ld", displacement);
364
365 return scnprintf(hpp->buf, hpp->size, fmt, buf);
366}
367
368static int hpp__header_formula(struct perf_hpp *hpp) 329static int hpp__header_formula(struct perf_hpp *hpp)
369{ 330{
370 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; 331 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
@@ -379,67 +340,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
379 340
380static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) 341static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
381{ 342{
343 struct hist_entry *pair = hist_entry__next_pair(he);
382 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; 344 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
383 char buf[96] = " "; 345 char buf[96] = " ";
384 346
385 perf_diff__formula(buf, sizeof(buf), he); 347 if (pair)
348 perf_diff__formula(he, pair, buf, sizeof(buf));
349
386 return scnprintf(hpp->buf, hpp->size, fmt, buf); 350 return scnprintf(hpp->buf, hpp->size, fmt, buf);
387} 351}
388 352
389#define HPP__COLOR_PRINT_FNS(_name) \ 353#define HPP__COLOR_PRINT_FNS(_name) \
390 .header = hpp__header_ ## _name, \ 354 { \
391 .width = hpp__width_ ## _name, \ 355 .header = hpp__header_ ## _name, \
392 .color = hpp__color_ ## _name, \ 356 .width = hpp__width_ ## _name, \
393 .entry = hpp__entry_ ## _name 357 .color = hpp__color_ ## _name, \
358 .entry = hpp__entry_ ## _name \
359 }
394 360
395#define HPP__PRINT_FNS(_name) \ 361#define HPP__PRINT_FNS(_name) \
396 .header = hpp__header_ ## _name, \ 362 { \
397 .width = hpp__width_ ## _name, \ 363 .header = hpp__header_ ## _name, \
398 .entry = hpp__entry_ ## _name 364 .width = hpp__width_ ## _name, \
365 .entry = hpp__entry_ ## _name \
366 }
399 367
400struct perf_hpp_fmt perf_hpp__format[] = { 368struct perf_hpp_fmt perf_hpp__format[] = {
401 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, 369 HPP__COLOR_PRINT_FNS(baseline),
402 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, 370 HPP__COLOR_PRINT_FNS(overhead),
403 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, 371 HPP__COLOR_PRINT_FNS(overhead_sys),
404 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, 372 HPP__COLOR_PRINT_FNS(overhead_us),
405 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, 373 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
406 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 374 HPP__COLOR_PRINT_FNS(overhead_guest_us),
407 { .cond = false, HPP__PRINT_FNS(samples) }, 375 HPP__PRINT_FNS(samples),
408 { .cond = false, HPP__PRINT_FNS(period) }, 376 HPP__PRINT_FNS(period),
409 { .cond = false, HPP__PRINT_FNS(period_baseline) }, 377 HPP__PRINT_FNS(period_baseline),
410 { .cond = false, HPP__PRINT_FNS(delta) }, 378 HPP__PRINT_FNS(delta),
411 { .cond = false, HPP__PRINT_FNS(ratio) }, 379 HPP__PRINT_FNS(ratio),
412 { .cond = false, HPP__PRINT_FNS(wdiff) }, 380 HPP__PRINT_FNS(wdiff),
413 { .cond = false, HPP__PRINT_FNS(displ) }, 381 HPP__PRINT_FNS(formula)
414 { .cond = false, HPP__PRINT_FNS(formula) }
415}; 382};
416 383
384LIST_HEAD(perf_hpp__list);
385
386
417#undef HPP__COLOR_PRINT_FNS 387#undef HPP__COLOR_PRINT_FNS
418#undef HPP__PRINT_FNS 388#undef HPP__PRINT_FNS
419 389
390#undef HPP_PERCENT_FNS
391#undef HPP_RAW_FNS
392
393#undef __HPP_HEADER_FN
394#undef __HPP_WIDTH_FN
395#undef __HPP_COLOR_PERCENT_FN
396#undef __HPP_ENTRY_PERCENT_FN
397#undef __HPP_ENTRY_RAW_FN
398
399
420void perf_hpp__init(void) 400void perf_hpp__init(void)
421{ 401{
422 if (symbol_conf.show_cpu_utilization) { 402 if (symbol_conf.show_cpu_utilization) {
423 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; 403 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
424 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; 404 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
425 405
426 if (perf_guest) { 406 if (perf_guest) {
427 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; 407 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
428 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; 408 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
429 } 409 }
430 } 410 }
431 411
432 if (symbol_conf.show_nr_samples) 412 if (symbol_conf.show_nr_samples)
433 perf_hpp__format[PERF_HPP__SAMPLES].cond = true; 413 perf_hpp__column_enable(PERF_HPP__SAMPLES);
434 414
435 if (symbol_conf.show_total_period) 415 if (symbol_conf.show_total_period)
436 perf_hpp__format[PERF_HPP__PERIOD].cond = true; 416 perf_hpp__column_enable(PERF_HPP__PERIOD);
417}
418
419void perf_hpp__column_register(struct perf_hpp_fmt *format)
420{
421 list_add_tail(&format->list, &perf_hpp__list);
437} 422}
438 423
439void perf_hpp__column_enable(unsigned col, bool enable) 424void perf_hpp__column_enable(unsigned col)
440{ 425{
441 BUG_ON(col >= PERF_HPP__MAX_INDEX); 426 BUG_ON(col >= PERF_HPP__MAX_INDEX);
442 perf_hpp__format[col].cond = enable; 427 perf_hpp__column_register(&perf_hpp__format[col]);
443} 428}
444 429
445static inline void advance_hpp(struct perf_hpp *hpp, int inc) 430static inline void advance_hpp(struct perf_hpp *hpp, int inc)
@@ -452,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
452 bool color) 437 bool color)
453{ 438{
454 const char *sep = symbol_conf.field_sep; 439 const char *sep = symbol_conf.field_sep;
440 struct perf_hpp_fmt *fmt;
455 char *start = hpp->buf; 441 char *start = hpp->buf;
456 int i, ret; 442 int ret;
457 bool first = true; 443 bool first = true;
458 444
459 if (symbol_conf.exclude_other && !he->parent) 445 if (symbol_conf.exclude_other && !he->parent)
460 return 0; 446 return 0;
461 447
462 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 448 perf_hpp__for_each_format(fmt) {
463 if (!perf_hpp__format[i].cond) 449 /*
464 continue; 450 * If there's no field_sep, we still need
465 451 * to display initial ' '.
452 */
466 if (!sep || !first) { 453 if (!sep || !first) {
467 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 454 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
468 advance_hpp(hpp, ret); 455 advance_hpp(hpp, ret);
456 } else
469 first = false; 457 first = false;
470 }
471 458
472 if (color && perf_hpp__format[i].color) 459 if (color && fmt->color)
473 ret = perf_hpp__format[i].color(hpp, he); 460 ret = fmt->color(hpp, he);
474 else 461 else
475 ret = perf_hpp__format[i].entry(hpp, he); 462 ret = fmt->entry(hpp, he);
476 463
477 advance_hpp(hpp, ret); 464 advance_hpp(hpp, ret);
478 } 465 }
@@ -504,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
504 */ 491 */
505unsigned int hists__sort_list_width(struct hists *hists) 492unsigned int hists__sort_list_width(struct hists *hists)
506{ 493{
494 struct perf_hpp_fmt *fmt;
507 struct sort_entry *se; 495 struct sort_entry *se;
508 int i, ret = 0; 496 int i = 0, ret = 0;
497 struct perf_hpp dummy_hpp = {
498 .ptr = hists_to_evsel(hists),
499 };
509 500
510 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 501 perf_hpp__for_each_format(fmt) {
511 if (!perf_hpp__format[i].cond)
512 continue;
513 if (i) 502 if (i)
514 ret += 2; 503 ret += 2;
515 504
516 ret += perf_hpp__format[i].width(NULL); 505 ret += fmt->width(&dummy_hpp);
517 } 506 }
518 507
519 list_for_each_entry(se, &hist_entry__sort_list, list) 508 list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..65092d576b4e 100644
--- a/tools/perf/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
@@ -23,5 +23,6 @@
23#define K_TIMER -1 23#define K_TIMER -1
24#define K_ERROR -2 24#define K_ERROR -2
25#define K_RESIZE -3 25#define K_RESIZE -3
26#define K_SWITCH_INPUT_DATA -4
26 27
27#endif /* _PERF_KEYSYMS_H_ */ 28#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ebb4cc107876..ae6a789cb0f6 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
8 8
9void setup_browser(bool fallback_to_pager) 9void setup_browser(bool fallback_to_pager)
10{ 10{
11 if (!isatty(1) || dump_trace) 11 if (use_browser < 2 && (!isatty(1) || dump_trace))
12 use_browser = 0; 12 use_browser = 0;
13 13
14 /* default to TUI */ 14 /* default to TUI */
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager)
30 if (fallback_to_pager) 30 if (fallback_to_pager)
31 setup_pager(); 31 setup_pager();
32 32
33 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
33 perf_hpp__init(); 34 perf_hpp__init();
34 break; 35 break;
35 } 36 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index f0ee204f99bb..ff1f60cf442e 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -3,6 +3,7 @@
3#include "../../util/util.h" 3#include "../../util/util.h"
4#include "../../util/hist.h" 4#include "../../util/hist.h"
5#include "../../util/sort.h" 5#include "../../util/sort.h"
6#include "../../util/evsel.h"
6 7
7 8
8static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 9static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -335,17 +336,19 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
335size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 336size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
336 int max_cols, FILE *fp) 337 int max_cols, FILE *fp)
337{ 338{
339 struct perf_hpp_fmt *fmt;
338 struct sort_entry *se; 340 struct sort_entry *se;
339 struct rb_node *nd; 341 struct rb_node *nd;
340 size_t ret = 0; 342 size_t ret = 0;
341 unsigned int width; 343 unsigned int width;
342 const char *sep = symbol_conf.field_sep; 344 const char *sep = symbol_conf.field_sep;
343 const char *col_width = symbol_conf.col_width_list_str; 345 const char *col_width = symbol_conf.col_width_list_str;
344 int idx, nr_rows = 0; 346 int nr_rows = 0;
345 char bf[96]; 347 char bf[96];
346 struct perf_hpp dummy_hpp = { 348 struct perf_hpp dummy_hpp = {
347 .buf = bf, 349 .buf = bf,
348 .size = sizeof(bf), 350 .size = sizeof(bf),
351 .ptr = hists_to_evsel(hists),
349 }; 352 };
350 bool first = true; 353 bool first = true;
351 354
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
355 goto print_entries; 358 goto print_entries;
356 359
357 fprintf(fp, "# "); 360 fprintf(fp, "# ");
358 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
359 if (!perf_hpp__format[idx].cond)
360 continue;
361 361
362 perf_hpp__for_each_format(fmt) {
362 if (!first) 363 if (!first)
363 fprintf(fp, "%s", sep ?: " "); 364 fprintf(fp, "%s", sep ?: " ");
364 else 365 else
365 first = false; 366 first = false;
366 367
367 perf_hpp__format[idx].header(&dummy_hpp); 368 fmt->header(&dummy_hpp);
368 fprintf(fp, "%s", bf); 369 fprintf(fp, "%s", bf);
369 } 370 }
370 371
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
400 first = true; 401 first = true;
401 402
402 fprintf(fp, "# "); 403 fprintf(fp, "# ");
403 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
404 unsigned int i;
405 404
406 if (!perf_hpp__format[idx].cond) 405 perf_hpp__for_each_format(fmt) {
407 continue; 406 unsigned int i;
408 407
409 if (!first) 408 if (!first)
410 fprintf(fp, "%s", sep ?: " "); 409 fprintf(fp, "%s", sep ?: " ");
411 else 410 else
412 first = false; 411 first = false;
413 412
414 width = perf_hpp__format[idx].width(&dummy_hpp); 413 width = fmt->width(&dummy_hpp);
415 for (i = 0; i < width; i++) 414 for (i = 0; i < width; i++)
416 fprintf(fp, "."); 415 fprintf(fp, ".");
417 } 416 }
@@ -462,7 +461,7 @@ out:
462 return ret; 461 return ret;
463} 462}
464 463
465size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) 464size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
466{ 465{
467 int i; 466 int i;
468 size_t ret = 0; 467 size_t ret = 0;
@@ -470,7 +469,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
470 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 469 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
471 const char *name; 470 const char *name;
472 471
473 if (hists->stats.nr_events[i] == 0) 472 if (stats->nr_events[i] == 0)
474 continue; 473 continue;
475 474
476 name = perf_event__name(i); 475 name = perf_event__name(i);
@@ -478,7 +477,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
478 continue; 477 continue;
479 478
480 ret += fprintf(fp, "%16s events: %10d\n", name, 479 ret += fprintf(fp, "%16s events: %10d\n", name,
481 hists->stats.nr_events[i]); 480 stats->nr_events[i]);
482 } 481 }
483 482
484 return ret; 483 return ret;
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
index 2884d2f41e33..1c8b9afd5d6e 100644
--- a/tools/perf/ui/tui/helpline.c
+++ b/tools/perf/ui/tui/helpline.c
@@ -8,6 +8,8 @@
8#include "../ui.h" 8#include "../ui.h"
9#include "../libslang.h" 9#include "../libslang.h"
10 10
11char ui_helpline__last_msg[1024];
12
11static void tui_helpline__pop(void) 13static void tui_helpline__pop(void)
12{ 14{
13} 15}
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg)
23 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; 25 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
24} 26}
25 27
26struct ui_helpline tui_helpline_fns = { 28static int tui_helpline__show(const char *format, va_list ap)
27 .pop = tui_helpline__pop,
28 .push = tui_helpline__push,
29};
30
31void ui_helpline__init(void)
32{
33 helpline_fns = &tui_helpline_fns;
34 ui_helpline__puts(" ");
35}
36
37char ui_helpline__last_msg[1024];
38
39int ui_helpline__show_help(const char *format, va_list ap)
40{ 29{
41 int ret; 30 int ret;
42 static int backlog; 31 static int backlog;
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 44
56 return ret; 45 return ret;
57} 46}
47
48struct ui_helpline tui_helpline_fns = {
49 .pop = tui_helpline__pop,
50 .push = tui_helpline__push,
51 .show = tui_helpline__show,
52};
53
54void ui_helpline__init(void)
55{
56 helpline_fns = &tui_helpline_fns;
57 ui_helpline__puts(" ");
58}
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index 4f989774c8c6..e3e0a963d03a 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...)
52 return ret; 52 return ret;
53} 53}
54 54
55
56/** 55/**
57 * perf_error__register - Register error logging functions 56 * perf_error__register - Register error logging functions
58 * @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/annotate.c b/tools/perf/util/annotate.c
index 07aaeea60000..d33fe937e6f1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -809,7 +809,7 @@ fallback:
809 pr_err("Can't annotate %s:\n\n" 809 pr_err("Can't annotate %s:\n\n"
810 "No vmlinux file%s\nwas found in the path.\n\n" 810 "No vmlinux file%s\nwas found in the path.\n\n"
811 "Please use:\n\n" 811 "Please use:\n\n"
812 " perf buildid-cache -av vmlinux\n\n" 812 " perf buildid-cache -vu vmlinux\n\n"
813 "or:\n\n" 813 "or:\n\n"
814 " --vmlinux vmlinux\n", 814 " --vmlinux vmlinux\n",
815 sym->name, build_id_msg ?: ""); 815 sym->name, build_id_msg ?: "");
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 8eec94358a4a..c422440fe611 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -6,6 +6,7 @@
6#include "types.h" 6#include "types.h"
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h"
9#include <linux/list.h> 10#include <linux/list.h>
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <pthread.h> 12#include <pthread.h>
@@ -154,6 +155,29 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
154} 155}
155#endif 156#endif
156 157
158#ifdef GTK2_SUPPORT
159int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
160 struct hist_browser_timer *hbt);
161
162static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
163 struct hist_browser_timer *hbt)
164{
165 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
166}
167
168void perf_gtk__show_annotations(void);
169#else
170static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
171 int evidx __maybe_unused,
172 struct hist_browser_timer *hbt
173 __maybe_unused)
174{
175 return 0;
176}
177
178static inline void perf_gtk__show_annotations(void) {}
179#endif
180
157extern const char *disassembler_style; 181extern const char *disassembler_style;
158 182
159#endif /* __PERF_ANNOTATE_H */ 183#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index d3b3f5d82137..42b6a632fe7b 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
444 struct callchain_cursor_node *node = *cursor->last; 444 struct callchain_cursor_node *node = *cursor->last;
445 445
446 if (!node) { 446 if (!node) {
447 node = calloc(sizeof(*node), 1); 447 node = calloc(1, sizeof(*node));
448 if (!node) 448 if (!node)
449 return -ENOMEM; 449 return -ENOMEM;
450 450
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index eb340571e7d6..3ee9f67d5af0 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
143 cursor->curr = cursor->curr->next; 143 cursor->curr = cursor->curr->next;
144 cursor->pos++; 144 cursor->pos++;
145} 145}
146
147struct option;
148
149int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
150extern const char record_callchain_help[];
146#endif /* __PERF_CALLCHAIN_H */ 151#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 2b32ffa9ebdb..f817046e22b1 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,4 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "cpumap.h" 4#include "cpumap.h"
4#include <assert.h> 5#include <assert.h>
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map)
201{ 202{
202 free(map); 203 free(map);
203} 204}
205
206int cpu_map__get_socket(struct cpu_map *map, int idx)
207{
208 FILE *fp;
209 const char *mnt;
210 char path[PATH_MAX];
211 int cpu, ret;
212
213 if (idx > map->nr)
214 return -1;
215
216 cpu = map->map[idx];
217
218 mnt = sysfs_find_mountpoint();
219 if (!mnt)
220 return -1;
221
222 sprintf(path,
223 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
224 mnt, cpu);
225
226 fp = fopen(path, "r");
227 if (!fp)
228 return -1;
229 ret = fscanf(fp, "%d", &cpu);
230 fclose(fp);
231 return ret == 1 ? cpu : -1;
232}
233
234int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
235{
236 struct cpu_map *sock;
237 int nr = cpus->nr;
238 int cpu, s1, s2;
239
240 sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
241 if (!sock)
242 return -1;
243
244 for (cpu = 0; cpu < nr; cpu++) {
245 s1 = cpu_map__get_socket(cpus, cpu);
246 for (s2 = 0; s2 < sock->nr; s2++) {
247 if (s1 == sock->map[s2])
248 break;
249 }
250 if (s2 == sock->nr) {
251 sock->map[sock->nr] = s1;
252 sock->nr++;
253 }
254 }
255 *sockp = sock;
256 return 0;
257}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2f68a3b8c285..161b00756a12 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void);
14void cpu_map__delete(struct cpu_map *map); 14void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
19
20static inline int cpu_map__socket(struct cpu_map *sock, int s)
21{
22 if (!sock || s > sock->nr || s < 0)
23 return 0;
24 return sock->map[s];
25}
17 26
18static inline int cpu_map__nr(const struct cpu_map *map) 27static inline int cpu_map__nr(const struct cpu_map *map)
19{ 28{
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03f830b48148..399e74c34c1a 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...)
23 23
24 if (verbose >= level) { 24 if (verbose >= level) {
25 va_start(args, fmt); 25 va_start(args, fmt);
26 if (use_browser == 1) 26 if (use_browser >= 1)
27 ret = ui_helpline__show_help(fmt, args); 27 ui_helpline__vshow(fmt, args);
28 else if (use_browser == 2)
29 ret = perf_gtk__show_helpline(fmt, args);
30 else 28 else
31 ret = vfprintf(stderr, fmt, args); 29 ret = vfprintf(stderr, fmt, args);
32 va_end(args); 30 va_end(args);
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...)
49 return ret; 47 return ret;
50} 48}
51 49
52#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT)
53int ui__warning(const char *format, ...)
54{
55 va_list args;
56
57 va_start(args, format);
58 vfprintf(stderr, format, args);
59 va_end(args);
60 return 0;
61}
62#endif
63
64int ui__error_paranoid(void)
65{
66 return ui__error("Permission error - are you root?\n"
67 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
68 " -1 - Not paranoid at all\n"
69 " 0 - Disallow raw tracepoint access for unpriv\n"
70 " 1 - Disallow cpu events for unpriv\n"
71 " 2 - Disallow kernel profiling for unpriv\n");
72}
73
74void trace_event(union perf_event *event) 50void trace_event(union perf_event *event)
75{ 51{
76 unsigned char *raw_event = (void *)event; 52 unsigned char *raw_event = (void *)event;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 83e8d234af6b..efbd98805ad0 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -5,6 +5,8 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include "event.h" 6#include "event.h"
7#include "../ui/helpline.h" 7#include "../ui/helpline.h"
8#include "../ui/progress.h"
9#include "../ui/util.h"
8 10
9extern int verbose; 11extern int verbose;
10extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
@@ -12,39 +14,7 @@ extern bool quiet, dump_trace;
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(union perf_event *event); 15void trace_event(union perf_event *event);
14 16
15struct ui_progress;
16struct perf_error_ops;
17
18#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
19
20#include "../ui/progress.h"
21int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
22#include "../ui/util.h"
23
24#else
25
26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {}
29static inline void ui_progress__finish(void) {}
30
31#define ui__error(format, arg...) ui__warning(format, ##arg)
32
33static inline int
34perf_error__register(struct perf_error_ops *eops __maybe_unused)
35{
36 return 0;
37}
38
39static inline int
40perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
41{
42 return 0;
43}
44
45#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
46
47int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
48int ui__error_paranoid(void);
49 19
50#endif /* __PERF_DEBUG_H */ 20#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d6d9a465acdb..6f7d5a9d6b05 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name)
539} 539}
540 540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool with_hits) 542 bool (skip)(struct dso *dso, int parm), int parm)
543{ 543{
544 struct dso *pos; 544 struct dso *pos;
545 size_t ret = 0; 545 size_t ret = 0;
546 546
547 list_for_each_entry(pos, head, node) { 547 list_for_each_entry(pos, head, node) {
548 if (with_hits && !pos->hit) 548 if (skip && skip(pos, parm))
549 continue; 549 continue;
550 ret += dso__fprintf_buildid(pos, fp); 550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name); 551 ret += fprintf(fp, " %s\n", pos->long_name);
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
583 if (dso->short_name != dso->long_name) 583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name); 584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso->loaded ? "" : "NOT "); 586 dso__loaded(dso, type) ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp); 587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n"); 588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index e03276940b99..450199ab51b5 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139 139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool with_hits); 141 bool (skip)(struct dso *dso, int parm), int parm);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp); 142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143 143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); 144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 3cf2c3e0605f..5cd13d768cec 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
476 } 476 }
477 } 477 }
478 478
479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) 479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
480 free(event);
480 return -ENOENT; 481 return -ENOENT;
482 }
481 483
482 map = machine->vmlinux_maps[MAP__FUNCTION]; 484 map = machine->vmlinux_maps[MAP__FUNCTION];
483 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 485 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 705293489e3c..bc4ad7977438 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
49 return evlist; 49 return evlist;
50} 50}
51 51
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 52void perf_evlist__config(struct perf_evlist *evlist,
53 struct perf_record_opts *opts) 53 struct perf_record_opts *opts)
54{ 54{
55 struct perf_evsel *evsel; 55 struct perf_evsel *evsel;
56 /*
57 * Set the evsel leader links before we configure attributes,
58 * since some might depend on this info.
59 */
60 if (opts->group)
61 perf_evlist__set_leader(evlist);
56 62
57 if (evlist->cpus->map[0] < 0) 63 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true; 64 opts->no_inherit = true;
@@ -61,7 +67,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist,
61 perf_evsel__config(evsel, opts); 67 perf_evsel__config(evsel, opts);
62 68
63 if (evlist->nr_entries > 1) 69 if (evlist->nr_entries > 1)
64 evsel->attr.sample_type |= PERF_SAMPLE_ID; 70 perf_evsel__set_sample_id(evsel);
65 } 71 }
66} 72}
67 73
@@ -111,18 +117,21 @@ void __perf_evlist__set_leader(struct list_head *list)
111 struct perf_evsel *evsel, *leader; 117 struct perf_evsel *evsel, *leader;
112 118
113 leader = list_entry(list->next, struct perf_evsel, node); 119 leader = list_entry(list->next, struct perf_evsel, node);
114 leader->leader = NULL; 120 evsel = list_entry(list->prev, struct perf_evsel, node);
121
122 leader->nr_members = evsel->idx - leader->idx + 1;
115 123
116 list_for_each_entry(evsel, list, node) { 124 list_for_each_entry(evsel, list, node) {
117 if (evsel != leader) 125 evsel->leader = leader;
118 evsel->leader = leader;
119 } 126 }
120} 127}
121 128
122void perf_evlist__set_leader(struct perf_evlist *evlist) 129void perf_evlist__set_leader(struct perf_evlist *evlist)
123{ 130{
124 if (evlist->nr_entries) 131 if (evlist->nr_entries) {
132 evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
125 __perf_evlist__set_leader(&evlist->entries); 133 __perf_evlist__set_leader(&evlist->entries);
134 }
126} 135}
127 136
128int perf_evlist__add_default(struct perf_evlist *evlist) 137int perf_evlist__add_default(struct perf_evlist *evlist)
@@ -222,7 +231,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
222 231
223 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 232 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
224 list_for_each_entry(pos, &evlist->entries, node) { 233 list_for_each_entry(pos, &evlist->entries, node) {
225 if (perf_evsel__is_group_member(pos)) 234 if (!perf_evsel__is_group_leader(pos))
226 continue; 235 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 236 for (thread = 0; thread < evlist->threads->nr; thread++)
228 ioctl(FD(pos, cpu, thread), 237 ioctl(FD(pos, cpu, thread),
@@ -238,7 +247,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
238 247
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 248 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 249 list_for_each_entry(pos, &evlist->entries, node) {
241 if (perf_evsel__is_group_member(pos)) 250 if (!perf_evsel__is_group_leader(pos))
242 continue; 251 continue;
243 for (thread = 0; thread < evlist->threads->nr; thread++) 252 for (thread = 0; thread < evlist->threads->nr; thread++)
244 ioctl(FD(pos, cpu, thread), 253 ioctl(FD(pos, cpu, thread),
@@ -366,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
366 if ((old & md->mask) + size != ((old + size) & md->mask)) { 375 if ((old & md->mask) + size != ((old + size) & md->mask)) {
367 unsigned int offset = old; 376 unsigned int offset = old;
368 unsigned int len = min(sizeof(*event), size), cpy; 377 unsigned int len = min(sizeof(*event), size), cpy;
369 void *dst = &evlist->event_copy; 378 void *dst = &md->event_copy;
370 379
371 do { 380 do {
372 cpy = min(md->mask + 1 - (offset & md->mask), len); 381 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -376,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
376 len -= cpy; 385 len -= cpy;
377 } while (len); 386 } while (len);
378 387
379 event = &evlist->event_copy; 388 event = &md->event_copy;
380 } 389 }
381 390
382 old += size; 391 old += size;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 56003f779e60..2dd07bd60b4f 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -17,10 +17,18 @@ struct perf_record_opts;
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
19 19
20struct perf_mmap {
21 void *base;
22 int mask;
23 unsigned int prev;
24 union perf_event event_copy;
25};
26
20struct perf_evlist { 27struct perf_evlist {
21 struct list_head entries; 28 struct list_head entries;
22 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; 29 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
23 int nr_entries; 30 int nr_entries;
31 int nr_groups;
24 int nr_fds; 32 int nr_fds;
25 int nr_mmaps; 33 int nr_mmaps;
26 int mmap_len; 34 int mmap_len;
@@ -29,7 +37,6 @@ struct perf_evlist {
29 pid_t pid; 37 pid_t pid;
30 } workload; 38 } workload;
31 bool overwrite; 39 bool overwrite;
32 union perf_event event_copy;
33 struct perf_mmap *mmap; 40 struct perf_mmap *mmap;
34 struct pollfd *pollfd; 41 struct pollfd *pollfd;
35 struct thread_map *threads; 42 struct thread_map *threads;
@@ -76,8 +83,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
76 83
77int perf_evlist__open(struct perf_evlist *evlist); 84int perf_evlist__open(struct perf_evlist *evlist);
78 85
79void perf_evlist__config_attrs(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
80 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
81 88
82int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int perf_evlist__prepare_workload(struct perf_evlist *evlist,
83 struct perf_record_opts *opts, 90 struct perf_record_opts *opts,
@@ -135,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
135} 142}
136 143
137size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 144size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
145
146static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
147{
148 struct perf_event_mmap_page *pc = mm->base;
149 int head = pc->data_head;
150 rmb();
151 return head;
152}
153
154static inline void perf_mmap__write_tail(struct perf_mmap *md,
155 unsigned long tail)
156{
157 struct perf_event_mmap_page *pc = md->base;
158
159 /*
160 * ensure all reads are done before we write the tail out.
161 */
162 /* mb(); */
163 pc->data_tail = tail;
164}
165
138#endif /* __PERF_EVLIST_H */ 166#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1b16dd1edc8e..9c82f98f26de 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)
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists)
50 pthread_mutex_init(&hists->lock, NULL); 55 pthread_mutex_init(&hists->lock, NULL);
51} 56}
52 57
58void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
59 enum perf_event_sample_format bit)
60{
61 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64);
64 }
65}
66
67void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
68 enum perf_event_sample_format bit)
69{
70 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64);
73 }
74}
75
76void perf_evsel__set_sample_id(struct perf_evsel *evsel)
77{
78 perf_evsel__set_sample_bit(evsel, ID);
79 evsel->attr.read_format |= PERF_FORMAT_ID;
80}
81
53void perf_evsel__init(struct perf_evsel *evsel, 82void perf_evsel__init(struct perf_evsel *evsel,
54 struct perf_event_attr *attr, int idx) 83 struct perf_event_attr *attr, int idx)
55{ 84{
56 evsel->idx = idx; 85 evsel->idx = idx;
57 evsel->attr = *attr; 86 evsel->attr = *attr;
87 evsel->leader = evsel;
58 INIT_LIST_HEAD(&evsel->node); 88 INIT_LIST_HEAD(&evsel->node);
59 hists__init(&evsel->hists); 89 hists__init(&evsel->hists);
60 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -404,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
404 return evsel->name ?: "unknown"; 434 return evsel->name ?: "unknown";
405} 435}
406 436
437const char *perf_evsel__group_name(struct perf_evsel *evsel)
438{
439 return evsel->group_name ?: "anon group";
440}
441
442int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
443{
444 int ret;
445 struct perf_evsel *pos;
446 const char *group_name = perf_evsel__group_name(evsel);
447
448 ret = scnprintf(buf, size, "%s", group_name);
449
450 ret += scnprintf(buf + ret, size - ret, " { %s",
451 perf_evsel__name(evsel));
452
453 for_each_group_member(pos, evsel)
454 ret += scnprintf(buf + ret, size - ret, ", %s",
455 perf_evsel__name(pos));
456
457 ret += scnprintf(buf + ret, size - ret, " }");
458
459 return ret;
460}
461
407/* 462/*
408 * The enable_on_exec/disabled value strategy: 463 * The enable_on_exec/disabled value strategy:
409 * 464 *
@@ -438,13 +493,11 @@ void perf_evsel__config(struct perf_evsel *evsel,
438 struct perf_event_attr *attr = &evsel->attr; 493 struct perf_event_attr *attr = &evsel->attr;
439 int track = !evsel->idx; /* only the first counter needs these */ 494 int track = !evsel->idx; /* only the first counter needs these */
440 495
441 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 496 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
442 attr->inherit = !opts->no_inherit; 497 attr->inherit = !opts->no_inherit;
443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
444 PERF_FORMAT_TOTAL_TIME_RUNNING |
445 PERF_FORMAT_ID;
446 498
447 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 499 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID);
448 501
449 /* 502 /*
450 * We default some events to a 1 default interval. But keep 503 * We default some events to a 1 default interval. But keep
@@ -453,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
453 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 506 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
454 opts->user_interval != ULLONG_MAX)) { 507 opts->user_interval != ULLONG_MAX)) {
455 if (opts->freq) { 508 if (opts->freq) {
456 attr->sample_type |= PERF_SAMPLE_PERIOD; 509 perf_evsel__set_sample_bit(evsel, PERIOD);
457 attr->freq = 1; 510 attr->freq = 1;
458 attr->sample_freq = opts->freq; 511 attr->sample_freq = opts->freq;
459 } else { 512 } else {
@@ -468,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel,
468 attr->inherit_stat = 1; 521 attr->inherit_stat = 1;
469 522
470 if (opts->sample_address) { 523 if (opts->sample_address) {
471 attr->sample_type |= PERF_SAMPLE_ADDR; 524 perf_evsel__set_sample_bit(evsel, ADDR);
472 attr->mmap_data = track; 525 attr->mmap_data = track;
473 } 526 }
474 527
475 if (opts->call_graph) { 528 if (opts->call_graph) {
476 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 529 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
477 530
478 if (opts->call_graph == CALLCHAIN_DWARF) { 531 if (opts->call_graph == CALLCHAIN_DWARF) {
479 attr->sample_type |= PERF_SAMPLE_REGS_USER | 532 perf_evsel__set_sample_bit(evsel, REGS_USER);
480 PERF_SAMPLE_STACK_USER; 533 perf_evsel__set_sample_bit(evsel, STACK_USER);
481 attr->sample_regs_user = PERF_REGS_MASK; 534 attr->sample_regs_user = PERF_REGS_MASK;
482 attr->sample_stack_user = opts->stack_dump_size; 535 attr->sample_stack_user = opts->stack_dump_size;
483 attr->exclude_callchain_user = 1; 536 attr->exclude_callchain_user = 1;
@@ -485,20 +538,20 @@ void perf_evsel__config(struct perf_evsel *evsel,
485 } 538 }
486 539
487 if (perf_target__has_cpu(&opts->target)) 540 if (perf_target__has_cpu(&opts->target))
488 attr->sample_type |= PERF_SAMPLE_CPU; 541 perf_evsel__set_sample_bit(evsel, CPU);
489 542
490 if (opts->period) 543 if (opts->period)
491 attr->sample_type |= PERF_SAMPLE_PERIOD; 544 perf_evsel__set_sample_bit(evsel, PERIOD);
492 545
493 if (!opts->sample_id_all_missing && 546 if (!perf_missing_features.sample_id_all &&
494 (opts->sample_time || !opts->no_inherit || 547 (opts->sample_time || !opts->no_inherit ||
495 perf_target__has_cpu(&opts->target))) 548 perf_target__has_cpu(&opts->target)))
496 attr->sample_type |= PERF_SAMPLE_TIME; 549 perf_evsel__set_sample_bit(evsel, TIME);
497 550
498 if (opts->raw_samples) { 551 if (opts->raw_samples) {
499 attr->sample_type |= PERF_SAMPLE_TIME; 552 perf_evsel__set_sample_bit(evsel, TIME);
500 attr->sample_type |= PERF_SAMPLE_RAW; 553 perf_evsel__set_sample_bit(evsel, RAW);
501 attr->sample_type |= PERF_SAMPLE_CPU; 554 perf_evsel__set_sample_bit(evsel, CPU);
502 } 555 }
503 556
504 if (opts->no_delay) { 557 if (opts->no_delay) {
@@ -506,7 +559,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
506 attr->wakeup_events = 1; 559 attr->wakeup_events = 1;
507 } 560 }
508 if (opts->branch_stack) { 561 if (opts->branch_stack) {
509 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; 562 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
510 attr->branch_sample_type = opts->branch_stack; 563 attr->branch_sample_type = opts->branch_stack;
511 } 564 }
512 565
@@ -519,14 +572,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
519 * Disabling only independent events or group leaders, 572 * Disabling only independent events or group leaders,
520 * keeping group members enabled. 573 * keeping group members enabled.
521 */ 574 */
522 if (!perf_evsel__is_group_member(evsel)) 575 if (perf_evsel__is_group_leader(evsel))
523 attr->disabled = 1; 576 attr->disabled = 1;
524 577
525 /* 578 /*
526 * Setting enable_on_exec for independent events and 579 * Setting enable_on_exec for independent events and
527 * group leaders for traced executed by perf. 580 * group leaders for traced executed by perf.
528 */ 581 */
529 if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel)) 582 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
530 attr->enable_on_exec = 1; 583 attr->enable_on_exec = 1;
531} 584}
532 585
@@ -612,6 +665,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
612 } 665 }
613} 666}
614 667
668void perf_evsel__free_counts(struct perf_evsel *evsel)
669{
670 free(evsel->counts);
671}
672
615void perf_evsel__exit(struct perf_evsel *evsel) 673void perf_evsel__exit(struct perf_evsel *evsel)
616{ 674{
617 assert(list_empty(&evsel->node)); 675 assert(list_empty(&evsel->node));
@@ -631,6 +689,28 @@ void perf_evsel__delete(struct perf_evsel *evsel)
631 free(evsel); 689 free(evsel);
632} 690}
633 691
692static inline void compute_deltas(struct perf_evsel *evsel,
693 int cpu,
694 struct perf_counts_values *count)
695{
696 struct perf_counts_values tmp;
697
698 if (!evsel->prev_raw_counts)
699 return;
700
701 if (cpu == -1) {
702 tmp = evsel->prev_raw_counts->aggr;
703 evsel->prev_raw_counts->aggr = *count;
704 } else {
705 tmp = evsel->prev_raw_counts->cpu[cpu];
706 evsel->prev_raw_counts->cpu[cpu] = *count;
707 }
708
709 count->val = count->val - tmp.val;
710 count->ena = count->ena - tmp.ena;
711 count->run = count->run - tmp.run;
712}
713
634int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 714int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
635 int cpu, int thread, bool scale) 715 int cpu, int thread, bool scale)
636{ 716{
@@ -646,6 +726,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
646 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 726 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
647 return -errno; 727 return -errno;
648 728
729 compute_deltas(evsel, cpu, &count);
730
649 if (scale) { 731 if (scale) {
650 if (count.run == 0) 732 if (count.run == 0)
651 count.val = 0; 733 count.val = 0;
@@ -684,6 +766,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
684 } 766 }
685 } 767 }
686 768
769 compute_deltas(evsel, -1, aggr);
770
687 evsel->counts->scaled = 0; 771 evsel->counts->scaled = 0;
688 if (scale) { 772 if (scale) {
689 if (aggr->run == 0) { 773 if (aggr->run == 0) {
@@ -707,7 +791,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
707 struct perf_evsel *leader = evsel->leader; 791 struct perf_evsel *leader = evsel->leader;
708 int fd; 792 int fd;
709 793
710 if (!perf_evsel__is_group_member(evsel)) 794 if (perf_evsel__is_group_leader(evsel))
711 return -1; 795 return -1;
712 796
713 /* 797 /*
@@ -738,6 +822,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
738 pid = evsel->cgrp->fd; 822 pid = evsel->cgrp->fd;
739 } 823 }
740 824
825fallback_missing_features:
826 if (perf_missing_features.exclude_guest)
827 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
828retry_sample_id:
829 if (perf_missing_features.sample_id_all)
830 evsel->attr.sample_id_all = 0;
831
741 for (cpu = 0; cpu < cpus->nr; cpu++) { 832 for (cpu = 0; cpu < cpus->nr; cpu++) {
742 833
743 for (thread = 0; thread < threads->nr; thread++) { 834 for (thread = 0; thread < threads->nr; thread++) {
@@ -754,13 +845,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
754 group_fd, flags); 845 group_fd, flags);
755 if (FD(evsel, cpu, thread) < 0) { 846 if (FD(evsel, cpu, thread) < 0) {
756 err = -errno; 847 err = -errno;
757 goto out_close; 848 goto try_fallback;
758 } 849 }
759 } 850 }
760 } 851 }
761 852
762 return 0; 853 return 0;
763 854
855try_fallback:
856 if (err != -EINVAL || cpu > 0 || thread > 0)
857 goto out_close;
858
859 if (!perf_missing_features.exclude_guest &&
860 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
861 perf_missing_features.exclude_guest = true;
862 goto fallback_missing_features;
863 } else if (!perf_missing_features.sample_id_all) {
864 perf_missing_features.sample_id_all = true;
865 goto retry_sample_id;
866 }
867
764out_close: 868out_close:
765 do { 869 do {
766 while (--thread >= 0) { 870 while (--thread >= 0) {
@@ -1205,3 +1309,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1205 1309
1206 return 0; 1310 return 0;
1207} 1311}
1312
1313static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
1314{
1315 va_list args;
1316 int ret = 0;
1317
1318 if (!*first) {
1319 ret += fprintf(fp, ",");
1320 } else {
1321 ret += fprintf(fp, ":");
1322 *first = false;
1323 }
1324
1325 va_start(args, fmt);
1326 ret += vfprintf(fp, fmt, args);
1327 va_end(args);
1328 return ret;
1329}
1330
1331static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value)
1332{
1333 if (value == 0)
1334 return 0;
1335
1336 return comma_fprintf(fp, first, " %s: %" PRIu64, field, value);
1337}
1338
1339#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field)
1340
1341struct bit_names {
1342 int bit;
1343 const char *name;
1344};
1345
1346static int bits__fprintf(FILE *fp, const char *field, u64 value,
1347 struct bit_names *bits, bool *first)
1348{
1349 int i = 0, printed = comma_fprintf(fp, first, " %s: ", field);
1350 bool first_bit = true;
1351
1352 do {
1353 if (value & bits[i].bit) {
1354 printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name);
1355 first_bit = false;
1356 }
1357 } while (bits[++i].name != NULL);
1358
1359 return printed;
1360}
1361
1362static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1363{
1364#define bit_name(n) { PERF_SAMPLE_##n, #n }
1365 struct bit_names bits[] = {
1366 bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR),
1367 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1368 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1369 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1370 { .name = NULL, }
1371 };
1372#undef bit_name
1373 return bits__fprintf(fp, "sample_type", value, bits, first);
1374}
1375
1376static int read_format__fprintf(FILE *fp, bool *first, u64 value)
1377{
1378#define bit_name(n) { PERF_FORMAT_##n, #n }
1379 struct bit_names bits[] = {
1380 bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING),
1381 bit_name(ID), bit_name(GROUP),
1382 { .name = NULL, }
1383 };
1384#undef bit_name
1385 return bits__fprintf(fp, "read_format", value, bits, first);
1386}
1387
1388int perf_evsel__fprintf(struct perf_evsel *evsel,
1389 struct perf_attr_details *details, FILE *fp)
1390{
1391 bool first = true;
1392 int printed = 0;
1393
1394 if (details->event_group) {
1395 struct perf_evsel *pos;
1396
1397 if (!perf_evsel__is_group_leader(evsel))
1398 return 0;
1399
1400 if (evsel->nr_members > 1)
1401 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
1402
1403 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1404 for_each_group_member(pos, evsel)
1405 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
1406
1407 if (evsel->nr_members > 1)
1408 printed += fprintf(fp, "}");
1409 goto out;
1410 }
1411
1412 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1413
1414 if (details->verbose || details->freq) {
1415 printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64,
1416 (u64)evsel->attr.sample_freq);
1417 }
1418
1419 if (details->verbose) {
1420 if_print(type);
1421 if_print(config);
1422 if_print(config1);
1423 if_print(config2);
1424 if_print(size);
1425 printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type);
1426 if (evsel->attr.read_format)
1427 printed += read_format__fprintf(fp, &first, evsel->attr.read_format);
1428 if_print(disabled);
1429 if_print(inherit);
1430 if_print(pinned);
1431 if_print(exclusive);
1432 if_print(exclude_user);
1433 if_print(exclude_kernel);
1434 if_print(exclude_hv);
1435 if_print(exclude_idle);
1436 if_print(mmap);
1437 if_print(comm);
1438 if_print(freq);
1439 if_print(inherit_stat);
1440 if_print(enable_on_exec);
1441 if_print(task);
1442 if_print(watermark);
1443 if_print(precise_ip);
1444 if_print(mmap_data);
1445 if_print(sample_id_all);
1446 if_print(exclude_host);
1447 if_print(exclude_guest);
1448 if_print(__reserved_1);
1449 if_print(wakeup_events);
1450 if_print(bp_type);
1451 if_print(branch_sample_type);
1452 }
1453out:
1454 fputc('\n', fp);
1455 return ++printed;
1456}
1457
1458bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1459 char *msg, size_t msgsize)
1460{
1461 if ((err == ENOENT || err == ENXIO) &&
1462 evsel->attr.type == PERF_TYPE_HARDWARE &&
1463 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1464 /*
1465 * If it's cycles then fall back to hrtimer based
1466 * cpu-clock-tick sw counter, which is always available even if
1467 * no PMU support.
1468 *
1469 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
1470 * b0a873e).
1471 */
1472 scnprintf(msg, msgsize, "%s",
1473"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
1474
1475 evsel->attr.type = PERF_TYPE_SOFTWARE;
1476 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
1477
1478 free(evsel->name);
1479 evsel->name = NULL;
1480 return true;
1481 }
1482
1483 return false;
1484}
1485
1486int perf_evsel__open_strerror(struct perf_evsel *evsel,
1487 struct perf_target *target,
1488 int err, char *msg, size_t size)
1489{
1490 switch (err) {
1491 case EPERM:
1492 case EACCES:
1493 return scnprintf(msg, size, "%s",
1494 "You may not have permission to collect %sstats.\n"
1495 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1496 " -1 - Not paranoid at all\n"
1497 " 0 - Disallow raw tracepoint access for unpriv\n"
1498 " 1 - Disallow cpu events for unpriv\n"
1499 " 2 - Disallow kernel profiling for unpriv",
1500 target->system_wide ? "system-wide " : "");
1501 case ENOENT:
1502 return scnprintf(msg, size, "The %s event is not supported.",
1503 perf_evsel__name(evsel));
1504 case EMFILE:
1505 return scnprintf(msg, size, "%s",
1506 "Too many events are opened.\n"
1507 "Try again after reducing the number of events.");
1508 case ENODEV:
1509 if (target->cpu_list)
1510 return scnprintf(msg, size, "%s",
1511 "No such device - did you specify an out-of-range profile CPU?\n");
1512 break;
1513 case EOPNOTSUPP:
1514 if (evsel->attr.precise_ip)
1515 return scnprintf(msg, size, "%s",
1516 "\'precise\' request may not be supported. Try removing 'p' modifier.");
1517#if defined(__i386__) || defined(__x86_64__)
1518 if (evsel->attr.type == PERF_TYPE_HARDWARE)
1519 return scnprintf(msg, size, "%s",
1520 "No hardware sampling interrupt available.\n"
1521 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
1522#endif
1523 break;
1524 default:
1525 break;
1526 }
1527
1528 return scnprintf(msg, size,
1529 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n"
1530 "/bin/dmesg may provide additional information.\n"
1531 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
1532 err, strerror(err), perf_evsel__name(evsel));
1533}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d2b8017438c..52021c3087df 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -53,6 +53,7 @@ struct perf_evsel {
53 struct xyarray *sample_id; 53 struct xyarray *sample_id;
54 u64 *id; 54 u64 *id;
55 struct perf_counts *counts; 55 struct perf_counts *counts;
56 struct perf_counts *prev_raw_counts;
56 int idx; 57 int idx;
57 u32 ids; 58 u32 ids;
58 struct hists hists; 59 struct hists hists;
@@ -73,10 +74,13 @@ struct perf_evsel {
73 bool needs_swap; 74 bool needs_swap;
74 /* parse modifier helper */ 75 /* parse modifier helper */
75 int exclude_GH; 76 int exclude_GH;
77 int nr_members;
76 struct perf_evsel *leader; 78 struct perf_evsel *leader;
77 char *group_name; 79 char *group_name;
78}; 80};
79 81
82#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
83
80struct cpu_map; 84struct cpu_map;
81struct thread_map; 85struct thread_map;
82struct perf_evlist; 86struct perf_evlist;
@@ -110,14 +114,30 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
110int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 114int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
111 char *bf, size_t size); 115 char *bf, size_t size);
112const char *perf_evsel__name(struct perf_evsel *evsel); 116const char *perf_evsel__name(struct perf_evsel *evsel);
117const char *perf_evsel__group_name(struct perf_evsel *evsel);
118int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
113 119
114int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 120int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
115int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
116int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
117void perf_evsel__free_fd(struct perf_evsel *evsel); 123void perf_evsel__free_fd(struct perf_evsel *evsel);
118void perf_evsel__free_id(struct perf_evsel *evsel); 124void perf_evsel__free_id(struct perf_evsel *evsel);
125void perf_evsel__free_counts(struct perf_evsel *evsel);
119void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 126void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
120 127
128void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
129 enum perf_event_sample_format bit);
130void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
131 enum perf_event_sample_format bit);
132
133#define perf_evsel__set_sample_bit(evsel, bit) \
134 __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit)
135
136#define perf_evsel__reset_sample_bit(evsel, bit) \
137 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
138
139void perf_evsel__set_sample_id(struct perf_evsel *evsel);
140
121int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 141int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122 const char *filter); 142 const char *filter);
123 143
@@ -226,8 +246,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
226 return list_entry(evsel->node.next, struct perf_evsel, node); 246 return list_entry(evsel->node.next, struct perf_evsel, node);
227} 247}
228 248
229static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel) 249static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
250{
251 return evsel->leader == evsel;
252}
253
254struct perf_attr_details {
255 bool freq;
256 bool verbose;
257 bool event_group;
258};
259
260int perf_evsel__fprintf(struct perf_evsel *evsel,
261 struct perf_attr_details *details, FILE *fp);
262
263bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
264 char *msg, size_t msgsize);
265int perf_evsel__open_strerror(struct perf_evsel *evsel,
266 struct perf_target *target,
267 int err, char *msg, size_t size);
268
269static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
230{ 270{
231 return evsel->leader != NULL; 271 return evsel->idx - evsel->leader->idx;
232} 272}
273
274#define for_each_group_member(_evsel, _leader) \
275for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
276 (_evsel) && (_evsel)->leader == (_leader); \
277 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
278
233#endif /* __PERF_EVSEL_H */ 279#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b7da4634a047..f4bfd79ef6a7 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)
@@ -313,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
313 if (is_kallsyms) { 313 if (is_kallsyms) {
314 if (symbol_conf.kptr_restrict) { 314 if (symbol_conf.kptr_restrict) {
315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
316 return 0; 316 err = 0;
317 goto out_free;
317 } 318 }
318 realname = (char *) name; 319 realname = (char *) name;
319 } else 320 } else
@@ -448,9 +449,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
448 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 449 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
449 return -1; 450 return -1;
450 451
451 ret = machine__cache_build_ids(&session->host_machine, debugdir); 452 ret = machine__cache_build_ids(&session->machines.host, debugdir);
452 453
453 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 454 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
454 struct machine *pos = rb_entry(nd, struct machine, rb_node); 455 struct machine *pos = rb_entry(nd, struct machine, rb_node);
455 ret |= machine__cache_build_ids(pos, debugdir); 456 ret |= machine__cache_build_ids(pos, debugdir);
456 } 457 }
@@ -467,9 +468,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) 468static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
468{ 469{
469 struct rb_node *nd; 470 struct rb_node *nd;
470 bool ret = machine__read_build_ids(&session->host_machine, with_hits); 471 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
471 472
472 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 473 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
473 struct machine *pos = rb_entry(nd, struct machine, rb_node); 474 struct machine *pos = rb_entry(nd, struct machine, rb_node);
474 ret |= machine__read_build_ids(pos, with_hits); 475 ret |= machine__read_build_ids(pos, with_hits);
475 } 476 }
@@ -954,6 +955,7 @@ static int write_topo_node(int fd, int node)
954 } 955 }
955 956
956 fclose(fp); 957 fclose(fp);
958 fp = NULL;
957 959
958 ret = do_write(fd, &mem_total, sizeof(u64)); 960 ret = do_write(fd, &mem_total, sizeof(u64));
959 if (ret) 961 if (ret)
@@ -980,7 +982,8 @@ static int write_topo_node(int fd, int node)
980 ret = do_write_string(fd, buf); 982 ret = do_write_string(fd, buf);
981done: 983done:
982 free(buf); 984 free(buf);
983 fclose(fp); 985 if (fp)
986 fclose(fp);
984 return ret; 987 return ret;
985} 988}
986 989
@@ -1051,16 +1054,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1051 struct perf_pmu *pmu = NULL; 1054 struct perf_pmu *pmu = NULL;
1052 off_t offset = lseek(fd, 0, SEEK_CUR); 1055 off_t offset = lseek(fd, 0, SEEK_CUR);
1053 __u32 pmu_num = 0; 1056 __u32 pmu_num = 0;
1057 int ret;
1054 1058
1055 /* write real pmu_num later */ 1059 /* write real pmu_num later */
1056 do_write(fd, &pmu_num, sizeof(pmu_num)); 1060 ret = do_write(fd, &pmu_num, sizeof(pmu_num));
1061 if (ret < 0)
1062 return ret;
1057 1063
1058 while ((pmu = perf_pmu__scan(pmu))) { 1064 while ((pmu = perf_pmu__scan(pmu))) {
1059 if (!pmu->name) 1065 if (!pmu->name)
1060 continue; 1066 continue;
1061 pmu_num++; 1067 pmu_num++;
1062 do_write(fd, &pmu->type, sizeof(pmu->type)); 1068
1063 do_write_string(fd, pmu->name); 1069 ret = do_write(fd, &pmu->type, sizeof(pmu->type));
1070 if (ret < 0)
1071 return ret;
1072
1073 ret = do_write_string(fd, pmu->name);
1074 if (ret < 0)
1075 return ret;
1064 } 1076 }
1065 1077
1066 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 1078 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1073,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1073} 1085}
1074 1086
1075/* 1087/*
1088 * File format:
1089 *
1090 * struct group_descs {
1091 * u32 nr_groups;
1092 * struct group_desc {
1093 * char name[];
1094 * u32 leader_idx;
1095 * u32 nr_members;
1096 * }[nr_groups];
1097 * };
1098 */
1099static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1100 struct perf_evlist *evlist)
1101{
1102 u32 nr_groups = evlist->nr_groups;
1103 struct perf_evsel *evsel;
1104 int ret;
1105
1106 ret = do_write(fd, &nr_groups, sizeof(nr_groups));
1107 if (ret < 0)
1108 return ret;
1109
1110 list_for_each_entry(evsel, &evlist->entries, node) {
1111 if (perf_evsel__is_group_leader(evsel) &&
1112 evsel->nr_members > 1) {
1113 const char *name = evsel->group_name ?: "{anon_group}";
1114 u32 leader_idx = evsel->idx;
1115 u32 nr_members = evsel->nr_members;
1116
1117 ret = do_write_string(fd, name);
1118 if (ret < 0)
1119 return ret;
1120
1121 ret = do_write(fd, &leader_idx, sizeof(leader_idx));
1122 if (ret < 0)
1123 return ret;
1124
1125 ret = do_write(fd, &nr_members, sizeof(nr_members));
1126 if (ret < 0)
1127 return ret;
1128 }
1129 }
1130 return 0;
1131}
1132
1133/*
1076 * default get_cpuid(): nothing gets recorded 1134 * default get_cpuid(): nothing gets recorded
1077 * actual implementation must be in arch/$(ARCH)/util/header.c 1135 * actual implementation must be in arch/$(ARCH)/util/header.c
1078 */ 1136 */
@@ -1209,14 +1267,14 @@ read_event_desc(struct perf_header *ph, int fd)
1209 size_t msz; 1267 size_t msz;
1210 1268
1211 /* number of events */ 1269 /* number of events */
1212 ret = read(fd, &nre, sizeof(nre)); 1270 ret = readn(fd, &nre, sizeof(nre));
1213 if (ret != (ssize_t)sizeof(nre)) 1271 if (ret != (ssize_t)sizeof(nre))
1214 goto error; 1272 goto error;
1215 1273
1216 if (ph->needs_swap) 1274 if (ph->needs_swap)
1217 nre = bswap_32(nre); 1275 nre = bswap_32(nre);
1218 1276
1219 ret = read(fd, &sz, sizeof(sz)); 1277 ret = readn(fd, &sz, sizeof(sz));
1220 if (ret != (ssize_t)sizeof(sz)) 1278 if (ret != (ssize_t)sizeof(sz))
1221 goto error; 1279 goto error;
1222 1280
@@ -1244,7 +1302,7 @@ read_event_desc(struct perf_header *ph, int fd)
1244 * must read entire on-file attr struct to 1302 * must read entire on-file attr struct to
1245 * sync up with layout. 1303 * sync up with layout.
1246 */ 1304 */
1247 ret = read(fd, buf, sz); 1305 ret = readn(fd, buf, sz);
1248 if (ret != (ssize_t)sz) 1306 if (ret != (ssize_t)sz)
1249 goto error; 1307 goto error;
1250 1308
@@ -1253,7 +1311,7 @@ read_event_desc(struct perf_header *ph, int fd)
1253 1311
1254 memcpy(&evsel->attr, buf, msz); 1312 memcpy(&evsel->attr, buf, msz);
1255 1313
1256 ret = read(fd, &nr, sizeof(nr)); 1314 ret = readn(fd, &nr, sizeof(nr));
1257 if (ret != (ssize_t)sizeof(nr)) 1315 if (ret != (ssize_t)sizeof(nr))
1258 goto error; 1316 goto error;
1259 1317
@@ -1274,7 +1332,7 @@ read_event_desc(struct perf_header *ph, int fd)
1274 evsel->id = id; 1332 evsel->id = id;
1275 1333
1276 for (j = 0 ; j < nr; j++) { 1334 for (j = 0 ; j < nr; j++) {
1277 ret = read(fd, id, sizeof(*id)); 1335 ret = readn(fd, id, sizeof(*id));
1278 if (ret != (ssize_t)sizeof(*id)) 1336 if (ret != (ssize_t)sizeof(*id))
1279 goto error; 1337 goto error;
1280 if (ph->needs_swap) 1338 if (ph->needs_swap)
@@ -1435,6 +1493,31 @@ error:
1435 fprintf(fp, "# pmu mappings: unable to read\n"); 1493 fprintf(fp, "# pmu mappings: unable to read\n");
1436} 1494}
1437 1495
1496static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1497 FILE *fp)
1498{
1499 struct perf_session *session;
1500 struct perf_evsel *evsel;
1501 u32 nr = 0;
1502
1503 session = container_of(ph, struct perf_session, header);
1504
1505 list_for_each_entry(evsel, &session->evlist->entries, node) {
1506 if (perf_evsel__is_group_leader(evsel) &&
1507 evsel->nr_members > 1) {
1508 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
1509 perf_evsel__name(evsel));
1510
1511 nr = evsel->nr_members - 1;
1512 } else if (nr) {
1513 fprintf(fp, ",%s", perf_evsel__name(evsel));
1514
1515 if (--nr == 0)
1516 fprintf(fp, "}\n");
1517 }
1518 }
1519}
1520
1438static int __event_process_build_id(struct build_id_event *bev, 1521static int __event_process_build_id(struct build_id_event *bev,
1439 char *filename, 1522 char *filename,
1440 struct perf_session *session) 1523 struct perf_session *session)
@@ -1506,14 +1589,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1506 while (offset < limit) { 1589 while (offset < limit) {
1507 ssize_t len; 1590 ssize_t len;
1508 1591
1509 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 1592 if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1510 return -1; 1593 return -1;
1511 1594
1512 if (header->needs_swap) 1595 if (header->needs_swap)
1513 perf_event_header__bswap(&old_bev.header); 1596 perf_event_header__bswap(&old_bev.header);
1514 1597
1515 len = old_bev.header.size - sizeof(old_bev); 1598 len = old_bev.header.size - sizeof(old_bev);
1516 if (read(input, filename, len) != len) 1599 if (readn(input, filename, len) != len)
1517 return -1; 1600 return -1;
1518 1601
1519 bev.header = old_bev.header; 1602 bev.header = old_bev.header;
@@ -1548,14 +1631,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
1548 while (offset < limit) { 1631 while (offset < limit) {
1549 ssize_t len; 1632 ssize_t len;
1550 1633
1551 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 1634 if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
1552 goto out; 1635 goto out;
1553 1636
1554 if (header->needs_swap) 1637 if (header->needs_swap)
1555 perf_event_header__bswap(&bev.header); 1638 perf_event_header__bswap(&bev.header);
1556 1639
1557 len = bev.header.size - sizeof(bev); 1640 len = bev.header.size - sizeof(bev);
1558 if (read(input, filename, len) != len) 1641 if (readn(input, filename, len) != len)
1559 goto out; 1642 goto out;
1560 /* 1643 /*
1561 * The a1645ce1 changeset: 1644 * The a1645ce1 changeset:
@@ -1641,7 +1724,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1641 size_t ret; 1724 size_t ret;
1642 u32 nr; 1725 u32 nr;
1643 1726
1644 ret = read(fd, &nr, sizeof(nr)); 1727 ret = readn(fd, &nr, sizeof(nr));
1645 if (ret != sizeof(nr)) 1728 if (ret != sizeof(nr))
1646 return -1; 1729 return -1;
1647 1730
@@ -1650,7 +1733,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1650 1733
1651 ph->env.nr_cpus_online = nr; 1734 ph->env.nr_cpus_online = nr;
1652 1735
1653 ret = read(fd, &nr, sizeof(nr)); 1736 ret = readn(fd, &nr, sizeof(nr));
1654 if (ret != sizeof(nr)) 1737 if (ret != sizeof(nr))
1655 return -1; 1738 return -1;
1656 1739
@@ -1684,7 +1767,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1684 uint64_t mem; 1767 uint64_t mem;
1685 size_t ret; 1768 size_t ret;
1686 1769
1687 ret = read(fd, &mem, sizeof(mem)); 1770 ret = readn(fd, &mem, sizeof(mem));
1688 if (ret != sizeof(mem)) 1771 if (ret != sizeof(mem))
1689 return -1; 1772 return -1;
1690 1773
@@ -1756,7 +1839,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1756 u32 nr, i; 1839 u32 nr, i;
1757 struct strbuf sb; 1840 struct strbuf sb;
1758 1841
1759 ret = read(fd, &nr, sizeof(nr)); 1842 ret = readn(fd, &nr, sizeof(nr));
1760 if (ret != sizeof(nr)) 1843 if (ret != sizeof(nr))
1761 return -1; 1844 return -1;
1762 1845
@@ -1792,7 +1875,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1792 char *str; 1875 char *str;
1793 struct strbuf sb; 1876 struct strbuf sb;
1794 1877
1795 ret = read(fd, &nr, sizeof(nr)); 1878 ret = readn(fd, &nr, sizeof(nr));
1796 if (ret != sizeof(nr)) 1879 if (ret != sizeof(nr))
1797 return -1; 1880 return -1;
1798 1881
@@ -1813,7 +1896,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1813 } 1896 }
1814 ph->env.sibling_cores = strbuf_detach(&sb, NULL); 1897 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1815 1898
1816 ret = read(fd, &nr, sizeof(nr)); 1899 ret = readn(fd, &nr, sizeof(nr));
1817 if (ret != sizeof(nr)) 1900 if (ret != sizeof(nr))
1818 return -1; 1901 return -1;
1819 1902
@@ -1850,7 +1933,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1850 struct strbuf sb; 1933 struct strbuf sb;
1851 1934
1852 /* nr nodes */ 1935 /* nr nodes */
1853 ret = read(fd, &nr, sizeof(nr)); 1936 ret = readn(fd, &nr, sizeof(nr));
1854 if (ret != sizeof(nr)) 1937 if (ret != sizeof(nr))
1855 goto error; 1938 goto error;
1856 1939
@@ -1862,15 +1945,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1862 1945
1863 for (i = 0; i < nr; i++) { 1946 for (i = 0; i < nr; i++) {
1864 /* node number */ 1947 /* node number */
1865 ret = read(fd, &node, sizeof(node)); 1948 ret = readn(fd, &node, sizeof(node));
1866 if (ret != sizeof(node)) 1949 if (ret != sizeof(node))
1867 goto error; 1950 goto error;
1868 1951
1869 ret = read(fd, &mem_total, sizeof(u64)); 1952 ret = readn(fd, &mem_total, sizeof(u64));
1870 if (ret != sizeof(u64)) 1953 if (ret != sizeof(u64))
1871 goto error; 1954 goto error;
1872 1955
1873 ret = read(fd, &mem_free, sizeof(u64)); 1956 ret = readn(fd, &mem_free, sizeof(u64));
1874 if (ret != sizeof(u64)) 1957 if (ret != sizeof(u64))
1875 goto error; 1958 goto error;
1876 1959
@@ -1909,7 +1992,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1909 u32 type; 1992 u32 type;
1910 struct strbuf sb; 1993 struct strbuf sb;
1911 1994
1912 ret = read(fd, &pmu_num, sizeof(pmu_num)); 1995 ret = readn(fd, &pmu_num, sizeof(pmu_num));
1913 if (ret != sizeof(pmu_num)) 1996 if (ret != sizeof(pmu_num))
1914 return -1; 1997 return -1;
1915 1998
@@ -1925,7 +2008,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1925 strbuf_init(&sb, 128); 2008 strbuf_init(&sb, 128);
1926 2009
1927 while (pmu_num) { 2010 while (pmu_num) {
1928 if (read(fd, &type, sizeof(type)) != sizeof(type)) 2011 if (readn(fd, &type, sizeof(type)) != sizeof(type))
1929 goto error; 2012 goto error;
1930 if (ph->needs_swap) 2013 if (ph->needs_swap)
1931 type = bswap_32(type); 2014 type = bswap_32(type);
@@ -1949,6 +2032,98 @@ error:
1949 return -1; 2032 return -1;
1950} 2033}
1951 2034
2035static int process_group_desc(struct perf_file_section *section __maybe_unused,
2036 struct perf_header *ph, int fd,
2037 void *data __maybe_unused)
2038{
2039 size_t ret = -1;
2040 u32 i, nr, nr_groups;
2041 struct perf_session *session;
2042 struct perf_evsel *evsel, *leader = NULL;
2043 struct group_desc {
2044 char *name;
2045 u32 leader_idx;
2046 u32 nr_members;
2047 } *desc;
2048
2049 if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
2050 return -1;
2051
2052 if (ph->needs_swap)
2053 nr_groups = bswap_32(nr_groups);
2054
2055 ph->env.nr_groups = nr_groups;
2056 if (!nr_groups) {
2057 pr_debug("group desc not available\n");
2058 return 0;
2059 }
2060
2061 desc = calloc(nr_groups, sizeof(*desc));
2062 if (!desc)
2063 return -1;
2064
2065 for (i = 0; i < nr_groups; i++) {
2066 desc[i].name = do_read_string(fd, ph);
2067 if (!desc[i].name)
2068 goto out_free;
2069
2070 if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
2071 goto out_free;
2072
2073 if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
2074 goto out_free;
2075
2076 if (ph->needs_swap) {
2077 desc[i].leader_idx = bswap_32(desc[i].leader_idx);
2078 desc[i].nr_members = bswap_32(desc[i].nr_members);
2079 }
2080 }
2081
2082 /*
2083 * Rebuild group relationship based on the group_desc
2084 */
2085 session = container_of(ph, struct perf_session, header);
2086 session->evlist->nr_groups = nr_groups;
2087
2088 i = nr = 0;
2089 list_for_each_entry(evsel, &session->evlist->entries, node) {
2090 if (evsel->idx == (int) desc[i].leader_idx) {
2091 evsel->leader = evsel;
2092 /* {anon_group} is a dummy name */
2093 if (strcmp(desc[i].name, "{anon_group}"))
2094 evsel->group_name = desc[i].name;
2095 evsel->nr_members = desc[i].nr_members;
2096
2097 if (i >= nr_groups || nr > 0) {
2098 pr_debug("invalid group desc\n");
2099 goto out_free;
2100 }
2101
2102 leader = evsel;
2103 nr = evsel->nr_members - 1;
2104 i++;
2105 } else if (nr) {
2106 /* This is a group member */
2107 evsel->leader = leader;
2108
2109 nr--;
2110 }
2111 }
2112
2113 if (i != nr_groups || nr != 0) {
2114 pr_debug("invalid group desc\n");
2115 goto out_free;
2116 }
2117
2118 ret = 0;
2119out_free:
2120 while ((int) --i >= 0)
2121 free(desc[i].name);
2122 free(desc);
2123
2124 return ret;
2125}
2126
1952struct feature_ops { 2127struct feature_ops {
1953 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2128 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1954 void (*print)(struct perf_header *h, int fd, FILE *fp); 2129 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1988,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1988 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 2163 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1989 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 2164 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1990 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2165 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
2166 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1991}; 2167};
1992 2168
1993struct header_print_data { 2169struct header_print_data {
@@ -2077,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header,
2077 if (!nr_sections) 2253 if (!nr_sections)
2078 return 0; 2254 return 0;
2079 2255
2080 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); 2256 feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
2081 if (feat_sec == NULL) 2257 if (feat_sec == NULL)
2082 return -ENOMEM; 2258 return -ENOMEM;
2083 2259
@@ -2249,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2249 if (!nr_sections) 2425 if (!nr_sections)
2250 return 0; 2426 return 0;
2251 2427
2252 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); 2428 feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
2253 if (!feat_sec) 2429 if (!feat_sec)
2254 return -1; 2430 return -1;
2255 2431
@@ -2912,16 +3088,22 @@ int perf_event__process_tracing_data(union perf_event *event,
2912 session->repipe); 3088 session->repipe);
2913 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3089 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
2914 3090
2915 if (read(session->fd, buf, padding) < 0) 3091 if (readn(session->fd, buf, padding) < 0) {
2916 die("reading input file"); 3092 pr_err("%s: reading input file", __func__);
3093 return -1;
3094 }
2917 if (session->repipe) { 3095 if (session->repipe) {
2918 int retw = write(STDOUT_FILENO, buf, padding); 3096 int retw = write(STDOUT_FILENO, buf, padding);
2919 if (retw <= 0 || retw != padding) 3097 if (retw <= 0 || retw != padding) {
2920 die("repiping tracing data padding"); 3098 pr_err("%s: repiping tracing data padding", __func__);
3099 return -1;
3100 }
2921 } 3101 }
2922 3102
2923 if (size_read + padding != size) 3103 if (size_read + padding != size) {
2924 die("tracing data size mismatch"); 3104 pr_err("%s: tracing data size mismatch", __func__);
3105 return -1;
3106 }
2925 3107
2926 perf_evlist__prepare_tracepoint_events(session->evlist, 3108 perf_evlist__prepare_tracepoint_events(session->evlist,
2927 session->pevent); 3109 session->pevent);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 20f0344accb1..c9fc55cada6d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC,
32 HEADER_LAST_FEATURE, 33 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
34}; 35};
@@ -79,6 +80,7 @@ struct perf_session_env {
79 char *numa_nodes; 80 char *numa_nodes;
80 int nr_pmu_mappings; 81 int nr_pmu_mappings;
81 char *pmu_mappings; 82 char *pmu_mappings;
83 int nr_groups;
82}; 84};
83 85
84struct perf_header { 86struct perf_header {
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cb17e2a8c6ed..f855941bebea 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "hist.h" 4#include "hist.h"
5#include "session.h" 5#include "session.h"
6#include "sort.h" 6#include "sort.h"
7#include "evsel.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -82,6 +83,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
82 hists__new_col_len(hists, HISTC_DSO, len); 83 hists__new_col_len(hists, HISTC_DSO, len);
83 } 84 }
84 85
86 if (h->parent)
87 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
88
85 if (h->branch_info) { 89 if (h->branch_info) {
86 int symlen; 90 int symlen;
87 /* 91 /*
@@ -242,6 +246,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
242 246
243 if (he->ms.map) 247 if (he->ms.map)
244 he->ms.map->referenced = true; 248 he->ms.map->referenced = true;
249
250 if (he->branch_info) {
251 if (he->branch_info->from.map)
252 he->branch_info->from.map->referenced = true;
253 if (he->branch_info->to.map)
254 he->branch_info->to.map->referenced = true;
255 }
256
245 if (symbol_conf.use_callchain) 257 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 258 callchain_init(he->callchain);
247 259
@@ -251,7 +263,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
251 return he; 263 return he;
252} 264}
253 265
254static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 266void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
255{ 267{
256 if (!h->filtered) { 268 if (!h->filtered) {
257 hists__calc_col_len(hists, h); 269 hists__calc_col_len(hists, h);
@@ -285,7 +297,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
285 parent = *p; 297 parent = *p;
286 he = rb_entry(parent, struct hist_entry, rb_node_in); 298 he = rb_entry(parent, struct hist_entry, rb_node_in);
287 299
288 cmp = hist_entry__cmp(entry, he); 300 /*
301 * Make sure that it receives arguments in a same order as
302 * hist_entry__collapse() so that we can use an appropriate
303 * function when searching an entry regardless which sort
304 * keys were used.
305 */
306 cmp = hist_entry__cmp(he, entry);
289 307
290 if (!cmp) { 308 if (!cmp) {
291 he_stat__add_period(&he->stat, period); 309 he_stat__add_period(&he->stat, period);
@@ -523,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists)
523 * reverse the map, sort on period. 541 * reverse the map, sort on period.
524 */ 542 */
525 543
544static int period_cmp(u64 period_a, u64 period_b)
545{
546 if (period_a > period_b)
547 return 1;
548 if (period_a < period_b)
549 return -1;
550 return 0;
551}
552
553static int hist_entry__sort_on_period(struct hist_entry *a,
554 struct hist_entry *b)
555{
556 int ret;
557 int i, nr_members;
558 struct perf_evsel *evsel;
559 struct hist_entry *pair;
560 u64 *periods_a, *periods_b;
561
562 ret = period_cmp(a->stat.period, b->stat.period);
563 if (ret || !symbol_conf.event_group)
564 return ret;
565
566 evsel = hists_to_evsel(a->hists);
567 nr_members = evsel->nr_members;
568 if (nr_members <= 1)
569 return ret;
570
571 periods_a = zalloc(sizeof(periods_a) * nr_members);
572 periods_b = zalloc(sizeof(periods_b) * nr_members);
573
574 if (!periods_a || !periods_b)
575 goto out;
576
577 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
578 evsel = hists_to_evsel(pair->hists);
579 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
580 }
581
582 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
583 evsel = hists_to_evsel(pair->hists);
584 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
585 }
586
587 for (i = 1; i < nr_members; i++) {
588 ret = period_cmp(periods_a[i], periods_b[i]);
589 if (ret)
590 break;
591 }
592
593out:
594 free(periods_a);
595 free(periods_b);
596
597 return ret;
598}
599
526static void __hists__insert_output_entry(struct rb_root *entries, 600static void __hists__insert_output_entry(struct rb_root *entries,
527 struct hist_entry *he, 601 struct hist_entry *he,
528 u64 min_callchain_hits) 602 u64 min_callchain_hits)
@@ -539,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
539 parent = *p; 613 parent = *p;
540 iter = rb_entry(parent, struct hist_entry, rb_node); 614 iter = rb_entry(parent, struct hist_entry, rb_node);
541 615
542 if (he->stat.period > iter->stat.period) 616 if (hist_entry__sort_on_period(he, iter) > 0)
543 p = &(*p)->rb_left; 617 p = &(*p)->rb_left;
544 else 618 else
545 p = &(*p)->rb_right; 619 p = &(*p)->rb_right;
@@ -711,25 +785,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
711 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 785 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
712} 786}
713 787
788void events_stats__inc(struct events_stats *stats, u32 type)
789{
790 ++stats->nr_events[0];
791 ++stats->nr_events[type];
792}
793
714void hists__inc_nr_events(struct hists *hists, u32 type) 794void hists__inc_nr_events(struct hists *hists, u32 type)
715{ 795{
716 ++hists->stats.nr_events[0]; 796 events_stats__inc(&hists->stats, type);
717 ++hists->stats.nr_events[type];
718} 797}
719 798
720static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 799static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
721 struct hist_entry *pair) 800 struct hist_entry *pair)
722{ 801{
723 struct rb_node **p = &hists->entries.rb_node; 802 struct rb_root *root;
803 struct rb_node **p;
724 struct rb_node *parent = NULL; 804 struct rb_node *parent = NULL;
725 struct hist_entry *he; 805 struct hist_entry *he;
726 int cmp; 806 int cmp;
727 807
808 if (sort__need_collapse)
809 root = &hists->entries_collapsed;
810 else
811 root = hists->entries_in;
812
813 p = &root->rb_node;
814
728 while (*p != NULL) { 815 while (*p != NULL) {
729 parent = *p; 816 parent = *p;
730 he = rb_entry(parent, struct hist_entry, rb_node); 817 he = rb_entry(parent, struct hist_entry, rb_node_in);
731 818
732 cmp = hist_entry__cmp(pair, he); 819 cmp = hist_entry__collapse(he, pair);
733 820
734 if (!cmp) 821 if (!cmp)
735 goto out; 822 goto out;
@@ -744,8 +831,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
744 if (he) { 831 if (he) {
745 memset(&he->stat, 0, sizeof(he->stat)); 832 memset(&he->stat, 0, sizeof(he->stat));
746 he->hists = hists; 833 he->hists = hists;
747 rb_link_node(&he->rb_node, parent, p); 834 rb_link_node(&he->rb_node_in, parent, p);
748 rb_insert_color(&he->rb_node, &hists->entries); 835 rb_insert_color(&he->rb_node_in, root);
749 hists__inc_nr_entries(hists, he); 836 hists__inc_nr_entries(hists, he);
750 } 837 }
751out: 838out:
@@ -755,11 +842,16 @@ out:
755static struct hist_entry *hists__find_entry(struct hists *hists, 842static struct hist_entry *hists__find_entry(struct hists *hists,
756 struct hist_entry *he) 843 struct hist_entry *he)
757{ 844{
758 struct rb_node *n = hists->entries.rb_node; 845 struct rb_node *n;
846
847 if (sort__need_collapse)
848 n = hists->entries_collapsed.rb_node;
849 else
850 n = hists->entries_in->rb_node;
759 851
760 while (n) { 852 while (n) {
761 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 853 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
762 int64_t cmp = hist_entry__cmp(he, iter); 854 int64_t cmp = hist_entry__collapse(iter, he);
763 855
764 if (cmp < 0) 856 if (cmp < 0)
765 n = n->rb_left; 857 n = n->rb_left;
@@ -777,15 +869,21 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
777 */ 869 */
778void hists__match(struct hists *leader, struct hists *other) 870void hists__match(struct hists *leader, struct hists *other)
779{ 871{
872 struct rb_root *root;
780 struct rb_node *nd; 873 struct rb_node *nd;
781 struct hist_entry *pos, *pair; 874 struct hist_entry *pos, *pair;
782 875
783 for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { 876 if (sort__need_collapse)
784 pos = rb_entry(nd, struct hist_entry, rb_node); 877 root = &leader->entries_collapsed;
878 else
879 root = leader->entries_in;
880
881 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
882 pos = rb_entry(nd, struct hist_entry, rb_node_in);
785 pair = hists__find_entry(other, pos); 883 pair = hists__find_entry(other, pos);
786 884
787 if (pair) 885 if (pair)
788 hist__entry_add_pair(pos, pair); 886 hist_entry__add_pair(pair, pos);
789 } 887 }
790} 888}
791 889
@@ -796,17 +894,23 @@ void hists__match(struct hists *leader, struct hists *other)
796 */ 894 */
797int hists__link(struct hists *leader, struct hists *other) 895int hists__link(struct hists *leader, struct hists *other)
798{ 896{
897 struct rb_root *root;
799 struct rb_node *nd; 898 struct rb_node *nd;
800 struct hist_entry *pos, *pair; 899 struct hist_entry *pos, *pair;
801 900
802 for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { 901 if (sort__need_collapse)
803 pos = rb_entry(nd, struct hist_entry, rb_node); 902 root = &other->entries_collapsed;
903 else
904 root = other->entries_in;
905
906 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
907 pos = rb_entry(nd, struct hist_entry, rb_node_in);
804 908
805 if (!hist_entry__has_pairs(pos)) { 909 if (!hist_entry__has_pairs(pos)) {
806 pair = hists__add_dummy_entry(leader, pos); 910 pair = hists__add_dummy_entry(leader, pos);
807 if (pair == NULL) 911 if (pair == NULL)
808 return -1; 912 return -1;
809 hist__entry_add_pair(pair, pos); 913 hist_entry__add_pair(pos, pair);
810 } 914 }
811 } 915 }
812 916
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8b091a51e4a2..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);
@@ -126,13 +128,19 @@ struct perf_hpp {
126}; 128};
127 129
128struct perf_hpp_fmt { 130struct perf_hpp_fmt {
129 bool cond;
130 int (*header)(struct perf_hpp *hpp); 131 int (*header)(struct perf_hpp *hpp);
131 int (*width)(struct perf_hpp *hpp); 132 int (*width)(struct perf_hpp *hpp);
132 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 133 int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
133 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 134 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
135
136 struct list_head list;
134}; 137};
135 138
139extern struct list_head perf_hpp__list;
140
141#define perf_hpp__for_each_format(format) \
142 list_for_each_entry(format, &perf_hpp__list, list)
143
136extern struct perf_hpp_fmt perf_hpp__format[]; 144extern struct perf_hpp_fmt perf_hpp__format[];
137 145
138enum { 146enum {
@@ -148,14 +156,14 @@ enum {
148 PERF_HPP__DELTA, 156 PERF_HPP__DELTA,
149 PERF_HPP__RATIO, 157 PERF_HPP__RATIO,
150 PERF_HPP__WEIGHTED_DIFF, 158 PERF_HPP__WEIGHTED_DIFF,
151 PERF_HPP__DISPL,
152 PERF_HPP__FORMULA, 159 PERF_HPP__FORMULA,
153 160
154 PERF_HPP__MAX_INDEX 161 PERF_HPP__MAX_INDEX
155}; 162};
156 163
157void perf_hpp__init(void); 164void perf_hpp__init(void);
158void perf_hpp__column_enable(unsigned col, bool enable); 165void perf_hpp__column_register(struct perf_hpp_fmt *format);
166void perf_hpp__column_enable(unsigned col);
159int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 167int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
160 bool color); 168 bool color);
161 169
@@ -219,8 +227,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
219 227
220unsigned int hists__sort_list_width(struct hists *self); 228unsigned int hists__sort_list_width(struct hists *self);
221 229
222double perf_diff__compute_delta(struct hist_entry *he); 230double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
223double perf_diff__compute_ratio(struct hist_entry *he); 231double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
224s64 perf_diff__compute_wdiff(struct hist_entry *he); 232s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
225int perf_diff__formula(char *buf, size_t size, struct hist_entry *he); 233int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
234 char *buf, size_t size);
235double perf_diff__period_percent(struct hist_entry *he, u64 period);
226#endif /* __PERF_HIST_H */ 236#endif /* __PERF_HIST_H */
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 1f09d0581e6b..efdb38e65a92 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1,10 +1,15 @@
1#include "callchain.h"
1#include "debug.h" 2#include "debug.h"
2#include "event.h" 3#include "event.h"
4#include "evsel.h"
5#include "hist.h"
3#include "machine.h" 6#include "machine.h"
4#include "map.h" 7#include "map.h"
8#include "sort.h"
5#include "strlist.h" 9#include "strlist.h"
6#include "thread.h" 10#include "thread.h"
7#include <stdbool.h> 11#include <stdbool.h>
12#include "unwind.h"
8 13
9int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 14int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
10{ 15{
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos)
48 } 53 }
49} 54}
50 55
56void machine__delete_dead_threads(struct machine *machine)
57{
58 struct thread *n, *t;
59
60 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
61 list_del(&t->node);
62 thread__delete(t);
63 }
64}
65
66void machine__delete_threads(struct machine *machine)
67{
68 struct rb_node *nd = rb_first(&machine->threads);
69
70 while (nd) {
71 struct thread *t = rb_entry(nd, struct thread, rb_node);
72
73 rb_erase(&t->rb_node, &machine->threads);
74 nd = rb_next(nd);
75 thread__delete(t);
76 }
77}
78
51void machine__exit(struct machine *machine) 79void machine__exit(struct machine *machine)
52{ 80{
53 map_groups__exit(&machine->kmaps); 81 map_groups__exit(&machine->kmaps);
@@ -63,10 +91,22 @@ void machine__delete(struct machine *machine)
63 free(machine); 91 free(machine);
64} 92}
65 93
66struct 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,
67 const char *root_dir) 107 const char *root_dir)
68{ 108{
69 struct rb_node **p = &machines->rb_node; 109 struct rb_node **p = &machines->guests.rb_node;
70 struct rb_node *parent = NULL; 110 struct rb_node *parent = NULL;
71 struct machine *pos, *machine = malloc(sizeof(*machine)); 111 struct machine *pos, *machine = malloc(sizeof(*machine));
72 112
@@ -88,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
88 } 128 }
89 129
90 rb_link_node(&machine->rb_node, parent, p); 130 rb_link_node(&machine->rb_node, parent, p);
91 rb_insert_color(&machine->rb_node, machines); 131 rb_insert_color(&machine->rb_node, &machines->guests);
92 132
93 return machine; 133 return machine;
94} 134}
95 135
96struct machine *machines__find(struct rb_root *machines, pid_t pid) 136struct machine *machines__find(struct machines *machines, pid_t pid)
97{ 137{
98 struct rb_node **p = &machines->rb_node; 138 struct rb_node **p = &machines->guests.rb_node;
99 struct rb_node *parent = NULL; 139 struct rb_node *parent = NULL;
100 struct machine *machine; 140 struct machine *machine;
101 struct machine *default_machine = NULL; 141 struct machine *default_machine = NULL;
102 142
143 if (pid == HOST_KERNEL_ID)
144 return &machines->host;
145
103 while (*p != NULL) { 146 while (*p != NULL) {
104 parent = *p; 147 parent = *p;
105 machine = rb_entry(parent, struct machine, rb_node); 148 machine = rb_entry(parent, struct machine, rb_node);
@@ -116,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
116 return default_machine; 159 return default_machine;
117} 160}
118 161
119struct machine *machines__findnew(struct rb_root *machines, pid_t pid) 162struct machine *machines__findnew(struct machines *machines, pid_t pid)
120{ 163{
121 char path[PATH_MAX]; 164 char path[PATH_MAX];
122 const char *root_dir = ""; 165 const char *root_dir = "";
@@ -150,12 +193,12 @@ out:
150 return machine; 193 return machine;
151} 194}
152 195
153void machines__process(struct rb_root *machines, 196void machines__process_guests(struct machines *machines,
154 machine__process_t process, void *data) 197 machine__process_t process, void *data)
155{ 198{
156 struct rb_node *nd; 199 struct rb_node *nd;
157 200
158 for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 201 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
159 struct machine *pos = rb_entry(nd, struct machine, rb_node); 202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
160 process(pos, data); 203 process(pos, data);
161 } 204 }
@@ -175,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
175 return bf; 218 return bf;
176} 219}
177 220
178void 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)
179{ 222{
180 struct rb_node *node; 223 struct rb_node *node;
181 struct machine *machine; 224 struct machine *machine;
182 225
183 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)) {
184 machine = rb_entry(node, struct machine, rb_node); 229 machine = rb_entry(node, struct machine, rb_node);
185 machine->id_hdr_size = id_hdr_size; 230 machine->id_hdr_size = id_hdr_size;
186 } 231 }
@@ -264,6 +309,537 @@ int machine__process_lost_event(struct machine *machine __maybe_unused,
264 return 0; 309 return 0;
265} 310}
266 311
312struct map *machine__new_module(struct machine *machine, u64 start,
313 const char *filename)
314{
315 struct map *map;
316 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
317
318 if (dso == NULL)
319 return NULL;
320
321 map = map__new2(start, dso, MAP__FUNCTION);
322 if (map == NULL)
323 return NULL;
324
325 if (machine__is_host(machine))
326 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
327 else
328 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
329 map_groups__insert(&machine->kmaps, map);
330 return map;
331}
332
333size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
334{
335 struct rb_node *nd;
336 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
337 __dsos__fprintf(&machines->host.user_dsos, fp);
338
339 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
340 struct machine *pos = rb_entry(nd, struct machine, rb_node);
341 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
342 ret += __dsos__fprintf(&pos->user_dsos, fp);
343 }
344
345 return ret;
346}
347
348size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
349 bool (skip)(struct dso *dso, int parm), int parm)
350{
351 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
352 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
353}
354
355size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
356 bool (skip)(struct dso *dso, int parm), int parm)
357{
358 struct rb_node *nd;
359 size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
360
361 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
362 struct machine *pos = rb_entry(nd, struct machine, rb_node);
363 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
364 }
365 return ret;
366}
367
368size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
369{
370 int i;
371 size_t printed = 0;
372 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
373
374 if (kdso->has_build_id) {
375 char filename[PATH_MAX];
376 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
377 printed += fprintf(fp, "[0] %s\n", filename);
378 }
379
380 for (i = 0; i < vmlinux_path__nr_entries; ++i)
381 printed += fprintf(fp, "[%d] %s\n",
382 i + kdso->has_build_id, vmlinux_path[i]);
383
384 return printed;
385}
386
387size_t machine__fprintf(struct machine *machine, FILE *fp)
388{
389 size_t ret = 0;
390 struct rb_node *nd;
391
392 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
393 struct thread *pos = rb_entry(nd, struct thread, rb_node);
394
395 ret += thread__fprintf(pos, fp);
396 }
397
398 return ret;
399}
400
401static struct dso *machine__get_kernel(struct machine *machine)
402{
403 const char *vmlinux_name = NULL;
404 struct dso *kernel;
405
406 if (machine__is_host(machine)) {
407 vmlinux_name = symbol_conf.vmlinux_name;
408 if (!vmlinux_name)
409 vmlinux_name = "[kernel.kallsyms]";
410
411 kernel = dso__kernel_findnew(machine, vmlinux_name,
412 "[kernel]",
413 DSO_TYPE_KERNEL);
414 } else {
415 char bf[PATH_MAX];
416
417 if (machine__is_default_guest(machine))
418 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
419 if (!vmlinux_name)
420 vmlinux_name = machine__mmap_name(machine, bf,
421 sizeof(bf));
422
423 kernel = dso__kernel_findnew(machine, vmlinux_name,
424 "[guest.kernel]",
425 DSO_TYPE_GUEST_KERNEL);
426 }
427
428 if (kernel != NULL && (!kernel->has_build_id))
429 dso__read_running_kernel_build_id(kernel, machine);
430
431 return kernel;
432}
433
434struct process_args {
435 u64 start;
436};
437
438static int symbol__in_kernel(void *arg, const char *name,
439 char type __maybe_unused, u64 start)
440{
441 struct process_args *args = arg;
442
443 if (strchr(name, '['))
444 return 0;
445
446 args->start = start;
447 return 1;
448}
449
450/* Figure out the start address of kernel map from /proc/kallsyms */
451static u64 machine__get_kernel_start_addr(struct machine *machine)
452{
453 const char *filename;
454 char path[PATH_MAX];
455 struct process_args args;
456
457 if (machine__is_host(machine)) {
458 filename = "/proc/kallsyms";
459 } else {
460 if (machine__is_default_guest(machine))
461 filename = (char *)symbol_conf.default_guest_kallsyms;
462 else {
463 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
464 filename = path;
465 }
466 }
467
468 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
469 return 0;
470
471 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
472 return 0;
473
474 return args.start;
475}
476
477int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
478{
479 enum map_type type;
480 u64 start = machine__get_kernel_start_addr(machine);
481
482 for (type = 0; type < MAP__NR_TYPES; ++type) {
483 struct kmap *kmap;
484
485 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
486 if (machine->vmlinux_maps[type] == NULL)
487 return -1;
488
489 machine->vmlinux_maps[type]->map_ip =
490 machine->vmlinux_maps[type]->unmap_ip =
491 identity__map_ip;
492 kmap = map__kmap(machine->vmlinux_maps[type]);
493 kmap->kmaps = &machine->kmaps;
494 map_groups__insert(&machine->kmaps,
495 machine->vmlinux_maps[type]);
496 }
497
498 return 0;
499}
500
501void machine__destroy_kernel_maps(struct machine *machine)
502{
503 enum map_type type;
504
505 for (type = 0; type < MAP__NR_TYPES; ++type) {
506 struct kmap *kmap;
507
508 if (machine->vmlinux_maps[type] == NULL)
509 continue;
510
511 kmap = map__kmap(machine->vmlinux_maps[type]);
512 map_groups__remove(&machine->kmaps,
513 machine->vmlinux_maps[type]);
514 if (kmap->ref_reloc_sym) {
515 /*
516 * ref_reloc_sym is shared among all maps, so free just
517 * on one of them.
518 */
519 if (type == MAP__FUNCTION) {
520 free((char *)kmap->ref_reloc_sym->name);
521 kmap->ref_reloc_sym->name = NULL;
522 free(kmap->ref_reloc_sym);
523 }
524 kmap->ref_reloc_sym = NULL;
525 }
526
527 map__delete(machine->vmlinux_maps[type]);
528 machine->vmlinux_maps[type] = NULL;
529 }
530}
531
532int machines__create_guest_kernel_maps(struct machines *machines)
533{
534 int ret = 0;
535 struct dirent **namelist = NULL;
536 int i, items = 0;
537 char path[PATH_MAX];
538 pid_t pid;
539 char *endp;
540
541 if (symbol_conf.default_guest_vmlinux_name ||
542 symbol_conf.default_guest_modules ||
543 symbol_conf.default_guest_kallsyms) {
544 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
545 }
546
547 if (symbol_conf.guestmount) {
548 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
549 if (items <= 0)
550 return -ENOENT;
551 for (i = 0; i < items; i++) {
552 if (!isdigit(namelist[i]->d_name[0])) {
553 /* Filter out . and .. */
554 continue;
555 }
556 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
557 if ((*endp != '\0') ||
558 (endp == namelist[i]->d_name) ||
559 (errno == ERANGE)) {
560 pr_debug("invalid directory (%s). Skipping.\n",
561 namelist[i]->d_name);
562 continue;
563 }
564 sprintf(path, "%s/%s/proc/kallsyms",
565 symbol_conf.guestmount,
566 namelist[i]->d_name);
567 ret = access(path, R_OK);
568 if (ret) {
569 pr_debug("Can't access file %s\n", path);
570 goto failure;
571 }
572 machines__create_kernel_maps(machines, pid);
573 }
574failure:
575 free(namelist);
576 }
577
578 return ret;
579}
580
581void machines__destroy_kernel_maps(struct machines *machines)
582{
583 struct rb_node *next = rb_first(&machines->guests);
584
585 machine__destroy_kernel_maps(&machines->host);
586
587 while (next) {
588 struct machine *pos = rb_entry(next, struct machine, rb_node);
589
590 next = rb_next(&pos->rb_node);
591 rb_erase(&pos->rb_node, &machines->guests);
592 machine__delete(pos);
593 }
594}
595
596int machines__create_kernel_maps(struct machines *machines, pid_t pid)
597{
598 struct machine *machine = machines__findnew(machines, pid);
599
600 if (machine == NULL)
601 return -1;
602
603 return machine__create_kernel_maps(machine);
604}
605
606int machine__load_kallsyms(struct machine *machine, const char *filename,
607 enum map_type type, symbol_filter_t filter)
608{
609 struct map *map = machine->vmlinux_maps[type];
610 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
611
612 if (ret > 0) {
613 dso__set_loaded(map->dso, type);
614 /*
615 * Since /proc/kallsyms will have multiple sessions for the
616 * kernel, with modules between them, fixup the end of all
617 * sections.
618 */
619 __map_groups__fixup_end(&machine->kmaps, type);
620 }
621
622 return ret;
623}
624
625int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
626 symbol_filter_t filter)
627{
628 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630
631 if (ret > 0) {
632 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635
636 return ret;
637}
638
639static void map_groups__fixup_end(struct map_groups *mg)
640{
641 int i;
642 for (i = 0; i < MAP__NR_TYPES; ++i)
643 __map_groups__fixup_end(mg, i);
644}
645
646static char *get_kernel_version(const char *root_dir)
647{
648 char version[PATH_MAX];
649 FILE *file;
650 char *name, *tmp;
651 const char *prefix = "Linux version ";
652
653 sprintf(version, "%s/proc/version", root_dir);
654 file = fopen(version, "r");
655 if (!file)
656 return NULL;
657
658 version[0] = '\0';
659 tmp = fgets(version, sizeof(version), file);
660 fclose(file);
661
662 name = strstr(version, prefix);
663 if (!name)
664 return NULL;
665 name += strlen(prefix);
666 tmp = strchr(name, ' ');
667 if (tmp)
668 *tmp = '\0';
669
670 return strdup(name);
671}
672
673static int map_groups__set_modules_path_dir(struct map_groups *mg,
674 const char *dir_name)
675{
676 struct dirent *dent;
677 DIR *dir = opendir(dir_name);
678 int ret = 0;
679
680 if (!dir) {
681 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
682 return -1;
683 }
684
685 while ((dent = readdir(dir)) != NULL) {
686 char path[PATH_MAX];
687 struct stat st;
688
689 /*sshfs might return bad dent->d_type, so we have to stat*/
690 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
691 if (stat(path, &st))
692 continue;
693
694 if (S_ISDIR(st.st_mode)) {
695 if (!strcmp(dent->d_name, ".") ||
696 !strcmp(dent->d_name, ".."))
697 continue;
698
699 ret = map_groups__set_modules_path_dir(mg, path);
700 if (ret < 0)
701 goto out;
702 } else {
703 char *dot = strrchr(dent->d_name, '.'),
704 dso_name[PATH_MAX];
705 struct map *map;
706 char *long_name;
707
708 if (dot == NULL || strcmp(dot, ".ko"))
709 continue;
710 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
711 (int)(dot - dent->d_name), dent->d_name);
712
713 strxfrchar(dso_name, '-', '_');
714 map = map_groups__find_by_name(mg, MAP__FUNCTION,
715 dso_name);
716 if (map == NULL)
717 continue;
718
719 long_name = strdup(path);
720 if (long_name == NULL) {
721 ret = -1;
722 goto out;
723 }
724 dso__set_long_name(map->dso, long_name);
725 map->dso->lname_alloc = 1;
726 dso__kernel_module_get_build_id(map->dso, "");
727 }
728 }
729
730out:
731 closedir(dir);
732 return ret;
733}
734
735static int machine__set_modules_path(struct machine *machine)
736{
737 char *version;
738 char modules_path[PATH_MAX];
739
740 version = get_kernel_version(machine->root_dir);
741 if (!version)
742 return -1;
743
744 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
745 machine->root_dir, version);
746 free(version);
747
748 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
749}
750
751static int machine__create_modules(struct machine *machine)
752{
753 char *line = NULL;
754 size_t n;
755 FILE *file;
756 struct map *map;
757 const char *modules;
758 char path[PATH_MAX];
759
760 if (machine__is_default_guest(machine))
761 modules = symbol_conf.default_guest_modules;
762 else {
763 sprintf(path, "%s/proc/modules", machine->root_dir);
764 modules = path;
765 }
766
767 if (symbol__restricted_filename(path, "/proc/modules"))
768 return -1;
769
770 file = fopen(modules, "r");
771 if (file == NULL)
772 return -1;
773
774 while (!feof(file)) {
775 char name[PATH_MAX];
776 u64 start;
777 char *sep;
778 int line_len;
779
780 line_len = getline(&line, &n, file);
781 if (line_len < 0)
782 break;
783
784 if (!line)
785 goto out_failure;
786
787 line[--line_len] = '\0'; /* \n */
788
789 sep = strrchr(line, 'x');
790 if (sep == NULL)
791 continue;
792
793 hex2u64(sep + 1, &start);
794
795 sep = strchr(line, ' ');
796 if (sep == NULL)
797 continue;
798
799 *sep = '\0';
800
801 snprintf(name, sizeof(name), "[%s]", line);
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 goto out_delete_line;
805 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
806 }
807
808 free(line);
809 fclose(file);
810
811 return machine__set_modules_path(machine);
812
813out_delete_line:
814 free(line);
815out_failure:
816 return -1;
817}
818
819int machine__create_kernel_maps(struct machine *machine)
820{
821 struct dso *kernel = machine__get_kernel(machine);
822
823 if (kernel == NULL ||
824 __machine__create_kernel_maps(machine, kernel) < 0)
825 return -1;
826
827 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
828 if (machine__is_host(machine))
829 pr_debug("Problems creating module maps, "
830 "continuing anyway...\n");
831 else
832 pr_debug("Problems creating module maps for guest %d, "
833 "continuing anyway...\n", machine->pid);
834 }
835
836 /*
837 * Now that we have all the maps created, just set the ->end of them:
838 */
839 map_groups__fixup_end(&machine->kmaps);
840 return 0;
841}
842
267static void machine__set_kernel_mmap_len(struct machine *machine, 843static void machine__set_kernel_mmap_len(struct machine *machine,
268 union perf_event *event) 844 union perf_event *event)
269{ 845{
@@ -462,3 +1038,189 @@ int machine__process_event(struct machine *machine, union perf_event *event)
462 1038
463 return ret; 1039 return ret;
464} 1040}
1041
1042void machine__remove_thread(struct machine *machine, struct thread *th)
1043{
1044 machine->last_match = NULL;
1045 rb_erase(&th->rb_node, &machine->threads);
1046 /*
1047 * We may have references to this thread, for instance in some hist_entry
1048 * instances, so just move them to a separate list.
1049 */
1050 list_add_tail(&th->node, &machine->dead_threads);
1051}
1052
1053static bool symbol__match_parent_regex(struct symbol *sym)
1054{
1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1056 return 1;
1057
1058 return 0;
1059}
1060
1061static const u8 cpumodes[] = {
1062 PERF_RECORD_MISC_USER,
1063 PERF_RECORD_MISC_KERNEL,
1064 PERF_RECORD_MISC_GUEST_USER,
1065 PERF_RECORD_MISC_GUEST_KERNEL
1066};
1067#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
1068
1069static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1070 struct addr_map_symbol *ams,
1071 u64 ip)
1072{
1073 struct addr_location al;
1074 size_t i;
1075 u8 m;
1076
1077 memset(&al, 0, sizeof(al));
1078
1079 for (i = 0; i < NCPUMODES; i++) {
1080 m = cpumodes[i];
1081 /*
1082 * We cannot use the header.misc hint to determine whether a
1083 * branch stack address is user, kernel, guest, hypervisor.
1084 * Branches may straddle the kernel/user/hypervisor boundaries.
1085 * Thus, we have to try consecutively until we find a match
1086 * or else, the symbol is unknown
1087 */
1088 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1089 ip, &al, NULL);
1090 if (al.sym)
1091 goto found;
1092 }
1093found:
1094 ams->addr = ip;
1095 ams->al_addr = al.addr;
1096 ams->sym = al.sym;
1097 ams->map = al.map;
1098}
1099
1100struct branch_info *machine__resolve_bstack(struct machine *machine,
1101 struct thread *thr,
1102 struct branch_stack *bs)
1103{
1104 struct branch_info *bi;
1105 unsigned int i;
1106
1107 bi = calloc(bs->nr, sizeof(struct branch_info));
1108 if (!bi)
1109 return NULL;
1110
1111 for (i = 0; i < bs->nr; i++) {
1112 ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
1113 ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
1114 bi[i].flags = bs->entries[i].flags;
1115 }
1116 return bi;
1117}
1118
1119static int machine__resolve_callchain_sample(struct machine *machine,
1120 struct thread *thread,
1121 struct ip_callchain *chain,
1122 struct symbol **parent)
1123
1124{
1125 u8 cpumode = PERF_RECORD_MISC_USER;
1126 unsigned int i;
1127 int err;
1128
1129 callchain_cursor_reset(&callchain_cursor);
1130
1131 if (chain->nr > PERF_MAX_STACK_DEPTH) {
1132 pr_warning("corrupted callchain. skipping...\n");
1133 return 0;
1134 }
1135
1136 for (i = 0; i < chain->nr; i++) {
1137 u64 ip;
1138 struct addr_location al;
1139
1140 if (callchain_param.order == ORDER_CALLEE)
1141 ip = chain->ips[i];
1142 else
1143 ip = chain->ips[chain->nr - i - 1];
1144
1145 if (ip >= PERF_CONTEXT_MAX) {
1146 switch (ip) {
1147 case PERF_CONTEXT_HV:
1148 cpumode = PERF_RECORD_MISC_HYPERVISOR;
1149 break;
1150 case PERF_CONTEXT_KERNEL:
1151 cpumode = PERF_RECORD_MISC_KERNEL;
1152 break;
1153 case PERF_CONTEXT_USER:
1154 cpumode = PERF_RECORD_MISC_USER;
1155 break;
1156 default:
1157 pr_debug("invalid callchain context: "
1158 "%"PRId64"\n", (s64) ip);
1159 /*
1160 * It seems the callchain is corrupted.
1161 * Discard all.
1162 */
1163 callchain_cursor_reset(&callchain_cursor);
1164 return 0;
1165 }
1166 continue;
1167 }
1168
1169 al.filtered = false;
1170 thread__find_addr_location(thread, machine, cpumode,
1171 MAP__FUNCTION, ip, &al, NULL);
1172 if (al.sym != NULL) {
1173 if (sort__has_parent && !*parent &&
1174 symbol__match_parent_regex(al.sym))
1175 *parent = al.sym;
1176 if (!symbol_conf.use_callchain)
1177 break;
1178 }
1179
1180 err = callchain_cursor_append(&callchain_cursor,
1181 ip, al.map, al.sym);
1182 if (err)
1183 return err;
1184 }
1185
1186 return 0;
1187}
1188
1189static int unwind_entry(struct unwind_entry *entry, void *arg)
1190{
1191 struct callchain_cursor *cursor = arg;
1192 return callchain_cursor_append(cursor, entry->ip,
1193 entry->map, entry->sym);
1194}
1195
1196int machine__resolve_callchain(struct machine *machine,
1197 struct perf_evsel *evsel,
1198 struct thread *thread,
1199 struct perf_sample *sample,
1200 struct symbol **parent)
1201
1202{
1203 int ret;
1204
1205 callchain_cursor_reset(&callchain_cursor);
1206
1207 ret = machine__resolve_callchain_sample(machine, thread,
1208 sample->callchain, parent);
1209 if (ret)
1210 return ret;
1211
1212 /* Can we do dwarf post unwind? */
1213 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
1214 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
1215 return 0;
1216
1217 /* Bail out if nothing was captured. */
1218 if ((!sample->user_regs.regs) ||
1219 (!sample->user_stack.size))
1220 return 0;
1221
1222 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1223 thread, evsel->attr.sample_regs_user,
1224 sample);
1225
1226}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index b7cde7467d55..5ac5892f2326 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -47,23 +47,32 @@ 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);
52 57
53struct machine *machines__add(struct rb_root *machines, pid_t pid, 58void machines__process_guests(struct machines *machines,
59 machine__process_t process, void *data);
60
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);
63void machine__exit(struct machine *machine); 71void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine);
73void machine__delete_threads(struct machine *machine);
64void machine__delete(struct machine *machine); 74void machine__delete(struct machine *machine);
65 75
66
67struct branch_info *machine__resolve_bstack(struct machine *machine, 76struct branch_info *machine__resolve_bstack(struct machine *machine,
68 struct thread *thread, 77 struct thread *thread,
69 struct branch_stack *bs); 78 struct branch_stack *bs);
@@ -129,19 +138,19 @@ int machine__load_kallsyms(struct machine *machine, const char *filename,
129int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 138int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
130 symbol_filter_t filter); 139 symbol_filter_t filter);
131 140
132size_t machine__fprintf_dsos_buildid(struct machine *machine, 141size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
133 FILE *fp, bool with_hits); 142 bool (skip)(struct dso *dso, int parm), int parm);
134size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); 143size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
135size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 144size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
136 FILE *fp, bool with_hits); 145 bool (skip)(struct dso *dso, int parm), int parm);
137 146
138void machine__destroy_kernel_maps(struct machine *machine); 147void machine__destroy_kernel_maps(struct machine *machine);
139int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); 148int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
140int machine__create_kernel_maps(struct machine *machine); 149int machine__create_kernel_maps(struct machine *machine);
141 150
142int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); 151int machines__create_kernel_maps(struct machines *machines, pid_t pid);
143int machines__create_guest_kernel_maps(struct rb_root *machines); 152int machines__create_guest_kernel_maps(struct machines *machines);
144void machines__destroy_guest_kernel_maps(struct rb_root *machines); 153void machines__destroy_kernel_maps(struct machines *machines);
145 154
146size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 155size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
147 156
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 0328d45c4f2a..6fcb9de62340 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include <linux/string.h>
14 15
15const char *map_type__name[MAP__NR_TYPES] = { 16const char *map_type__name[MAP__NR_TYPES] = {
16 [MAP__FUNCTION] = "Functions", 17 [MAP__FUNCTION] = "Functions",
@@ -19,7 +20,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
19 20
20static inline int is_anon_memory(const char *filename) 21static inline int is_anon_memory(const char *filename)
21{ 22{
22 return strcmp(filename, "//anon") == 0; 23 return !strcmp(filename, "//anon") ||
24 !strcmp(filename, "/anon_hugepage (deleted)");
23} 25}
24 26
25static inline int is_no_dso_memory(const char *filename) 27static inline int is_no_dso_memory(const char *filename)
@@ -28,29 +30,29 @@ static inline int is_no_dso_memory(const char *filename)
28 !strcmp(filename, "[heap]"); 30 !strcmp(filename, "[heap]");
29} 31}
30 32
31void map__init(struct map *self, enum map_type type, 33void map__init(struct map *map, enum map_type type,
32 u64 start, u64 end, u64 pgoff, struct dso *dso) 34 u64 start, u64 end, u64 pgoff, struct dso *dso)
33{ 35{
34 self->type = type; 36 map->type = type;
35 self->start = start; 37 map->start = start;
36 self->end = end; 38 map->end = end;
37 self->pgoff = pgoff; 39 map->pgoff = pgoff;
38 self->dso = dso; 40 map->dso = dso;
39 self->map_ip = map__map_ip; 41 map->map_ip = map__map_ip;
40 self->unmap_ip = map__unmap_ip; 42 map->unmap_ip = map__unmap_ip;
41 RB_CLEAR_NODE(&self->rb_node); 43 RB_CLEAR_NODE(&map->rb_node);
42 self->groups = NULL; 44 map->groups = NULL;
43 self->referenced = false; 45 map->referenced = false;
44 self->erange_warned = false; 46 map->erange_warned = false;
45} 47}
46 48
47struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 49struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
48 u64 pgoff, u32 pid, char *filename, 50 u64 pgoff, u32 pid, char *filename,
49 enum map_type type) 51 enum map_type type)
50{ 52{
51 struct map *self = malloc(sizeof(*self)); 53 struct map *map = malloc(sizeof(*map));
52 54
53 if (self != NULL) { 55 if (map != NULL) {
54 char newfilename[PATH_MAX]; 56 char newfilename[PATH_MAX];
55 struct dso *dso; 57 struct dso *dso;
56 int anon, no_dso, vdso; 58 int anon, no_dso, vdso;
@@ -73,10 +75,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
73 if (dso == NULL) 75 if (dso == NULL)
74 goto out_delete; 76 goto out_delete;
75 77
76 map__init(self, type, start, start + len, pgoff, dso); 78 map__init(map, type, start, start + len, pgoff, dso);
77 79
78 if (anon || no_dso) { 80 if (anon || no_dso) {
79 self->map_ip = self->unmap_ip = identity__map_ip; 81 map->map_ip = map->unmap_ip = identity__map_ip;
80 82
81 /* 83 /*
82 * Set memory without DSO as loaded. All map__find_* 84 * Set memory without DSO as loaded. All map__find_*
@@ -84,12 +86,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
84 * unnecessary map__load warning. 86 * unnecessary map__load warning.
85 */ 87 */
86 if (no_dso) 88 if (no_dso)
87 dso__set_loaded(dso, self->type); 89 dso__set_loaded(dso, map->type);
88 } 90 }
89 } 91 }
90 return self; 92 return map;
91out_delete: 93out_delete:
92 free(self); 94 free(map);
93 return NULL; 95 return NULL;
94} 96}
95 97
@@ -112,48 +114,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
112 return map; 114 return map;
113} 115}
114 116
115void map__delete(struct map *self) 117void map__delete(struct map *map)
116{ 118{
117 free(self); 119 free(map);
118} 120}
119 121
120void map__fixup_start(struct map *self) 122void map__fixup_start(struct map *map)
121{ 123{
122 struct rb_root *symbols = &self->dso->symbols[self->type]; 124 struct rb_root *symbols = &map->dso->symbols[map->type];
123 struct rb_node *nd = rb_first(symbols); 125 struct rb_node *nd = rb_first(symbols);
124 if (nd != NULL) { 126 if (nd != NULL) {
125 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 127 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
126 self->start = sym->start; 128 map->start = sym->start;
127 } 129 }
128} 130}
129 131
130void map__fixup_end(struct map *self) 132void map__fixup_end(struct map *map)
131{ 133{
132 struct rb_root *symbols = &self->dso->symbols[self->type]; 134 struct rb_root *symbols = &map->dso->symbols[map->type];
133 struct rb_node *nd = rb_last(symbols); 135 struct rb_node *nd = rb_last(symbols);
134 if (nd != NULL) { 136 if (nd != NULL) {
135 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 137 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
136 self->end = sym->end; 138 map->end = sym->end;
137 } 139 }
138} 140}
139 141
140#define DSO__DELETED "(deleted)" 142#define DSO__DELETED "(deleted)"
141 143
142int map__load(struct map *self, symbol_filter_t filter) 144int map__load(struct map *map, symbol_filter_t filter)
143{ 145{
144 const char *name = self->dso->long_name; 146 const char *name = map->dso->long_name;
145 int nr; 147 int nr;
146 148
147 if (dso__loaded(self->dso, self->type)) 149 if (dso__loaded(map->dso, map->type))
148 return 0; 150 return 0;
149 151
150 nr = dso__load(self->dso, self, filter); 152 nr = dso__load(map->dso, map, filter);
151 if (nr < 0) { 153 if (nr < 0) {
152 if (self->dso->has_build_id) { 154 if (map->dso->has_build_id) {
153 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 155 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
154 156
155 build_id__sprintf(self->dso->build_id, 157 build_id__sprintf(map->dso->build_id,
156 sizeof(self->dso->build_id), 158 sizeof(map->dso->build_id),
157 sbuild_id); 159 sbuild_id);
158 pr_warning("%s with build id %s not found", 160 pr_warning("%s with build id %s not found",
159 name, sbuild_id); 161 name, sbuild_id);
@@ -183,43 +185,36 @@ int map__load(struct map *self, symbol_filter_t filter)
183 * Only applies to the kernel, as its symtabs aren't relative like the 185 * Only applies to the kernel, as its symtabs aren't relative like the
184 * module ones. 186 * module ones.
185 */ 187 */
186 if (self->dso->kernel) 188 if (map->dso->kernel)
187 map__reloc_vmlinux(self); 189 map__reloc_vmlinux(map);
188 190
189 return 0; 191 return 0;
190} 192}
191 193
192struct symbol *map__find_symbol(struct map *self, u64 addr, 194struct symbol *map__find_symbol(struct map *map, u64 addr,
193 symbol_filter_t filter) 195 symbol_filter_t filter)
194{ 196{
195 if (map__load(self, filter) < 0) 197 if (map__load(map, filter) < 0)
196 return NULL; 198 return NULL;
197 199
198 return dso__find_symbol(self->dso, self->type, addr); 200 return dso__find_symbol(map->dso, map->type, addr);
199} 201}
200 202
201struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 203struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
202 symbol_filter_t filter) 204 symbol_filter_t filter)
203{ 205{
204 if (map__load(self, filter) < 0) 206 if (map__load(map, filter) < 0)
205 return NULL; 207 return NULL;
206 208
207 if (!dso__sorted_by_name(self->dso, self->type)) 209 if (!dso__sorted_by_name(map->dso, map->type))
208 dso__sort_by_name(self->dso, self->type); 210 dso__sort_by_name(map->dso, map->type);
209 211
210 return dso__find_symbol_by_name(self->dso, self->type, name); 212 return dso__find_symbol_by_name(map->dso, map->type, name);
211} 213}
212 214
213struct map *map__clone(struct map *self) 215struct map *map__clone(struct map *map)
214{ 216{
215 struct map *map = malloc(sizeof(*self)); 217 return memdup(map, sizeof(*map));
216
217 if (!map)
218 return NULL;
219
220 memcpy(map, self, sizeof(*self));
221
222 return map;
223} 218}
224 219
225int map__overlap(struct map *l, struct map *r) 220int map__overlap(struct map *l, struct map *r)
@@ -236,10 +231,10 @@ int map__overlap(struct map *l, struct map *r)
236 return 0; 231 return 0;
237} 232}
238 233
239size_t map__fprintf(struct map *self, FILE *fp) 234size_t map__fprintf(struct map *map, FILE *fp)
240{ 235{
241 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 236 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
242 self->start, self->end, self->pgoff, self->dso->name); 237 map->start, map->end, map->pgoff, map->dso->name);
243} 238}
244 239
245size_t map__fprintf_dsoname(struct map *map, FILE *fp) 240size_t map__fprintf_dsoname(struct map *map, FILE *fp)
@@ -527,9 +522,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
527 return ip - (s64)map->pgoff; 522 return ip - (s64)map->pgoff;
528} 523}
529 524
530void map__reloc_vmlinux(struct map *self) 525void map__reloc_vmlinux(struct map *map)
531{ 526{
532 struct kmap *kmap = map__kmap(self); 527 struct kmap *kmap = map__kmap(map);
533 s64 reloc; 528 s64 reloc;
534 529
535 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) 530 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
@@ -541,9 +536,9 @@ void map__reloc_vmlinux(struct map *self)
541 if (!reloc) 536 if (!reloc)
542 return; 537 return;
543 538
544 self->map_ip = map__reloc_map_ip; 539 map->map_ip = map__reloc_map_ip;
545 self->unmap_ip = map__reloc_unmap_ip; 540 map->unmap_ip = map__reloc_unmap_ip;
546 self->pgoff = reloc; 541 map->pgoff = reloc;
547} 542}
548 543
549void maps__insert(struct rb_root *maps, struct map *map) 544void maps__insert(struct rb_root *maps, struct map *map)
@@ -566,9 +561,9 @@ void maps__insert(struct rb_root *maps, struct map *map)
566 rb_insert_color(&map->rb_node, maps); 561 rb_insert_color(&map->rb_node, maps);
567} 562}
568 563
569void maps__remove(struct rb_root *self, struct map *map) 564void maps__remove(struct rb_root *maps, struct map *map)
570{ 565{
571 rb_erase(&map->rb_node, self); 566 rb_erase(&map->rb_node, maps);
572} 567}
573 568
574struct map *maps__find(struct rb_root *maps, u64 ip) 569struct map *maps__find(struct rb_root *maps, u64 ip)
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index bcb39e2a6965..a887f2c9dfbb 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -57,9 +57,9 @@ struct map_groups {
57 struct machine *machine; 57 struct machine *machine;
58}; 58};
59 59
60static inline struct kmap *map__kmap(struct map *self) 60static inline struct kmap *map__kmap(struct map *map)
61{ 61{
62 return (struct kmap *)(self + 1); 62 return (struct kmap *)(map + 1);
63} 63}
64 64
65static inline u64 map__map_ip(struct map *map, u64 ip) 65static inline u64 map__map_ip(struct map *map, u64 ip)
@@ -85,27 +85,27 @@ struct symbol;
85 85
86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
87 87
88void map__init(struct map *self, enum map_type type, 88void map__init(struct map *map, enum map_type type,
89 u64 start, u64 end, u64 pgoff, struct dso *dso); 89 u64 start, u64 end, u64 pgoff, struct dso *dso);
90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
91 u64 pgoff, u32 pid, char *filename, 91 u64 pgoff, u32 pid, char *filename,
92 enum map_type type); 92 enum map_type type);
93struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 93struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
94void map__delete(struct map *self); 94void map__delete(struct map *map);
95struct map *map__clone(struct map *self); 95struct map *map__clone(struct map *map);
96int map__overlap(struct map *l, struct map *r); 96int map__overlap(struct map *l, struct map *r);
97size_t map__fprintf(struct map *self, FILE *fp); 97size_t map__fprintf(struct map *map, FILE *fp);
98size_t map__fprintf_dsoname(struct map *map, FILE *fp); 98size_t map__fprintf_dsoname(struct map *map, FILE *fp);
99 99
100int map__load(struct map *self, symbol_filter_t filter); 100int map__load(struct map *map, symbol_filter_t filter);
101struct symbol *map__find_symbol(struct map *self, 101struct symbol *map__find_symbol(struct map *map,
102 u64 addr, symbol_filter_t filter); 102 u64 addr, symbol_filter_t filter);
103struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 103struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
104 symbol_filter_t filter); 104 symbol_filter_t filter);
105void map__fixup_start(struct map *self); 105void map__fixup_start(struct map *map);
106void map__fixup_end(struct map *self); 106void map__fixup_end(struct map *map);
107 107
108void map__reloc_vmlinux(struct map *self); 108void map__reloc_vmlinux(struct map *map);
109 109
110size_t __map_groups__fprintf_maps(struct map_groups *mg, 110size_t __map_groups__fprintf_maps(struct map_groups *mg,
111 enum map_type type, int verbose, FILE *fp); 111 enum map_type type, int verbose, FILE *fp);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 2d8d53bec17e..c84f48cf9678 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))
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
657 int exclude = eu | ek | eh; 699 int exclude = eu | ek | eh;
658 int exclude_GH = evsel ? evsel->exclude_GH : 0; 700 int exclude_GH = evsel ? evsel->exclude_GH : 0;
659 701
660 /*
661 * We are here for group and 'GH' was not set as event
662 * modifier and whatever event/group modifier override
663 * default 'GH' setup.
664 */
665 if (evsel && !exclude_GH)
666 eH = eG = 0;
667
668 memset(mod, 0, sizeof(*mod)); 702 memset(mod, 0, sizeof(*mod));
669 703
670 while (*str) { 704 while (*str) {
@@ -814,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
814 */ 848 */
815int parse_events_terms(struct list_head *terms, const char *str) 849int parse_events_terms(struct list_head *terms, const char *str)
816{ 850{
817 struct parse_events_data__terms data = { 851 struct parse_events_terms data = {
818 .terms = NULL, 852 .terms = NULL,
819 }; 853 };
820 int ret; 854 int ret;
@@ -830,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
830 return ret; 864 return ret;
831} 865}
832 866
833int parse_events(struct perf_evlist *evlist, const char *str, 867int parse_events(struct perf_evlist *evlist, const char *str)
834 int unset __maybe_unused)
835{ 868{
836 struct parse_events_data__events data = { 869 struct parse_events_evlist data = {
837 .list = LIST_HEAD_INIT(data.list), 870 .list = LIST_HEAD_INIT(data.list),
838 .idx = evlist->nr_entries, 871 .idx = evlist->nr_entries,
839 }; 872 };
@@ -843,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
843 if (!ret) { 876 if (!ret) {
844 int entries = data.idx - evlist->nr_entries; 877 int entries = data.idx - evlist->nr_entries;
845 perf_evlist__splice_list_tail(evlist, &data.list, entries); 878 perf_evlist__splice_list_tail(evlist, &data.list, entries);
879 evlist->nr_groups += data.nr_groups;
846 return 0; 880 return 0;
847 } 881 }
848 882
@@ -858,7 +892,7 @@ int parse_events_option(const struct option *opt, const char *str,
858 int unset __maybe_unused) 892 int unset __maybe_unused)
859{ 893{
860 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 894 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
861 int ret = parse_events(evlist, str, unset); 895 int ret = parse_events(evlist, str);
862 896
863 if (ret) { 897 if (ret) {
864 fprintf(stderr, "invalid or unsupported event: '%s'\n", str); 898 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only)
1121 print_tracepoint_events(NULL, NULL, name_only); 1155 print_tracepoint_events(NULL, NULL, name_only);
1122} 1156}
1123 1157
1124int parse_events__is_hardcoded_term(struct parse_events__term *term) 1158int parse_events__is_hardcoded_term(struct parse_events_term *term)
1125{ 1159{
1126 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 1160 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1127} 1161}
1128 1162
1129static int new_term(struct parse_events__term **_term, int type_val, 1163static int new_term(struct parse_events_term **_term, int type_val,
1130 int type_term, char *config, 1164 int type_term, char *config,
1131 char *str, u64 num) 1165 char *str, u64 num)
1132{ 1166{
1133 struct parse_events__term *term; 1167 struct parse_events_term *term;
1134 1168
1135 term = zalloc(sizeof(*term)); 1169 term = zalloc(sizeof(*term));
1136 if (!term) 1170 if (!term)
@@ -1156,21 +1190,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
1156 return 0; 1190 return 0;
1157} 1191}
1158 1192
1159int parse_events__term_num(struct parse_events__term **term, 1193int parse_events_term__num(struct parse_events_term **term,
1160 int type_term, char *config, u64 num) 1194 int type_term, char *config, u64 num)
1161{ 1195{
1162 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1196 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1163 config, NULL, num); 1197 config, NULL, num);
1164} 1198}
1165 1199
1166int parse_events__term_str(struct parse_events__term **term, 1200int parse_events_term__str(struct parse_events_term **term,
1167 int type_term, char *config, char *str) 1201 int type_term, char *config, char *str)
1168{ 1202{
1169 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1203 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1170 config, str, 0); 1204 config, str, 0);
1171} 1205}
1172 1206
1173int parse_events__term_sym_hw(struct parse_events__term **term, 1207int parse_events_term__sym_hw(struct parse_events_term **term,
1174 char *config, unsigned idx) 1208 char *config, unsigned idx)
1175{ 1209{
1176 struct event_symbol *sym; 1210 struct event_symbol *sym;
@@ -1188,8 +1222,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
1188 (char *) "event", (char *) sym->symbol, 0); 1222 (char *) "event", (char *) sym->symbol, 0);
1189} 1223}
1190 1224
1191int parse_events__term_clone(struct parse_events__term **new, 1225int parse_events_term__clone(struct parse_events_term **new,
1192 struct parse_events__term *term) 1226 struct parse_events_term *term)
1193{ 1227{
1194 return new_term(new, term->type_val, term->type_term, term->config, 1228 return new_term(new, term->type_val, term->type_term, term->config,
1195 term->val.str, term->val.num); 1229 term->val.str, term->val.num);
@@ -1197,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new,
1197 1231
1198void parse_events__free_terms(struct list_head *terms) 1232void parse_events__free_terms(struct list_head *terms)
1199{ 1233{
1200 struct parse_events__term *term, *h; 1234 struct parse_events_term *term, *h;
1201 1235
1202 list_for_each_entry_safe(term, h, terms, list) 1236 list_for_each_entry_safe(term, h, terms, list)
1203 free(term); 1237 free(term);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b7af80b8bdda..8a4859315fd9 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,25 @@ 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;
67 int nr_groups;
68}; 68};
69 69
70struct parse_events_data__terms { 70struct parse_events_terms {
71 struct list_head *terms; 71 struct list_head *terms;
72}; 72};
73 73
74int parse_events__is_hardcoded_term(struct parse_events__term *term); 74int parse_events__is_hardcoded_term(struct parse_events_term *term);
75int parse_events__term_num(struct parse_events__term **_term, 75int parse_events_term__num(struct parse_events_term **_term,
76 int type_term, char *config, u64 num); 76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 77int parse_events_term__str(struct parse_events_term **_term,
78 int type_term, char *config, char *str); 78 int type_term, char *config, char *str);
79int parse_events__term_sym_hw(struct parse_events__term **term, 79int parse_events_term__sym_hw(struct parse_events_term **term,
80 char *config, unsigned idx); 80 char *config, unsigned idx);
81int parse_events__term_clone(struct parse_events__term **new, 81int parse_events_term__clone(struct parse_events_term **new,
82 struct parse_events__term *term); 82 struct parse_events_term *term);
83void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 84int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 85int 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..afc44c18dfe1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,5 +1,4 @@
1%pure-parser 1%pure-parser
2%name-prefix "parse_events_"
3%parse-param {void *_data} 2%parse-param {void *_data}
4%parse-param {void *scanner} 3%parse-param {void *scanner}
5%lex-param {void* scanner} 4%lex-param {void* scanner}
@@ -23,6 +22,14 @@ do { \
23 YYABORT; \ 22 YYABORT; \
24} while (0) 23} while (0)
25 24
25static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data)
27{
28 /* Count groups only have more than 1 members */
29 if (!list_is_last(list->next, list))
30 data->nr_groups++;
31}
32
26%} 33%}
27 34
28%token PE_START_EVENTS PE_START_TERMS 35%token PE_START_EVENTS PE_START_TERMS
@@ -68,7 +75,7 @@ do { \
68 char *str; 75 char *str;
69 u64 num; 76 u64 num;
70 struct list_head *head; 77 struct list_head *head;
71 struct parse_events__term *term; 78 struct parse_events_term *term;
72} 79}
73%% 80%%
74 81
@@ -79,7 +86,7 @@ PE_START_TERMS start_terms
79 86
80start_events: groups 87start_events: groups
81{ 88{
82 struct parse_events_data__events *data = _data; 89 struct parse_events_evlist *data = _data;
83 90
84 parse_events_update_lists($1, &data->list); 91 parse_events_update_lists($1, &data->list);
85} 92}
@@ -123,6 +130,7 @@ PE_NAME '{' events '}'
123{ 130{
124 struct list_head *list = $3; 131 struct list_head *list = $3;
125 132
133 inc_group_count(list, _data);
126 parse_events__set_leader($1, list); 134 parse_events__set_leader($1, list);
127 $$ = list; 135 $$ = list;
128} 136}
@@ -131,6 +139,7 @@ PE_NAME '{' events '}'
131{ 139{
132 struct list_head *list = $2; 140 struct list_head *list = $2;
133 141
142 inc_group_count(list, _data);
134 parse_events__set_leader(NULL, list); 143 parse_events__set_leader(NULL, list);
135 $$ = list; 144 $$ = list;
136} 145}
@@ -186,7 +195,7 @@ event_def: event_pmu |
186event_pmu: 195event_pmu:
187PE_NAME '/' event_config '/' 196PE_NAME '/' event_config '/'
188{ 197{
189 struct parse_events_data__events *data = _data; 198 struct parse_events_evlist *data = _data;
190 struct list_head *list = NULL; 199 struct list_head *list = NULL;
191 200
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW
202event_legacy_symbol: 211event_legacy_symbol:
203value_sym '/' event_config '/' 212value_sym '/' event_config '/'
204{ 213{
205 struct parse_events_data__events *data = _data; 214 struct parse_events_evlist *data = _data;
206 struct list_head *list = NULL; 215 struct list_head *list = NULL;
207 int type = $1 >> 16; 216 int type = $1 >> 16;
208 int config = $1 & 255; 217 int config = $1 & 255;
@@ -215,7 +224,7 @@ value_sym '/' event_config '/'
215| 224|
216value_sym sep_slash_dc 225value_sym sep_slash_dc
217{ 226{
218 struct parse_events_data__events *data = _data; 227 struct parse_events_evlist *data = _data;
219 struct list_head *list = NULL; 228 struct list_head *list = NULL;
220 int type = $1 >> 16; 229 int type = $1 >> 16;
221 int config = $1 & 255; 230 int config = $1 & 255;
@@ -228,7 +237,7 @@ value_sym sep_slash_dc
228event_legacy_cache: 237event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{ 239{
231 struct parse_events_data__events *data = _data; 240 struct parse_events_evlist *data = _data;
232 struct list_head *list = NULL; 241 struct list_head *list = NULL;
233 242
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
237| 246|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{ 248{
240 struct parse_events_data__events *data = _data; 249 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 250 struct list_head *list = NULL;
242 251
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
246| 255|
247PE_NAME_CACHE_TYPE 256PE_NAME_CACHE_TYPE
248{ 257{
249 struct parse_events_data__events *data = _data; 258 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 259 struct list_head *list = NULL;
251 260
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE
256event_legacy_mem: 265event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{ 267{
259 struct parse_events_data__events *data = _data; 268 struct parse_events_evlist *data = _data;
260 struct list_head *list = NULL; 269 struct list_head *list = NULL;
261 270
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
266| 275|
267PE_PREFIX_MEM PE_VALUE sep_dc 276PE_PREFIX_MEM PE_VALUE sep_dc
268{ 277{
269 struct parse_events_data__events *data = _data; 278 struct parse_events_evlist *data = _data;
270 struct list_head *list = NULL; 279 struct list_head *list = NULL;
271 280
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
277event_legacy_tracepoint: 286event_legacy_tracepoint:
278PE_NAME ':' PE_NAME 287PE_NAME ':' PE_NAME
279{ 288{
280 struct parse_events_data__events *data = _data; 289 struct parse_events_evlist *data = _data;
281 struct list_head *list = NULL; 290 struct list_head *list = NULL;
282 291
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME
287event_legacy_numeric: 296event_legacy_numeric:
288PE_VALUE ':' PE_VALUE 297PE_VALUE ':' PE_VALUE
289{ 298{
290 struct parse_events_data__events *data = _data; 299 struct parse_events_evlist *data = _data;
291 struct list_head *list = NULL; 300 struct list_head *list = NULL;
292 301
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE
297event_legacy_raw: 306event_legacy_raw:
298PE_RAW 307PE_RAW
299{ 308{
300 struct parse_events_data__events *data = _data; 309 struct parse_events_evlist *data = _data;
301 struct list_head *list = NULL; 310 struct list_head *list = NULL;
302 311
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 312 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +316,7 @@ PE_RAW
307 316
308start_terms: event_config 317start_terms: event_config
309{ 318{
310 struct parse_events_data__terms *data = _data; 319 struct parse_events_terms *data = _data;
311 data->terms = $1; 320 data->terms = $1;
312} 321}
313 322
@@ -315,7 +324,7 @@ event_config:
315event_config ',' event_term 324event_config ',' event_term
316{ 325{
317 struct list_head *head = $1; 326 struct list_head *head = $1;
318 struct parse_events__term *term = $3; 327 struct parse_events_term *term = $3;
319 328
320 ABORT_ON(!head); 329 ABORT_ON(!head);
321 list_add_tail(&term->list, head); 330 list_add_tail(&term->list, head);
@@ -325,7 +334,7 @@ event_config ',' event_term
325event_term 334event_term
326{ 335{
327 struct list_head *head = malloc(sizeof(*head)); 336 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1; 337 struct parse_events_term *term = $1;
329 338
330 ABORT_ON(!head); 339 ABORT_ON(!head);
331 INIT_LIST_HEAD(head); 340 INIT_LIST_HEAD(head);
@@ -336,70 +345,70 @@ event_term
336event_term: 345event_term:
337PE_NAME '=' PE_NAME 346PE_NAME '=' PE_NAME
338{ 347{
339 struct parse_events__term *term; 348 struct parse_events_term *term;
340 349
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, 350 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3)); 351 $1, $3));
343 $$ = term; 352 $$ = term;
344} 353}
345| 354|
346PE_NAME '=' PE_VALUE 355PE_NAME '=' PE_VALUE
347{ 356{
348 struct parse_events__term *term; 357 struct parse_events_term *term;
349 358
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 359 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3)); 360 $1, $3));
352 $$ = term; 361 $$ = term;
353} 362}
354| 363|
355PE_NAME '=' PE_VALUE_SYM_HW 364PE_NAME '=' PE_VALUE_SYM_HW
356{ 365{
357 struct parse_events__term *term; 366 struct parse_events_term *term;
358 int config = $3 & 255; 367 int config = $3 & 255;
359 368
360 ABORT_ON(parse_events__term_sym_hw(&term, $1, config)); 369 ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
361 $$ = term; 370 $$ = term;
362} 371}
363| 372|
364PE_NAME 373PE_NAME
365{ 374{
366 struct parse_events__term *term; 375 struct parse_events_term *term;
367 376
368 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 377 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
369 $1, 1)); 378 $1, 1));
370 $$ = term; 379 $$ = term;
371} 380}
372| 381|
373PE_VALUE_SYM_HW 382PE_VALUE_SYM_HW
374{ 383{
375 struct parse_events__term *term; 384 struct parse_events_term *term;
376 int config = $1 & 255; 385 int config = $1 & 255;
377 386
378 ABORT_ON(parse_events__term_sym_hw(&term, NULL, config)); 387 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
379 $$ = term; 388 $$ = term;
380} 389}
381| 390|
382PE_TERM '=' PE_NAME 391PE_TERM '=' PE_NAME
383{ 392{
384 struct parse_events__term *term; 393 struct parse_events_term *term;
385 394
386 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); 395 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
387 $$ = term; 396 $$ = term;
388} 397}
389| 398|
390PE_TERM '=' PE_VALUE 399PE_TERM '=' PE_VALUE
391{ 400{
392 struct parse_events__term *term; 401 struct parse_events_term *term;
393 402
394 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); 403 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
395 $$ = term; 404 $$ = term;
396} 405}
397| 406|
398PE_TERM 407PE_TERM
399{ 408{
400 struct parse_events__term *term; 409 struct parse_events_term *term;
401 410
402 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); 411 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
403 $$ = term; 412 $$ = term;
404} 413}
405 414
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/pmu.y b/tools/perf/util/pmu.y
index ec898047ebb9..bfd7e8509869 100644
--- a/tools/perf/util/pmu.y
+++ b/tools/perf/util/pmu.y
@@ -1,5 +1,4 @@
1 1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format} 2%parse-param {struct list_head *format}
4%parse-param {char *name} 3%parse-param {char *name}
5 4
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-ext-sources b/tools/perf/util/python-ext-sources
index c40c2d33199e..64536a993f4a 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,4 +18,5 @@ util/cgroup.c
18util/debugfs.c 18util/debugfs.c
19util/rblist.c 19util/rblist.c
20util/strlist.c 20util/strlist.c
21util/sysfs.c
21../../lib/rbtree.c 22../../lib/rbtree.c
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 ce6f51162386..bd85280bb6e8 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,7 +16,6 @@
16#include "cpumap.h" 16#include "cpumap.h"
17#include "event-parse.h" 17#include "event-parse.h"
18#include "perf_regs.h" 18#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h" 19#include "vdso.h"
21 20
22static int perf_session__open(struct perf_session *self, bool force) 21static int perf_session__open(struct perf_session *self, bool force)
@@ -87,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
87{ 86{
88 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 87 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
89 88
90 session->host_machine.id_hdr_size = id_hdr_size;
91 machines__set_id_hdr_size(&session->machines, id_hdr_size); 89 machines__set_id_hdr_size(&session->machines, id_hdr_size);
92} 90}
93 91
94int perf_session__create_kernel_maps(struct perf_session *self) 92int perf_session__create_kernel_maps(struct perf_session *self)
95{ 93{
96 int ret = machine__create_kernel_maps(&self->host_machine); 94 int ret = machine__create_kernel_maps(&self->machines.host);
97 95
98 if (ret >= 0) 96 if (ret >= 0)
99 ret = machines__create_guest_kernel_maps(&self->machines); 97 ret = machines__create_guest_kernel_maps(&self->machines);
@@ -102,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
102 100
103static void perf_session__destroy_kernel_maps(struct perf_session *self) 101static void perf_session__destroy_kernel_maps(struct perf_session *self)
104{ 102{
105 machine__destroy_kernel_maps(&self->host_machine); 103 machines__destroy_kernel_maps(&self->machines);
106 machines__destroy_guest_kernel_maps(&self->machines);
107} 104}
108 105
109struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
@@ -128,22 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
128 goto out; 125 goto out;
129 126
130 memcpy(self->filename, filename, len); 127 memcpy(self->filename, filename, len);
131 /*
132 * On 64bit we can mmap the data file in one go. No need for tiny mmap
133 * slices. On 32bit we use 32MB.
134 */
135#if BITS_PER_LONG == 64
136 self->mmap_window = ULLONG_MAX;
137#else
138 self->mmap_window = 32 * 1024 * 1024ULL;
139#endif
140 self->machines = RB_ROOT;
141 self->repipe = repipe; 128 self->repipe = repipe;
142 INIT_LIST_HEAD(&self->ordered_samples.samples); 129 INIT_LIST_HEAD(&self->ordered_samples.samples);
143 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 130 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
144 INIT_LIST_HEAD(&self->ordered_samples.to_free); 131 INIT_LIST_HEAD(&self->ordered_samples.to_free);
145 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 132 machines__init(&self->machines);
146 hists__init(&self->hists);
147 133
148 if (mode == O_RDONLY) { 134 if (mode == O_RDONLY) {
149 if (perf_session__open(self, force) < 0) 135 if (perf_session__open(self, force) < 0)
@@ -171,37 +157,30 @@ out_delete:
171 return NULL; 157 return NULL;
172} 158}
173 159
174static void machine__delete_dead_threads(struct machine *machine)
175{
176 struct thread *n, *t;
177
178 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
179 list_del(&t->node);
180 thread__delete(t);
181 }
182}
183
184static void perf_session__delete_dead_threads(struct perf_session *session) 160static void perf_session__delete_dead_threads(struct perf_session *session)
185{ 161{
186 machine__delete_dead_threads(&session->host_machine); 162 machine__delete_dead_threads(&session->machines.host);
187} 163}
188 164
189static void machine__delete_threads(struct machine *self) 165static void perf_session__delete_threads(struct perf_session *session)
190{ 166{
191 struct rb_node *nd = rb_first(&self->threads); 167 machine__delete_threads(&session->machines.host);
192
193 while (nd) {
194 struct thread *t = rb_entry(nd, struct thread, rb_node);
195
196 rb_erase(&t->rb_node, &self->threads);
197 nd = rb_next(nd);
198 thread__delete(t);
199 }
200} 168}
201 169
202static void perf_session__delete_threads(struct perf_session *session) 170static void perf_session_env__delete(struct perf_session_env *env)
203{ 171{
204 machine__delete_threads(&session->host_machine); 172 free(env->hostname);
173 free(env->os_release);
174 free(env->version);
175 free(env->arch);
176 free(env->cpu_desc);
177 free(env->cpuid);
178
179 free(env->cmdline);
180 free(env->sibling_cores);
181 free(env->sibling_threads);
182 free(env->numa_nodes);
183 free(env->pmu_mappings);
205} 184}
206 185
207void perf_session__delete(struct perf_session *self) 186void perf_session__delete(struct perf_session *self)
@@ -209,198 +188,13 @@ void perf_session__delete(struct perf_session *self)
209 perf_session__destroy_kernel_maps(self); 188 perf_session__destroy_kernel_maps(self);
210 perf_session__delete_dead_threads(self); 189 perf_session__delete_dead_threads(self);
211 perf_session__delete_threads(self); 190 perf_session__delete_threads(self);
212 machine__exit(&self->host_machine); 191 perf_session_env__delete(&self->header.env);
192 machines__exit(&self->machines);
213 close(self->fd); 193 close(self->fd);
214 free(self); 194 free(self);
215 vdso__exit(); 195 vdso__exit();
216} 196}
217 197
218void machine__remove_thread(struct machine *self, struct thread *th)
219{
220 self->last_match = NULL;
221 rb_erase(&th->rb_node, &self->threads);
222 /*
223 * We may have references to this thread, for instance in some hist_entry
224 * instances, so just move them to a separate list.
225 */
226 list_add_tail(&th->node, &self->dead_threads);
227}
228
229static bool symbol__match_parent_regex(struct symbol *sym)
230{
231 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
232 return 1;
233
234 return 0;
235}
236
237static const u8 cpumodes[] = {
238 PERF_RECORD_MISC_USER,
239 PERF_RECORD_MISC_KERNEL,
240 PERF_RECORD_MISC_GUEST_USER,
241 PERF_RECORD_MISC_GUEST_KERNEL
242};
243#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
244
245static void ip__resolve_ams(struct machine *self, struct thread *thread,
246 struct addr_map_symbol *ams,
247 u64 ip)
248{
249 struct addr_location al;
250 size_t i;
251 u8 m;
252
253 memset(&al, 0, sizeof(al));
254
255 for (i = 0; i < NCPUMODES; i++) {
256 m = cpumodes[i];
257 /*
258 * We cannot use the header.misc hint to determine whether a
259 * branch stack address is user, kernel, guest, hypervisor.
260 * Branches may straddle the kernel/user/hypervisor boundaries.
261 * Thus, we have to try consecutively until we find a match
262 * or else, the symbol is unknown
263 */
264 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
265 ip, &al, NULL);
266 if (al.sym)
267 goto found;
268 }
269found:
270 ams->addr = ip;
271 ams->al_addr = al.addr;
272 ams->sym = al.sym;
273 ams->map = al.map;
274}
275
276struct branch_info *machine__resolve_bstack(struct machine *self,
277 struct thread *thr,
278 struct branch_stack *bs)
279{
280 struct branch_info *bi;
281 unsigned int i;
282
283 bi = calloc(bs->nr, sizeof(struct branch_info));
284 if (!bi)
285 return NULL;
286
287 for (i = 0; i < bs->nr; i++) {
288 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
289 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
290 bi[i].flags = bs->entries[i].flags;
291 }
292 return bi;
293}
294
295static int machine__resolve_callchain_sample(struct machine *machine,
296 struct thread *thread,
297 struct ip_callchain *chain,
298 struct symbol **parent)
299
300{
301 u8 cpumode = PERF_RECORD_MISC_USER;
302 unsigned int i;
303 int err;
304
305 callchain_cursor_reset(&callchain_cursor);
306
307 if (chain->nr > PERF_MAX_STACK_DEPTH) {
308 pr_warning("corrupted callchain. skipping...\n");
309 return 0;
310 }
311
312 for (i = 0; i < chain->nr; i++) {
313 u64 ip;
314 struct addr_location al;
315
316 if (callchain_param.order == ORDER_CALLEE)
317 ip = chain->ips[i];
318 else
319 ip = chain->ips[chain->nr - i - 1];
320
321 if (ip >= PERF_CONTEXT_MAX) {
322 switch (ip) {
323 case PERF_CONTEXT_HV:
324 cpumode = PERF_RECORD_MISC_HYPERVISOR;
325 break;
326 case PERF_CONTEXT_KERNEL:
327 cpumode = PERF_RECORD_MISC_KERNEL;
328 break;
329 case PERF_CONTEXT_USER:
330 cpumode = PERF_RECORD_MISC_USER;
331 break;
332 default:
333 pr_debug("invalid callchain context: "
334 "%"PRId64"\n", (s64) ip);
335 /*
336 * It seems the callchain is corrupted.
337 * Discard all.
338 */
339 callchain_cursor_reset(&callchain_cursor);
340 return 0;
341 }
342 continue;
343 }
344
345 al.filtered = false;
346 thread__find_addr_location(thread, machine, cpumode,
347 MAP__FUNCTION, ip, &al, NULL);
348 if (al.sym != NULL) {
349 if (sort__has_parent && !*parent &&
350 symbol__match_parent_regex(al.sym))
351 *parent = al.sym;
352 if (!symbol_conf.use_callchain)
353 break;
354 }
355
356 err = callchain_cursor_append(&callchain_cursor,
357 ip, al.map, al.sym);
358 if (err)
359 return err;
360 }
361
362 return 0;
363}
364
365static int unwind_entry(struct unwind_entry *entry, void *arg)
366{
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event 198static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused, 199 __maybe_unused,
406 struct perf_session *session 200 struct perf_session *session
@@ -1027,7 +821,7 @@ static struct machine *
1027 return perf_session__findnew_machine(session, pid); 821 return perf_session__findnew_machine(session, pid);
1028 } 822 }
1029 823
1030 return perf_session__find_host_machine(session); 824 return &session->machines.host;
1031} 825}
1032 826
1033static int perf_session_deliver_event(struct perf_session *session, 827static int perf_session_deliver_event(struct perf_session *session,
@@ -1065,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
1065 case PERF_RECORD_SAMPLE: 859 case PERF_RECORD_SAMPLE:
1066 dump_sample(evsel, event, sample); 860 dump_sample(evsel, event, sample);
1067 if (evsel == NULL) { 861 if (evsel == NULL) {
1068 ++session->hists.stats.nr_unknown_id; 862 ++session->stats.nr_unknown_id;
1069 return 0; 863 return 0;
1070 } 864 }
1071 if (machine == NULL) { 865 if (machine == NULL) {
1072 ++session->hists.stats.nr_unprocessable_samples; 866 ++session->stats.nr_unprocessable_samples;
1073 return 0; 867 return 0;
1074 } 868 }
1075 return tool->sample(tool, event, sample, evsel, machine); 869 return tool->sample(tool, event, sample, evsel, machine);
@@ -1083,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1083 return tool->exit(tool, event, sample, machine); 877 return tool->exit(tool, event, sample, machine);
1084 case PERF_RECORD_LOST: 878 case PERF_RECORD_LOST:
1085 if (tool->lost == perf_event__process_lost) 879 if (tool->lost == perf_event__process_lost)
1086 session->hists.stats.total_lost += event->lost.lost; 880 session->stats.total_lost += event->lost.lost;
1087 return tool->lost(tool, event, sample, machine); 881 return tool->lost(tool, event, sample, machine);
1088 case PERF_RECORD_READ: 882 case PERF_RECORD_READ:
1089 return tool->read(tool, event, sample, evsel, machine); 883 return tool->read(tool, event, sample, evsel, machine);
@@ -1092,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1092 case PERF_RECORD_UNTHROTTLE: 886 case PERF_RECORD_UNTHROTTLE:
1093 return tool->unthrottle(tool, event, sample, machine); 887 return tool->unthrottle(tool, event, sample, machine);
1094 default: 888 default:
1095 ++session->hists.stats.nr_unknown_events; 889 ++session->stats.nr_unknown_events;
1096 return -1; 890 return -1;
1097 } 891 }
1098} 892}
@@ -1106,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1106 900
1107 if (!ip_callchain__valid(sample->callchain, event)) { 901 if (!ip_callchain__valid(sample->callchain, event)) {
1108 pr_debug("call-chain problem with event, skipping it.\n"); 902 pr_debug("call-chain problem with event, skipping it.\n");
1109 ++session->hists.stats.nr_invalid_chains; 903 ++session->stats.nr_invalid_chains;
1110 session->hists.stats.total_invalid_chains += sample->period; 904 session->stats.total_invalid_chains += sample->period;
1111 return -EINVAL; 905 return -EINVAL;
1112 } 906 }
1113 return 0; 907 return 0;
@@ -1165,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
1165 if (event->header.type >= PERF_RECORD_HEADER_MAX) 959 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1166 return -EINVAL; 960 return -EINVAL;
1167 961
1168 hists__inc_nr_events(&session->hists, event->header.type); 962 events_stats__inc(&session->stats, event->header.type);
1169 963
1170 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 964 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
1171 return perf_session__process_user_event(session, event, tool, file_offset); 965 return perf_session__process_user_event(session, event, tool, file_offset);
@@ -1201,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
1201 995
1202struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 996struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1203{ 997{
1204 return machine__findnew_thread(&session->host_machine, pid); 998 return machine__findnew_thread(&session->machines.host, pid);
1205} 999}
1206 1000
1207static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1001static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1220,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1220 const struct perf_tool *tool) 1014 const struct perf_tool *tool)
1221{ 1015{
1222 if (tool->lost == perf_event__process_lost && 1016 if (tool->lost == perf_event__process_lost &&
1223 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 1017 session->stats.nr_events[PERF_RECORD_LOST] != 0) {
1224 ui__warning("Processed %d events and lost %d chunks!\n\n" 1018 ui__warning("Processed %d events and lost %d chunks!\n\n"
1225 "Check IO/CPU overload!\n\n", 1019 "Check IO/CPU overload!\n\n",
1226 session->hists.stats.nr_events[0], 1020 session->stats.nr_events[0],
1227 session->hists.stats.nr_events[PERF_RECORD_LOST]); 1021 session->stats.nr_events[PERF_RECORD_LOST]);
1228 } 1022 }
1229 1023
1230 if (session->hists.stats.nr_unknown_events != 0) { 1024 if (session->stats.nr_unknown_events != 0) {
1231 ui__warning("Found %u unknown events!\n\n" 1025 ui__warning("Found %u unknown events!\n\n"
1232 "Is this an older tool processing a perf.data " 1026 "Is this an older tool processing a perf.data "
1233 "file generated by a more recent tool?\n\n" 1027 "file generated by a more recent tool?\n\n"
1234 "If that is not the case, consider " 1028 "If that is not the case, consider "
1235 "reporting to linux-kernel@vger.kernel.org.\n\n", 1029 "reporting to linux-kernel@vger.kernel.org.\n\n",
1236 session->hists.stats.nr_unknown_events); 1030 session->stats.nr_unknown_events);
1237 } 1031 }
1238 1032
1239 if (session->hists.stats.nr_unknown_id != 0) { 1033 if (session->stats.nr_unknown_id != 0) {
1240 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",
1241 session->hists.stats.nr_unknown_id); 1035 session->stats.nr_unknown_id);
1242 } 1036 }
1243 1037
1244 if (session->hists.stats.nr_invalid_chains != 0) { 1038 if (session->stats.nr_invalid_chains != 0) {
1245 ui__warning("Found invalid callchains!\n\n" 1039 ui__warning("Found invalid callchains!\n\n"
1246 "%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"
1247 "Consider reporting to linux-kernel@vger.kernel.org.\n\n", 1041 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1248 session->hists.stats.nr_invalid_chains, 1042 session->stats.nr_invalid_chains,
1249 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1043 session->stats.nr_events[PERF_RECORD_SAMPLE]);
1250 } 1044 }
1251 1045
1252 if (session->hists.stats.nr_unprocessable_samples != 0) { 1046 if (session->stats.nr_unprocessable_samples != 0) {
1253 ui__warning("%u unprocessable samples recorded.\n" 1047 ui__warning("%u unprocessable samples recorded.\n"
1254 "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",
1255 session->hists.stats.nr_unprocessable_samples); 1049 session->stats.nr_unprocessable_samples);
1256 } 1050 }
1257} 1051}
1258 1052
@@ -1369,6 +1163,18 @@ fetch_mmaped_event(struct perf_session *session,
1369 return event; 1163 return event;
1370} 1164}
1371 1165
1166/*
1167 * On 64bit we can mmap the data file in one go. No need for tiny mmap
1168 * slices. On 32bit we use 32MB.
1169 */
1170#if BITS_PER_LONG == 64
1171#define MMAP_SIZE ULLONG_MAX
1172#define NUM_MMAPS 1
1173#else
1174#define MMAP_SIZE (32 * 1024 * 1024ULL)
1175#define NUM_MMAPS 128
1176#endif
1177
1372int __perf_session__process_events(struct perf_session *session, 1178int __perf_session__process_events(struct perf_session *session,
1373 u64 data_offset, u64 data_size, 1179 u64 data_offset, u64 data_size,
1374 u64 file_size, struct perf_tool *tool) 1180 u64 file_size, struct perf_tool *tool)
@@ -1376,7 +1182,7 @@ int __perf_session__process_events(struct perf_session *session,
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1182 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1183 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t mmap_size; 1184 size_t mmap_size;
1379 char *buf, *mmaps[8]; 1185 char *buf, *mmaps[NUM_MMAPS];
1380 union perf_event *event; 1186 union perf_event *event;
1381 uint32_t size; 1187 uint32_t size;
1382 1188
@@ -1391,7 +1197,7 @@ int __perf_session__process_events(struct perf_session *session,
1391 1197
1392 progress_next = file_size / 16; 1198 progress_next = file_size / 16;
1393 1199
1394 mmap_size = session->mmap_window; 1200 mmap_size = MMAP_SIZE;
1395 if (mmap_size > file_size) 1201 if (mmap_size > file_size)
1396 mmap_size = file_size; 1202 mmap_size = file_size;
1397 1203
@@ -1526,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1526 1332
1527size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1333size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1528{ 1334{
1529 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + 1335 return machines__fprintf_dsos(&self->machines, fp);
1530 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1531 machines__fprintf_dsos(&self->machines, fp);
1532} 1336}
1533 1337
1534size_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,
1535 bool with_hits) 1339 bool (skip)(struct dso *dso, int parm), int parm)
1536{ 1340{
1537 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1341 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1538 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1539} 1342}
1540 1343
1541size_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)
@@ -1543,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1543 struct perf_evsel *pos; 1346 struct perf_evsel *pos;
1544 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1347 size_t ret = fprintf(fp, "Aggregated stats:\n");
1545 1348
1546 ret += hists__fprintf_nr_events(&session->hists, fp); 1349 ret += events_stats__fprintf(&session->stats, fp);
1547 1350
1548 list_for_each_entry(pos, &session->evlist->entries, node) { 1351 list_for_each_entry(pos, &session->evlist->entries, node) {
1549 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1352 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1550 ret += hists__fprintf_nr_events(&pos->hists, fp); 1353 ret += events_stats__fprintf(&pos->hists.stats, fp);
1551 } 1354 }
1552 1355
1553 return ret; 1356 return ret;
@@ -1559,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1559 * 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
1560 * session, not just the host... 1363 * session, not just the host...
1561 */ 1364 */
1562 return machine__fprintf(&session->host_machine, fp); 1365 return machine__fprintf(&session->machines.host, fp);
1563} 1366}
1564 1367
1565void perf_session__remove_thread(struct perf_session *session, 1368void perf_session__remove_thread(struct perf_session *session,
@@ -1568,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
1568 /* 1371 /*
1569 * 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
1570 * 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
1571 * 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
1572 * the 'perf kvm' code. 1375 * the 'perf kvm' code.
1573 */ 1376 */
1574 machine__remove_thread(&session->host_machine, th); 1377 machine__remove_thread(&session->machines.host, th);
1575} 1378}
1576 1379
1577struct 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 cea133a6bdf1..b5c0847edfa9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -30,16 +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 unsigned long mmap_window; 33 struct machines machines;
34 struct machine host_machine;
35 struct rb_root machines;
36 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
37 struct pevent *pevent; 35 struct pevent *pevent;
38 /* 36 struct events_stats stats;
39 * FIXME: Need to split this up further, we need global
40 * stats + per event stats.
41 */
42 struct hists hists;
43 int fd; 37 int fd;
44 bool fd_pipe; 38 bool fd_pipe;
45 bool repipe; 39 bool repipe;
@@ -54,7 +48,7 @@ struct perf_tool;
54struct perf_session *perf_session__new(const char *filename, int mode, 48struct perf_session *perf_session__new(const char *filename, int mode,
55 bool force, bool repipe, 49 bool force, bool repipe,
56 struct perf_tool *tool); 50 struct perf_tool *tool);
57void perf_session__delete(struct perf_session *self); 51void perf_session__delete(struct perf_session *session);
58 52
59void perf_event_header__bswap(struct perf_event_header *self); 53void perf_event_header__bswap(struct perf_event_header *self);
60 54
@@ -81,43 +75,24 @@ void perf_session__set_id_hdr_size(struct perf_session *session);
81void perf_session__remove_thread(struct perf_session *self, struct thread *th); 75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
82 76
83static inline 77static inline
84struct machine *perf_session__find_host_machine(struct perf_session *self)
85{
86 return &self->host_machine;
87}
88
89static inline
90struct 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)
91{ 79{
92 if (pid == HOST_KERNEL_ID)
93 return &self->host_machine;
94 return machines__find(&self->machines, pid); 80 return machines__find(&self->machines, pid);
95} 81}
96 82
97static inline 83static inline
98struct 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)
99{ 85{
100 if (pid == HOST_KERNEL_ID)
101 return &self->host_machine;
102 return machines__findnew(&self->machines, pid); 86 return machines__findnew(&self->machines, pid);
103} 87}
104 88
105static inline
106void perf_session__process_machines(struct perf_session *self,
107 struct perf_tool *tool,
108 machine__process_t process)
109{
110 process(&self->host_machine, tool);
111 return machines__process(&self->machines, process, tool);
112}
113
114struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 89struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
115size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 90size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
116 91
117size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 92size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
118 93
119size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 94size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
120 FILE *fp, bool with_hits); 95 bool (fn)(struct dso *dso, int parm), int parm);
121 96
122size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 97size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
123 98
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32d..d41926cb9e3f 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,40 +127,12 @@ 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
136
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r)
139{
140 if (!sym_l || !sym_r)
141 return cmp_null(sym_l, sym_r);
142
143 if (sym_l == sym_r)
144 return 0;
145
146 if (sym_l)
147 ip_l = sym_l->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150
151 return (int64_t)(ip_r - ip_l);
152}
153
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 136static int _hist_entry__dso_snprintf(struct map *map, char *bf,
155 size_t size, unsigned int width) 137 size_t size, unsigned int width)
156{ 138{
@@ -169,9 +151,43 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 151 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
170} 152}
171 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 */
162
163static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
164{
165 u64 ip_l, ip_r;
166
167 if (!sym_l || !sym_r)
168 return cmp_null(sym_l, sym_r);
169
170 if (sym_l == sym_r)
171 return 0;
172
173 ip_l = sym_l->start;
174 ip_r = sym_r->start;
175
176 return (int64_t)(ip_r - ip_l);
177}
178
179static int64_t
180sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
181{
182 if (!left->ms.sym && !right->ms.sym)
183 return right->level - left->level;
184
185 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
186}
187
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 188static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
173 u64 ip, char level, char *bf, size_t size, 189 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused) 190 unsigned int width)
175{ 191{
176 size_t ret = 0; 192 size_t ret = 0;
177 193
@@ -197,43 +213,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
197 return ret; 213 return ret;
198} 214}
199 215
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, 216static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size, 217 size_t size, unsigned int width)
210 unsigned int width __maybe_unused)
211{ 218{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 219 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width); 220 self->level, bf, size, width);
214} 221}
215 222
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 = { 223struct sort_entry sort_sym = {
238 .se_header = "Symbol", 224 .se_header = "Symbol",
239 .se_cmp = sort__sym_cmp, 225 .se_cmp = sort__sym_cmp,
@@ -253,7 +239,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
253 size_t size, 239 size_t size,
254 unsigned int width __maybe_unused) 240 unsigned int width __maybe_unused)
255{ 241{
256 FILE *fp; 242 FILE *fp = NULL;
257 char cmd[PATH_MAX + 2], *path = self->srcline, *nl; 243 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
258 size_t line_len; 244 size_t line_len;
259 245
@@ -274,7 +260,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
274 260
275 if (getline(&path, &line_len, fp) < 0 || !line_len) 261 if (getline(&path, &line_len, fp) < 0 || !line_len)
276 goto out_ip; 262 goto out_ip;
277 fclose(fp);
278 self->srcline = strdup(path); 263 self->srcline = strdup(path);
279 if (self->srcline == NULL) 264 if (self->srcline == NULL)
280 goto out_ip; 265 goto out_ip;
@@ -284,8 +269,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
284 *nl = '\0'; 269 *nl = '\0';
285 path = self->srcline; 270 path = self->srcline;
286out_path: 271out_path:
272 if (fp)
273 pclose(fp);
287 return repsep_snprintf(bf, size, "%s", path); 274 return repsep_snprintf(bf, size, "%s", path);
288out_ip: 275out_ip:
276 if (fp)
277 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); 278 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 279}
291 280
@@ -335,7 +324,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 324static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width) 325 size_t size, unsigned int width)
337{ 326{
338 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 327 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
339} 328}
340 329
341struct sort_entry sort_cpu = { 330struct sort_entry sort_cpu = {
@@ -345,6 +334,8 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 334 .se_width_idx = HISTC_CPU,
346}; 335};
347 336
337/* sort keys for branch stacks */
338
348static int64_t 339static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 340sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 341{
@@ -359,13 +350,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
359 bf, size, width); 350 bf, size, width);
360} 351}
361 352
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 353static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 354sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{ 355{
@@ -389,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
389 if (!from_l->sym && !from_r->sym) 373 if (!from_l->sym && !from_r->sym)
390 return right->level - left->level; 374 return right->level - left->level;
391 375
392 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, 376 return _sort__sym_cmp(from_l->sym, from_r->sym);
393 from_r->addr);
394} 377}
395 378
396static int64_t 379static int64_t
@@ -402,12 +385,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
402 if (!to_l->sym && !to_r->sym) 385 if (!to_l->sym && !to_r->sym)
403 return right->level - left->level; 386 return right->level - left->level;
404 387
405 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); 388 return _sort__sym_cmp(to_l->sym, to_r->sym);
406} 389}
407 390
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 391static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size, 392 size_t size, unsigned int width)
410 unsigned int width __maybe_unused)
411{ 393{
412 struct addr_map_symbol *from = &self->branch_info->from; 394 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 395 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +398,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
416} 398}
417 399
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 400static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size, 401 size_t size, unsigned int width)
420 unsigned int width __maybe_unused)
421{ 402{
422 struct addr_map_symbol *to = &self->branch_info->to; 403 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 404 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +406,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
425 406
426} 407}
427 408
409struct sort_entry sort_dso_from = {
410 .se_header = "Source Shared Object",
411 .se_cmp = sort__dso_from_cmp,
412 .se_snprintf = hist_entry__dso_from_snprintf,
413 .se_width_idx = HISTC_DSO_FROM,
414};
415
428struct sort_entry sort_dso_to = { 416struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object", 417 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp, 418 .se_cmp = sort__dso_to_cmp,
@@ -484,30 +472,40 @@ struct sort_dimension {
484 472
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 473#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486 474
487static struct sort_dimension sort_dimensions[] = { 475static struct sort_dimension common_sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 476 DIM(SORT_PID, "pid", sort_thread),
489 DIM(SORT_COMM, "comm", sort_comm), 477 DIM(SORT_COMM, "comm", sort_comm),
490 DIM(SORT_DSO, "dso", sort_dso), 478 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), 479 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), 480 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu), 481 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline), 482 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 483};
501 484
485#undef DIM
486
487#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
488
489static struct sort_dimension bstack_sort_dimensions[] = {
490 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
491 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
492 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
493 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
494 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
495};
496
497#undef DIM
498
502int sort_dimension__add(const char *tok) 499int sort_dimension__add(const char *tok)
503{ 500{
504 unsigned int i; 501 unsigned int i;
505 502
506 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 503 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
507 struct sort_dimension *sd = &sort_dimensions[i]; 504 struct sort_dimension *sd = &common_sort_dimensions[i];
508 505
509 if (strncasecmp(tok, sd->name, strlen(tok))) 506 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 507 continue;
508
511 if (sd->entry == &sort_parent) { 509 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 510 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 511 if (ret) {
@@ -518,9 +516,7 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 516 return -EINVAL;
519 } 517 }
520 sort__has_parent = 1; 518 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym || 519 } else if (sd->entry == &sort_sym) {
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1; 520 sort__has_sym = 1;
525 } 521 }
526 522
@@ -530,52 +526,69 @@ int sort_dimension__add(const char *tok)
530 if (sd->entry->se_collapse) 526 if (sd->entry->se_collapse)
531 sort__need_collapse = 1; 527 sort__need_collapse = 1;
532 528
533 if (list_empty(&hist_entry__sort_list)) { 529 if (list_empty(&hist_entry__sort_list))
534 if (!strcmp(sd->name, "pid")) 530 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 531
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 532 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
559 sd->taken = 1; 533 sd->taken = 1;
560 534
561 return 0; 535 return 0;
562 } 536 }
537
538 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
539 struct sort_dimension *sd = &bstack_sort_dimensions[i];
540
541 if (strncasecmp(tok, sd->name, strlen(tok)))
542 continue;
543
544 if (sort__branch_mode != 1)
545 return -EINVAL;
546
547 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
548 sort__has_sym = 1;
549
550 if (sd->taken)
551 return 0;
552
553 if (sd->entry->se_collapse)
554 sort__need_collapse = 1;
555
556 if (list_empty(&hist_entry__sort_list))
557 sort__first_dimension = i + __SORT_BRANCH_STACK;
558
559 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
560 sd->taken = 1;
561
562 return 0;
563 }
564
563 return -ESRCH; 565 return -ESRCH;
564} 566}
565 567
566void setup_sorting(const char * const usagestr[], const struct option *opts) 568int setup_sorting(void)
567{ 569{
568 char *tmp, *tok, *str = strdup(sort_order); 570 char *tmp, *tok, *str = strdup(sort_order);
571 int ret = 0;
572
573 if (str == NULL) {
574 error("Not enough memory to setup sort keys");
575 return -ENOMEM;
576 }
569 577
570 for (tok = strtok_r(str, ", ", &tmp); 578 for (tok = strtok_r(str, ", ", &tmp);
571 tok; tok = strtok_r(NULL, ", ", &tmp)) { 579 tok; tok = strtok_r(NULL, ", ", &tmp)) {
572 if (sort_dimension__add(tok) < 0) { 580 ret = sort_dimension__add(tok);
581 if (ret == -EINVAL) {
582 error("Invalid --sort key: `%s'", tok);
583 break;
584 } else if (ret == -ESRCH) {
573 error("Unknown --sort key: `%s'", tok); 585 error("Unknown --sort key: `%s'", tok);
574 usage_with_options(usagestr, opts); 586 break;
575 } 587 }
576 } 588 }
577 589
578 free(str); 590 free(str);
591 return ret;
579} 592}
580 593
581void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 594void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b4e8c3ba559d..b13e56f6ccbe 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -55,9 +55,6 @@ struct he_stat {
55struct hist_entry_diff { 55struct hist_entry_diff {
56 bool computed; 56 bool computed;
57 57
58 /* PERF_HPP__DISPL */
59 int displacement;
60
61 /* PERF_HPP__DELTA */ 58 /* PERF_HPP__DELTA */
62 double period_ratio_delta; 59 double period_ratio_delta;
63 60
@@ -118,25 +115,29 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
118 return NULL; 115 return NULL;
119} 116}
120 117
121static inline void hist__entry_add_pair(struct hist_entry *he, 118static inline void hist_entry__add_pair(struct hist_entry *he,
122 struct hist_entry *pair) 119 struct hist_entry *pair)
123{ 120{
124 list_add_tail(&he->pairs.head, &pair->pairs.node); 121 list_add_tail(&he->pairs.head, &pair->pairs.node);
125} 122}
126 123
127enum sort_type { 124enum sort_type {
125 /* common sort keys */
128 SORT_PID, 126 SORT_PID,
129 SORT_COMM, 127 SORT_COMM,
130 SORT_DSO, 128 SORT_DSO,
131 SORT_SYM, 129 SORT_SYM,
132 SORT_PARENT, 130 SORT_PARENT,
133 SORT_CPU, 131 SORT_CPU,
134 SORT_DSO_FROM, 132 SORT_SRCLINE,
133
134 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK,
136 SORT_DSO_FROM = __SORT_BRANCH_STACK,
135 SORT_DSO_TO, 137 SORT_DSO_TO,
136 SORT_SYM_FROM, 138 SORT_SYM_FROM,
137 SORT_SYM_TO, 139 SORT_SYM_TO,
138 SORT_MISPREDICT, 140 SORT_MISPREDICT,
139 SORT_SRCLINE,
140}; 141};
141 142
142/* 143/*
@@ -159,7 +160,7 @@ struct sort_entry {
159extern struct sort_entry sort_thread; 160extern struct sort_entry sort_thread;
160extern struct list_head hist_entry__sort_list; 161extern struct list_head hist_entry__sort_list;
161 162
162void setup_sorting(const char * const usagestr[], const struct option *opts); 163int setup_sorting(void);
163extern int sort_dimension__add(const char *); 164extern int sort_dimension__add(const char *);
164void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 165void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
165 const char *list_name, FILE *fp); 166 const char *list_name, FILE *fp);
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/strlist.c b/tools/perf/util/strlist.c
index 155d8b7078a7..55433aa42c8f 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -35,11 +35,11 @@ out_delete:
35 return NULL; 35 return NULL;
36} 36}
37 37
38static void str_node__delete(struct str_node *self, bool dupstr) 38static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 39{
40 if (dupstr) 40 if (dupstr)
41 free((void *)self->s); 41 free((void *)snode->s);
42 free(self); 42 free(snode);
43} 43}
44 44
45static 45static
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
59 return strcmp(snode->s, str); 59 return strcmp(snode->s, str);
60} 60}
61 61
62int strlist__add(struct strlist *self, const char *new_entry) 62int strlist__add(struct strlist *slist, const char *new_entry)
63{ 63{
64 return rblist__add_node(&self->rblist, new_entry); 64 return rblist__add_node(&slist->rblist, new_entry);
65} 65}
66 66
67int strlist__load(struct strlist *self, const char *filename) 67int strlist__load(struct strlist *slist, const char *filename)
68{ 68{
69 char entry[1024]; 69 char entry[1024];
70 int err; 70 int err;
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename)
80 continue; 80 continue;
81 entry[len - 1] = '\0'; 81 entry[len - 1] = '\0';
82 82
83 err = strlist__add(self, entry); 83 err = strlist__add(slist, entry);
84 if (err != 0) 84 if (err != 0)
85 goto out; 85 goto out;
86 } 86 }
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry)
107 return snode; 107 return snode;
108} 108}
109 109
110static int strlist__parse_list_entry(struct strlist *self, const char *s) 110static int strlist__parse_list_entry(struct strlist *slist, const char *s)
111{ 111{
112 if (strncmp(s, "file://", 7) == 0) 112 if (strncmp(s, "file://", 7) == 0)
113 return strlist__load(self, s + 7); 113 return strlist__load(slist, s + 7);
114 114
115 return strlist__add(self, s); 115 return strlist__add(slist, s);
116} 116}
117 117
118int strlist__parse_list(struct strlist *self, const char *s) 118int strlist__parse_list(struct strlist *slist, const char *s)
119{ 119{
120 char *sep; 120 char *sep;
121 int err; 121 int err;
122 122
123 while ((sep = strchr(s, ',')) != NULL) { 123 while ((sep = strchr(s, ',')) != NULL) {
124 *sep = '\0'; 124 *sep = '\0';
125 err = strlist__parse_list_entry(self, s); 125 err = strlist__parse_list_entry(slist, s);
126 *sep = ','; 126 *sep = ',';
127 if (err != 0) 127 if (err != 0)
128 return err; 128 return err;
129 s = sep + 1; 129 s = sep + 1;
130 } 130 }
131 131
132 return *s ? strlist__parse_list_entry(self, s) : 0; 132 return *s ? strlist__parse_list_entry(slist, s) : 0;
133} 133}
134 134
135struct strlist *strlist__new(bool dupstr, const char *slist) 135struct strlist *strlist__new(bool dupstr, const char *list)
136{ 136{
137 struct strlist *self = malloc(sizeof(*self)); 137 struct strlist *slist = malloc(sizeof(*slist));
138 138
139 if (self != NULL) { 139 if (slist != NULL) {
140 rblist__init(&self->rblist); 140 rblist__init(&slist->rblist);
141 self->rblist.node_cmp = strlist__node_cmp; 141 slist->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new; 142 slist->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete; 143 slist->rblist.node_delete = strlist__node_delete;
144 144
145 self->dupstr = dupstr; 145 slist->dupstr = dupstr;
146 if (slist && strlist__parse_list(self, slist) != 0) 146 if (slist && strlist__parse_list(slist, list) != 0)
147 goto out_error; 147 goto out_error;
148 } 148 }
149 149
150 return self; 150 return slist;
151out_error: 151out_error:
152 free(self); 152 free(slist);
153 return NULL; 153 return NULL;
154} 154}
155 155
156void strlist__delete(struct strlist *self) 156void strlist__delete(struct strlist *slist)
157{ 157{
158 if (self != NULL) 158 if (slist != NULL)
159 rblist__delete(&self->rblist); 159 rblist__delete(&slist->rblist);
160} 160}
161 161
162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) 162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index dd9f922ec67c..5c7f87069d9c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -17,34 +17,34 @@ struct strlist {
17}; 17};
18 18
19struct strlist *strlist__new(bool dupstr, const char *slist); 19struct strlist *strlist__new(bool dupstr, const char *slist);
20void strlist__delete(struct strlist *self); 20void strlist__delete(struct strlist *slist);
21 21
22void strlist__remove(struct strlist *self, struct str_node *sn); 22void strlist__remove(struct strlist *slist, struct str_node *sn);
23int strlist__load(struct strlist *self, const char *filename); 23int strlist__load(struct strlist *slist, const char *filename);
24int strlist__add(struct strlist *self, const char *str); 24int strlist__add(struct strlist *slist, const char *str);
25 25
26struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 26struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx);
27struct str_node *strlist__find(struct strlist *self, const char *entry); 27struct str_node *strlist__find(struct strlist *slist, const char *entry);
28 28
29static inline bool strlist__has_entry(struct strlist *self, const char *entry) 29static inline bool strlist__has_entry(struct strlist *slist, const char *entry)
30{ 30{
31 return strlist__find(self, entry) != NULL; 31 return strlist__find(slist, entry) != NULL;
32} 32}
33 33
34static inline bool strlist__empty(const struct strlist *self) 34static inline bool strlist__empty(const struct strlist *slist)
35{ 35{
36 return rblist__empty(&self->rblist); 36 return rblist__empty(&slist->rblist);
37} 37}
38 38
39static inline unsigned int strlist__nr_entries(const struct strlist *self) 39static inline unsigned int strlist__nr_entries(const struct strlist *slist)
40{ 40{
41 return rblist__nr_entries(&self->rblist); 41 return rblist__nr_entries(&slist->rblist);
42} 42}
43 43
44/* For strlist iteration */ 44/* For strlist iteration */
45static inline struct str_node *strlist__first(struct strlist *self) 45static inline struct str_node *strlist__first(struct strlist *slist)
46{ 46{
47 struct rb_node *rn = rb_first(&self->rblist.entries); 47 struct rb_node *rn = rb_first(&slist->rblist.entries);
48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
49} 49}
50static inline struct str_node *strlist__next(struct str_node *sn) 50static inline struct str_node *strlist__next(struct str_node *sn)
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn)
59/** 59/**
60 * strlist_for_each - iterate over a strlist 60 * strlist_for_each - iterate over a strlist
61 * @pos: the &struct str_node to use as a loop cursor. 61 * @pos: the &struct str_node to use as a loop cursor.
62 * @self: the &struct strlist for loop. 62 * @slist: the &struct strlist for loop.
63 */ 63 */
64#define strlist__for_each(pos, self) \ 64#define strlist__for_each(pos, slist) \
65 for (pos = strlist__first(self); pos; pos = strlist__next(pos)) 65 for (pos = strlist__first(slist); pos; pos = strlist__next(pos))
66 66
67/** 67/**
68 * strlist_for_each_safe - iterate over a strlist safe against removal of 68 * strlist_for_each_safe - iterate over a strlist safe against removal of
69 * str_node 69 * str_node
70 * @pos: the &struct str_node to use as a loop cursor. 70 * @pos: the &struct str_node to use as a loop cursor.
71 * @n: another &struct str_node to use as temporary storage. 71 * @n: another &struct str_node to use as temporary storage.
72 * @self: the &struct strlist for loop. 72 * @slist: the &struct strlist for loop.
73 */ 73 */
74#define strlist__for_each_safe(pos, n, self) \ 74#define strlist__for_each_safe(pos, n, slist) \
75 for (pos = strlist__first(self), n = strlist__next(pos); pos;\ 75 for (pos = strlist__first(slist), n = strlist__next(pos); pos;\
76 pos = n, n = strlist__next(n)) 76 pos = n, n = strlist__next(n))
77 77
78int strlist__parse_list(struct strlist *self, const char *s); 78int strlist__parse_list(struct strlist *slist, const char *s);
79#endif /* __PERF_STRLIST_H */ 79#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index db0cc92cf2ea..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>
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
718 sym.st_value); 715 sym.st_value);
719 used_opd = true; 716 used_opd = true;
720 } 717 }
718 /*
719 * When loading symbols in a data mapping, ABS symbols (which
720 * has a value of SHN_ABS in its st_shndx) failed at
721 * elf_getscn(). And it marks the loading as a failure so
722 * already loaded symbols cannot be fixed up.
723 *
724 * I'm not sure what should be done. Just ignore them for now.
725 * - Namhyung Kim
726 */
727 if (sym.st_shndx == SHN_ABS)
728 continue;
721 729
722 sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 730 sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
723 if (!sec) 731 if (!sec)
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 295f8d4feedf..e6432d85b43d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31static int vmlinux_path__nr_entries; 31int vmlinux_path__nr_entries;
32static char **vmlinux_path; 32char **vmlinux_path;
33 33
34struct symbol_conf symbol_conf = { 34struct symbol_conf symbol_conf = {
35 .exclude_other = true, 35 .exclude_other = true,
@@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
202 curr->end = ~0ULL; 202 curr->end = ~0ULL;
203} 203}
204 204
205static void map_groups__fixup_end(struct map_groups *mg)
206{
207 int i;
208 for (i = 0; i < MAP__NR_TYPES; ++i)
209 __map_groups__fixup_end(mg, i);
210}
211
212struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 205struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
213{ 206{
214 size_t namelen = strlen(name) + 1; 207 size_t namelen = strlen(name) + 1;
@@ -652,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root);
652 return count + moved; 645 return count + moved;
653} 646}
654 647
655static bool symbol__restricted_filename(const char *filename, 648bool symbol__restricted_filename(const char *filename,
656 const char *restricted_filename) 649 const char *restricted_filename)
657{ 650{
658 bool restricted = false; 651 bool restricted = false;
659 652
@@ -775,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
775 else 768 else
776 machine = NULL; 769 machine = NULL;
777 770
778 name = malloc(PATH_MAX);
779 if (!name)
780 return -1;
781
782 dso->adjust_symbols = 0; 771 dso->adjust_symbols = 0;
783 772
784 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 773 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -802,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
802 if (machine) 791 if (machine)
803 root_dir = machine->root_dir; 792 root_dir = machine->root_dir;
804 793
794 name = malloc(PATH_MAX);
795 if (!name)
796 return -1;
797
805 /* Iterate over candidate debug images. 798 /* Iterate over candidate debug images.
806 * Keep track of "interesting" ones (those which have a symtab, dynsym, 799 * Keep track of "interesting" ones (those which have a symtab, dynsym,
807 * and/or opd section) for processing. 800 * and/or opd section) for processing.
@@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
887 return NULL; 880 return NULL;
888} 881}
889 882
890static int map_groups__set_modules_path_dir(struct map_groups *mg,
891 const char *dir_name)
892{
893 struct dirent *dent;
894 DIR *dir = opendir(dir_name);
895 int ret = 0;
896
897 if (!dir) {
898 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
899 return -1;
900 }
901
902 while ((dent = readdir(dir)) != NULL) {
903 char path[PATH_MAX];
904 struct stat st;
905
906 /*sshfs might return bad dent->d_type, so we have to stat*/
907 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
908 if (stat(path, &st))
909 continue;
910
911 if (S_ISDIR(st.st_mode)) {
912 if (!strcmp(dent->d_name, ".") ||
913 !strcmp(dent->d_name, ".."))
914 continue;
915
916 ret = map_groups__set_modules_path_dir(mg, path);
917 if (ret < 0)
918 goto out;
919 } else {
920 char *dot = strrchr(dent->d_name, '.'),
921 dso_name[PATH_MAX];
922 struct map *map;
923 char *long_name;
924
925 if (dot == NULL || strcmp(dot, ".ko"))
926 continue;
927 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
928 (int)(dot - dent->d_name), dent->d_name);
929
930 strxfrchar(dso_name, '-', '_');
931 map = map_groups__find_by_name(mg, MAP__FUNCTION,
932 dso_name);
933 if (map == NULL)
934 continue;
935
936 long_name = strdup(path);
937 if (long_name == NULL) {
938 ret = -1;
939 goto out;
940 }
941 dso__set_long_name(map->dso, long_name);
942 map->dso->lname_alloc = 1;
943 dso__kernel_module_get_build_id(map->dso, "");
944 }
945 }
946
947out:
948 closedir(dir);
949 return ret;
950}
951
952static char *get_kernel_version(const char *root_dir)
953{
954 char version[PATH_MAX];
955 FILE *file;
956 char *name, *tmp;
957 const char *prefix = "Linux version ";
958
959 sprintf(version, "%s/proc/version", root_dir);
960 file = fopen(version, "r");
961 if (!file)
962 return NULL;
963
964 version[0] = '\0';
965 tmp = fgets(version, sizeof(version), file);
966 fclose(file);
967
968 name = strstr(version, prefix);
969 if (!name)
970 return NULL;
971 name += strlen(prefix);
972 tmp = strchr(name, ' ');
973 if (tmp)
974 *tmp = '\0';
975
976 return strdup(name);
977}
978
979static int machine__set_modules_path(struct machine *machine)
980{
981 char *version;
982 char modules_path[PATH_MAX];
983
984 version = get_kernel_version(machine->root_dir);
985 if (!version)
986 return -1;
987
988 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
989 machine->root_dir, version);
990 free(version);
991
992 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
993}
994
995struct map *machine__new_module(struct machine *machine, u64 start,
996 const char *filename)
997{
998 struct map *map;
999 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1000
1001 if (dso == NULL)
1002 return NULL;
1003
1004 map = map__new2(start, dso, MAP__FUNCTION);
1005 if (map == NULL)
1006 return NULL;
1007
1008 if (machine__is_host(machine))
1009 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
1010 else
1011 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
1012 map_groups__insert(&machine->kmaps, map);
1013 return map;
1014}
1015
1016static int machine__create_modules(struct machine *machine)
1017{
1018 char *line = NULL;
1019 size_t n;
1020 FILE *file;
1021 struct map *map;
1022 const char *modules;
1023 char path[PATH_MAX];
1024
1025 if (machine__is_default_guest(machine))
1026 modules = symbol_conf.default_guest_modules;
1027 else {
1028 sprintf(path, "%s/proc/modules", machine->root_dir);
1029 modules = path;
1030 }
1031
1032 if (symbol__restricted_filename(path, "/proc/modules"))
1033 return -1;
1034
1035 file = fopen(modules, "r");
1036 if (file == NULL)
1037 return -1;
1038
1039 while (!feof(file)) {
1040 char name[PATH_MAX];
1041 u64 start;
1042 char *sep;
1043 int line_len;
1044
1045 line_len = getline(&line, &n, file);
1046 if (line_len < 0)
1047 break;
1048
1049 if (!line)
1050 goto out_failure;
1051
1052 line[--line_len] = '\0'; /* \n */
1053
1054 sep = strrchr(line, 'x');
1055 if (sep == NULL)
1056 continue;
1057
1058 hex2u64(sep + 1, &start);
1059
1060 sep = strchr(line, ' ');
1061 if (sep == NULL)
1062 continue;
1063
1064 *sep = '\0';
1065
1066 snprintf(name, sizeof(name), "[%s]", line);
1067 map = machine__new_module(machine, start, name);
1068 if (map == NULL)
1069 goto out_delete_line;
1070 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1071 }
1072
1073 free(line);
1074 fclose(file);
1075
1076 return machine__set_modules_path(machine);
1077
1078out_delete_line:
1079 free(line);
1080out_failure:
1081 return -1;
1082}
1083
1084int dso__load_vmlinux(struct dso *dso, struct map *map, 883int dso__load_vmlinux(struct dso *dso, struct map *map,
1085 const char *vmlinux, symbol_filter_t filter) 884 const char *vmlinux, symbol_filter_t filter)
1086{ 885{
@@ -1124,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1124 filename = dso__build_id_filename(dso, NULL, 0); 923 filename = dso__build_id_filename(dso, NULL, 0);
1125 if (filename != NULL) { 924 if (filename != NULL) {
1126 err = dso__load_vmlinux(dso, map, filename, filter); 925 err = dso__load_vmlinux(dso, map, filename, filter);
1127 if (err > 0) 926 if (err > 0) {
927 dso->lname_alloc = 1;
1128 goto out; 928 goto out;
929 }
1129 free(filename); 930 free(filename);
1130 } 931 }
1131 932
@@ -1133,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1133 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 934 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1134 if (err > 0) { 935 if (err > 0) {
1135 dso__set_long_name(dso, strdup(vmlinux_path[i])); 936 dso__set_long_name(dso, strdup(vmlinux_path[i]));
937 dso->lname_alloc = 1;
1136 break; 938 break;
1137 } 939 }
1138 } 940 }
@@ -1172,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1172 if (err > 0) { 974 if (err > 0) {
1173 dso__set_long_name(dso, 975 dso__set_long_name(dso,
1174 strdup(symbol_conf.vmlinux_name)); 976 strdup(symbol_conf.vmlinux_name));
977 dso->lname_alloc = 1;
1175 goto out_fixup; 978 goto out_fixup;
1176 } 979 }
1177 return err; 980 return err;
@@ -1300,195 +1103,6 @@ out_try_fixup:
1300 return err; 1103 return err;
1301} 1104}
1302 1105
1303size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1304{
1305 struct rb_node *nd;
1306 size_t ret = 0;
1307
1308 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1309 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1310 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1311 ret += __dsos__fprintf(&pos->user_dsos, fp);
1312 }
1313
1314 return ret;
1315}
1316
1317size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1318 bool with_hits)
1319{
1320 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1321 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
1322}
1323
1324size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1325 FILE *fp, bool with_hits)
1326{
1327 struct rb_node *nd;
1328 size_t ret = 0;
1329
1330 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1331 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1332 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1333 }
1334 return ret;
1335}
1336
1337static struct dso *machine__get_kernel(struct machine *machine)
1338{
1339 const char *vmlinux_name = NULL;
1340 struct dso *kernel;
1341
1342 if (machine__is_host(machine)) {
1343 vmlinux_name = symbol_conf.vmlinux_name;
1344 if (!vmlinux_name)
1345 vmlinux_name = "[kernel.kallsyms]";
1346
1347 kernel = dso__kernel_findnew(machine, vmlinux_name,
1348 "[kernel]",
1349 DSO_TYPE_KERNEL);
1350 } else {
1351 char bf[PATH_MAX];
1352
1353 if (machine__is_default_guest(machine))
1354 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
1355 if (!vmlinux_name)
1356 vmlinux_name = machine__mmap_name(machine, bf,
1357 sizeof(bf));
1358
1359 kernel = dso__kernel_findnew(machine, vmlinux_name,
1360 "[guest.kernel]",
1361 DSO_TYPE_GUEST_KERNEL);
1362 }
1363
1364 if (kernel != NULL && (!kernel->has_build_id))
1365 dso__read_running_kernel_build_id(kernel, machine);
1366
1367 return kernel;
1368}
1369
1370struct process_args {
1371 u64 start;
1372};
1373
1374static int symbol__in_kernel(void *arg, const char *name,
1375 char type __maybe_unused, u64 start)
1376{
1377 struct process_args *args = arg;
1378
1379 if (strchr(name, '['))
1380 return 0;
1381
1382 args->start = start;
1383 return 1;
1384}
1385
1386/* Figure out the start address of kernel map from /proc/kallsyms */
1387static u64 machine__get_kernel_start_addr(struct machine *machine)
1388{
1389 const char *filename;
1390 char path[PATH_MAX];
1391 struct process_args args;
1392
1393 if (machine__is_host(machine)) {
1394 filename = "/proc/kallsyms";
1395 } else {
1396 if (machine__is_default_guest(machine))
1397 filename = (char *)symbol_conf.default_guest_kallsyms;
1398 else {
1399 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1400 filename = path;
1401 }
1402 }
1403
1404 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1405 return 0;
1406
1407 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1408 return 0;
1409
1410 return args.start;
1411}
1412
1413int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
1414{
1415 enum map_type type;
1416 u64 start = machine__get_kernel_start_addr(machine);
1417
1418 for (type = 0; type < MAP__NR_TYPES; ++type) {
1419 struct kmap *kmap;
1420
1421 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1422 if (machine->vmlinux_maps[type] == NULL)
1423 return -1;
1424
1425 machine->vmlinux_maps[type]->map_ip =
1426 machine->vmlinux_maps[type]->unmap_ip =
1427 identity__map_ip;
1428 kmap = map__kmap(machine->vmlinux_maps[type]);
1429 kmap->kmaps = &machine->kmaps;
1430 map_groups__insert(&machine->kmaps,
1431 machine->vmlinux_maps[type]);
1432 }
1433
1434 return 0;
1435}
1436
1437void machine__destroy_kernel_maps(struct machine *machine)
1438{
1439 enum map_type type;
1440
1441 for (type = 0; type < MAP__NR_TYPES; ++type) {
1442 struct kmap *kmap;
1443
1444 if (machine->vmlinux_maps[type] == NULL)
1445 continue;
1446
1447 kmap = map__kmap(machine->vmlinux_maps[type]);
1448 map_groups__remove(&machine->kmaps,
1449 machine->vmlinux_maps[type]);
1450 if (kmap->ref_reloc_sym) {
1451 /*
1452 * ref_reloc_sym is shared among all maps, so free just
1453 * on one of them.
1454 */
1455 if (type == MAP__FUNCTION) {
1456 free((char *)kmap->ref_reloc_sym->name);
1457 kmap->ref_reloc_sym->name = NULL;
1458 free(kmap->ref_reloc_sym);
1459 }
1460 kmap->ref_reloc_sym = NULL;
1461 }
1462
1463 map__delete(machine->vmlinux_maps[type]);
1464 machine->vmlinux_maps[type] = NULL;
1465 }
1466}
1467
1468int machine__create_kernel_maps(struct machine *machine)
1469{
1470 struct dso *kernel = machine__get_kernel(machine);
1471
1472 if (kernel == NULL ||
1473 __machine__create_kernel_maps(machine, kernel) < 0)
1474 return -1;
1475
1476 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1477 if (machine__is_host(machine))
1478 pr_debug("Problems creating module maps, "
1479 "continuing anyway...\n");
1480 else
1481 pr_debug("Problems creating module maps for guest %d, "
1482 "continuing anyway...\n", machine->pid);
1483 }
1484
1485 /*
1486 * Now that we have all the maps created, just set the ->end of them:
1487 */
1488 map_groups__fixup_end(&machine->kmaps);
1489 return 0;
1490}
1491
1492static void vmlinux_path__exit(void) 1106static void vmlinux_path__exit(void)
1493{ 1107{
1494 while (--vmlinux_path__nr_entries >= 0) { 1108 while (--vmlinux_path__nr_entries >= 0) {
@@ -1549,25 +1163,6 @@ out_fail:
1549 return -1; 1163 return -1;
1550} 1164}
1551 1165
1552size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
1553{
1554 int i;
1555 size_t printed = 0;
1556 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
1557
1558 if (kdso->has_build_id) {
1559 char filename[PATH_MAX];
1560 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
1561 printed += fprintf(fp, "[0] %s\n", filename);
1562 }
1563
1564 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1565 printed += fprintf(fp, "[%d] %s\n",
1566 i + kdso->has_build_id, vmlinux_path[i]);
1567
1568 return printed;
1569}
1570
1571static int setup_list(struct strlist **list, const char *list_str, 1166static int setup_list(struct strlist **list, const char *list_str,
1572 const char *list_name) 1167 const char *list_name)
1573{ 1168{
@@ -1671,108 +1266,3 @@ void symbol__exit(void)
1671 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 1266 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
1672 symbol_conf.initialized = false; 1267 symbol_conf.initialized = false;
1673} 1268}
1674
1675int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
1676{
1677 struct machine *machine = machines__findnew(machines, pid);
1678
1679 if (machine == NULL)
1680 return -1;
1681
1682 return machine__create_kernel_maps(machine);
1683}
1684
1685int machines__create_guest_kernel_maps(struct rb_root *machines)
1686{
1687 int ret = 0;
1688 struct dirent **namelist = NULL;
1689 int i, items = 0;
1690 char path[PATH_MAX];
1691 pid_t pid;
1692 char *endp;
1693
1694 if (symbol_conf.default_guest_vmlinux_name ||
1695 symbol_conf.default_guest_modules ||
1696 symbol_conf.default_guest_kallsyms) {
1697 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
1698 }
1699
1700 if (symbol_conf.guestmount) {
1701 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
1702 if (items <= 0)
1703 return -ENOENT;
1704 for (i = 0; i < items; i++) {
1705 if (!isdigit(namelist[i]->d_name[0])) {
1706 /* Filter out . and .. */
1707 continue;
1708 }
1709 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
1710 if ((*endp != '\0') ||
1711 (endp == namelist[i]->d_name) ||
1712 (errno == ERANGE)) {
1713 pr_debug("invalid directory (%s). Skipping.\n",
1714 namelist[i]->d_name);
1715 continue;
1716 }
1717 sprintf(path, "%s/%s/proc/kallsyms",
1718 symbol_conf.guestmount,
1719 namelist[i]->d_name);
1720 ret = access(path, R_OK);
1721 if (ret) {
1722 pr_debug("Can't access file %s\n", path);
1723 goto failure;
1724 }
1725 machines__create_kernel_maps(machines, pid);
1726 }
1727failure:
1728 free(namelist);
1729 }
1730
1731 return ret;
1732}
1733
1734void machines__destroy_guest_kernel_maps(struct rb_root *machines)
1735{
1736 struct rb_node *next = rb_first(machines);
1737
1738 while (next) {
1739 struct machine *pos = rb_entry(next, struct machine, rb_node);
1740
1741 next = rb_next(&pos->rb_node);
1742 rb_erase(&pos->rb_node, machines);
1743 machine__delete(pos);
1744 }
1745}
1746
1747int machine__load_kallsyms(struct machine *machine, const char *filename,
1748 enum map_type type, symbol_filter_t filter)
1749{
1750 struct map *map = machine->vmlinux_maps[type];
1751 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
1752
1753 if (ret > 0) {
1754 dso__set_loaded(map->dso, type);
1755 /*
1756 * Since /proc/kallsyms will have multiple sessions for the
1757 * kernel, with modules between them, fixup the end of all
1758 * sections.
1759 */
1760 __map_groups__fixup_end(&machine->kmaps, type);
1761 }
1762
1763 return ret;
1764}
1765
1766int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
1767 symbol_filter_t filter)
1768{
1769 struct map *map = machine->vmlinux_maps[type];
1770 int ret = dso__load_vmlinux_path(map->dso, map, filter);
1771
1772 if (ret > 0) {
1773 dso__set_loaded(map->dso, type);
1774 map__reloc_vmlinux(map);
1775 }
1776
1777 return ret;
1778}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index de68f98b236d..b62ca37c4b77 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
@@ -96,7 +96,8 @@ struct symbol_conf {
96 initialized, 96 initialized,
97 kptr_restrict, 97 kptr_restrict,
98 annotate_asm_raw, 98 annotate_asm_raw,
99 annotate_src; 99 annotate_src,
100 event_group;
100 const char *vmlinux_name, 101 const char *vmlinux_name,
101 *kallsyms_name, 102 *kallsyms_name,
102 *source_prefix, 103 *source_prefix,
@@ -120,6 +121,8 @@ struct symbol_conf {
120}; 121};
121 122
122extern struct symbol_conf symbol_conf; 123extern struct symbol_conf symbol_conf;
124extern int vmlinux_path__nr_entries;
125extern char **vmlinux_path;
123 126
124static inline void *symbol__priv(struct symbol *sym) 127static inline void *symbol__priv(struct symbol *sym)
125{ 128{
@@ -223,6 +226,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
223size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 226size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
224size_t symbol__fprintf(struct symbol *sym, FILE *fp); 227size_t symbol__fprintf(struct symbol *sym, FILE *fp);
225bool symbol_type__is_a(char symbol_type, enum map_type map_type); 228bool symbol_type__is_a(char symbol_type, enum map_type map_type);
229bool symbol__restricted_filename(const char *filename,
230 const char *restricted_filename);
226 231
227int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 232int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
228 struct symsrc *runtime_ss, symbol_filter_t filter, 233 struct symsrc *runtime_ss, symbol_filter_t filter,
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/thread.c b/tools/perf/util/thread.c
index df59623ac763..632e40e5ceca 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self)
54 return self->comm_len; 54 return self->comm_len;
55} 55}
56 56
57static size_t thread__fprintf(struct thread *self, FILE *fp) 57size_t thread__fprintf(struct thread *thread, FILE *fp)
58{ 58{
59 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 59 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
60 map_groups__fprintf(&self->mg, verbose, fp); 60 map_groups__fprintf(&thread->mg, verbose, fp);
61} 61}
62 62
63void thread__insert_map(struct thread *self, struct map *map) 63void thread__insert_map(struct thread *self, struct map *map)
@@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent)
84 return -ENOMEM; 84 return -ENOMEM;
85 return 0; 85 return 0;
86} 86}
87
88size_t machine__fprintf(struct machine *machine, FILE *fp)
89{
90 size_t ret = 0;
91 struct rb_node *nd;
92
93 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
94 struct thread *pos = rb_entry(nd, struct thread, rb_node);
95
96 ret += thread__fprintf(pos, fp);
97 }
98
99 return ret;
100}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f2fa17caa7d5..5ad266403098 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm);
30int thread__comm_len(struct thread *self); 30int thread__comm_len(struct thread *self);
31void thread__insert_map(struct thread *self, struct map *map); 31void thread__insert_map(struct thread *self, struct map *map);
32int thread__fork(struct thread *self, struct thread *parent); 32int thread__fork(struct thread *self, struct thread *parent);
33size_t thread__fprintf(struct thread *thread, FILE *fp);
33 34
34static inline struct map *thread__find_map(struct thread *self, 35static inline struct map *thread__find_map(struct thread *self,
35 enum map_type type, u64 addr) 36 enum map_type type, u64 addr)
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 884dde9b9bc1..54d37a4753c5 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
26 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target;
29 size_t ret = 0; 31 size_t ret = 0;
30 32
31 if (!perf_guest) { 33 if (!perf_guest) {
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
61 struct perf_evsel *first = perf_evlist__first(top->evlist); 63 struct perf_evsel *first = perf_evlist__first(top->evlist);
62 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 64 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
63 (uint64_t)first->attr.sample_period, 65 (uint64_t)first->attr.sample_period,
64 top->freq ? "Hz" : ""); 66 opts->freq ? "Hz" : "");
65 } 67 }
66 68
67 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); 69 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
68 70
69 ret += SNPRINTF(bf + ret, size - ret, "], "); 71 ret += SNPRINTF(bf + ret, size - ret, "], ");
70 72
71 if (top->target.pid) 73 if (target->pid)
72 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 74 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
73 top->target.pid); 75 target->pid);
74 else if (top->target.tid) 76 else if (target->tid)
75 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 77 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
76 top->target.tid); 78 target->tid);
77 else if (top->target.uid_str != NULL) 79 else if (target->uid_str != NULL)
78 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 80 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
79 top->target.uid_str); 81 target->uid_str);
80 else 82 else
81 ret += SNPRINTF(bf + ret, size - ret, " (all"); 83 ret += SNPRINTF(bf + ret, size - ret, " (all");
82 84
83 if (top->target.cpu_list) 85 if (target->cpu_list)
84 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 86 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
85 top->evlist->cpus->nr > 1 ? "s" : "", 87 top->evlist->cpus->nr > 1 ? "s" : "",
86 top->target.cpu_list); 88 target->cpu_list);
87 else { 89 else {
88 if (top->target.tid) 90 if (target->tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 91 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 92 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 93 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 86ff1b15059b..7ebf357dc9e1 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_target target; 17 struct perf_record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
@@ -24,24 +24,16 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int freq;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
30 bool sort_has_symbols; 29 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
33 bool vmlinux_warned; 31 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_missing;
37 bool exclude_guest_missing;
38 bool dump_symtab; 32 bool dump_symtab;
39 struct hist_entry *sym_filter_entry; 33 struct hist_entry *sym_filter_entry;
40 struct perf_evsel *sym_evsel; 34 struct perf_evsel *sym_evsel;
41 struct perf_session *session; 35 struct perf_session *session;
42 struct winsize winsize; 36 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio; 37 int realtime_prio;
46 int sym_pcnt_filter; 38 int sym_pcnt_filter;
47 const char *sym_filter; 39 const char *sym_filter;
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