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:

 * Align the 'Ok'/'FAILED!' test results in 'perf test.

 * Support interrupted syscalls in 'trace'

 * Add an event duration column and filter in 'trace'.

 * There are references to the man pages in some tools, so try to build
   Documentation when installing, warning the user if that is not possible,
   from Borislav Petkov.

 * Give user better message if precise is not supported, from David Ahern.

 * Try to find cross-built objdump path by using the session environment
   information in the perf.data file header, from Irina Tirdea, original
   patch and idea by Namhyung Kim.

 * Diplays more output on features check for make V=1, so that one can figure
   out what is happening by looking at gcc output, etc. From Jiri Olsa.

 * Account the nr_entries in rblist properly, fix by Suzuki K. Poulose.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Ingo Molnar 12 years ago
parent
commit
6ca2a9c654

+ 29 - 2
tools/perf/Documentation/Makefile

@@ -1,3 +1,5 @@
+include ../config/utilities.mak
+
 OUTPUT := ./
 OUTPUT := ./
 ifeq ("$(origin O)", "command line")
 ifeq ("$(origin O)", "command line")
   ifneq ($(O),)
   ifneq ($(O),)
@@ -64,6 +66,7 @@ MAKEINFO=makeinfo
 INSTALL_INFO=install-info
 INSTALL_INFO=install-info
 DOCBOOK2X_TEXI=docbook2x-texi
 DOCBOOK2X_TEXI=docbook2x-texi
 DBLATEX=dblatex
 DBLATEX=dblatex
+XMLTO=xmlto
 ifndef PERL_PATH
 ifndef PERL_PATH
 	PERL_PATH = /usr/bin/perl
 	PERL_PATH = /usr/bin/perl
 endif
 endif
@@ -71,6 +74,16 @@ endif
 -include ../config.mak.autogen
 -include ../config.mak.autogen
 -include ../config.mak
 -include ../config.mak
 
 
+_tmp_tool_path := $(call get-executable,$(ASCIIDOC))
+ifeq ($(_tmp_tool_path),)
+	missing_tools = $(ASCIIDOC)
+endif
+
+_tmp_tool_path := $(call get-executable,$(XMLTO))
+ifeq ($(_tmp_tool_path),)
+	missing_tools += $(XMLTO)
+endif
+
 #
 #
 # For asciidoc ...
 # For asciidoc ...
 #	-7.1.2,	no extra settings are needed.
 #	-7.1.2,	no extra settings are needed.
@@ -170,7 +183,12 @@ pdf: $(OUTPUT)user-manual.pdf
 
 
 install: install-man
 install: install-man
 
 
-install-man: man
+check-man-tools:
+ifdef missing_tools
+	$(error "You need to install $(missing_tools) for man pages")
+endif
+
+do-install-man: man
 	$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
 	$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
 #	$(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
 #	$(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
 #	$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
 #	$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
@@ -178,6 +196,15 @@ install-man: man
 #	$(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
 #	$(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
 #	$(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
 #	$(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
 
 
+install-man: check-man-tools man
+
+try-install-man:
+ifdef missing_tools
+	$(warning Please install $(missing_tools) to have the man pages installed)
+else
+	$(MAKE) do-install-man
+endif
+
 install-info: info
 install-info: info
 	$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
 	$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
 	$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
 	$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
@@ -246,7 +273,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
 
 
 $(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
 $(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
 	$(QUIET_XMLTO)$(RM) $@ && \
 	$(QUIET_XMLTO)$(RM) $@ && \
-	xmlto -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+	$(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
 
 
 $(OUTPUT)%.xml : %.txt
 $(OUTPUT)%.xml : %.txt
 	$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
 	$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \

+ 3 - 0
tools/perf/Documentation/perf-trace.txt

@@ -48,6 +48,9 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
 In per-thread mode with inheritance mode on (default), Events are captured only when
 In per-thread mode with inheritance mode on (default), Events are captured only when
 the thread executes on the designated CPUs. Default is to monitor all CPUs.
 the thread executes on the designated CPUs. Default is to monitor all CPUs.
 
 
+--duration:
+	Show only events that had a duration greater than N.M ms.
+
 SEE ALSO
 SEE ALSO
 --------
 --------
 linkperf:perf-record[1], linkperf:perf-script[1]
 linkperf:perf-record[1], linkperf:perf-script[1]

+ 29 - 24
tools/perf/Makefile

@@ -155,15 +155,15 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
 
 
 -include config/feature-tests.mak
 -include config/feature-tests.mak
 
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all),y)
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
 	CFLAGS := $(CFLAGS) -fstack-protector-all
 	CFLAGS := $(CFLAGS) -fstack-protector-all
 endif
 endif
 
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector),y)
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
        CFLAGS := $(CFLAGS) -Wstack-protector
        CFLAGS := $(CFLAGS) -Wstack-protector
 endif
 endif
 
 
-ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var),y)
+ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
        CFLAGS := $(CFLAGS) -Wvolatile-register-var
        CFLAGS := $(CFLAGS) -Wvolatile-register-var
 endif
 endif
 
 
@@ -172,7 +172,7 @@ endif
 BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_LDFLAGS =
 BASIC_LDFLAGS =
 
 
-ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS)),y)
+ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
 	BIONIC := 1
 	BIONIC := 1
 	EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
 	EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
 	EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
 	EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
@@ -426,6 +426,8 @@ LIB_OBJS += $(OUTPUT)ui/helpline.o
 LIB_OBJS += $(OUTPUT)ui/hist.o
 LIB_OBJS += $(OUTPUT)ui/hist.o
 LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
 LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
 
 
+LIB_OBJS += $(OUTPUT)arch/common.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
 # Benchmark modules
 # Benchmark modules
@@ -477,9 +479,9 @@ ifdef NO_LIBELF
 	NO_LIBUNWIND := 1
 	NO_LIBUNWIND := 1
 else
 else
 FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
 FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
-ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
+ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
 	FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
 	FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
-	ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
+	ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
 		LIBC_SUPPORT := 1
 		LIBC_SUPPORT := 1
 	endif
 	endif
 	ifeq ($(BIONIC),1)
 	ifeq ($(BIONIC),1)
@@ -494,7 +496,7 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
 	endif
 	endif
 else
 else
 	FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
 	FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
-	ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
+	ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
 		msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
 		msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
 		NO_DWARF := 1
 		NO_DWARF := 1
 	endif # Dwarf support
 	endif # Dwarf support
@@ -510,7 +512,7 @@ ifdef LIBUNWIND_DIR
 endif
 endif
 
 
 FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
 FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
-ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y)
+ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
 	msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
 	msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
 	NO_LIBUNWIND := 1
 	NO_LIBUNWIND := 1
 endif # Libunwind support
 endif # Libunwind support
@@ -539,7 +541,7 @@ LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
 else # NO_LIBELF
 else # NO_LIBELF
 BASIC_CFLAGS += -DLIBELF_SUPPORT
 BASIC_CFLAGS += -DLIBELF_SUPPORT
 
 
-ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
+ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON),-DLIBELF_MMAP),y)
 	BASIC_CFLAGS += -DLIBELF_MMAP
 	BASIC_CFLAGS += -DLIBELF_MMAP
 endif
 endif
 
 
@@ -565,7 +567,7 @@ endif
 
 
 ifndef NO_LIBAUDIT
 ifndef NO_LIBAUDIT
 	FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
 	FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
-	ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y)
+	ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
 		msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
 		msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
 	else
 	else
 		BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
 		BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
@@ -576,7 +578,7 @@ endif
 
 
 ifndef NO_NEWT
 ifndef NO_NEWT
 	FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
 	FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
-	ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
+	ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y)
 		msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
 		msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
 	else
 	else
 		# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
 		# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
@@ -605,10 +607,10 @@ endif
 
 
 ifndef NO_GTK2
 ifndef NO_GTK2
 	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
 	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
-	ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
+	ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
 		msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
 		msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
 	else
 	else
-		ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
+		ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
 			BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
 			BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
 		endif
 		endif
 		BASIC_CFLAGS += -DGTK2_SUPPORT
 		BASIC_CFLAGS += -DGTK2_SUPPORT
@@ -635,7 +637,7 @@ else
 	PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
 	PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
 	FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 	FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 
 
-	ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
+	ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
 		BASIC_CFLAGS += -DNO_LIBPERL
 		BASIC_CFLAGS += -DNO_LIBPERL
 	else
 	else
                ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
                ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
@@ -689,11 +691,11 @@ else
       PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
       PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
       FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
       FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
 
 
-      ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
+      ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
         $(call disable-python,Python.h (for Python 2.x))
         $(call disable-python,Python.h (for Python 2.x))
       else
       else
 
 
-        ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y)
+        ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
           $(warning Python 3 is not yet supported; please set)
           $(warning Python 3 is not yet supported; please set)
           $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
           $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
           $(warning If you also have Python 2 installed, then)
           $(warning If you also have Python 2 installed, then)
@@ -727,22 +729,22 @@ else
 		BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
 		BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
         else
         else
 		FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
 		FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
-		has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
+		has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
 		ifeq ($(has_bfd),y)
 		ifeq ($(has_bfd),y)
 			EXTLIBS += -lbfd
 			EXTLIBS += -lbfd
 		else
 		else
 			FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
 			FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
-			has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
+			has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
 			ifeq ($(has_bfd_iberty),y)
 			ifeq ($(has_bfd_iberty),y)
 				EXTLIBS += -lbfd -liberty
 				EXTLIBS += -lbfd -liberty
 			else
 			else
 				FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
 				FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
-				has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
+				has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
 				ifeq ($(has_bfd_iberty_z),y)
 				ifeq ($(has_bfd_iberty_z),y)
 					EXTLIBS += -lbfd -liberty -lz
 					EXTLIBS += -lbfd -liberty -lz
 				else
 				else
 					FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
 					FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
-					has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
+					has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
 					ifeq ($(has_cplus_demangle),y)
 					ifeq ($(has_cplus_demangle),y)
 						EXTLIBS += -liberty
 						EXTLIBS += -liberty
 						BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
 						BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -764,19 +766,19 @@ ifeq ($(NO_PERF_REGS),0)
 endif
 endif
 
 
 ifndef NO_STRLCPY
 ifndef NO_STRLCPY
-	ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y)
+	ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
 		BASIC_CFLAGS += -DHAVE_STRLCPY
 		BASIC_CFLAGS += -DHAVE_STRLCPY
 	endif
 	endif
 endif
 endif
 
 
 ifndef NO_ON_EXIT
 ifndef NO_ON_EXIT
-	ifeq ($(call try-cc,$(SOURCE_ON_EXIT),),y)
+	ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
 		BASIC_CFLAGS += -DHAVE_ON_EXIT
 		BASIC_CFLAGS += -DHAVE_ON_EXIT
 	endif
 	endif
 endif
 endif
 
 
 ifndef NO_BACKTRACE
 ifndef NO_BACKTRACE
-       ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y)
+       ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
                BASIC_CFLAGS += -DBACKTRACE_SUPPORT
                BASIC_CFLAGS += -DBACKTRACE_SUPPORT
        endif
        endif
 endif
 endif
@@ -1039,7 +1041,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
 endif
 endif
 perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
 perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
 
 
-install: all
+install: all try-install-man
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1065,6 +1067,9 @@ install-doc:
 install-man:
 install-man:
 	$(MAKE) -C Documentation install-man
 	$(MAKE) -C Documentation install-man
 
 
+try-install-man:
+	$(MAKE) -C Documentation try-install-man
+
 install-html:
 install-html:
 	$(MAKE) -C Documentation install-html
 	$(MAKE) -C Documentation install-html
 
 

+ 178 - 0
tools/perf/arch/common.c

@@ -0,0 +1,178 @@
+#include <stdio.h>
+#include <sys/utsname.h>
+#include "common.h"
+#include "../util/debug.h"
+
+const char *const arm_triplets[] = {
+	"arm-eabi-",
+	"arm-linux-androideabi-",
+	"arm-unknown-linux-",
+	"arm-unknown-linux-gnu-",
+	"arm-unknown-linux-gnueabi-",
+	NULL
+};
+
+const char *const powerpc_triplets[] = {
+	"powerpc-unknown-linux-gnu-",
+	"powerpc64-unknown-linux-gnu-",
+	NULL
+};
+
+const char *const s390_triplets[] = {
+	"s390-ibm-linux-",
+	NULL
+};
+
+const char *const sh_triplets[] = {
+	"sh-unknown-linux-gnu-",
+	"sh64-unknown-linux-gnu-",
+	NULL
+};
+
+const char *const sparc_triplets[] = {
+	"sparc-unknown-linux-gnu-",
+	"sparc64-unknown-linux-gnu-",
+	NULL
+};
+
+const char *const x86_triplets[] = {
+	"x86_64-pc-linux-gnu-",
+	"x86_64-unknown-linux-gnu-",
+	"i686-pc-linux-gnu-",
+	"i586-pc-linux-gnu-",
+	"i486-pc-linux-gnu-",
+	"i386-pc-linux-gnu-",
+	"i686-linux-android-",
+	"i686-android-linux-",
+	NULL
+};
+
+const char *const mips_triplets[] = {
+	"mips-unknown-linux-gnu-",
+	"mipsel-linux-android-",
+	NULL
+};
+
+static bool lookup_path(char *name)
+{
+	bool found = false;
+	char *path, *tmp;
+	char buf[PATH_MAX];
+	char *env = getenv("PATH");
+
+	if (!env)
+		return false;
+
+	env = strdup(env);
+	if (!env)
+		return false;
+
+	path = strtok_r(env, ":", &tmp);
+	while (path) {
+		scnprintf(buf, sizeof(buf), "%s/%s", path, name);
+		if (access(buf, F_OK) == 0) {
+			found = true;
+			break;
+		}
+		path = strtok_r(NULL, ":", &tmp);
+	}
+	free(env);
+	return found;
+}
+
+static int lookup_triplets(const char *const *triplets, const char *name)
+{
+	int i;
+	char buf[PATH_MAX];
+
+	for (i = 0; triplets[i] != NULL; i++) {
+		scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name);
+		if (lookup_path(buf))
+			return i;
+	}
+	return -1;
+}
+
+static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
+						  const char *name,
+						  const char **path)
+{
+	int idx;
+	char *arch, *cross_env;
+	struct utsname uts;
+	const char *const *path_list;
+	char *buf = NULL;
+
+	if (uname(&uts) < 0)
+		goto out;
+
+	/*
+	 * We don't need to try to find objdump path for native system.
+	 * Just use default binutils path (e.g.: "objdump").
+	 */
+	if (!strcmp(uts.machine, env->arch))
+		goto out;
+
+	cross_env = getenv("CROSS_COMPILE");
+	if (cross_env) {
+		if (asprintf(&buf, "%s%s", cross_env, name) < 0)
+			goto out_error;
+		if (buf[0] == '/') {
+			if (access(buf, F_OK) == 0)
+				goto out;
+			goto out_error;
+		}
+		if (lookup_path(buf))
+			goto out;
+		free(buf);
+	}
+
+	arch = env->arch;
+
+	if (!strcmp(arch, "arm"))
+		path_list = arm_triplets;
+	else if (!strcmp(arch, "powerpc"))
+		path_list = powerpc_triplets;
+	else if (!strcmp(arch, "sh"))
+		path_list = sh_triplets;
+	else if (!strcmp(arch, "s390"))
+		path_list = s390_triplets;
+	else if (!strcmp(arch, "sparc"))
+		path_list = sparc_triplets;
+	else if (!strcmp(arch, "x86") || !strcmp(arch, "i386") ||
+		 !strcmp(arch, "i486") || !strcmp(arch, "i586") ||
+		 !strcmp(arch, "i686"))
+		path_list = x86_triplets;
+	else if (!strcmp(arch, "mips"))
+		path_list = mips_triplets;
+	else {
+		ui__error("binutils for %s not supported.\n", arch);
+		goto out_error;
+	}
+
+	idx = lookup_triplets(path_list, name);
+	if (idx < 0) {
+		ui__error("Please install %s for %s.\n"
+			  "You can add it to PATH, set CROSS_COMPILE or "
+			  "override the default using --%s.\n",
+			  name, arch, name);
+		goto out_error;
+	}
+
+	if (asprintf(&buf, "%s%s", path_list[idx], name) < 0)
+		goto out_error;
+
+out:
+	*path = buf;
+	return 0;
+out_error:
+	free(buf);
+	*path = NULL;
+	return -1;
+}
+
+int perf_session_env__lookup_objdump(struct perf_session_env *env)
+{
+	return perf_session_env__lookup_binutils_path(env, "objdump",
+						      &objdump_path);
+}

+ 10 - 0
tools/perf/arch/common.h

@@ -0,0 +1,10 @@
+#ifndef ARCH_PERF_COMMON_H
+#define ARCH_PERF_COMMON_H
+
+#include "../util/session.h"
+
+extern const char *objdump_path;
+
+int perf_session_env__lookup_objdump(struct perf_session_env *env);
+
+#endif /* ARCH_PERF_COMMON_H */

+ 7 - 0
tools/perf/builtin-annotate.c

@@ -28,6 +28,7 @@
 #include "util/hist.h"
 #include "util/hist.h"
 #include "util/session.h"
 #include "util/session.h"
 #include "util/tool.h"
 #include "util/tool.h"
+#include "arch/common.h"
 
 
 #include <linux/bitmap.h>
 #include <linux/bitmap.h>
 
 
@@ -186,6 +187,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
 			goto out_delete;
 			goto out_delete;
 	}
 	}
 
 
+	if (!objdump_path) {
+		ret = perf_session_env__lookup_objdump(&session->header.env);
+		if (ret)
+			goto out_delete;
+	}
+
 	ret = perf_session__process_events(session, &ann->tool);
 	ret = perf_session__process_events(session, &ann->tool);
 	if (ret)
 	if (ret)
 		goto out_delete;
 		goto out_delete;

+ 5 - 0
tools/perf/builtin-record.c

@@ -317,6 +317,11 @@ try_again:
 					  perf_evsel__name(pos));
 					  perf_evsel__name(pos));
 				rc = -err;
 				rc = -err;
 				goto out;
 				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");
 			printf("\n");

+ 7 - 0
tools/perf/builtin-report.c

@@ -33,6 +33,7 @@
 #include "util/thread.h"
 #include "util/thread.h"
 #include "util/sort.h"
 #include "util/sort.h"
 #include "util/hist.h"
 #include "util/hist.h"
+#include "arch/common.h"
 
 
 #include <linux/bitmap.h>
 #include <linux/bitmap.h>
 
 
@@ -672,6 +673,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 	has_br_stack = perf_header__has_feat(&session->header,
 	has_br_stack = perf_header__has_feat(&session->header,
 					     HEADER_BRANCH_STACK);
 					     HEADER_BRANCH_STACK);
 
 
+	if (!objdump_path) {
+		ret = perf_session_env__lookup_objdump(&session->header.env);
+		if (ret)
+			goto error;
+	}
+
 	if (sort__branch_mode == -1 && has_br_stack)
 	if (sort__branch_mode == -1 && has_br_stack)
 		sort__branch_mode = 1;
 		sort__branch_mode = 1;
 
 

+ 16 - 2
tools/perf/builtin-test.c

@@ -6,6 +6,7 @@
 #include "builtin.h"
 #include "builtin.h"
 
 
 #include "util/cache.h"
 #include "util/cache.h"
+#include "util/color.h"
 #include "util/debug.h"
 #include "util/debug.h"
 #include "util/debugfs.h"
 #include "util/debugfs.h"
 #include "util/evlist.h"
 #include "util/evlist.h"
@@ -1485,18 +1486,31 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
 static int __cmd_test(int argc, const char *argv[])
 static int __cmd_test(int argc, const char *argv[])
 {
 {
 	int i = 0;
 	int i = 0;
+	int width = 0;
 
 
+	while (tests[i].func) {
+		int len = strlen(tests[i].desc);
+
+		if (width < len)
+			width = len;
+		++i;
+	}
+		
+	i = 0;
 	while (tests[i].func) {
 	while (tests[i].func) {
 		int curr = i++, err;
 		int curr = i++, err;
 
 
 		if (!perf_test__matches(curr, argc, argv))
 		if (!perf_test__matches(curr, argc, argv))
 			continue;
 			continue;
 
 
-		pr_info("%2d: %s:", i, tests[curr].desc);
+		pr_info("%2d: %-*s:", i, width, tests[curr].desc);
 		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);
-		pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
+		if (err)
+			color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
+		else
+			pr_info(" Ok\n");
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 4 - 0
tools/perf/builtin-top.c

@@ -977,6 +977,10 @@ try_again:
 				ui__error("Too many events are opened.\n"
 				ui__error("Too many events are opened.\n"
 					    "Try again after reducing the number of events\n");
 					    "Try again after reducing the number of events\n");
 				goto out_err;
 				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 "
 			ui__error("The sys_perf_event_open() syscall "

+ 227 - 23
tools/perf/builtin-trace.c

@@ -1,5 +1,8 @@
 #include "builtin.h"
 #include "builtin.h"
+#include "util/color.h"
 #include "util/evlist.h"
 #include "util/evlist.h"
+#include "util/machine.h"
+#include "util/thread.h"
 #include "util/parse-options.h"
 #include "util/parse-options.h"
 #include "util/thread_map.h"
 #include "util/thread_map.h"
 #include "event-parse.h"
 #include "event-parse.h"
@@ -13,15 +16,18 @@ static struct syscall_fmt {
 	bool	   errmsg;
 	bool	   errmsg;
 	bool	   timeout;
 	bool	   timeout;
 } syscall_fmts[] = {
 } syscall_fmts[] = {
+	{ .name	    = "access",	    .errmsg = true, },
 	{ .name	    = "arch_prctl", .errmsg = true, .alias = "prctl", },
 	{ .name	    = "arch_prctl", .errmsg = true, .alias = "prctl", },
 	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat", },
 	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat", },
 	{ .name	    = "fstatat",    .errmsg = true, .alias = "newfstatat", },
 	{ .name	    = "fstatat",    .errmsg = true, .alias = "newfstatat", },
 	{ .name	    = "futex",	    .errmsg = true, },
 	{ .name	    = "futex",	    .errmsg = true, },
+	{ .name	    = "open",	    .errmsg = true, },
 	{ .name	    = "poll",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "poll",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "ppoll",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "ppoll",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "read",	    .errmsg = true, },
 	{ .name	    = "read",	    .errmsg = true, },
 	{ .name	    = "recvfrom",   .errmsg = true, },
 	{ .name	    = "recvfrom",   .errmsg = true, },
 	{ .name	    = "select",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "select",	    .errmsg = true, .timeout = true, },
+	{ .name	    = "socket",	    .errmsg = true, },
 	{ .name	    = "stat",	    .errmsg = true, .alias = "newstat", },
 	{ .name	    = "stat",	    .errmsg = true, .alias = "newstat", },
 };
 };
 
 
@@ -43,6 +49,50 @@ struct syscall {
 	struct syscall_fmt  *fmt;
 	struct syscall_fmt  *fmt;
 };
 };
 
 
+static size_t fprintf_duration(unsigned long t, FILE *fp)
+{
+	double duration = (double)t / NSEC_PER_MSEC;
+	size_t printed = fprintf(fp, "(");
+
+	if (duration >= 1.0)
+		printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
+	else if (duration >= 0.01)
+		printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
+	else
+		printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
+	return printed + fprintf(stdout, "): ");
+}
+
+struct thread_trace {
+	u64		  entry_time;
+	u64		  exit_time;
+	bool		  entry_pending;
+	char		  *entry_str;
+};
+
+static struct thread_trace *thread_trace__new(void)
+{
+	return zalloc(sizeof(struct thread_trace));
+}
+
+static struct thread_trace *thread__trace(struct thread *thread)
+{
+	if (thread == NULL)
+		goto fail;
+
+	if (thread->priv == NULL)
+		thread->priv = thread_trace__new();
+
+	if (thread->priv == NULL)
+		goto fail;
+
+	return thread->priv;
+fail:
+	color_fprintf(stdout, PERF_COLOR_RED,
+		      "WARNING: not enough memory, dropping samples!\n");
+	return NULL;
+}
+
 struct trace {
 struct trace {
 	int			audit_machine;
 	int			audit_machine;
 	struct {
 	struct {
@@ -50,8 +100,24 @@ struct trace {
 		struct syscall  *table;
 		struct syscall  *table;
 	} syscalls;
 	} syscalls;
 	struct perf_record_opts opts;
 	struct perf_record_opts opts;
+	struct machine		host;
+	u64			base_time;
+	bool			multiple_threads;
+	double			duration_filter;
 };
 };
 
 
+static bool trace__filter_duration(struct trace *trace, double t)
+{
+	return t < (trace->duration_filter * NSEC_PER_MSEC);
+}
+
+static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
+{
+	double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
+
+	return fprintf(fp, "%10.3f ", ts);
+}
+
 static bool done = false;
 static bool done = false;
 
 
 static void sig_handler(int sig __maybe_unused)
 static void sig_handler(int sig __maybe_unused)
@@ -59,6 +125,68 @@ static void sig_handler(int sig __maybe_unused)
 	done = true;
 	done = true;
 }
 }
 
 
+static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
+					u64 duration, u64 tstamp, FILE *fp)
+{
+	size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
+	printed += fprintf_duration(duration, fp);
+
+	if (trace->multiple_threads)
+		printed += fprintf(fp, "%d ", thread->pid);
+
+	return printed;
+}
+
+static int trace__process_event(struct machine *machine, union perf_event *event)
+{
+	int ret = 0;
+
+	switch (event->header.type) {
+	case PERF_RECORD_LOST:
+		color_fprintf(stdout, PERF_COLOR_RED,
+			      "LOST %" PRIu64 " events!\n", event->lost.lost);
+		ret = machine__process_lost_event(machine, event);
+	default:
+		ret = machine__process_event(machine, event);
+		break;
+	}
+
+	return ret;
+}
+
+static int trace__tool_process(struct perf_tool *tool __maybe_unused,
+			       union perf_event *event,
+			       struct perf_sample *sample __maybe_unused,
+			       struct machine *machine)
+{
+	return trace__process_event(machine, event);
+}
+
+static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
+{
+	int err = symbol__init();
+
+	if (err)
+		return err;
+
+	machine__init(&trace->host, "", HOST_KERNEL_ID);
+	machine__create_kernel_maps(&trace->host);
+
+	if (perf_target__has_task(&trace->opts.target)) {
+		err = perf_event__synthesize_thread_map(NULL, evlist->threads,
+							trace__tool_process,
+							&trace->host);
+	} else {
+		err = perf_event__synthesize_threads(NULL, trace__tool_process,
+						     &trace->host);
+	}
+
+	if (err)
+		symbol__exit();
+
+	return err;
+}
+
 static int trace__read_syscall_info(struct trace *trace, int id)
 static int trace__read_syscall_info(struct trace *trace, int id)
 {
 {
 	char tp_name[128];
 	char tp_name[128];
@@ -100,7 +228,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
 	return sc->tp_format != NULL ? 0 : -1;
 	return sc->tp_format != NULL ? 0 : -1;
 }
 }
 
 
-static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp)
+static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
+				      unsigned long *args)
 {
 {
 	int i = 0;
 	int i = 0;
 	size_t printed = 0;
 	size_t printed = 0;
@@ -109,12 +238,15 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL
 		struct format_field *field;
 		struct format_field *field;
 
 
 		for (field = sc->tp_format->format.fields->next; field; field = field->next) {
 		for (field = sc->tp_format->format.fields->next; field; field = field->next) {
-			printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "",
-					   field->name, args[i++]);
+			printed += scnprintf(bf + printed, size - printed,
+					     "%s%s: %ld", printed ? ", " : "",
+					     field->name, args[i++]);
 		}
 		}
 	} else {
 	} else {
 		while (i < 6) {
 		while (i < 6) {
-			printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]);
+			printed += scnprintf(bf + printed, size - printed,
+					     "%sarg%d: %ld",
+					     printed ? ", " : "", i, args[i]);
 			++i;
 			++i;
 		}
 		}
 	}
 	}
@@ -146,17 +278,24 @@ static struct syscall *trace__syscall_info(struct trace *trace,
 	return &trace->syscalls.table[id];
 	return &trace->syscalls.table[id];
 
 
 out_cant_read:
 out_cant_read:
-	printf("Problems reading syscall %d information\n", id);
+	printf("Problems reading syscall %d", id);
+	if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
+		printf("(%s)", trace->syscalls.table[id].name);
+	puts(" information");
 	return NULL;
 	return NULL;
 }
 }
 
 
 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 			    struct perf_sample *sample)
 			    struct perf_sample *sample)
 {
 {
+	char *msg;
 	void *args;
 	void *args;
+	size_t printed = 0;
+	struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
+	struct thread_trace *ttrace = thread__trace(thread);
 
 
-	if (sc == NULL)
+	if (ttrace == NULL || sc == NULL)
 		return -1;
 		return -1;
 
 
 	args = perf_evsel__rawptr(evsel, sample, "args");
 	args = perf_evsel__rawptr(evsel, sample, "args");
@@ -165,8 +304,27 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	printf("%s(", sc->name);
-	syscall__fprintf_args(sc, args, stdout);
+	ttrace = thread->priv;
+
+	if (ttrace->entry_str == NULL) {
+		ttrace->entry_str = malloc(1024);
+		if (!ttrace->entry_str)
+			return -1;
+	}
+
+	ttrace->entry_time = sample->time;
+	msg = ttrace->entry_str;
+	printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
+
+	printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,  args);
+
+	if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
+		if (!trace->duration_filter) {
+			trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
+			printf("%-70s\n", ttrace->entry_str);
+		}
+	} else
+		ttrace->entry_pending = true;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -175,13 +333,37 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 			   struct perf_sample *sample)
 			   struct perf_sample *sample)
 {
 {
 	int ret;
 	int ret;
+	u64 duration = 0;
+	struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
+	struct thread_trace *ttrace = thread__trace(thread);
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
 
 
-	if (sc == NULL)
+	if (ttrace == NULL || sc == NULL)
 		return -1;
 		return -1;
 
 
 	ret = perf_evsel__intval(evsel, sample, "ret");
 	ret = perf_evsel__intval(evsel, sample, "ret");
 
 
+	ttrace = thread->priv;
+
+	ttrace->exit_time = sample->time;
+
+	if (ttrace->entry_time) {
+		duration = sample->time - ttrace->entry_time;
+		if (trace__filter_duration(trace, duration))
+			goto out;
+	} else if (trace->duration_filter)
+		goto out;
+
+	trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
+
+	if (ttrace->entry_pending) {
+		printf("%-70s", ttrace->entry_str);
+	} else {
+		printf(" ... [");
+		color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
+		printf("]: %s()", sc->name);
+	}
+
 	if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
 	if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
 		char bf[256];
 		char bf[256];
 		const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
 		const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
@@ -194,6 +376,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
 		printf(") = %d", ret);
 		printf(") = %d", ret);
 
 
 	putchar('\n');
 	putchar('\n');
+out:
+	ttrace->entry_pending = false;
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -221,6 +406,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 		goto out_delete_evlist;
 		goto out_delete_evlist;
 	}
 	}
 
 
+	err = trace__symbols_init(trace, evlist);
+	if (err < 0) {
+		printf("Problems initializing symbol libraries!\n");
+		goto out_delete_evlist;
+	}
+
 	perf_evlist__config_attrs(evlist, &trace->opts);
 	perf_evlist__config_attrs(evlist, &trace->opts);
 
 
 	signal(SIGCHLD, sig_handler);
 	signal(SIGCHLD, sig_handler);
@@ -251,6 +442,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
 	if (forks)
 	if (forks)
 		perf_evlist__start_workload(evlist);
 		perf_evlist__start_workload(evlist);
 
 
+	trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
 again:
 again:
 	before = nr_events;
 	before = nr_events;
 
 
@@ -264,32 +456,32 @@ again:
 
 
 			++nr_events;
 			++nr_events;
 
 
-			switch (type) {
-			case PERF_RECORD_SAMPLE:
-				break;
-			case PERF_RECORD_LOST:
-				printf("LOST %" PRIu64 " events!\n", event->lost.lost);
-				continue;
-			default:
-				printf("Unexpected %s event, skipping...\n",
-					perf_event__name(type));
-				continue;
-			}
-
 			err = perf_evlist__parse_sample(evlist, event, &sample);
 			err = perf_evlist__parse_sample(evlist, event, &sample);
 			if (err) {
 			if (err) {
 				printf("Can't parse sample, err = %d, skipping...\n", err);
 				printf("Can't parse sample, err = %d, skipping...\n", err);
 				continue;
 				continue;
 			}
 			}
 
 
+			if (trace->base_time == 0)
+				trace->base_time = sample.time;
+
+			if (type != PERF_RECORD_SAMPLE) {
+				trace__process_event(&trace->host, event);
+				continue;
+			}
+
 			evsel = perf_evlist__id2evsel(evlist, sample.id);
 			evsel = perf_evlist__id2evsel(evlist, sample.id);
 			if (evsel == NULL) {
 			if (evsel == NULL) {
 				printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
 				printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
 				continue;
 				continue;
 			}
 			}
 
 
-			if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1)
-				printf("%d ", sample.tid);
+			if (sample.raw_data == NULL) {
+				printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
+				       perf_evsel__name(evsel), sample.tid,
+				       sample.cpu, sample.raw_size);
+				continue;
+			}
 
 
 			if (sample.raw_data == NULL) {
 			if (sample.raw_data == NULL) {
 				printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
 				printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
@@ -321,6 +513,15 @@ out:
 	return err;
 	return err;
 }
 }
 
 
+static int trace__set_duration(const struct option *opt, const char *str,
+			       int unset __maybe_unused)
+{
+	struct trace *trace = opt->value;
+
+	trace->duration_filter = atof(str);
+	return 0;
+}
+
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 {
 	const char * const trace_usage[] = {
 	const char * const trace_usage[] = {
@@ -359,6 +560,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 		     "number of mmap data pages"),
 		     "number of mmap data pages"),
 	OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
 	OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
 		   "user to profile"),
 		   "user to profile"),
+	OPT_CALLBACK(0, "duration", &trace, "float",
+		     "show only events with duration > N.M ms",
+		     trace__set_duration),
 	OPT_END()
 	OPT_END()
 	};
 	};
 	int err;
 	int err;

+ 4 - 1
tools/perf/config/feature-tests.mak

@@ -121,7 +121,10 @@ define SOURCE_PYTHON_VERSION
 #if PY_VERSION_HEX >= 0x03000000
 #if PY_VERSION_HEX >= 0x03000000
 	#error
 	#error
 #endif
 #endif
-int main(void){}
+int main(void)
+{
+	return 0;
+}
 endef
 endef
 define SOURCE_PYTHON_EMBED
 define SOURCE_PYTHON_EMBED
 #include <Python.h>
 #include <Python.h>

+ 9 - 2
tools/perf/config/utilities.mak

@@ -180,9 +180,16 @@ _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))
 
 
 # try-cc
 # try-cc
-# Usage: option = $(call try-cc, source-to-build, cc-options)
+# Usage: option = $(call try-cc, source-to-build, cc-options, msg)
+ifndef V
+TRY_CC_OUTPUT= > /dev/null 2>&1
+else
+TRY_CC_MSG=echo "CHK $(3)" 1>&2;
+endif
+
 try-cc = $(shell sh -c						  \
 try-cc = $(shell sh -c						  \
 	'TMP="$(OUTPUT)$(TMPOUT).$$$$";				  \
 	'TMP="$(OUTPUT)$(TMPOUT).$$$$";				  \
+	 $(TRY_CC_MSG)						  \
 	 echo "$(1)" |						  \
 	 echo "$(1)" |						  \
-	 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
+	 $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
 	 rm -f "$$TMP"')
 	 rm -f "$$TMP"')

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

@@ -154,6 +154,5 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
 #endif
 #endif
 
 
 extern const char	*disassembler_style;
 extern const char	*disassembler_style;
-extern const char	*objdump_path;
 
 
 #endif	/* __PERF_ANNOTATE_H */
 #endif	/* __PERF_ANNOTATE_H */

+ 1 - 1
tools/perf/util/parse-events.c

@@ -1081,7 +1081,7 @@ void print_events(const char *event_glob, bool name_only)
 		printf("  %-50s [%s]\n",
 		printf("  %-50s [%s]\n",
 		       "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
 		       "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
 		       event_type_descriptors[PERF_TYPE_RAW]);
 		       event_type_descriptors[PERF_TYPE_RAW]);
-		printf("   (see 'perf list --help' on how to encode it)\n");
+		printf("   (see 'man perf-list' on how to encode it)\n");
 		printf("\n");
 		printf("\n");
 
 
 		printf("  %-50s [%s]\n",
 		printf("  %-50s [%s]\n",

+ 2 - 2
tools/perf/util/rblist.c

@@ -44,6 +44,7 @@ int rblist__add_node(struct rblist *rblist, const void *new_entry)
 void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
 void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
 {
 {
 	rb_erase(rb_node, &rblist->entries);
 	rb_erase(rb_node, &rblist->entries);
+	--rblist->nr_entries;
 	rblist->node_delete(rblist, rb_node);
 	rblist->node_delete(rblist, rb_node);
 }
 }
 
 
@@ -87,8 +88,7 @@ void rblist__delete(struct rblist *rblist)
 		while (next) {
 		while (next) {
 			pos = next;
 			pos = next;
 			next = rb_next(pos);
 			next = rb_next(pos);
-			rb_erase(pos, &rblist->entries);
-			rblist->node_delete(rblist, pos);
+			rblist__remove_node(rblist, pos);
 		}
 		}
 		free(rblist);
 		free(rblist);
 	}
 	}

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

@@ -198,6 +198,10 @@ static inline int has_extension(const char *filename, const char *ext)
 #undef tolower
 #undef tolower
 #undef toupper
 #undef toupper
 
 
+#ifndef NSEC_PER_MSEC
+#define NSEC_PER_MSEC	1000000L
+#endif
+
 extern unsigned char sane_ctype[256];
 extern unsigned char sane_ctype[256];
 #define GIT_SPACE		0x01
 #define GIT_SPACE		0x01
 #define GIT_DIGIT		0x02
 #define GIT_DIGIT		0x02