Browse Source

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

. Allow skipping problematic entries in 'perf test'.

. Fix some namespace problems in the event parsing routines.

. Add 'perf test' entry to make sure the python binding doesn't have
  linking problems.

. Adjust 'perf test' attr tests verbosity levels.

. Make tools/perf build with GNU make v3.80, fix from Al Cooper.

. Do missing feature fallbacks in just one place, removing duplicated
  code in multiple tools.

. Fix some memory leaks, from David Ahern.

. Fix segfault when drawing out-of-bounds jumps, from Frederik Deweerdt.

. Allow of casting an array of char to string in 'perf probe', from
  Hyeoncheol Lee.

. Add support for wildcard in tracepoint system name, from Jiri Olsa.

. Update FSF postal address to be URL's, from Jon Stanley.

. Add anonymous huge page recognition, from Joshua Zhu.

. Remove some needless feature test checks, from Namhyung Kim.

. Multiple improvements to the sort routines, from Namhyung Kim.

. Fix warning on '>=' operator in libtraceevent, from Namhyung Kim.

. Use ARRAY_SIZE instead of reinventing it in 'perf script' and 'perf kmem',
  from Sasha Levin.

. Remove some redundant checks, from Sasha Levin.

. Test correct variable after allocation in libtraceevent, fix from Sasha Levin.

. Mark branch_info maps as referenced, fix from Stephane Eranian.

. Fix PMU format parsing test failure, from Sukadev Bhattiprolu.

. Fix possible (unlikely) buffer overflow, from Thomas Jarosch.

. Multiple 'perf script' fixes, from Tom Zanussi.

. Add missing field in PERF_RECORD_SAMPLE documentation, from Vince Weaver.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Ingo Molnar 12 years ago
parent
commit
a2d28d0c19
81 changed files with 1816 additions and 1202 deletions
  1. 2 1
      include/uapi/linux/perf_event.h
  2. 1 2
      kernel/events/uprobes.c
  3. 6 4
      tools/lib/traceevent/event-parse.c
  4. 1 2
      tools/lib/traceevent/event-parse.h
  5. 1 2
      tools/lib/traceevent/event-utils.h
  6. 1 2
      tools/lib/traceevent/parse-filter.c
  7. 19 0
      tools/lib/traceevent/parse-utils.c
  8. 1 2
      tools/lib/traceevent/trace-seq.c
  9. 35 3
      tools/perf/Documentation/perf-report.txt
  10. 0 2
      tools/perf/Documentation/perf-script-python.txt
  11. 4 0
      tools/perf/Documentation/perf-test.txt
  12. 11 6
      tools/perf/Makefile
  13. 2 0
      tools/perf/builtin-bench.c
  14. 36 56
      tools/perf/builtin-diff.c
  15. 2 8
      tools/perf/builtin-kmem.c
  16. 1 2
      tools/perf/builtin-kvm.c
  17. 12 115
      tools/perf/builtin-record.c
  18. 3 3
      tools/perf/builtin-report.c
  19. 3 3
      tools/perf/builtin-sched.c
  20. 3 14
      tools/perf/builtin-script.c
  21. 8 38
      tools/perf/builtin-stat.c
  22. 13 93
      tools/perf/builtin-top.c
  23. 3 3
      tools/perf/config/utilities.mak
  24. 21 11
      tools/perf/perf.c
  25. 0 6
      tools/perf/perf.h
  26. 0 2
      tools/perf/scripts/perl/bin/workqueue-stats-record
  27. 0 3
      tools/perf/scripts/perl/bin/workqueue-stats-report
  28. 0 129
      tools/perf/scripts/perl/workqueue-stats.pl
  29. 1 3
      tools/perf/tests/attr.c
  30. 18 9
      tools/perf/tests/attr.py
  31. 1 1
      tools/perf/tests/attr/test-record-group1
  32. 35 5
      tools/perf/tests/builtin-test.c
  33. 2 2
      tools/perf/tests/evsel-roundtrip-name.c
  34. 499 0
      tools/perf/tests/hists_link.c
  35. 80 18
      tools/perf/tests/parse-events.c
  36. 3 8
      tools/perf/tests/pmu.c
  37. 23 0
      tools/perf/tests/python-use.c
  38. 8 0
      tools/perf/tests/tests.h
  39. 2 1
      tools/perf/tests/vmlinux-kallsyms.c
  40. 2 2
      tools/perf/ui/browser.c
  41. 17 16
      tools/perf/ui/browsers/annotate.c
  42. 5 222
      tools/perf/ui/gtk/browser.c
  43. 8 1
      tools/perf/ui/gtk/gtk.h
  44. 226 0
      tools/perf/ui/gtk/hists.c
  45. 3 3
      tools/perf/ui/stdio/hist.c
  46. 0 11
      tools/perf/ui/util.c
  47. 2 2
      tools/perf/util/PERF-VERSION-GEN
  48. 0 1
      tools/perf/util/debug.h
  49. 105 3
      tools/perf/util/evsel.c
  50. 6 0
      tools/perf/util/evsel.h
  51. 42 33
      tools/perf/util/header.c
  52. 63 16
      tools/perf/util/hist.c
  53. 3 1
      tools/perf/util/hist.h
  54. 1 0
      tools/perf/util/include/linux/bitops.h
  55. 33 3
      tools/perf/util/intlist.c
  56. 1 1
      tools/perf/util/intlist.h
  57. 42 22
      tools/perf/util/machine.c
  58. 20 12
      tools/perf/util/machine.h
  59. 2 1
      tools/perf/util/map.c
  60. 64 23
      tools/perf/util/parse-events.c
  61. 10 11
      tools/perf/util/parse-events.h
  62. 32 32
      tools/perf/util/parse-events.y
  63. 29 17
      tools/perf/util/pmu.c
  64. 1 14
      tools/perf/util/pmu.h
  65. 5 5
      tools/perf/util/probe-finder.c
  66. 9 0
      tools/perf/util/python.c
  67. 1 0
      tools/perf/util/scripting-engines/trace-event-perl.c
  68. 1 0
      tools/perf/util/scripting-engines/trace-event-python.c
  69. 34 41
      tools/perf/util/session.c
  70. 3 27
      tools/perf/util/session.h
  71. 122 108
      tools/perf/util/sort.c
  72. 6 2
      tools/perf/util/sort.h
  73. 18 0
      tools/perf/util/string.c
  74. 0 3
      tools/perf/util/symbol-elf.c
  75. 0 1
      tools/perf/util/symbol-minimal.c
  76. 9 5
      tools/perf/util/symbol.c
  77. 1 1
      tools/perf/util/symbol.h
  78. 1 1
      tools/perf/util/sysfs.c
  79. 0 2
      tools/perf/util/top.h
  80. 24 0
      tools/perf/util/util.c
  81. 4 0
      tools/perf/util/util.h

+ 2 - 1
include/uapi/linux/perf_event.h

@@ -579,7 +579,8 @@ enum perf_event_type {
 	 *	{ u32			size;
 	 *	{ u32			size;
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
 	 *
 	 *
-	 *	{ u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+	 *	{ u64                   nr;
+	 *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
 	 *
 	 *
 	 * 	{ u64			abi; # enum perf_sample_regs_abi
 	 * 	{ u64			abi; # enum perf_sample_regs_abi
 	 * 	  u64			regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
 	 * 	  u64			regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER

+ 1 - 2
kernel/events/uprobes.c

@@ -901,8 +901,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
 	}
 	}
 
 
 	mutex_unlock(uprobes_hash(inode));
 	mutex_unlock(uprobes_hash(inode));
-	if (uprobe)
-		put_uprobe(uprobe);
+	put_uprobe(uprobe);
 }
 }
 
 
 static struct rb_node *
 static struct rb_node *

+ 6 - 4
tools/lib/traceevent/event-parse.c

@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  * GNU Lesser General Public License for more details.
  *
  *
  * You should have received a copy of the GNU Lesser General Public
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  *
@@ -1463,7 +1462,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
 			if (read_expect_type(EVENT_ITEM, &token))
 			if (read_expect_type(EVENT_ITEM, &token))
 				goto fail;
 				goto fail;
 
 
-			/* add signed type */
+			if (strtoul(token, NULL, 0))
+				field->flags |= FIELD_IS_SIGNED;
 
 
 			free_token(token);
 			free_token(token);
 			if (read_expected(EVENT_OP, ";") < 0)
 			if (read_expected(EVENT_OP, ";") < 0)
@@ -1785,6 +1785,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
 		   strcmp(token, "/") == 0 ||
 		   strcmp(token, "/") == 0 ||
 		   strcmp(token, "<") == 0 ||
 		   strcmp(token, "<") == 0 ||
 		   strcmp(token, ">") == 0 ||
 		   strcmp(token, ">") == 0 ||
+		   strcmp(token, "<=") == 0 ||
+		   strcmp(token, ">=") == 0 ||
 		   strcmp(token, "==") == 0 ||
 		   strcmp(token, "==") == 0 ||
 		   strcmp(token, "!=") == 0) {
 		   strcmp(token, "!=") == 0) {
 
 
@@ -2481,7 +2483,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char **
 
 
 	free_token(token);
 	free_token(token);
 	arg = alloc_arg();
 	arg = alloc_arg();
-	if (!field) {
+	if (!arg) {
 		do_warning("%s: not enough memory!", __func__);
 		do_warning("%s: not enough memory!", __func__);
 		*tok = NULL;
 		*tok = NULL;
 		return EVENT_ERROR;
 		return EVENT_ERROR;

+ 1 - 2
tools/lib/traceevent/event-parse.h

@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  * GNU Lesser General Public License for more details.
  *
  *
  * You should have received a copy of the GNU Lesser General Public
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
  */

+ 1 - 2
tools/lib/traceevent/event-utils.h

@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  * GNU Lesser General Public License for more details.
  *
  *
  * You should have received a copy of the GNU Lesser General Public
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
  */

+ 1 - 2
tools/lib/traceevent/parse-filter.c

@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  * GNU Lesser General Public License for more details.
  *
  *
  * You should have received a copy of the GNU Lesser General Public
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
  */

+ 19 - 0
tools/lib/traceevent/parse-utils.c

@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>

+ 1 - 2
tools/lib/traceevent/trace-seq.c

@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  * GNU Lesser General Public License for more details.
  *
  *
  * You should have received a copy of the GNU Lesser General Public
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
  */

+ 35 - 3
tools/perf/Documentation/perf-report.txt

@@ -57,11 +57,44 @@ OPTIONS
 
 
 -s::
 -s::
 --sort=::
 --sort=::
-	Sort by key(s): pid, comm, dso, symbol, parent, srcline.
+	Sort histogram entries by given key(s) - multiple keys can be specified
+	in CSV format.  Following sort keys are available:
+	pid, comm, dso, symbol, parent, cpu, srcline.
+
+	Each key has following meaning:
+
+	- comm: command (name) of the task which can be read via /proc/<pid>/comm
+	- pid: command and tid of the task
+	- dso: name of library or module executed at the time of sample
+	- symbol: name of function executed at the time of sample
+	- parent: name of function matched to the parent regex filter. Unmatched
+	entries are displayed as "[other]".
+	- cpu: cpu number the task ran at the time of sample
+	- srcline: filename and line number executed at the time of sample.  The
+	DWARF debuggin info must be provided.
+
+	By default, comm, dso and symbol keys are used.
+	(i.e. --sort comm,dso,symbol)
+
+	If --branch-stack option is used, following sort keys are also
+	available:
+	dso_from, dso_to, symbol_from, symbol_to, mispredict.
+
+	- dso_from: name of library or module branched from
+	- dso_to: name of library or module branched to
+	- symbol_from: name of function branched from
+	- symbol_to: name of function branched to
+	- mispredict: "N" for predicted branch, "Y" for mispredicted branch
+
+	And default sort keys are changed to comm, dso_from, symbol_from, dso_to
+	and symbol_to, see '--branch-stack'.
 
 
 -p::
 -p::
 --parent=<regex>::
 --parent=<regex>::
-        regex filter to identify parent, see: '--sort parent'
+        A regex filter to identify parent. The parent is a caller of this
+	function and searched through the callchain, thus it requires callchain
+	information recorded. The pattern is in the exteneded regex format and
+	defaults to "\^sys_|^do_page_fault", see '--sort parent'.
 
 
 -x::
 -x::
 --exclude-other::
 --exclude-other::
@@ -74,7 +107,6 @@ OPTIONS
 
 
 -t::
 -t::
 --field-separator=::
 --field-separator=::
-
 	Use a special separator character and don't pad with spaces, replacing
 	Use a special separator character and don't pad with spaces, replacing
 	all occurrences of this separator in symbol names (and other output)
 	all occurrences of this separator in symbol names (and other output)
 	with a '.' character, that thus it's the only non valid separator.
 	with a '.' character, that thus it's the only non valid separator.

+ 0 - 2
tools/perf/Documentation/perf-script-python.txt

@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.:
 ----
 ----
 root@tropicana:~# perf script -l
 root@tropicana:~# perf script -l
 List of available trace scripts:
 List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
   wakeup-latency                       system-wide min/max/avg wakeup latency
   wakeup-latency                       system-wide min/max/avg wakeup latency
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-pid                            system-wide r/w activity
   rw-by-pid                            system-wide r/w activity
@@ -402,7 +401,6 @@ should show a new entry for your script:
 ----
 ----
 root@tropicana:~# perf script -l
 root@tropicana:~# perf script -l
 List of available trace scripts:
 List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
   wakeup-latency                       system-wide min/max/avg wakeup latency
   wakeup-latency                       system-wide min/max/avg wakeup latency
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-pid                            system-wide r/w activity
   rw-by-pid                            system-wide r/w activity

+ 4 - 0
tools/perf/Documentation/perf-test.txt

@@ -23,6 +23,10 @@ from 'perf test list'.
 
 
 OPTIONS
 OPTIONS
 -------
 -------
+-s::
+--skip::
+	Tests to skip (comma separater numeric list).
+
 -v::
 -v::
 --verbose::
 --verbose::
 	Be more verbose.
 	Be more verbose.

+ 11 - 6
tools/perf/Makefile

@@ -50,7 +50,6 @@ include config/utilities.mak
 
 
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
 	@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
 	@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
--include $(OUTPUT)PERF-VERSION-FILE
 
 
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 
 
@@ -487,6 +486,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
 LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
 LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
 LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
 LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
 LIB_OBJS += $(OUTPUT)tests/pmu.o
 LIB_OBJS += $(OUTPUT)tests/pmu.o
+LIB_OBJS += $(OUTPUT)tests/hists_link.o
+LIB_OBJS += $(OUTPUT)tests/python-use.o
 
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -532,9 +533,6 @@ ifneq ($(MAKECMDGOALS),tags)
 # because maintaining the nesting to match is a pain.  If
 # because maintaining the nesting to match is a pain.  If
 # we had "elif" things would have been much nicer...
 # we had "elif" things would have been much nicer...
 
 
--include config.mak.autogen
--include config.mak
-
 ifdef NO_LIBELF
 ifdef NO_LIBELF
 	NO_DWARF := 1
 	NO_DWARF := 1
 	NO_DEMANGLE := 1
 	NO_DEMANGLE := 1
@@ -686,6 +684,7 @@ ifndef NO_GTK2
 		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
 		BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
 		EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
 		EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
 		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
+		LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/util.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/util.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
 		LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
@@ -887,7 +886,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
 	$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
 	$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
 
 
 $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
+	$(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
 		'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
 		'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
 		$(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 		$(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
 
@@ -951,7 +950,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
 
 
 $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
 	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
-		'-DBINDIR="$(bindir_SQ)"' \
+		'-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
+		$<
+
+$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
+	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+		-DPYTHONPATH='"$(OUTPUT)python"' \
+		-DPYTHON='"$(PYTHON_WORD)"' \
 		$<
 		$<
 
 
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS

+ 2 - 0
tools/perf/builtin-bench.c

@@ -159,6 +159,7 @@ static void all_suite(struct bench_subsys *subsys)	  /* FROM HERE */
 		printf("# Running %s/%s benchmark...\n",
 		printf("# Running %s/%s benchmark...\n",
 		       subsys->name,
 		       subsys->name,
 		       suites[i].name);
 		       suites[i].name);
+		fflush(stdout);
 
 
 		argv[1] = suites[i].name;
 		argv[1] = suites[i].name;
 		suites[i].fn(1, argv, NULL);
 		suites[i].fn(1, argv, NULL);
@@ -225,6 +226,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
 				printf("# Running %s/%s benchmark...\n",
 				printf("# Running %s/%s benchmark...\n",
 				       subsystems[i].name,
 				       subsystems[i].name,
 				       subsystems[i].suites[j].name);
 				       subsystems[i].suites[j].name);
+			fflush(stdout);
 			status = subsystems[i].suites[j].fn(argc - 1,
 			status = subsystems[i].suites[j].fn(argc - 1,
 							    argv + 1, prefix);
 							    argv + 1, prefix);
 			goto end;
 			goto end;

+ 36 - 56
tools/perf/builtin-diff.c

@@ -275,43 +275,6 @@ static struct perf_tool tool = {
 	.ordering_requires_timestamps = true,
 	.ordering_requires_timestamps = true,
 };
 };
 
 
-static void insert_hist_entry_by_name(struct rb_root *root,
-				      struct hist_entry *he)
-{
-	struct rb_node **p = &root->rb_node;
-	struct rb_node *parent = NULL;
-	struct hist_entry *iter;
-
-	while (*p != NULL) {
-		parent = *p;
-		iter = rb_entry(parent, struct hist_entry, rb_node);
-		if (hist_entry__cmp(he, iter) < 0)
-			p = &(*p)->rb_left;
-		else
-			p = &(*p)->rb_right;
-	}
-
-	rb_link_node(&he->rb_node, parent, p);
-	rb_insert_color(&he->rb_node, root);
-}
-
-static void hists__name_resort(struct hists *self)
-{
-	struct rb_root tmp = RB_ROOT;
-	struct rb_node *next = rb_first(&self->entries);
-
-	while (next != NULL) {
-		struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
-
-		next = rb_next(&n->rb_node);
-
-		rb_erase(&n->rb_node, &self->entries);
-		insert_hist_entry_by_name(&tmp, n);
-	}
-
-	self->entries = tmp;
-}
-
 static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
 static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
 				      struct perf_evlist *evlist)
 				      struct perf_evlist *evlist)
 {
 {
@@ -324,30 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
 	return NULL;
 	return NULL;
 }
 }
 
 
-static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
+static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
 {
 {
 	struct perf_evsel *evsel;
 	struct perf_evsel *evsel;
 
 
 	list_for_each_entry(evsel, &evlist->entries, node) {
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		struct hists *hists = &evsel->hists;
 		struct hists *hists = &evsel->hists;
 
 
-		hists__output_resort(hists);
-
-		if (name)
-			hists__name_resort(hists);
+		hists__collapse_resort(hists);
 	}
 	}
 }
 }
 
 
 static void hists__baseline_only(struct hists *hists)
 static void hists__baseline_only(struct hists *hists)
 {
 {
-	struct rb_node *next = rb_first(&hists->entries);
+	struct rb_root *root;
+	struct rb_node *next;
+
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
 
 
+	next = rb_first(root);
 	while (next != NULL) {
 	while (next != NULL) {
-		struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+		struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
 
 
-		next = rb_next(&he->rb_node);
+		next = rb_next(&he->rb_node_in);
 		if (!hist_entry__next_pair(he)) {
 		if (!hist_entry__next_pair(he)) {
-			rb_erase(&he->rb_node, &hists->entries);
+			rb_erase(&he->rb_node_in, root);
 			hist_entry__free(he);
 			hist_entry__free(he);
 		}
 		}
 	}
 	}
@@ -447,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
 
 
 static void hists__compute_resort(struct hists *hists)
 static void hists__compute_resort(struct hists *hists)
 {
 {
-	struct rb_root tmp = RB_ROOT;
-	struct rb_node *next = rb_first(&hists->entries);
+	struct rb_root *root;
+	struct rb_node *next;
+
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
+
+	hists->entries = RB_ROOT;
+	next = rb_first(root);
+
+	hists->nr_entries = 0;
+	hists->stats.total_period = 0;
+	hists__reset_col_len(hists);
 
 
 	while (next != NULL) {
 	while (next != NULL) {
-		struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+		struct hist_entry *he;
 
 
-		next = rb_next(&he->rb_node);
+		he = rb_entry(next, struct hist_entry, rb_node_in);
+		next = rb_next(&he->rb_node_in);
 
 
-		rb_erase(&he->rb_node, &hists->entries);
-		insert_hist_entry_by_compute(&tmp, he, compute);
+		insert_hist_entry_by_compute(&hists->entries, he, compute);
+		hists__inc_nr_entries(hists, he);
 	}
 	}
-
-	hists->entries = tmp;
 }
 }
 
 
 static void hists__process(struct hists *old, struct hists *new)
 static void hists__process(struct hists *old, struct hists *new)
@@ -474,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new)
 	if (sort_compute) {
 	if (sort_compute) {
 		hists__precompute(new);
 		hists__precompute(new);
 		hists__compute_resort(new);
 		hists__compute_resort(new);
+	} else {
+		hists__output_resort(new);
 	}
 	}
 
 
 	hists__fprintf(new, true, 0, 0, stdout);
 	hists__fprintf(new, true, 0, 0, stdout);
@@ -505,8 +485,8 @@ static int __cmd_diff(void)
 	evlist_old = older->evlist;
 	evlist_old = older->evlist;
 	evlist_new = newer->evlist;
 	evlist_new = newer->evlist;
 
 
-	perf_evlist__resort_hists(evlist_old, true);
-	perf_evlist__resort_hists(evlist_new, false);
+	perf_evlist__collapse_resort(evlist_old);
+	perf_evlist__collapse_resort(evlist_new);
 
 
 	list_for_each_entry(evsel, &evlist_new->entries, node) {
 	list_for_each_entry(evsel, &evlist_new->entries, node) {
 		struct perf_evsel *evsel_old;
 		struct perf_evsel *evsel_old;

+ 2 - 8
tools/perf/builtin-kmem.c

@@ -340,7 +340,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 			   int n_lines, int is_caller)
 			   int n_lines, int is_caller)
 {
 {
 	struct rb_node *next;
 	struct rb_node *next;
-	struct machine *machine;
+	struct machine *machine = &session->machines.host;
 
 
 	printf("%.102s\n", graph_dotted_line);
 	printf("%.102s\n", graph_dotted_line);
 	printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
 	printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +349,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
 
 	next = rb_first(root);
 	next = rb_first(root);
 
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("__print_result: couldn't find kernel information\n");
-		return;
-	}
 	while (next && n_lines--) {
 	while (next && n_lines--) {
 		struct alloc_stat *data = rb_entry(next, struct alloc_stat,
 		struct alloc_stat *data = rb_entry(next, struct alloc_stat,
 						   node);
 						   node);
@@ -614,8 +609,7 @@ static struct sort_dimension *avail_sorts[] = {
 	&pingpong_sort_dimension,
 	&pingpong_sort_dimension,
 };
 };
 
 
-#define NUM_AVAIL_SORTS	\
-	(int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
+#define NUM_AVAIL_SORTS	((int)ARRAY_SIZE(avail_sorts))
 
 
 static int sort_dimension__add(const char *tok, struct list_head *list)
 static int sort_dimension__add(const char *tok, struct list_head *list)
 {
 {

+ 1 - 2
tools/perf/builtin-kvm.c

@@ -973,8 +973,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
 
 
 int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
 int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 {
-	const char *file_name;
-
+	const char *file_name = NULL;
 	const struct option kvm_options[] = {
 	const struct option kvm_options[] = {
 		OPT_STRING('i', "input", &file_name, "file",
 		OPT_STRING('i', "input", &file_name, "file",
 			   "Input file name"),
 			   "Input file name"),

+ 12 - 115
tools/perf/builtin-record.c

@@ -224,6 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
 
 
 static int perf_record__open(struct perf_record *rec)
 static int perf_record__open(struct perf_record *rec)
 {
 {
+	char msg[512];
 	struct perf_evsel *pos;
 	struct perf_evsel *pos;
 	struct perf_evlist *evlist = rec->evlist;
 	struct perf_evlist *evlist = rec->evlist;
 	struct perf_session *session = rec->session;
 	struct perf_session *session = rec->session;
@@ -233,114 +234,18 @@ static int perf_record__open(struct perf_record *rec)
 	perf_evlist__config(evlist, opts);
 	perf_evlist__config(evlist, opts);
 
 
 	list_for_each_entry(pos, &evlist->entries, node) {
 	list_for_each_entry(pos, &evlist->entries, node) {
-		struct perf_event_attr *attr = &pos->attr;
-		/*
-		 * Check if parse_single_tracepoint_event has already asked for
-		 * PERF_SAMPLE_TIME.
-		 *
-		 * XXX this is kludgy but short term fix for problems introduced by
-		 * eac23d1c that broke 'perf script' by having different sample_types
-		 * when using multiple tracepoint events when we use a perf binary
-		 * that tries to use sample_id_all on an older kernel.
-		 *
-		 * We need to move counter creation to perf_session, support
-		 * different sample_types, etc.
-		 */
-		bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
-
-fallback_missing_features:
-		if (opts->exclude_guest_missing)
-			attr->exclude_guest = attr->exclude_host = 0;
-retry_sample_id:
-		attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 try_again:
 try_again:
 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
 		if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
-			int err = errno;
-
-			if (err == EPERM || err == EACCES) {
-				ui__error_paranoid();
-				rc = -err;
-				goto out;
-			} else if (err ==  ENODEV && opts->target.cpu_list) {
-				pr_err("No such device - did you specify"
-				       " an out-of-range profile CPU?\n");
-				rc = -err;
-				goto out;
-			} else if (err == EINVAL) {
-				if (!opts->exclude_guest_missing &&
-				    (attr->exclude_guest || attr->exclude_host)) {
-					pr_debug("Old kernel, cannot exclude "
-						 "guest or host samples.\n");
-					opts->exclude_guest_missing = true;
-					goto fallback_missing_features;
-				} else if (!opts->sample_id_all_missing) {
-					/*
-					 * Old kernel, no attr->sample_id_type_all field
-					 */
-					opts->sample_id_all_missing = true;
-					if (!opts->sample_time && !opts->raw_samples && !time_needed)
-						perf_evsel__reset_sample_bit(pos, TIME);
-
-					goto retry_sample_id;
-				}
-			}
-
-			/*
-			 * If it's cycles then fall back to hrtimer
-			 * based cpu-clock-tick sw counter, which
-			 * is always available even if no PMU support.
-			 *
-			 * PPC returns ENXIO until 2.6.37 (behavior changed
-			 * with commit b0a873e).
-			 */
-			if ((err == ENOENT || err == ENXIO)
-					&& attr->type == PERF_TYPE_HARDWARE
-					&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
-
+			if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
 				if (verbose)
 				if (verbose)
-					ui__warning("The cycles event is not supported, "
-						    "trying to fall back to cpu-clock-ticks\n");
-				attr->type = PERF_TYPE_SOFTWARE;
-				attr->config = PERF_COUNT_SW_CPU_CLOCK;
-				if (pos->name) {
-					free(pos->name);
-					pos->name = NULL;
-				}
+					ui__warning("%s\n", msg);
 				goto try_again;
 				goto try_again;
 			}
 			}
 
 
-			if (err == ENOENT) {
-				ui__error("The %s event is not supported.\n",
-					  perf_evsel__name(pos));
-				rc = -err;
-				goto out;
-			} else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
-				ui__error("\'precise\' request may not be supported. "
-					  "Try removing 'p' modifier\n");
-				rc = -err;
-				goto out;
-			}
-
-			printf("\n");
-			error("sys_perf_event_open() syscall returned with %d "
-			      "(%s) for event %s. /bin/dmesg may provide "
-			      "additional information.\n",
-			      err, strerror(err), perf_evsel__name(pos));
-
-#if defined(__i386__) || defined(__x86_64__)
-			if (attr->type == PERF_TYPE_HARDWARE &&
-			    err == EOPNOTSUPP) {
-				pr_err("No hardware sampling interrupt available."
-				       " No APIC? If so then you can boot the kernel"
-				       " with the \"lapic\" boot parameter to"
-				       " force-enable it.\n");
-				rc = -err;
-				goto out;
-			}
-#endif
-
-			pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
-			rc = -err;
+			rc = -errno;
+			perf_evsel__open_strerror(pos, &opts->target,
+						  errno, msg, sizeof(msg));
+			ui__error("%s\n", msg);
 			goto out;
 			goto out;
 		}
 		}
 	}
 	}
@@ -423,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
 {
 	int err;
 	int err;
 	struct perf_tool *tool = data;
 	struct perf_tool *tool = data;
-
-	if (machine__is_host(machine))
-		return;
-
 	/*
 	/*
 	 *As for guest kernel when processing subcommand record&report,
 	 *As for guest kernel when processing subcommand record&report,
 	 *we arrange module mmap prior to guest kernel mmap and trigger
 	 *we arrange module mmap prior to guest kernel mmap and trigger
@@ -611,12 +512,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 
 
 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
 	rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
 
 
-	machine = perf_session__find_host_machine(session);
-	if (!machine) {
-		pr_err("Couldn't find native kernel information.\n");
-		err = -1;
-		goto out_delete_session;
-	}
+	machine = &session->machines.host;
 
 
 	if (opts->pipe_output) {
 	if (opts->pipe_output) {
 		err = perf_event__synthesize_attrs(tool, session,
 		err = perf_event__synthesize_attrs(tool, session,
@@ -669,9 +565,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
 		       "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
 		       "Check /proc/modules permission or run as root.\n");
 		       "Check /proc/modules permission or run as root.\n");
 
 
-	if (perf_guest)
-		perf_session__process_machines(session, tool,
-					       perf_event__synthesize_guest_os);
+	if (perf_guest) {
+		machines__process_guests(&session->machines,
+					 perf_event__synthesize_guest_os, tool);
+	}
 
 
 	if (!opts->target.system_wide)
 	if (!opts->target.system_wide)
 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
 		err = perf_event__synthesize_thread_map(tool, evsel_list->threads,

+ 3 - 3
tools/perf/builtin-report.c

@@ -372,7 +372,7 @@ static int __cmd_report(struct perf_report *rep)
 	if (ret)
 	if (ret)
 		goto out_delete;
 		goto out_delete;
 
 
-	kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
+	kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
 	kernel_kmap = map__kmap(kernel_map);
 	kernel_kmap = map__kmap(kernel_map);
 	if (kernel_map == NULL ||
 	if (kernel_map == NULL ||
 	    (kernel_map->dso->hit &&
 	    (kernel_map->dso->hit &&
@@ -595,8 +595,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
 	OPT_BOOLEAN(0, "stdio", &report.use_stdio,
 		    "Use the stdio interface"),
 		    "Use the stdio interface"),
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
-		   "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
-		   " dso_from, symbol_to, symbol_from, mispredict"),
+		   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
+		   " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
 	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
 	OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
 		    "Show sample percentage for different cpu modes"),
 		    "Show sample percentage for different cpu modes"),
 	OPT_STRING('p', "parent", &parent_pattern, "regex",
 	OPT_STRING('p', "parent", &parent_pattern, "regex",

+ 3 - 3
tools/perf/builtin-sched.c

@@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
 			goto out_delete;
 			goto out_delete;
 		}
 		}
 
 
-		sched->nr_events      = session->hists.stats.nr_events[0];
-		sched->nr_lost_events = session->hists.stats.total_lost;
-		sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
+		sched->nr_events      = session->stats.nr_events[0];
+		sched->nr_lost_events = session->stats.total_lost;
+		sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
 	}
 	}
 
 
 	if (destroy)
 	if (destroy)

+ 3 - 14
tools/perf/builtin-script.c

@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
 			    const char *arg, int unset __maybe_unused)
 			    const char *arg, int unset __maybe_unused)
 {
 {
 	char *tok;
 	char *tok;
-	int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
+	int i, imax = ARRAY_SIZE(all_output_options);
 	int j;
 	int j;
 	int rc = 0;
 	int rc = 0;
 	char *str = strdup(arg);
 	char *str = strdup(arg);
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix)
 	return NULL;
 	return NULL;
 }
 }
 
 
-static char *ltrim(char *str)
-{
-	int len = strlen(str);
-
-	while (len && isspace(*str)) {
-		len--;
-		str++;
-	}
-
-	return str;
-}
-
 static int read_script_info(struct script_desc *desc, const char *filename)
 static int read_script_info(struct script_desc *desc, const char *filename)
 {
 {
 	char line[BUFSIZ], *p;
 	char line[BUFSIZ], *p;
@@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 			return -1;
 			return -1;
 	}
 	}
 
 
-	perf_session__fprintf_info(session, stdout, show_full_info);
+	if (!script_name && !generate_script_lang)
+		perf_session__fprintf_info(session, stdout, show_full_info);
 
 
 	if (!no_callchain)
 	if (!no_callchain)
 		symbol_conf.use_callchain = true;
 		symbol_conf.use_callchain = true;

+ 8 - 38
tools/perf/builtin-stat.c

@@ -132,8 +132,6 @@ static struct stats walltime_nsecs_stats;
 static int create_perf_stat_counter(struct perf_evsel *evsel)
 static int create_perf_stat_counter(struct perf_evsel *evsel)
 {
 {
 	struct perf_event_attr *attr = &evsel->attr;
 	struct perf_event_attr *attr = &evsel->attr;
-	bool exclude_guest_missing = false;
-	int ret;
 
 
 	if (scale)
 	if (scale)
 		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
 		attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,16 +139,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
 
 
 	attr->inherit = !no_inherit;
 	attr->inherit = !no_inherit;
 
 
-retry:
-	if (exclude_guest_missing)
-		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
-
-	if (perf_target__has_cpu(&target)) {
-		ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
-		if (ret)
-			goto check_ret;
-		return 0;
-	}
+	if (perf_target__has_cpu(&target))
+		return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
 
 
 	if (!perf_target__has_task(&target) &&
 	if (!perf_target__has_task(&target) &&
 	    perf_evsel__is_group_leader(evsel)) {
 	    perf_evsel__is_group_leader(evsel)) {
@@ -158,21 +148,7 @@ retry:
 		attr->enable_on_exec = 1;
 		attr->enable_on_exec = 1;
 	}
 	}
 
 
-	ret = perf_evsel__open_per_thread(evsel, evsel_list->threads);
-	if (!ret)
-		return 0;
-	/* fall through */
-check_ret:
-	if (ret && errno == EINVAL) {
-		if (!exclude_guest_missing &&
-		    (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
-			pr_debug("Old kernel, cannot exclude "
-				 "guest or host samples.\n");
-			exclude_guest_missing = true;
-			goto retry;
-		}
-	}
-	return ret;
+	return perf_evsel__open_per_thread(evsel, evsel_list->threads);
 }
 }
 
 
 /*
 /*
@@ -271,6 +247,7 @@ static int read_counter(struct perf_evsel *counter)
 
 
 static int __run_perf_stat(int argc __maybe_unused, const char **argv)
 static int __run_perf_stat(int argc __maybe_unused, const char **argv)
 {
 {
+	char msg[512];
 	unsigned long long t0, t1;
 	unsigned long long t0, t1;
 	struct perf_evsel *counter;
 	struct perf_evsel *counter;
 	int status = 0;
 	int status = 0;
@@ -348,20 +325,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
 				continue;
 				continue;
 			}
 			}
 
 
-			if (errno == EPERM || errno == EACCES) {
-				error("You may not have permission to collect %sstats.\n"
-				      "\t Consider tweaking"
-				      " /proc/sys/kernel/perf_event_paranoid or running as root.",
-				      target.system_wide ? "system-wide " : "");
-			} else {
-				error("open_counter returned with %d (%s). "
-				      "/bin/dmesg may provide additional information.\n",
-				       errno, strerror(errno));
-			}
+			perf_evsel__open_strerror(counter, &target,
+						  errno, msg, sizeof(msg));
+			ui__error("%s\n", msg);
+
 			if (child_pid != -1)
 			if (child_pid != -1)
 				kill(child_pid, SIGTERM);
 				kill(child_pid, SIGTERM);
 
 
-			pr_err("Not all events could be opened.\n");
 			return -1;
 			return -1;
 		}
 		}
 		counter->supported = true;
 		counter->supported = true;

+ 13 - 93
tools/perf/builtin-top.c

@@ -68,28 +68,6 @@
 #include <linux/unistd.h>
 #include <linux/unistd.h>
 #include <linux/types.h>
 #include <linux/types.h>
 
 
-void get_term_dimensions(struct winsize *ws)
-{
-	char *s = getenv("LINES");
-
-	if (s != NULL) {
-		ws->ws_row = atoi(s);
-		s = getenv("COLUMNS");
-		if (s != NULL) {
-			ws->ws_col = atoi(s);
-			if (ws->ws_row && ws->ws_col)
-				return;
-		}
-	}
-#ifdef TIOCGWINSZ
-	if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
-	    ws->ws_row && ws->ws_col)
-		return;
-#endif
-	ws->ws_row = 25;
-	ws->ws_col = 80;
-}
-
 static void perf_top__update_print_entries(struct perf_top *top)
 static void perf_top__update_print_entries(struct perf_top *top)
 {
 {
 	if (top->print_entries > 9)
 	if (top->print_entries > 9)
@@ -716,7 +694,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
 		static struct intlist *seen;
 		static struct intlist *seen;
 
 
 		if (!seen)
 		if (!seen)
-			seen = intlist__new();
+			seen = intlist__new(NULL);
 
 
 		if (!intlist__has_entry(seen, event->ip.pid)) {
 		if (!intlist__has_entry(seen, event->ip.pid)) {
 			pr_err("Can't find guest [%d]'s kernel information\n",
 			pr_err("Can't find guest [%d]'s kernel information\n",
@@ -728,7 +706,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
 
 
 	if (!machine) {
 	if (!machine) {
 		pr_err("%u unprocessable samples recorded.\n",
 		pr_err("%u unprocessable samples recorded.\n",
-		       top->session->hists.stats.nr_unprocessable_samples++);
+		       top->session->stats.nr_unprocessable_samples++);
 		return;
 		return;
 	}
 	}
 
 
@@ -847,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
 			++top->us_samples;
 			++top->us_samples;
 			if (top->hide_user_symbols)
 			if (top->hide_user_symbols)
 				continue;
 				continue;
-			machine = perf_session__find_host_machine(session);
+			machine = &session->machines.host;
 			break;
 			break;
 		case PERF_RECORD_MISC_KERNEL:
 		case PERF_RECORD_MISC_KERNEL:
 			++top->kernel_samples;
 			++top->kernel_samples;
 			if (top->hide_kernel_symbols)
 			if (top->hide_kernel_symbols)
 				continue;
 				continue;
-			machine = perf_session__find_host_machine(session);
+			machine = &session->machines.host;
 			break;
 			break;
 		case PERF_RECORD_MISC_GUEST_KERNEL:
 		case PERF_RECORD_MISC_GUEST_KERNEL:
 			++top->guest_kernel_samples;
 			++top->guest_kernel_samples;
@@ -878,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
 			hists__inc_nr_events(&evsel->hists, event->header.type);
 			hists__inc_nr_events(&evsel->hists, event->header.type);
 			machine__process_event(machine, event);
 			machine__process_event(machine, event);
 		} else
 		} else
-			++session->hists.stats.nr_unknown_events;
+			++session->stats.nr_unknown_events;
 	}
 	}
 }
 }
 
 
@@ -892,6 +870,7 @@ static void perf_top__mmap_read(struct perf_top *top)
 
 
 static void perf_top__start_counters(struct perf_top *top)
 static void perf_top__start_counters(struct perf_top *top)
 {
 {
+	char msg[512];
 	struct perf_evsel *counter;
 	struct perf_evsel *counter;
 	struct perf_evlist *evlist = top->evlist;
 	struct perf_evlist *evlist = top->evlist;
 	struct perf_record_opts *opts = &top->record_opts;
 	struct perf_record_opts *opts = &top->record_opts;
@@ -899,77 +878,18 @@ static void perf_top__start_counters(struct perf_top *top)
 	perf_evlist__config(evlist, opts);
 	perf_evlist__config(evlist, opts);
 
 
 	list_for_each_entry(counter, &evlist->entries, node) {
 	list_for_each_entry(counter, &evlist->entries, node) {
-		struct perf_event_attr *attr = &counter->attr;
-
-fallback_missing_features:
-		if (top->exclude_guest_missing)
-			attr->exclude_guest = attr->exclude_host = 0;
-retry_sample_id:
-		attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
 try_again:
 try_again:
 		if (perf_evsel__open(counter, top->evlist->cpus,
 		if (perf_evsel__open(counter, top->evlist->cpus,
 				     top->evlist->threads) < 0) {
 				     top->evlist->threads) < 0) {
-			int err = errno;
-
-			if (err == EPERM || err == EACCES) {
-				ui__error_paranoid();
-				goto out_err;
-			} else if (err == EINVAL) {
-				if (!top->exclude_guest_missing &&
-				    (attr->exclude_guest || attr->exclude_host)) {
-					pr_debug("Old kernel, cannot exclude "
-						 "guest or host samples.\n");
-					top->exclude_guest_missing = true;
-					goto fallback_missing_features;
-				} else if (!top->sample_id_all_missing) {
-					/*
-					 * Old kernel, no attr->sample_id_type_all field
-					 */
-					top->sample_id_all_missing = true;
-					goto retry_sample_id;
-				}
-			}
-			/*
-			 * If it's cycles then fall back to hrtimer
-			 * based cpu-clock-tick sw counter, which
-			 * is always available even if no PMU support:
-			 */
-			if ((err == ENOENT || err == ENXIO) &&
-			    (attr->type == PERF_TYPE_HARDWARE) &&
-			    (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
-
+			if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
 				if (verbose)
 				if (verbose)
-					ui__warning("Cycles event not supported,\n"
-						    "trying to fall back to cpu-clock-ticks\n");
-
-				attr->type = PERF_TYPE_SOFTWARE;
-				attr->config = PERF_COUNT_SW_CPU_CLOCK;
-				if (counter->name) {
-					free(counter->name);
-					counter->name = NULL;
-				}
+					ui__warning("%s\n", msg);
 				goto try_again;
 				goto try_again;
 			}
 			}
 
 
-			if (err == ENOENT) {
-				ui__error("The %s event is not supported.\n",
-					  perf_evsel__name(counter));
-				goto out_err;
-			} else if (err == EMFILE) {
-				ui__error("Too many events are opened.\n"
-					    "Try again after reducing the number of events\n");
-				goto out_err;
-			} else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
-				ui__error("\'precise\' request may not be supported. "
-					  "Try removing 'p' modifier\n");
-				goto out_err;
-			}
-
-			ui__error("The sys_perf_event_open() syscall "
-				    "returned with %d (%s).  /bin/dmesg "
-				    "may provide additional information.\n"
-				    "No CONFIG_PERF_EVENTS=y kernel support "
-				    "configured?\n", err, strerror(err));
+			perf_evsel__open_strerror(counter, &opts->target,
+						  errno, msg, sizeof(msg));
+			ui__error("%s\n", msg);
 			goto out_err;
 			goto out_err;
 		}
 		}
 	}
 	}
@@ -1024,10 +944,10 @@ static int __cmd_top(struct perf_top *top)
 	if (perf_target__has_task(&opts->target))
 	if (perf_target__has_task(&opts->target))
 		perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
 		perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
 						  perf_event__process,
 						  perf_event__process,
-						  &top->session->host_machine);
+						  &top->session->machines.host);
 	else
 	else
 		perf_event__synthesize_threads(&top->tool, perf_event__process,
 		perf_event__synthesize_threads(&top->tool, perf_event__process,
-					       &top->session->host_machine);
+					       &top->session->machines.host);
 	perf_top__start_counters(top);
 	perf_top__start_counters(top);
 	top->session->evlist = top->evlist;
 	top->session->evlist = top->evlist;
 	perf_session__set_id_hdr_size(top->session);
 	perf_session__set_id_hdr_size(top->session);

+ 3 - 3
tools/perf/config/utilities.mak

@@ -13,7 +13,7 @@ newline := $(newline)
 # what should replace a newline when escaping
 # what should replace a newline when escaping
 # newlines; the default is a bizarre string.
 # newlines; the default is a bizarre string.
 #
 #
-nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
+nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
 
 
 # escape-nl
 # escape-nl
 #
 #
@@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1))
 # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
 # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
 #
 #
 define get-executable-or-default
 define get-executable-or-default
-$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
+$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
 endef
 endef
-_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2)))
+_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
 _gea_warn = $(warning The path '$(1)' is not executable.)
 _gea_warn = $(warning The path '$(1)' is not executable.)
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
 
 

+ 21 - 11
tools/perf/perf.c

@@ -328,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
 	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
 	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
 		return 0;
 		return 0;
 
 
+	status = 1;
 	/* Check for ENOSPC and EIO errors.. */
 	/* Check for ENOSPC and EIO errors.. */
-	if (fflush(stdout))
-		die("write failure on standard output: %s", strerror(errno));
-	if (ferror(stdout))
-		die("unknown write failure on standard output");
-	if (fclose(stdout))
-		die("close failed on standard output: %s", strerror(errno));
-	return 0;
+	if (fflush(stdout)) {
+		fprintf(stderr, "write failure on standard output: %s", strerror(errno));
+		goto out;
+	}
+	if (ferror(stdout)) {
+		fprintf(stderr, "unknown write failure on standard output");
+		goto out;
+	}
+	if (fclose(stdout)) {
+		fprintf(stderr, "close failed on standard output: %s", strerror(errno));
+		goto out;
+	}
+	status = 0;
+out:
+	return status;
 }
 }
 
 
 static void handle_internal_command(int argc, const char **argv)
 static void handle_internal_command(int argc, const char **argv)
@@ -467,7 +476,8 @@ int main(int argc, const char **argv)
 		cmd += 5;
 		cmd += 5;
 		argv[0] = cmd;
 		argv[0] = cmd;
 		handle_internal_command(argc, argv);
 		handle_internal_command(argc, argv);
-		die("cannot handle %s internally", cmd);
+		fprintf(stderr, "cannot handle %s internally", cmd);
+		goto out;
 	}
 	}
 
 
 	/* Look for flags.. */
 	/* Look for flags.. */
@@ -485,7 +495,7 @@ int main(int argc, const char **argv)
 		printf("\n usage: %s\n\n", perf_usage_string);
 		printf("\n usage: %s\n\n", perf_usage_string);
 		list_common_cmds_help();
 		list_common_cmds_help();
 		printf("\n %s\n\n", perf_more_info_string);
 		printf("\n %s\n\n", perf_more_info_string);
-		exit(1);
+		goto out;
 	}
 	}
 	cmd = argv[0];
 	cmd = argv[0];
 
 
@@ -517,7 +527,7 @@ int main(int argc, const char **argv)
 			fprintf(stderr, "Expansion of alias '%s' failed; "
 			fprintf(stderr, "Expansion of alias '%s' failed; "
 				"'%s' is not a perf-command\n",
 				"'%s' is not a perf-command\n",
 				cmd, argv[0]);
 				cmd, argv[0]);
-			exit(1);
+			goto out;
 		}
 		}
 		if (!done_help) {
 		if (!done_help) {
 			cmd = argv[0] = help_unknown_cmd(cmd);
 			cmd = argv[0] = help_unknown_cmd(cmd);
@@ -528,6 +538,6 @@ int main(int argc, const char **argv)
 
 
 	fprintf(stderr, "Failed to run command '%s': %s\n",
 	fprintf(stderr, "Failed to run command '%s': %s\n",
 		cmd, strerror(errno));
 		cmd, strerror(errno));
-
+out:
 	return 1;
 	return 1;
 }
 }

+ 0 - 6
tools/perf/perf.h

@@ -1,10 +1,6 @@
 #ifndef _PERF_PERF_H
 #ifndef _PERF_PERF_H
 #define _PERF_PERF_H
 #define _PERF_PERF_H
 
 
-struct winsize;
-
-void get_term_dimensions(struct winsize *ws);
-
 #include <asm/unistd.h>
 #include <asm/unistd.h>
 
 
 #if defined(__i386__)
 #if defined(__i386__)
@@ -237,8 +233,6 @@ struct perf_record_opts {
 	bool	     raw_samples;
 	bool	     raw_samples;
 	bool	     sample_address;
 	bool	     sample_address;
 	bool	     sample_time;
 	bool	     sample_time;
-	bool	     sample_id_all_missing;
-	bool	     exclude_guest_missing;
 	bool	     period;
 	bool	     period;
 	unsigned int freq;
 	unsigned int freq;
 	unsigned int mmap_pages;
 	unsigned int mmap_pages;

+ 0 - 2
tools/perf/scripts/perl/bin/workqueue-stats-record

@@ -1,2 +0,0 @@
-#!/bin/bash
-perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@

+ 0 - 3
tools/perf/scripts/perl/bin/workqueue-stats-report

@@ -1,3 +0,0 @@
-#!/bin/bash
-# description: workqueue stats (ins/exe/create/destroy)
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl

+ 0 - 129
tools/perf/scripts/perl/workqueue-stats.pl

@@ -1,129 +0,0 @@
-#!/usr/bin/perl -w
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-# Licensed under the terms of the GNU GPL License version 2
-
-# Displays workqueue stats
-#
-# Usage:
-#
-#   perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
-#     workqueue:workqueue_destruction -e workqueue:workqueue_execution
-#     -e workqueue:workqueue_insertion
-#
-#   perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-
-my @cpus;
-
-sub workqueue::workqueue_destruction
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-	$common_pid, $common_comm,
-	$thread_comm, $thread_pid) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{destroyed}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_creation
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-	$common_pid, $common_comm,
-	$thread_comm, $thread_pid, $cpu) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{created}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_execution
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-	$common_pid, $common_comm,
-	$thread_comm, $thread_pid, $func) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{executed}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_insertion
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-	$common_pid, $common_comm,
-	$thread_comm, $thread_pid, $func) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{inserted}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub trace_end
-{
-    print "workqueue work stats:\n\n";
-    my $cpu = 0;
-    printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
-    printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
-    foreach my $pidhash (@cpus) {
-	while ((my $pid, my $wqhash) = each %$pidhash) {
-	    my $ins = $$wqhash{'inserted'} || 0;
-	    my $exe = $$wqhash{'executed'} || 0;
-	    my $comm = $$wqhash{'comm'} || "";
-	    if ($ins || $exe) {
-		printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
-	    }
-	}
-	$cpu++;
-    }
-
-    $cpu = 0;
-    print "\nworkqueue lifecycle stats:\n\n";
-    printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
-    printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
-    foreach my $pidhash (@cpus) {
-	while ((my $pid, my $wqhash) = each %$pidhash) {
-	    my $created = $$wqhash{'created'} || 0;
-	    my $destroyed = $$wqhash{'destroyed'} || 0;
-	    my $comm = $$wqhash{'comm'} || "";
-	    if ($created || $destroyed) {
-		printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
-		       $comm);
-	    }
-	}
-	$cpu++;
-    }
-
-    print_unhandled();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
-    if ((scalar keys %unhandled) == 0) {
-	return;
-    }
-
-    print "\nunhandled events:\n\n";
-
-    printf("%-40s  %10s\n", "event", "count");
-    printf("%-40s  %10s\n", "----------------------------------------",
-	   "-----------");
-
-    foreach my $event_name (keys %unhandled) {
-	printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
-    }
-}
-
-sub trace_unhandled
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-	$common_pid, $common_comm) = @_;
-
-    $unhandled{$event_name}++;
-}

+ 1 - 3
tools/perf/tests/attr.c

@@ -33,8 +33,6 @@
 
 
 extern int verbose;
 extern int verbose;
 
 
-bool test_attr__enabled;
-
 static char *dir;
 static char *dir;
 
 
 void test_attr__init(void)
 void test_attr__init(void)
@@ -146,7 +144,7 @@ static int run_dir(const char *d, const char *perf)
 {
 {
 	char cmd[3*PATH_MAX];
 	char cmd[3*PATH_MAX];
 
 
-	snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s",
+	snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
 		 d, d, perf, verbose ? "-v" : "");
 		 d, d, perf, verbose ? "-v" : "");
 
 
 	return system(cmd);
 	return system(cmd);

+ 18 - 9
tools/perf/tests/attr.py

@@ -68,7 +68,7 @@ class Event(dict):
             self[key] = val
             self[key] = val
 
 
     def __init__(self, name, data, base):
     def __init__(self, name, data, base):
-        log.info("    Event %s" % name);
+        log.debug("    Event %s" % name);
         self.name  = name;
         self.name  = name;
         self.group = ''
         self.group = ''
         self.add(base)
         self.add(base)
@@ -97,6 +97,14 @@ class Event(dict):
                 return False
                 return False
         return True
         return True
 
 
+    def diff(self, other):
+        for t in Event.terms:
+            if not self.has_key(t) or not other.has_key(t):
+                continue
+            if not self.compare_data(self[t], other[t]):
+		log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
+                
+
 # Test file description needs to have following sections:
 # Test file description needs to have following sections:
 # [config]
 # [config]
 #   - just single instance in file
 #   - just single instance in file
@@ -113,7 +121,7 @@ class Test(object):
         parser = ConfigParser.SafeConfigParser()
         parser = ConfigParser.SafeConfigParser()
         parser.read(path)
         parser.read(path)
 
 
-        log.warning("running '%s'" % path)
+        log.debug("running '%s'" % path)
 
 
         self.path     = path
         self.path     = path
         self.test_dir = options.test_dir
         self.test_dir = options.test_dir
@@ -128,7 +136,7 @@ class Test(object):
 
 
         self.expect   = {}
         self.expect   = {}
         self.result   = {}
         self.result   = {}
-        log.info("  loading expected events");
+        log.debug("  loading expected events");
         self.load_events(path, self.expect)
         self.load_events(path, self.expect)
 
 
     def is_event(self, name):
     def is_event(self, name):
@@ -164,7 +172,7 @@ class Test(object):
               self.perf, self.command, tempdir, self.args)
               self.perf, self.command, tempdir, self.args)
         ret = os.WEXITSTATUS(os.system(cmd))
         ret = os.WEXITSTATUS(os.system(cmd))
 
 
-        log.info("  running '%s' ret %d " % (cmd, ret))
+        log.warning("  running '%s' ret %d " % (cmd, ret))
 
 
         if ret != int(self.ret):
         if ret != int(self.ret):
             raise Unsup(self)
             raise Unsup(self)
@@ -172,7 +180,7 @@ class Test(object):
     def compare(self, expect, result):
     def compare(self, expect, result):
         match = {}
         match = {}
 
 
-        log.info("  compare");
+        log.debug("  compare");
 
 
         # For each expected event find all matching
         # For each expected event find all matching
         # events in result. Fail if there's not any.
         # events in result. Fail if there's not any.
@@ -187,10 +195,11 @@ class Test(object):
                 else:
                 else:
                     log.debug("    ->FAIL");
                     log.debug("    ->FAIL");
 
 
-            log.info("    match: [%s] matches %s" % (exp_name, str(exp_list)))
+            log.debug("    match: [%s] matches %s" % (exp_name, str(exp_list)))
 
 
             # we did not any matching event - fail
             # we did not any matching event - fail
             if (not exp_list):
             if (not exp_list):
+		exp_event.diff(res_event)
                 raise Fail(self, 'match failure');
                 raise Fail(self, 'match failure');
 
 
             match[exp_name] = exp_list
             match[exp_name] = exp_list
@@ -208,10 +217,10 @@ class Test(object):
                 if res_group not in match[group]:
                 if res_group not in match[group]:
                     raise Fail(self, 'group failure')
                     raise Fail(self, 'group failure')
 
 
-                log.info("    group: [%s] matches group leader %s" %
+                log.debug("    group: [%s] matches group leader %s" %
                          (exp_name, str(match[group])))
                          (exp_name, str(match[group])))
 
 
-        log.info("  matched")
+        log.debug("  matched")
 
 
     def resolve_groups(self, events):
     def resolve_groups(self, events):
         for name, event in events.items():
         for name, event in events.items():
@@ -233,7 +242,7 @@ class Test(object):
             self.run_cmd(tempdir);
             self.run_cmd(tempdir);
 
 
             # load events expectation for the test
             # load events expectation for the test
-            log.info("  loading result events");
+            log.debug("  loading result events");
             for f in glob.glob(tempdir + '/event*'):
             for f in glob.glob(tempdir + '/event*'):
                 self.load_events(f, self.result);
                 self.load_events(f, self.result);
 
 

+ 1 - 1
tools/perf/tests/attr/test-record-group1

@@ -1,6 +1,6 @@
 [config]
 [config]
 command = record
 command = record
-args    = -e '{cycles,instructions}' kill >/tmp/krava 2>&1
+args    = -e '{cycles,instructions}' kill >/dev/null 2>&1
 
 
 [event-1:base-record]
 [event-1:base-record]
 fd=1
 fd=1

+ 35 - 5
tools/perf/tests/builtin-test.c

@@ -4,6 +4,7 @@
  * Builtin regression testing command: ever growing number of sanity tests
  * Builtin regression testing command: ever growing number of sanity tests
  */
  */
 #include "builtin.h"
 #include "builtin.h"
+#include "intlist.h"
 #include "tests.h"
 #include "tests.h"
 #include "debug.h"
 #include "debug.h"
 #include "color.h"
 #include "color.h"
@@ -68,6 +69,14 @@ static struct test {
 		.desc = "struct perf_event_attr setup",
 		.desc = "struct perf_event_attr setup",
 		.func = test__attr,
 		.func = test__attr,
 	},
 	},
+	{
+		.desc = "Test matching and linking mutliple hists",
+		.func = test__hists_link,
+	},
+	{
+		.desc = "Try 'use perf' in python, checking link problems",
+		.func = test__python_use,
+	},
 	{
 	{
 		.func = NULL,
 		.func = NULL,
 	},
 	},
@@ -97,7 +106,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
 	return false;
 	return false;
 }
 }
 
 
-static int __cmd_test(int argc, const char *argv[])
+static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 {
 {
 	int i = 0;
 	int i = 0;
 	int width = 0;
 	int width = 0;
@@ -118,13 +127,28 @@ static int __cmd_test(int argc, const char *argv[])
 			continue;
 			continue;
 
 
 		pr_info("%2d: %-*s:", i, width, tests[curr].desc);
 		pr_info("%2d: %-*s:", i, width, tests[curr].desc);
+
+		if (intlist__find(skiplist, i)) {
+			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
+			continue;
+		}
+
 		pr_debug("\n--- start ---\n");
 		pr_debug("\n--- start ---\n");
 		err = tests[curr].func();
 		err = tests[curr].func();
 		pr_debug("---- end ----\n%s:", tests[curr].desc);
 		pr_debug("---- end ----\n%s:", tests[curr].desc);
-		if (err)
-			color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
-		else
+
+		switch (err) {
+		case TEST_OK:
 			pr_info(" Ok\n");
 			pr_info(" Ok\n");
+			break;
+		case TEST_SKIP:
+			color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
+			break;
+		case TEST_FAIL:
+		default:
+			color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
+			break;
+		}
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -152,11 +176,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
 	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
 	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
 	NULL,
 	NULL,
 	};
 	};
+	const char *skip = NULL;
 	const struct option test_options[] = {
 	const struct option test_options[] = {
+	OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
 	OPT_INCR('v', "verbose", &verbose,
 	OPT_INCR('v', "verbose", &verbose,
 		    "be more verbose (show symbol address, etc)"),
 		    "be more verbose (show symbol address, etc)"),
 	OPT_END()
 	OPT_END()
 	};
 	};
+	struct intlist *skiplist = NULL;
 
 
 	argc = parse_options(argc, argv, test_options, test_usage, 0);
 	argc = parse_options(argc, argv, test_options, test_usage, 0);
 	if (argc >= 1 && !strcmp(argv[0], "list"))
 	if (argc >= 1 && !strcmp(argv[0], "list"))
@@ -169,5 +196,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (symbol__init() < 0)
 	if (symbol__init() < 0)
 		return -1;
 		return -1;
 
 
-	return __cmd_test(argc, argv);
+	if (skip != NULL)
+		skiplist = intlist__new(skip);
+
+	return __cmd_test(argc, argv, skiplist);
 }
 }

+ 2 - 2
tools/perf/tests/evsel-roundtrip-name.c

@@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
 			for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
 			for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
 				__perf_evsel__hw_cache_type_op_res_name(type, op, i,
 				__perf_evsel__hw_cache_type_op_res_name(type, op, i,
 									name, sizeof(name));
 									name, sizeof(name));
-				err = parse_events(evlist, name, 0);
+				err = parse_events(evlist, name);
 				if (err)
 				if (err)
 					ret = err;
 					ret = err;
 			}
 			}
@@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
                 return -ENOMEM;
                 return -ENOMEM;
 
 
 	for (i = 0; i < nr_names; ++i) {
 	for (i = 0; i < nr_names; ++i) {
-		err = parse_events(evlist, names[i], 0);
+		err = parse_events(evlist, names[i]);
 		if (err) {
 		if (err) {
 			pr_debug("failed to parse event '%s', err %d\n",
 			pr_debug("failed to parse event '%s', err %d\n",
 				 names[i], err);
 				 names[i], err);

+ 499 - 0
tools/perf/tests/hists_link.c

@@ -0,0 +1,499 @@
+#include "perf.h"
+#include "tests.h"
+#include "debug.h"
+#include "symbol.h"
+#include "sort.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "machine.h"
+#include "thread.h"
+#include "parse-events.h"
+
+static struct {
+	u32 pid;
+	const char *comm;
+} fake_threads[] = {
+	{ 100, "perf" },
+	{ 200, "perf" },
+	{ 300, "bash" },
+};
+
+static struct {
+	u32 pid;
+	u64 start;
+	const char *filename;
+} fake_mmap_info[] = {
+	{ 100, 0x40000, "perf" },
+	{ 100, 0x50000, "libc" },
+	{ 100, 0xf0000, "[kernel]" },
+	{ 200, 0x40000, "perf" },
+	{ 200, 0x50000, "libc" },
+	{ 200, 0xf0000, "[kernel]" },
+	{ 300, 0x40000, "bash" },
+	{ 300, 0x50000, "libc" },
+	{ 300, 0xf0000, "[kernel]" },
+};
+
+struct fake_sym {
+	u64 start;
+	u64 length;
+	const char *name;
+};
+
+static struct fake_sym perf_syms[] = {
+	{ 700, 100, "main" },
+	{ 800, 100, "run_command" },
+	{ 900, 100, "cmd_record" },
+};
+
+static struct fake_sym bash_syms[] = {
+	{ 700, 100, "main" },
+	{ 800, 100, "xmalloc" },
+	{ 900, 100, "xfree" },
+};
+
+static struct fake_sym libc_syms[] = {
+	{ 700, 100, "malloc" },
+	{ 800, 100, "free" },
+	{ 900, 100, "realloc" },
+};
+
+static struct fake_sym kernel_syms[] = {
+	{ 700, 100, "schedule" },
+	{ 800, 100, "page_fault" },
+	{ 900, 100, "sys_perf_event_open" },
+};
+
+static struct {
+	const char *dso_name;
+	struct fake_sym *syms;
+	size_t nr_syms;
+} fake_symbols[] = {
+	{ "perf", perf_syms, ARRAY_SIZE(perf_syms) },
+	{ "bash", bash_syms, ARRAY_SIZE(bash_syms) },
+	{ "libc", libc_syms, ARRAY_SIZE(libc_syms) },
+	{ "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
+};
+
+static struct machine *setup_fake_machine(struct machines *machines)
+{
+	struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
+	size_t i;
+
+	if (machine == NULL) {
+		pr_debug("Not enough memory for machine setup\n");
+		return NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
+		struct thread *thread;
+
+		thread = machine__findnew_thread(machine, fake_threads[i].pid);
+		if (thread == NULL)
+			goto out;
+
+		thread__set_comm(thread, fake_threads[i].comm);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
+		union perf_event fake_mmap_event = {
+			.mmap = {
+				.header = { .misc = PERF_RECORD_MISC_USER, },
+				.pid = fake_mmap_info[i].pid,
+				.start = fake_mmap_info[i].start,
+				.len = 0x1000ULL,
+				.pgoff = 0ULL,
+			},
+		};
+
+		strcpy(fake_mmap_event.mmap.filename,
+		       fake_mmap_info[i].filename);
+
+		machine__process_mmap_event(machine, &fake_mmap_event);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
+		size_t k;
+		struct dso *dso;
+
+		dso = __dsos__findnew(&machine->user_dsos,
+				      fake_symbols[i].dso_name);
+		if (dso == NULL)
+			goto out;
+
+		/* emulate dso__load() */
+		dso__set_loaded(dso, MAP__FUNCTION);
+
+		for (k = 0; k < fake_symbols[i].nr_syms; k++) {
+			struct symbol *sym;
+			struct fake_sym *fsym = &fake_symbols[i].syms[k];
+
+			sym = symbol__new(fsym->start, fsym->length,
+					  STB_GLOBAL, fsym->name);
+			if (sym == NULL)
+				goto out;
+
+			symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
+		}
+	}
+
+	return machine;
+
+out:
+	pr_debug("Not enough memory for machine setup\n");
+	machine__delete_threads(machine);
+	machine__delete(machine);
+	return NULL;
+}
+
+struct sample {
+	u32 pid;
+	u64 ip;
+	struct thread *thread;
+	struct map *map;
+	struct symbol *sym;
+};
+
+static struct sample fake_common_samples[] = {
+	/* perf [kernel] schedule() */
+	{ .pid = 100, .ip = 0xf0000 + 700, },
+	/* perf [perf]   main() */
+	{ .pid = 200, .ip = 0x40000 + 700, },
+	/* perf [perf]   cmd_record() */
+	{ .pid = 200, .ip = 0x40000 + 900, },
+	/* bash [bash]   xmalloc() */
+	{ .pid = 300, .ip = 0x40000 + 800, },
+	/* bash [libc]   malloc() */
+	{ .pid = 300, .ip = 0x50000 + 700, },
+};
+
+static struct sample fake_samples[][5] = {
+	{
+		/* perf [perf]   run_command() */
+		{ .pid = 100, .ip = 0x40000 + 800, },
+		/* perf [libc]   malloc() */
+		{ .pid = 100, .ip = 0x50000 + 700, },
+		/* perf [kernel] page_fault() */
+		{ .pid = 100, .ip = 0xf0000 + 800, },
+		/* perf [kernel] sys_perf_event_open() */
+		{ .pid = 200, .ip = 0xf0000 + 900, },
+		/* bash [libc]   free() */
+		{ .pid = 300, .ip = 0x50000 + 800, },
+	},
+	{
+		/* perf [libc]   free() */
+		{ .pid = 200, .ip = 0x50000 + 800, },
+		/* bash [libc]   malloc() */
+		{ .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */
+		/* bash [bash]   xfee() */
+		{ .pid = 300, .ip = 0x40000 + 900, },
+		/* bash [libc]   realloc() */
+		{ .pid = 300, .ip = 0x50000 + 900, },
+		/* bash [kernel] page_fault() */
+		{ .pid = 300, .ip = 0xf0000 + 800, },
+	},
+};
+
+static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
+{
+	struct perf_evsel *evsel;
+	struct addr_location al;
+	struct hist_entry *he;
+	struct perf_sample sample = { .cpu = 0, };
+	size_t i = 0, k;
+
+	/*
+	 * each evsel will have 10 samples - 5 common and 5 distinct.
+	 * However the second evsel also has a collapsed entry for
+	 * "bash [libc] malloc" so total 9 entries will be in the tree.
+	 */
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
+			const union perf_event event = {
+				.ip = {
+					.header = {
+						.misc = PERF_RECORD_MISC_USER,
+					},
+					.pid = fake_common_samples[k].pid,
+					.ip  = fake_common_samples[k].ip,
+				},
+			};
+
+			if (perf_event__preprocess_sample(&event, machine, &al,
+							  &sample, 0) < 0)
+				goto out;
+
+			he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+			if (he == NULL)
+				goto out;
+
+			fake_common_samples[k].thread = al.thread;
+			fake_common_samples[k].map = al.map;
+			fake_common_samples[k].sym = al.sym;
+		}
+
+		for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
+			const union perf_event event = {
+				.ip = {
+					.header = {
+						.misc = PERF_RECORD_MISC_USER,
+					},
+					.pid = fake_samples[i][k].pid,
+					.ip  = fake_samples[i][k].ip,
+				},
+			};
+
+			if (perf_event__preprocess_sample(&event, machine, &al,
+							  &sample, 0) < 0)
+				goto out;
+
+			he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+			if (he == NULL)
+				goto out;
+
+			fake_samples[i][k].thread = al.thread;
+			fake_samples[i][k].map = al.map;
+			fake_samples[i][k].sym = al.sym;
+		}
+		i++;
+	}
+
+	return 0;
+
+out:
+	pr_debug("Not enough memory for adding a hist entry\n");
+	return -1;
+}
+
+static int find_sample(struct sample *samples, size_t nr_samples,
+		       struct thread *t, struct map *m, struct symbol *s)
+{
+	while (nr_samples--) {
+		if (samples->thread == t && samples->map == m &&
+		    samples->sym == s)
+			return 1;
+		samples++;
+	}
+	return 0;
+}
+
+static int __validate_match(struct hists *hists)
+{
+	size_t count = 0;
+	struct rb_root *root;
+	struct rb_node *node;
+
+	/*
+	 * Only entries from fake_common_samples should have a pair.
+	 */
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
+
+	node = rb_first(root);
+	while (node) {
+		struct hist_entry *he;
+
+		he = rb_entry(node, struct hist_entry, rb_node_in);
+
+		if (hist_entry__has_pairs(he)) {
+			if (find_sample(fake_common_samples,
+					ARRAY_SIZE(fake_common_samples),
+					he->thread, he->ms.map, he->ms.sym)) {
+				count++;
+			} else {
+				pr_debug("Can't find the matched entry\n");
+				return -1;
+			}
+		}
+
+		node = rb_next(node);
+	}
+
+	if (count != ARRAY_SIZE(fake_common_samples)) {
+		pr_debug("Invalid count for matched entries: %zd of %zd\n",
+			 count, ARRAY_SIZE(fake_common_samples));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int validate_match(struct hists *leader, struct hists *other)
+{
+	return __validate_match(leader) || __validate_match(other);
+}
+
+static int __validate_link(struct hists *hists, int idx)
+{
+	size_t count = 0;
+	size_t count_pair = 0;
+	size_t count_dummy = 0;
+	struct rb_root *root;
+	struct rb_node *node;
+
+	/*
+	 * Leader hists (idx = 0) will have dummy entries from other,
+	 * and some entries will have no pair.  However every entry
+	 * in other hists should have (dummy) pair.
+	 */
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
+
+	node = rb_first(root);
+	while (node) {
+		struct hist_entry *he;
+
+		he = rb_entry(node, struct hist_entry, rb_node_in);
+
+		if (hist_entry__has_pairs(he)) {
+			if (!find_sample(fake_common_samples,
+					 ARRAY_SIZE(fake_common_samples),
+					 he->thread, he->ms.map, he->ms.sym) &&
+			    !find_sample(fake_samples[idx],
+					 ARRAY_SIZE(fake_samples[idx]),
+					 he->thread, he->ms.map, he->ms.sym)) {
+				count_dummy++;
+			}
+			count_pair++;
+		} else if (idx) {
+			pr_debug("A entry from the other hists should have pair\n");
+			return -1;
+		}
+
+		count++;
+		node = rb_next(node);
+	}
+
+	/*
+	 * Note that we have a entry collapsed in the other (idx = 1) hists.
+	 */
+	if (idx == 0) {
+		if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
+			pr_debug("Invalid count of dummy entries: %zd of %zd\n",
+				 count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
+			return -1;
+		}
+		if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
+			pr_debug("Invalid count of total leader entries: %zd of %zd\n",
+				 count, count_pair + ARRAY_SIZE(fake_samples[0]));
+			return -1;
+		}
+	} else {
+		if (count != count_pair) {
+			pr_debug("Invalid count of total other entries: %zd of %zd\n",
+				 count, count_pair);
+			return -1;
+		}
+		if (count_dummy > 0) {
+			pr_debug("Other hists should not have dummy entries: %zd\n",
+				 count_dummy);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int validate_link(struct hists *leader, struct hists *other)
+{
+	return __validate_link(leader, 0) || __validate_link(other, 1);
+}
+
+static void print_hists(struct hists *hists)
+{
+	int i = 0;
+	struct rb_root *root;
+	struct rb_node *node;
+
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
+
+	pr_info("----- %s --------\n", __func__);
+	node = rb_first(root);
+	while (node) {
+		struct hist_entry *he;
+
+		he = rb_entry(node, struct hist_entry, rb_node_in);
+
+		pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
+			i, he->thread->comm, he->ms.map->dso->short_name,
+			he->ms.sym->name, he->stat.period);
+
+		i++;
+		node = rb_next(node);
+	}
+}
+
+int test__hists_link(void)
+{
+	int err = -1;
+	struct machines machines;
+	struct machine *machine = NULL;
+	struct perf_evsel *evsel, *first;
+        struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+
+	if (evlist == NULL)
+                return -ENOMEM;
+
+	err = parse_events(evlist, "cpu-clock");
+	if (err)
+		goto out;
+	err = parse_events(evlist, "task-clock");
+	if (err)
+		goto out;
+
+	/* default sort order (comm,dso,sym) will be used */
+	setup_sorting(NULL, NULL);
+
+	machines__init(&machines);
+
+	/* setup threads/dso/map/symbols also */
+	machine = setup_fake_machine(&machines);
+	if (!machine)
+		goto out;
+
+	if (verbose > 1)
+		machine__fprintf(machine, stderr);
+
+	/* process sample events */
+	err = add_hist_entries(evlist, machine);
+	if (err < 0)
+		goto out;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		hists__collapse_resort(&evsel->hists);
+
+		if (verbose > 2)
+			print_hists(&evsel->hists);
+	}
+
+	first = perf_evlist__first(evlist);
+	evsel = perf_evlist__last(evlist);
+
+	/* match common entries */
+	hists__match(&first->hists, &evsel->hists);
+	err = validate_match(&first->hists, &evsel->hists);
+	if (err)
+		goto out;
+
+	/* link common and/or dummy entries */
+	hists__link(&first->hists, &evsel->hists);
+	err = validate_link(&first->hists, &evsel->hists);
+	if (err)
+		goto out;
+
+	err = 0;
+
+out:
+	/* tear down everything */
+	perf_evlist__delete(evlist);
+	machines__exit(&machines);
+
+	return err;
+}

+ 80 - 18
tools/perf/tests/parse-events.c

@@ -3,6 +3,7 @@
 #include "evsel.h"
 #include "evsel.h"
 #include "evlist.h"
 #include "evlist.h"
 #include "sysfs.h"
 #include "sysfs.h"
+#include "debugfs.h"
 #include "tests.h"
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
 #include <linux/hw_breakpoint.h>
 
 
@@ -463,10 +464,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
 
 
 static int test__checkterms_simple(struct list_head *terms)
 static int test__checkterms_simple(struct list_head *terms)
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
 	/* config=10 */
 	/* config=10 */
-	term = list_entry(terms->next, struct parse_events__term, list);
+	term = list_entry(terms->next, struct parse_events_term, list);
 	TEST_ASSERT_VAL("wrong type term",
 	TEST_ASSERT_VAL("wrong type term",
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
 	TEST_ASSERT_VAL("wrong type val",
 	TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +476,7 @@ static int test__checkterms_simple(struct list_head *terms)
 	TEST_ASSERT_VAL("wrong config", !term->config);
 	TEST_ASSERT_VAL("wrong config", !term->config);
 
 
 	/* config1 */
 	/* config1 */
-	term = list_entry(term->list.next, struct parse_events__term, list);
+	term = list_entry(term->list.next, struct parse_events_term, list);
 	TEST_ASSERT_VAL("wrong type term",
 	TEST_ASSERT_VAL("wrong type term",
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
 	TEST_ASSERT_VAL("wrong type val",
 	TEST_ASSERT_VAL("wrong type val",
@@ -484,7 +485,7 @@ static int test__checkterms_simple(struct list_head *terms)
 	TEST_ASSERT_VAL("wrong config", !term->config);
 	TEST_ASSERT_VAL("wrong config", !term->config);
 
 
 	/* config2=3 */
 	/* config2=3 */
-	term = list_entry(term->list.next, struct parse_events__term, list);
+	term = list_entry(term->list.next, struct parse_events_term, list);
 	TEST_ASSERT_VAL("wrong type term",
 	TEST_ASSERT_VAL("wrong type term",
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
 			term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
 	TEST_ASSERT_VAL("wrong type val",
 	TEST_ASSERT_VAL("wrong type val",
@@ -493,7 +494,7 @@ static int test__checkterms_simple(struct list_head *terms)
 	TEST_ASSERT_VAL("wrong config", !term->config);
 	TEST_ASSERT_VAL("wrong config", !term->config);
 
 
 	/* umask=1*/
 	/* umask=1*/
-	term = list_entry(term->list.next, struct parse_events__term, list);
+	term = list_entry(term->list.next, struct parse_events_term, list);
 	TEST_ASSERT_VAL("wrong type term",
 	TEST_ASSERT_VAL("wrong type term",
 			term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
 			term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
 	TEST_ASSERT_VAL("wrong type val",
 	TEST_ASSERT_VAL("wrong type val",
@@ -782,13 +783,70 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
 	return 0;
 	return 0;
 }
 }
 
 
-struct test__event_st {
+static int count_tracepoints(void)
+{
+	char events_path[PATH_MAX];
+	struct dirent *events_ent;
+	DIR *events_dir;
+	int cnt = 0;
+
+	scnprintf(events_path, PATH_MAX, "%s/tracing/events",
+		  debugfs_find_mountpoint());
+
+	events_dir = opendir(events_path);
+
+	TEST_ASSERT_VAL("Can't open events dir", events_dir);
+
+	while ((events_ent = readdir(events_dir))) {
+		char sys_path[PATH_MAX];
+		struct dirent *sys_ent;
+		DIR *sys_dir;
+
+		if (!strcmp(events_ent->d_name, ".")
+		    || !strcmp(events_ent->d_name, "..")
+		    || !strcmp(events_ent->d_name, "enable")
+		    || !strcmp(events_ent->d_name, "header_event")
+		    || !strcmp(events_ent->d_name, "header_page"))
+			continue;
+
+		scnprintf(sys_path, PATH_MAX, "%s/%s",
+			  events_path, events_ent->d_name);
+
+		sys_dir = opendir(sys_path);
+		TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
+
+		while ((sys_ent = readdir(sys_dir))) {
+			if (!strcmp(sys_ent->d_name, ".")
+			    || !strcmp(sys_ent->d_name, "..")
+			    || !strcmp(sys_ent->d_name, "enable")
+			    || !strcmp(sys_ent->d_name, "filter"))
+				continue;
+
+			cnt++;
+		}
+
+		closedir(sys_dir);
+	}
+
+	closedir(events_dir);
+	return cnt;
+}
+
+static int test__all_tracepoints(struct perf_evlist *evlist)
+{
+	TEST_ASSERT_VAL("wrong events count",
+			count_tracepoints() == evlist->nr_entries);
+
+	return test__checkevent_tracepoint_multi(evlist);
+}
+
+struct evlist_test {
 	const char *name;
 	const char *name;
 	__u32 type;
 	__u32 type;
 	int (*check)(struct perf_evlist *evlist);
 	int (*check)(struct perf_evlist *evlist);
 };
 };
 
 
-static struct test__event_st test__events[] = {
+static struct evlist_test test__events[] = {
 	[0] = {
 	[0] = {
 		.name  = "syscalls:sys_enter_open",
 		.name  = "syscalls:sys_enter_open",
 		.check = test__checkevent_tracepoint,
 		.check = test__checkevent_tracepoint,
@@ -921,9 +979,13 @@ static struct test__event_st test__events[] = {
 		.name  = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
 		.name  = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
 		.check = test__group5,
 		.check = test__group5,
 	},
 	},
+	[33] = {
+		.name  = "*:*",
+		.check = test__all_tracepoints,
+	},
 };
 };
 
 
-static struct test__event_st test__events_pmu[] = {
+static struct evlist_test test__events_pmu[] = {
 	[0] = {
 	[0] = {
 		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
 		.name  = "cpu/config=10,config1,config2=3,period=1000/u",
 		.check = test__checkevent_pmu,
 		.check = test__checkevent_pmu,
@@ -934,20 +996,20 @@ static struct test__event_st test__events_pmu[] = {
 	},
 	},
 };
 };
 
 
-struct test__term {
+struct terms_test {
 	const char *str;
 	const char *str;
 	__u32 type;
 	__u32 type;
 	int (*check)(struct list_head *terms);
 	int (*check)(struct list_head *terms);
 };
 };
 
 
-static struct test__term test__terms[] = {
+static struct terms_test test__terms[] = {
 	[0] = {
 	[0] = {
 		.str   = "config=10,config1,config2=3,umask=1",
 		.str   = "config=10,config1,config2=3,umask=1",
 		.check = test__checkterms_simple,
 		.check = test__checkterms_simple,
 	},
 	},
 };
 };
 
 
-static int test_event(struct test__event_st *e)
+static int test_event(struct evlist_test *e)
 {
 {
 	struct perf_evlist *evlist;
 	struct perf_evlist *evlist;
 	int ret;
 	int ret;
@@ -956,7 +1018,7 @@ static int test_event(struct test__event_st *e)
 	if (evlist == NULL)
 	if (evlist == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	ret = parse_events(evlist, e->name, 0);
+	ret = parse_events(evlist, e->name);
 	if (ret) {
 	if (ret) {
 		pr_debug("failed to parse event '%s', err %d\n",
 		pr_debug("failed to parse event '%s', err %d\n",
 			 e->name, ret);
 			 e->name, ret);
@@ -969,13 +1031,13 @@ static int test_event(struct test__event_st *e)
 	return ret;
 	return ret;
 }
 }
 
 
-static int test_events(struct test__event_st *events, unsigned cnt)
+static int test_events(struct evlist_test *events, unsigned cnt)
 {
 {
 	int ret1, ret2 = 0;
 	int ret1, ret2 = 0;
 	unsigned i;
 	unsigned i;
 
 
 	for (i = 0; i < cnt; i++) {
 	for (i = 0; i < cnt; i++) {
-		struct test__event_st *e = &events[i];
+		struct evlist_test *e = &events[i];
 
 
 		pr_debug("running test %d '%s'\n", i, e->name);
 		pr_debug("running test %d '%s'\n", i, e->name);
 		ret1 = test_event(e);
 		ret1 = test_event(e);
@@ -986,7 +1048,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
 	return ret2;
 	return ret2;
 }
 }
 
 
-static int test_term(struct test__term *t)
+static int test_term(struct terms_test *t)
 {
 {
 	struct list_head *terms;
 	struct list_head *terms;
 	int ret;
 	int ret;
@@ -1010,13 +1072,13 @@ static int test_term(struct test__term *t)
 	return ret;
 	return ret;
 }
 }
 
 
-static int test_terms(struct test__term *terms, unsigned cnt)
+static int test_terms(struct terms_test *terms, unsigned cnt)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	unsigned i;
 	unsigned i;
 
 
 	for (i = 0; i < cnt; i++) {
 	for (i = 0; i < cnt; i++) {
-		struct test__term *t = &terms[i];
+		struct terms_test *t = &terms[i];
 
 
 		pr_debug("running test %d '%s'\n", i, t->str);
 		pr_debug("running test %d '%s'\n", i, t->str);
 		ret = test_term(t);
 		ret = test_term(t);
@@ -1067,7 +1129,7 @@ static int test_pmu_events(void)
 
 
 	while (!ret && (ent = readdir(dir))) {
 	while (!ret && (ent = readdir(dir))) {
 #define MAX_NAME 100
 #define MAX_NAME 100
-		struct test__event_st e;
+		struct evlist_test e;
 		char name[MAX_NAME];
 		char name[MAX_NAME];
 
 
 		if (!strcmp(ent->d_name, ".") ||
 		if (!strcmp(ent->d_name, ".") ||

+ 3 - 8
tools/perf/tests/pmu.c

@@ -19,10 +19,8 @@ static struct test_format {
 	{ "krava23", "config2:28-29,38\n", },
 	{ "krava23", "config2:28-29,38\n", },
 };
 };
 
 
-#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
-
 /* Simulated users input. */
 /* Simulated users input. */
-static struct parse_events__term test_terms[] = {
+static struct parse_events_term test_terms[] = {
 	{
 	{
 		.config    = (char *) "krava01",
 		.config    = (char *) "krava01",
 		.val.num   = 15,
 		.val.num   = 15,
@@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = {
 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 		.type_term = PARSE_EVENTS__TERM_TYPE_USER,
 	},
 	},
 };
 };
-#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
 
 
 /*
 /*
  * Prepare format directory data, exported by kernel
  * Prepare format directory data, exported by kernel
@@ -93,7 +90,7 @@ static char *test_format_dir_get(void)
 	if (!mkdtemp(dir))
 	if (!mkdtemp(dir))
 		return NULL;
 		return NULL;
 
 
-	for (i = 0; i < TEST_FORMATS_CNT; i++) {
+	for (i = 0; i < ARRAY_SIZE(test_formats); i++) {
 		static char name[PATH_MAX];
 		static char name[PATH_MAX];
 		struct test_format *format = &test_formats[i];
 		struct test_format *format = &test_formats[i];
 		FILE *file;
 		FILE *file;
@@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void)
 	static LIST_HEAD(terms);
 	static LIST_HEAD(terms);
 	unsigned int i;
 	unsigned int i;
 
 
-	for (i = 0; i < TERMS_CNT; i++)
+	for (i = 0; i < ARRAY_SIZE(test_terms); i++)
 		list_add_tail(&test_terms[i].list, &terms);
 		list_add_tail(&test_terms[i].list, &terms);
 
 
 	return &terms;
 	return &terms;
 }
 }
 
 
-#undef TERMS_CNT
-
 int test__pmu(void)
 int test__pmu(void)
 {
 {
 	char *format = test_format_dir_get();
 	char *format = test_format_dir_get();

+ 23 - 0
tools/perf/tests/python-use.c

@@ -0,0 +1,23 @@
+/*
+ * Just test if we can load the python binding.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "tests.h"
+
+extern int verbose;
+
+int test__python_use(void)
+{
+	char *cmd;
+	int ret;
+
+	if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s",
+		     PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0)
+		return -1;
+
+	ret = system(cmd) ? -1 : 0;
+	free(cmd);
+	return ret;
+}

+ 8 - 0
tools/perf/tests/tests.h

@@ -1,6 +1,12 @@
 #ifndef TESTS_H
 #ifndef TESTS_H
 #define TESTS_H
 #define TESTS_H
 
 
+enum {
+	TEST_OK   =  0,
+	TEST_FAIL = -1,
+	TEST_SKIP = -2,
+};
+
 /* Tests */
 /* Tests */
 int test__vmlinux_matches_kallsyms(void);
 int test__vmlinux_matches_kallsyms(void);
 int test__open_syscall_event(void);
 int test__open_syscall_event(void);
@@ -15,5 +21,7 @@ int test__pmu(void);
 int test__attr(void);
 int test__attr(void);
 int test__dso_data(void);
 int test__dso_data(void);
 int test__parse_events(void);
 int test__parse_events(void);
+int test__hists_link(void);
+int test__python_use(void);
 
 
 #endif /* TESTS_H */
 #endif /* TESTS_H */

+ 2 - 1
tools/perf/tests/vmlinux-kallsyms.c

@@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void)
 	 */
 	 */
 	if (machine__load_vmlinux_path(&vmlinux, type,
 	if (machine__load_vmlinux_path(&vmlinux, type,
 				       vmlinux_matches_kallsyms_filter) <= 0) {
 				       vmlinux_matches_kallsyms_filter) <= 0) {
-		pr_debug("machine__load_vmlinux_path ");
+		pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
+		err = TEST_SKIP;
 		goto out;
 		goto out;
 	}
 	}
 
 

+ 2 - 2
tools/perf/ui/browser.c

@@ -471,7 +471,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
 	return row;
 	return row;
 }
 }
 
 
-static struct ui_browser__colorset {
+static struct ui_browser_colorset {
 	const char *name, *fg, *bg;
 	const char *name, *fg, *bg;
 	int colorset;
 	int colorset;
 } ui_browser__colorsets[] = {
 } ui_browser__colorsets[] = {
@@ -706,7 +706,7 @@ void ui_browser__init(void)
 	perf_config(ui_browser__color_config, NULL);
 	perf_config(ui_browser__color_config, NULL);
 
 
 	while (ui_browser__colorsets[i].name) {
 	while (ui_browser__colorsets[i].name) {
-		struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
+		struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
 		sltt_set_color(c->colorset, c->name, c->fg, c->bg);
 		sltt_set_color(c->colorset, c->name, c->fg, c->bg);
 	}
 	}
 
 

+ 17 - 16
tools/perf/ui/browsers/annotate.c

@@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
 		ab->selection = dl;
 		ab->selection = dl;
 }
 }
 
 
+static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
+{
+	if (!dl || !dl->ins || !ins__is_jump(dl->ins)
+	    || !disasm_line__has_offset(dl)
+	    || dl->ops.target.offset >= symbol__size(sym))
+		return false;
+
+	return true;
+}
+
 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 {
 {
 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
 	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)
 	if (strstr(sym->name, "@plt"))
 	if (strstr(sym->name, "@plt"))
 		return;
 		return;
 
 
-	if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
-	    !disasm_line__has_offset(cursor))
+	if (!disasm_line__is_valid_jump(cursor, sym))
 		return;
 		return;
 
 
 	target = ab->offsets[cursor->ops.target.offset];
 	target = ab->offsets[cursor->ops.target.offset];
@@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
 		struct disasm_line *dl = browser->offsets[offset], *dlt;
 		struct disasm_line *dl = browser->offsets[offset], *dlt;
 		struct browser_disasm_line *bdlt;
 		struct browser_disasm_line *bdlt;
 
 
-		if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
-		    !disasm_line__has_offset(dl))
+		if (!disasm_line__is_valid_jump(dl, sym))
 			continue;
 			continue;
 
 
-		if (dl->ops.target.offset >= size) {
-			ui__error("jump to after symbol!\n"
-				  "size: %zx, jump target: %" PRIx64,
-				  size, dl->ops.target.offset);
-			continue;
-		}
-
 		dlt = browser->offsets[dl->ops.target.offset];
 		dlt = browser->offsets[dl->ops.target.offset];
 		/*
 		/*
  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
  		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -921,11 +922,11 @@ out_free_offsets:
 
 
 #define ANNOTATE_CFG(n) \
 #define ANNOTATE_CFG(n) \
 	{ .name = #n, .value = &annotate_browser__opts.n, }
 	{ .name = #n, .value = &annotate_browser__opts.n, }
-	
+
 /*
 /*
  * Keep the entries sorted, they are bsearch'ed
  * Keep the entries sorted, they are bsearch'ed
  */
  */
-static struct annotate__config {
+static struct annotate_config {
 	const char *name;
 	const char *name;
 	bool *value;
 	bool *value;
 } annotate__configs[] = {
 } annotate__configs[] = {
@@ -939,7 +940,7 @@ static struct annotate__config {
 
 
 static int annotate_config__cmp(const void *name, const void *cfgp)
 static int annotate_config__cmp(const void *name, const void *cfgp)
 {
 {
-	const struct annotate__config *cfg = cfgp;
+	const struct annotate_config *cfg = cfgp;
 
 
 	return strcmp(name, cfg->name);
 	return strcmp(name, cfg->name);
 }
 }
@@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
 static int annotate__config(const char *var, const char *value,
 static int annotate__config(const char *var, const char *value,
 			    void *data __maybe_unused)
 			    void *data __maybe_unused)
 {
 {
-	struct annotate__config *cfg;
+	struct annotate_config *cfg;
 	const char *name;
 	const char *name;
 
 
 	if (prefixcmp(var, "annotate.") != 0)
 	if (prefixcmp(var, "annotate.") != 0)
@@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value,
 
 
 	name = var + 9;
 	name = var + 9;
 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
 	cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
-		      sizeof(struct annotate__config), annotate_config__cmp);
+		      sizeof(struct annotate_config), annotate_config__cmp);
 
 
 	if (cfg == NULL)
 	if (cfg == NULL)
 		return -1;
 		return -1;

+ 5 - 222
tools/perf/ui/gtk/browser.c

@@ -8,15 +8,13 @@
 
 
 #include <signal.h>
 #include <signal.h>
 
 
-#define MAX_COLUMNS			32
-
-static void perf_gtk__signal(int sig)
+void perf_gtk__signal(int sig)
 {
 {
 	perf_gtk__exit(false);
 	perf_gtk__exit(false);
 	psignal(sig, "perf");
 	psignal(sig, "perf");
 }
 }
 
 
-static void perf_gtk__resize_window(GtkWidget *window)
+void perf_gtk__resize_window(GtkWidget *window)
 {
 {
 	GdkRectangle rect;
 	GdkRectangle rect;
 	GdkScreen *screen;
 	GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
 	gtk_window_resize(GTK_WINDOW(window), width, height);
 	gtk_window_resize(GTK_WINDOW(window), width, height);
 }
 }
 
 
-static const char *perf_gtk__get_percent_color(double percent)
+const char *perf_gtk__get_percent_color(double percent)
 {
 {
 	if (percent >= MIN_RED)
 	if (percent >= MIN_RED)
 		return "<span fgcolor='red'>";
 		return "<span fgcolor='red'>";
@@ -45,147 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
 	return NULL;
 	return NULL;
 }
 }
 
 
-#define HPP__COLOR_FN(_name, _field)						\
-static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp,			\
-					 struct hist_entry *he)			\
-{										\
-	struct hists *hists = he->hists;					\
-	double percent = 100.0 * he->stat._field / hists->stats.total_period;	\
-	const char *markup;							\
-	int ret = 0;								\
-										\
-	markup = perf_gtk__get_percent_color(percent);				\
-	if (markup)								\
-		ret += scnprintf(hpp->buf, hpp->size, "%s", markup);		\
-	ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); 	\
-	if (markup)								\
-		ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); 	\
-										\
-	return ret;								\
-}
-
-HPP__COLOR_FN(overhead, period)
-HPP__COLOR_FN(overhead_sys, period_sys)
-HPP__COLOR_FN(overhead_us, period_us)
-HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
-HPP__COLOR_FN(overhead_guest_us, period_guest_us)
-
-#undef HPP__COLOR_FN
-
-void perf_gtk__init_hpp(void)
-{
-	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
-
-	perf_hpp__init();
-
-	perf_hpp__format[PERF_HPP__OVERHEAD].color =
-				perf_gtk__hpp_color_overhead;
-	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
-				perf_gtk__hpp_color_overhead_sys;
-	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
-				perf_gtk__hpp_color_overhead_us;
-	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
-				perf_gtk__hpp_color_overhead_guest_sys;
-	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
-				perf_gtk__hpp_color_overhead_guest_us;
-}
-
-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
-{
-	struct perf_hpp_fmt *fmt;
-	GType col_types[MAX_COLUMNS];
-	GtkCellRenderer *renderer;
-	struct sort_entry *se;
-	GtkListStore *store;
-	struct rb_node *nd;
-	GtkWidget *view;
-	int col_idx;
-	int nr_cols;
-	char s[512];
-
-	struct perf_hpp hpp = {
-		.buf		= s,
-		.size		= sizeof(s),
-	};
-
-	nr_cols = 0;
-
-	perf_hpp__for_each_format(fmt)
-		col_types[nr_cols++] = G_TYPE_STRING;
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-
-		col_types[nr_cols++] = G_TYPE_STRING;
-	}
-
-	store = gtk_list_store_newv(nr_cols, col_types);
-
-	view = gtk_tree_view_new();
-
-	renderer = gtk_cell_renderer_text_new();
-
-	col_idx = 0;
-
-	perf_hpp__for_each_format(fmt) {
-		fmt->header(&hpp);
-		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-							    -1, s,
-							    renderer, "markup",
-							    col_idx++, NULL);
-	}
-
-	list_for_each_entry(se, &hist_entry__sort_list, list) {
-		if (se->elide)
-			continue;
-
-		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-							    -1, se->se_header,
-							    renderer, "text",
-							    col_idx++, NULL);
-	}
-
-	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
-
-	g_object_unref(GTK_TREE_MODEL(store));
-
-	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
-		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-		GtkTreeIter iter;
-
-		if (h->filtered)
-			continue;
-
-		gtk_list_store_append(store, &iter);
-
-		col_idx = 0;
-
-		perf_hpp__for_each_format(fmt) {
-			if (fmt->color)
-				fmt->color(&hpp, h);
-			else
-				fmt->entry(&hpp, h);
-
-			gtk_list_store_set(store, &iter, col_idx++, s, -1);
-		}
-
-		list_for_each_entry(se, &hist_entry__sort_list, list) {
-			if (se->elide)
-				continue;
-
-			se->se_snprintf(h, s, ARRAY_SIZE(s),
-					hists__col_len(hists, se->se_width_idx));
-
-			gtk_list_store_set(store, &iter, col_idx++, s, -1);
-		}
-	}
-
-	gtk_container_add(GTK_CONTAINER(window), view);
-}
-
 #ifdef HAVE_GTK_INFO_BAR
 #ifdef HAVE_GTK_INFO_BAR
-static GtkWidget *perf_gtk__setup_info_bar(void)
+GtkWidget *perf_gtk__setup_info_bar(void)
 {
 {
 	GtkWidget *info_bar;
 	GtkWidget *info_bar;
 	GtkWidget *label;
 	GtkWidget *label;
@@ -212,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
 }
 }
 #endif
 #endif
 
 
-static GtkWidget *perf_gtk__setup_statusbar(void)
+GtkWidget *perf_gtk__setup_statusbar(void)
 {
 {
 	GtkWidget *stbar;
 	GtkWidget *stbar;
 	unsigned ctxid;
 	unsigned ctxid;
@@ -226,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
 
 
 	return stbar;
 	return stbar;
 }
 }
-
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
-				  const char *help,
-				  struct hist_browser_timer *hbt __maybe_unused)
-{
-	struct perf_evsel *pos;
-	GtkWidget *vbox;
-	GtkWidget *notebook;
-	GtkWidget *info_bar;
-	GtkWidget *statbar;
-	GtkWidget *window;
-
-	signal(SIGSEGV, perf_gtk__signal);
-	signal(SIGFPE,  perf_gtk__signal);
-	signal(SIGINT,  perf_gtk__signal);
-	signal(SIGQUIT, perf_gtk__signal);
-	signal(SIGTERM, perf_gtk__signal);
-
-	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-	gtk_window_set_title(GTK_WINDOW(window), "perf report");
-
-	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
-
-	pgctx = perf_gtk__activate_context(window);
-	if (!pgctx)
-		return -1;
-
-	vbox = gtk_vbox_new(FALSE, 0);
-
-	notebook = gtk_notebook_new();
-
-	list_for_each_entry(pos, &evlist->entries, node) {
-		struct hists *hists = &pos->hists;
-		const char *evname = perf_evsel__name(pos);
-		GtkWidget *scrolled_window;
-		GtkWidget *tab_label;
-
-		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-
-		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-							GTK_POLICY_AUTOMATIC,
-							GTK_POLICY_AUTOMATIC);
-
-		perf_gtk__show_hists(scrolled_window, hists);
-
-		tab_label = gtk_label_new(evname);
-
-		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
-	}
-
-	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-	info_bar = perf_gtk__setup_info_bar();
-	if (info_bar)
-		gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
-
-	statbar = perf_gtk__setup_statusbar();
-	gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
-
-	gtk_container_add(GTK_CONTAINER(window), vbox);
-
-	gtk_widget_show_all(window);
-
-	perf_gtk__resize_window(window);
-
-	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-
-	ui_helpline__push(help);
-
-	gtk_main();
-
-	perf_gtk__deactivate_context(&pgctx);
-
-	return 0;
-}

+ 8 - 1
tools/perf/ui/gtk/gtk.h

@@ -33,7 +33,14 @@ void perf_gtk__init_helpline(void);
 void perf_gtk__init_progress(void);
 void perf_gtk__init_progress(void);
 void perf_gtk__init_hpp(void);
 void perf_gtk__init_hpp(void);
 
 
-#ifndef HAVE_GTK_INFO_BAR
+void perf_gtk__signal(int sig);
+void perf_gtk__resize_window(GtkWidget *window);
+const char *perf_gtk__get_percent_color(double percent);
+GtkWidget *perf_gtk__setup_statusbar(void);
+
+#ifdef HAVE_GTK_INFO_BAR
+GtkWidget *perf_gtk__setup_info_bar(void);
+#else
 static inline GtkWidget *perf_gtk__setup_info_bar(void)
 static inline GtkWidget *perf_gtk__setup_info_bar(void)
 {
 {
 	return NULL;
 	return NULL;

+ 226 - 0
tools/perf/ui/gtk/hists.c

@@ -0,0 +1,226 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "../helpline.h"
+#include "gtk.h"
+
+#define MAX_COLUMNS			32
+
+#define HPP__COLOR_FN(_name, _field)						\
+static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp,			\
+					 struct hist_entry *he)			\
+{										\
+	struct hists *hists = he->hists;					\
+	double percent = 100.0 * he->stat._field / hists->stats.total_period;	\
+	const char *markup;							\
+	int ret = 0;								\
+										\
+	markup = perf_gtk__get_percent_color(percent);				\
+	if (markup)								\
+		ret += scnprintf(hpp->buf, hpp->size, "%s", markup);		\
+	ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); 	\
+	if (markup)								\
+		ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); 	\
+										\
+	return ret;								\
+}
+
+HPP__COLOR_FN(overhead, period)
+HPP__COLOR_FN(overhead_sys, period_sys)
+HPP__COLOR_FN(overhead_us, period_us)
+HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
+HPP__COLOR_FN(overhead_guest_us, period_guest_us)
+
+#undef HPP__COLOR_FN
+
+
+void perf_gtk__init_hpp(void)
+{
+	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
+	perf_hpp__init();
+
+	perf_hpp__format[PERF_HPP__OVERHEAD].color =
+				perf_gtk__hpp_color_overhead;
+	perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
+				perf_gtk__hpp_color_overhead_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
+				perf_gtk__hpp_color_overhead_us;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
+				perf_gtk__hpp_color_overhead_guest_sys;
+	perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
+				perf_gtk__hpp_color_overhead_guest_us;
+}
+
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+{
+	struct perf_hpp_fmt *fmt;
+	GType col_types[MAX_COLUMNS];
+	GtkCellRenderer *renderer;
+	struct sort_entry *se;
+	GtkListStore *store;
+	struct rb_node *nd;
+	GtkWidget *view;
+	int col_idx;
+	int nr_cols;
+	char s[512];
+
+	struct perf_hpp hpp = {
+		.buf		= s,
+		.size		= sizeof(s),
+	};
+
+	nr_cols = 0;
+
+	perf_hpp__for_each_format(fmt)
+		col_types[nr_cols++] = G_TYPE_STRING;
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		col_types[nr_cols++] = G_TYPE_STRING;
+	}
+
+	store = gtk_list_store_newv(nr_cols, col_types);
+
+	view = gtk_tree_view_new();
+
+	renderer = gtk_cell_renderer_text_new();
+
+	col_idx = 0;
+
+	perf_hpp__for_each_format(fmt) {
+		fmt->header(&hpp);
+
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+							    -1, s,
+							    renderer, "markup",
+							    col_idx++, NULL);
+	}
+
+	list_for_each_entry(se, &hist_entry__sort_list, list) {
+		if (se->elide)
+			continue;
+
+		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+							    -1, se->se_header,
+							    renderer, "text",
+							    col_idx++, NULL);
+	}
+
+	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+	g_object_unref(GTK_TREE_MODEL(store));
+
+	for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+		GtkTreeIter iter;
+
+		if (h->filtered)
+			continue;
+
+		gtk_list_store_append(store, &iter);
+
+		col_idx = 0;
+
+		perf_hpp__for_each_format(fmt) {
+			if (fmt->color)
+				fmt->color(&hpp, h);
+			else
+				fmt->entry(&hpp, h);
+
+			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+		}
+
+		list_for_each_entry(se, &hist_entry__sort_list, list) {
+			if (se->elide)
+				continue;
+
+			se->se_snprintf(h, s, ARRAY_SIZE(s),
+					hists__col_len(hists, se->se_width_idx));
+
+			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+		}
+	}
+
+	gtk_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+				  const char *help,
+				  struct hist_browser_timer *hbt __maybe_unused)
+{
+	struct perf_evsel *pos;
+	GtkWidget *vbox;
+	GtkWidget *notebook;
+	GtkWidget *info_bar;
+	GtkWidget *statbar;
+	GtkWidget *window;
+
+	signal(SIGSEGV, perf_gtk__signal);
+	signal(SIGFPE,  perf_gtk__signal);
+	signal(SIGINT,  perf_gtk__signal);
+	signal(SIGQUIT, perf_gtk__signal);
+	signal(SIGTERM, perf_gtk__signal);
+
+	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+	gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+	g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+	pgctx = perf_gtk__activate_context(window);
+	if (!pgctx)
+		return -1;
+
+	vbox = gtk_vbox_new(FALSE, 0);
+
+	notebook = gtk_notebook_new();
+
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+	info_bar = perf_gtk__setup_info_bar();
+	if (info_bar)
+		gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
+	statbar = perf_gtk__setup_statusbar();
+	gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+	gtk_container_add(GTK_CONTAINER(window), vbox);
+
+	list_for_each_entry(pos, &evlist->entries, node) {
+		struct hists *hists = &pos->hists;
+		const char *evname = perf_evsel__name(pos);
+		GtkWidget *scrolled_window;
+		GtkWidget *tab_label;
+
+		scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+							GTK_POLICY_AUTOMATIC,
+							GTK_POLICY_AUTOMATIC);
+
+		perf_gtk__show_hists(scrolled_window, hists);
+
+		tab_label = gtk_label_new(evname);
+
+		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+	}
+
+	gtk_widget_show_all(window);
+
+	perf_gtk__resize_window(window);
+
+	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+	ui_helpline__push(help);
+
+	gtk_main();
+
+	perf_gtk__deactivate_context(&pgctx);
+
+	return 0;
+}

+ 3 - 3
tools/perf/ui/stdio/hist.c

@@ -459,7 +459,7 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
 {
 {
 	int i;
 	int i;
 	size_t ret = 0;
 	size_t ret = 0;
@@ -467,7 +467,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
 	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
 	for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
 		const char *name;
 		const char *name;
 
 
-		if (hists->stats.nr_events[i] == 0)
+		if (stats->nr_events[i] == 0)
 			continue;
 			continue;
 
 
 		name = perf_event__name(i);
 		name = perf_event__name(i);
@@ -475,7 +475,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
 			continue;
 			continue;
 
 
 		ret += fprintf(fp, "%16s events: %10d\n", name,
 		ret += fprintf(fp, "%16s events: %10d\n", name,
-			       hists->stats.nr_events[i]);
+			       stats->nr_events[i]);
 	}
 	}
 
 
 	return ret;
 	return ret;

+ 0 - 11
tools/perf/ui/util.c

@@ -52,17 +52,6 @@ int ui__warning(const char *format, ...)
 	return ret;
 	return ret;
 }
 }
 
 
-int ui__error_paranoid(void)
-{
-	return ui__error("Permission error - are you root?\n"
-		    "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
-		    " -1 - Not paranoid at all\n"
-		    "  0 - Disallow raw tracepoint access for unpriv\n"
-		    "  1 - Disallow cpu events for unpriv\n"
-		    "  2 - Disallow kernel profiling for unpriv\n");
-}
-
-
 /**
 /**
  * perf_error__register - Register error logging functions
  * perf_error__register - Register error logging functions
  * @eops: The pointer to error logging function struct
  * @eops: The pointer to error logging function struct

+ 2 - 2
tools/perf/util/PERF-VERSION-GEN

@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
 
 
 if test -r $GVF
 if test -r $GVF
 then
 then
-	VC=$(sed -e 's/^PERF_VERSION = //' <$GVF)
+	VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
 else
 else
 	VC=unset
 	VC=unset
 fi
 fi
 test "$VN" = "$VC" || {
 test "$VN" = "$VC" || {
 	echo >&2 "PERF_VERSION = $VN"
 	echo >&2 "PERF_VERSION = $VN"
-	echo "PERF_VERSION = $VN" >$GVF
+	echo "#define PERF_VERSION \"$VN\"" >$GVF
 }
 }
 
 
 
 

+ 0 - 1
tools/perf/util/debug.h

@@ -16,6 +16,5 @@ void trace_event(union perf_event *event);
 
 
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
-int ui__error_paranoid(void);
 
 
 #endif	/* __PERF_DEBUG_H */
 #endif	/* __PERF_DEBUG_H */

+ 105 - 3
tools/perf/util/evsel.c

@@ -22,6 +22,11 @@
 #include <linux/perf_event.h>
 #include <linux/perf_event.h>
 #include "perf_regs.h"
 #include "perf_regs.h"
 
 
+static struct {
+	bool sample_id_all;
+	bool exclude_guest;
+} perf_missing_features;
+
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
 
 static int __perf_evsel__sample_size(u64 sample_type)
 static int __perf_evsel__sample_size(u64 sample_type)
@@ -463,7 +468,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
 	struct perf_event_attr *attr = &evsel->attr;
 	struct perf_event_attr *attr = &evsel->attr;
 	int track = !evsel->idx; /* only the first counter needs these */
 	int track = !evsel->idx; /* only the first counter needs these */
 
 
-	attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
+	attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
 	attr->inherit	    = !opts->no_inherit;
 	attr->inherit	    = !opts->no_inherit;
 
 
 	perf_evsel__set_sample_bit(evsel, IP);
 	perf_evsel__set_sample_bit(evsel, IP);
@@ -513,7 +518,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
 	if (opts->period)
 	if (opts->period)
 		perf_evsel__set_sample_bit(evsel, PERIOD);
 		perf_evsel__set_sample_bit(evsel, PERIOD);
 
 
-	if (!opts->sample_id_all_missing &&
+	if (!perf_missing_features.sample_id_all &&
 	    (opts->sample_time || !opts->no_inherit ||
 	    (opts->sample_time || !opts->no_inherit ||
 	     perf_target__has_cpu(&opts->target)))
 	     perf_target__has_cpu(&opts->target)))
 		perf_evsel__set_sample_bit(evsel, TIME);
 		perf_evsel__set_sample_bit(evsel, TIME);
@@ -761,6 +766,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 		pid = evsel->cgrp->fd;
 		pid = evsel->cgrp->fd;
 	}
 	}
 
 
+fallback_missing_features:
+	if (perf_missing_features.exclude_guest)
+		evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
+retry_sample_id:
+	if (perf_missing_features.sample_id_all)
+		evsel->attr.sample_id_all = 0;
+
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
 
 
 		for (thread = 0; thread < threads->nr; thread++) {
 		for (thread = 0; thread < threads->nr; thread++) {
@@ -777,13 +789,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 								     group_fd, flags);
 								     group_fd, flags);
 			if (FD(evsel, cpu, thread) < 0) {
 			if (FD(evsel, cpu, thread) < 0) {
 				err = -errno;
 				err = -errno;
-				goto out_close;
+				goto try_fallback;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
+try_fallback:
+	if (err != -EINVAL || cpu > 0 || thread > 0)
+		goto out_close;
+
+	if (!perf_missing_features.exclude_guest &&
+	    (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+		perf_missing_features.exclude_guest = true;
+		goto fallback_missing_features;
+	} else if (!perf_missing_features.sample_id_all) {
+		perf_missing_features.sample_id_all = true;
+		goto retry_sample_id;
+	}
+
 out_close:
 out_close:
 	do {
 	do {
 		while (--thread >= 0) {
 		while (--thread >= 0) {
@@ -1353,3 +1378,80 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
 	fputc('\n', fp);
 	fputc('\n', fp);
 	return ++printed;
 	return ++printed;
 }
 }
+
+bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
+			  char *msg, size_t msgsize)
+{
+	if ((err == ENOENT || err == ENXIO) &&
+	    evsel->attr.type   == PERF_TYPE_HARDWARE &&
+	    evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
+		/*
+		 * If it's cycles then fall back to hrtimer based
+		 * cpu-clock-tick sw counter, which is always available even if
+		 * no PMU support.
+		 *
+		 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
+		 * b0a873e).
+		 */
+		scnprintf(msg, msgsize, "%s",
+"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
+
+		evsel->attr.type   = PERF_TYPE_SOFTWARE;
+		evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
+
+		free(evsel->name);
+		evsel->name = NULL;
+		return true;
+	}
+
+	return false;
+}
+
+int perf_evsel__open_strerror(struct perf_evsel *evsel,
+			      struct perf_target *target,
+			      int err, char *msg, size_t size)
+{
+	switch (err) {
+	case EPERM:
+	case EACCES:
+		return scnprintf(msg, size, "%s",
+		 "You may not have permission to collect %sstats.\n"
+		 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
+		 " -1 - Not paranoid at all\n"
+		 "  0 - Disallow raw tracepoint access for unpriv\n"
+		 "  1 - Disallow cpu events for unpriv\n"
+		 "  2 - Disallow kernel profiling for unpriv",
+				 target->system_wide ? "system-wide " : "");
+	case ENOENT:
+		return scnprintf(msg, size, "The %s event is not supported.",
+				 perf_evsel__name(evsel));
+	case EMFILE:
+		return scnprintf(msg, size, "%s",
+			 "Too many events are opened.\n"
+			 "Try again after reducing the number of events.");
+	case ENODEV:
+		if (target->cpu_list)
+			return scnprintf(msg, size, "%s",
+	 "No such device - did you specify an out-of-range profile CPU?\n");
+		break;
+	case EOPNOTSUPP:
+		if (evsel->attr.precise_ip)
+			return scnprintf(msg, size, "%s",
+	"\'precise\' request may not be supported. Try removing 'p' modifier.");
+#if defined(__i386__) || defined(__x86_64__)
+		if (evsel->attr.type == PERF_TYPE_HARDWARE)
+			return scnprintf(msg, size, "%s",
+	"No hardware sampling interrupt available.\n"
+	"No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
+#endif
+		break;
+	default:
+		break;
+	}
+
+	return scnprintf(msg, size,
+	"The sys_perf_event_open() syscall returned with %d (%s) for event (%s).  \n"
+	"/bin/dmesg may provide additional information.\n"
+	"No CONFIG_PERF_EVENTS=y kernel support configured?\n",
+			 err, strerror(err), perf_evsel__name(evsel));
+}

+ 6 - 0
tools/perf/util/evsel.h

@@ -251,4 +251,10 @@ struct perf_attr_details {
 
 
 int perf_evsel__fprintf(struct perf_evsel *evsel,
 int perf_evsel__fprintf(struct perf_evsel *evsel,
 			struct perf_attr_details *details, FILE *fp);
 			struct perf_attr_details *details, FILE *fp);
+
+bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
+			  char *msg, size_t msgsize);
+int perf_evsel__open_strerror(struct perf_evsel *evsel,
+			      struct perf_target *target,
+			      int err, char *msg, size_t size);
 #endif /* __PERF_EVSEL_H */
 #endif /* __PERF_EVSEL_H */

+ 42 - 33
tools/perf/util/header.c

@@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
 	u32 len;
 	u32 len;
 	char *buf;
 	char *buf;
 
 
-	sz = read(fd, &len, sizeof(len));
+	sz = readn(fd, &len, sizeof(len));
 	if (sz < (ssize_t)sizeof(len))
 	if (sz < (ssize_t)sizeof(len))
 		return NULL;
 		return NULL;
 
 
@@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
 	if (!buf)
 	if (!buf)
 		return NULL;
 		return NULL;
 
 
-	ret = read(fd, buf, len);
+	ret = readn(fd, buf, len);
 	if (ret == (ssize_t)len) {
 	if (ret == (ssize_t)len) {
 		/*
 		/*
 		 * strings are padded by zeroes
 		 * strings are padded by zeroes
@@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
 	struct perf_session *session = container_of(header,
 	struct perf_session *session = container_of(header,
 			struct perf_session, header);
 			struct perf_session, header);
 	struct rb_node *nd;
 	struct rb_node *nd;
-	int err = machine__write_buildid_table(&session->host_machine, fd);
+	int err = machine__write_buildid_table(&session->machines.host, fd);
 
 
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		err = machine__write_buildid_table(pos, fd);
 		err = machine__write_buildid_table(pos, fd);
 		if (err)
 		if (err)
@@ -448,9 +448,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
 	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
 	if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
 		return -1;
 		return -1;
 
 
-	ret = machine__cache_build_ids(&session->host_machine, debugdir);
+	ret = machine__cache_build_ids(&session->machines.host, debugdir);
 
 
-	for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		ret |= machine__cache_build_ids(pos, debugdir);
 		ret |= machine__cache_build_ids(pos, debugdir);
 	}
 	}
@@ -467,9 +467,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits)
 static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
 static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
 {
 {
 	struct rb_node *nd;
 	struct rb_node *nd;
-	bool ret = machine__read_build_ids(&session->host_machine, with_hits);
+	bool ret = machine__read_build_ids(&session->machines.host, with_hits);
 
 
-	for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		ret |= machine__read_build_ids(pos, with_hits);
 		ret |= machine__read_build_ids(pos, with_hits);
 	}
 	}
@@ -1051,16 +1051,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
 	struct perf_pmu *pmu = NULL;
 	struct perf_pmu *pmu = NULL;
 	off_t offset = lseek(fd, 0, SEEK_CUR);
 	off_t offset = lseek(fd, 0, SEEK_CUR);
 	__u32 pmu_num = 0;
 	__u32 pmu_num = 0;
+	int ret;
 
 
 	/* write real pmu_num later */
 	/* write real pmu_num later */
-	do_write(fd, &pmu_num, sizeof(pmu_num));
+	ret = do_write(fd, &pmu_num, sizeof(pmu_num));
+	if (ret < 0)
+		return ret;
 
 
 	while ((pmu = perf_pmu__scan(pmu))) {
 	while ((pmu = perf_pmu__scan(pmu))) {
 		if (!pmu->name)
 		if (!pmu->name)
 			continue;
 			continue;
 		pmu_num++;
 		pmu_num++;
-		do_write(fd, &pmu->type, sizeof(pmu->type));
-		do_write_string(fd, pmu->name);
+
+		ret = do_write(fd, &pmu->type, sizeof(pmu->type));
+		if (ret < 0)
+			return ret;
+
+		ret = do_write_string(fd, pmu->name);
+		if (ret < 0)
+			return ret;
 	}
 	}
 
 
 	if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
 	if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1209,14 +1218,14 @@ read_event_desc(struct perf_header *ph, int fd)
 	size_t msz;
 	size_t msz;
 
 
 	/* number of events */
 	/* number of events */
-	ret = read(fd, &nre, sizeof(nre));
+	ret = readn(fd, &nre, sizeof(nre));
 	if (ret != (ssize_t)sizeof(nre))
 	if (ret != (ssize_t)sizeof(nre))
 		goto error;
 		goto error;
 
 
 	if (ph->needs_swap)
 	if (ph->needs_swap)
 		nre = bswap_32(nre);
 		nre = bswap_32(nre);
 
 
-	ret = read(fd, &sz, sizeof(sz));
+	ret = readn(fd, &sz, sizeof(sz));
 	if (ret != (ssize_t)sizeof(sz))
 	if (ret != (ssize_t)sizeof(sz))
 		goto error;
 		goto error;
 
 
@@ -1244,7 +1253,7 @@ read_event_desc(struct perf_header *ph, int fd)
 		 * must read entire on-file attr struct to
 		 * must read entire on-file attr struct to
 		 * sync up with layout.
 		 * sync up with layout.
 		 */
 		 */
-		ret = read(fd, buf, sz);
+		ret = readn(fd, buf, sz);
 		if (ret != (ssize_t)sz)
 		if (ret != (ssize_t)sz)
 			goto error;
 			goto error;
 
 
@@ -1253,7 +1262,7 @@ read_event_desc(struct perf_header *ph, int fd)
 
 
 		memcpy(&evsel->attr, buf, msz);
 		memcpy(&evsel->attr, buf, msz);
 
 
-		ret = read(fd, &nr, sizeof(nr));
+		ret = readn(fd, &nr, sizeof(nr));
 		if (ret != (ssize_t)sizeof(nr))
 		if (ret != (ssize_t)sizeof(nr))
 			goto error;
 			goto error;
 
 
@@ -1274,7 +1283,7 @@ read_event_desc(struct perf_header *ph, int fd)
 		evsel->id = id;
 		evsel->id = id;
 
 
 		for (j = 0 ; j < nr; j++) {
 		for (j = 0 ; j < nr; j++) {
-			ret = read(fd, id, sizeof(*id));
+			ret = readn(fd, id, sizeof(*id));
 			if (ret != (ssize_t)sizeof(*id))
 			if (ret != (ssize_t)sizeof(*id))
 				goto error;
 				goto error;
 			if (ph->needs_swap)
 			if (ph->needs_swap)
@@ -1506,14 +1515,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
 	while (offset < limit) {
 	while (offset < limit) {
 		ssize_t len;
 		ssize_t len;
 
 
-		if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
+		if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
 			return -1;
 			return -1;
 
 
 		if (header->needs_swap)
 		if (header->needs_swap)
 			perf_event_header__bswap(&old_bev.header);
 			perf_event_header__bswap(&old_bev.header);
 
 
 		len = old_bev.header.size - sizeof(old_bev);
 		len = old_bev.header.size - sizeof(old_bev);
-		if (read(input, filename, len) != len)
+		if (readn(input, filename, len) != len)
 			return -1;
 			return -1;
 
 
 		bev.header = old_bev.header;
 		bev.header = old_bev.header;
@@ -1548,14 +1557,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
 	while (offset < limit) {
 	while (offset < limit) {
 		ssize_t len;
 		ssize_t len;
 
 
-		if (read(input, &bev, sizeof(bev)) != sizeof(bev))
+		if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
 			goto out;
 			goto out;
 
 
 		if (header->needs_swap)
 		if (header->needs_swap)
 			perf_event_header__bswap(&bev.header);
 			perf_event_header__bswap(&bev.header);
 
 
 		len = bev.header.size - sizeof(bev);
 		len = bev.header.size - sizeof(bev);
-		if (read(input, filename, len) != len)
+		if (readn(input, filename, len) != len)
 			goto out;
 			goto out;
 		/*
 		/*
 		 * The a1645ce1 changeset:
 		 * The a1645ce1 changeset:
@@ -1641,7 +1650,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
 	size_t ret;
 	size_t ret;
 	u32 nr;
 	u32 nr;
 
 
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		return -1;
 		return -1;
 
 
@@ -1650,7 +1659,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
 
 
 	ph->env.nr_cpus_online = nr;
 	ph->env.nr_cpus_online = nr;
 
 
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		return -1;
 		return -1;
 
 
@@ -1684,7 +1693,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
 	uint64_t mem;
 	uint64_t mem;
 	size_t ret;
 	size_t ret;
 
 
-	ret = read(fd, &mem, sizeof(mem));
+	ret = readn(fd, &mem, sizeof(mem));
 	if (ret != sizeof(mem))
 	if (ret != sizeof(mem))
 		return -1;
 		return -1;
 
 
@@ -1756,7 +1765,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
 	u32 nr, i;
 	u32 nr, i;
 	struct strbuf sb;
 	struct strbuf sb;
 
 
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		return -1;
 		return -1;
 
 
@@ -1792,7 +1801,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
 	char *str;
 	char *str;
 	struct strbuf sb;
 	struct strbuf sb;
 
 
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		return -1;
 		return -1;
 
 
@@ -1813,7 +1822,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
 	}
 	}
 	ph->env.sibling_cores = strbuf_detach(&sb, NULL);
 	ph->env.sibling_cores = strbuf_detach(&sb, NULL);
 
 
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		return -1;
 		return -1;
 
 
@@ -1850,7 +1859,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
 	struct strbuf sb;
 	struct strbuf sb;
 
 
 	/* nr nodes */
 	/* nr nodes */
-	ret = read(fd, &nr, sizeof(nr));
+	ret = readn(fd, &nr, sizeof(nr));
 	if (ret != sizeof(nr))
 	if (ret != sizeof(nr))
 		goto error;
 		goto error;
 
 
@@ -1862,15 +1871,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
 
 
 	for (i = 0; i < nr; i++) {
 	for (i = 0; i < nr; i++) {
 		/* node number */
 		/* node number */
-		ret = read(fd, &node, sizeof(node));
+		ret = readn(fd, &node, sizeof(node));
 		if (ret != sizeof(node))
 		if (ret != sizeof(node))
 			goto error;
 			goto error;
 
 
-		ret = read(fd, &mem_total, sizeof(u64));
+		ret = readn(fd, &mem_total, sizeof(u64));
 		if (ret != sizeof(u64))
 		if (ret != sizeof(u64))
 			goto error;
 			goto error;
 
 
-		ret = read(fd, &mem_free, sizeof(u64));
+		ret = readn(fd, &mem_free, sizeof(u64));
 		if (ret != sizeof(u64))
 		if (ret != sizeof(u64))
 			goto error;
 			goto error;
 
 
@@ -1909,7 +1918,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
 	u32 type;
 	u32 type;
 	struct strbuf sb;
 	struct strbuf sb;
 
 
-	ret = read(fd, &pmu_num, sizeof(pmu_num));
+	ret = readn(fd, &pmu_num, sizeof(pmu_num));
 	if (ret != sizeof(pmu_num))
 	if (ret != sizeof(pmu_num))
 		return -1;
 		return -1;
 
 
@@ -1925,7 +1934,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
 	strbuf_init(&sb, 128);
 	strbuf_init(&sb, 128);
 
 
 	while (pmu_num) {
 	while (pmu_num) {
-		if (read(fd, &type, sizeof(type)) != sizeof(type))
+		if (readn(fd, &type, sizeof(type)) != sizeof(type))
 			goto error;
 			goto error;
 		if (ph->needs_swap)
 		if (ph->needs_swap)
 			type = bswap_32(type);
 			type = bswap_32(type);
@@ -2912,7 +2921,7 @@ int perf_event__process_tracing_data(union perf_event *event,
 				 session->repipe);
 				 session->repipe);
 	padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
 	padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
 
 
-	if (read(session->fd, buf, padding) < 0)
+	if (readn(session->fd, buf, padding) < 0)
 		die("reading input file");
 		die("reading input file");
 	if (session->repipe) {
 	if (session->repipe) {
 		int retw = write(STDOUT_FILENO, buf, padding);
 		int retw = write(STDOUT_FILENO, buf, padding);

+ 63 - 16
tools/perf/util/hist.c

@@ -82,6 +82,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 		hists__new_col_len(hists, HISTC_DSO, len);
 		hists__new_col_len(hists, HISTC_DSO, len);
 	}
 	}
 
 
+	if (h->parent)
+		hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
+
 	if (h->branch_info) {
 	if (h->branch_info) {
 		int symlen;
 		int symlen;
 		/*
 		/*
@@ -242,6 +245,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
 
 
 		if (he->ms.map)
 		if (he->ms.map)
 			he->ms.map->referenced = true;
 			he->ms.map->referenced = true;
+
+		if (he->branch_info) {
+			if (he->branch_info->from.map)
+				he->branch_info->from.map->referenced = true;
+			if (he->branch_info->to.map)
+				he->branch_info->to.map->referenced = true;
+		}
+
 		if (symbol_conf.use_callchain)
 		if (symbol_conf.use_callchain)
 			callchain_init(he->callchain);
 			callchain_init(he->callchain);
 
 
@@ -251,7 +262,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
 	return he;
 	return he;
 }
 }
 
 
-static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
+void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
 {
 {
 	if (!h->filtered) {
 	if (!h->filtered) {
 		hists__calc_col_len(hists, h);
 		hists__calc_col_len(hists, h);
@@ -285,7 +296,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
 		parent = *p;
 		parent = *p;
 		he = rb_entry(parent, struct hist_entry, rb_node_in);
 		he = rb_entry(parent, struct hist_entry, rb_node_in);
 
 
-		cmp = hist_entry__cmp(entry, he);
+		/*
+		 * Make sure that it receives arguments in a same order as
+		 * hist_entry__collapse() so that we can use an appropriate
+		 * function when searching an entry regardless which sort
+		 * keys were used.
+		 */
+		cmp = hist_entry__cmp(he, entry);
 
 
 		if (!cmp) {
 		if (!cmp) {
 			he_stat__add_period(&he->stat, period);
 			he_stat__add_period(&he->stat, period);
@@ -711,25 +728,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
 	return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 	return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 }
 }
 
 
+void events_stats__inc(struct events_stats *stats, u32 type)
+{
+	++stats->nr_events[0];
+	++stats->nr_events[type];
+}
+
 void hists__inc_nr_events(struct hists *hists, u32 type)
 void hists__inc_nr_events(struct hists *hists, u32 type)
 {
 {
-	++hists->stats.nr_events[0];
-	++hists->stats.nr_events[type];
+	events_stats__inc(&hists->stats, type);
 }
 }
 
 
 static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
 static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
 						 struct hist_entry *pair)
 						 struct hist_entry *pair)
 {
 {
-	struct rb_node **p = &hists->entries.rb_node;
+	struct rb_root *root;
+	struct rb_node **p;
 	struct rb_node *parent = NULL;
 	struct rb_node *parent = NULL;
 	struct hist_entry *he;
 	struct hist_entry *he;
 	int cmp;
 	int cmp;
 
 
+	if (sort__need_collapse)
+		root = &hists->entries_collapsed;
+	else
+		root = hists->entries_in;
+
+	p = &root->rb_node;
+
 	while (*p != NULL) {
 	while (*p != NULL) {
 		parent = *p;
 		parent = *p;
-		he = rb_entry(parent, struct hist_entry, rb_node);
+		he = rb_entry(parent, struct hist_entry, rb_node_in);
 
 
-		cmp = hist_entry__cmp(pair, he);
+		cmp = hist_entry__collapse(he, pair);
 
 
 		if (!cmp)
 		if (!cmp)
 			goto out;
 			goto out;
@@ -744,8 +774,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
 	if (he) {
 	if (he) {
 		memset(&he->stat, 0, sizeof(he->stat));
 		memset(&he->stat, 0, sizeof(he->stat));
 		he->hists = hists;
 		he->hists = hists;
-		rb_link_node(&he->rb_node, parent, p);
-		rb_insert_color(&he->rb_node, &hists->entries);
+		rb_link_node(&he->rb_node_in, parent, p);
+		rb_insert_color(&he->rb_node_in, root);
 		hists__inc_nr_entries(hists, he);
 		hists__inc_nr_entries(hists, he);
 	}
 	}
 out:
 out:
@@ -755,11 +785,16 @@ out:
 static struct hist_entry *hists__find_entry(struct hists *hists,
 static struct hist_entry *hists__find_entry(struct hists *hists,
 					    struct hist_entry *he)
 					    struct hist_entry *he)
 {
 {
-	struct rb_node *n = hists->entries.rb_node;
+	struct rb_node *n;
+
+	if (sort__need_collapse)
+		n = hists->entries_collapsed.rb_node;
+	else
+		n = hists->entries_in->rb_node;
 
 
 	while (n) {
 	while (n) {
-		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
-		int64_t cmp = hist_entry__cmp(he, iter);
+		struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
+		int64_t cmp = hist_entry__collapse(iter, he);
 
 
 		if (cmp < 0)
 		if (cmp < 0)
 			n = n->rb_left;
 			n = n->rb_left;
@@ -777,11 +812,17 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
  */
  */
 void hists__match(struct hists *leader, struct hists *other)
 void hists__match(struct hists *leader, struct hists *other)
 {
 {
+	struct rb_root *root;
 	struct rb_node *nd;
 	struct rb_node *nd;
 	struct hist_entry *pos, *pair;
 	struct hist_entry *pos, *pair;
 
 
-	for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) {
-		pos  = rb_entry(nd, struct hist_entry, rb_node);
+	if (sort__need_collapse)
+		root = &leader->entries_collapsed;
+	else
+		root = leader->entries_in;
+
+	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+		pos  = rb_entry(nd, struct hist_entry, rb_node_in);
 		pair = hists__find_entry(other, pos);
 		pair = hists__find_entry(other, pos);
 
 
 		if (pair)
 		if (pair)
@@ -796,11 +837,17 @@ void hists__match(struct hists *leader, struct hists *other)
  */
  */
 int hists__link(struct hists *leader, struct hists *other)
 int hists__link(struct hists *leader, struct hists *other)
 {
 {
+	struct rb_root *root;
 	struct rb_node *nd;
 	struct rb_node *nd;
 	struct hist_entry *pos, *pair;
 	struct hist_entry *pos, *pair;
 
 
-	for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) {
-		pos = rb_entry(nd, struct hist_entry, rb_node);
+	if (sort__need_collapse)
+		root = &other->entries_collapsed;
+	else
+		root = other->entries_in;
+
+	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+		pos = rb_entry(nd, struct hist_entry, rb_node_in);
 
 
 		if (!hist_entry__has_pairs(pos)) {
 		if (!hist_entry__has_pairs(pos)) {
 			pair = hists__add_dummy_entry(leader, pos);
 			pair = hists__add_dummy_entry(leader, pos);

+ 3 - 1
tools/perf/util/hist.h

@@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
 				   bool zap_kernel);
 				   bool zap_kernel);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
 
+void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
 void hists__inc_nr_events(struct hists *self, u32 type);
 void hists__inc_nr_events(struct hists *self, u32 type);
-size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
+void events_stats__inc(struct events_stats *stats, u32 type);
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
 
 
 size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
 size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
 		      int max_cols, FILE *fp);
 		      int max_cols, FILE *fp);

+ 1 - 0
tools/perf/util/include/linux/bitops.h

@@ -14,6 +14,7 @@
 #define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 #define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 #define BITS_TO_U64(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
 #define BITS_TO_U64(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
 #define BITS_TO_U32(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
 #define BITS_TO_U32(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
+#define BITS_TO_BYTES(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE)
 
 
 #define for_each_set_bit(bit, addr, size) \
 #define for_each_set_bit(bit, addr, size) \
 	for ((bit) = find_first_bit((addr), (size));		\
 	for ((bit) = find_first_bit((addr), (size));		\

+ 33 - 3
tools/perf/util/intlist.c

@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
 
 
 struct int_node *intlist__find(struct intlist *ilist, int i)
 struct int_node *intlist__find(struct intlist *ilist, int i)
 {
 {
-	struct int_node *node = NULL;
-	struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
+	struct int_node *node;
+	struct rb_node *rb_node;
 
 
+	if (ilist == NULL)
+		return NULL;
+
+	node = NULL;
+	rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
 	if (rb_node)
 	if (rb_node)
 		node = container_of(rb_node, struct int_node, rb_node);
 		node = container_of(rb_node, struct int_node, rb_node);
 
 
 	return node;
 	return node;
 }
 }
 
 
-struct intlist *intlist__new(void)
+static int intlist__parse_list(struct intlist *ilist, const char *s)
+{
+	char *sep;
+	int err;
+
+	do {
+		long value = strtol(s, &sep, 10);
+		err = -EINVAL;
+		if (*sep != ',' && *sep != '\0')
+			break;
+		err = intlist__add(ilist, value);
+		if (err)
+			break;
+		s = sep + 1;
+	} while (*sep != '\0');
+
+	return err;
+}
+
+struct intlist *intlist__new(const char *slist)
 {
 {
 	struct intlist *ilist = malloc(sizeof(*ilist));
 	struct intlist *ilist = malloc(sizeof(*ilist));
 
 
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
 		ilist->rblist.node_cmp    = intlist__node_cmp;
 		ilist->rblist.node_cmp    = intlist__node_cmp;
 		ilist->rblist.node_new    = intlist__node_new;
 		ilist->rblist.node_new    = intlist__node_new;
 		ilist->rblist.node_delete = intlist__node_delete;
 		ilist->rblist.node_delete = intlist__node_delete;
+
+		if (slist && intlist__parse_list(ilist, slist))
+			goto out_delete;
 	}
 	}
 
 
 	return ilist;
 	return ilist;
+out_delete:
+	intlist__delete(ilist);
+	return NULL;
 }
 }
 
 
 void intlist__delete(struct intlist *ilist)
 void intlist__delete(struct intlist *ilist)

+ 1 - 1
tools/perf/util/intlist.h

@@ -15,7 +15,7 @@ struct intlist {
 	struct rblist rblist;
 	struct rblist rblist;
 };
 };
 
 
-struct intlist *intlist__new(void);
+struct intlist *intlist__new(const char *slist);
 void intlist__delete(struct intlist *ilist);
 void intlist__delete(struct intlist *ilist);
 
 
 void intlist__remove(struct intlist *ilist, struct int_node *in);
 void intlist__remove(struct intlist *ilist, struct int_node *in);

+ 42 - 22
tools/perf/util/machine.c

@@ -91,10 +91,22 @@ void machine__delete(struct machine *machine)
 	free(machine);
 	free(machine);
 }
 }
 
 
-struct machine *machines__add(struct rb_root *machines, pid_t pid,
+void machines__init(struct machines *machines)
+{
+	machine__init(&machines->host, "", HOST_KERNEL_ID);
+	machines->guests = RB_ROOT;
+}
+
+void machines__exit(struct machines *machines)
+{
+	machine__exit(&machines->host);
+	/* XXX exit guest */
+}
+
+struct machine *machines__add(struct machines *machines, pid_t pid,
 			      const char *root_dir)
 			      const char *root_dir)
 {
 {
-	struct rb_node **p = &machines->rb_node;
+	struct rb_node **p = &machines->guests.rb_node;
 	struct rb_node *parent = NULL;
 	struct rb_node *parent = NULL;
 	struct machine *pos, *machine = malloc(sizeof(*machine));
 	struct machine *pos, *machine = malloc(sizeof(*machine));
 
 
@@ -116,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
 	}
 	}
 
 
 	rb_link_node(&machine->rb_node, parent, p);
 	rb_link_node(&machine->rb_node, parent, p);
-	rb_insert_color(&machine->rb_node, machines);
+	rb_insert_color(&machine->rb_node, &machines->guests);
 
 
 	return machine;
 	return machine;
 }
 }
 
 
-struct machine *machines__find(struct rb_root *machines, pid_t pid)
+struct machine *machines__find(struct machines *machines, pid_t pid)
 {
 {
-	struct rb_node **p = &machines->rb_node;
+	struct rb_node **p = &machines->guests.rb_node;
 	struct rb_node *parent = NULL;
 	struct rb_node *parent = NULL;
 	struct machine *machine;
 	struct machine *machine;
 	struct machine *default_machine = NULL;
 	struct machine *default_machine = NULL;
 
 
+	if (pid == HOST_KERNEL_ID)
+		return &machines->host;
+
 	while (*p != NULL) {
 	while (*p != NULL) {
 		parent = *p;
 		parent = *p;
 		machine = rb_entry(parent, struct machine, rb_node);
 		machine = rb_entry(parent, struct machine, rb_node);
@@ -144,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
 	return default_machine;
 	return default_machine;
 }
 }
 
 
-struct machine *machines__findnew(struct rb_root *machines, pid_t pid)
+struct machine *machines__findnew(struct machines *machines, pid_t pid)
 {
 {
 	char path[PATH_MAX];
 	char path[PATH_MAX];
 	const char *root_dir = "";
 	const char *root_dir = "";
@@ -178,12 +193,12 @@ out:
 	return machine;
 	return machine;
 }
 }
 
 
-void machines__process(struct rb_root *machines,
-		       machine__process_t process, void *data)
+void machines__process_guests(struct machines *machines,
+			      machine__process_t process, void *data)
 {
 {
 	struct rb_node *nd;
 	struct rb_node *nd;
 
 
-	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		process(pos, data);
 		process(pos, data);
 	}
 	}
@@ -203,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
 	return bf;
 	return bf;
 }
 }
 
 
-void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
+void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 {
 {
 	struct rb_node *node;
 	struct rb_node *node;
 	struct machine *machine;
 	struct machine *machine;
 
 
-	for (node = rb_first(machines); node; node = rb_next(node)) {
+	machines->host.id_hdr_size = id_hdr_size;
+
+	for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
 		machine = rb_entry(node, struct machine, rb_node);
 		machine = rb_entry(node, struct machine, rb_node);
 		machine->id_hdr_size = id_hdr_size;
 		machine->id_hdr_size = id_hdr_size;
 	}
 	}
@@ -313,12 +330,13 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 	return map;
 	return map;
 }
 }
 
 
-size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
+size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
 {
 {
 	struct rb_node *nd;
 	struct rb_node *nd;
-	size_t ret = 0;
+	size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
+		     __dsos__fprintf(&machines->host.user_dsos, fp);
 
 
-	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
 		ret += __dsos__fprintf(&pos->user_dsos, fp);
 		ret += __dsos__fprintf(&pos->user_dsos, fp);
@@ -334,13 +352,13 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
 	       __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
 }
 }
 
 
-size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp,
+size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
 				     bool (skip)(struct dso *dso, int parm), int parm)
 				     bool (skip)(struct dso *dso, int parm), int parm)
 {
 {
 	struct rb_node *nd;
 	struct rb_node *nd;
-	size_t ret = 0;
+	size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
 
 
-	for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
 		ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
 		ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
 	}
 	}
@@ -511,7 +529,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
 	}
 	}
 }
 }
 
 
-int machines__create_guest_kernel_maps(struct rb_root *machines)
+int machines__create_guest_kernel_maps(struct machines *machines)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	struct dirent **namelist = NULL;
 	struct dirent **namelist = NULL;
@@ -560,20 +578,22 @@ failure:
 	return ret;
 	return ret;
 }
 }
 
 
-void machines__destroy_guest_kernel_maps(struct rb_root *machines)
+void machines__destroy_kernel_maps(struct machines *machines)
 {
 {
-	struct rb_node *next = rb_first(machines);
+	struct rb_node *next = rb_first(&machines->guests);
+
+	machine__destroy_kernel_maps(&machines->host);
 
 
 	while (next) {
 	while (next) {
 		struct machine *pos = rb_entry(next, struct machine, rb_node);
 		struct machine *pos = rb_entry(next, struct machine, rb_node);
 
 
 		next = rb_next(&pos->rb_node);
 		next = rb_next(&pos->rb_node);
-		rb_erase(&pos->rb_node, machines);
+		rb_erase(&pos->rb_node, &machines->guests);
 		machine__delete(pos);
 		machine__delete(pos);
 	}
 	}
 }
 }
 
 
-int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
+int machines__create_kernel_maps(struct machines *machines, pid_t pid)
 {
 {
 	struct machine *machine = machines__findnew(machines, pid);
 	struct machine *machine = machines__findnew(machines, pid);
 
 

+ 20 - 12
tools/perf/util/machine.h

@@ -47,16 +47,24 @@ int machine__process_event(struct machine *machine, union perf_event *event);
 
 
 typedef void (*machine__process_t)(struct machine *machine, void *data);
 typedef void (*machine__process_t)(struct machine *machine, void *data);
 
 
-void machines__process(struct rb_root *machines,
-		       machine__process_t process, void *data);
+struct machines {
+	struct machine host;
+	struct rb_root guests;
+};
+
+void machines__init(struct machines *machines);
+void machines__exit(struct machines *machines);
+
+void machines__process_guests(struct machines *machines,
+			      machine__process_t process, void *data);
 
 
-struct machine *machines__add(struct rb_root *machines, pid_t pid,
+struct machine *machines__add(struct machines *machines, pid_t pid,
 			      const char *root_dir);
 			      const char *root_dir);
-struct machine *machines__find_host(struct rb_root *machines);
-struct machine *machines__find(struct rb_root *machines, pid_t pid);
-struct machine *machines__findnew(struct rb_root *machines, pid_t pid);
+struct machine *machines__find_host(struct machines *machines);
+struct machine *machines__find(struct machines *machines, pid_t pid);
+struct machine *machines__findnew(struct machines *machines, pid_t pid);
 
 
-void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size);
+void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
 char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
@@ -132,17 +140,17 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
 
 
 size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
 size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
 				     bool (skip)(struct dso *dso, int parm), int parm);
 				     bool (skip)(struct dso *dso, int parm), int parm);
-size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
-size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp,
+size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
+size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
 				     bool (skip)(struct dso *dso, int parm), int parm);
 				     bool (skip)(struct dso *dso, int parm), int parm);
 
 
 void machine__destroy_kernel_maps(struct machine *machine);
 void machine__destroy_kernel_maps(struct machine *machine);
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
 int machine__create_kernel_maps(struct machine *machine);
 int machine__create_kernel_maps(struct machine *machine);
 
 
-int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
-int machines__create_guest_kernel_maps(struct rb_root *machines);
-void machines__destroy_guest_kernel_maps(struct rb_root *machines);
+int machines__create_kernel_maps(struct machines *machines, pid_t pid);
+int machines__create_guest_kernel_maps(struct machines *machines);
+void machines__destroy_kernel_maps(struct machines *machines);
 
 
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
 
 

+ 2 - 1
tools/perf/util/map.c

@@ -19,7 +19,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
 
 
 static inline int is_anon_memory(const char *filename)
 static inline int is_anon_memory(const char *filename)
 {
 {
-	return strcmp(filename, "//anon") == 0;
+	return !strcmp(filename, "//anon") ||
+	       !strcmp(filename, "/anon_hugepage (deleted)");
 }
 }
 
 
 static inline int is_no_dso_memory(const char *filename)
 static inline int is_no_dso_memory(const char *filename)

+ 64 - 23
tools/perf/util/parse-events.c

@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
 	return 0;
 	return 0;
 }
 }
 
 
-static int add_tracepoint_multi(struct list_head **list, int *idx,
-				char *sys_name, char *evt_name)
+static int add_tracepoint_multi_event(struct list_head **list, int *idx,
+				      char *sys_name, char *evt_name)
 {
 {
 	char evt_path[MAXPATHLEN];
 	char evt_path[MAXPATHLEN];
 	struct dirent *evt_ent;
 	struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
 		ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 		ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
 	}
 	}
 
 
+	closedir(evt_dir);
+	return ret;
+}
+
+static int add_tracepoint_event(struct list_head **list, int *idx,
+				char *sys_name, char *evt_name)
+{
+	return strpbrk(evt_name, "*?") ?
+	       add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
+	       add_tracepoint(list, idx, sys_name, evt_name);
+}
+
+static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
+				    char *sys_name, char *evt_name)
+{
+	struct dirent *events_ent;
+	DIR *events_dir;
+	int ret = 0;
+
+	events_dir = opendir(tracing_events_path);
+	if (!events_dir) {
+		perror("Can't open event dir");
+		return -1;
+	}
+
+	while (!ret && (events_ent = readdir(events_dir))) {
+		if (!strcmp(events_ent->d_name, ".")
+		    || !strcmp(events_ent->d_name, "..")
+		    || !strcmp(events_ent->d_name, "enable")
+		    || !strcmp(events_ent->d_name, "header_event")
+		    || !strcmp(events_ent->d_name, "header_page"))
+			continue;
+
+		if (!strglobmatch(events_ent->d_name, sys_name))
+			continue;
+
+		ret = add_tracepoint_event(list, idx, events_ent->d_name,
+					   evt_name);
+	}
+
+	closedir(events_dir);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	return strpbrk(event, "*?") ?
-	       add_tracepoint_multi(list, idx, sys, event) :
-	       add_tracepoint(list, idx, sys, event);
+	if (strpbrk(sys, "*?"))
+		return add_tracepoint_multi_sys(list, idx, sys, event);
+	else
+		return add_tracepoint_event(list, idx, sys, event);
 }
 }
 
 
 static int
 static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
 }
 }
 
 
 static int config_term(struct perf_event_attr *attr,
 static int config_term(struct perf_event_attr *attr,
-		       struct parse_events__term *term)
+		       struct parse_events_term *term)
 {
 {
 #define CHECK_TYPE_VAL(type)					\
 #define CHECK_TYPE_VAL(type)					\
 do {								\
 do {								\
@@ -537,7 +579,7 @@ do {								\
 static int config_attr(struct perf_event_attr *attr,
 static int config_attr(struct perf_event_attr *attr,
 		       struct list_head *head, int fail)
 		       struct list_head *head, int fail)
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
 	list_for_each_entry(term, head, list)
 	list_for_each_entry(term, head, list)
 		if (config_term(attr, term) && fail)
 		if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
 	return add_event(list, idx, &attr, NULL);
 	return add_event(list, idx, &attr, NULL);
 }
 }
 
 
-static int parse_events__is_name_term(struct parse_events__term *term)
+static int parse_events__is_name_term(struct parse_events_term *term)
 {
 {
 	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
 	return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
 }
 }
 
 
 static char *pmu_event_name(struct list_head *head_terms)
 static char *pmu_event_name(struct list_head *head_terms)
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
 	list_for_each_entry(term, head_terms, list)
 	list_for_each_entry(term, head_terms, list)
 		if (parse_events__is_name_term(term))
 		if (parse_events__is_name_term(term))
@@ -814,7 +856,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
  */
  */
 int parse_events_terms(struct list_head *terms, const char *str)
 int parse_events_terms(struct list_head *terms, const char *str)
 {
 {
-	struct parse_events_data__terms data = {
+	struct parse_events_terms data = {
 		.terms = NULL,
 		.terms = NULL,
 	};
 	};
 	int ret;
 	int ret;
@@ -830,10 +872,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
 	return ret;
 	return ret;
 }
 }
 
 
-int parse_events(struct perf_evlist *evlist, const char *str,
-		 int unset __maybe_unused)
+int parse_events(struct perf_evlist *evlist, const char *str)
 {
 {
-	struct parse_events_data__events data = {
+	struct parse_events_evlist data = {
 		.list = LIST_HEAD_INIT(data.list),
 		.list = LIST_HEAD_INIT(data.list),
 		.idx  = evlist->nr_entries,
 		.idx  = evlist->nr_entries,
 	};
 	};
@@ -858,7 +899,7 @@ int parse_events_option(const struct option *opt, const char *str,
 			int unset __maybe_unused)
 			int unset __maybe_unused)
 {
 {
 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
-	int ret = parse_events(evlist, str, unset);
+	int ret = parse_events(evlist, str);
 
 
 	if (ret) {
 	if (ret) {
 		fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
 		fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1162,16 @@ void print_events(const char *event_glob, bool name_only)
 	print_tracepoint_events(NULL, NULL, name_only);
 	print_tracepoint_events(NULL, NULL, name_only);
 }
 }
 
 
-int parse_events__is_hardcoded_term(struct parse_events__term *term)
+int parse_events__is_hardcoded_term(struct parse_events_term *term)
 {
 {
 	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 	return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 }
 
 
-static int new_term(struct parse_events__term **_term, int type_val,
+static int new_term(struct parse_events_term **_term, int type_val,
 		    int type_term, char *config,
 		    int type_term, char *config,
 		    char *str, u64 num)
 		    char *str, u64 num)
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
 	term = zalloc(sizeof(*term));
 	term = zalloc(sizeof(*term));
 	if (!term)
 	if (!term)
@@ -1156,21 +1197,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
 	return 0;
 	return 0;
 }
 }
 
 
-int parse_events__term_num(struct parse_events__term **term,
+int parse_events_term__num(struct parse_events_term **term,
 			   int type_term, char *config, u64 num)
 			   int type_term, char *config, u64 num)
 {
 {
 	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
 	return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
 			config, NULL, num);
 			config, NULL, num);
 }
 }
 
 
-int parse_events__term_str(struct parse_events__term **term,
+int parse_events_term__str(struct parse_events_term **term,
 			   int type_term, char *config, char *str)
 			   int type_term, char *config, char *str)
 {
 {
 	return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
 	return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
 			config, str, 0);
 			config, str, 0);
 }
 }
 
 
-int parse_events__term_sym_hw(struct parse_events__term **term,
+int parse_events_term__sym_hw(struct parse_events_term **term,
 			      char *config, unsigned idx)
 			      char *config, unsigned idx)
 {
 {
 	struct event_symbol *sym;
 	struct event_symbol *sym;
@@ -1188,8 +1229,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
 				(char *) "event", (char *) sym->symbol, 0);
 				(char *) "event", (char *) sym->symbol, 0);
 }
 }
 
 
-int parse_events__term_clone(struct parse_events__term **new,
-			     struct parse_events__term *term)
+int parse_events_term__clone(struct parse_events_term **new,
+			     struct parse_events_term *term)
 {
 {
 	return new_term(new, term->type_val, term->type_term, term->config,
 	return new_term(new, term->type_val, term->type_term, term->config,
 			term->val.str, term->val.num);
 			term->val.str, term->val.num);
@@ -1197,7 +1238,7 @@ int parse_events__term_clone(struct parse_events__term **new,
 
 
 void parse_events__free_terms(struct list_head *terms)
 void parse_events__free_terms(struct list_head *terms)
 {
 {
-	struct parse_events__term *term, *h;
+	struct parse_events_term *term, *h;
 
 
 	list_for_each_entry_safe(term, h, terms, list)
 	list_for_each_entry_safe(term, h, terms, list)
 		free(term);
 		free(term);

+ 10 - 11
tools/perf/util/parse-events.h

@@ -29,8 +29,7 @@ const char *event_type(int type);
 
 
 extern int parse_events_option(const struct option *opt, const char *str,
 extern int parse_events_option(const struct option *opt, const char *str,
 			       int unset);
 			       int unset);
-extern int parse_events(struct perf_evlist *evlist, const char *str,
-			int unset);
+extern int parse_events(struct perf_evlist *evlist, const char *str);
 extern int parse_events_terms(struct list_head *terms, const char *str);
 extern int parse_events_terms(struct list_head *terms, const char *str);
 extern int parse_filter(const struct option *opt, const char *str, int unset);
 extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 
@@ -51,7 +50,7 @@ enum {
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 	PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
 };
 
 
-struct parse_events__term {
+struct parse_events_term {
 	char *config;
 	char *config;
 	union {
 	union {
 		char *str;
 		char *str;
@@ -62,24 +61,24 @@ struct parse_events__term {
 	struct list_head list;
 	struct list_head list;
 };
 };
 
 
-struct parse_events_data__events {
+struct parse_events_evlist {
 	struct list_head list;
 	struct list_head list;
 	int idx;
 	int idx;
 };
 };
 
 
-struct parse_events_data__terms {
+struct parse_events_terms {
 	struct list_head *terms;
 	struct list_head *terms;
 };
 };
 
 
-int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__term_num(struct parse_events__term **_term,
+int parse_events__is_hardcoded_term(struct parse_events_term *term);
+int parse_events_term__num(struct parse_events_term **_term,
 			   int type_term, char *config, u64 num);
 			   int type_term, char *config, u64 num);
-int parse_events__term_str(struct parse_events__term **_term,
+int parse_events_term__str(struct parse_events_term **_term,
 			   int type_term, char *config, char *str);
 			   int type_term, char *config, char *str);
-int parse_events__term_sym_hw(struct parse_events__term **term,
+int parse_events_term__sym_hw(struct parse_events_term **term,
 			      char *config, unsigned idx);
 			      char *config, unsigned idx);
-int parse_events__term_clone(struct parse_events__term **new,
-			     struct parse_events__term *term);
+int parse_events_term__clone(struct parse_events_term **new,
+			     struct parse_events_term *term);
 void parse_events__free_terms(struct list_head *terms);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);

+ 32 - 32
tools/perf/util/parse-events.y

@@ -68,7 +68,7 @@ do { \
 	char *str;
 	char *str;
 	u64 num;
 	u64 num;
 	struct list_head *head;
 	struct list_head *head;
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 }
 }
 %%
 %%
 
 
@@ -79,7 +79,7 @@ PE_START_TERMS  start_terms
 
 
 start_events: groups
 start_events: groups
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 
 
 	parse_events_update_lists($1, &data->list);
 	parse_events_update_lists($1, &data->list);
 }
 }
@@ -186,7 +186,7 @@ event_def: event_pmu |
 event_pmu:
 event_pmu:
 PE_NAME '/' event_config '/'
 PE_NAME '/' event_config '/'
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
 	ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +202,7 @@ PE_VALUE_SYM_SW
 event_legacy_symbol:
 event_legacy_symbol:
 value_sym '/' event_config '/'
 value_sym '/' event_config '/'
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 	int config = $1 & 255;
@@ -215,7 +215,7 @@ value_sym '/' event_config '/'
 |
 |
 value_sym sep_slash_dc
 value_sym sep_slash_dc
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 	int type = $1 >> 16;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 	int config = $1 & 255;
@@ -228,7 +228,7 @@ value_sym sep_slash_dc
 event_legacy_cache:
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +237,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 |
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 |
 |
 PE_NAME_CACHE_TYPE
 PE_NAME_CACHE_TYPE
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
 	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +256,7 @@ PE_NAME_CACHE_TYPE
 event_legacy_mem:
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
 	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +266,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 |
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
 	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +277,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
 event_legacy_tracepoint:
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 PE_NAME ':' PE_NAME
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
 	ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +287,7 @@ PE_NAME ':' PE_NAME
 event_legacy_numeric:
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 PE_VALUE ':' PE_VALUE
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
 	ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +297,7 @@ PE_VALUE ':' PE_VALUE
 event_legacy_raw:
 event_legacy_raw:
 PE_RAW
 PE_RAW
 {
 {
-	struct parse_events_data__events *data = _data;
+	struct parse_events_evlist *data = _data;
 	struct list_head *list = NULL;
 	struct list_head *list = NULL;
 
 
 	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
 	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +307,7 @@ PE_RAW
 
 
 start_terms: event_config
 start_terms: event_config
 {
 {
-	struct parse_events_data__terms *data = _data;
+	struct parse_events_terms *data = _data;
 	data->terms = $1;
 	data->terms = $1;
 }
 }
 
 
@@ -315,7 +315,7 @@ event_config:
 event_config ',' event_term
 event_config ',' event_term
 {
 {
 	struct list_head *head = $1;
 	struct list_head *head = $1;
-	struct parse_events__term *term = $3;
+	struct parse_events_term *term = $3;
 
 
 	ABORT_ON(!head);
 	ABORT_ON(!head);
 	list_add_tail(&term->list, head);
 	list_add_tail(&term->list, head);
@@ -325,7 +325,7 @@ event_config ',' event_term
 event_term
 event_term
 {
 {
 	struct list_head *head = malloc(sizeof(*head));
 	struct list_head *head = malloc(sizeof(*head));
-	struct parse_events__term *term = $1;
+	struct parse_events_term *term = $1;
 
 
 	ABORT_ON(!head);
 	ABORT_ON(!head);
 	INIT_LIST_HEAD(head);
 	INIT_LIST_HEAD(head);
@@ -336,70 +336,70 @@ event_term
 event_term:
 event_term:
 PE_NAME '=' PE_NAME
 PE_NAME '=' PE_NAME
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
+	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
 					$1, $3));
 					$1, $3));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_NAME '=' PE_VALUE
 PE_NAME '=' PE_VALUE
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
 					$1, $3));
 					$1, $3));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_NAME '=' PE_VALUE_SYM_HW
 PE_NAME '=' PE_VALUE_SYM_HW
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 	int config = $3 & 255;
 	int config = $3 & 255;
 
 
-	ABORT_ON(parse_events__term_sym_hw(&term, $1, config));
+	ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_NAME
 PE_NAME
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
 					$1, 1));
 					$1, 1));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_VALUE_SYM_HW
 PE_VALUE_SYM_HW
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 	int config = $1 & 255;
 	int config = $1 & 255;
 
 
-	ABORT_ON(parse_events__term_sym_hw(&term, NULL, config));
+	ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_TERM '=' PE_NAME
 PE_TERM '=' PE_NAME
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3));
+	ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_TERM '=' PE_VALUE
 PE_TERM '=' PE_VALUE
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3));
+	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
 	$$ = term;
 	$$ = term;
 }
 }
 |
 |
 PE_TERM
 PE_TERM
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
-	ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1));
+	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
 	$$ = term;
 	$$ = term;
 }
 }
 
 

+ 29 - 17
tools/perf/util/pmu.c

@@ -1,4 +1,3 @@
-
 #include <linux/list.h>
 #include <linux/list.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
@@ -11,6 +10,19 @@
 #include "parse-events.h"
 #include "parse-events.h"
 #include "cpumap.h"
 #include "cpumap.h"
 
 
+struct perf_pmu_alias {
+	char *name;
+	struct list_head terms;
+	struct list_head list;
+};
+
+struct perf_pmu_format {
+	char *name;
+	int value;
+	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+	struct list_head list;
+};
+
 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 
 
 int perf_pmu_parse(struct list_head *list, char *name);
 int perf_pmu_parse(struct list_head *list, char *name);
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
 
 
 static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
 static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
 {
 {
-	struct perf_pmu__alias *alias;
+	struct perf_pmu_alias *alias;
 	char buf[256];
 	char buf[256];
 	int ret;
 	int ret;
 
 
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
 	return 0;
 	return 0;
 }
 }
 
 
-static int pmu_alias_terms(struct perf_pmu__alias *alias,
+static int pmu_alias_terms(struct perf_pmu_alias *alias,
 			   struct list_head *terms)
 			   struct list_head *terms)
 {
 {
-	struct parse_events__term *term, *clone;
+	struct parse_events_term *term, *clone;
 	LIST_HEAD(list);
 	LIST_HEAD(list);
 	int ret;
 	int ret;
 
 
 	list_for_each_entry(term, &alias->terms, list) {
 	list_for_each_entry(term, &alias->terms, list) {
-		ret = parse_events__term_clone(&clone, term);
+		ret = parse_events_term__clone(&clone, term);
 		if (ret) {
 		if (ret) {
 			parse_events__free_terms(&list);
 			parse_events__free_terms(&list);
 			return ret;
 			return ret;
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
 	return pmu_lookup(name);
 	return pmu_lookup(name);
 }
 }
 
 
-static struct perf_pmu__format*
+static struct perf_pmu_format *
 pmu_find_format(struct list_head *formats, char *name)
 pmu_find_format(struct list_head *formats, char *name)
 {
 {
-	struct perf_pmu__format *format;
+	struct perf_pmu_format *format;
 
 
 	list_for_each_entry(format, formats, list)
 	list_for_each_entry(format, formats, list)
 		if (!strcmp(format->name, name))
 		if (!strcmp(format->name, name))
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
  */
  */
 static int pmu_config_term(struct list_head *formats,
 static int pmu_config_term(struct list_head *formats,
 			   struct perf_event_attr *attr,
 			   struct perf_event_attr *attr,
-			   struct parse_events__term *term)
+			   struct parse_events_term *term)
 {
 {
-	struct perf_pmu__format *format;
+	struct perf_pmu_format *format;
 	__u64 *vp;
 	__u64 *vp;
 
 
 	/*
 	/*
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats,
 			   struct perf_event_attr *attr,
 			   struct perf_event_attr *attr,
 			   struct list_head *head_terms)
 			   struct list_head *head_terms)
 {
 {
-	struct parse_events__term *term;
+	struct parse_events_term *term;
 
 
 	list_for_each_entry(term, head_terms, list)
 	list_for_each_entry(term, head_terms, list)
 		if (pmu_config_term(formats, attr, term))
 		if (pmu_config_term(formats, attr, term))
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
 	return perf_pmu__config_terms(&pmu->format, attr, head_terms);
 }
 }
 
 
-static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
-					      struct parse_events__term *term)
+static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
+					     struct parse_events_term *term)
 {
 {
-	struct perf_pmu__alias *alias;
+	struct perf_pmu_alias *alias;
 	char *name;
 	char *name;
 
 
 	if (parse_events__is_hardcoded_term(term))
 	if (parse_events__is_hardcoded_term(term))
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
  */
  */
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
 {
 {
-	struct parse_events__term *term, *h;
-	struct perf_pmu__alias *alias;
+	struct parse_events_term *term, *h;
+	struct perf_pmu_alias *alias;
 	int ret;
 	int ret;
 
 
 	list_for_each_entry_safe(term, h, head_terms, list) {
 	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)
 int perf_pmu__new_format(struct list_head *list, char *name,
 int perf_pmu__new_format(struct list_head *list, char *name,
 			 int config, unsigned long *bits)
 			 int config, unsigned long *bits)
 {
 {
-	struct perf_pmu__format *format;
+	struct perf_pmu_format *format;
 
 
 	format = zalloc(sizeof(*format));
 	format = zalloc(sizeof(*format));
 	if (!format)
 	if (!format)
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
 	if (!to)
 	if (!to)
 		to = from;
 		to = from;
 
 
-	memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
+	memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
 	for (b = from; b <= to; b++)
 	for (b = from; b <= to; b++)
 		set_bit(b, bits);
 		set_bit(b, bits);
 }
 }

+ 1 - 14
tools/perf/util/pmu.h

@@ -12,19 +12,6 @@ enum {
 
 
 #define PERF_PMU_FORMAT_BITS 64
 #define PERF_PMU_FORMAT_BITS 64
 
 
-struct perf_pmu__format {
-	char *name;
-	int value;
-	DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
-	struct list_head list;
-};
-
-struct perf_pmu__alias {
-	char *name;
-	struct list_head terms;
-	struct list_head list;
-};
-
 struct perf_pmu {
 struct perf_pmu {
 	char *name;
 	char *name;
 	__u32 type;
 	__u32 type;
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats,
 			   struct list_head *head_terms);
 			   struct list_head *head_terms);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
-				struct list_head *head_terms);
+				  struct list_head *head_terms);
 int perf_pmu_wrap(void);
 int perf_pmu_wrap(void);
 void perf_pmu_error(struct list_head *list, char *name, char const *msg);
 void perf_pmu_error(struct list_head *list, char *name, char const *msg);
 
 

+ 5 - 5
tools/perf/util/probe-finder.c

@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
 				   dwarf_diename(vr_die), dwarf_diename(&type));
 				   dwarf_diename(vr_die), dwarf_diename(&type));
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
+		if (die_get_real_type(&type, &type) == NULL) {
+			pr_warning("Failed to get a type"
+				   " information.\n");
+			return -ENOENT;
+		}
 		if (ret == DW_TAG_pointer_type) {
 		if (ret == DW_TAG_pointer_type) {
-			if (die_get_real_type(&type, &type) == NULL) {
-				pr_warning("Failed to get a type"
-					   " information.\n");
-				return -ENOENT;
-			}
 			while (*ref_ptr)
 			while (*ref_ptr)
 				ref_ptr = &(*ref_ptr)->next;
 				ref_ptr = &(*ref_ptr)->next;
 			/* Add new reference with offset +0 */
 			/* Add new reference with offset +0 */

+ 9 - 0
tools/perf/util/python.c

@@ -1045,3 +1045,12 @@ error:
 	if (PyErr_Occurred())
 	if (PyErr_Occurred())
 		PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
 		PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
 }
 }
+
+/*
+ * Dummy, to avoid dragging all the test_attr infrastructure in the python
+ * binding.
+ */
+void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
+                     int fd, int group_fd, unsigned long flags)
+{
+}

+ 1 - 0
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,
 	ns = nsecs - s * NSECS_PER_SEC;
 	ns = nsecs - s * NSECS_PER_SEC;
 
 
 	scripting_context->event_data = data;
 	scripting_context->event_data = data;
+	scripting_context->pevent = evsel->tp_format->pevent;
 
 
 	ENTER;
 	ENTER;
 	SAVETMPS;
 	SAVETMPS;

+ 1 - 0
tools/perf/util/scripting-engines/trace-event-python.c

@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
 	ns = nsecs - s * NSECS_PER_SEC;
 	ns = nsecs - s * NSECS_PER_SEC;
 
 
 	scripting_context->event_data = data;
 	scripting_context->event_data = data;
+	scripting_context->pevent = evsel->tp_format->pevent;
 
 
 	context = PyCObject_FromVoidPtr(scripting_context, NULL);
 	context = PyCObject_FromVoidPtr(scripting_context, NULL);
 
 

+ 34 - 41
tools/perf/util/session.c

@@ -86,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
 {
 {
 	u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
 	u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
 
 
-	session->host_machine.id_hdr_size = id_hdr_size;
 	machines__set_id_hdr_size(&session->machines, id_hdr_size);
 	machines__set_id_hdr_size(&session->machines, id_hdr_size);
 }
 }
 
 
 int perf_session__create_kernel_maps(struct perf_session *self)
 int perf_session__create_kernel_maps(struct perf_session *self)
 {
 {
-	int ret = machine__create_kernel_maps(&self->host_machine);
+	int ret = machine__create_kernel_maps(&self->machines.host);
 
 
 	if (ret >= 0)
 	if (ret >= 0)
 		ret = machines__create_guest_kernel_maps(&self->machines);
 		ret = machines__create_guest_kernel_maps(&self->machines);
@@ -101,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
 
 
 static void perf_session__destroy_kernel_maps(struct perf_session *self)
 static void perf_session__destroy_kernel_maps(struct perf_session *self)
 {
 {
-	machine__destroy_kernel_maps(&self->host_machine);
-	machines__destroy_guest_kernel_maps(&self->machines);
+	machines__destroy_kernel_maps(&self->machines);
 }
 }
 
 
 struct perf_session *perf_session__new(const char *filename, int mode,
 struct perf_session *perf_session__new(const char *filename, int mode,
@@ -127,13 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
 		goto out;
 		goto out;
 
 
 	memcpy(self->filename, filename, len);
 	memcpy(self->filename, filename, len);
-	self->machines = RB_ROOT;
 	self->repipe = repipe;
 	self->repipe = repipe;
 	INIT_LIST_HEAD(&self->ordered_samples.samples);
 	INIT_LIST_HEAD(&self->ordered_samples.samples);
 	INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
 	INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
 	INIT_LIST_HEAD(&self->ordered_samples.to_free);
 	INIT_LIST_HEAD(&self->ordered_samples.to_free);
-	machine__init(&self->host_machine, "", HOST_KERNEL_ID);
-	hists__init(&self->hists);
+	machines__init(&self->machines);
 
 
 	if (mode == O_RDONLY) {
 	if (mode == O_RDONLY) {
 		if (perf_session__open(self, force) < 0)
 		if (perf_session__open(self, force) < 0)
@@ -163,12 +159,12 @@ out_delete:
 
 
 static void perf_session__delete_dead_threads(struct perf_session *session)
 static void perf_session__delete_dead_threads(struct perf_session *session)
 {
 {
-	machine__delete_dead_threads(&session->host_machine);
+	machine__delete_dead_threads(&session->machines.host);
 }
 }
 
 
 static void perf_session__delete_threads(struct perf_session *session)
 static void perf_session__delete_threads(struct perf_session *session)
 {
 {
-	machine__delete_threads(&session->host_machine);
+	machine__delete_threads(&session->machines.host);
 }
 }
 
 
 static void perf_session_env__delete(struct perf_session_env *env)
 static void perf_session_env__delete(struct perf_session_env *env)
@@ -193,7 +189,7 @@ void perf_session__delete(struct perf_session *self)
 	perf_session__delete_dead_threads(self);
 	perf_session__delete_dead_threads(self);
 	perf_session__delete_threads(self);
 	perf_session__delete_threads(self);
 	perf_session_env__delete(&self->header.env);
 	perf_session_env__delete(&self->header.env);
-	machine__exit(&self->host_machine);
+	machines__exit(&self->machines);
 	close(self->fd);
 	close(self->fd);
 	free(self);
 	free(self);
 	vdso__exit();
 	vdso__exit();
@@ -825,7 +821,7 @@ static struct machine *
 		return perf_session__findnew_machine(session, pid);
 		return perf_session__findnew_machine(session, pid);
 	}
 	}
 
 
-	return perf_session__find_host_machine(session);
+	return &session->machines.host;
 }
 }
 
 
 static int perf_session_deliver_event(struct perf_session *session,
 static int perf_session_deliver_event(struct perf_session *session,
@@ -863,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
 	case PERF_RECORD_SAMPLE:
 	case PERF_RECORD_SAMPLE:
 		dump_sample(evsel, event, sample);
 		dump_sample(evsel, event, sample);
 		if (evsel == NULL) {
 		if (evsel == NULL) {
-			++session->hists.stats.nr_unknown_id;
+			++session->stats.nr_unknown_id;
 			return 0;
 			return 0;
 		}
 		}
 		if (machine == NULL) {
 		if (machine == NULL) {
-			++session->hists.stats.nr_unprocessable_samples;
+			++session->stats.nr_unprocessable_samples;
 			return 0;
 			return 0;
 		}
 		}
 		return tool->sample(tool, event, sample, evsel, machine);
 		return tool->sample(tool, event, sample, evsel, machine);
@@ -881,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
 		return tool->exit(tool, event, sample, machine);
 		return tool->exit(tool, event, sample, machine);
 	case PERF_RECORD_LOST:
 	case PERF_RECORD_LOST:
 		if (tool->lost == perf_event__process_lost)
 		if (tool->lost == perf_event__process_lost)
-			session->hists.stats.total_lost += event->lost.lost;
+			session->stats.total_lost += event->lost.lost;
 		return tool->lost(tool, event, sample, machine);
 		return tool->lost(tool, event, sample, machine);
 	case PERF_RECORD_READ:
 	case PERF_RECORD_READ:
 		return tool->read(tool, event, sample, evsel, machine);
 		return tool->read(tool, event, sample, evsel, machine);
@@ -890,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
 	case PERF_RECORD_UNTHROTTLE:
 	case PERF_RECORD_UNTHROTTLE:
 		return tool->unthrottle(tool, event, sample, machine);
 		return tool->unthrottle(tool, event, sample, machine);
 	default:
 	default:
-		++session->hists.stats.nr_unknown_events;
+		++session->stats.nr_unknown_events;
 		return -1;
 		return -1;
 	}
 	}
 }
 }
@@ -904,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
 
 
 	if (!ip_callchain__valid(sample->callchain, event)) {
 	if (!ip_callchain__valid(sample->callchain, event)) {
 		pr_debug("call-chain problem with event, skipping it.\n");
 		pr_debug("call-chain problem with event, skipping it.\n");
-		++session->hists.stats.nr_invalid_chains;
-		session->hists.stats.total_invalid_chains += sample->period;
+		++session->stats.nr_invalid_chains;
+		session->stats.total_invalid_chains += sample->period;
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	return 0;
 	return 0;
@@ -963,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
 	if (event->header.type >= PERF_RECORD_HEADER_MAX)
 	if (event->header.type >= PERF_RECORD_HEADER_MAX)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	hists__inc_nr_events(&session->hists, event->header.type);
+	events_stats__inc(&session->stats, event->header.type);
 
 
 	if (event->header.type >= PERF_RECORD_USER_TYPE_START)
 	if (event->header.type >= PERF_RECORD_USER_TYPE_START)
 		return perf_session__process_user_event(session, event, tool, file_offset);
 		return perf_session__process_user_event(session, event, tool, file_offset);
@@ -999,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
 
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 {
 {
-	return machine__findnew_thread(&session->host_machine, pid);
+	return machine__findnew_thread(&session->machines.host, pid);
 }
 }
 
 
 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1018,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
 					    const struct perf_tool *tool)
 					    const struct perf_tool *tool)
 {
 {
 	if (tool->lost == perf_event__process_lost &&
 	if (tool->lost == perf_event__process_lost &&
-	    session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
+	    session->stats.nr_events[PERF_RECORD_LOST] != 0) {
 		ui__warning("Processed %d events and lost %d chunks!\n\n"
 		ui__warning("Processed %d events and lost %d chunks!\n\n"
 			    "Check IO/CPU overload!\n\n",
 			    "Check IO/CPU overload!\n\n",
-			    session->hists.stats.nr_events[0],
-			    session->hists.stats.nr_events[PERF_RECORD_LOST]);
+			    session->stats.nr_events[0],
+			    session->stats.nr_events[PERF_RECORD_LOST]);
 	}
 	}
 
 
-	if (session->hists.stats.nr_unknown_events != 0) {
+	if (session->stats.nr_unknown_events != 0) {
 		ui__warning("Found %u unknown events!\n\n"
 		ui__warning("Found %u unknown events!\n\n"
 			    "Is this an older tool processing a perf.data "
 			    "Is this an older tool processing a perf.data "
 			    "file generated by a more recent tool?\n\n"
 			    "file generated by a more recent tool?\n\n"
 			    "If that is not the case, consider "
 			    "If that is not the case, consider "
 			    "reporting to linux-kernel@vger.kernel.org.\n\n",
 			    "reporting to linux-kernel@vger.kernel.org.\n\n",
-			    session->hists.stats.nr_unknown_events);
+			    session->stats.nr_unknown_events);
 	}
 	}
 
 
-	if (session->hists.stats.nr_unknown_id != 0) {
+	if (session->stats.nr_unknown_id != 0) {
 		ui__warning("%u samples with id not present in the header\n",
 		ui__warning("%u samples with id not present in the header\n",
-			    session->hists.stats.nr_unknown_id);
+			    session->stats.nr_unknown_id);
 	}
 	}
 
 
- 	if (session->hists.stats.nr_invalid_chains != 0) {
+ 	if (session->stats.nr_invalid_chains != 0) {
  		ui__warning("Found invalid callchains!\n\n"
  		ui__warning("Found invalid callchains!\n\n"
  			    "%u out of %u events were discarded for this reason.\n\n"
  			    "%u out of %u events were discarded for this reason.\n\n"
  			    "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
  			    "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
- 			    session->hists.stats.nr_invalid_chains,
- 			    session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
+ 			    session->stats.nr_invalid_chains,
+ 			    session->stats.nr_events[PERF_RECORD_SAMPLE]);
  	}
  	}
 
 
-	if (session->hists.stats.nr_unprocessable_samples != 0) {
+	if (session->stats.nr_unprocessable_samples != 0) {
 		ui__warning("%u unprocessable samples recorded.\n"
 		ui__warning("%u unprocessable samples recorded.\n"
 			    "Do you have a KVM guest running and not using 'perf kvm'?\n",
 			    "Do you have a KVM guest running and not using 'perf kvm'?\n",
-			    session->hists.stats.nr_unprocessable_samples);
+			    session->stats.nr_unprocessable_samples);
 	}
 	}
 }
 }
 
 
@@ -1336,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
 
 
 size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
 size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
 {
 {
-	return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
-	       __dsos__fprintf(&self->host_machine.user_dsos, fp) +
-	       machines__fprintf_dsos(&self->machines, fp);
+	return machines__fprintf_dsos(&self->machines, fp);
 }
 }
 
 
 size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
 size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
 					  bool (skip)(struct dso *dso, int parm), int parm)
 					  bool (skip)(struct dso *dso, int parm), int parm)
 {
 {
-	size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm);
-	return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
+	return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
 }
 }
 
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1353,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
 	struct perf_evsel *pos;
 	struct perf_evsel *pos;
 	size_t ret = fprintf(fp, "Aggregated stats:\n");
 	size_t ret = fprintf(fp, "Aggregated stats:\n");
 
 
-	ret += hists__fprintf_nr_events(&session->hists, fp);
+	ret += events_stats__fprintf(&session->stats, fp);
 
 
 	list_for_each_entry(pos, &session->evlist->entries, node) {
 	list_for_each_entry(pos, &session->evlist->entries, node) {
 		ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
 		ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
-		ret += hists__fprintf_nr_events(&pos->hists, fp);
+		ret += events_stats__fprintf(&pos->hists.stats, fp);
 	}
 	}
 
 
 	return ret;
 	return ret;
@@ -1369,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
 	 * FIXME: Here we have to actually print all the machines in this
 	 * FIXME: Here we have to actually print all the machines in this
 	 * session, not just the host...
 	 * session, not just the host...
 	 */
 	 */
-	return machine__fprintf(&session->host_machine, fp);
+	return machine__fprintf(&session->machines.host, fp);
 }
 }
 
 
 void perf_session__remove_thread(struct perf_session *session,
 void perf_session__remove_thread(struct perf_session *session,
@@ -1378,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
 	/*
 	/*
 	 * FIXME: This one makes no sense, we need to remove the thread from
 	 * FIXME: This one makes no sense, we need to remove the thread from
 	 * the machine it belongs to, perf_session can have many machines, so
 	 * the machine it belongs to, perf_session can have many machines, so
-	 * doing it always on ->host_machine is wrong.  Fix when auditing all
+	 * doing it always on ->machines.host is wrong.  Fix when auditing all
 	 * the 'perf kvm' code.
 	 * the 'perf kvm' code.
 	 */
 	 */
-	machine__remove_thread(&session->host_machine, th);
+	machine__remove_thread(&session->machines.host, th);
 }
 }
 
 
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,

+ 3 - 27
tools/perf/util/session.h

@@ -30,15 +30,10 @@ struct ordered_samples {
 struct perf_session {
 struct perf_session {
 	struct perf_header	header;
 	struct perf_header	header;
 	unsigned long		size;
 	unsigned long		size;
-	struct machine		host_machine;
-	struct rb_root		machines;
+	struct machines		machines;
 	struct perf_evlist	*evlist;
 	struct perf_evlist	*evlist;
 	struct pevent		*pevent;
 	struct pevent		*pevent;
-	/*
-	 * FIXME: Need to split this up further, we need global
-	 *	  stats + per event stats.
-	 */
-	struct hists		hists;
+	struct events_stats	stats;
 	int			fd;
 	int			fd;
 	bool			fd_pipe;
 	bool			fd_pipe;
 	bool			repipe;
 	bool			repipe;
@@ -53,7 +48,7 @@ struct perf_tool;
 struct perf_session *perf_session__new(const char *filename, int mode,
 struct perf_session *perf_session__new(const char *filename, int mode,
 				       bool force, bool repipe,
 				       bool force, bool repipe,
 				       struct perf_tool *tool);
 				       struct perf_tool *tool);
-void perf_session__delete(struct perf_session *self);
+void perf_session__delete(struct perf_session *session);
 
 
 void perf_event_header__bswap(struct perf_event_header *self);
 void perf_event_header__bswap(struct perf_event_header *self);
 
 
@@ -79,37 +74,18 @@ int perf_session__create_kernel_maps(struct perf_session *self);
 void perf_session__set_id_hdr_size(struct perf_session *session);
 void perf_session__set_id_hdr_size(struct perf_session *session);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 
-static inline
-struct machine *perf_session__find_host_machine(struct perf_session *self)
-{
-	return &self->host_machine;
-}
-
 static inline
 static inline
 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
 {
 {
-	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
 	return machines__find(&self->machines, pid);
 	return machines__find(&self->machines, pid);
 }
 }
 
 
 static inline
 static inline
 struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
 struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
 {
 {
-	if (pid == HOST_KERNEL_ID)
-		return &self->host_machine;
 	return machines__findnew(&self->machines, pid);
 	return machines__findnew(&self->machines, pid);
 }
 }
 
 
-static inline
-void perf_session__process_machines(struct perf_session *self,
-				    struct perf_tool *tool,
-				    machine__process_t process)
-{
-	process(&self->host_machine, tool);
-	return machines__process(&self->machines, process, tool);
-}
-
 struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
 struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
 size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
 size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
 
 

+ 122 - 108
tools/perf/util/sort.c

@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
 				       size_t size, unsigned int width)
 				       size_t size, unsigned int width)
 {
 {
-	return repsep_snprintf(bf, size, "%*s:%5d", width,
+	return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
 			      self->thread->comm ?: "", self->thread->pid);
 			      self->thread->comm ?: "", self->thread->pid);
 }
 }
 
 
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
 	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 	return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 }
 }
 
 
+struct sort_entry sort_comm = {
+	.se_header	= "Command",
+	.se_cmp		= sort__comm_cmp,
+	.se_collapse	= sort__comm_collapse,
+	.se_snprintf	= hist_entry__comm_snprintf,
+	.se_width_idx	= HISTC_COMM,
+};
+
+/* --sort dso */
+
 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 {
 {
 	struct dso *dso_l = map_l ? map_l->dso : NULL;
 	struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,22 +127,38 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 	return strcmp(dso_name_l, dso_name_r);
 	return strcmp(dso_name_l, dso_name_r);
 }
 }
 
 
-struct sort_entry sort_comm = {
-	.se_header	= "Command",
-	.se_cmp		= sort__comm_cmp,
-	.se_collapse	= sort__comm_collapse,
-	.se_snprintf	= hist_entry__comm_snprintf,
-	.se_width_idx	= HISTC_COMM,
-};
-
-/* --sort dso */
-
 static int64_t
 static int64_t
 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 {
 {
 	return _sort__dso_cmp(left->ms.map, right->ms.map);
 	return _sort__dso_cmp(left->ms.map, right->ms.map);
 }
 }
 
 
+static int _hist_entry__dso_snprintf(struct map *map, char *bf,
+				     size_t size, unsigned int width)
+{
+	if (map && map->dso) {
+		const char *dso_name = !verbose ? map->dso->short_name :
+			map->dso->long_name;
+		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
+	}
+
+	return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
+}
+
+static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
+				    size_t size, unsigned int width)
+{
+	return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
+}
+
+struct sort_entry sort_dso = {
+	.se_header	= "Shared Object",
+	.se_cmp		= sort__dso_cmp,
+	.se_snprintf	= hist_entry__dso_snprintf,
+	.se_width_idx	= HISTC_DSO,
+};
+
+/* --sort symbol */
 
 
 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
 			      u64 ip_l, u64 ip_r)
 			      u64 ip_l, u64 ip_r)
@@ -143,35 +169,35 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
 	if (sym_l == sym_r)
 	if (sym_l == sym_r)
 		return 0;
 		return 0;
 
 
-	if (sym_l)
-		ip_l = sym_l->start;
-	if (sym_r)
-		ip_r = sym_r->start;
+	ip_l = sym_l->start;
+	ip_r = sym_r->start;
 
 
 	return (int64_t)(ip_r - ip_l);
 	return (int64_t)(ip_r - ip_l);
 }
 }
 
 
-static int _hist_entry__dso_snprintf(struct map *map, char *bf,
-				     size_t size, unsigned int width)
+static int64_t
+sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
 {
 {
-	if (map && map->dso) {
-		const char *dso_name = !verbose ? map->dso->short_name :
-			map->dso->long_name;
-		return repsep_snprintf(bf, size, "%-*s", width, dso_name);
-	}
+	u64 ip_l, ip_r;
 
 
-	return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
-}
+	if (!left->ms.sym && !right->ms.sym)
+		return right->level - left->level;
 
 
-static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
-				    size_t size, unsigned int width)
-{
-	return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
+	if (!left->ms.sym || !right->ms.sym)
+		return cmp_null(left->ms.sym, right->ms.sym);
+
+	if (left->ms.sym == right->ms.sym)
+		return 0;
+
+	ip_l = left->ms.sym->start;
+	ip_r = right->ms.sym->start;
+
+	return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
 }
 }
 
 
 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 				     u64 ip, char level, char *bf, size_t size,
 				     u64 ip, char level, char *bf, size_t size,
-				     unsigned int width __maybe_unused)
+				     unsigned int width)
 {
 {
 	size_t ret = 0;
 	size_t ret = 0;
 
 
@@ -197,43 +223,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 	return ret;
 	return ret;
 }
 }
 
 
-
-struct sort_entry sort_dso = {
-	.se_header	= "Shared Object",
-	.se_cmp		= sort__dso_cmp,
-	.se_snprintf	= hist_entry__dso_snprintf,
-	.se_width_idx	= HISTC_DSO,
-};
-
 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
-				    size_t size,
-				    unsigned int width __maybe_unused)
+				    size_t size, unsigned int width)
 {
 {
 	return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
 	return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
 					 self->level, bf, size, width);
 					 self->level, bf, size, width);
 }
 }
 
 
-/* --sort symbol */
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-	u64 ip_l, ip_r;
-
-	if (!left->ms.sym && !right->ms.sym)
-		return right->level - left->level;
-
-	if (!left->ms.sym || !right->ms.sym)
-		return cmp_null(left->ms.sym, right->ms.sym);
-
-	if (left->ms.sym == right->ms.sym)
-		return 0;
-
-	ip_l = left->ms.sym->start;
-	ip_r = right->ms.sym->start;
-
-	return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
-}
-
 struct sort_entry sort_sym = {
 struct sort_entry sort_sym = {
 	.se_header	= "Symbol",
 	.se_header	= "Symbol",
 	.se_cmp		= sort__sym_cmp,
 	.se_cmp		= sort__sym_cmp,
@@ -335,7 +331,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
 				       size_t size, unsigned int width)
 				       size_t size, unsigned int width)
 {
 {
-	return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
+	return repsep_snprintf(bf, size, "%*d", width, self->cpu);
 }
 }
 
 
 struct sort_entry sort_cpu = {
 struct sort_entry sort_cpu = {
@@ -345,6 +341,8 @@ struct sort_entry sort_cpu = {
 	.se_width_idx	= HISTC_CPU,
 	.se_width_idx	= HISTC_CPU,
 };
 };
 
 
+/* sort keys for branch stacks */
+
 static int64_t
 static int64_t
 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
 {
 {
@@ -359,13 +357,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
 					 bf, size, width);
 					 bf, size, width);
 }
 }
 
 
-struct sort_entry sort_dso_from = {
-	.se_header	= "Source Shared Object",
-	.se_cmp		= sort__dso_from_cmp,
-	.se_snprintf	= hist_entry__dso_from_snprintf,
-	.se_width_idx	= HISTC_DSO_FROM,
-};
-
 static int64_t
 static int64_t
 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
 {
 {
@@ -406,8 +397,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 }
 
 
 static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
 static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
-					size_t size,
-					unsigned int width __maybe_unused)
+					 size_t size, unsigned int width)
 {
 {
 	struct addr_map_symbol *from = &self->branch_info->from;
 	struct addr_map_symbol *from = &self->branch_info->from;
 	return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
 	return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +406,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
 }
 }
 
 
 static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
 static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
-				       size_t size,
-				       unsigned int width __maybe_unused)
+				       size_t size, unsigned int width)
 {
 {
 	struct addr_map_symbol *to = &self->branch_info->to;
 	struct addr_map_symbol *to = &self->branch_info->to;
 	return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
 	return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +414,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
 
 
 }
 }
 
 
+struct sort_entry sort_dso_from = {
+	.se_header	= "Source Shared Object",
+	.se_cmp		= sort__dso_from_cmp,
+	.se_snprintf	= hist_entry__dso_from_snprintf,
+	.se_width_idx	= HISTC_DSO_FROM,
+};
+
 struct sort_entry sort_dso_to = {
 struct sort_entry sort_dso_to = {
 	.se_header	= "Target Shared Object",
 	.se_header	= "Target Shared Object",
 	.se_cmp		= sort__dso_to_cmp,
 	.se_cmp		= sort__dso_to_cmp,
@@ -484,30 +480,40 @@ struct sort_dimension {
 
 
 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
 
 
-static struct sort_dimension sort_dimensions[] = {
+static struct sort_dimension common_sort_dimensions[] = {
 	DIM(SORT_PID, "pid", sort_thread),
 	DIM(SORT_PID, "pid", sort_thread),
 	DIM(SORT_COMM, "comm", sort_comm),
 	DIM(SORT_COMM, "comm", sort_comm),
 	DIM(SORT_DSO, "dso", sort_dso),
 	DIM(SORT_DSO, "dso", sort_dso),
-	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
-	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
 	DIM(SORT_SYM, "symbol", sort_sym),
 	DIM(SORT_SYM, "symbol", sort_sym),
-	DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
-	DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
 	DIM(SORT_PARENT, "parent", sort_parent),
 	DIM(SORT_PARENT, "parent", sort_parent),
 	DIM(SORT_CPU, "cpu", sort_cpu),
 	DIM(SORT_CPU, "cpu", sort_cpu),
-	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
 	DIM(SORT_SRCLINE, "srcline", sort_srcline),
 	DIM(SORT_SRCLINE, "srcline", sort_srcline),
 };
 };
 
 
+#undef DIM
+
+#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
+
+static struct sort_dimension bstack_sort_dimensions[] = {
+	DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
+	DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
+	DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
+	DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
+	DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
+};
+
+#undef DIM
+
 int sort_dimension__add(const char *tok)
 int sort_dimension__add(const char *tok)
 {
 {
 	unsigned int i;
 	unsigned int i;
 
 
-	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-		struct sort_dimension *sd = &sort_dimensions[i];
+	for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
+		struct sort_dimension *sd = &common_sort_dimensions[i];
 
 
 		if (strncasecmp(tok, sd->name, strlen(tok)))
 		if (strncasecmp(tok, sd->name, strlen(tok)))
 			continue;
 			continue;
+
 		if (sd->entry == &sort_parent) {
 		if (sd->entry == &sort_parent) {
 			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
 			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
 			if (ret) {
 			if (ret) {
@@ -518,9 +524,7 @@ int sort_dimension__add(const char *tok)
 				return -EINVAL;
 				return -EINVAL;
 			}
 			}
 			sort__has_parent = 1;
 			sort__has_parent = 1;
-		} else if (sd->entry == &sort_sym ||
-			   sd->entry == &sort_sym_from ||
-			   sd->entry == &sort_sym_to) {
+		} else if (sd->entry == &sort_sym) {
 			sort__has_sym = 1;
 			sort__has_sym = 1;
 		}
 		}
 
 
@@ -530,36 +534,42 @@ int sort_dimension__add(const char *tok)
 		if (sd->entry->se_collapse)
 		if (sd->entry->se_collapse)
 			sort__need_collapse = 1;
 			sort__need_collapse = 1;
 
 
-		if (list_empty(&hist_entry__sort_list)) {
-			if (!strcmp(sd->name, "pid"))
-				sort__first_dimension = SORT_PID;
-			else if (!strcmp(sd->name, "comm"))
-				sort__first_dimension = SORT_COMM;
-			else if (!strcmp(sd->name, "dso"))
-				sort__first_dimension = SORT_DSO;
-			else if (!strcmp(sd->name, "symbol"))
-				sort__first_dimension = SORT_SYM;
-			else if (!strcmp(sd->name, "parent"))
-				sort__first_dimension = SORT_PARENT;
-			else if (!strcmp(sd->name, "cpu"))
-				sort__first_dimension = SORT_CPU;
-			else if (!strcmp(sd->name, "symbol_from"))
-				sort__first_dimension = SORT_SYM_FROM;
-			else if (!strcmp(sd->name, "symbol_to"))
-				sort__first_dimension = SORT_SYM_TO;
-			else if (!strcmp(sd->name, "dso_from"))
-				sort__first_dimension = SORT_DSO_FROM;
-			else if (!strcmp(sd->name, "dso_to"))
-				sort__first_dimension = SORT_DSO_TO;
-			else if (!strcmp(sd->name, "mispredict"))
-				sort__first_dimension = SORT_MISPREDICT;
-		}
+		if (list_empty(&hist_entry__sort_list))
+			sort__first_dimension = i;
 
 
 		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
 		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
 		sd->taken = 1;
 		sd->taken = 1;
 
 
 		return 0;
 		return 0;
 	}
 	}
+
+	for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
+		struct sort_dimension *sd = &bstack_sort_dimensions[i];
+
+		if (strncasecmp(tok, sd->name, strlen(tok)))
+			continue;
+
+		if (sort__branch_mode != 1)
+			return -EINVAL;
+
+		if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
+			sort__has_sym = 1;
+
+		if (sd->taken)
+			return 0;
+
+		if (sd->entry->se_collapse)
+			sort__need_collapse = 1;
+
+		if (list_empty(&hist_entry__sort_list))
+			sort__first_dimension = i + __SORT_BRANCH_STACK;
+
+		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+		sd->taken = 1;
+
+		return 0;
+	}
+
 	return -ESRCH;
 	return -ESRCH;
 }
 }
 
 
@@ -569,7 +579,11 @@ void setup_sorting(const char * const usagestr[], const struct option *opts)
 
 
 	for (tok = strtok_r(str, ", ", &tmp);
 	for (tok = strtok_r(str, ", ", &tmp);
 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
-		if (sort_dimension__add(tok) < 0) {
+		int ret = sort_dimension__add(tok);
+		if (ret == -EINVAL) {
+			error("Invalid --sort key: `%s'", tok);
+			usage_with_options(usagestr, opts);
+		} else if (ret == -ESRCH) {
 			error("Unknown --sort key: `%s'", tok);
 			error("Unknown --sort key: `%s'", tok);
 			usage_with_options(usagestr, opts);
 			usage_with_options(usagestr, opts);
 		}
 		}

+ 6 - 2
tools/perf/util/sort.h

@@ -122,18 +122,22 @@ static inline void hist_entry__add_pair(struct hist_entry *he,
 }
 }
 
 
 enum sort_type {
 enum sort_type {
+	/* common sort keys */
 	SORT_PID,
 	SORT_PID,
 	SORT_COMM,
 	SORT_COMM,
 	SORT_DSO,
 	SORT_DSO,
 	SORT_SYM,
 	SORT_SYM,
 	SORT_PARENT,
 	SORT_PARENT,
 	SORT_CPU,
 	SORT_CPU,
-	SORT_DSO_FROM,
+	SORT_SRCLINE,
+
+	/* branch stack specific sort keys */
+	__SORT_BRANCH_STACK,
+	SORT_DSO_FROM = __SORT_BRANCH_STACK,
 	SORT_DSO_TO,
 	SORT_DSO_TO,
 	SORT_SYM_FROM,
 	SORT_SYM_FROM,
 	SORT_SYM_TO,
 	SORT_SYM_TO,
 	SORT_MISPREDICT,
 	SORT_MISPREDICT,
-	SORT_SRCLINE,
 };
 };
 
 
 /*
 /*

+ 18 - 0
tools/perf/util/string.c

@@ -331,6 +331,24 @@ char *strxfrchar(char *s, char from, char to)
 	return s;
 	return s;
 }
 }
 
 
+/**
+ * ltrim - Removes leading whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Return pointer to the first non-whitespace character in @s.
+ */
+char *ltrim(char *s)
+{
+	int len = strlen(s);
+
+	while (len && isspace(*s)) {
+		len--;
+		s++;
+	}
+
+	return s;
+}
+
 /**
 /**
  * rtrim - Removes trailing whitespace from @s.
  * rtrim - Removes trailing whitespace from @s.
  * @s: The string to be stripped.
  * @s: The string to be stripped.

+ 0 - 3
tools/perf/util/symbol-elf.c

@@ -1,6 +1,3 @@
-#include <libelf.h>
-#include <gelf.h>
-#include <elf.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <errno.h>
 #include <errno.h>

+ 0 - 1
tools/perf/util/symbol-minimal.c

@@ -1,6 +1,5 @@
 #include "symbol.h"
 #include "symbol.h"
 
 
-#include <elf.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <fcntl.h>
 #include <string.h>
 #include <string.h>

+ 9 - 5
tools/perf/util/symbol.c

@@ -768,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 	else
 	else
 		machine = NULL;
 		machine = NULL;
 
 
-	name = malloc(PATH_MAX);
-	if (!name)
-		return -1;
-
 	dso->adjust_symbols = 0;
 	dso->adjust_symbols = 0;
 
 
 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
 	if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -795,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 	if (machine)
 	if (machine)
 		root_dir = machine->root_dir;
 		root_dir = machine->root_dir;
 
 
+	name = malloc(PATH_MAX);
+	if (!name)
+		return -1;
+
 	/* Iterate over candidate debug images.
 	/* Iterate over candidate debug images.
 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
 	 * Keep track of "interesting" ones (those which have a symtab, dynsym,
 	 * and/or opd section) for processing.
 	 * and/or opd section) for processing.
@@ -923,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 	filename = dso__build_id_filename(dso, NULL, 0);
 	filename = dso__build_id_filename(dso, NULL, 0);
 	if (filename != NULL) {
 	if (filename != NULL) {
 		err = dso__load_vmlinux(dso, map, filename, filter);
 		err = dso__load_vmlinux(dso, map, filename, filter);
-		if (err > 0)
+		if (err > 0) {
+			dso->lname_alloc = 1;
 			goto out;
 			goto out;
+		}
 		free(filename);
 		free(filename);
 	}
 	}
 
 
@@ -932,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
 		err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
 		if (err > 0) {
 		if (err > 0) {
 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
 			dso__set_long_name(dso, strdup(vmlinux_path[i]));
+			dso->lname_alloc = 1;
 			break;
 			break;
 		}
 		}
 	}
 	}
@@ -971,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
 		if (err > 0) {
 		if (err > 0) {
 			dso__set_long_name(dso,
 			dso__set_long_name(dso,
 					   strdup(symbol_conf.vmlinux_name));
 					   strdup(symbol_conf.vmlinux_name));
+			dso->lname_alloc = 1;
 			goto out_fixup;
 			goto out_fixup;
 		}
 		}
 		return err;
 		return err;

+ 1 - 1
tools/perf/util/symbol.h

@@ -16,8 +16,8 @@
 #ifdef LIBELF_SUPPORT
 #ifdef LIBELF_SUPPORT
 #include <libelf.h>
 #include <libelf.h>
 #include <gelf.h>
 #include <gelf.h>
-#include <elf.h>
 #endif
 #endif
+#include <elf.h>
 
 
 #include "dso.h"
 #include "dso.h"
 
 

+ 1 - 1
tools/perf/util/sysfs.c

@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
 };
 };
 
 
 static int sysfs_found;
 static int sysfs_found;
-char sysfs_mountpoint[PATH_MAX];
+char sysfs_mountpoint[PATH_MAX + 1];
 
 
 static int sysfs_valid_mountpoint(const char *sysfs)
 static int sysfs_valid_mountpoint(const char *sysfs)
 {
 {

+ 0 - 2
tools/perf/util/top.h

@@ -29,8 +29,6 @@ struct perf_top {
 	bool		   sort_has_symbols;
 	bool		   sort_has_symbols;
 	bool		   kptr_restrict_warned;
 	bool		   kptr_restrict_warned;
 	bool		   vmlinux_warned;
 	bool		   vmlinux_warned;
-	bool		   sample_id_all_missing;
-	bool		   exclude_guest_missing;
 	bool		   dump_symtab;
 	bool		   dump_symtab;
 	struct hist_entry  *sym_filter_entry;
 	struct hist_entry  *sym_filter_entry;
 	struct perf_evsel  *sym_evsel;
 	struct perf_evsel  *sym_evsel;

+ 24 - 0
tools/perf/util/util.c

@@ -12,6 +12,8 @@
  */
  */
 unsigned int page_size;
 unsigned int page_size;
 
 
+bool test_attr__enabled;
+
 bool perf_host  = true;
 bool perf_host  = true;
 bool perf_guest = false;
 bool perf_guest = false;
 
 
@@ -218,3 +220,25 @@ void dump_stack(void)
 #else
 #else
 void dump_stack(void) {}
 void dump_stack(void) {}
 #endif
 #endif
+
+void get_term_dimensions(struct winsize *ws)
+{
+	char *s = getenv("LINES");
+
+	if (s != NULL) {
+		ws->ws_row = atoi(s);
+		s = getenv("COLUMNS");
+		if (s != NULL) {
+			ws->ws_col = atoi(s);
+			if (ws->ws_row && ws->ws_col)
+				return;
+		}
+	}
+#ifdef TIOCGWINSZ
+	if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+	    ws->ws_row && ws->ws_col)
+		return;
+#endif
+	ws->ws_row = 25;
+	ws->ws_col = 80;
+}

+ 4 - 0
tools/perf/util/util.h

@@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n)
 size_t hex_width(u64 v);
 size_t hex_width(u64 v);
 int hex2u64(const char *ptr, u64 *val);
 int hex2u64(const char *ptr, u64 *val);
 
 
+char *ltrim(char *s);
 char *rtrim(char *s);
 char *rtrim(char *s);
 
 
 void dump_stack(void);
 void dump_stack(void);
 
 
 extern unsigned int page_size;
 extern unsigned int page_size;
 
 
+struct winsize;
+void get_term_dimensions(struct winsize *ws);
+
 #endif
 #endif