提交 1ff9ecf7 编写于 作者: I Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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:

  * kcore annotation improvements, including build-id cache support,
    multi map 'call' instruction navigation fixes, kcore address
    validation, objdump workarounds. From Adrian Hunter.

  * 'trace' beautifiers for lots of syscall arguments, from Arnaldo Carvalho de Melo.

  * More compact 'trace' output by suppressing zeroed args, from Arnaldo Carvalho de Melo.

  * Show thread COMM by default in 'trace', from Arnaldo Carvalho de Melo.

  * Show path associated with fd in live sessions, using a 'vfs_getname'
    'perf probe' created dynamic tracepoint or by looking at /proc/pid/fd, from Arnaldo Carvalho de Melo.

  * Memory and mmap leak fixes from Chenggang Qin.

  * Add option to show full timestamp in 'trace', from David Ahern.

  * Add 'record' command in 'trace', to record raw_syscalls:*, from David Ahern.

  * Add summary option to dump syscall statistics in 'trace', from David Ahern.

  * Fix comm resolution in 'trace' when reading events from file, from David Ahern.

  * Improved messages when doing profiling in all or a subset of CPUs
    using a workload as the session delimitator, as in:

     'perf stat --cpu 0,2 sleep 10s'

    from Arnaldo Carvalho de Melo.

  * Add units to nanosec-based counters in 'perf stat', from David Ahern.

  * Assorted build fixes for from David Ahern and Jiri Olsa.

  * 'perf lock' fixes and cleanups, from Davidlohr Bueso.

  * Memory leak fixes in 'perf test', from Felipe Pena.

  * Build system super speedups, from Ingo Molnar.

  * Fix mmap_read event overflow, from Jiri Olsa.

  * Code cleanups from Jiri Olsa.

  * Allow specifying B/K/M/G unit to the --mmap-pages arguments, from Jiri Olsa.

  * Separate the GTK support in a separate libperf-gtk.so DSO, that is
    only loaded when --gtk is specified, from Namhyung Kim.

  * Fixes for some memory leaks, from Namhyumg Kim.

  * Fix srcline sort key behavior, from Namhyung Kim.

  * Fix failing assertions in numa bench, from Petr Holasek.

  * perf bash completion fixes and improvements from Ramkumar Ramachandra.

  * Improve error messages in 'trace', providing hints about system configuration
    steps needed for using it, from Ramkumar Ramachandra.

  * Remove bogus info when using 'perf stat' -e cycles/instructions, from
    Ramkumar Ramachandra.

  * Support for Openembedded/Yocto -dbg packages, from Ricardo Ribalda Delgado.

  * Implement addr2line directly using libbfd, from Roberto Vitillo.

  * Add new option --ignore-vmlinux for perf top, from Willy Tarreau.
Signed-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: NIngo Molnar <mingo@kernel.org>
...@@ -134,14 +134,14 @@ ifeq ($(VERBOSE),1) ...@@ -134,14 +134,14 @@ ifeq ($(VERBOSE),1)
print_install = print_install =
else else
Q = @ Q = @
print_compile = echo ' CC '$(OBJ); print_compile = echo ' CC '$(OBJ);
print_app_build = echo ' BUILD '$(OBJ); print_app_build = echo ' BUILD '$(OBJ);
print_fpic_compile = echo ' CC FPIC '$(OBJ); print_fpic_compile = echo ' CC FPIC '$(OBJ);
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ); print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
print_plugin_build = echo ' CC PLUGI '$(OBJ); print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
endif endif
do_fpic_compile = \ do_fpic_compile = \
...@@ -268,7 +268,7 @@ TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE) ...@@ -268,7 +268,7 @@ TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
TRACEEVENT-CFLAGS: force TRACEEVENT-CFLAGS: force
@FLAGS='$(TRACK_CFLAGS)'; \ @FLAGS='$(TRACK_CFLAGS)'; \
if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \ if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
echo 1>&2 " * new build flags or cross compiler"; \ echo 1>&2 " FLAGS: * new build flags or cross compiler"; \
echo "$$FLAGS" >TRACEEVENT-CFLAGS; \ echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
fi fi
......
...@@ -13,6 +13,7 @@ perf*.html ...@@ -13,6 +13,7 @@ perf*.html
common-cmds.h common-cmds.h
perf.data perf.data
perf.data.old perf.data.old
output.svg
perf-archive perf-archive
tags tags
TAGS TAGS
......
...@@ -145,16 +145,17 @@ endif ...@@ -145,16 +145,17 @@ endif
ifneq ($(findstring $(MAKEFLAGS),s),s) ifneq ($(findstring $(MAKEFLAGS),s),s)
ifneq ($(V),1) ifneq ($(V),1)
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@; QUIET_ASCIIDOC = @echo ' ASCIIDOC '$@;
QUIET_XMLTO = @echo ' ' XMLTO $@; QUIET_XMLTO = @echo ' XMLTO '$@;
QUIET_DB2TEXI = @echo ' ' DB2TEXI $@; QUIET_DB2TEXI = @echo ' DB2TEXI '$@;
QUIET_MAKEINFO = @echo ' ' MAKEINFO $@; QUIET_MAKEINFO = @echo ' MAKEINFO '$@;
QUIET_DBLATEX = @echo ' ' DBLATEX $@; QUIET_DBLATEX = @echo ' DBLATEX '$@;
QUIET_XSLTPROC = @echo ' ' XSLTPROC $@; QUIET_XSLTPROC = @echo ' XSLTPROC '$@;
QUIET_GEN = @echo ' ' GEN $@; QUIET_GEN = @echo ' GEN '$@;
QUIET_STDERR = 2> /dev/null QUIET_STDERR = 2> /dev/null
QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
echo ' SUBDIR ' $$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir $(MAKE) $(PRINT_DIR) -C $$subdir
export V export V
endif endif
...@@ -183,47 +184,43 @@ ifdef missing_tools ...@@ -183,47 +184,43 @@ ifdef missing_tools
endif endif
do-install-man: man do-install-man: man
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) $(call QUIET_INSTALL, Documentation-man) \
# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir); \
# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) # $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir); \
$(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir) # $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \
# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir); \
# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) # $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir); \
# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
install-man: check-man-tools man install-man: check-man-tools man
try-install-man:
ifdef missing_tools ifdef missing_tools
$(warning Please install $(missing_tools) to have the man pages installed) DO_INSTALL_MAN = $(warning Please install $(missing_tools) to have the man pages installed)
else else
$(MAKE) do-install-man DO_INSTALL_MAN = do-install-man
endif endif
try-install-man: $(DO_INSTALL_MAN)
install-info: info install-info: info
$(INSTALL) -d -m 755 $(DESTDIR)$(infodir) $(call QUIET_INSTALL, Documentation-info) \
$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir) $(INSTALL) -d -m 755 $(DESTDIR)$(infodir); \
$(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir); \
if test -r $(DESTDIR)$(infodir)/dir; then \ if test -r $(DESTDIR)$(infodir)/dir; then \
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\ $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perf.info ;\
$(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\ $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) perfman.info ;\
else \ else \
echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \ echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
fi fi
install-pdf: pdf install-pdf: pdf
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) $(call QUIET_INSTALL, Documentation-pdf) \
$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir) $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir); \
$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(DESTDIR)$(pdfdir)
#install-html: html #install-html: html
# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) # '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),tags)
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
-include $(OUTPUT)PERF-VERSION-FILE
endif
endif
# #
# Determine "include::" file references in asciidoc files. # Determine "include::" file references in asciidoc files.
...@@ -253,15 +250,17 @@ $(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT) ...@@ -253,15 +250,17 @@ $(OUTPUT)cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \ $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
date >$@ date >$@
CLEAN_FILES = \
$(MAN_XML) $(addsuffix +,$(MAN_XML)) \
$(MAN_HTML) $(addsuffix +,$(MAN_HTML)) \
$(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7) \
$(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++ \
$(OUTPUT)perf.info $(OUTPUT)perfman.info \
$(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep \
$(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt \
$(cmds_txt) $(OUTPUT)*.made
clean: clean:
$(RM) $(MAN_XML) $(addsuffix +,$(MAN_XML)) $(call QUIET_CLEAN, Documentation) $(RM) $(CLEAN_FILES)
$(RM) $(MAN_HTML) $(addsuffix +,$(MAN_HTML))
$(RM) $(DOC_HTML) $(DOC_MAN1) $(DOC_MAN5) $(DOC_MAN7)
$(RM) $(OUTPUT)*.texi $(OUTPUT)*.texi+ $(OUTPUT)*.texi++
$(RM) $(OUTPUT)perf.info $(OUTPUT)perfman.info
$(RM) $(OUTPUT)howto-index.txt $(OUTPUT)howto/*.html $(OUTPUT)doc.dep
$(RM) $(OUTPUT)technical/api-*.html $(OUTPUT)technical/api-index.txt
$(RM) $(cmds_txt) $(OUTPUT)*.made
$(MAN_HTML): $(OUTPUT)%.html : %.txt $(MAN_HTML): $(OUTPUT)%.html : %.txt
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
...@@ -342,5 +341,3 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt ...@@ -342,5 +341,3 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
#quick-install-html: #quick-install-html:
# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) # '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
.PHONY: .FORCE-PERF-VERSION-FILE
...@@ -21,6 +21,19 @@ OPTIONS ...@@ -21,6 +21,19 @@ OPTIONS
-a:: -a::
--add=:: --add=::
Add specified file to the cache. Add specified file to the cache.
-k::
--kcore::
Add specified kcore file to the cache. For the current host that is
/proc/kcore which requires root permissions to read. Be aware that
running 'perf buildid-cache' as root may update root's build-id cache
not the user's. Use the -v option to see where the file is created.
Note that the copied file contains only code sections not the whole core
image. Note also that files "kallsyms" and "modules" must also be in the
same directory and are also copied. All 3 files are created with read
permissions for root only. kcore will not be added if there is already a
kcore in the cache (with the same build-id) that has the same modules at
the same addresses. Use the -v option to see if a copy of kcore is
actually made.
-r:: -r::
--remove=:: --remove=::
Remove specified file from the cache. Remove specified file from the cache.
......
...@@ -109,7 +109,9 @@ STAT LIVE OPTIONS ...@@ -109,7 +109,9 @@ STAT LIVE OPTIONS
-m:: -m::
--mmap-pages=:: --mmap-pages=::
Number of mmap data pages. Must be a power of two. Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
-a:: -a::
--all-cpus:: --all-cpus::
......
...@@ -48,7 +48,7 @@ REPORT OPTIONS ...@@ -48,7 +48,7 @@ REPORT OPTIONS
-k:: -k::
--key=<value>:: --key=<value>::
Sorting key. Possible values: acquired (default), contended, Sorting key. Possible values: acquired (default), contended,
wait_total, wait_max, wait_min. avg_wait, wait_total, wait_max, wait_min.
INFO OPTIONS INFO OPTIONS
------------ ------------
......
...@@ -87,7 +87,9 @@ OPTIONS ...@@ -87,7 +87,9 @@ OPTIONS
-m:: -m::
--mmap-pages=:: --mmap-pages=::
Number of mmap data pages. Must be a power of two. Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
-g:: -g::
--call-graph:: --call-graph::
......
...@@ -8,7 +8,8 @@ perf-timechart - Tool to visualize total system behavior during a workload ...@@ -8,7 +8,8 @@ perf-timechart - Tool to visualize total system behavior during a workload
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'perf timechart' {record} 'perf timechart' record <command>
'perf timechart' [<options>]
DESCRIPTION DESCRIPTION
----------- -----------
...@@ -41,6 +42,18 @@ OPTIONS ...@@ -41,6 +42,18 @@ OPTIONS
--symfs=<directory>:: --symfs=<directory>::
Look for files with symbols relative to this directory. Look for files with symbols relative to this directory.
EXAMPLES
--------
$ perf timechart record git pull
[ perf record: Woken up 13 times to write data ]
[ perf record: Captured and wrote 4.253 MB perf.data (~185801 samples) ]
$ perf timechart
Written 10.2 seconds of trace to output.svg.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-record[1] linkperf:perf-record[1]
...@@ -68,7 +68,9 @@ Default is to monitor all CPUS. ...@@ -68,7 +68,9 @@ Default is to monitor all CPUS.
-m <pages>:: -m <pages>::
--mmap-pages=<pages>:: --mmap-pages=<pages>::
Number of mmapped data pages. Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
-p <pid>:: -p <pid>::
--pid=<pid>:: --pid=<pid>::
......
...@@ -9,6 +9,7 @@ SYNOPSIS ...@@ -9,6 +9,7 @@ SYNOPSIS
-------- --------
[verse] [verse]
'perf trace' 'perf trace'
'perf trace record'
DESCRIPTION DESCRIPTION
----------- -----------
...@@ -16,9 +17,14 @@ This command will show the events associated with the target, initially ...@@ -16,9 +17,14 @@ This command will show the events associated with the target, initially
syscalls, but other system events like pagefaults, task lifetime events, syscalls, but other system events like pagefaults, task lifetime events,
scheduling events, etc. scheduling events, etc.
Initially this is a live mode only tool, but eventually will work with This is a live mode tool in addition to working with perf.data files like
perf.data files like the other tools, allowing a detached 'record' from the other perf tools. Files can be generated using the 'perf record' command
analysis phases. but the session needs to include the raw_syscalls events (-e 'raw_syscalls:*').
Alernatively, the 'perf trace record' can be used as a shortcut to
automatically include the raw_syscalls events when writing events to a file.
The following options apply to perf trace; options to perf trace record are
found in the perf record man page.
OPTIONS OPTIONS
------- -------
...@@ -59,7 +65,9 @@ OPTIONS ...@@ -59,7 +65,9 @@ OPTIONS
-m:: -m::
--mmap-pages=:: --mmap-pages=::
Number of mmap data pages. Must be a power of two. Number of mmap data pages (must be a power of two) or size
specification with appended unit character - B/K/M/G. The
size is rounded up to have nearest pages power of two value.
-C:: -C::
--cpu:: --cpu::
...@@ -78,6 +86,17 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. ...@@ -78,6 +86,17 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
--input --input
Process events from a given perf data file. Process events from a given perf data file.
-T
--time
Print full timestamp rather time relative to first sample.
--comm::
Show process COMM right beside its ID, on by default, disable with --no-comm.
--summary::
Show a summary of syscalls by thread with min, max, and average times (in
msec) and relative stddev.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-record[1], linkperf:perf-script[1] linkperf:perf-record[1], linkperf:perf-script[1]
include ../scripts/Makefile.include
# The default target of this Makefile is...
all:
include config/utilities.mak
# Define V to have a more verbose compile.
#
# Define O to save output files in a separate directory.
#
# Define ARCH as name of target architecture if you want cross-builds.
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
# Define NO_LIBPERL to disable perl script extension.
#
# Define NO_LIBPYTHON to disable python script extension.
#
# Define PYTHON to point to the python binary if the default
# `python' is not correct; for example: PYTHON=python2
#
# Define PYTHON_CONFIG to point to the python-config binary if
# the default `$(PYTHON)-config' is not correct.
# #
# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 # This is a simple wrapper Makefile that calls the main Makefile.perf
# with a -j option to do parallel builds
# #
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. # If you want to invoke the perf build in some non-standard way then
# you can use the 'make -f Makefile.perf' method to invoke it.
# #
# Define LDFLAGS=-static to build a static binary.
#
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
#
# Define NO_DWARF if you do not want debug-info analysis feature at all.
#
# Define WERROR=0 to disable treating any warnings as errors.
#
# Define NO_NEWT if you do not want TUI support. (deprecated)
#
# Define NO_SLANG if you do not want TUI support.
#
# Define NO_GTK2 if you do not want GTK+ GUI support.
# #
# Define NO_DEMANGLE if you do not want C++ symbol demangling. # Clear out the built-in rules GNU make defines by default (such as .o targets),
# so that we pass through all targets to Makefile.perf:
# #
# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) .SUFFIXES:
# #
# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf # We don't want to pass along options like -j:
# backtrace post unwind.
# #
# Define NO_BACKTRACE if you do not want stack backtrace debug feature unexport MAKEFLAGS
# #
# Define NO_LIBNUMA if you do not want numa perf benchmark # Do a parallel build with multiple jobs, based on the number of CPUs online
# in this system: 'make -j8' on a 8-CPU system, etc.
# #
# Define NO_LIBAUDIT if you do not want libaudit support # (To override it, run 'make JOBS=1' and similar.)
# #
# Define NO_LIBBIONIC if you do not want bionic support ifeq ($(JOBS),)
JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
ifeq ($(srctree),) ifeq ($(JOBS),)
srctree := $(patsubst %/,%,$(dir $(shell pwd))) JOBS := 1
srctree := $(patsubst %/,%,$(dir $(srctree))) endif
#$(info Determined 'srctree' to be $(srctree))
endif
ifneq ($(objtree),)
#$(info Determined 'objtree' to be $(objtree))
endif
ifneq ($(OUTPUT),)
#$(info Determined 'OUTPUT' to be $(OUTPUT))
endif
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
RM = rm -f
MKDIR = mkdir
FIND = find
INSTALL = install
FLEX = flex
BISON = bison
STRIP = strip
LK_DIR = $(srctree)/tools/lib/lk/
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
# include config/Makefile by default and rule out
# non-config cases
config := 1
NON_CONFIG_TARGETS := clean TAGS tags cscope help
ifdef MAKECMDGOALS
ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
config := 0
endif
endif endif
ifeq ($(config),1) #
include config/Makefile # Only pass canonical directory names as the output directory:
#
ifneq ($(O),)
FULL_O := $(shell readlink -f $(O) || echo $(O))
endif endif
export prefix bindir sharedir sysconfdir #
# Only accept the 'DEBUG' variable from the command line:
# sparse is architecture-neutral, which means that we need to tell it #
# explicitly what architecture to check for. Fix this up for yours.. ifeq ("$(origin DEBUG)", "command line")
SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ ifeq ($(DEBUG),)
override DEBUG = 0
# Guard against environment variables else
BUILTIN_OBJS = SET_DEBUG = "DEBUG=$(DEBUG)"
LIB_H = endif
LIB_OBJS =
PYRF_OBJS =
SCRIPT_SH =
SCRIPT_SH += perf-archive.sh
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
ifneq ($(subdir),)
LK_PATH=$(OUTPUT)/../lib/lk/
else
LK_PATH=$(OUTPUT)
endif
else else
TE_PATH=$(TRACE_EVENT_DIR) override DEBUG = 0
LK_PATH=$(LK_DIR)
endif endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a define print_msg
export LIBTRACEEVENT @printf ' BUILD: Doing '\''make \033[33m-j'$(JOBS)'\033[m'\'' parallel build\n'
endef
LIBLK = $(LK_PATH)liblk.a
export LIBLK
# python extension build directories
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so define make
@$(MAKE) -f Makefile.perf --no-print-directory -j$(JOBS) O=$(FULL_O) $(SET_DEBUG) $@
endef
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
--quiet build_ext; \
mkdir -p $(OUTPUT)python && \
cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
# #
# No Perl scripts right now: # Needed if no target specified:
# #
all:
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) $(print_msg)
$(make)
# #
# Single 'perf' binary right now: # The clean target is not really parallel, don't print the jobs info:
# #
PROGRAMS += $(OUTPUT)perf clean:
$(make)
# what 'all' will build and 'install' will install, in perfexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
# what 'all' will build but not install in perfexecdir
OTHER_PROGRAMS = $(OUTPUT)perf
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
export PERL_PATH
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
$(OUTPUT)util/pmu-bison.c: util/pmu.y
$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
LIB_FILE=$(OUTPUT)libperf.a
LIB_H += ../../include/uapi/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h
LIB_H += ../../include/uapi/linux/const.h
LIB_H += ../../include/linux/hash.h
LIB_H += ../../include/linux/stringify.h
LIB_H += util/include/linux/bitmap.h
LIB_H += util/include/linux/bitops.h
LIB_H += util/include/linux/compiler.h
LIB_H += util/include/linux/const.h
LIB_H += util/include/linux/ctype.h
LIB_H += util/include/linux/kernel.h
LIB_H += util/include/linux/list.h
LIB_H += util/include/linux/export.h
LIB_H += util/include/linux/magic.h
LIB_H += util/include/linux/poison.h
LIB_H += util/include/linux/prefetch.h
LIB_H += util/include/linux/rbtree.h
LIB_H += util/include/linux/rbtree_augmented.h
LIB_H += util/include/linux/string.h
LIB_H += util/include/linux/types.h
LIB_H += util/include/linux/linkage.h
LIB_H += util/include/asm/asm-offsets.h
LIB_H += util/include/asm/bug.h
LIB_H += util/include/asm/byteorder.h
LIB_H += util/include/asm/hweight.h
LIB_H += util/include/asm/swab.h
LIB_H += util/include/asm/system.h
LIB_H += util/include/asm/uaccess.h
LIB_H += util/include/dwarf-regs.h
LIB_H += util/include/asm/dwarf2.h
LIB_H += util/include/asm/cpufeature.h
LIB_H += util/include/asm/unistd_32.h
LIB_H += util/include/asm/unistd_64.h
LIB_H += perf.h
LIB_H += util/annotate.h
LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
LIB_H += util/debug.h
LIB_H += util/sysfs.h
LIB_H += util/pmu.h
LIB_H += util/event.h
LIB_H += util/evsel.h
LIB_H += util/evlist.h
LIB_H += util/exec_cmd.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
LIB_H += util/machine.h
LIB_H += util/map.h
LIB_H += util/parse-options.h
LIB_H += util/parse-events.h
LIB_H += util/quote.h
LIB_H += util/util.h
LIB_H += util/xyarray.h
LIB_H += util/header.h
LIB_H += util/help.h
LIB_H += util/session.h
LIB_H += util/strbuf.h
LIB_H += util/strlist.h
LIB_H += util/strfilter.h
LIB_H += util/svghelper.h
LIB_H += util/tool.h
LIB_H += util/run-command.h
LIB_H += util/sigchain.h
LIB_H += util/dso.h
LIB_H += util/symbol.h
LIB_H += util/color.h
LIB_H += util/values.h
LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/thread.h
LIB_H += util/thread_map.h
LIB_H += util/trace-event.h
LIB_H += util/probe-finder.h
LIB_H += util/dwarf-aux.h
LIB_H += util/probe-event.h
LIB_H += util/pstack.h
LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h
LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
LIB_H += util/target.h
LIB_H += util/rblist.h
LIB_H += util/intlist.h
LIB_H += util/perf_regs.h
LIB_H += util/unwind.h
LIB_H += util/vdso.h
LIB_H += ui/helpline.h
LIB_H += ui/progress.h
LIB_H += ui/util.h
LIB_H += ui/ui.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
LIB_OBJS += $(OUTPUT)util/sysfs.o
LIB_OBJS += $(OUTPUT)util/pmu.o
LIB_OBJS += $(OUTPUT)util/environment.o
LIB_OBJS += $(OUTPUT)util/event.o
LIB_OBJS += $(OUTPUT)util/evlist.o
LIB_OBJS += $(OUTPUT)util/evsel.o
LIB_OBJS += $(OUTPUT)util/exec_cmd.o
LIB_OBJS += $(OUTPUT)util/help.o
LIB_OBJS += $(OUTPUT)util/levenshtein.o
LIB_OBJS += $(OUTPUT)util/parse-options.o
LIB_OBJS += $(OUTPUT)util/parse-events.o
LIB_OBJS += $(OUTPUT)util/path.o
LIB_OBJS += $(OUTPUT)util/rbtree.o
LIB_OBJS += $(OUTPUT)util/bitmap.o
LIB_OBJS += $(OUTPUT)util/hweight.o
LIB_OBJS += $(OUTPUT)util/run-command.o
LIB_OBJS += $(OUTPUT)util/quote.o
LIB_OBJS += $(OUTPUT)util/strbuf.o
LIB_OBJS += $(OUTPUT)util/string.o
LIB_OBJS += $(OUTPUT)util/strlist.o
LIB_OBJS += $(OUTPUT)util/strfilter.o
LIB_OBJS += $(OUTPUT)util/top.o
LIB_OBJS += $(OUTPUT)util/usage.o
LIB_OBJS += $(OUTPUT)util/wrapper.o
LIB_OBJS += $(OUTPUT)util/sigchain.o
LIB_OBJS += $(OUTPUT)util/dso.o
LIB_OBJS += $(OUTPUT)util/symbol.o
LIB_OBJS += $(OUTPUT)util/symbol-elf.o
LIB_OBJS += $(OUTPUT)util/color.o
LIB_OBJS += $(OUTPUT)util/pager.o
LIB_OBJS += $(OUTPUT)util/header.o
LIB_OBJS += $(OUTPUT)util/callchain.o
LIB_OBJS += $(OUTPUT)util/values.o
LIB_OBJS += $(OUTPUT)util/debug.o
LIB_OBJS += $(OUTPUT)util/machine.o
LIB_OBJS += $(OUTPUT)util/map.o
LIB_OBJS += $(OUTPUT)util/pstack.o
LIB_OBJS += $(OUTPUT)util/session.o
LIB_OBJS += $(OUTPUT)util/thread.o
LIB_OBJS += $(OUTPUT)util/thread_map.o
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
LIB_OBJS += $(OUTPUT)util/pmu-flex.o
LIB_OBJS += $(OUTPUT)util/pmu-bison.o
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
LIB_OBJS += $(OUTPUT)util/svghelper.o
LIB_OBJS += $(OUTPUT)util/sort.o
LIB_OBJS += $(OUTPUT)util/hist.o
LIB_OBJS += $(OUTPUT)util/probe-event.o
LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o
LIB_OBJS += $(OUTPUT)util/cgroup.o
LIB_OBJS += $(OUTPUT)util/target.o
LIB_OBJS += $(OUTPUT)util/rblist.o
LIB_OBJS += $(OUTPUT)util/intlist.o
LIB_OBJS += $(OUTPUT)util/vdso.o
LIB_OBJS += $(OUTPUT)util/stat.o
LIB_OBJS += $(OUTPUT)util/record.o
LIB_OBJS += $(OUTPUT)ui/setup.o
LIB_OBJS += $(OUTPUT)ui/helpline.o
LIB_OBJS += $(OUTPUT)ui/progress.o
LIB_OBJS += $(OUTPUT)ui/util.o
LIB_OBJS += $(OUTPUT)ui/hist.o
LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
LIB_OBJS += $(OUTPUT)arch/common.o
LIB_OBJS += $(OUTPUT)tests/parse-events.o
LIB_OBJS += $(OUTPUT)tests/dso-data.o
LIB_OBJS += $(OUTPUT)tests/attr.o
LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
LIB_OBJS += $(OUTPUT)tests/open-syscall.o
LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
LIB_OBJS += $(OUTPUT)tests/perf-record.o
LIB_OBJS += $(OUTPUT)tests/rdpmc.o
LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
LIB_OBJS += $(OUTPUT)tests/pmu.o
LIB_OBJS += $(OUTPUT)tests/hists_link.o
LIB_OBJS += $(OUTPUT)tests/python-use.o
LIB_OBJS += $(OUTPUT)tests/bp_signal.o
LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
LIB_OBJS += $(OUTPUT)tests/task-exit.o
LIB_OBJS += $(OUTPUT)tests/sw-clock.o
ifeq ($(ARCH),x86)
LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
# Benchmark modules
BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
ifeq ($(RAW_ARCH),x86_64)
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
BUILTIN_OBJS += $(OUTPUT)builtin-list.o
BUILTIN_OBJS += $(OUTPUT)builtin-record.o
BUILTIN_OBJS += $(OUTPUT)builtin-report.o
BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
BUILTIN_OBJS += $(OUTPUT)builtin-top.o
BUILTIN_OBJS += $(OUTPUT)builtin-script.o
BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
# We choose to avoid "if .. else if .. else .. endif endif"
# because maintaining the nesting to match is a pain. If
# we had "elif" things would have been much nicer...
-include arch/$(ARCH)/Makefile
ifneq ($(OUTPUT),)
CFLAGS += -I$(OUTPUT)
endif
ifdef NO_LIBELF
EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
# Remove ELF/DWARF dependent codes
LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
# Use minimal symbol handling
LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
else # NO_LIBELF
ifndef NO_DWARF
LIB_OBJS += $(OUTPUT)util/probe-finder.o
LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
endif # NO_DWARF
endif # NO_LIBELF
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)util/unwind.o
endif
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
ifndef NO_LIBAUDIT
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
endif
ifndef NO_SLANG
LIB_OBJS += $(OUTPUT)ui/browser.o
LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
LIB_OBJS += $(OUTPUT)ui/browsers/map.o
LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
LIB_OBJS += $(OUTPUT)ui/tui/util.o
LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
LIB_OBJS += $(OUTPUT)ui/tui/progress.o
LIB_H += ui/browser.h
LIB_H += ui/browsers/map.h
LIB_H += ui/keysyms.h
LIB_H += ui/libslang.h
endif
ifndef NO_GTK2
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/util.o
LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
endif
ifndef NO_LIBPERL
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
endif
ifndef NO_LIBPYTHON
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
endif
ifeq ($(NO_PERF_REGS),0)
ifeq ($(ARCH),x86)
LIB_H += arch/x86/include/perf_regs.h
endif
endif
ifndef NO_LIBNUMA
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
endif
ifdef ASCIIDOC8
export ASCIIDOC8
endif
LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
export INSTALL SHELL_PATH
### Build rules
SHELL = $(SHELL_PATH)
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
please_set_SHELL_PATH_to_a_more_modern_shell:
@$$(:)
shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
strip: $(PROGRAMS) $(OUTPUT)perf
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
$(CFLAGS) -c $(filter %.c,$^) -o $@
$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
$(BUILTIN_OBJS) $(LIBS) -o $@
$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
$(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
$(SCRIPTS) : % : %.sh
$(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
# These can record PERF_VERSION
$(OUTPUT)perf.o perf.spec \
$(SCRIPTS) \
: $(OUTPUT)PERF-VERSION-FILE
.SUFFIXES:
.SUFFIXES: .o .c .S .s
# These two need to be here so that when O= is not used they take precedence
# over the general rule for .o
$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
$(OUTPUT)%.o: %.S
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
$(OUTPUT)%.s: %.S
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
'-DPREFIX="$(prefix_SQ)"' \
$<
$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
$<
$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-DPYTHONPATH='"$(OUTPUT)python"' \
-DPYTHON='"$(PYTHON_WORD)"' \
$<
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS #
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< # All other targets get passed through:
#
$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS %:
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< $(print_msg)
$(make)
$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
$(OUTPUT)perf-%: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
# we depend the various files onto their directories.
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
# In the second step, we make a rule to actually create these directories
$(sort $(dir $(DIRECTORY_DEPS))):
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
# libtraceevent.a
$(LIBTRACEEVENT):
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
$(LIBTRACEEVENT)-clean:
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
# if subdir is set, we've been called from above so target has been built
# already
$(LIBLK):
ifeq ($(subdir),)
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
endif
$(LIBLK)-clean:
ifeq ($(subdir),)
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
endif
help:
@echo 'Perf make targets:'
@echo ' doc - make *all* documentation (see below)'
@echo ' man - make manpage documentation (access with man <foo>)'
@echo ' html - make html documentation'
@echo ' info - make GNU info documentation (access with info <foo>)'
@echo ' pdf - make pdf documentation'
@echo ' TAGS - use etags to make tag information for source browsing'
@echo ' tags - use ctags to make tag information for source browsing'
@echo ' cscope - use cscope to make interactive browsing database'
@echo ''
@echo 'Perf install targets:'
@echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
@echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
@echo ' path like make prefix=/usr/local install install-doc'
@echo ' install - install compiled binaries'
@echo ' install-doc - install *all* documentation'
@echo ' install-man - install manpage documentation'
@echo ' install-html - install html documentation'
@echo ' install-info - install GNU info documentation'
@echo ' install-pdf - install pdf documentation'
@echo ''
@echo ' quick-install-doc - alias for quick-install-man'
@echo ' quick-install-man - install the documentation quickly'
@echo ' quick-install-html - install the html documentation quickly'
@echo ''
@echo 'Perf maintainer targets:'
@echo ' clean - clean all binary objects and build output'
DOC_TARGETS := doc man html info pdf
INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
# 'make doc' should call 'make -C Documentation all'
$(DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
TAGS:
$(RM) TAGS
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
tags:
$(RM) tags
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
cscope:
$(RM) cscope*
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@FLAGS='$(TRACK_CFLAGS)'; \
if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
echo 1>&2 " * new build flags or prefix"; \
echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
fi
### Testing rules
# GNU make supports exporting all variables by "export" without parameters.
# However, the environment gets quite big, and some programs have problems
# with that.
check: $(OUTPUT)common-cmds.h
if sparse; \
then \
for i in *.c */*.c; \
do \
sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
done; \
else \
exit 1; \
fi
### Installation rules
install-bin: all
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
ifndef NO_LIBPERL
$(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/bin'
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
$(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
endif
ifndef NO_LIBPYTHON
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
endif
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
install: install-bin try-install-man
install-python_ext:
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
# 'make install-doc' should call 'make -C Documentation install'
$(INSTALL_DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
### Cleaning rules
clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
$(RM) $(ALL_PROGRAMS) perf
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
$(RM) $(OUTPUT)util/*-bison*
$(RM) $(OUTPUT)util/*-flex*
$(python-clean)
.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
include ../scripts/Makefile.include
# The default target of this Makefile is...
all:
include config/utilities.mak
# Define V to have a more verbose compile.
#
# Define O to save output files in a separate directory.
#
# Define ARCH as name of target architecture if you want cross-builds.
#
# Define CROSS_COMPILE as prefix name of compiler if you want cross-builds.
#
# Define NO_LIBPERL to disable perl script extension.
#
# Define NO_LIBPYTHON to disable python script extension.
#
# Define PYTHON to point to the python binary if the default
# `python' is not correct; for example: PYTHON=python2
#
# Define PYTHON_CONFIG to point to the python-config binary if
# the default `$(PYTHON)-config' is not correct.
#
# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
#
# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
#
# Define LDFLAGS=-static to build a static binary.
#
# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
#
# Define NO_DWARF if you do not want debug-info analysis feature at all.
#
# Define WERROR=0 to disable treating any warnings as errors.
#
# Define NO_NEWT if you do not want TUI support. (deprecated)
#
# Define NO_SLANG if you do not want TUI support.
#
# Define NO_GTK2 if you do not want GTK+ GUI support.
#
# Define NO_DEMANGLE if you do not want C++ symbol demangling.
#
# Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds)
#
# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf
# backtrace post unwind.
#
# Define NO_BACKTRACE if you do not want stack backtrace debug feature
#
# Define NO_LIBNUMA if you do not want numa perf benchmark
#
# Define NO_LIBAUDIT if you do not want libaudit support
#
# Define NO_LIBBIONIC if you do not want bionic support
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
#$(info Determined 'srctree' to be $(srctree))
endif
ifneq ($(objtree),)
#$(info Determined 'objtree' to be $(objtree))
endif
ifneq ($(OUTPUT),)
#$(info Determined 'OUTPUT' to be $(OUTPUT))
endif
$(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
@touch $(OUTPUT)PERF-VERSION-FILE
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
RM = rm -f
LN = ln -f
MKDIR = mkdir
FIND = find
INSTALL = install
FLEX = flex
BISON = bison
STRIP = strip
LK_DIR = $(srctree)/tools/lib/lk/
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
# include config/Makefile by default and rule out
# non-config cases
config := 1
NON_CONFIG_TARGETS := clean TAGS tags cscope help
ifdef MAKECMDGOALS
ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
config := 0
endif
endif
ifeq ($(config),1)
include config/Makefile
endif
export prefix bindir sharedir sysconfdir
# sparse is architecture-neutral, which means that we need to tell it
# explicitly what architecture to check for. Fix this up for yours..
SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
# Guard against environment variables
BUILTIN_OBJS =
LIB_H =
LIB_OBJS =
GTK_OBJS =
PYRF_OBJS =
SCRIPT_SH =
SCRIPT_SH += perf-archive.sh
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
ifneq ($(subdir),)
LK_PATH=$(OUTPUT)/../lib/lk/
else
LK_PATH=$(OUTPUT)
endif
else
TE_PATH=$(TRACE_EVENT_DIR)
LK_PATH=$(LK_DIR)
endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
export LIBTRACEEVENT
LIBLK = $(LK_PATH)liblk.a
export LIBLK
# python extension build directories
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
--quiet build_ext; \
mkdir -p $(OUTPUT)python && \
cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/
#
# No Perl scripts right now:
#
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
#
# Single 'perf' binary right now:
#
PROGRAMS += $(OUTPUT)perf
# what 'all' will build and 'install' will install, in perfexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
# what 'all' will build but not install in perfexecdir
OTHER_PROGRAMS = $(OUTPUT)perf
# Set paths to tools early so that they can be used for version tests.
ifndef SHELL_PATH
SHELL_PATH = /bin/sh
endif
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
export PERL_PATH
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
$(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
$(OUTPUT)util/pmu-bison.c: util/pmu.y
$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
LIB_FILE=$(OUTPUT)libperf.a
LIB_H += ../../include/uapi/linux/perf_event.h
LIB_H += ../../include/linux/rbtree.h
LIB_H += ../../include/linux/list.h
LIB_H += ../../include/uapi/linux/const.h
LIB_H += ../../include/linux/hash.h
LIB_H += ../../include/linux/stringify.h
LIB_H += util/include/linux/bitmap.h
LIB_H += util/include/linux/bitops.h
LIB_H += util/include/linux/compiler.h
LIB_H += util/include/linux/const.h
LIB_H += util/include/linux/ctype.h
LIB_H += util/include/linux/kernel.h
LIB_H += util/include/linux/list.h
LIB_H += util/include/linux/export.h
LIB_H += util/include/linux/magic.h
LIB_H += util/include/linux/poison.h
LIB_H += util/include/linux/prefetch.h
LIB_H += util/include/linux/rbtree.h
LIB_H += util/include/linux/rbtree_augmented.h
LIB_H += util/include/linux/string.h
LIB_H += util/include/linux/types.h
LIB_H += util/include/linux/linkage.h
LIB_H += util/include/asm/asm-offsets.h
LIB_H += util/include/asm/bug.h
LIB_H += util/include/asm/byteorder.h
LIB_H += util/include/asm/hweight.h
LIB_H += util/include/asm/swab.h
LIB_H += util/include/asm/system.h
LIB_H += util/include/asm/uaccess.h
LIB_H += util/include/dwarf-regs.h
LIB_H += util/include/asm/dwarf2.h
LIB_H += util/include/asm/cpufeature.h
LIB_H += util/include/asm/unistd_32.h
LIB_H += util/include/asm/unistd_64.h
LIB_H += perf.h
LIB_H += util/annotate.h
LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
LIB_H += util/debug.h
LIB_H += util/sysfs.h
LIB_H += util/pmu.h
LIB_H += util/event.h
LIB_H += util/evsel.h
LIB_H += util/evlist.h
LIB_H += util/exec_cmd.h
LIB_H += util/types.h
LIB_H += util/levenshtein.h
LIB_H += util/machine.h
LIB_H += util/map.h
LIB_H += util/parse-options.h
LIB_H += util/parse-events.h
LIB_H += util/quote.h
LIB_H += util/util.h
LIB_H += util/xyarray.h
LIB_H += util/header.h
LIB_H += util/help.h
LIB_H += util/session.h
LIB_H += util/strbuf.h
LIB_H += util/strlist.h
LIB_H += util/strfilter.h
LIB_H += util/svghelper.h
LIB_H += util/tool.h
LIB_H += util/run-command.h
LIB_H += util/sigchain.h
LIB_H += util/dso.h
LIB_H += util/symbol.h
LIB_H += util/color.h
LIB_H += util/values.h
LIB_H += util/sort.h
LIB_H += util/hist.h
LIB_H += util/thread.h
LIB_H += util/thread_map.h
LIB_H += util/trace-event.h
LIB_H += util/probe-finder.h
LIB_H += util/dwarf-aux.h
LIB_H += util/probe-event.h
LIB_H += util/pstack.h
LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h
LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
LIB_H += util/target.h
LIB_H += util/rblist.h
LIB_H += util/intlist.h
LIB_H += util/perf_regs.h
LIB_H += util/unwind.h
LIB_H += util/vdso.h
LIB_H += ui/helpline.h
LIB_H += ui/progress.h
LIB_H += ui/util.h
LIB_H += ui/ui.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
LIB_OBJS += $(OUTPUT)util/sysfs.o
LIB_OBJS += $(OUTPUT)util/pmu.o
LIB_OBJS += $(OUTPUT)util/environment.o
LIB_OBJS += $(OUTPUT)util/event.o
LIB_OBJS += $(OUTPUT)util/evlist.o
LIB_OBJS += $(OUTPUT)util/evsel.o
LIB_OBJS += $(OUTPUT)util/exec_cmd.o
LIB_OBJS += $(OUTPUT)util/help.o
LIB_OBJS += $(OUTPUT)util/levenshtein.o
LIB_OBJS += $(OUTPUT)util/parse-options.o
LIB_OBJS += $(OUTPUT)util/parse-events.o
LIB_OBJS += $(OUTPUT)util/path.o
LIB_OBJS += $(OUTPUT)util/rbtree.o
LIB_OBJS += $(OUTPUT)util/bitmap.o
LIB_OBJS += $(OUTPUT)util/hweight.o
LIB_OBJS += $(OUTPUT)util/run-command.o
LIB_OBJS += $(OUTPUT)util/quote.o
LIB_OBJS += $(OUTPUT)util/strbuf.o
LIB_OBJS += $(OUTPUT)util/string.o
LIB_OBJS += $(OUTPUT)util/strlist.o
LIB_OBJS += $(OUTPUT)util/strfilter.o
LIB_OBJS += $(OUTPUT)util/top.o
LIB_OBJS += $(OUTPUT)util/usage.o
LIB_OBJS += $(OUTPUT)util/wrapper.o
LIB_OBJS += $(OUTPUT)util/sigchain.o
LIB_OBJS += $(OUTPUT)util/dso.o
LIB_OBJS += $(OUTPUT)util/symbol.o
LIB_OBJS += $(OUTPUT)util/symbol-elf.o
LIB_OBJS += $(OUTPUT)util/color.o
LIB_OBJS += $(OUTPUT)util/pager.o
LIB_OBJS += $(OUTPUT)util/header.o
LIB_OBJS += $(OUTPUT)util/callchain.o
LIB_OBJS += $(OUTPUT)util/values.o
LIB_OBJS += $(OUTPUT)util/debug.o
LIB_OBJS += $(OUTPUT)util/machine.o
LIB_OBJS += $(OUTPUT)util/map.o
LIB_OBJS += $(OUTPUT)util/pstack.o
LIB_OBJS += $(OUTPUT)util/session.o
LIB_OBJS += $(OUTPUT)util/thread.o
LIB_OBJS += $(OUTPUT)util/thread_map.o
LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
LIB_OBJS += $(OUTPUT)util/parse-events-flex.o
LIB_OBJS += $(OUTPUT)util/parse-events-bison.o
LIB_OBJS += $(OUTPUT)util/pmu-flex.o
LIB_OBJS += $(OUTPUT)util/pmu-bison.o
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
LIB_OBJS += $(OUTPUT)util/svghelper.o
LIB_OBJS += $(OUTPUT)util/sort.o
LIB_OBJS += $(OUTPUT)util/hist.o
LIB_OBJS += $(OUTPUT)util/probe-event.o
LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o
LIB_OBJS += $(OUTPUT)util/cgroup.o
LIB_OBJS += $(OUTPUT)util/target.o
LIB_OBJS += $(OUTPUT)util/rblist.o
LIB_OBJS += $(OUTPUT)util/intlist.o
LIB_OBJS += $(OUTPUT)util/vdso.o
LIB_OBJS += $(OUTPUT)util/stat.o
LIB_OBJS += $(OUTPUT)util/record.o
LIB_OBJS += $(OUTPUT)util/srcline.o
LIB_OBJS += $(OUTPUT)ui/setup.o
LIB_OBJS += $(OUTPUT)ui/helpline.o
LIB_OBJS += $(OUTPUT)ui/progress.o
LIB_OBJS += $(OUTPUT)ui/util.o
LIB_OBJS += $(OUTPUT)ui/hist.o
LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
LIB_OBJS += $(OUTPUT)arch/common.o
LIB_OBJS += $(OUTPUT)tests/parse-events.o
LIB_OBJS += $(OUTPUT)tests/dso-data.o
LIB_OBJS += $(OUTPUT)tests/attr.o
LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
LIB_OBJS += $(OUTPUT)tests/open-syscall.o
LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
LIB_OBJS += $(OUTPUT)tests/perf-record.o
LIB_OBJS += $(OUTPUT)tests/rdpmc.o
LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
LIB_OBJS += $(OUTPUT)tests/pmu.o
LIB_OBJS += $(OUTPUT)tests/hists_link.o
LIB_OBJS += $(OUTPUT)tests/python-use.o
LIB_OBJS += $(OUTPUT)tests/bp_signal.o
LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
LIB_OBJS += $(OUTPUT)tests/task-exit.o
LIB_OBJS += $(OUTPUT)tests/sw-clock.o
ifeq ($(ARCH),x86)
LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
endif
LIB_OBJS += $(OUTPUT)tests/code-reading.o
LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
# Benchmark modules
BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
ifeq ($(RAW_ARCH),x86_64)
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
BUILTIN_OBJS += $(OUTPUT)builtin-list.o
BUILTIN_OBJS += $(OUTPUT)builtin-record.o
BUILTIN_OBJS += $(OUTPUT)builtin-report.o
BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
BUILTIN_OBJS += $(OUTPUT)builtin-top.o
BUILTIN_OBJS += $(OUTPUT)builtin-script.o
BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
# We choose to avoid "if .. else if .. else .. endif endif"
# because maintaining the nesting to match is a pain. If
# we had "elif" things would have been much nicer...
-include arch/$(ARCH)/Makefile
ifneq ($(OUTPUT),)
CFLAGS += -I$(OUTPUT)
endif
ifdef NO_LIBELF
EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
# Remove ELF/DWARF dependent codes
LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-event.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/probe-finder.o,$(LIB_OBJS))
BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
# Use minimal symbol handling
LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
else # NO_LIBELF
ifndef NO_DWARF
LIB_OBJS += $(OUTPUT)util/probe-finder.o
LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
endif # NO_DWARF
endif # NO_LIBELF
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)util/unwind.o
endif
LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
ifndef NO_LIBAUDIT
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
endif
ifndef NO_SLANG
LIB_OBJS += $(OUTPUT)ui/browser.o
LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
LIB_OBJS += $(OUTPUT)ui/browsers/map.o
LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
LIB_OBJS += $(OUTPUT)ui/tui/util.o
LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
LIB_OBJS += $(OUTPUT)ui/tui/progress.o
LIB_H += ui/browser.h
LIB_H += ui/browsers/map.h
LIB_H += ui/keysyms.h
LIB_H += ui/libslang.h
endif
ifndef NO_GTK2
ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so
GTK_OBJS += $(OUTPUT)ui/gtk/browser.o
GTK_OBJS += $(OUTPUT)ui/gtk/hists.o
GTK_OBJS += $(OUTPUT)ui/gtk/setup.o
GTK_OBJS += $(OUTPUT)ui/gtk/util.o
GTK_OBJS += $(OUTPUT)ui/gtk/helpline.o
GTK_OBJS += $(OUTPUT)ui/gtk/progress.o
GTK_OBJS += $(OUTPUT)ui/gtk/annotate.o
install-gtk: $(OUTPUT)libperf-gtk.so
$(call QUIET_INSTALL, 'GTK UI') \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \
$(INSTALL) $(OUTPUT)libperf-gtk.so '$(DESTDIR_SQ)$(libdir_SQ)'
endif
ifndef NO_LIBPERL
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
endif
ifndef NO_LIBPYTHON
LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
endif
ifeq ($(NO_PERF_REGS),0)
ifeq ($(ARCH),x86)
LIB_H += arch/x86/include/perf_regs.h
endif
endif
ifndef NO_LIBNUMA
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
endif
ifdef ASCIIDOC8
export ASCIIDOC8
endif
LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive -Wl,--start-group $(EXTLIBS) -Wl,--end-group
export INSTALL SHELL_PATH
### Build rules
SHELL = $(SHELL_PATH)
all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
please_set_SHELL_PATH_to_a_more_modern_shell:
@$$(:)
shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
strip: $(PROGRAMS) $(OUTPUT)perf
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
$(CFLAGS) -c $(filter %.c,$^) -o $@
$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(OUTPUT)perf.o \
$(BUILTIN_OBJS) $(LIBS) -o $@
$(GTK_OBJS): $(OUTPUT)%.o: %.c $(LIB_H)
$(QUIET_CC)$(CC) -o $@ -c -fPIC $(CFLAGS) $(GTK_CFLAGS) $<
$(OUTPUT)libperf-gtk.so: $(GTK_OBJS) $(PERFLIBS)
$(QUIET_LINK)$(CC) -o $@ -shared $(ALL_LDFLAGS) $(filter %.o,$^) $(GTK_LIBS)
$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
'-DPERF_MAN_PATH="$(mandir_SQ)"' \
'-DPERF_INFO_PATH="$(infodir_SQ)"' $<
$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
$(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
$(SCRIPTS) : % : %.sh
$(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@'
# These can record PERF_VERSION
$(OUTPUT)perf.o perf.spec \
$(SCRIPTS) \
: $(OUTPUT)PERF-VERSION-FILE
.SUFFIXES:
#
# If a target does not match any of the later rules then prefix it by $(OUTPUT)
# This makes targets like 'make O=/tmp/perf perf.o' work in a natural way.
#
ifneq ($(OUTPUT),)
%.o: $(OUTPUT)%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
util/%.o: $(OUTPUT)util/%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
bench/%.o: $(OUTPUT)bench/%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
tests/%.o: $(OUTPUT)tests/%.o
@echo " # Redirected target $@ => $(OUTPUT)$@"
endif
# These two need to be here so that when O= is not used they take precedence
# over the general rule for .o
$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -w $<
$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c -Iutil/ $(CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w $<
$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
$(OUTPUT)%.i: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -S $(CFLAGS) $<
$(OUTPUT)%.o: %.S
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
$(OUTPUT)%.s: %.S
$(QUIET_CC)$(CC) -o $@ -E $(CFLAGS) $<
$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
'-DPREFIX="$(prefix_SQ)"' \
$<
$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
'-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
$<
$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) \
-DPYTHONPATH='"$(OUTPUT)python"' \
-DPYTHON='"$(PYTHON_WORD)"' \
$<
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
$(OUTPUT)ui/setup.o: ui/setup.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DLIBDIR='"$(libdir_SQ)"' $<
$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
$(OUTPUT)perf-%: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
# we depend the various files onto their directories.
DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(GTK_OBJS)
DIRECTORY_DEPS += $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
# In the second step, we make a rule to actually create these directories
$(sort $(dir $(DIRECTORY_DEPS))):
$(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
# libtraceevent.a
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
$(LIBTRACEEVENT): $(TE_SOURCES)
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libtraceevent.a
$(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent)
@$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
# if subdir is set, we've been called from above so target has been built
# already
$(LIBLK): $(LIBLK_SOURCES)
ifeq ($(subdir),)
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
endif
$(LIBLK)-clean:
ifeq ($(subdir),)
$(call QUIET_CLEAN, liblk)
@$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null
endif
help:
@echo 'Perf make targets:'
@echo ' doc - make *all* documentation (see below)'
@echo ' man - make manpage documentation (access with man <foo>)'
@echo ' html - make html documentation'
@echo ' info - make GNU info documentation (access with info <foo>)'
@echo ' pdf - make pdf documentation'
@echo ' TAGS - use etags to make tag information for source browsing'
@echo ' tags - use ctags to make tag information for source browsing'
@echo ' cscope - use cscope to make interactive browsing database'
@echo ''
@echo 'Perf install targets:'
@echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
@echo ' HINT: use "make prefix=<path> <install target>" to install to a particular'
@echo ' path like make prefix=/usr/local install install-doc'
@echo ' install - install compiled binaries'
@echo ' install-doc - install *all* documentation'
@echo ' install-man - install manpage documentation'
@echo ' install-html - install html documentation'
@echo ' install-info - install GNU info documentation'
@echo ' install-pdf - install pdf documentation'
@echo ''
@echo ' quick-install-doc - alias for quick-install-man'
@echo ' quick-install-man - install the documentation quickly'
@echo ' quick-install-html - install the html documentation quickly'
@echo ''
@echo 'Perf maintainer targets:'
@echo ' clean - clean all binary objects and build output'
DOC_TARGETS := doc man html info pdf
INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
# 'make doc' should call 'make -C Documentation all'
$(DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
TAGS:
$(RM) TAGS
$(FIND) . -name '*.[hcS]' -print | xargs etags -a
tags:
$(RM) tags
$(FIND) . -name '*.[hcS]' -print | xargs ctags -a
cscope:
$(RM) cscope*
$(FIND) . -name '*.[hcS]' -print | xargs cscope -b
### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@FLAGS='$(TRACK_CFLAGS)'; \
if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
echo 1>&2 " FLAGS: * new build flags or prefix"; \
echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
fi
### Testing rules
# GNU make supports exporting all variables by "export" without parameters.
# However, the environment gets quite big, and some programs have problems
# with that.
check: $(OUTPUT)common-cmds.h
if sparse; \
then \
for i in *.c */*.c; \
do \
sparse $(CFLAGS) $(SPARSE_FLAGS) $$i || exit; \
done; \
else \
exit 1; \
fi
### Installation rules
install-gtk:
install-bin: all install-gtk
$(call QUIET_INSTALL, binaries) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
$(call QUIET_INSTALL, libexec) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(call QUIET_INSTALL, perf-archive) \
$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
ifndef NO_LIBPERL
$(call QUIET_INSTALL, perl-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'; \
$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
endif
ifndef NO_LIBPYTHON
$(call QUIET_INSTALL, python-scripts) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'; \
$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'; \
$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
endif
$(call QUIET_INSTALL, bash_completion-script) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
$(call QUIET_INSTALL, tests) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
install: install-bin try-install-man
install-python_ext:
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
# 'make install-doc' should call 'make -C Documentation install'
$(INSTALL_DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
### Cleaning rules
#
# This is here, not in config/Makefile, because config/Makefile does
# not get included for the clean target:
#
config-clean:
$(call QUIET_CLEAN, config)
@$(MAKE) -C config/feature-checks clean >/dev/null
clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
$(call QUIET_CLEAN, Documentation)
@$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
$(python-clean)
#
# Trick: if ../../.git does not exist - we are building out of tree for example,
# then force version regeneration:
#
ifeq ($(wildcard ../../.git/HEAD),)
GIT-HEAD-PHONY = ../../.git/HEAD
else
GIT-HEAD-PHONY =
endif
.PHONY: all install clean config-clean strip install-gtk
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope .FORCE-PERF-CFLAGS
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include "../../util/types.h" #include "../../util/types.h"
#include <asm/perf_regs.h> #include <asm/perf_regs.h>
#ifndef ARCH_X86_64 #ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
#else #else
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \ #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
...@@ -52,7 +52,7 @@ static inline const char *perf_reg_name(int id) ...@@ -52,7 +52,7 @@ static inline const char *perf_reg_name(int id)
return "FS"; return "FS";
case PERF_REG_X86_GS: case PERF_REG_X86_GS:
return "GS"; return "GS";
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
case PERF_REG_X86_R8: case PERF_REG_X86_R8:
return "R8"; return "R8";
case PERF_REG_X86_R9: case PERF_REG_X86_R9:
...@@ -69,7 +69,7 @@ static inline const char *perf_reg_name(int id) ...@@ -69,7 +69,7 @@ static inline const char *perf_reg_name(int id)
return "R14"; return "R14";
case PERF_REG_X86_R15: case PERF_REG_X86_R15:
return "R15"; return "R15";
#endif /* ARCH_X86_64 */ #endif /* HAVE_ARCH_X86_64_SUPPORT */
default: default:
return NULL; return NULL;
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "perf_regs.h" #include "perf_regs.h"
#include "../../util/unwind.h" #include "../../util/unwind.h"
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
int unwind__arch_reg_id(int regnum) int unwind__arch_reg_id(int regnum)
{ {
int id; int id;
...@@ -108,4 +108,4 @@ int unwind__arch_reg_id(int regnum) ...@@ -108,4 +108,4 @@ int unwind__arch_reg_id(int regnum)
return id; return id;
} }
#endif /* ARCH_X86_64 */ #endif /* HAVE_ARCH_X86_64_SUPPORT */
# perf completion # perf completion
function_exists() # Taken from git.git's completion script.
__my_reassemble_comp_words_by_ref()
{ {
declare -F $1 > /dev/null local exclude i j first
return $? # Which word separators to exclude?
exclude="${1//[^$COMP_WORDBREAKS]}"
cword_=$COMP_CWORD
if [ -z "$exclude" ]; then
words_=("${COMP_WORDS[@]}")
return
fi
# List of word completion separators has shrunk;
# re-assemble words to complete.
for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
# Append each nonempty word consisting of just
# word separator characters to the current word.
first=t
while
[ $i -gt 0 ] &&
[ -n "${COMP_WORDS[$i]}" ] &&
# word consists of excluded word separators
[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
do
# Attach to the previous token,
# unless the previous token is the command name.
if [ $j -ge 2 ] && [ -n "$first" ]; then
((j--))
fi
first=
words_[$j]=${words_[j]}${COMP_WORDS[i]}
if [ $i = $COMP_CWORD ]; then
cword_=$j
fi
if (($i < ${#COMP_WORDS[@]} - 1)); then
((i++))
else
# Done.
return
fi
done
words_[$j]=${words_[j]}${COMP_WORDS[i]}
if [ $i = $COMP_CWORD ]; then
cword_=$j
fi
done
} }
function_exists __ltrim_colon_completions || type _get_comp_words_by_ref &>/dev/null ||
_get_comp_words_by_ref()
{
local exclude cur_ words_ cword_
if [ "$1" = "-n" ]; then
exclude=$2
shift 2
fi
__my_reassemble_comp_words_by_ref "$exclude"
cur_=${words_[cword_]}
while [ $# -gt 0 ]; do
case "$1" in
cur)
cur=$cur_
;;
prev)
prev=${words_[$cword_-1]}
;;
words)
words=("${words_[@]}")
;;
cword)
cword=$cword_
;;
esac
shift
done
}
type __ltrim_colon_completions &>/dev/null ||
__ltrim_colon_completions() __ltrim_colon_completions()
{ {
if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
# Remove colon-word prefix from COMPREPLY items # Remove colon-word prefix from COMPREPLY items
local colon_word=${1%${1##*:}} local colon_word=${1%"${1##*:}"}
local i=${#COMPREPLY[*]} local i=${#COMPREPLY[*]}
while [[ $((--i)) -ge 0 ]]; do while [[ $((--i)) -ge 0 ]]; do
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
...@@ -19,23 +89,18 @@ __ltrim_colon_completions() ...@@ -19,23 +89,18 @@ __ltrim_colon_completions()
fi fi
} }
have perf && type perf &>/dev/null &&
_perf() _perf()
{ {
local cur prev cmd local cur words cword prev cmd
COMPREPLY=() COMPREPLY=()
if function_exists _get_comp_words_by_ref; then _get_comp_words_by_ref -n =: cur words cword prev
_get_comp_words_by_ref -n : cur prev
else
cur=$(_get_cword :)
prev=${COMP_WORDS[COMP_CWORD-1]}
fi
cmd=${COMP_WORDS[0]} cmd=${words[0]}
# List perf subcommands or long options # List perf subcommands or long options
if [ $COMP_CWORD -eq 1 ]; then if [ $cword -eq 1 ]; then
if [[ $cur == --* ]]; then if [[ $cur == --* ]]; then
COMPREPLY=( $( compgen -W '--help --version \ COMPREPLY=( $( compgen -W '--help --version \
--exec-path --html-path --paginate --no-pager \ --exec-path --html-path --paginate --no-pager \
...@@ -45,18 +110,17 @@ _perf() ...@@ -45,18 +110,17 @@ _perf()
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
fi fi
# List possible events for -e option # List possible events for -e option
elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
evts=$($cmd list --raw-dump) evts=$($cmd list --raw-dump)
COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) )
__ltrim_colon_completions $cur __ltrim_colon_completions $cur
# List long option names # List long option names
elif [[ $cur == --* ]]; then elif [[ $cur == --* ]]; then
subcmd=${COMP_WORDS[1]} subcmd=${words[1]}
opts=$($cmd $subcmd --list-opts) opts=$($cmd $subcmd --list-opts)
COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) )
# Fall down to list regular files
else
_filedir
fi fi
} && } &&
complete -F _perf perf
complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
|| complete -o default -o nospace -F _perf perf
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
#define MEMCPY_FN(fn, name, desc) \ #define MEMCPY_FN(fn, name, desc) \
extern void *fn(void *, const void *, size_t); extern void *fn(void *, const void *, size_t);
......
...@@ -58,7 +58,7 @@ struct routine routines[] = { ...@@ -58,7 +58,7 @@ struct routine routines[] = {
{ "default", { "default",
"Default memcpy() provided by glibc", "Default memcpy() provided by glibc",
memcpy }, memcpy },
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
#define MEMCPY_FN(fn, name, desc) { name, desc, fn }, #define MEMCPY_FN(fn, name, desc) { name, desc, fn },
#include "mem-memcpy-x86-64-asm-def.h" #include "mem-memcpy-x86-64-asm-def.h"
......
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
#define MEMSET_FN(fn, name, desc) \ #define MEMSET_FN(fn, name, desc) \
extern void *fn(void *, int, size_t); extern void *fn(void *, int, size_t);
......
...@@ -58,7 +58,7 @@ static const struct routine routines[] = { ...@@ -58,7 +58,7 @@ static const struct routine routines[] = {
{ "default", { "default",
"Default memset() provided by glibc", "Default memset() provided by glibc",
memset }, memset },
#ifdef ARCH_X86_64 #ifdef HAVE_ARCH_X86_64_SUPPORT
#define MEMSET_FN(fn, name, desc) { name, desc, fn }, #define MEMSET_FN(fn, name, desc) { name, desc, fn },
#include "mem-memset-x86-64-asm-def.h" #include "mem-memset-x86-64-asm-def.h"
......
...@@ -429,14 +429,14 @@ static int parse_cpu_list(const char *arg) ...@@ -429,14 +429,14 @@ static int parse_cpu_list(const char *arg)
return 0; return 0;
} }
static void parse_setup_cpu_list(void) static int parse_setup_cpu_list(void)
{ {
struct thread_data *td; struct thread_data *td;
char *str0, *str; char *str0, *str;
int t; int t;
if (!g->p.cpu_list_str) if (!g->p.cpu_list_str)
return; return 0;
dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
...@@ -500,8 +500,12 @@ static void parse_setup_cpu_list(void) ...@@ -500,8 +500,12 @@ static void parse_setup_cpu_list(void)
dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul); dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus); if (bind_cpu_0 >= g->p.nr_cpus || bind_cpu_1 >= g->p.nr_cpus) {
BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus); printf("\nTest not applicable, system has only %d CPUs.\n", g->p.nr_cpus);
return -1;
}
BUG_ON(bind_cpu_0 < 0 || bind_cpu_1 < 0);
BUG_ON(bind_cpu_0 > bind_cpu_1); BUG_ON(bind_cpu_0 > bind_cpu_1);
for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) { for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
...@@ -541,6 +545,7 @@ static void parse_setup_cpu_list(void) ...@@ -541,6 +545,7 @@ static void parse_setup_cpu_list(void)
printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t); printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
free(str0); free(str0);
return 0;
} }
static int parse_cpus_opt(const struct option *opt __maybe_unused, static int parse_cpus_opt(const struct option *opt __maybe_unused,
...@@ -561,14 +566,14 @@ static int parse_node_list(const char *arg) ...@@ -561,14 +566,14 @@ static int parse_node_list(const char *arg)
return 0; return 0;
} }
static void parse_setup_node_list(void) static int parse_setup_node_list(void)
{ {
struct thread_data *td; struct thread_data *td;
char *str0, *str; char *str0, *str;
int t; int t;
if (!g->p.node_list_str) if (!g->p.node_list_str)
return; return 0;
dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks); dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
...@@ -619,8 +624,12 @@ static void parse_setup_node_list(void) ...@@ -619,8 +624,12 @@ static void parse_setup_node_list(void)
dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step); dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes); if (bind_node_0 >= g->p.nr_nodes || bind_node_1 >= g->p.nr_nodes) {
BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes); printf("\nTest not applicable, system has only %d nodes.\n", g->p.nr_nodes);
return -1;
}
BUG_ON(bind_node_0 < 0 || bind_node_1 < 0);
BUG_ON(bind_node_0 > bind_node_1); BUG_ON(bind_node_0 > bind_node_1);
for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) { for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
...@@ -651,6 +660,7 @@ static void parse_setup_node_list(void) ...@@ -651,6 +660,7 @@ static void parse_setup_node_list(void)
printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t); printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
free(str0); free(str0);
return 0;
} }
static int parse_nodes_opt(const struct option *opt __maybe_unused, static int parse_nodes_opt(const struct option *opt __maybe_unused,
...@@ -1356,8 +1366,8 @@ static int init(void) ...@@ -1356,8 +1366,8 @@ static int init(void)
init_thread_data(); init_thread_data();
tprintf("#\n"); tprintf("#\n");
parse_setup_cpu_list(); if (parse_setup_cpu_list() || parse_setup_node_list())
parse_setup_node_list(); return -1;
tprintf("#\n"); tprintf("#\n");
print_summary(); print_summary();
...@@ -1600,7 +1610,6 @@ static int run_bench_numa(const char *name, const char **argv) ...@@ -1600,7 +1610,6 @@ static int run_bench_numa(const char *name, const char **argv)
return 0; return 0;
err: err:
usage_with_options(numa_usage, options);
return -1; return -1;
} }
...@@ -1701,8 +1710,7 @@ static int bench_all(void) ...@@ -1701,8 +1710,7 @@ static int bench_all(void)
BUG_ON(ret < 0); BUG_ON(ret < 0);
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
if (run_bench_numa(tests[i][0], tests[i] + 1)) run_bench_numa(tests[i][0], tests[i] + 1);
return -1;
} }
printf("\n"); printf("\n");
......
...@@ -7,9 +7,7 @@ ...@@ -7,9 +7,7 @@
* Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
* http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
* Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
*
*/ */
#include "../perf.h" #include "../perf.h"
#include "../util/util.h" #include "../util/util.h"
#include "../util/parse-options.h" #include "../util/parse-options.h"
...@@ -28,12 +26,24 @@ ...@@ -28,12 +26,24 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <pthread.h>
struct thread_data {
int nr;
int pipe_read;
int pipe_write;
pthread_t pthread;
};
#define LOOPS_DEFAULT 1000000 #define LOOPS_DEFAULT 1000000
static int loops = LOOPS_DEFAULT; static int loops = LOOPS_DEFAULT;
/* Use processes by default: */
static bool threaded;
static const struct option options[] = { static const struct option options[] = {
OPT_INTEGER('l', "loop", &loops, OPT_INTEGER('l', "loop", &loops, "Specify number of loops"),
"Specify number of loops"), OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"),
OPT_END() OPT_END()
}; };
...@@ -42,13 +52,37 @@ static const char * const bench_sched_pipe_usage[] = { ...@@ -42,13 +52,37 @@ static const char * const bench_sched_pipe_usage[] = {
NULL NULL
}; };
int bench_sched_pipe(int argc, const char **argv, static void *worker_thread(void *__tdata)
const char *prefix __maybe_unused)
{ {
int pipe_1[2], pipe_2[2]; struct thread_data *td = __tdata;
int m = 0, i; int m = 0, i;
int ret;
for (i = 0; i < loops; i++) {
if (!td->nr) {
ret = read(td->pipe_read, &m, sizeof(int));
BUG_ON(ret != sizeof(int));
ret = write(td->pipe_write, &m, sizeof(int));
BUG_ON(ret != sizeof(int));
} else {
ret = write(td->pipe_write, &m, sizeof(int));
BUG_ON(ret != sizeof(int));
ret = read(td->pipe_read, &m, sizeof(int));
BUG_ON(ret != sizeof(int));
}
}
return NULL;
}
int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct thread_data threads[2], *td;
int pipe_1[2], pipe_2[2];
struct timeval start, stop, diff; struct timeval start, stop, diff;
unsigned long long result_usec = 0; unsigned long long result_usec = 0;
int nr_threads = 2;
int t;
/* /*
* why does "ret" exist? * why does "ret" exist?
...@@ -58,43 +92,66 @@ int bench_sched_pipe(int argc, const char **argv, ...@@ -58,43 +92,66 @@ int bench_sched_pipe(int argc, const char **argv,
int __maybe_unused ret, wait_stat; int __maybe_unused ret, wait_stat;
pid_t pid, retpid __maybe_unused; pid_t pid, retpid __maybe_unused;
argc = parse_options(argc, argv, options, argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0);
bench_sched_pipe_usage, 0);
BUG_ON(pipe(pipe_1)); BUG_ON(pipe(pipe_1));
BUG_ON(pipe(pipe_2)); BUG_ON(pipe(pipe_2));
pid = fork();
assert(pid >= 0);
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
if (!pid) { for (t = 0; t < nr_threads; t++) {
for (i = 0; i < loops; i++) { td = threads + t;
ret = read(pipe_1[0], &m, sizeof(int));
ret = write(pipe_2[1], &m, sizeof(int)); td->nr = t;
}
} else { if (t == 0) {
for (i = 0; i < loops; i++) { td->pipe_read = pipe_1[0];
ret = write(pipe_1[1], &m, sizeof(int)); td->pipe_write = pipe_2[1];
ret = read(pipe_2[0], &m, sizeof(int)); } else {
td->pipe_write = pipe_1[1];
td->pipe_read = pipe_2[0];
} }
} }
gettimeofday(&stop, NULL);
timersub(&stop, &start, &diff);
if (pid) { if (threaded) {
for (t = 0; t < nr_threads; t++) {
td = threads + t;
ret = pthread_create(&td->pthread, NULL, worker_thread, td);
BUG_ON(ret);
}
for (t = 0; t < nr_threads; t++) {
td = threads + t;
ret = pthread_join(td->pthread, NULL);
BUG_ON(ret);
}
} else {
pid = fork();
assert(pid >= 0);
if (!pid) {
worker_thread(threads + 0);
exit(0);
} else {
worker_thread(threads + 1);
}
retpid = waitpid(pid, &wait_stat, 0); retpid = waitpid(pid, &wait_stat, 0);
assert((retpid == pid) && WIFEXITED(wait_stat)); assert((retpid == pid) && WIFEXITED(wait_stat));
} else {
exit(0);
} }
gettimeofday(&stop, NULL);
timersub(&stop, &start, &diff);
switch (bench_format) { switch (bench_format) {
case BENCH_FORMAT_DEFAULT: case BENCH_FORMAT_DEFAULT:
printf("# Executed %d pipe operations between two tasks\n\n", printf("# Executed %d pipe operations between two %s\n\n",
loops); loops, threaded ? "threads" : "processes");
result_usec = diff.tv_sec * 1000000; result_usec = diff.tv_sec * 1000000;
result_usec += diff.tv_usec; result_usec += diff.tv_usec;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "util/tool.h" #include "util/tool.h"
#include "arch/common.h" #include "arch/common.h"
#include <dlfcn.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
struct perf_annotate { struct perf_annotate {
...@@ -142,8 +143,18 @@ static void hists__find_annotations(struct hists *self, ...@@ -142,8 +143,18 @@ static void hists__find_annotations(struct hists *self,
if (use_browser == 2) { if (use_browser == 2) {
int ret; int ret;
int (*annotate)(struct hist_entry *he,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
annotate = dlsym(perf_gtk_handle,
"hist_entry__gtk_annotate");
if (annotate == NULL) {
ui__error("GTK browser not found!\n");
return;
}
ret = hist_entry__gtk_annotate(he, evsel, NULL); ret = annotate(he, evsel, NULL);
if (!ret || !ann->skip_missing) if (!ret || !ann->skip_missing)
return; return;
...@@ -247,8 +258,17 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -247,8 +258,17 @@ static int __cmd_annotate(struct perf_annotate *ann)
goto out_delete; goto out_delete;
} }
if (use_browser == 2) if (use_browser == 2) {
perf_gtk__show_annotations(); void (*show_annotations)(void);
show_annotations = dlsym(perf_gtk_handle,
"perf_gtk__show_annotations");
if (show_annotations == NULL) {
ui__error("GTK browser not found!\n");
goto out_delete;
}
show_annotations();
}
out_delete: out_delete:
/* /*
......
...@@ -35,7 +35,7 @@ struct bench_suite { ...@@ -35,7 +35,7 @@ struct bench_suite {
/* sentinel: easy for help */ /* sentinel: easy for help */
#define suite_all { "all", "Test all benchmark suites", NULL } #define suite_all { "all", "Test all benchmark suites", NULL }
#ifdef LIBNUMA_SUPPORT #ifdef HAVE_LIBNUMA_SUPPORT
static struct bench_suite numa_suites[] = { static struct bench_suite numa_suites[] = {
{ "mem", { "mem",
"Benchmark for NUMA workloads", "Benchmark for NUMA workloads",
...@@ -80,7 +80,7 @@ struct bench_subsys { ...@@ -80,7 +80,7 @@ struct bench_subsys {
}; };
static struct bench_subsys subsystems[] = { static struct bench_subsys subsystems[] = {
#ifdef LIBNUMA_SUPPORT #ifdef HAVE_LIBNUMA_SUPPORT
{ "numa", { "numa",
"NUMA scheduling and MM behavior", "NUMA scheduling and MM behavior",
numa_suites }, numa_suites },
......
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
* Copyright (C) 2010, Red Hat Inc. * Copyright (C) 2010, Red Hat Inc.
* Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com> * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
*/ */
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <dirent.h>
#include <unistd.h>
#include "builtin.h" #include "builtin.h"
#include "perf.h" #include "perf.h"
#include "util/cache.h" #include "util/cache.h"
...@@ -17,6 +22,140 @@ ...@@ -17,6 +22,140 @@
#include "util/session.h" #include "util/session.h"
#include "util/symbol.h" #include "util/symbol.h"
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
{
char root_dir[PATH_MAX];
char notes[PATH_MAX];
u8 build_id[BUILD_ID_SIZE];
char *p;
strlcpy(root_dir, proc_dir, sizeof(root_dir));
p = strrchr(root_dir, '/');
if (!p)
return -1;
*p = '\0';
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
return -1;
build_id__sprintf(build_id, sizeof(build_id), sbuildid);
return 0;
}
static int build_id_cache__kcore_dir(char *dir, size_t sz)
{
struct timeval tv;
struct tm tm;
char dt[32];
if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
return -1;
if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
return -1;
scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
return 0;
}
static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
size_t to_dir_sz)
{
char from[PATH_MAX];
char to[PATH_MAX];
struct dirent *dent;
int ret = -1;
DIR *d;
d = opendir(to_dir);
if (!d)
return -1;
scnprintf(from, sizeof(from), "%s/modules", from_dir);
while (1) {
dent = readdir(d);
if (!dent)
break;
if (dent->d_type != DT_DIR)
continue;
scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
dent->d_name);
if (!compare_proc_modules(from, to)) {
scnprintf(to, sizeof(to), "%s/%s", to_dir,
dent->d_name);
strlcpy(to_dir, to, to_dir_sz);
ret = 0;
break;
}
}
closedir(d);
return ret;
}
static int build_id_cache__add_kcore(const char *filename, const char *debugdir)
{
char dir[32], sbuildid[BUILD_ID_SIZE * 2 + 1];
char from_dir[PATH_MAX], to_dir[PATH_MAX];
char *p;
strlcpy(from_dir, filename, sizeof(from_dir));
p = strrchr(from_dir, '/');
if (!p || strcmp(p + 1, "kcore"))
return -1;
*p = '\0';
if (build_id_cache__kcore_buildid(from_dir, sbuildid))
return -1;
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
debugdir, sbuildid);
if (!build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
pr_debug("same kcore found in %s\n", to_dir);
return 0;
}
if (build_id_cache__kcore_dir(dir, sizeof(dir)))
return -1;
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s/%s",
debugdir, sbuildid, dir);
if (mkdir_p(to_dir, 0755))
return -1;
if (kcore_copy(from_dir, to_dir)) {
/* Remove YYYYmmddHHMMSShh directory */
if (!rmdir(to_dir)) {
p = strrchr(to_dir, '/');
if (p)
*p = '\0';
/* Try to remove buildid directory */
if (!rmdir(to_dir)) {
p = strrchr(to_dir, '/');
if (p)
*p = '\0';
/* Try to remove [kernel.kcore] directory */
rmdir(to_dir);
}
}
return -1;
}
pr_debug("kcore added to build-id cache directory %s\n", to_dir);
return 0;
}
static int build_id_cache__add_file(const char *filename, const char *debugdir) static int build_id_cache__add_file(const char *filename, const char *debugdir)
{ {
char sbuild_id[BUILD_ID_SIZE * 2 + 1]; char sbuild_id[BUILD_ID_SIZE * 2 + 1];
...@@ -130,11 +269,14 @@ int cmd_buildid_cache(int argc, const char **argv, ...@@ -130,11 +269,14 @@ int cmd_buildid_cache(int argc, const char **argv,
char const *add_name_list_str = NULL, char const *add_name_list_str = NULL,
*remove_name_list_str = NULL, *remove_name_list_str = NULL,
*missing_filename = NULL, *missing_filename = NULL,
*update_name_list_str = NULL; *update_name_list_str = NULL,
*kcore_filename;
const struct option buildid_cache_options[] = { const struct option buildid_cache_options[] = {
OPT_STRING('a', "add", &add_name_list_str, OPT_STRING('a', "add", &add_name_list_str,
"file list", "file(s) to add"), "file list", "file(s) to add"),
OPT_STRING('k', "kcore", &kcore_filename,
"file", "kcore file to add"),
OPT_STRING('r', "remove", &remove_name_list_str, "file list", OPT_STRING('r', "remove", &remove_name_list_str, "file list",
"file(s) to remove"), "file(s) to remove"),
OPT_STRING('M', "missing", &missing_filename, "file", OPT_STRING('M', "missing", &missing_filename, "file",
...@@ -217,5 +359,9 @@ int cmd_buildid_cache(int argc, const char **argv, ...@@ -217,5 +359,9 @@ int cmd_buildid_cache(int argc, const char **argv,
} }
} }
if (kcore_filename &&
build_id_cache__add_kcore(kcore_filename, debugdir))
pr_warning("Couldn't add %s\n", kcore_filename);
return ret; return ret;
} }
...@@ -231,7 +231,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool, ...@@ -231,7 +231,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
* account this as unresolved. * account this as unresolved.
*/ */
} else { } else {
#ifdef LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
pr_warning("no symbols found in %s, maybe " pr_warning("no symbols found in %s, maybe "
"install a debug package?\n", "install a debug package?\n",
al.map->dso->long_name); al.map->dso->long_name);
......
...@@ -1426,8 +1426,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, ...@@ -1426,8 +1426,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
const struct option live_options[] = { const struct option live_options[] = {
OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
"record events on existing process id"), "record events on existing process id"),
OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages, OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",
"number of mmap data pages"), "number of mmap data pages",
perf_evlist__parse_mmap_pages),
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"), "be more verbose (show counter open errors, etc)"),
OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide, OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
......
...@@ -56,7 +56,9 @@ struct lock_stat { ...@@ -56,7 +56,9 @@ struct lock_stat {
unsigned int nr_readlock; unsigned int nr_readlock;
unsigned int nr_trylock; unsigned int nr_trylock;
/* these times are in nano sec. */ /* these times are in nano sec. */
u64 avg_wait_time;
u64 wait_time_total; u64 wait_time_total;
u64 wait_time_min; u64 wait_time_min;
u64 wait_time_max; u64 wait_time_max;
...@@ -208,6 +210,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid) ...@@ -208,6 +210,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
SINGLE_KEY(nr_acquired) SINGLE_KEY(nr_acquired)
SINGLE_KEY(nr_contended) SINGLE_KEY(nr_contended)
SINGLE_KEY(avg_wait_time)
SINGLE_KEY(wait_time_total) SINGLE_KEY(wait_time_total)
SINGLE_KEY(wait_time_max) SINGLE_KEY(wait_time_max)
...@@ -244,6 +247,7 @@ static struct rb_root result; /* place to store sorted data */ ...@@ -244,6 +247,7 @@ static struct rb_root result; /* place to store sorted data */
struct lock_key keys[] = { struct lock_key keys[] = {
DEF_KEY_LOCK(acquired, nr_acquired), DEF_KEY_LOCK(acquired, nr_acquired),
DEF_KEY_LOCK(contended, nr_contended), DEF_KEY_LOCK(contended, nr_contended),
DEF_KEY_LOCK(avg_wait, avg_wait_time),
DEF_KEY_LOCK(wait_total, wait_time_total), DEF_KEY_LOCK(wait_total, wait_time_total),
DEF_KEY_LOCK(wait_min, wait_time_min), DEF_KEY_LOCK(wait_min, wait_time_min),
DEF_KEY_LOCK(wait_max, wait_time_max), DEF_KEY_LOCK(wait_max, wait_time_max),
...@@ -321,10 +325,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name) ...@@ -321,10 +325,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
new->addr = addr; new->addr = addr;
new->name = zalloc(sizeof(char) * strlen(name) + 1); new->name = zalloc(sizeof(char) * strlen(name) + 1);
if (!new->name) if (!new->name) {
free(new);
goto alloc_failed; goto alloc_failed;
strcpy(new->name, name); }
strcpy(new->name, name);
new->wait_time_min = ULLONG_MAX; new->wait_time_min = ULLONG_MAX;
list_add(&new->hash_entry, entry); list_add(&new->hash_entry, entry);
...@@ -400,17 +406,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel, ...@@ -400,17 +406,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
ls = lock_stat_findnew(addr, name); ls = lock_stat_findnew(addr, name);
if (!ls) if (!ls)
return -1; return -ENOMEM;
if (ls->discard) if (ls->discard)
return 0; return 0;
ts = thread_stat_findnew(sample->tid); ts = thread_stat_findnew(sample->tid);
if (!ts) if (!ts)
return -1; return -ENOMEM;
seq = get_seq(ts, addr); seq = get_seq(ts, addr);
if (!seq) if (!seq)
return -1; return -ENOMEM;
switch (seq->state) { switch (seq->state) {
case SEQ_STATE_UNINITIALIZED: case SEQ_STATE_UNINITIALIZED:
...@@ -446,7 +452,6 @@ static int report_lock_acquire_event(struct perf_evsel *evsel, ...@@ -446,7 +452,6 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
list_del(&seq->list); list_del(&seq->list);
free(seq); free(seq);
goto end; goto end;
break;
default: default:
BUG_ON("Unknown state of lock sequence found!\n"); BUG_ON("Unknown state of lock sequence found!\n");
break; break;
...@@ -473,17 +478,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel, ...@@ -473,17 +478,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
ls = lock_stat_findnew(addr, name); ls = lock_stat_findnew(addr, name);
if (!ls) if (!ls)
return -1; return -ENOMEM;
if (ls->discard) if (ls->discard)
return 0; return 0;
ts = thread_stat_findnew(sample->tid); ts = thread_stat_findnew(sample->tid);
if (!ts) if (!ts)
return -1; return -ENOMEM;
seq = get_seq(ts, addr); seq = get_seq(ts, addr);
if (!seq) if (!seq)
return -1; return -ENOMEM;
switch (seq->state) { switch (seq->state) {
case SEQ_STATE_UNINITIALIZED: case SEQ_STATE_UNINITIALIZED:
...@@ -508,8 +513,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel, ...@@ -508,8 +513,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
list_del(&seq->list); list_del(&seq->list);
free(seq); free(seq);
goto end; goto end;
break;
default: default:
BUG_ON("Unknown state of lock sequence found!\n"); BUG_ON("Unknown state of lock sequence found!\n");
break; break;
...@@ -517,6 +520,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel, ...@@ -517,6 +520,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
seq->state = SEQ_STATE_ACQUIRED; seq->state = SEQ_STATE_ACQUIRED;
ls->nr_acquired++; ls->nr_acquired++;
ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
seq->prev_event_time = sample->time; seq->prev_event_time = sample->time;
end: end:
return 0; return 0;
...@@ -536,17 +540,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel, ...@@ -536,17 +540,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
ls = lock_stat_findnew(addr, name); ls = lock_stat_findnew(addr, name);
if (!ls) if (!ls)
return -1; return -ENOMEM;
if (ls->discard) if (ls->discard)
return 0; return 0;
ts = thread_stat_findnew(sample->tid); ts = thread_stat_findnew(sample->tid);
if (!ts) if (!ts)
return -1; return -ENOMEM;
seq = get_seq(ts, addr); seq = get_seq(ts, addr);
if (!seq) if (!seq)
return -1; return -ENOMEM;
switch (seq->state) { switch (seq->state) {
case SEQ_STATE_UNINITIALIZED: case SEQ_STATE_UNINITIALIZED:
...@@ -564,7 +568,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel, ...@@ -564,7 +568,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
list_del(&seq->list); list_del(&seq->list);
free(seq); free(seq);
goto end; goto end;
break;
default: default:
BUG_ON("Unknown state of lock sequence found!\n"); BUG_ON("Unknown state of lock sequence found!\n");
break; break;
...@@ -572,6 +575,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel, ...@@ -572,6 +575,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
seq->state = SEQ_STATE_CONTENDED; seq->state = SEQ_STATE_CONTENDED;
ls->nr_contended++; ls->nr_contended++;
ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
seq->prev_event_time = sample->time; seq->prev_event_time = sample->time;
end: end:
return 0; return 0;
...@@ -591,22 +595,21 @@ static int report_lock_release_event(struct perf_evsel *evsel, ...@@ -591,22 +595,21 @@ static int report_lock_release_event(struct perf_evsel *evsel,
ls = lock_stat_findnew(addr, name); ls = lock_stat_findnew(addr, name);
if (!ls) if (!ls)
return -1; return -ENOMEM;
if (ls->discard) if (ls->discard)
return 0; return 0;
ts = thread_stat_findnew(sample->tid); ts = thread_stat_findnew(sample->tid);
if (!ts) if (!ts)
return -1; return -ENOMEM;
seq = get_seq(ts, addr); seq = get_seq(ts, addr);
if (!seq) if (!seq)
return -1; return -ENOMEM;
switch (seq->state) { switch (seq->state) {
case SEQ_STATE_UNINITIALIZED: case SEQ_STATE_UNINITIALIZED:
goto end; goto end;
break;
case SEQ_STATE_ACQUIRED: case SEQ_STATE_ACQUIRED:
break; break;
case SEQ_STATE_READ_ACQUIRED: case SEQ_STATE_READ_ACQUIRED:
...@@ -624,7 +627,6 @@ static int report_lock_release_event(struct perf_evsel *evsel, ...@@ -624,7 +627,6 @@ static int report_lock_release_event(struct perf_evsel *evsel,
ls->discard = 1; ls->discard = 1;
bad_hist[BROKEN_RELEASE]++; bad_hist[BROKEN_RELEASE]++;
goto free_seq; goto free_seq;
break;
default: default:
BUG_ON("Unknown state of lock sequence found!\n"); BUG_ON("Unknown state of lock sequence found!\n");
break; break;
...@@ -690,7 +692,7 @@ static void print_bad_events(int bad, int total) ...@@ -690,7 +692,7 @@ static void print_bad_events(int bad, int total)
pr_info("\n=== output for debug===\n\n"); pr_info("\n=== output for debug===\n\n");
pr_info("bad: %d, total: %d\n", bad, total); pr_info("bad: %d, total: %d\n", bad, total);
pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100); pr_info("bad rate: %.2f %%\n", (double)bad / (double)total * 100);
pr_info("histogram of events caused bad sequence\n"); pr_info("histogram of events caused bad sequence\n");
for (i = 0; i < BROKEN_MAX; i++) for (i = 0; i < BROKEN_MAX; i++)
pr_info(" %10s: %d\n", name[i], bad_hist[i]); pr_info(" %10s: %d\n", name[i], bad_hist[i]);
...@@ -707,6 +709,7 @@ static void print_result(void) ...@@ -707,6 +709,7 @@ static void print_result(void)
pr_info("%10s ", "acquired"); pr_info("%10s ", "acquired");
pr_info("%10s ", "contended"); pr_info("%10s ", "contended");
pr_info("%15s ", "avg wait (ns)");
pr_info("%15s ", "total wait (ns)"); pr_info("%15s ", "total wait (ns)");
pr_info("%15s ", "max wait (ns)"); pr_info("%15s ", "max wait (ns)");
pr_info("%15s ", "min wait (ns)"); pr_info("%15s ", "min wait (ns)");
...@@ -738,6 +741,7 @@ static void print_result(void) ...@@ -738,6 +741,7 @@ static void print_result(void)
pr_info("%10u ", st->nr_acquired); pr_info("%10u ", st->nr_acquired);
pr_info("%10u ", st->nr_contended); pr_info("%10u ", st->nr_contended);
pr_info("%15" PRIu64 " ", st->avg_wait_time);
pr_info("%15" PRIu64 " ", st->wait_time_total); pr_info("%15" PRIu64 " ", st->wait_time_total);
pr_info("%15" PRIu64 " ", st->wait_time_max); pr_info("%15" PRIu64 " ", st->wait_time_max);
pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ? pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
...@@ -822,6 +826,18 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -822,6 +826,18 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return 0; return 0;
} }
static void sort_result(void)
{
unsigned int i;
struct lock_stat *st;
for (i = 0; i < LOCKHASH_SIZE; i++) {
list_for_each_entry(st, &lockhash_table[i], hash_entry) {
insert_to_result(st, compare);
}
}
}
static const struct perf_evsel_str_handler lock_tracepoints[] = { static const struct perf_evsel_str_handler lock_tracepoints[] = {
{ "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */ { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
{ "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */ { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
...@@ -829,51 +845,47 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = { ...@@ -829,51 +845,47 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = {
{ "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */ { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
}; };
static int read_events(void) static int __cmd_report(bool display_info)
{ {
int err = -EINVAL;
struct perf_tool eops = { struct perf_tool eops = {
.sample = process_sample_event, .sample = process_sample_event,
.comm = perf_event__process_comm, .comm = perf_event__process_comm,
.ordered_samples = true, .ordered_samples = true,
}; };
session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
if (!session) { if (!session) {
pr_err("Initializing perf session failed\n"); pr_err("Initializing perf session failed\n");
return -1; return -ENOMEM;
} }
if (!perf_session__has_traces(session, "lock record"))
goto out_delete;
if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) { if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
pr_err("Initializing perf session tracepoint handlers failed\n"); pr_err("Initializing perf session tracepoint handlers failed\n");
return -1; goto out_delete;
} }
return perf_session__process_events(session, &eops); if (select_key())
} goto out_delete;
static void sort_result(void) err = perf_session__process_events(session, &eops);
{ if (err)
unsigned int i; goto out_delete;
struct lock_stat *st;
for (i = 0; i < LOCKHASH_SIZE; i++) {
list_for_each_entry(st, &lockhash_table[i], hash_entry) {
insert_to_result(st, compare);
}
}
}
static int __cmd_report(void)
{
setup_pager(); setup_pager();
if (display_info) /* used for info subcommand */
err = dump_info();
else {
sort_result();
print_result();
}
if ((select_key() != 0) || out_delete:
(read_events() != 0)) perf_session__delete(session);
return -1; return err;
sort_result();
print_result();
return 0;
} }
static int __cmd_record(int argc, const char **argv) static int __cmd_record(int argc, const char **argv)
...@@ -881,7 +893,7 @@ static int __cmd_record(int argc, const char **argv) ...@@ -881,7 +893,7 @@ static int __cmd_record(int argc, const char **argv)
const char *record_args[] = { const char *record_args[] = {
"record", "-R", "-m", "1024", "-c", "1", "record", "-R", "-m", "1024", "-c", "1",
}; };
unsigned int rec_argc, i, j; unsigned int rec_argc, i, j, ret;
const char **rec_argv; const char **rec_argv;
for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) { for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
...@@ -898,7 +910,7 @@ static int __cmd_record(int argc, const char **argv) ...@@ -898,7 +910,7 @@ static int __cmd_record(int argc, const char **argv)
rec_argc += 2 * ARRAY_SIZE(lock_tracepoints); rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (rec_argv == NULL) if (!rec_argv)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(record_args); i++) for (i = 0; i < ARRAY_SIZE(record_args); i++)
...@@ -914,7 +926,9 @@ static int __cmd_record(int argc, const char **argv) ...@@ -914,7 +926,9 @@ static int __cmd_record(int argc, const char **argv)
BUG_ON(i != rec_argc); BUG_ON(i != rec_argc);
return cmd_record(i, rec_argv, NULL); ret = cmd_record(i, rec_argv, NULL);
free(rec_argv);
return ret;
} }
int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
...@@ -934,7 +948,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -934,7 +948,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
}; };
const struct option report_options[] = { const struct option report_options[] = {
OPT_STRING('k', "key", &sort_key, "acquired", OPT_STRING('k', "key", &sort_key, "acquired",
"key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
/* TODO: type */ /* TODO: type */
OPT_END() OPT_END()
}; };
...@@ -972,7 +986,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -972,7 +986,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc) if (argc)
usage_with_options(report_usage, report_options); usage_with_options(report_usage, report_options);
} }
__cmd_report(); rc = __cmd_report(false);
} else if (!strcmp(argv[0], "script")) { } else if (!strcmp(argv[0], "script")) {
/* Aliased to 'perf script' */ /* Aliased to 'perf script' */
return cmd_script(argc, argv, prefix); return cmd_script(argc, argv, prefix);
...@@ -985,11 +999,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -985,11 +999,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
} }
/* recycling report_lock_ops */ /* recycling report_lock_ops */
trace_handler = &report_lock_ops; trace_handler = &report_lock_ops;
setup_pager(); rc = __cmd_report(true);
if (read_events() != 0)
rc = -1;
else
rc = dump_info();
} else { } else {
usage_with_options(lock_usage, lock_options); usage_with_options(lock_usage, lock_options);
} }
......
...@@ -173,7 +173,7 @@ static int opt_set_target(const struct option *opt, const char *str, ...@@ -173,7 +173,7 @@ static int opt_set_target(const struct option *opt, const char *str,
if (str && !params.target) { if (str && !params.target) {
if (!strcmp(opt->long_name, "exec")) if (!strcmp(opt->long_name, "exec"))
params.uprobes = true; params.uprobes = true;
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
else if (!strcmp(opt->long_name, "module")) else if (!strcmp(opt->long_name, "module"))
params.uprobes = false; params.uprobes = false;
#endif #endif
...@@ -187,7 +187,7 @@ static int opt_set_target(const struct option *opt, const char *str, ...@@ -187,7 +187,7 @@ static int opt_set_target(const struct option *opt, const char *str,
return ret; return ret;
} }
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
static int opt_show_lines(const struct option *opt __maybe_unused, static int opt_show_lines(const struct option *opt __maybe_unused,
const char *str, int unset __maybe_unused) const char *str, int unset __maybe_unused)
{ {
...@@ -257,7 +257,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -257,7 +257,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
"perf probe [<options>] --del '[GROUP:]EVENT' ...", "perf probe [<options>] --del '[GROUP:]EVENT' ...",
"perf probe --list", "perf probe --list",
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
"perf probe [<options>] --line 'LINEDESC'", "perf probe [<options>] --line 'LINEDESC'",
"perf probe [<options>] --vars 'PROBEPOINT'", "perf probe [<options>] --vars 'PROBEPOINT'",
#endif #endif
...@@ -271,7 +271,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -271,7 +271,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
opt_del_probe_event), opt_del_probe_event),
OPT_CALLBACK('a', "add", NULL, OPT_CALLBACK('a', "add", NULL,
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
"[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
" [[NAME=]ARG ...]", " [[NAME=]ARG ...]",
#else #else
...@@ -283,7 +283,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -283,7 +283,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
"\t\tFUNC:\tFunction name\n" "\t\tFUNC:\tFunction name\n"
"\t\tOFF:\tOffset from function entry (in byte)\n" "\t\tOFF:\tOffset from function entry (in byte)\n"
"\t\t%return:\tPut the probe at function return\n" "\t\t%return:\tPut the probe at function return\n"
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
"\t\tSRC:\tSource code path\n" "\t\tSRC:\tSource code path\n"
"\t\tRL:\tRelative line number from function entry.\n" "\t\tRL:\tRelative line number from function entry.\n"
"\t\tAL:\tAbsolute line number in file.\n" "\t\tAL:\tAbsolute line number in file.\n"
...@@ -296,7 +296,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -296,7 +296,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
opt_add_probe_event), opt_add_probe_event),
OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events" OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
" with existing name"), " with existing name"),
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
OPT_CALLBACK('L', "line", NULL, OPT_CALLBACK('L', "line", NULL,
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
"Show source code lines.", opt_show_lines), "Show source code lines.", opt_show_lines),
...@@ -408,7 +408,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -408,7 +408,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
return ret; return ret;
} }
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
if (params.show_lines && !params.uprobes) { if (params.show_lines && !params.uprobes) {
if (params.mod_events) { if (params.mod_events) {
pr_err(" Error: Don't use --line with" pr_err(" Error: Don't use --line with"
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <sched.h> #include <sched.h>
#include <sys/mman.h> #include <sys/mman.h>
#ifndef HAVE_ON_EXIT #ifndef HAVE_ON_EXIT_SUPPORT
#ifndef ATEXIT_MAX #ifndef ATEXIT_MAX
#define ATEXIT_MAX 32 #define ATEXIT_MAX 32
#endif #endif
...@@ -70,7 +70,6 @@ struct perf_record { ...@@ -70,7 +70,6 @@ struct perf_record {
struct perf_session *session; struct perf_session *session;
const char *progname; const char *progname;
int output; int output;
unsigned int page_size;
int realtime_prio; int realtime_prio;
bool no_buildid; bool no_buildid;
bool no_buildid_cache; bool no_buildid_cache;
...@@ -119,7 +118,7 @@ static int perf_record__mmap_read(struct perf_record *rec, ...@@ -119,7 +118,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
{ {
unsigned int head = perf_mmap__read_head(md); unsigned int head = perf_mmap__read_head(md);
unsigned int old = md->prev; unsigned int old = md->prev;
unsigned char *data = md->base + rec->page_size; unsigned char *data = md->base + page_size;
unsigned long size; unsigned long size;
void *buf; void *buf;
int rc = 0; int rc = 0;
...@@ -234,10 +233,6 @@ static int perf_record__open(struct perf_record *rec) ...@@ -234,10 +233,6 @@ static int perf_record__open(struct perf_record *rec)
"or try again with a smaller value of -m/--mmap_pages.\n" "or try again with a smaller value of -m/--mmap_pages.\n"
"(current value: %d)\n", opts->mmap_pages); "(current value: %d)\n", opts->mmap_pages);
rc = -errno; rc = -errno;
} else if (!is_power_of_2(opts->mmap_pages) &&
(opts->mmap_pages != UINT_MAX)) {
pr_err("--mmap_pages/-m value must be a power of two.");
rc = -EINVAL;
} else { } else {
pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
rc = -errno; rc = -errno;
...@@ -360,8 +355,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) ...@@ -360,8 +355,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
rec->progname = argv[0]; rec->progname = argv[0];
rec->page_size = sysconf(_SC_PAGE_SIZE);
on_exit(perf_record__sig_exit, rec); on_exit(perf_record__sig_exit, rec);
signal(SIGCHLD, sig_handler); signal(SIGCHLD, sig_handler);
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
...@@ -687,7 +680,7 @@ parse_branch_stack(const struct option *opt, const char *str, int unset) ...@@ -687,7 +680,7 @@ parse_branch_stack(const struct option *opt, const char *str, int unset)
return ret; return ret;
} }
#ifdef LIBUNWIND_SUPPORT #ifdef HAVE_LIBUNWIND_SUPPORT
static int get_stack_size(char *str, unsigned long *_size) static int get_stack_size(char *str, unsigned long *_size)
{ {
char *endptr; char *endptr;
...@@ -713,7 +706,7 @@ static int get_stack_size(char *str, unsigned long *_size) ...@@ -713,7 +706,7 @@ static int get_stack_size(char *str, unsigned long *_size)
max_size, str); max_size, str);
return -1; return -1;
} }
#endif /* LIBUNWIND_SUPPORT */ #endif /* HAVE_LIBUNWIND_SUPPORT */
int record_parse_callchain_opt(const struct option *opt, int record_parse_callchain_opt(const struct option *opt,
const char *arg, int unset) const char *arg, int unset)
...@@ -751,7 +744,7 @@ int record_parse_callchain_opt(const struct option *opt, ...@@ -751,7 +744,7 @@ int record_parse_callchain_opt(const struct option *opt,
"needed for -g fp\n"); "needed for -g fp\n");
break; break;
#ifdef LIBUNWIND_SUPPORT #ifdef HAVE_LIBUNWIND_SUPPORT
/* Dwarf style */ /* Dwarf style */
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
const unsigned long default_stack_dump_size = 8192; const unsigned long default_stack_dump_size = 8192;
...@@ -771,7 +764,7 @@ int record_parse_callchain_opt(const struct option *opt, ...@@ -771,7 +764,7 @@ int record_parse_callchain_opt(const struct option *opt,
if (!ret) if (!ret)
pr_debug("callchain: stack dump size %d\n", pr_debug("callchain: stack dump size %d\n",
opts->stack_dump_size); opts->stack_dump_size);
#endif /* LIBUNWIND_SUPPORT */ #endif /* HAVE_LIBUNWIND_SUPPORT */
} else { } else {
pr_err("callchain: Unknown -g option " pr_err("callchain: Unknown -g option "
"value: %s\n", arg); "value: %s\n", arg);
...@@ -818,7 +811,7 @@ static struct perf_record record = { ...@@ -818,7 +811,7 @@ static struct perf_record record = {
#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
#ifdef LIBUNWIND_SUPPORT #ifdef HAVE_LIBUNWIND_SUPPORT
const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
#else #else
const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
...@@ -857,8 +850,9 @@ const struct option record_options[] = { ...@@ -857,8 +850,9 @@ const struct option record_options[] = {
OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
"child tasks do not inherit counters"), "child tasks do not inherit counters"),
OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
"number of mmap data pages"), "number of mmap data pages",
perf_evlist__parse_mmap_pages),
OPT_BOOLEAN(0, "group", &record.opts.group, OPT_BOOLEAN(0, "group", &record.opts.group,
"put the counters into a counter group"), "put the counters into a counter group"),
OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "util/hist.h" #include "util/hist.h"
#include "arch/common.h" #include "arch/common.h"
#include <dlfcn.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
struct perf_report { struct perf_report {
...@@ -591,8 +592,19 @@ static int __cmd_report(struct perf_report *rep) ...@@ -591,8 +592,19 @@ static int __cmd_report(struct perf_report *rep)
ret = 0; ret = 0;
} else if (use_browser == 2) { } else if (use_browser == 2) {
perf_evlist__gtk_browse_hists(session->evlist, help, int (*hist_browser)(struct perf_evlist *,
NULL, rep->min_percent); const char *,
struct hist_browser_timer *,
float min_pcnt);
hist_browser = dlsym(perf_gtk_handle,
"perf_evlist__gtk_browse_hists");
if (hist_browser == NULL) {
ui__error("GTK browser not found!\n");
return ret;
}
hist_browser(session->evlist, help, NULL,
rep->min_percent);
} }
} else } else
perf_evlist__tty_browse_hists(session->evlist, rep, help); perf_evlist__tty_browse_hists(session->evlist, rep, help);
......
...@@ -706,10 +706,13 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) ...@@ -706,10 +706,13 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
{ {
double msecs = avg / 1e6; double msecs = avg / 1e6;
const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
char name[25];
aggr_printout(evsel, cpu, nr); aggr_printout(evsel, cpu, nr);
fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel)); scnprintf(name, sizeof(name), "%s%s",
perf_evsel__name(evsel), csv_output ? "" : " (msec)");
fprintf(output, fmt, msecs, csv_sep, name);
if (evsel->cgrp) if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
...@@ -930,11 +933,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) ...@@ -930,11 +933,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
total = avg_stats(&runtime_cycles_stats[cpu]); total = avg_stats(&runtime_cycles_stats[cpu]);
if (total) if (total) {
ratio = avg / total; ratio = avg / total;
fprintf(output, " # %5.2f insns per cycle ", ratio);
fprintf(output, " # %5.2f insns per cycle ", ratio); }
total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
...@@ -997,10 +999,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) ...@@ -997,10 +999,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
} else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
total = avg_stats(&runtime_nsecs_stats[cpu]); total = avg_stats(&runtime_nsecs_stats[cpu]);
if (total) if (total) {
ratio = 1.0 * avg / total; ratio = avg / total;
fprintf(output, " # %8.3f GHz ", ratio);
fprintf(output, " # %8.3f GHz ", ratio); }
} else if (transaction_run && } else if (transaction_run &&
perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) { perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
total = avg_stats(&runtime_cycles_stats[cpu]); total = avg_stats(&runtime_cycles_stats[cpu]);
...@@ -1230,7 +1232,11 @@ static void print_stat(int argc, const char **argv) ...@@ -1230,7 +1232,11 @@ static void print_stat(int argc, const char **argv)
if (!csv_output) { if (!csv_output) {
fprintf(output, "\n"); fprintf(output, "\n");
fprintf(output, " Performance counter stats for "); fprintf(output, " Performance counter stats for ");
if (!perf_target__has_task(&target)) { if (target.system_wide)
fprintf(output, "\'system wide");
else if (target.cpu_list)
fprintf(output, "\'CPU(s) %s", target.cpu_list);
else if (!perf_target__has_task(&target)) {
fprintf(output, "\'%s", argv[0]); fprintf(output, "\'%s", argv[0]);
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
fprintf(output, " %s", argv[i]); fprintf(output, " %s", argv[i]);
...@@ -1656,8 +1662,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1656,8 +1662,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
} else if (big_num_opt == 0) /* User passed --no-big-num */ } else if (big_num_opt == 0) /* User passed --no-big-num */
big_num = false; big_num = false;
if (!argc && !perf_target__has_task(&target)) if (!argc && perf_target__none(&target))
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
if (run_count < 0) { if (run_count < 0) {
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
} else if (run_count == 0) { } else if (run_count == 0) {
......
...@@ -1073,10 +1073,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1073,10 +1073,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"list of cpus to monitor"), "list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"), "file", "vmlinux pathname"),
OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
"don't load vmlinux even if found"),
OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
"hide kernel symbols"), "hide kernel symbols"),
OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages, OPT_CALLBACK('m', "mmap-pages", &opts->mmap_pages, "pages",
"number of mmap data pages"), "number of mmap data pages",
perf_evlist__parse_mmap_pages),
OPT_INTEGER('r', "realtime", &top.realtime_prio, OPT_INTEGER('r', "realtime", &top.realtime_prio,
"collect data with this RT SCHED_FIFO priority"), "collect data with this RT SCHED_FIFO priority"),
OPT_INTEGER('d', "delay", &top.delay_secs, OPT_INTEGER('d', "delay", &top.delay_secs,
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
#include "util/strlist.h" #include "util/strlist.h"
#include "util/intlist.h" #include "util/intlist.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include "util/stat.h"
#include <libaudit.h> #include <libaudit.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/eventfd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <linux/futex.h> #include <linux/futex.h>
...@@ -33,49 +35,96 @@ ...@@ -33,49 +35,96 @@
# define MADV_UNMERGEABLE 13 # define MADV_UNMERGEABLE 13
#endif #endif
static size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg {
unsigned long arg, unsigned long val;
u8 arg_idx __maybe_unused, struct thread *thread;
u8 *arg_mask __maybe_unused) struct trace *trace;
void *parm;
u8 idx;
u8 mask;
};
struct strarray {
int offset;
int nr_entries;
const char **entries;
};
#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
.nr_entries = ARRAY_SIZE(array), \
.entries = array, \
}
#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
.offset = off, \
.nr_entries = ARRAY_SIZE(array), \
.entries = array, \
}
static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
const char *intfmt,
struct syscall_arg *arg)
{ {
return scnprintf(bf, size, "%#lx", arg); struct strarray *sa = arg->parm;
int idx = arg->val - sa->offset;
if (idx < 0 || idx >= sa->nr_entries)
return scnprintf(bf, size, intfmt, arg->val);
return scnprintf(bf, size, "%s", sa->entries[idx]);
} }
#define SCA_HEX syscall_arg__scnprintf_hex static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
struct syscall_arg *arg)
{
return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
}
static size_t syscall_arg__scnprintf_whence(char *bf, size_t size, #define SCA_STRARRAY syscall_arg__scnprintf_strarray
unsigned long arg,
u8 arg_idx __maybe_unused, static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
u8 *arg_mask __maybe_unused) struct syscall_arg *arg)
{ {
int whence = arg; return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
}
switch (whence) { #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
P_WHENCE(SET); static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
P_WHENCE(CUR); struct syscall_arg *arg);
P_WHENCE(END);
#ifdef SEEK_DATA #define SCA_FD syscall_arg__scnprintf_fd
P_WHENCE(DATA);
#endif static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
#ifdef SEEK_HOLE struct syscall_arg *arg)
P_WHENCE(HOLE); {
#endif int fd = arg->val;
#undef P_WHENCE
default: break; if (fd == AT_FDCWD)
} return scnprintf(bf, size, "CWD");
return scnprintf(bf, size, "%#x", whence); return syscall_arg__scnprintf_fd(bf, size, arg);
} }
#define SCA_WHENCE syscall_arg__scnprintf_whence #define SCA_FDAT syscall_arg__scnprintf_fd_at
static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
struct syscall_arg *arg);
#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
struct syscall_arg *arg)
{
return scnprintf(bf, size, "%#lx", arg->val);
}
#define SCA_HEX syscall_arg__scnprintf_hex
static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
unsigned long arg, struct syscall_arg *arg)
u8 arg_idx __maybe_unused,
u8 *arg_mask __maybe_unused)
{ {
int printed = 0, prot = arg; int printed = 0, prot = arg->val;
if (prot == PROT_NONE) if (prot == PROT_NONE)
return scnprintf(bf, size, "NONE"); return scnprintf(bf, size, "NONE");
...@@ -104,10 +153,9 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, ...@@ -104,10 +153,9 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
unsigned long arg, u8 arg_idx __maybe_unused, struct syscall_arg *arg)
u8 *arg_mask __maybe_unused)
{ {
int printed = 0, flags = arg; int printed = 0, flags = arg->val;
#define P_MMAP_FLAG(n) \ #define P_MMAP_FLAG(n) \
if (flags & MAP_##n) { \ if (flags & MAP_##n) { \
...@@ -148,10 +196,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, ...@@ -148,10 +196,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
unsigned long arg, u8 arg_idx __maybe_unused, struct syscall_arg *arg)
u8 *arg_mask __maybe_unused)
{ {
int behavior = arg; int behavior = arg->val;
switch (behavior) { switch (behavior) {
#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
...@@ -190,8 +237,38 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, ...@@ -190,8 +237,38 @@ static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg, static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
u8 arg_idx __maybe_unused, u8 *arg_mask) struct syscall_arg *arg)
{
int printed = 0, op = arg->val;
if (op == 0)
return scnprintf(bf, size, "NONE");
#define P_CMD(cmd) \
if ((op & LOCK_##cmd) == LOCK_##cmd) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
op &= ~LOCK_##cmd; \
}
P_CMD(SH);
P_CMD(EX);
P_CMD(NB);
P_CMD(UN);
P_CMD(MAND);
P_CMD(RW);
P_CMD(READ);
P_CMD(WRITE);
#undef P_OP
if (op)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
return printed;
}
#define SCA_FLOCK syscall_arg__scnprintf_flock
static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
{ {
enum syscall_futex_args { enum syscall_futex_args {
SCF_UADDR = (1 << 0), SCF_UADDR = (1 << 0),
...@@ -201,24 +278,24 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo ...@@ -201,24 +278,24 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
SCF_UADDR2 = (1 << 4), SCF_UADDR2 = (1 << 4),
SCF_VAL3 = (1 << 5), SCF_VAL3 = (1 << 5),
}; };
int op = arg; int op = arg->val;
int cmd = op & FUTEX_CMD_MASK; int cmd = op & FUTEX_CMD_MASK;
size_t printed = 0; size_t printed = 0;
switch (cmd) { switch (cmd) {
#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break; P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break; P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break; P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
P_FUTEX_OP(WAKE_OP); break; P_FUTEX_OP(WAKE_OP); break;
P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break; P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break; P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break; P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
P_FUTEX_OP(WAIT_REQUEUE_PI); break; P_FUTEX_OP(WAIT_REQUEUE_PI); break;
default: printed = scnprintf(bf, size, "%#x", cmd); break; default: printed = scnprintf(bf, size, "%#x", cmd); break;
} }
...@@ -234,14 +311,194 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo ...@@ -234,14 +311,194 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned lo
#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
static DEFINE_STRARRAY(itimers);
static const char *whences[] = { "SET", "CUR", "END",
#ifdef SEEK_DATA
"DATA",
#endif
#ifdef SEEK_HOLE
"HOLE",
#endif
};
static DEFINE_STRARRAY(whences);
static const char *fcntl_cmds[] = {
"DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
"SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
"F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
"F_GETOWNER_UIDS",
};
static DEFINE_STRARRAY(fcntl_cmds);
static const char *rlimit_resources[] = {
"CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
"MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
"RTTIME",
};
static DEFINE_STRARRAY(rlimit_resources);
static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
static DEFINE_STRARRAY(sighow);
static const char *clockid[] = {
"REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
"MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
};
static DEFINE_STRARRAY(clockid);
static const char *socket_families[] = {
"UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
"BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
"SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
"RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
"BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
"ALG", "NFC", "VSOCK",
};
static DEFINE_STRARRAY(socket_families);
#ifndef SOCK_TYPE_MASK
#define SOCK_TYPE_MASK 0xf
#endif
static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
struct syscall_arg *arg)
{
size_t printed;
int type = arg->val,
flags = type & ~SOCK_TYPE_MASK;
type &= SOCK_TYPE_MASK;
/*
* Can't use a strarray, MIPS may override for ABI reasons.
*/
switch (type) {
#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
P_SK_TYPE(STREAM);
P_SK_TYPE(DGRAM);
P_SK_TYPE(RAW);
P_SK_TYPE(RDM);
P_SK_TYPE(SEQPACKET);
P_SK_TYPE(DCCP);
P_SK_TYPE(PACKET);
#undef P_SK_TYPE
default:
printed = scnprintf(bf, size, "%#x", type);
}
#define P_SK_FLAG(n) \
if (flags & SOCK_##n) { \
printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
flags &= ~SOCK_##n; \
}
P_SK_FLAG(CLOEXEC);
P_SK_FLAG(NONBLOCK);
#undef P_SK_FLAG
if (flags)
printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
return printed;
}
#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
#ifndef MSG_PROBE
#define MSG_PROBE 0x10
#endif
#ifndef MSG_WAITFORONE
#define MSG_WAITFORONE 0x10000
#endif
#ifndef MSG_SENDPAGE_NOTLAST
#define MSG_SENDPAGE_NOTLAST 0x20000
#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
struct syscall_arg *arg)
{
int printed = 0, flags = arg->val;
if (flags == 0)
return scnprintf(bf, size, "NONE");
#define P_MSG_FLAG(n) \
if (flags & MSG_##n) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
flags &= ~MSG_##n; \
}
P_MSG_FLAG(OOB);
P_MSG_FLAG(PEEK);
P_MSG_FLAG(DONTROUTE);
P_MSG_FLAG(TRYHARD);
P_MSG_FLAG(CTRUNC);
P_MSG_FLAG(PROBE);
P_MSG_FLAG(TRUNC);
P_MSG_FLAG(DONTWAIT);
P_MSG_FLAG(EOR);
P_MSG_FLAG(WAITALL);
P_MSG_FLAG(FIN);
P_MSG_FLAG(SYN);
P_MSG_FLAG(CONFIRM);
P_MSG_FLAG(RST);
P_MSG_FLAG(ERRQUEUE);
P_MSG_FLAG(NOSIGNAL);
P_MSG_FLAG(MORE);
P_MSG_FLAG(WAITFORONE);
P_MSG_FLAG(SENDPAGE_NOTLAST);
P_MSG_FLAG(FASTOPEN);
P_MSG_FLAG(CMSG_CLOEXEC);
#undef P_MSG_FLAG
if (flags)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
return printed;
}
#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
struct syscall_arg *arg)
{
size_t printed = 0;
int mode = arg->val;
if (mode == F_OK) /* 0 */
return scnprintf(bf, size, "F");
#define P_MODE(n) \
if (mode & n##_OK) { \
printed += scnprintf(bf + printed, size - printed, "%s", #n); \
mode &= ~n##_OK; \
}
P_MODE(R);
P_MODE(W);
P_MODE(X);
#undef P_MODE
if (mode)
printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
return printed;
}
#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
unsigned long arg, struct syscall_arg *arg)
u8 arg_idx, u8 *arg_mask)
{ {
int printed = 0, flags = arg; int printed = 0, flags = arg->val;
if (!(flags & O_CREAT)) if (!(flags & O_CREAT))
*arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */ arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
if (flags == 0) if (flags == 0)
return scnprintf(bf, size, "RDONLY"); return scnprintf(bf, size, "RDONLY");
...@@ -291,32 +548,225 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, ...@@ -291,32 +548,225 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
struct syscall_arg *arg)
{
int printed = 0, flags = arg->val;
if (flags == 0)
return scnprintf(bf, size, "NONE");
#define P_FLAG(n) \
if (flags & EFD_##n) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
flags &= ~EFD_##n; \
}
P_FLAG(SEMAPHORE);
P_FLAG(CLOEXEC);
P_FLAG(NONBLOCK);
#undef P_FLAG
if (flags)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
return printed;
}
#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
struct syscall_arg *arg)
{
int printed = 0, flags = arg->val;
#define P_FLAG(n) \
if (flags & O_##n) { \
printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
flags &= ~O_##n; \
}
P_FLAG(CLOEXEC);
P_FLAG(NONBLOCK);
#undef P_FLAG
if (flags)
printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
return printed;
}
#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
{
int sig = arg->val;
switch (sig) {
#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
P_SIGNUM(HUP);
P_SIGNUM(INT);
P_SIGNUM(QUIT);
P_SIGNUM(ILL);
P_SIGNUM(TRAP);
P_SIGNUM(ABRT);
P_SIGNUM(BUS);
P_SIGNUM(FPE);
P_SIGNUM(KILL);
P_SIGNUM(USR1);
P_SIGNUM(SEGV);
P_SIGNUM(USR2);
P_SIGNUM(PIPE);
P_SIGNUM(ALRM);
P_SIGNUM(TERM);
P_SIGNUM(STKFLT);
P_SIGNUM(CHLD);
P_SIGNUM(CONT);
P_SIGNUM(STOP);
P_SIGNUM(TSTP);
P_SIGNUM(TTIN);
P_SIGNUM(TTOU);
P_SIGNUM(URG);
P_SIGNUM(XCPU);
P_SIGNUM(XFSZ);
P_SIGNUM(VTALRM);
P_SIGNUM(PROF);
P_SIGNUM(WINCH);
P_SIGNUM(IO);
P_SIGNUM(PWR);
P_SIGNUM(SYS);
default: break;
}
return scnprintf(bf, size, "%#x", sig);
}
#define SCA_SIGNUM syscall_arg__scnprintf_signum
#define TCGETS 0x5401
static const char *tioctls[] = {
"TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
"TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
"TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
"TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
"TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
"TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
"TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
"TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
"TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
"TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
"TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
[0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
"TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
"TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
"TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
};
static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
#define STRARRAY(arg, name, array) \
.arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
.arg_parm = { [arg] = &strarray__##array, }
static struct syscall_fmt { static struct syscall_fmt {
const char *name; const char *name;
const char *alias; const char *alias;
size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask); size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
void *arg_parm[6];
bool errmsg; bool errmsg;
bool timeout; bool timeout;
bool hexret; bool hexret;
} syscall_fmts[] = { } syscall_fmts[] = {
{ .name = "access", .errmsg = true, }, { .name = "access", .errmsg = true,
.arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
{ .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
{ .name = "brk", .hexret = true, { .name = "brk", .hexret = true,
.arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
{ .name = "mmap", .hexret = true, }, { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
{ .name = "close", .errmsg = true,
.arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
{ .name = "connect", .errmsg = true, }, { .name = "connect", .errmsg = true, },
{ .name = "fstat", .errmsg = true, .alias = "newfstat", }, { .name = "dup", .errmsg = true,
{ .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "dup2", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "dup3", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
{ .name = "eventfd2", .errmsg = true,
.arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
{ .name = "faccessat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "fadvise64", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fallocate", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchdir", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchmod", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchmodat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "fchown", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fchownat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "fcntl", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */
[1] = SCA_STRARRAY, /* cmd */ },
.arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
{ .name = "fdatasync", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "flock", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */
[1] = SCA_FLOCK, /* cmd */ }, },
{ .name = "fsetxattr", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fstat", .errmsg = true, .alias = "newfstat",
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fstatat", .errmsg = true, .alias = "newfstatat",
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "fstatfs", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "fsync", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "ftruncate", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "futex", .errmsg = true, { .name = "futex", .errmsg = true,
.arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
{ .name = "futimesat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "getdents", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "getdents64", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
{ .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
{ .name = "ioctl", .errmsg = true, { .name = "ioctl", .errmsg = true,
.arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */
[1] = SCA_STRHEXARRAY, /* cmd */
[2] = SCA_HEX, /* arg */ },
.arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
{ .name = "kill", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "linkat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "lseek", .errmsg = true, { .name = "lseek", .errmsg = true,
.arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */
[2] = SCA_STRARRAY, /* whence */ },
.arg_parm = { [2] = &strarray__whences, /* whence */ }, },
{ .name = "lstat", .errmsg = true, .alias = "newlstat", }, { .name = "lstat", .errmsg = true, .alias = "newlstat", },
{ .name = "madvise", .errmsg = true, { .name = "madvise", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* start */ .arg_scnprintf = { [0] = SCA_HEX, /* start */
[2] = SCA_MADV_BHV, /* behavior */ }, }, [2] = SCA_MADV_BHV, /* behavior */ }, },
{ .name = "mkdirat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "mknodat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
{ .name = "mlock", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "mlockall", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "mmap", .hexret = true, { .name = "mmap", .hexret = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ .arg_scnprintf = { [0] = SCA_HEX, /* addr */
[2] = SCA_MMAP_PROT, /* prot */ [2] = SCA_MMAP_PROT, /* prot */
...@@ -327,24 +777,91 @@ static struct syscall_fmt { ...@@ -327,24 +777,91 @@ static struct syscall_fmt {
{ .name = "mremap", .hexret = true, { .name = "mremap", .hexret = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ .arg_scnprintf = { [0] = SCA_HEX, /* addr */
[4] = SCA_HEX, /* new_addr */ }, }, [4] = SCA_HEX, /* new_addr */ }, },
{ .name = "munlock", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "munmap", .errmsg = true, { .name = "munmap", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "name_to_handle_at", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "newfstatat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "open", .errmsg = true, { .name = "open", .errmsg = true,
.arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
{ .name = "open_by_handle_at", .errmsg = true, { .name = "open_by_handle_at", .errmsg = true,
.arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
[2] = SCA_OPEN_FLAGS, /* flags */ }, },
{ .name = "openat", .errmsg = true, { .name = "openat", .errmsg = true,
.arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, }, .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
[2] = SCA_OPEN_FLAGS, /* flags */ }, },
{ .name = "pipe2", .errmsg = true,
.arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
{ .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 = "pread", .errmsg = true, .alias = "pread64", }, { .name = "pread", .errmsg = true, .alias = "pread64",
{ .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "read", .errmsg = true, }, { .name = "preadv", .errmsg = true, .alias = "pread",
{ .name = "recvfrom", .errmsg = true, }, .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
{ .name = "pwrite", .errmsg = true, .alias = "pwrite64",
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "pwritev", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "read", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "readlinkat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "readv", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "recvfrom", .errmsg = true,
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "recvmmsg", .errmsg = true,
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "recvmsg", .errmsg = true,
.arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "renameat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "rt_sigaction", .errmsg = true,
.arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
{ .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
{ .name = "rt_sigqueueinfo", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "rt_tgsigqueueinfo", .errmsg = true,
.arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
{ .name = "select", .errmsg = true, .timeout = true, }, { .name = "select", .errmsg = true, .timeout = true, },
{ .name = "socket", .errmsg = true, }, { .name = "sendmmsg", .errmsg = true,
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "sendmsg", .errmsg = true,
.arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "sendto", .errmsg = true,
.arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
{ .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
{ .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
{ .name = "shutdown", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "socket", .errmsg = true,
.arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
[1] = SCA_SK_TYPE, /* type */ },
.arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
{ .name = "socketpair", .errmsg = true,
.arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
[1] = SCA_SK_TYPE, /* type */ },
.arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
{ .name = "stat", .errmsg = true, .alias = "newstat", }, { .name = "stat", .errmsg = true, .alias = "newstat", },
{ .name = "symlinkat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "tgkill", .errmsg = true,
.arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
{ .name = "tkill", .errmsg = true,
.arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
{ .name = "uname", .errmsg = true, .alias = "newuname", }, { .name = "uname", .errmsg = true, .alias = "newuname", },
{ .name = "unlinkat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
{ .name = "utimensat", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
{ .name = "write", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
{ .name = "writev", .errmsg = true,
.arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
}; };
static int syscall_fmt__cmp(const void *name, const void *fmtp) static int syscall_fmt__cmp(const void *name, const void *fmtp)
...@@ -364,8 +881,8 @@ struct syscall { ...@@ -364,8 +881,8 @@ struct syscall {
const char *name; const char *name;
bool filtered; bool filtered;
struct syscall_fmt *fmt; struct syscall_fmt *fmt;
size_t (**arg_scnprintf)(char *bf, size_t size, size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
unsigned long arg, u8 arg_idx, u8 *args_mask); void **arg_parm;
}; };
static size_t fprintf_duration(unsigned long t, FILE *fp) static size_t fprintf_duration(unsigned long t, FILE *fp)
...@@ -389,11 +906,24 @@ struct thread_trace { ...@@ -389,11 +906,24 @@ struct thread_trace {
unsigned long nr_events; unsigned long nr_events;
char *entry_str; char *entry_str;
double runtime_ms; double runtime_ms;
struct {
int max;
char **table;
} paths;
struct intlist *syscall_stats;
}; };
static struct thread_trace *thread_trace__new(void) static struct thread_trace *thread_trace__new(void)
{ {
return zalloc(sizeof(struct thread_trace)); struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
if (ttrace)
ttrace->paths.max = -1;
ttrace->syscall_stats = intlist__new(NULL);
return ttrace;
} }
static struct thread_trace *thread__trace(struct thread *thread, FILE *fp) static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
...@@ -427,20 +957,116 @@ struct trace { ...@@ -427,20 +957,116 @@ struct trace {
struct syscall *table; struct syscall *table;
} syscalls; } syscalls;
struct perf_record_opts opts; struct perf_record_opts opts;
struct machine host; struct machine *host;
u64 base_time; u64 base_time;
bool full_time;
FILE *output; FILE *output;
unsigned long nr_events; unsigned long nr_events;
struct strlist *ev_qualifier; struct strlist *ev_qualifier;
bool not_ev_qualifier; bool not_ev_qualifier;
bool live;
struct intlist *tid_list; struct intlist *tid_list;
struct intlist *pid_list; struct intlist *pid_list;
bool sched; bool sched;
bool multiple_threads; bool multiple_threads;
bool summary;
bool show_comm;
double duration_filter; double duration_filter;
double runtime_ms; double runtime_ms;
}; };
static int thread__read_fd_path(struct thread *thread, int fd)
{
struct thread_trace *ttrace = thread->priv;
char linkname[PATH_MAX], pathname[PATH_MAX];
struct stat st;
int ret;
if (thread->pid_ == thread->tid) {
scnprintf(linkname, sizeof(linkname),
"/proc/%d/fd/%d", thread->pid_, fd);
} else {
scnprintf(linkname, sizeof(linkname),
"/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
}
if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
return -1;
ret = readlink(linkname, pathname, sizeof(pathname));
if (ret < 0 || ret > st.st_size)
return -1;
pathname[ret] = '\0';
if (fd > ttrace->paths.max) {
char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
if (npath == NULL)
return -1;
if (ttrace->paths.max != -1) {
memset(npath + ttrace->paths.max + 1, 0,
(fd - ttrace->paths.max) * sizeof(char *));
} else {
memset(npath, 0, (fd + 1) * sizeof(char *));
}
ttrace->paths.table = npath;
ttrace->paths.max = fd;
}
ttrace->paths.table[fd] = strdup(pathname);
return ttrace->paths.table[fd] != NULL ? 0 : -1;
}
static const char *thread__fd_path(struct thread *thread, int fd, bool live)
{
struct thread_trace *ttrace = thread->priv;
if (ttrace == NULL)
return NULL;
if (fd < 0)
return NULL;
if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
(!live || thread__read_fd_path(thread, fd)))
return NULL;
return ttrace->paths.table[fd];
}
static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
struct syscall_arg *arg)
{
int fd = arg->val;
size_t printed = scnprintf(bf, size, "%d", fd);
const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
if (path)
printed += scnprintf(bf + printed, size - printed, "<%s>", path);
return printed;
}
static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
struct syscall_arg *arg)
{
int fd = arg->val;
size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
struct thread_trace *ttrace = arg->thread->priv;
if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
free(ttrace->paths.table[fd]);
ttrace->paths.table[fd] = NULL;
}
return printed;
}
static bool trace__filter_duration(struct trace *trace, double t) static bool trace__filter_duration(struct trace *trace, double t)
{ {
return t < (trace->duration_filter * NSEC_PER_MSEC); return t < (trace->duration_filter * NSEC_PER_MSEC);
...@@ -466,8 +1092,11 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre ...@@ -466,8 +1092,11 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
printed += fprintf_duration(duration, fp); printed += fprintf_duration(duration, fp);
if (trace->multiple_threads) if (trace->multiple_threads) {
if (trace->show_comm)
printed += fprintf(fp, "%.14s/", thread->comm);
printed += fprintf(fp, "%d ", thread->tid); printed += fprintf(fp, "%d ", thread->tid);
}
return printed; return printed;
} }
...@@ -506,16 +1135,17 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) ...@@ -506,16 +1135,17 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
if (err) if (err)
return err; return err;
machine__init(&trace->host, "", HOST_KERNEL_ID); trace->host = machine__new_host();
machine__create_kernel_maps(&trace->host); if (trace->host == NULL)
return -ENOMEM;
if (perf_target__has_task(&trace->opts.target)) { if (perf_target__has_task(&trace->opts.target)) {
err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads, err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
trace__tool_process, trace__tool_process,
&trace->host); trace->host);
} else { } else {
err = perf_event__synthesize_threads(&trace->tool, trace__tool_process, err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
&trace->host); trace->host);
} }
if (err) if (err)
...@@ -533,6 +1163,9 @@ static int syscall__set_arg_fmts(struct syscall *sc) ...@@ -533,6 +1163,9 @@ static int syscall__set_arg_fmts(struct syscall *sc)
if (sc->arg_scnprintf == NULL) if (sc->arg_scnprintf == NULL)
return -1; return -1;
if (sc->fmt)
sc->arg_parm = sc->fmt->arg_parm;
for (field = sc->tp_format->format.fields->next; field; field = field->next) { for (field = sc->tp_format->format.fields->next; field; field = field->next) {
if (sc->fmt && sc->fmt->arg_scnprintf[idx]) if (sc->fmt && sc->fmt->arg_scnprintf[idx])
sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
...@@ -603,32 +1236,52 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -603,32 +1236,52 @@ static int trace__read_syscall_info(struct trace *trace, int id)
} }
static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
unsigned long *args) unsigned long *args, struct trace *trace,
struct thread *thread)
{ {
int i = 0;
size_t printed = 0; size_t printed = 0;
if (sc->tp_format != NULL) { if (sc->tp_format != NULL) {
struct format_field *field; struct format_field *field;
u8 mask = 0, bit = 1; u8 bit = 1;
struct syscall_arg arg = {
.idx = 0,
.mask = 0,
.trace = trace,
.thread = thread,
};
for (field = sc->tp_format->format.fields->next; field; for (field = sc->tp_format->format.fields->next; field;
field = field->next, ++i, bit <<= 1) { field = field->next, ++arg.idx, bit <<= 1) {
if (mask & bit) if (arg.mask & bit)
continue;
/*
* Suppress this argument if its value is zero and
* and we don't have a string associated in an
* strarray for it.
*/
if (args[arg.idx] == 0 &&
!(sc->arg_scnprintf &&
sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
sc->arg_parm[arg.idx]))
continue; continue;
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
"%s%s: ", printed ? ", " : "", field->name); "%s%s: ", printed ? ", " : "", field->name);
if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
if (sc->arg_scnprintf && sc->arg_scnprintf[i]) { arg.val = args[arg.idx];
printed += sc->arg_scnprintf[i](bf + printed, size - printed, if (sc->arg_parm)
args[i], i, &mask); arg.parm = sc->arg_parm[arg.idx];
printed += sc->arg_scnprintf[arg.idx](bf + printed,
size - printed, &arg);
} else { } else {
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
"%ld", args[i]); "%ld", args[arg.idx]);
} }
} }
} else { } else {
int i = 0;
while (i < 6) { while (i < 6) {
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
"%sarg%d: %ld", "%sarg%d: %ld",
...@@ -644,10 +1297,8 @@ typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel, ...@@ -644,10 +1297,8 @@ typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
struct perf_sample *sample); struct perf_sample *sample);
static struct syscall *trace__syscall_info(struct trace *trace, static struct syscall *trace__syscall_info(struct trace *trace,
struct perf_evsel *evsel, struct perf_evsel *evsel, int id)
struct perf_sample *sample)
{ {
int id = perf_evsel__intval(evsel, sample, "id");
if (id < 0) { if (id < 0) {
...@@ -688,6 +1339,32 @@ static struct syscall *trace__syscall_info(struct trace *trace, ...@@ -688,6 +1339,32 @@ static struct syscall *trace__syscall_info(struct trace *trace,
return NULL; return NULL;
} }
static void thread__update_stats(struct thread_trace *ttrace,
int id, struct perf_sample *sample)
{
struct int_node *inode;
struct stats *stats;
u64 duration = 0;
inode = intlist__findnew(ttrace->syscall_stats, id);
if (inode == NULL)
return;
stats = inode->priv;
if (stats == NULL) {
stats = malloc(sizeof(struct stats));
if (stats == NULL)
return;
init_stats(stats);
inode->priv = stats;
}
if (ttrace->entry_time && sample->time > ttrace->entry_time)
duration = sample->time - ttrace->entry_time;
update_stats(stats, duration);
}
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)
{ {
...@@ -695,7 +1372,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -695,7 +1372,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
void *args; void *args;
size_t printed = 0; size_t printed = 0;
struct thread *thread; struct thread *thread;
struct syscall *sc = trace__syscall_info(trace, evsel, sample); int id = perf_evsel__intval(evsel, sample, "id");
struct syscall *sc = trace__syscall_info(trace, evsel, id);
struct thread_trace *ttrace; struct thread_trace *ttrace;
if (sc == NULL) if (sc == NULL)
...@@ -704,8 +1382,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -704,8 +1382,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
if (sc->filtered) if (sc->filtered)
return 0; return 0;
thread = machine__findnew_thread(&trace->host, sample->pid, thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
sample->tid);
ttrace = thread__trace(thread, trace->output); ttrace = thread__trace(thread, trace->output);
if (ttrace == NULL) if (ttrace == NULL)
return -1; return -1;
...@@ -728,7 +1405,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, ...@@ -728,7 +1405,8 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
msg = ttrace->entry_str; msg = ttrace->entry_str;
printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name); printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args); printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
args, trace, thread);
if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) { if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
if (!trace->duration_filter) { if (!trace->duration_filter) {
...@@ -747,7 +1425,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -747,7 +1425,8 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
int ret; int ret;
u64 duration = 0; u64 duration = 0;
struct thread *thread; struct thread *thread;
struct syscall *sc = trace__syscall_info(trace, evsel, sample); int id = perf_evsel__intval(evsel, sample, "id");
struct syscall *sc = trace__syscall_info(trace, evsel, id);
struct thread_trace *ttrace; struct thread_trace *ttrace;
if (sc == NULL) if (sc == NULL)
...@@ -756,12 +1435,14 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, ...@@ -756,12 +1435,14 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
if (sc->filtered) if (sc->filtered)
return 0; return 0;
thread = machine__findnew_thread(&trace->host, sample->pid, thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
sample->tid);
ttrace = thread__trace(thread, trace->output); ttrace = thread__trace(thread, trace->output);
if (ttrace == NULL) if (ttrace == NULL)
return -1; return -1;
if (trace->summary)
thread__update_stats(ttrace, id, sample);
ret = perf_evsel__intval(evsel, sample, "ret"); ret = perf_evsel__intval(evsel, sample, "ret");
ttrace = thread->priv; ttrace = thread->priv;
...@@ -813,7 +1494,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs ...@@ -813,7 +1494,7 @@ static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evs
{ {
u64 runtime = perf_evsel__intval(evsel, sample, "runtime"); u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
double runtime_ms = (double)runtime / NSEC_PER_MSEC; double runtime_ms = (double)runtime / NSEC_PER_MSEC;
struct thread *thread = machine__findnew_thread(&trace->host, struct thread *thread = machine__findnew_thread(trace->host,
sample->pid, sample->pid,
sample->tid); sample->tid);
struct thread_trace *ttrace = thread__trace(thread, trace->output); struct thread_trace *ttrace = thread__trace(thread, trace->output);
...@@ -861,7 +1542,7 @@ static int trace__process_sample(struct perf_tool *tool, ...@@ -861,7 +1542,7 @@ static int trace__process_sample(struct perf_tool *tool,
if (skip_sample(trace, sample)) if (skip_sample(trace, sample))
return 0; return 0;
if (trace->base_time == 0) if (!trace->full_time && trace->base_time == 0)
trace->base_time = sample->time; trace->base_time = sample->time;
if (handler) if (handler)
...@@ -901,6 +1582,35 @@ static int parse_target_str(struct trace *trace) ...@@ -901,6 +1582,35 @@ static int parse_target_str(struct trace *trace)
return 0; return 0;
} }
static int trace__record(int argc, const char **argv)
{
unsigned int rec_argc, i, j;
const char **rec_argv;
const char * const record_args[] = {
"record",
"-R",
"-m", "1024",
"-c", "1",
"-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
};
rec_argc = ARRAY_SIZE(record_args) + argc;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (rec_argv == NULL)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(record_args); i++)
rec_argv[i] = record_args[i];
for (j = 0; j < (unsigned int)argc; j++, i++)
rec_argv[i] = argv[j];
return cmd_record(i, rec_argv, NULL);
}
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
static int trace__run(struct trace *trace, int argc, const char **argv) static int trace__run(struct trace *trace, int argc, const char **argv)
{ {
struct perf_evlist *evlist = perf_evlist__new(); struct perf_evlist *evlist = perf_evlist__new();
...@@ -909,23 +1619,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -909,23 +1619,21 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
unsigned long before; unsigned long before;
const bool forks = argc > 0; const bool forks = argc > 0;
trace->live = true;
if (evlist == NULL) { if (evlist == NULL) {
fprintf(trace->output, "Not enough memory to run!\n"); fprintf(trace->output, "Not enough memory to run!\n");
goto out; goto out;
} }
if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) { perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n"); goto out_error_tp;
goto out_delete_evlist;
}
if (trace->sched && if (trace->sched &&
perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
trace__sched_stat_runtime)) { trace__sched_stat_runtime))
fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n"); goto out_error_tp;
goto out_delete_evlist;
}
err = perf_evlist__create_maps(evlist, &trace->opts.target); err = perf_evlist__create_maps(evlist, &trace->opts.target);
if (err < 0) { if (err < 0) {
...@@ -990,11 +1698,11 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -990,11 +1698,11 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
continue; continue;
} }
if (trace->base_time == 0) if (!trace->full_time && trace->base_time == 0)
trace->base_time = sample.time; trace->base_time = sample.time;
if (type != PERF_RECORD_SAMPLE) { if (type != PERF_RECORD_SAMPLE) {
trace__process_event(trace, &trace->host, event); trace__process_event(trace, trace->host, event);
continue; continue;
} }
...@@ -1032,6 +1740,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -1032,6 +1740,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
goto again; goto again;
out_unmap_evlist: out_unmap_evlist:
if (!err && trace->summary)
trace__fprintf_thread_summary(trace, trace->output);
perf_evlist__munmap(evlist); perf_evlist__munmap(evlist);
out_close_evlist: out_close_evlist:
perf_evlist__close(evlist); perf_evlist__close(evlist);
...@@ -1040,7 +1751,31 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -1040,7 +1751,31 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
out_delete_evlist: out_delete_evlist:
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
out: out:
trace->live = false;
return err; return err;
out_error_tp:
switch(errno) {
case ENOENT:
fputs("Error:\tUnable to find debugfs\n"
"Hint:\tWas your kernel was compiled with debugfs support?\n"
"Hint:\tIs the debugfs filesystem mounted?\n"
"Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'\n",
trace->output);
break;
case EACCES:
fprintf(trace->output,
"Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
"Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
debugfs_mountpoint, debugfs_mountpoint);
break;
default: {
char bf[256];
fprintf(trace->output, "Can't trace: %s\n",
strerror_r(errno, bf, sizeof(bf)));
}
break;
}
goto out_delete_evlist;
} }
static int trace__replay(struct trace *trace) static int trace__replay(struct trace *trace)
...@@ -1077,6 +1812,8 @@ static int trace__replay(struct trace *trace) ...@@ -1077,6 +1812,8 @@ static int trace__replay(struct trace *trace)
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
trace->host = &session->machines.host;
err = perf_session__set_tracepoints_handlers(session, handlers); err = perf_session__set_tracepoints_handlers(session, handlers);
if (err) if (err)
goto out; goto out;
...@@ -1101,6 +1838,9 @@ static int trace__replay(struct trace *trace) ...@@ -1101,6 +1838,9 @@ static int trace__replay(struct trace *trace)
if (err) if (err)
pr_err("Failed to process events, error %d", err); pr_err("Failed to process events, error %d", err);
else if (trace->summary)
trace__fprintf_thread_summary(trace, trace->output);
out: out:
perf_session__delete(session); perf_session__delete(session);
...@@ -1111,47 +1851,111 @@ static size_t trace__fprintf_threads_header(FILE *fp) ...@@ -1111,47 +1851,111 @@ static size_t trace__fprintf_threads_header(FILE *fp)
{ {
size_t printed; size_t printed;
printed = fprintf(fp, "\n _____________________________________________________________________\n"); printed = fprintf(fp, "\n _____________________________________________________________________________\n");
printed += fprintf(fp," __) Summary of events (__\n\n"); printed += fprintf(fp, " __) Summary of events (__\n\n");
printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n"); printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
printed += fprintf(fp," _____________________________________________________________________\n\n"); printed += fprintf(fp, " syscall count min max avg stddev\n");
printed += fprintf(fp, " msec msec msec %%\n");
printed += fprintf(fp, " _____________________________________________________________________________\n\n");
return printed; return printed;
} }
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) static size_t thread__dump_stats(struct thread_trace *ttrace,
struct trace *trace, FILE *fp)
{ {
size_t printed = trace__fprintf_threads_header(fp); struct stats *stats;
struct rb_node *nd; size_t printed = 0;
struct syscall *sc;
for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) { struct int_node *inode = intlist__first(ttrace->syscall_stats);
struct thread *thread = rb_entry(nd, struct thread, rb_node);
struct thread_trace *ttrace = thread->priv; if (inode == NULL)
const char *color; return 0;
double ratio;
printed += fprintf(fp, "\n");
if (ttrace == NULL)
continue; /* each int_node is a syscall */
while (inode) {
ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; stats = inode->priv;
if (stats) {
color = PERF_COLOR_NORMAL; double min = (double)(stats->min) / NSEC_PER_MSEC;
if (ratio > 50.0) double max = (double)(stats->max) / NSEC_PER_MSEC;
color = PERF_COLOR_RED; double avg = avg_stats(stats);
else if (ratio > 25.0) double pct;
color = PERF_COLOR_GREEN; u64 n = (u64) stats->n;
else if (ratio > 5.0)
color = PERF_COLOR_YELLOW; pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
avg /= NSEC_PER_MSEC;
printed += color_fprintf(fp, color, "%20s", thread->comm);
printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); sc = &trace->syscalls.table[inode->i];
printed += color_fprintf(fp, color, "%5.1f%%", ratio); printed += fprintf(fp, "%24s %14s : ", "", sc->name);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
n, min, max);
printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
}
inode = intlist__next(inode);
} }
printed += fprintf(fp, "\n\n");
return printed; return printed;
} }
/* struct used to pass data to per-thread function */
struct summary_data {
FILE *fp;
struct trace *trace;
size_t printed;
};
static int trace__fprintf_one_thread(struct thread *thread, void *priv)
{
struct summary_data *data = priv;
FILE *fp = data->fp;
size_t printed = data->printed;
struct trace *trace = data->trace;
struct thread_trace *ttrace = thread->priv;
const char *color;
double ratio;
if (ttrace == NULL)
return 0;
ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
color = PERF_COLOR_NORMAL;
if (ratio > 50.0)
color = PERF_COLOR_RED;
else if (ratio > 25.0)
color = PERF_COLOR_GREEN;
else if (ratio > 5.0)
color = PERF_COLOR_YELLOW;
printed += color_fprintf(fp, color, "%20s", thread->comm);
printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
printed += color_fprintf(fp, color, "%5.1f%%", ratio);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
printed += thread__dump_stats(ttrace, trace, fp);
data->printed += printed;
return 0;
}
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
{
struct summary_data data = {
.fp = fp,
.trace = trace
};
data.printed = trace__fprintf_threads_header(fp);
machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
return data.printed;
}
static int trace__set_duration(const struct option *opt, const char *str, static int trace__set_duration(const struct option *opt, const char *str,
int unset __maybe_unused) int unset __maybe_unused)
{ {
...@@ -1183,6 +1987,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1183,6 +1987,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
const char * const trace_usage[] = { const char * const trace_usage[] = {
"perf trace [<options>] [<command>]", "perf trace [<options>] [<command>]",
"perf trace [<options>] -- <command> [<options>]", "perf trace [<options>] -- <command> [<options>]",
"perf trace record [<options>] [<command>]",
"perf trace record [<options>] -- <command> [<options>]",
NULL NULL
}; };
struct trace trace = { struct trace trace = {
...@@ -1201,10 +2007,13 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1201,10 +2007,13 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
.mmap_pages = 1024, .mmap_pages = 1024,
}, },
.output = stdout, .output = stdout,
.show_comm = true,
}; };
const char *output_name = NULL; const char *output_name = NULL;
const char *ev_qualifier_str = NULL; const char *ev_qualifier_str = NULL;
const struct option trace_options[] = { const struct option trace_options[] = {
OPT_BOOLEAN(0, "comm", &trace.show_comm,
"show the thread COMM next to its id"),
OPT_STRING('e', "expr", &ev_qualifier_str, "expr", OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
"list of events to trace"), "list of events to trace"),
OPT_STRING('o', "output", &output_name, "file", "output file name"), OPT_STRING('o', "output", &output_name, "file", "output file name"),
...@@ -1219,8 +2028,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1219,8 +2028,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
"list of cpus to monitor"), "list of cpus to monitor"),
OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
"child tasks do not inherit counters"), "child tasks do not inherit counters"),
OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages, OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
"number of mmap data pages"), "number of mmap data pages",
perf_evlist__parse_mmap_pages),
OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user", OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
"user to profile"), "user to profile"),
OPT_CALLBACK(0, "duration", &trace, "float", OPT_CALLBACK(0, "duration", &trace, "float",
...@@ -1228,11 +2038,18 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1228,11 +2038,18 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
trace__set_duration), trace__set_duration),
OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"), OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
OPT_INCR('v', "verbose", &verbose, "be more verbose"), OPT_INCR('v', "verbose", &verbose, "be more verbose"),
OPT_BOOLEAN('T', "time", &trace.full_time,
"Show full timestamp, not time relative to first start"),
OPT_BOOLEAN(0, "summary", &trace.summary,
"Show syscall summary with statistics"),
OPT_END() OPT_END()
}; };
int err; int err;
char bf[BUFSIZ]; char bf[BUFSIZ];
if ((argc > 1) && (strcmp(argv[1], "record") == 0))
return trace__record(argc-2, &argv[2]);
argc = parse_options(argc, argv, trace_options, trace_usage, 0); argc = parse_options(argc, argv, trace_options, trace_usage, 0);
if (output_name != NULL) { if (output_name != NULL) {
...@@ -1280,9 +2097,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1280,9 +2097,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
else else
err = trace__run(&trace, argc, argv); err = trace__run(&trace, argc, argv);
if (trace.sched && !err)
trace__fprintf_thread_summary(&trace, trace.output);
out_close: out_close:
if (output_name != NULL) if (output_name != NULL)
fclose(trace.output); fclose(trace.output);
......
...@@ -23,7 +23,7 @@ ifeq ($(ARCH),x86_64) ...@@ -23,7 +23,7 @@ ifeq ($(ARCH),x86_64)
endif endif
ifeq (${IS_X86_64}, 1) ifeq (${IS_X86_64}, 1)
RAW_ARCH := x86_64 RAW_ARCH := x86_64
CFLAGS += -DARCH_X86_64 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
endif endif
NO_PERF_REGS := 0 NO_PERF_REGS := 0
...@@ -31,7 +31,7 @@ ifeq ($(ARCH),x86_64) ...@@ -31,7 +31,7 @@ ifeq ($(ARCH),x86_64)
endif endif
ifeq ($(NO_PERF_REGS),0) ifeq ($(NO_PERF_REGS),0)
CFLAGS += -DHAVE_PERF_REGS CFLAGS += -DHAVE_PERF_REGS_SUPPORT
endif endif
ifeq ($(src-perf),) ifeq ($(src-perf),)
...@@ -51,7 +51,6 @@ LIB_INCLUDE := $(srctree)/tools/lib/ ...@@ -51,7 +51,6 @@ LIB_INCLUDE := $(srctree)/tools/lib/
# include ARCH specific config # include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile -include $(src-perf)/arch/$(ARCH)/Makefile
include $(src-perf)/config/feature-tests.mak
include $(src-perf)/config/utilities.mak include $(src-perf)/config/utilities.mak
ifeq ($(call get-executable,$(FLEX)),) ifeq ($(call get-executable,$(FLEX)),)
...@@ -67,10 +66,7 @@ ifneq ($(WERROR),0) ...@@ -67,10 +66,7 @@ ifneq ($(WERROR),0)
CFLAGS += -Werror CFLAGS += -Werror
endif endif
ifeq ("$(origin DEBUG)", "command line") ifeq ($(DEBUG),0)
PERF_DEBUG = $(DEBUG)
endif
ifndef PERF_DEBUG
CFLAGS += -O6 CFLAGS += -O6
endif endif
...@@ -89,20 +85,125 @@ CFLAGS += -std=gnu99 ...@@ -89,20 +85,125 @@ CFLAGS += -std=gnu99
EXTLIBS = -lelf -lpthread -lrt -lm -ldl EXTLIBS = -lelf -lpthread -lrt -lm -ldl
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) ifneq ($(OUTPUT),)
CFLAGS += -fstack-protector-all OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/
$(shell mkdir -p $(OUTPUT_FEATURES))
endif endif
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y) feature_check = $(eval $(feature_check_code))
CFLAGS += -Wstack-protector define feature_check_code
feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0)
endef
feature_set = $(eval $(feature_set_code))
define feature_set_code
feature-$(1) := 1
endef
#
# Build the feature check binaries in parallel, ignore errors, ignore return value and suppress output:
#
#
# Note that this is not a complete list of all feature tests, just
# those that are typically built on a fully configured system.
#
# [ Feature tests not mentioned here have to be built explicitly in
# the rule that uses them - an example for that is the 'bionic'
# feature check. ]
#
CORE_FEATURE_TESTS = \
backtrace \
dwarf \
fortify-source \
glibc \
gtk2 \
gtk2-infobar \
libaudit \
libbfd \
libelf \
libelf-getphdrnum \
libelf-mmap \
libnuma \
libperl \
libpython \
libpython-version \
libslang \
libunwind \
on-exit \
stackprotector \
stackprotector-all
#
# So here we detect whether test-all was rebuilt, to be able
# to skip the print-out of the long features list if the file
# existed before and after it was built:
#
ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),)
test-all-failed := 1
else
test-all-failed := 0
endif
#
# Special fast-path for the 'all features are available' case:
#
$(call feature_check,all,$(MSG))
#
# Just in case the build freshly failed, make sure we print the
# feature matrix:
#
ifeq ($(feature-all), 0)
test-all-failed := 1
endif endif
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y) ifeq ($(test-all-failed),1)
CFLAGS += -Wvolatile-register-var $(info )
$(info Auto-detecting system features:)
endif endif
ifndef PERF_DEBUG ifeq ($(feature-all), 1)
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -D_FORTIFY_SOURCE=2,-D_FORTIFY_SOURCE=2),y) #
# test-all.c passed - just set all the core feature flags to 1:
#
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
else
$(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1)
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
endif
#
# Print the result of the feature test:
#
feature_print = $(eval $(feature_print_code)) $(info $(MSG))
define feature_print_code
ifeq ($(feature-$(1)), 1)
MSG = $(shell printf '...%30s: [ \033[32mon\033[m ]' $(1))
else
MSG = $(shell printf '...%30s: [ \033[31mOFF\033[m ]' $(1))
endif
endef
#
# Only print out our features if we rebuilt the testcases or if a test failed:
#
ifeq ($(test-all-failed), 1)
$(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_print,$(feat)))
$(info )
endif
ifeq ($(feature-stackprotector-all), 1)
CFLAGS += -fstack-protector-all
endif
ifeq ($(feature-stackprotector), 1)
CFLAGS += -Wstack-protector
endif
ifeq ($(DEBUG),0)
ifeq ($(feature-fortify-source), 1)
CFLAGS += -D_FORTIFY_SOURCE=2 CFLAGS += -D_FORTIFY_SOURCE=2
endif endif
endif endif
...@@ -128,84 +229,74 @@ CFLAGS += -I$(LIB_INCLUDE) ...@@ -128,84 +229,74 @@ CFLAGS += -I$(LIB_INCLUDE)
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
ifndef NO_BIONIC ifndef NO_BIONIC
ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y) $(feature_check,bionic)
BIONIC := 1 ifeq ($(feature-bionic), 1)
EXTLIBS := $(filter-out -lrt,$(EXTLIBS)) BIONIC := 1
EXTLIBS := $(filter-out -lpthread,$(EXTLIBS)) EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
endif
endif endif
endif # NO_BIONIC
ifdef NO_LIBELF ifdef NO_LIBELF
NO_DWARF := 1 NO_DWARF := 1
NO_DEMANGLE := 1 NO_DEMANGLE := 1
NO_LIBUNWIND := 1 NO_LIBUNWIND := 1
else else
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) ifeq ($(feature-libelf), 0)
ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y) ifeq ($(feature-glibc), 1)
FLAGS_GLIBC=$(CFLAGS) $(LDFLAGS) LIBC_SUPPORT := 1
ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y) endif
LIBC_SUPPORT := 1 ifeq ($(BIONIC),1)
endif LIBC_SUPPORT := 1
ifeq ($(BIONIC),1) endif
LIBC_SUPPORT := 1 ifeq ($(LIBC_SUPPORT),1)
endif msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
ifeq ($(LIBC_SUPPORT),1)
msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
NO_LIBELF := 1 NO_LIBELF := 1
NO_DWARF := 1 NO_DWARF := 1
NO_DEMANGLE := 1 NO_DEMANGLE := 1
else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
endif
else else
msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); # for linking with debug library, run like:
endif # make DEBUG=1 LIBDW_DIR=/opt/libdw/
else ifdef LIBDW_DIR
# for linking with debug library, run like: LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
# make DEBUG=1 LIBDW_DIR=/opt/libdw/ LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
ifdef LIBDW_DIR endif
LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
endif
FLAGS_DWARF=$(CFLAGS) $(LIBDW_CFLAGS) -ldw -lz -lelf $(LIBDW_LDFLAGS) $(LDFLAGS) $(EXTLIBS) ifneq ($(feature-dwarf), 1)
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 endif # libelf support
endif # SOURCE_LIBELF
endif # NO_LIBELF endif # NO_LIBELF
ifndef NO_LIBELF ifndef NO_LIBELF
CFLAGS += -DLIBELF_SUPPORT CFLAGS += -DHAVE_LIBELF_SUPPORT
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS)
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
CFLAGS += -DLIBELF_MMAP
endif
ifeq ($(call try-cc,$(SOURCE_ELF_GETPHDRNUM),$(FLAGS_LIBELF),-DHAVE_ELF_GETPHDRNUM),y)
CFLAGS += -DHAVE_ELF_GETPHDRNUM
endif
# include ARCH specific config ifeq ($(feature-libelf-mmap), 1)
-include $(src-perf)/arch/$(ARCH)/Makefile CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
endif
ifndef NO_DWARF ifeq ($(feature-libelf-getphdrnum), 1)
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); endif
NO_DWARF := 1
else
CFLAGS += -DDWARF_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
EXTLIBS += -lelf -ldw
endif # PERF_HAVE_DWARF_REGS
endif # NO_DWARF
endif # NO_LIBELF # include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
ifndef NO_LIBELF ifndef NO_DWARF
CFLAGS += -DLIBELF_SUPPORT ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
FLAGS_LIBELF=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y) NO_DWARF := 1
CFLAGS += -DLIBELF_MMAP else
endif # try-cc CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
EXTLIBS += -lelf -ldw
endif # PERF_HAVE_DWARF_REGS
endif # NO_DWARF
endif # NO_LIBELF endif # NO_LIBELF
# There's only x86 (both 32 and 64) support for CFI unwind so far # There's only x86 (both 32 and 64) support for CFI unwind so far
...@@ -214,34 +305,35 @@ ifneq ($(ARCH),x86) ...@@ -214,34 +305,35 @@ ifneq ($(ARCH),x86)
endif endif
ifndef NO_LIBUNWIND ifndef NO_LIBUNWIND
# for linking with debug library, run like: #
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ # For linking with debug library, run like:
ifdef LIBUNWIND_DIR #
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib #
endif ifdef LIBUNWIND_DIR
LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
endif
FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(CFLAGS) $(LIBUNWIND_LDFLAGS) $(LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) ifneq ($(feature-libunwind), 1)
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
endif # Libunwind support endif
endif # NO_LIBUNWIND
ifndef NO_LIBUNWIND ifndef NO_LIBUNWIND
CFLAGS += -DLIBUNWIND_SUPPORT CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
EXTLIBS += $(LIBUNWIND_LIBS) EXTLIBS += $(LIBUNWIND_LIBS)
CFLAGS += $(LIBUNWIND_CFLAGS) CFLAGS += $(LIBUNWIND_CFLAGS)
LDFLAGS += $(LIBUNWIND_LDFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS)
endif # NO_LIBUNWIND endif
ifndef NO_LIBAUDIT ifndef NO_LIBAUDIT
FLAGS_LIBAUDIT = $(CFLAGS) $(LDFLAGS) -laudit ifneq ($(feature-libaudit), 1)
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);
NO_LIBAUDIT := 1 NO_LIBAUDIT := 1
else else
CFLAGS += -DLIBAUDIT_SUPPORT CFLAGS += -DHAVE_LIBAUDIT_SUPPORT
EXTLIBS += -laudit EXTLIBS += -laudit
endif endif
endif endif
...@@ -251,30 +343,30 @@ ifdef NO_NEWT ...@@ -251,30 +343,30 @@ ifdef NO_NEWT
endif endif
ifndef NO_SLANG ifndef NO_SLANG
FLAGS_SLANG=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang ifneq ($(feature-libslang), 1)
ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev); msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
NO_SLANG := 1 NO_SLANG := 1
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
CFLAGS += -I/usr/include/slang CFLAGS += -I/usr/include/slang
CFLAGS += -DSLANG_SUPPORT CFLAGS += -DHAVE_SLANG_SUPPORT
EXTLIBS += -lslang EXTLIBS += -lslang
endif endif
endif endif
ifndef NO_GTK2 ifndef NO_GTK2
FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y) ifneq ($(feature-gtk2), 1)
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);
NO_GTK2 := 1 NO_GTK2 := 1
else else
ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y) ifeq ($(feature-gtk2-infobar), 1)
CFLAGS += -DHAVE_GTK_INFO_BAR GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
endif endif
CFLAGS += -DGTK2_SUPPORT CFLAGS += -DHAVE_GTK2_SUPPORT
CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
EXTLIBS += -ldl
endif endif
endif endif
...@@ -290,7 +382,7 @@ else ...@@ -290,7 +382,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),perl),y) ifneq ($(feature-libperl), 1)
CFLAGS += -DNO_LIBPERL CFLAGS += -DNO_LIBPERL
NO_LIBPERL := 1 NO_LIBPERL := 1
else else
...@@ -335,11 +427,11 @@ else ...@@ -335,11 +427,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),python),y) ifneq ($(feature-libpython), 1)
$(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),python version),y) ifneq ($(feature-libpython-version), 1)
$(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)
...@@ -362,33 +454,30 @@ else ...@@ -362,33 +454,30 @@ else
endif endif
endif endif
ifeq ($(feature-libbfd), 1)
EXTLIBS += -lbfd
endif
ifdef NO_DEMANGLE ifdef NO_DEMANGLE
CFLAGS += -DNO_DEMANGLE CFLAGS += -DNO_DEMANGLE
else else
ifdef HAVE_CPLUS_DEMANGLE ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
EXTLIBS += -liberty EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
else else
FLAGS_BFD=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd ifneq ($(feature-libbfd), 1)
has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd) $(feature_check,liberty)
ifeq ($(has_bfd),y) ifeq ($(feature-liberty), 1)
EXTLIBS += -lbfd
else
FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
ifeq ($(has_bfd_iberty),y)
EXTLIBS += -lbfd -liberty EXTLIBS += -lbfd -liberty
else else
FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz $(feature_check,liberty-z)
has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz) ifeq ($(feature-liberty-z), 1)
ifeq ($(has_bfd_iberty_z),y)
EXTLIBS += -lbfd -liberty -lz EXTLIBS += -lbfd -liberty -lz
else else
FLAGS_CPLUS_DEMANGLE=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) -liberty $(feature_check,cplus-demangle)
has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle) ifeq ($(feature-cplus-demangle), 1)
ifeq ($(has_cplus_demangle),y)
EXTLIBS += -liberty EXTLIBS += -liberty
CFLAGS += -DHAVE_CPLUS_DEMANGLE CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
else else
msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
CFLAGS += -DNO_DEMANGLE CFLAGS += -DNO_DEMANGLE
...@@ -399,31 +488,28 @@ else ...@@ -399,31 +488,28 @@ else
endif endif
endif endif
ifndef NO_STRLCPY ifneq ($(filter -lbfd,$(EXTLIBS)),)
ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y) CFLAGS += -DHAVE_LIBBFD_SUPPORT
CFLAGS += -DHAVE_STRLCPY
endif
endif endif
ifndef NO_ON_EXIT ifndef NO_ON_EXIT
ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y) ifeq ($(feature-on-exit), 1)
CFLAGS += -DHAVE_ON_EXIT CFLAGS += -DHAVE_ON_EXIT_SUPPORT
endif endif
endif endif
ifndef NO_BACKTRACE ifndef NO_BACKTRACE
ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y) ifeq ($(feature-backtrace), 1)
CFLAGS += -DBACKTRACE_SUPPORT CFLAGS += -DHAVE_BACKTRACE_SUPPORT
endif endif
endif endif
ifndef NO_LIBNUMA ifndef NO_LIBNUMA
FLAGS_LIBNUMA = $(CFLAGS) $(LDFLAGS) -lnuma ifeq ($(feature-libnuma), 0)
ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
NO_LIBNUMA := 1 NO_LIBNUMA := 1
else else
CFLAGS += -DLIBNUMA_SUPPORT CFLAGS += -DHAVE_LIBNUMA_SUPPORT
EXTLIBS += -lnuma EXTLIBS += -lnuma
endif endif
endif endif
...@@ -459,7 +545,12 @@ else ...@@ -459,7 +545,12 @@ else
sysconfdir = $(prefix)/etc sysconfdir = $(prefix)/etc
ETC_PERFCONFIG = etc/perfconfig ETC_PERFCONFIG = etc/perfconfig
endif endif
ifeq ($(IS_X86_64),1)
lib = lib64
else
lib = lib lib = lib
endif
libdir = $(prefix)/$(lib)
# Shell quote (do not use $(call) to accommodate ancient setups); # Shell quote (do not use $(call) to accommodate ancient setups);
ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
...@@ -472,6 +563,7 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) ...@@ -472,6 +563,7 @@ template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_SQ = $(subst ','\'',$(htmldir)) htmldir_SQ = $(subst ','\'',$(htmldir))
prefix_SQ = $(subst ','\'',$(prefix)) prefix_SQ = $(subst ','\'',$(prefix))
sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
libdir_SQ = $(subst ','\'',$(libdir))
ifneq ($(filter /%,$(firstword $(perfexecdir))),) ifneq ($(filter /%,$(firstword $(perfexecdir))),)
perfexec_instdir = $(perfexecdir) perfexec_instdir = $(perfexecdir)
......
FILES= \
test-all \
test-backtrace \
test-bionic \
test-dwarf \
test-fortify-source \
test-glibc \
test-gtk2 \
test-gtk2-infobar \
test-hello \
test-libaudit \
test-libbfd \
test-liberty \
test-liberty-z \
test-cplus-demangle \
test-libelf \
test-libelf-getphdrnum \
test-libelf-mmap \
test-libnuma \
test-libperl \
test-libpython \
test-libpython-version \
test-libslang \
test-libunwind \
test-on-exit \
test-stackprotector-all \
test-stackprotector
CC := $(CC) -MD
all: $(FILES)
BUILD = $(CC) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
###############################
test-all:
$(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lunwind -lunwind-x86_64 -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
test-hello:
$(BUILD)
test-stackprotector-all:
$(BUILD) -Werror -fstack-protector-all
test-stackprotector:
$(BUILD) -Werror -fstack-protector -Wstack-protector
test-fortify-source:
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
test-bionic:
$(BUILD)
test-libelf:
$(BUILD) -lelf
test-glibc:
$(BUILD)
test-dwarf:
$(BUILD) -ldw
test-libelf-mmap:
$(BUILD) -lelf
test-libelf-getphdrnum:
$(BUILD) -lelf
test-libnuma:
$(BUILD) -lnuma
test-libunwind:
$(BUILD) -lunwind -lunwind-x86_64 -lelf
test-libaudit:
$(BUILD) -laudit
test-libslang:
$(BUILD) -I/usr/include/slang -lslang
test-gtk2:
$(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
test-gtk2-infobar:
$(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
test-libperl:
$(BUILD) $(FLAGS_PERL_EMBED)
override PYTHON := python
override PYTHON_CONFIG := python-config
escape-for-shell-sq = $(subst ','\'',$(1))
shell-sq = '$(escape-for-shell-sq)'
PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
test-libpython:
$(BUILD) $(FLAGS_PYTHON_EMBED)
test-libpython-version:
$(BUILD) $(FLAGS_PYTHON_EMBED)
test-libbfd:
$(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
test-liberty:
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
test-liberty-z:
$(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
test-cplus-demangle:
$(BUILD) -liberty
test-on-exit:
$(BUILD)
test-backtrace:
$(BUILD)
-include *.d
###############################
clean:
rm -f $(FILES) *.d
/*
* test-all.c: Try to build all the main testcases at once.
*
* A well-configured system will have all the prereqs installed, so we can speed
* up auto-detection on such systems.
*/
/*
* Quirk: Python and Perl headers cannot be in arbitrary places, so keep
* these 3 testcases at the top:
*/
#define main main_test_libpython
# include "test-libpython.c"
#undef main
#define main main_test_libpython_version
# include "test-libpython-version.c"
#undef main
#define main main_test_libperl
# include "test-libperl.c"
#undef main
#define main main_test_hello
# include "test-hello.c"
#undef main
#define main main_test_libelf
# include "test-libelf.c"
#undef main
#define main main_test_libelf_mmap
# include "test-libelf-mmap.c"
#undef main
#define main main_test_glibc
# include "test-glibc.c"
#undef main
#define main main_test_dwarf
# include "test-dwarf.c"
#undef main
#define main main_test_libelf_getphdrnum
# include "test-libelf-getphdrnum.c"
#undef main
#define main main_test_libunwind
# include "test-libunwind.c"
#undef main
#define main main_test_libaudit
# include "test-libaudit.c"
#undef main
#define main main_test_libslang
# include "test-libslang.c"
#undef main
#define main main_test_gtk2
# include "test-gtk2.c"
#undef main
#define main main_test_gtk2_infobar
# include "test-gtk2-infobar.c"
#undef main
#define main main_test_libbfd
# include "test-libbfd.c"
#undef main
#define main main_test_on_exit
# include "test-on-exit.c"
#undef main
#define main main_test_backtrace
# include "test-backtrace.c"
#undef main
#define main main_test_libnuma
# include "test-libnuma.c"
#undef main
int main(int argc, char *argv[])
{
main_test_libpython();
main_test_libpython_version();
main_test_libperl();
main_test_hello();
main_test_libelf();
main_test_libelf_mmap();
main_test_glibc();
main_test_dwarf();
main_test_libelf_getphdrnum();
main_test_libunwind();
main_test_libaudit();
main_test_libslang();
main_test_gtk2(argc, argv);
main_test_gtk2_infobar(argc, argv);
main_test_libbfd();
main_test_on_exit();
main_test_backtrace();
main_test_libnuma();
return 0;
}
#include <execinfo.h>
#include <stdio.h>
int main(void)
{
void *backtrace_fns[10];
size_t entries;
entries = backtrace(backtrace_fns, 10);
backtrace_symbols_fd(backtrace_fns, entries, 1);
return 0;
}
#include <android/api-level.h>
int main(void)
{
return __ANDROID_API__;
}
extern int printf(const char *format, ...);
extern char *cplus_demangle(const char *, int);
int main(void)
{
char symbol[4096] = "FieldName__9ClassNameFd";
char *tmp;
tmp = cplus_demangle(symbol, 0);
printf("demangled symbol: {%s}\n", tmp);
return 0;
}
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/version.h>
int main(void)
{
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
return (long)dbg;
}
#include <stdio.h>
int main(void)
{
return puts("hi");
}
#include <gnu/libc-version.h>
int main(void)
{
const char *version = gnu_get_libc_version();
return (long)version;
}
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <gtk/gtk.h>
#pragma GCC diagnostic error "-Wstrict-prototypes"
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
gtk_info_bar_new();
return 0;
}
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <gtk/gtk.h>
#pragma GCC diagnostic error "-Wstrict-prototypes"
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
return 0;
}
#include <stdio.h>
int main(void)
{
return puts("hi");
}
#include <libaudit.h>
extern int printf(const char *format, ...);
int main(void)
{
printf("error message: %s\n", audit_errno_to_name(0));
return audit_open();
}
#include <bfd.h>
extern int printf(const char *format, ...);
int main(void)
{
char symbol[4096] = "FieldName__9ClassNameFd";
char *tmp;
tmp = bfd_demangle(0, symbol, 0);
printf("demangled symbol: {%s}\n", tmp);
return 0;
}
#include <libelf.h>
int main(void)
{
size_t dst;
return elf_getphdrnum(0, &dst);
}
#include <libelf.h>
int main(void)
{
Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
return (long)elf;
}
#include <libelf.h>
int main(void)
{
Elf *elf = elf_begin(0, ELF_C_READ, 0);
return (long)elf;
}
#include <numa.h>
#include <numaif.h>
int main(void)
{
numa_available();
return 0;
}
#include <EXTERN.h>
#include <perl.h>
int main(void)
{
perl_alloc();
return 0;
}
#include <Python.h>
#if PY_VERSION_HEX >= 0x03000000
#error
#endif
int main(void)
{
return 0;
}
#include <Python.h>
int main(void)
{
Py_Initialize();
return 0;
}
#include <slang.h>
int main(void)
{
return SLsmg_init_smg();
}
#include <libunwind.h>
#include <stdlib.h>
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
unw_word_t ip,
unw_dyn_info_t *di,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
static unw_accessors_t accessors;
int main(void)
{
unw_addr_space_t addr_space;
addr_space = unw_create_addr_space(&accessors, 0);
if (addr_space)
return 0;
unw_init_remote(NULL, addr_space, NULL);
dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
return 0;
}
#include <stdio.h>
static void exit_fn(int status, void *__data)
{
printf("exit status: %d, data: %d\n", status, *(int *)__data);
}
static int data = 123;
int main(void)
{
on_exit(exit_fn, &data);
return 321;
}
#include <stdio.h>
int main(void)
{
return puts("hi");
}
#include <stdio.h>
int main(void)
{
return puts("hi");
}
#include <stdio.h>
int main(void)
{
return puts("hi");
}
define SOURCE_HELLO
#include <stdio.h>
int main(void)
{
return puts(\"hi\");
}
endef
ifndef NO_DWARF
define SOURCE_DWARF
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/version.h>
#ifndef _ELFUTILS_PREREQ
#error
#endif
int main(void)
{
Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
return (long)dbg;
}
endef
endif
define SOURCE_LIBELF
#include <libelf.h>
int main(void)
{
Elf *elf = elf_begin(0, ELF_C_READ, 0);
return (long)elf;
}
endef
define SOURCE_GLIBC
#include <gnu/libc-version.h>
int main(void)
{
const char *version = gnu_get_libc_version();
return (long)version;
}
endef
define SOURCE_BIONIC
#include <android/api-level.h>
int main(void)
{
return __ANDROID_API__;
}
endef
define SOURCE_ELF_MMAP
#include <libelf.h>
int main(void)
{
Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
return (long)elf;
}
endef
define SOURCE_ELF_GETPHDRNUM
#include <libelf.h>
int main(void)
{
size_t dst;
return elf_getphdrnum(0, &dst);
}
endef
ifndef NO_SLANG
define SOURCE_SLANG
#include <slang.h>
int main(void)
{
return SLsmg_init_smg();
}
endef
endif
ifndef NO_GTK2
define SOURCE_GTK2
#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
#include <gtk/gtk.h>
#pragma GCC diagnostic error \"-Wstrict-prototypes\"
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
return 0;
}
endef
define SOURCE_GTK2_INFOBAR
#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
#include <gtk/gtk.h>
#pragma GCC diagnostic error \"-Wstrict-prototypes\"
int main(void)
{
gtk_info_bar_new();
return 0;
}
endef
endif
ifndef NO_LIBPERL
define SOURCE_PERL_EMBED
#include <EXTERN.h>
#include <perl.h>
int main(void)
{
perl_alloc();
return 0;
}
endef
endif
ifndef NO_LIBPYTHON
define SOURCE_PYTHON_VERSION
#include <Python.h>
#if PY_VERSION_HEX >= 0x03000000
#error
#endif
int main(void)
{
return 0;
}
endef
define SOURCE_PYTHON_EMBED
#include <Python.h>
int main(void)
{
Py_Initialize();
return 0;
}
endef
endif
define SOURCE_BFD
#include <bfd.h>
int main(void)
{
bfd_demangle(0, 0, 0);
return 0;
}
endef
define SOURCE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int);
int main(void)
{
cplus_demangle(0, 0);
return 0;
}
endef
define SOURCE_STRLCPY
#include <stdlib.h>
extern size_t strlcpy(char *dest, const char *src, size_t size);
int main(void)
{
strlcpy(NULL, NULL, 0);
return 0;
}
endef
ifndef NO_LIBUNWIND
define SOURCE_LIBUNWIND
#include <libunwind.h>
#include <stdlib.h>
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
unw_word_t ip,
unw_dyn_info_t *di,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
int main(void)
{
unw_addr_space_t addr_space;
addr_space = unw_create_addr_space(NULL, 0);
unw_init_remote(NULL, addr_space, NULL);
dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
return 0;
}
endef
endif
ifndef NO_BACKTRACE
define SOURCE_BACKTRACE
#include <execinfo.h>
#include <stdio.h>
int main(void)
{
backtrace(NULL, 0);
backtrace_symbols(NULL, 0);
return 0;
}
endef
endif
ifndef NO_LIBAUDIT
define SOURCE_LIBAUDIT
#include <libaudit.h>
int main(void)
{
printf(\"error message: %s\", audit_errno_to_name(0));
return audit_open();
}
endef
endif
define SOURCE_ON_EXIT
#include <stdio.h>
int main(void)
{
return on_exit(NULL, NULL);
}
endef
define SOURCE_LIBNUMA
#include <numa.h>
#include <numaif.h>
int main(void)
{
numa_available();
return 0;
}
endef
...@@ -179,16 +179,9 @@ _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_e ...@@ -179,16 +179,9 @@ _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_e
_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))
# try-cc ifneq ($(findstring $(MAKEFLAGS),s),s)
# Usage: option = $(call try-cc, source-to-build, cc-options, msg) ifneq ($(V),1)
ifneq ($(V),1) QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
TRY_CC_OUTPUT= > /dev/null 2>&1 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
endif
endif endif
TRY_CC_MSG=echo " CHK $(3)" 1>&2;
try-cc = $(shell sh -c \
'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
$(TRY_CC_MSG) \
echo "$(1)" | \
$(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
rm -f "$$TMP"')
...@@ -49,14 +49,14 @@ static struct cmd_struct commands[] = { ...@@ -49,14 +49,14 @@ static struct cmd_struct commands[] = {
{ "version", cmd_version, 0 }, { "version", cmd_version, 0 },
{ "script", cmd_script, 0 }, { "script", cmd_script, 0 },
{ "sched", cmd_sched, 0 }, { "sched", cmd_sched, 0 },
#ifdef LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
{ "probe", cmd_probe, 0 }, { "probe", cmd_probe, 0 },
#endif #endif
{ "kmem", cmd_kmem, 0 }, { "kmem", cmd_kmem, 0 },
{ "lock", cmd_lock, 0 }, { "lock", cmd_lock, 0 },
{ "kvm", cmd_kvm, 0 }, { "kvm", cmd_kvm, 0 },
{ "test", cmd_test, 0 }, { "test", cmd_test, 0 },
#ifdef LIBAUDIT_SUPPORT #ifdef HAVE_LIBAUDIT_SUPPORT
{ "trace", cmd_trace, 0 }, { "trace", cmd_trace, 0 },
#endif #endif
{ "inject", cmd_inject, 0 }, { "inject", cmd_inject, 0 },
...@@ -456,6 +456,7 @@ int main(int argc, const char **argv) ...@@ -456,6 +456,7 @@ int main(int argc, const char **argv)
{ {
const char *cmd; const char *cmd;
/* The page_size is placed in util object. */
page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
cmd = perf_extract_argv0_path(argv[0]); cmd = perf_extract_argv0_path(argv[0]);
...@@ -480,7 +481,14 @@ int main(int argc, const char **argv) ...@@ -480,7 +481,14 @@ int main(int argc, const char **argv)
fprintf(stderr, "cannot handle %s internally", cmd); fprintf(stderr, "cannot handle %s internally", cmd);
goto out; goto out;
} }
#ifdef HAVE_LIBAUDIT_SUPPORT
if (!prefixcmp(cmd, "trace")) {
set_buildid_dir();
setup_path();
argv[0] = "trace";
return cmd_trace(argc, argv, NULL);
}
#endif
/* Look for flags.. */ /* Look for flags.. */
argv++; argv++;
argc--; argc--;
......
...@@ -35,6 +35,7 @@ static char *test_file(int size) ...@@ -35,6 +35,7 @@ static char *test_file(int size)
if (size != write(fd, buf, size)) if (size != write(fd, buf, size))
templ = NULL; templ = NULL;
free(buf);
close(fd); close(fd);
return templ; return templ;
} }
......
...@@ -45,7 +45,7 @@ int test__PERF_RECORD(void) ...@@ -45,7 +45,7 @@ int test__PERF_RECORD(void)
}; };
cpu_set_t cpu_mask; cpu_set_t cpu_mask;
size_t cpu_mask_size = sizeof(cpu_mask); size_t cpu_mask_size = sizeof(cpu_mask);
struct perf_evlist *evlist = perf_evlist__new(); struct perf_evlist *evlist = perf_evlist__new_default();
struct perf_evsel *evsel; struct perf_evsel *evsel;
struct perf_sample sample; struct perf_sample sample;
const char *cmd = "sleep"; const char *cmd = "sleep";
...@@ -65,16 +65,6 @@ int test__PERF_RECORD(void) ...@@ -65,16 +65,6 @@ int test__PERF_RECORD(void)
goto out; goto out;
} }
/*
* We need at least one evsel in the evlist, use the default
* one: "cycles".
*/
err = perf_evlist__add_default(evlist);
if (err < 0) {
pr_debug("Not enough memory to create evsel\n");
goto out_delete_evlist;
}
/* /*
* Create maps of threads and cpus to monitor. In this case * Create maps of threads and cpus to monitor. In this case
* we start with all threads and cpus (-1, -1) but then in * we start with all threads and cpus (-1, -1) but then in
......
...@@ -37,20 +37,11 @@ int test__task_exit(void) ...@@ -37,20 +37,11 @@ int test__task_exit(void)
signal(SIGCHLD, sig_handler); signal(SIGCHLD, sig_handler);
signal(SIGUSR1, sig_handler); signal(SIGUSR1, sig_handler);
evlist = perf_evlist__new(); evlist = perf_evlist__new_default();
if (evlist == NULL) { if (evlist == NULL) {
pr_debug("perf_evlist__new\n"); pr_debug("perf_evlist__new_default\n");
return -1; return -1;
} }
/*
* We need at least one evsel in the evlist, use the default
* one: "cycles".
*/
err = perf_evlist__add_default(evlist);
if (err < 0) {
pr_debug("Not enough memory to create evsel\n");
goto out_free_evlist;
}
/* /*
* Create maps of threads and cpus to monitor. In this case * Create maps of threads and cpus to monitor. In this case
...@@ -117,7 +108,6 @@ int test__task_exit(void) ...@@ -117,7 +108,6 @@ int test__task_exit(void)
perf_evlist__close(evlist); perf_evlist__close(evlist);
out_delete_maps: out_delete_maps:
perf_evlist__delete_maps(evlist); perf_evlist__delete_maps(evlist);
out_free_evlist:
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
return err; return err;
} }
...@@ -442,35 +442,37 @@ static bool annotate_browser__callq(struct annotate_browser *browser, ...@@ -442,35 +442,37 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
{ {
struct map_symbol *ms = browser->b.priv; struct map_symbol *ms = browser->b.priv;
struct disasm_line *dl = browser->selection; struct disasm_line *dl = browser->selection;
struct symbol *sym = ms->sym;
struct annotation *notes; struct annotation *notes;
struct symbol *target; struct addr_map_symbol target = {
u64 ip; .map = ms->map,
.addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
};
char title[SYM_TITLE_MAX_SIZE]; char title[SYM_TITLE_MAX_SIZE];
if (!ins__is_call(dl->ins)) if (!ins__is_call(dl->ins))
return false; return false;
ip = ms->map->map_ip(ms->map, dl->ops.target.addr); if (map_groups__find_ams(&target, NULL) ||
target = map__find_symbol(ms->map, ip, NULL); map__rip_2objdump(target.map, target.map->map_ip(target.map,
if (target == NULL) { target.addr)) !=
dl->ops.target.addr) {
ui_helpline__puts("The called function was not found."); ui_helpline__puts("The called function was not found.");
return true; return true;
} }
notes = symbol__annotation(target); notes = symbol__annotation(target.sym);
pthread_mutex_lock(&notes->lock); pthread_mutex_lock(&notes->lock);
if (notes->src == NULL && symbol__alloc_hist(target) < 0) { if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
ui__warning("Not enough memory for annotating '%s' symbol!\n", ui__warning("Not enough memory for annotating '%s' symbol!\n",
target->name); target.sym->name);
return true; return true;
} }
pthread_mutex_unlock(&notes->lock); pthread_mutex_unlock(&notes->lock);
symbol__tui_annotate(target, ms->map, evsel, hbt); symbol__tui_annotate(target.sym, target.map, evsel, hbt);
sym_title(sym, ms->map, title, sizeof(title)); sym_title(ms->sym, ms->map, title, sizeof(title));
ui_browser__show_title(&browser->b, title); ui_browser__show_title(&browser->b, title);
return true; return true;
} }
......
...@@ -154,9 +154,9 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, ...@@ -154,9 +154,9 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
return 0; return 0;
} }
int symbol__gtk_annotate(struct symbol *sym, struct map *map, static int symbol__gtk_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct hist_browser_timer *hbt) struct hist_browser_timer *hbt)
{ {
GtkWidget *window; GtkWidget *window;
GtkWidget *notebook; GtkWidget *notebook;
...@@ -226,6 +226,13 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, ...@@ -226,6 +226,13 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map,
return 0; return 0;
} }
int hist_entry__gtk_annotate(struct hist_entry *he,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
}
void perf_gtk__show_annotations(void) void perf_gtk__show_annotations(void)
{ {
GtkWidget *window; GtkWidget *window;
......
...@@ -43,7 +43,7 @@ const char *perf_gtk__get_percent_color(double percent) ...@@ -43,7 +43,7 @@ const char *perf_gtk__get_percent_color(double percent)
return NULL; return NULL;
} }
#ifdef HAVE_GTK_INFO_BAR #ifdef HAVE_GTK_INFO_BAR_SUPPORT
GtkWidget *perf_gtk__setup_info_bar(void) GtkWidget *perf_gtk__setup_info_bar(void)
{ {
GtkWidget *info_bar; GtkWidget *info_bar;
......
...@@ -12,7 +12,7 @@ struct perf_gtk_context { ...@@ -12,7 +12,7 @@ struct perf_gtk_context {
GtkWidget *main_window; GtkWidget *main_window;
GtkWidget *notebook; GtkWidget *notebook;
#ifdef HAVE_GTK_INFO_BAR #ifdef HAVE_GTK_INFO_BAR_SUPPORT
GtkWidget *info_bar; GtkWidget *info_bar;
GtkWidget *message_label; GtkWidget *message_label;
#endif #endif
...@@ -20,6 +20,9 @@ struct perf_gtk_context { ...@@ -20,6 +20,9 @@ struct perf_gtk_context {
guint statbar_ctx_id; guint statbar_ctx_id;
}; };
int perf_gtk__init(void);
void perf_gtk__exit(bool wait_for_ok);
extern struct perf_gtk_context *pgctx; extern struct perf_gtk_context *pgctx;
static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx) static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
...@@ -39,7 +42,7 @@ void perf_gtk__resize_window(GtkWidget *window); ...@@ -39,7 +42,7 @@ void perf_gtk__resize_window(GtkWidget *window);
const char *perf_gtk__get_percent_color(double percent); const char *perf_gtk__get_percent_color(double percent);
GtkWidget *perf_gtk__setup_statusbar(void); GtkWidget *perf_gtk__setup_statusbar(void);
#ifdef HAVE_GTK_INFO_BAR #ifdef HAVE_GTK_INFO_BAR_SUPPORT
GtkWidget *perf_gtk__setup_info_bar(void); GtkWidget *perf_gtk__setup_info_bar(void);
#else #else
static inline GtkWidget *perf_gtk__setup_info_bar(void) static inline GtkWidget *perf_gtk__setup_info_bar(void)
...@@ -48,4 +51,17 @@ static inline GtkWidget *perf_gtk__setup_info_bar(void) ...@@ -48,4 +51,17 @@ static inline GtkWidget *perf_gtk__setup_info_bar(void)
} }
#endif #endif
struct perf_evsel;
struct perf_evlist;
struct hist_entry;
struct hist_browser_timer;
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt,
float min_pcnt);
int hist_entry__gtk_annotate(struct hist_entry *he,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
void perf_gtk__show_annotations(void);
#endif /* _PERF_GTK_H_ */ #endif /* _PERF_GTK_H_ */
...@@ -53,7 +53,7 @@ static int perf_gtk__error(const char *format, va_list args) ...@@ -53,7 +53,7 @@ static int perf_gtk__error(const char *format, va_list args)
return 0; return 0;
} }
#ifdef HAVE_GTK_INFO_BAR #ifdef HAVE_GTK_INFO_BAR_SUPPORT
static int perf_gtk__warning_info_bar(const char *format, va_list args) static int perf_gtk__warning_info_bar(const char *format, va_list args)
{ {
char *msg; char *msg;
...@@ -105,7 +105,7 @@ static int perf_gtk__warning_statusbar(const char *format, va_list args) ...@@ -105,7 +105,7 @@ static int perf_gtk__warning_statusbar(const char *format, va_list args)
struct perf_error_ops perf_gtk_eops = { struct perf_error_ops perf_gtk_eops = {
.error = perf_gtk__error, .error = perf_gtk__error,
#ifdef HAVE_GTK_INFO_BAR #ifdef HAVE_GTK_INFO_BAR_SUPPORT
.warning = perf_gtk__warning_info_bar, .warning = perf_gtk__warning_info_bar,
#else #else
.warning = perf_gtk__warning_statusbar, .warning = perf_gtk__warning_statusbar,
......
#include <pthread.h> #include <pthread.h>
#include <dlfcn.h>
#include "../util/cache.h" #include "../util/cache.h"
#include "../util/debug.h" #include "../util/debug.h"
#include "../util/hist.h" #include "../util/hist.h"
pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
void *perf_gtk_handle;
#ifdef HAVE_GTK2_SUPPORT
static int setup_gtk_browser(void)
{
int (*perf_ui_init)(void);
if (perf_gtk_handle)
return 0;
perf_gtk_handle = dlopen(PERF_GTK_DSO, RTLD_LAZY);
if (perf_gtk_handle == NULL) {
char buf[PATH_MAX];
scnprintf(buf, sizeof(buf), "%s/%s", LIBDIR, PERF_GTK_DSO);
perf_gtk_handle = dlopen(buf, RTLD_LAZY);
}
if (perf_gtk_handle == NULL)
return -1;
perf_ui_init = dlsym(perf_gtk_handle, "perf_gtk__init");
if (perf_ui_init == NULL)
goto out_close;
if (perf_ui_init() == 0)
return 0;
out_close:
dlclose(perf_gtk_handle);
return -1;
}
static void exit_gtk_browser(bool wait_for_ok)
{
void (*perf_ui_exit)(bool);
if (perf_gtk_handle == NULL)
return;
perf_ui_exit = dlsym(perf_gtk_handle, "perf_gtk__exit");
if (perf_ui_exit == NULL)
goto out_close;
perf_ui_exit(wait_for_ok);
out_close:
dlclose(perf_gtk_handle);
perf_gtk_handle = NULL;
}
#else
static inline int setup_gtk_browser(void) { return -1; }
static inline void exit_gtk_browser(bool wait_for_ok __maybe_unused) {}
#endif
void setup_browser(bool fallback_to_pager) void setup_browser(bool fallback_to_pager)
{ {
...@@ -17,8 +71,11 @@ void setup_browser(bool fallback_to_pager) ...@@ -17,8 +71,11 @@ void setup_browser(bool fallback_to_pager)
switch (use_browser) { switch (use_browser) {
case 2: case 2:
if (perf_gtk__init() == 0) if (setup_gtk_browser() == 0)
break; break;
printf("GTK browser requested but could not find %s\n",
PERF_GTK_DSO);
sleep(1);
/* fall through */ /* fall through */
case 1: case 1:
use_browser = 1; use_browser = 1;
...@@ -39,7 +96,7 @@ void exit_browser(bool wait_for_ok) ...@@ -39,7 +96,7 @@ void exit_browser(bool wait_for_ok)
{ {
switch (use_browser) { switch (use_browser) {
case 2: case 2:
perf_gtk__exit(wait_for_ok); exit_gtk_browser(wait_for_ok);
break; break;
case 1: case 1:
......
...@@ -6,13 +6,14 @@ ...@@ -6,13 +6,14 @@
#include <linux/compiler.h> #include <linux/compiler.h>
extern pthread_mutex_t ui__lock; extern pthread_mutex_t ui__lock;
extern void *perf_gtk_handle;
extern int use_browser; extern int use_browser;
void setup_browser(bool fallback_to_pager); void setup_browser(bool fallback_to_pager);
void exit_browser(bool wait_for_ok); void exit_browser(bool wait_for_ok);
#ifdef SLANG_SUPPORT #ifdef HAVE_SLANG_SUPPORT
int ui__init(void); int ui__init(void);
void ui__exit(bool wait_for_ok); void ui__exit(bool wait_for_ok);
#else #else
...@@ -23,17 +24,6 @@ static inline int ui__init(void) ...@@ -23,17 +24,6 @@ static inline int ui__init(void)
static inline void ui__exit(bool wait_for_ok __maybe_unused) {} static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
#endif #endif
#ifdef GTK2_SUPPORT
int perf_gtk__init(void);
void perf_gtk__exit(bool wait_for_ok);
#else
static inline int perf_gtk__init(void)
{
return -1;
}
static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
#endif
void ui__refresh_dimensions(bool force); void ui__refresh_dimensions(bool force);
#endif /* _PERF_UI_H_ */ #endif /* _PERF_UI_H_ */
...@@ -40,7 +40,7 @@ else ...@@ -40,7 +40,7 @@ else
VC=unset VC=unset
fi fi
test "$VN" = "$VC" || { test "$VN" = "$VC" || {
echo >&2 "PERF_VERSION = $VN" echo >&2 " PERF_VERSION = $VN"
echo "#define PERF_VERSION \"$VN\"" >$GVF echo "#define PERF_VERSION \"$VN\"" >$GVF
} }
......
...@@ -825,20 +825,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -825,20 +825,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
dl->ops.target.offset = dl->ops.target.addr - dl->ops.target.offset = dl->ops.target.addr -
map__rip_2objdump(map, sym->start); map__rip_2objdump(map, sym->start);
/* /* kcore has no symbols, so add the call target name */
* kcore has no symbols, so add the call target name if it is on the
* same map.
*/
if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
struct symbol *s; struct addr_map_symbol target = {
u64 ip = dl->ops.target.addr; .map = map,
.addr = dl->ops.target.addr,
if (ip >= map->start && ip <= map->end) { };
ip = map->map_ip(map, ip);
s = map__find_symbol(map, ip, NULL); if (!map_groups__find_ams(&target, NULL) &&
if (s && s->start == ip) target.sym->start == target.al_addr)
dl->ops.target.name = strdup(s->name); dl->ops.target.name = strdup(target.sym->name);
}
} }
disasm__add(&notes->src->source, dl); disasm__add(&notes->src->source, dl);
...@@ -879,6 +875,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -879,6 +875,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
FILE *file; FILE *file;
int err = 0; int err = 0;
char symfs_filename[PATH_MAX]; char symfs_filename[PATH_MAX];
struct kcore_extract kce;
bool delete_extract = false;
if (filename) { if (filename) {
snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
...@@ -940,6 +938,23 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -940,6 +938,23 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
pr_debug("annotating [%p] %30s : [%p] %30s\n", pr_debug("annotating [%p] %30s : [%p] %30s\n",
dso, dso->long_name, sym, sym->name); dso, dso->long_name, sym, sym->name);
if (dso__is_kcore(dso)) {
kce.kcore_filename = symfs_filename;
kce.addr = map__rip_2objdump(map, sym->start);
kce.offs = sym->start;
kce.len = sym->end + 1 - sym->start;
if (!kcore_extract__create(&kce)) {
delete_extract = true;
strlcpy(symfs_filename, kce.extract_filename,
sizeof(symfs_filename));
if (free_filename) {
free(filename);
free_filename = false;
}
filename = symfs_filename;
}
}
snprintf(command, sizeof(command), snprintf(command, sizeof(command),
"%s %s%s --start-address=0x%016" PRIx64 "%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64
...@@ -972,6 +987,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -972,6 +987,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
pclose(file); pclose(file);
out_free_filename: out_free_filename:
if (delete_extract)
kcore_extract__delete(&kce);
if (free_filename) if (free_filename)
free(filename); free(filename);
return err; return err;
...@@ -1070,7 +1087,7 @@ static void symbol__free_source_line(struct symbol *sym, int len) ...@@ -1070,7 +1087,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
(sizeof(src_line->p) * (src_line->nr_pcnt - 1)); (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
free(src_line->path); free_srcline(src_line->path);
src_line = (void *)src_line + sizeof_src_line; src_line = (void *)src_line + sizeof_src_line;
} }
...@@ -1081,13 +1098,11 @@ static void symbol__free_source_line(struct symbol *sym, int len) ...@@ -1081,13 +1098,11 @@ static void symbol__free_source_line(struct symbol *sym, int len)
/* Get the filename:line for the colored entries */ /* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map, static int symbol__get_source_line(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct rb_root *root, int len, struct rb_root *root, int len)
const char *filename)
{ {
u64 start; u64 start;
int i, k; int i, k;
int evidx = evsel->idx; int evidx = evsel->idx;
char cmd[PATH_MAX * 2];
struct source_line *src_line; struct source_line *src_line;
struct annotation *notes = symbol__annotation(sym); struct annotation *notes = symbol__annotation(sym);
struct sym_hist *h = annotation__histogram(notes, evidx); struct sym_hist *h = annotation__histogram(notes, evidx);
...@@ -1115,10 +1130,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, ...@@ -1115,10 +1130,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
start = map__rip_2objdump(map, sym->start); start = map__rip_2objdump(map, sym->start);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
char *path = NULL;
size_t line_len;
u64 offset; u64 offset;
FILE *fp;
double percent_max = 0.0; double percent_max = 0.0;
src_line->nr_pcnt = nr_pcnt; src_line->nr_pcnt = nr_pcnt;
...@@ -1135,23 +1147,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, ...@@ -1135,23 +1147,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
goto next; goto next;
offset = start + i; offset = start + i;
sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); src_line->path = get_srcline(map->dso, offset);
fp = popen(cmd, "r");
if (!fp)
goto next;
if (getline(&path, &line_len, fp) < 0 || !line_len)
goto next_close;
src_line->path = malloc(sizeof(char) * line_len + 1);
if (!src_line->path)
goto next_close;
strcpy(src_line->path, path);
insert_source_line(&tmp_root, src_line); insert_source_line(&tmp_root, src_line);
next_close:
pclose(fp);
next: next:
src_line = (void *)src_line + sizeof_src_line; src_line = (void *)src_line + sizeof_src_line;
} }
...@@ -1192,7 +1190,7 @@ static void print_summary(struct rb_root *root, const char *filename) ...@@ -1192,7 +1190,7 @@ static void print_summary(struct rb_root *root, const char *filename)
path = src_line->path; path = src_line->path;
color = get_percent_color(percent_max); color = get_percent_color(percent_max);
color_fprintf(stdout, color, " %s", path); color_fprintf(stdout, color, " %s\n", path);
node = rb_next(node); node = rb_next(node);
} }
...@@ -1356,7 +1354,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, ...@@ -1356,7 +1354,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
bool full_paths, int min_pcnt, int max_lines) bool full_paths, int min_pcnt, int max_lines)
{ {
struct dso *dso = map->dso; struct dso *dso = map->dso;
const char *filename = dso->long_name;
struct rb_root source_line = RB_ROOT; struct rb_root source_line = RB_ROOT;
u64 len; u64 len;
...@@ -1366,9 +1363,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, ...@@ -1366,9 +1363,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
len = symbol__size(sym); len = symbol__size(sym);
if (print_lines) { if (print_lines) {
symbol__get_source_line(sym, map, evsel, &source_line, symbol__get_source_line(sym, map, evsel, &source_line, len);
len, filename); print_summary(&source_line, dso->long_name);
print_summary(&source_line, filename);
} }
symbol__annotate_printf(sym, map, evsel, full_paths, symbol__annotate_printf(sym, map, evsel, full_paths,
......
...@@ -150,7 +150,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, ...@@ -150,7 +150,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, bool print_lines, struct perf_evsel *evsel, bool print_lines,
bool full_paths, int min_pcnt, int max_lines); bool full_paths, int min_pcnt, int max_lines);
#ifdef SLANG_SUPPORT #ifdef HAVE_SLANG_SUPPORT
int symbol__tui_annotate(struct symbol *sym, struct map *map, int symbol__tui_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct hist_browser_timer *hbt); struct hist_browser_timer *hbt);
...@@ -165,30 +165,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, ...@@ -165,30 +165,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
} }
#endif #endif
#ifdef GTK2_SUPPORT
int symbol__gtk_annotate(struct symbol *sym, struct map *map,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
static inline int hist_entry__gtk_annotate(struct hist_entry *he,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
}
void perf_gtk__show_annotations(void);
#else
static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
struct perf_evsel *evsel __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused)
{
return 0;
}
static inline void perf_gtk__show_annotations(void) {}
#endif
extern const char *disassembler_style; extern const char *disassembler_style;
#endif /* __PERF_ANNOTATE_H */ #endif /* __PERF_ANNOTATE_H */
...@@ -70,8 +70,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2 ...@@ -70,8 +70,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
extern char *perf_pathdup(const char *fmt, ...) extern char *perf_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2))); __attribute__((format (printf, 1, 2)));
#ifndef HAVE_STRLCPY /* Matches the libc/libbsd function attribute so we declare this unconditionally: */
extern size_t strlcpy(char *dest, const char *src, size_t size); extern size_t strlcpy(char *dest, const char *src, size_t size);
#endif
#endif /* __PERF_CACHE_H */ #endif /* __PERF_CACHE_H */
...@@ -7,19 +7,20 @@ ...@@ -7,19 +7,20 @@
char dso__symtab_origin(const struct dso *dso) char dso__symtab_origin(const struct dso *dso)
{ {
static const char origin[] = { static const char origin[] = {
[DSO_BINARY_TYPE__KALLSYMS] = 'k', [DSO_BINARY_TYPE__KALLSYMS] = 'k',
[DSO_BINARY_TYPE__VMLINUX] = 'v', [DSO_BINARY_TYPE__VMLINUX] = 'v',
[DSO_BINARY_TYPE__JAVA_JIT] = 'j', [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
[DSO_BINARY_TYPE__DEBUGLINK] = 'l', [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
[DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
[DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
[DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
[DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
[DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
[DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
[DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
[DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
}; };
if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
...@@ -64,6 +65,28 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, ...@@ -64,6 +65,28 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
symbol_conf.symfs, dso->long_name); symbol_conf.symfs, dso->long_name);
break; break;
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
{
char *last_slash;
size_t len;
size_t dir_size;
last_slash = dso->long_name + dso->long_name_len;
while (last_slash != dso->long_name && *last_slash != '/')
last_slash--;
len = scnprintf(file, size, "%s", symbol_conf.symfs);
dir_size = last_slash - dso->long_name + 2;
if (dir_size > (size - len)) {
ret = -1;
break;
}
len += scnprintf(file + len, dir_size, "%s", dso->long_name);
len += scnprintf(file + len , size - len, ".debug%s",
last_slash);
break;
}
case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
if (!dso->has_build_id) { if (!dso->has_build_id) {
ret = -1; ret = -1;
...@@ -427,6 +450,7 @@ struct dso *dso__new(const char *name) ...@@ -427,6 +450,7 @@ struct dso *dso__new(const char *name)
dso->rel = 0; dso->rel = 0;
dso->sorted_by_name = 0; dso->sorted_by_name = 0;
dso->has_build_id = 0; dso->has_build_id = 0;
dso->has_srcline = 1;
dso->kernel = DSO_TYPE_USER; dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET; dso->needs_swap = DSO_SWAP__UNSET;
INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->node);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "types.h" #include "types.h"
#include "map.h" #include "map.h"
#include "build-id.h"
enum dso_binary_type { enum dso_binary_type {
DSO_BINARY_TYPE__KALLSYMS = 0, DSO_BINARY_TYPE__KALLSYMS = 0,
...@@ -23,6 +24,7 @@ enum dso_binary_type { ...@@ -23,6 +24,7 @@ enum dso_binary_type {
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
DSO_BINARY_TYPE__KCORE, DSO_BINARY_TYPE__KCORE,
DSO_BINARY_TYPE__GUEST_KCORE, DSO_BINARY_TYPE__GUEST_KCORE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__NOT_FOUND, DSO_BINARY_TYPE__NOT_FOUND,
}; };
...@@ -81,6 +83,7 @@ struct dso { ...@@ -81,6 +83,7 @@ struct dso {
enum dso_binary_type data_type; enum dso_binary_type data_type;
u8 adjust_symbols:1; u8 adjust_symbols:1;
u8 has_build_id:1; u8 has_build_id:1;
u8 has_srcline:1;
u8 hit:1; u8 hit:1;
u8 annotate_warned:1; u8 annotate_warned:1;
u8 sname_alloc:1; u8 sname_alloc:1;
......
...@@ -61,6 +61,12 @@ struct read_event { ...@@ -61,6 +61,12 @@ struct read_event {
u64 id; u64 id;
}; };
struct throttle_event {
struct perf_event_header header;
u64 time;
u64 id;
u64 stream_id;
};
#define PERF_SAMPLE_MASK \ #define PERF_SAMPLE_MASK \
(PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
...@@ -69,6 +75,9 @@ struct read_event { ...@@ -69,6 +75,9 @@ struct read_event {
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \ PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
PERF_SAMPLE_IDENTIFIER) PERF_SAMPLE_IDENTIFIER)
/* perf sample has 16 bits size limit */
#define PERF_SAMPLE_MAX_SIZE (1 << 16)
struct sample_event { struct sample_event {
struct perf_event_header header; struct perf_event_header header;
u64 array[]; u64 array[];
...@@ -178,6 +187,7 @@ union perf_event { ...@@ -178,6 +187,7 @@ union perf_event {
struct fork_event fork; struct fork_event fork;
struct lost_event lost; struct lost_event lost;
struct read_event read; struct read_event read;
struct throttle_event throttle;
struct sample_event sample; struct sample_event sample;
struct attr_event attr; struct attr_event attr;
struct event_type_event event_type; struct event_type_event event_type;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <unistd.h> #include <unistd.h>
#include "parse-events.h" #include "parse-events.h"
#include "parse-options.h"
#include <sys/mman.h> #include <sys/mman.h>
...@@ -49,6 +50,18 @@ struct perf_evlist *perf_evlist__new(void) ...@@ -49,6 +50,18 @@ struct perf_evlist *perf_evlist__new(void)
return evlist; return evlist;
} }
struct perf_evlist *perf_evlist__new_default(void)
{
struct perf_evlist *evlist = perf_evlist__new();
if (evlist && perf_evlist__add_default(evlist)) {
perf_evlist__delete(evlist);
evlist = NULL;
}
return evlist;
}
/** /**
* perf_evlist__set_id_pos - set the positions of event ids. * perf_evlist__set_id_pos - set the positions of event ids.
* @evlist: selected event list * @evlist: selected event list
...@@ -527,7 +540,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) ...@@ -527,7 +540,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
if ((old & md->mask) + size != ((old + size) & md->mask)) { if ((old & md->mask) + size != ((old + size) & md->mask)) {
unsigned int offset = old; unsigned int offset = old;
unsigned int len = min(sizeof(*event), size), cpy; unsigned int len = min(sizeof(*event), size), cpy;
void *dst = &md->event_copy; void *dst = md->event_copy;
do { do {
cpy = min(md->mask + 1 - (offset & md->mask), len); cpy = min(md->mask + 1 - (offset & md->mask), len);
...@@ -537,7 +550,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) ...@@ -537,7 +550,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
len -= cpy; len -= cpy;
} while (len); } while (len);
event = &md->event_copy; event = (union perf_event *) md->event_copy;
} }
old += size; old += size;
...@@ -672,6 +685,59 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in ...@@ -672,6 +685,59 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
return -1; return -1;
} }
static size_t perf_evlist__mmap_size(unsigned long pages)
{
/* 512 kiB: default amount of unprivileged mlocked memory */
if (pages == UINT_MAX)
pages = (512 * 1024) / page_size;
else if (!is_power_of_2(pages))
return 0;
return (pages + 1) * page_size;
}
int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
int unset __maybe_unused)
{
unsigned int pages, val, *mmap_pages = opt->value;
size_t size;
static struct parse_tag tags[] = {
{ .tag = 'B', .mult = 1 },
{ .tag = 'K', .mult = 1 << 10 },
{ .tag = 'M', .mult = 1 << 20 },
{ .tag = 'G', .mult = 1 << 30 },
{ .tag = 0 },
};
val = parse_tag_value(str, tags);
if (val != (unsigned int) -1) {
/* we got file size value */
pages = PERF_ALIGN(val, page_size) / page_size;
if (!is_power_of_2(pages)) {
pages = next_pow2(pages);
pr_info("rounding mmap pages size to %u (%u pages)\n",
pages * page_size, pages);
}
} else {
/* we got pages count value */
char *eptr;
pages = strtoul(str, &eptr, 10);
if (*eptr != '\0') {
pr_err("failed to parse --mmap_pages/-m value\n");
return -1;
}
}
size = perf_evlist__mmap_size(pages);
if (!size) {
pr_err("--mmap_pages/-m value must be a power of two.");
return -1;
}
*mmap_pages = pages;
return 0;
}
/** perf_evlist__mmap - Create per cpu maps to receive events /** perf_evlist__mmap - Create per cpu maps to receive events
* *
* @evlist - list of events * @evlist - list of events
...@@ -695,14 +761,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, ...@@ -695,14 +761,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
const struct thread_map *threads = evlist->threads; const struct thread_map *threads = evlist->threads;
int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
/* 512 kiB: default amount of unprivileged mlocked memory */
if (pages == UINT_MAX)
pages = (512 * 1024) / page_size;
else if (!is_power_of_2(pages))
return -EINVAL;
mask = pages * page_size - 1;
if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
return -ENOMEM; return -ENOMEM;
...@@ -710,7 +768,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, ...@@ -710,7 +768,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return -ENOMEM; return -ENOMEM;
evlist->overwrite = overwrite; evlist->overwrite = overwrite;
evlist->mmap_len = (pages + 1) * page_size; evlist->mmap_len = perf_evlist__mmap_size(pages);
pr_debug("mmap size %luB\n", evlist->mmap_len);
mask = evlist->mmap_len - page_size - 1;
list_for_each_entry(evsel, &evlist->entries, node) { list_for_each_entry(evsel, &evlist->entries, node) {
if ((evsel->attr.read_format & PERF_FORMAT_ID) && if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
......
...@@ -21,7 +21,7 @@ struct perf_mmap { ...@@ -21,7 +21,7 @@ struct perf_mmap {
void *base; void *base;
int mask; int mask;
unsigned int prev; unsigned int prev;
union perf_event event_copy; char event_copy[PERF_SAMPLE_MAX_SIZE];
}; };
struct perf_evlist { struct perf_evlist {
...@@ -31,7 +31,7 @@ struct perf_evlist { ...@@ -31,7 +31,7 @@ struct perf_evlist {
int nr_groups; int nr_groups;
int nr_fds; int nr_fds;
int nr_mmaps; int nr_mmaps;
int mmap_len; size_t mmap_len;
int id_pos; int id_pos;
int is_pos; int is_pos;
u64 combined_sample_type; u64 combined_sample_type;
...@@ -53,6 +53,7 @@ struct perf_evsel_str_handler { ...@@ -53,6 +53,7 @@ struct perf_evsel_str_handler {
}; };
struct perf_evlist *perf_evlist__new(void); struct perf_evlist *perf_evlist__new(void);
struct perf_evlist *perf_evlist__new_default(void);
void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
struct thread_map *threads); struct thread_map *threads);
void perf_evlist__exit(struct perf_evlist *evlist); void perf_evlist__exit(struct perf_evlist *evlist);
...@@ -103,6 +104,10 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, ...@@ -103,6 +104,10 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
bool want_signal); bool want_signal);
int perf_evlist__start_workload(struct perf_evlist *evlist); int perf_evlist__start_workload(struct perf_evlist *evlist);
int perf_evlist__parse_mmap_pages(const struct option *opt,
const char *str,
int unset);
int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
bool overwrite); bool overwrite);
void perf_evlist__munmap(struct perf_evlist *evlist); void perf_evlist__munmap(struct perf_evlist *evlist);
......
...@@ -1456,6 +1456,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -1456,6 +1456,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array = (void *)array + sz; array = (void *)array + sz;
OVERFLOW_CHECK_u64(array); OVERFLOW_CHECK_u64(array);
data->user_stack.size = *array++; data->user_stack.size = *array++;
if (WARN_ONCE(data->user_stack.size > sz,
"user stack dump failure\n"))
return -EFAULT;
} }
} }
......
...@@ -22,7 +22,7 @@ do ...@@ -22,7 +22,7 @@ do
}' "Documentation/perf-$cmd.txt" }' "Documentation/perf-$cmd.txt"
done done
echo "#ifdef LIBELF_SUPPORT" echo "#ifdef HAVE_LIBELF_SUPPORT"
sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt |
sort | sort |
while read cmd while read cmd
...@@ -35,5 +35,5 @@ do ...@@ -35,5 +35,5 @@ do
p p
}' "Documentation/perf-$cmd.txt" }' "Documentation/perf-$cmd.txt"
done done
echo "#endif /* LIBELF_SUPPORT */" echo "#endif /* HAVE_LIBELF_SUPPORT */"
echo "};" echo "};"
...@@ -535,6 +535,7 @@ void hist_entry__free(struct hist_entry *he) ...@@ -535,6 +535,7 @@ void hist_entry__free(struct hist_entry *he)
{ {
free(he->branch_info); free(he->branch_info);
free(he->mem_info); free(he->mem_info);
free_srcline(he->srcline);
free(he); free(he);
} }
......
...@@ -187,7 +187,7 @@ struct hist_browser_timer { ...@@ -187,7 +187,7 @@ struct hist_browser_timer {
int refresh; int refresh;
}; };
#ifdef SLANG_SUPPORT #ifdef HAVE_SLANG_SUPPORT
#include "../ui/keysyms.h" #include "../ui/keysyms.h"
int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt); struct hist_browser_timer *hbt);
...@@ -228,20 +228,5 @@ static inline int script_browse(const char *script_opt __maybe_unused) ...@@ -228,20 +228,5 @@ static inline int script_browse(const char *script_opt __maybe_unused)
#define K_SWITCH_INPUT_DATA -3000 #define K_SWITCH_INPUT_DATA -3000
#endif #endif
#ifdef GTK2_SUPPORT
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt);
#else
static inline
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused,
float min_pcnt __maybe_unused)
{
return 0;
}
#endif
unsigned int hists__sort_list_width(struct hists *self); unsigned int hists__sort_list_width(struct hists *self);
#endif /* __PERF_HIST_H */ #endif /* __PERF_HIST_H */
#ifndef _PERF_DWARF_REGS_H_ #ifndef _PERF_DWARF_REGS_H_
#define _PERF_DWARF_REGS_H_ #define _PERF_DWARF_REGS_H_
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
const char *get_arch_regstr(unsigned int n); const char *get_arch_regstr(unsigned int n);
#endif #endif
......
...@@ -2,20 +2,29 @@ ...@@ -2,20 +2,29 @@
#define _PERF_LINUX_COMPILER_H_ #define _PERF_LINUX_COMPILER_H_
#ifndef __always_inline #ifndef __always_inline
#define __always_inline inline # define __always_inline inline __attribute__((always_inline))
#endif #endif
#define __user #define __user
#ifndef __attribute_const__ #ifndef __attribute_const__
#define __attribute_const__ # define __attribute_const__
#endif #endif
#ifndef __maybe_unused #ifndef __maybe_unused
#define __maybe_unused __attribute__((unused)) # define __maybe_unused __attribute__((unused))
#endif
#ifndef __packed
# define __packed __attribute__((__packed__))
#endif #endif
#define __packed __attribute__((__packed__))
#ifndef __force #ifndef __force
#define __force # define __force
#endif
#ifndef __weak
# define __weak __attribute__((weak))
#endif #endif
#endif #endif
...@@ -20,6 +20,7 @@ static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused, ...@@ -20,6 +20,7 @@ static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
if (node != NULL) { if (node != NULL) {
node->i = i; node->i = i;
node->priv = NULL;
rc = &node->rb_node; rc = &node->rb_node;
} }
...@@ -57,22 +58,36 @@ void intlist__remove(struct intlist *ilist, struct int_node *node) ...@@ -57,22 +58,36 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
rblist__remove_node(&ilist->rblist, &node->rb_node); rblist__remove_node(&ilist->rblist, &node->rb_node);
} }
struct int_node *intlist__find(struct intlist *ilist, int i) static struct int_node *__intlist__findnew(struct intlist *ilist,
int i, bool create)
{ {
struct int_node *node; struct int_node *node = NULL;
struct rb_node *rb_node; struct rb_node *rb_node;
if (ilist == NULL) if (ilist == NULL)
return NULL; return NULL;
node = NULL; if (create)
rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); rb_node = rblist__findnew(&ilist->rblist, (void *)((long)i));
else
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 int_node *intlist__find(struct intlist *ilist, int i)
{
return __intlist__findnew(ilist, i, false);
}
struct int_node *intlist__findnew(struct intlist *ilist, int i)
{
return __intlist__findnew(ilist, i, true);
}
static int intlist__parse_list(struct intlist *ilist, const char *s) static int intlist__parse_list(struct intlist *ilist, const char *s)
{ {
char *sep; char *sep;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
struct int_node { struct int_node {
struct rb_node rb_node; struct rb_node rb_node;
int i; int i;
void *priv;
}; };
struct intlist { struct intlist {
...@@ -23,6 +24,7 @@ int intlist__add(struct intlist *ilist, int i); ...@@ -23,6 +24,7 @@ int intlist__add(struct intlist *ilist, int i);
struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx); struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
struct int_node *intlist__find(struct intlist *ilist, int i); struct int_node *intlist__find(struct intlist *ilist, int i);
struct int_node *intlist__findnew(struct intlist *ilist, int i);
static inline bool intlist__has_entry(struct intlist *ilist, int i) static inline bool intlist__has_entry(struct intlist *ilist, int i)
{ {
......
...@@ -46,6 +46,23 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) ...@@ -46,6 +46,23 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
return 0; return 0;
} }
struct machine *machine__new_host(void)
{
struct machine *machine = malloc(sizeof(*machine));
if (machine != NULL) {
machine__init(machine, "", HOST_KERNEL_ID);
if (machine__create_kernel_maps(machine) < 0)
goto out_delete;
}
return machine;
out_delete:
free(machine);
return NULL;
}
static void dsos__delete(struct list_head *dsos) static void dsos__delete(struct list_head *dsos)
{ {
struct dso *pos, *n; struct dso *pos, *n;
...@@ -776,75 +793,44 @@ static int machine__set_modules_path(struct machine *machine) ...@@ -776,75 +793,44 @@ static int machine__set_modules_path(struct machine *machine)
return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
} }
static int machine__create_modules(struct machine *machine) static int machine__create_module(void *arg, const char *name, u64 start)
{ {
char *line = NULL; struct machine *machine = arg;
size_t n;
FILE *file;
struct map *map; struct map *map;
map = machine__new_module(machine, start, name);
if (map == NULL)
return -1;
dso__kernel_module_get_build_id(map->dso, machine->root_dir);
return 0;
}
static int machine__create_modules(struct machine *machine)
{
const char *modules; const char *modules;
char path[PATH_MAX]; char path[PATH_MAX];
if (machine__is_default_guest(machine)) if (machine__is_default_guest(machine)) {
modules = symbol_conf.default_guest_modules; modules = symbol_conf.default_guest_modules;
else { } else {
sprintf(path, "%s/proc/modules", machine->root_dir); snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
modules = path; modules = path;
} }
if (symbol__restricted_filename(modules, "/proc/modules")) if (symbol__restricted_filename(modules, "/proc/modules"))
return -1; return -1;
file = fopen(modules, "r"); if (modules__parse(modules, machine, machine__create_module))
if (file == NULL)
return -1; return -1;
while (!feof(file)) { if (!machine__set_modules_path(machine))
char name[PATH_MAX]; return 0;
u64 start;
char *sep;
int line_len;
line_len = getline(&line, &n, file);
if (line_len < 0)
break;
if (!line)
goto out_failure;
line[--line_len] = '\0'; /* \n */
sep = strrchr(line, 'x');
if (sep == NULL)
continue;
hex2u64(sep + 1, &start);
sep = strchr(line, ' ');
if (sep == NULL)
continue;
*sep = '\0';
snprintf(name, sizeof(name), "[%s]", line);
map = machine__new_module(machine, start, name);
if (map == NULL)
goto out_delete_line;
dso__kernel_module_get_build_id(map->dso, machine->root_dir);
}
free(line); pr_debug("Problems setting modules path maps, continuing anyway...\n");
fclose(file);
if (machine__set_modules_path(machine) < 0) {
pr_debug("Problems setting modules path maps, continuing anyway...\n");
}
return 0; return 0;
out_delete_line:
free(line);
out_failure:
return -1;
} }
int machine__create_kernel_maps(struct machine *machine) int machine__create_kernel_maps(struct machine *machine)
...@@ -1376,3 +1362,26 @@ int machine__resolve_callchain(struct machine *machine, ...@@ -1376,3 +1362,26 @@ int machine__resolve_callchain(struct machine *machine,
sample); sample);
} }
int machine__for_each_thread(struct machine *machine,
int (*fn)(struct thread *thread, void *p),
void *priv)
{
struct rb_node *nd;
struct thread *thread;
int rc = 0;
for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
thread = rb_entry(nd, struct thread, rb_node);
rc = fn(thread, priv);
if (rc != 0)
return rc;
}
list_for_each_entry(thread, &machine->dead_threads, node) {
rc = fn(thread, priv);
if (rc != 0)
return rc;
}
return rc;
}
...@@ -74,6 +74,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); ...@@ -74,6 +74,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
void machines__set_symbol_filter(struct machines *machines, void machines__set_symbol_filter(struct machines *machines,
symbol_filter_t symbol_filter); symbol_filter_t symbol_filter);
struct machine *machine__new_host(void);
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);
void machine__exit(struct machine *machine); void machine__exit(struct machine *machine);
void machine__delete_dead_threads(struct machine *machine); void machine__delete_dead_threads(struct machine *machine);
...@@ -165,4 +166,8 @@ void machines__destroy_kernel_maps(struct machines *machines); ...@@ -165,4 +166,8 @@ 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);
int machine__for_each_thread(struct machine *machine,
int (*fn)(struct thread *thread, void *p),
void *priv);
#endif /* __PERF_MACHINE_H */ #endif /* __PERF_MACHINE_H */
...@@ -172,7 +172,7 @@ int map__load(struct map *map, symbol_filter_t filter) ...@@ -172,7 +172,7 @@ int map__load(struct map *map, symbol_filter_t filter)
pr_warning(", continuing without symbols\n"); pr_warning(", continuing without symbols\n");
return -1; return -1;
} else if (nr == 0) { } else if (nr == 0) {
#ifdef LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
const size_t len = strlen(name); const size_t len = strlen(name);
const size_t real_len = len - sizeof(DSO__DELETED); const size_t real_len = len - sizeof(DSO__DELETED);
...@@ -252,10 +252,16 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) ...@@ -252,10 +252,16 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
return fprintf(fp, "%s", dsoname); return fprintf(fp, "%s", dsoname);
} }
/* /**
* map__rip_2objdump - convert symbol start address to objdump address.
* @map: memory map
* @rip: symbol start address
*
* objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
* map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
* relative to section start. * relative to section start.
*
* Return: Address suitable for passing to "objdump --start-address="
*/ */
u64 map__rip_2objdump(struct map *map, u64 rip) u64 map__rip_2objdump(struct map *map, u64 rip)
{ {
...@@ -268,6 +274,29 @@ u64 map__rip_2objdump(struct map *map, u64 rip) ...@@ -268,6 +274,29 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
return map->unmap_ip(map, rip); return map->unmap_ip(map, rip);
} }
/**
* map__objdump_2mem - convert objdump address to a memory address.
* @map: memory map
* @ip: objdump address
*
* Closely related to map__rip_2objdump(), this function takes an address from
* objdump and converts it to a memory address. Note this assumes that @map
* contains the address. To be sure the result is valid, check it forwards
* e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
*
* Return: Memory address.
*/
u64 map__objdump_2mem(struct map *map, u64 ip)
{
if (!map->dso->adjust_symbols)
return map->unmap_ip(map, ip);
if (map->dso->rel)
return map->unmap_ip(map, ip + map->pgoff);
return ip;
}
void map_groups__init(struct map_groups *mg) void map_groups__init(struct map_groups *mg)
{ {
int i; int i;
...@@ -371,6 +400,23 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, ...@@ -371,6 +400,23 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
return NULL; return NULL;
} }
int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
{
if (ams->addr < ams->map->start || ams->addr > ams->map->end) {
if (ams->map->groups == NULL)
return -1;
ams->map = map_groups__find(ams->map->groups, ams->map->type,
ams->addr);
if (ams->map == NULL)
return -1;
}
ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);
return ams->sym ? 0 : -1;
}
size_t __map_groups__fprintf_maps(struct map_groups *mg, size_t __map_groups__fprintf_maps(struct map_groups *mg,
enum map_type type, int verbose, FILE *fp) enum map_type type, int verbose, FILE *fp)
{ {
......
...@@ -84,6 +84,9 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip) ...@@ -84,6 +84,9 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
u64 map__rip_2objdump(struct map *map, u64 rip); u64 map__rip_2objdump(struct map *map, u64 rip);
/* objdump address -> memory address */
u64 map__objdump_2mem(struct map *map, u64 ip);
struct symbol; struct symbol;
typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
...@@ -167,6 +170,10 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, ...@@ -167,6 +170,10 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
struct map **mapp, struct map **mapp,
symbol_filter_t filter); symbol_filter_t filter);
struct addr_map_symbol;
int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter);
static inline static inline
struct symbol *map_groups__find_function_by_name(struct map_groups *mg, struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
const char *name, struct map **mapp, const char *name, struct map **mapp,
......
...@@ -126,6 +126,37 @@ modifier_bp [rwx]{1,3} ...@@ -126,6 +126,37 @@ modifier_bp [rwx]{1,3}
} }
<config>{
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
, { return ','; }
"/" { BEGIN(INITIAL); return '/'; }
{name_minus} { return str(yyscanner, PE_NAME); }
}
<mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
: { return ':'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
* We need to separate 'mem:' scanner part, in order to get specific
* modifier bits parsed out. Otherwise we would need to handle PE_NAME
* and we'd need to parse it manually. During the escape from <mem>
* state we need to put the escaping char back, so we dont miss it.
*/
. { unput(*yytext); BEGIN(INITIAL); }
/*
* We destroy the scanner after reaching EOF,
* but anyway just to be sure get back to INIT state.
*/
<<EOF>> { BEGIN(INITIAL); }
}
cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
...@@ -162,18 +193,6 @@ speculative-read|speculative-load | ...@@ -162,18 +193,6 @@ speculative-read|speculative-load |
refs|Reference|ops|access | refs|Reference|ops|access |
misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
<config>{
config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
, { return ','; }
"/" { BEGIN(INITIAL); return '/'; }
{name_minus} { return str(yyscanner, PE_NAME); }
}
mem: { BEGIN(mem); return PE_PREFIX_MEM; } mem: { BEGIN(mem); return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(yyscanner); } r{num_raw_hex} { return raw(yyscanner); }
{num_dec} { return value(yyscanner, 10); } {num_dec} { return value(yyscanner, 10); }
...@@ -189,25 +208,7 @@ r{num_raw_hex} { return raw(yyscanner); } ...@@ -189,25 +208,7 @@ r{num_raw_hex} { return raw(yyscanner); }
"}" { return '}'; } "}" { return '}'; }
= { return '='; } = { return '='; }
\n { } \n { }
. { }
<mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
: { return ':'; }
{num_dec} { return value(yyscanner, 10); }
{num_hex} { return value(yyscanner, 16); }
/*
* We need to separate 'mem:' scanner part, in order to get specific
* modifier bits parsed out. Otherwise we would need to handle PE_NAME
* and we'd need to parse it manually. During the escape from <mem>
* state we need to put the escaping char back, so we dont miss it.
*/
. { unput(*yytext); BEGIN(INITIAL); }
/*
* We destroy the scanner after reaching EOF,
* but anyway just to be sure get back to INIT state.
*/
<<EOF>> { BEGIN(INITIAL); }
}
%% %%
......
...@@ -22,19 +22,23 @@ static const char *get_perf_dir(void) ...@@ -22,19 +22,23 @@ static const char *get_perf_dir(void)
return "."; return ".";
} }
#ifndef HAVE_STRLCPY /*
size_t strlcpy(char *dest, const char *src, size_t size) * If libc has strlcpy() then that version will override this
* implementation:
*/
size_t __weak strlcpy(char *dest, const char *src, size_t size)
{ {
size_t ret = strlen(src); size_t ret = strlen(src);
if (size) { if (size) {
size_t len = (ret >= size) ? size - 1 : ret; size_t len = (ret >= size) ? size - 1 : ret;
memcpy(dest, src, len); memcpy(dest, src, len);
dest[len] = '\0'; dest[len] = '\0';
} }
return ret; return ret;
} }
#endif
static char *get_pathname(void) static char *get_pathname(void)
{ {
......
#ifndef __PERF_REGS_H #ifndef __PERF_REGS_H
#define __PERF_REGS_H #define __PERF_REGS_H
#ifdef HAVE_PERF_REGS #ifdef HAVE_PERF_REGS_SUPPORT
#include <perf_regs.h> #include <perf_regs.h>
#else #else
#define PERF_REGS_MASK 0 #define PERF_REGS_MASK 0
...@@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused) ...@@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused)
{ {
return NULL; return NULL;
} }
#endif /* HAVE_PERF_REGS */ #endif /* HAVE_PERF_REGS_SUPPORT */
#endif /* __PERF_REGS_H */ #endif /* __PERF_REGS_H */
...@@ -201,7 +201,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp, ...@@ -201,7 +201,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
return 0; return 0;
} }
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
/* Open new debuginfo of given module */ /* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module) static struct debuginfo *open_debuginfo(const char *module)
{ {
...@@ -630,7 +630,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, ...@@ -630,7 +630,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
return ret; return ret;
} }
#else /* !DWARF_SUPPORT */ #else /* !HAVE_DWARF_SUPPORT */
static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
struct perf_probe_point *pp) struct perf_probe_point *pp)
......
...@@ -14,7 +14,7 @@ static inline int is_c_varname(const char *name) ...@@ -14,7 +14,7 @@ static inline int is_c_varname(const char *name)
return isalpha(name[0]) || name[0] == '_'; return isalpha(name[0]) || name[0] == '_';
} }
#ifdef DWARF_SUPPORT #ifdef HAVE_DWARF_SUPPORT
#include "dwarf-aux.h" #include "dwarf-aux.h"
...@@ -105,6 +105,6 @@ struct line_finder { ...@@ -105,6 +105,6 @@ struct line_finder {
int found; int found;
}; };
#endif /* DWARF_SUPPORT */ #endif /* HAVE_DWARF_SUPPORT */
#endif /*_PROBE_FINDER_H */ #endif /*_PROBE_FINDER_H */
...@@ -33,13 +33,6 @@ int eprintf(int level, const char *fmt, ...) ...@@ -33,13 +33,6 @@ int eprintf(int level, const char *fmt, ...)
# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, # define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
#endif #endif
struct throttle_event {
struct perf_event_header header;
u64 time;
u64 id;
u64 stream_id;
};
PyMODINIT_FUNC initperf(void); PyMODINIT_FUNC initperf(void);
#define member_def(type, member, ptype, help) \ #define member_def(type, member, ptype, help) \
...@@ -1036,6 +1029,7 @@ PyMODINIT_FUNC initperf(void) ...@@ -1036,6 +1029,7 @@ PyMODINIT_FUNC initperf(void)
pyrf_cpu_map__setup_types() < 0) pyrf_cpu_map__setup_types() < 0)
return; return;
/* The page_size is placed in util object. */
page_size = sysconf(_SC_PAGE_SIZE); page_size = sysconf(_SC_PAGE_SIZE);
Py_INCREF(&pyrf_evlist__type); Py_INCREF(&pyrf_evlist__type);
......
...@@ -48,10 +48,12 @@ void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) ...@@ -48,10 +48,12 @@ void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
rblist->node_delete(rblist, rb_node); rblist->node_delete(rblist, rb_node);
} }
struct rb_node *rblist__find(struct rblist *rblist, const void *entry) static struct rb_node *__rblist__findnew(struct rblist *rblist,
const void *entry,
bool create)
{ {
struct rb_node **p = &rblist->entries.rb_node; struct rb_node **p = &rblist->entries.rb_node;
struct rb_node *parent = NULL; struct rb_node *parent = NULL, *new_node = NULL;
while (*p != NULL) { while (*p != NULL) {
int rc; int rc;
...@@ -67,7 +69,26 @@ struct rb_node *rblist__find(struct rblist *rblist, const void *entry) ...@@ -67,7 +69,26 @@ struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
return parent; return parent;
} }
return NULL; if (create) {
new_node = rblist->node_new(rblist, entry);
if (new_node) {
rb_link_node(new_node, parent, p);
rb_insert_color(new_node, &rblist->entries);
++rblist->nr_entries;
}
}
return new_node;
}
struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
{
return __rblist__findnew(rblist, entry, false);
}
struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry)
{
return __rblist__findnew(rblist, entry, true);
} }
void rblist__init(struct rblist *rblist) void rblist__init(struct rblist *rblist)
......
...@@ -32,6 +32,7 @@ void rblist__delete(struct rblist *rblist); ...@@ -32,6 +32,7 @@ void rblist__delete(struct rblist *rblist);
int rblist__add_node(struct rblist *rblist, const void *new_entry); 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);
struct rb_node *rblist__find(struct rblist *rblist, const void *entry); struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry);
struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx); struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
static inline bool rblist__empty(const struct rblist *rblist) static inline bool rblist__empty(const struct rblist *rblist)
......
...@@ -397,6 +397,17 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all) ...@@ -397,6 +397,17 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
swap_sample_id_all(event, &event->read + 1); swap_sample_id_all(event, &event->read + 1);
} }
static void perf_event__throttle_swap(union perf_event *event,
bool sample_id_all)
{
event->throttle.time = bswap_64(event->throttle.time);
event->throttle.id = bswap_64(event->throttle.id);
event->throttle.stream_id = bswap_64(event->throttle.stream_id);
if (sample_id_all)
swap_sample_id_all(event, &event->throttle + 1);
}
static u8 revbyte(u8 b) static u8 revbyte(u8 b)
{ {
int rev = (b >> 4) | ((b & 0xf) << 4); int rev = (b >> 4) | ((b & 0xf) << 4);
...@@ -482,6 +493,8 @@ static perf_event__swap_op perf_event__swap_ops[] = { ...@@ -482,6 +493,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_EXIT] = perf_event__task_swap, [PERF_RECORD_EXIT] = perf_event__task_swap,
[PERF_RECORD_LOST] = perf_event__all64_swap, [PERF_RECORD_LOST] = perf_event__all64_swap,
[PERF_RECORD_READ] = perf_event__read_swap, [PERF_RECORD_READ] = perf_event__read_swap,
[PERF_RECORD_THROTTLE] = perf_event__throttle_swap,
[PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,
[PERF_RECORD_SAMPLE] = perf_event__all64_swap, [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
[PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
[PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
......
...@@ -243,50 +243,32 @@ struct sort_entry sort_sym = { ...@@ -243,50 +243,32 @@ struct sort_entry sort_sym = {
static int64_t static int64_t
sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
return (int64_t)(right->ip - left->ip); if (!left->srcline) {
if (!left->ms.map)
left->srcline = SRCLINE_UNKNOWN;
else {
struct map *map = left->ms.map;
left->srcline = get_srcline(map->dso,
map__rip_2objdump(map, left->ip));
}
}
if (!right->srcline) {
if (!right->ms.map)
right->srcline = SRCLINE_UNKNOWN;
else {
struct map *map = right->ms.map;
right->srcline = get_srcline(map->dso,
map__rip_2objdump(map, right->ip));
}
}
return strcmp(left->srcline, right->srcline);
} }
static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
size_t size, size_t size,
unsigned int width __maybe_unused) unsigned int width __maybe_unused)
{ {
FILE *fp = NULL; return repsep_snprintf(bf, size, "%s", self->srcline);
char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
size_t line_len;
if (path != NULL)
goto out_path;
if (!self->ms.map)
goto out_ip;
if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
goto out_ip;
snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
self->ms.map->dso->long_name, self->ip);
fp = popen(cmd, "r");
if (!fp)
goto out_ip;
if (getline(&path, &line_len, fp) < 0 || !line_len)
goto out_ip;
self->srcline = strdup(path);
if (self->srcline == NULL)
goto out_ip;
nl = strchr(self->srcline, '\n');
if (nl != NULL)
*nl = '\0';
path = self->srcline;
out_path:
if (fp)
pclose(fp);
return repsep_snprintf(bf, size, "%s", path);
out_ip:
if (fp)
pclose(fp);
return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
} }
struct sort_entry sort_srcline = { struct sort_entry sort_srcline = {
......
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/kernel.h>
#include "util/dso.h"
#include "util/util.h"
#include "util/debug.h"
#ifdef HAVE_LIBBFD_SUPPORT
/*
* Implement addr2line using libbfd.
*/
#define PACKAGE "perf"
#include <bfd.h>
struct a2l_data {
const char *input;
unsigned long addr;
bool found;
const char *filename;
const char *funcname;
unsigned line;
bfd *abfd;
asymbol **syms;
};
static int bfd_error(const char *string)
{
const char *errmsg;
errmsg = bfd_errmsg(bfd_get_error());
fflush(stdout);
if (string)
pr_debug("%s: %s\n", string, errmsg);
else
pr_debug("%s\n", errmsg);
return -1;
}
static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
{
long storage;
long symcount;
asymbol **syms;
bfd_boolean dynamic = FALSE;
if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
return bfd_error(bfd_get_filename(abfd));
storage = bfd_get_symtab_upper_bound(abfd);
if (storage == 0L) {
storage = bfd_get_dynamic_symtab_upper_bound(abfd);
dynamic = TRUE;
}
if (storage < 0L)
return bfd_error(bfd_get_filename(abfd));
syms = malloc(storage);
if (dynamic)
symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
else
symcount = bfd_canonicalize_symtab(abfd, syms);
if (symcount < 0) {
free(syms);
return bfd_error(bfd_get_filename(abfd));
}
a2l->syms = syms;
return 0;
}
static void find_address_in_section(bfd *abfd, asection *section, void *data)
{
bfd_vma pc, vma;
bfd_size_type size;
struct a2l_data *a2l = data;
if (a2l->found)
return;
if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
return;
pc = a2l->addr;
vma = bfd_get_section_vma(abfd, section);
size = bfd_get_section_size(section);
if (pc < vma || pc >= vma + size)
return;
a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
&a2l->filename, &a2l->funcname,
&a2l->line);
}
static struct a2l_data *addr2line_init(const char *path)
{
bfd *abfd;
struct a2l_data *a2l = NULL;
abfd = bfd_openr(path, NULL);
if (abfd == NULL)
return NULL;
if (!bfd_check_format(abfd, bfd_object))
goto out;
a2l = zalloc(sizeof(*a2l));
if (a2l == NULL)
goto out;
a2l->abfd = abfd;
a2l->input = strdup(path);
if (a2l->input == NULL)
goto out;
if (slurp_symtab(abfd, a2l))
goto out;
return a2l;
out:
if (a2l) {
free((void *)a2l->input);
free(a2l);
}
bfd_close(abfd);
return NULL;
}
static void addr2line_cleanup(struct a2l_data *a2l)
{
if (a2l->abfd)
bfd_close(a2l->abfd);
free((void *)a2l->input);
free(a2l->syms);
free(a2l);
}
static int addr2line(const char *dso_name, unsigned long addr,
char **file, unsigned int *line)
{
int ret = 0;
struct a2l_data *a2l;
a2l = addr2line_init(dso_name);
if (a2l == NULL) {
pr_warning("addr2line_init failed for %s\n", dso_name);
return 0;
}
a2l->addr = addr;
bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
if (a2l->found && a2l->filename) {
*file = strdup(a2l->filename);
*line = a2l->line;
if (*file)
ret = 1;
}
addr2line_cleanup(a2l);
return ret;
}
#else /* HAVE_LIBBFD_SUPPORT */
static int addr2line(const char *dso_name, unsigned long addr,
char **file, unsigned int *line_nr)
{
FILE *fp;
char cmd[PATH_MAX];
char *filename = NULL;
size_t len;
char *sep;
int ret = 0;
scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
dso_name, addr);
fp = popen(cmd, "r");
if (fp == NULL) {
pr_warning("popen failed for %s\n", dso_name);
return 0;
}
if (getline(&filename, &len, fp) < 0 || !len) {
pr_warning("addr2line has no output for %s\n", dso_name);
goto out;
}
sep = strchr(filename, '\n');
if (sep)
*sep = '\0';
if (!strcmp(filename, "??:0")) {
pr_debug("no debugging info in %s\n", dso_name);
free(filename);
goto out;
}
sep = strchr(filename, ':');
if (sep) {
*sep++ = '\0';
*file = filename;
*line_nr = strtoul(sep, NULL, 0);
ret = 1;
}
out:
pclose(fp);
return ret;
}
#endif /* HAVE_LIBBFD_SUPPORT */
char *get_srcline(struct dso *dso, unsigned long addr)
{
char *file = NULL;
unsigned line = 0;
char *srcline;
char *dso_name = dso->long_name;
size_t size;
if (!dso->has_srcline)
return SRCLINE_UNKNOWN;
if (dso_name[0] == '[')
goto out;
if (!strncmp(dso_name, "/tmp/perf-", 10))
goto out;
if (!addr2line(dso_name, addr, &file, &line))
goto out;
/* just calculate actual length */
size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
srcline = malloc(size);
if (srcline)
snprintf(srcline, size, "%s:%u", file, line);
else
srcline = SRCLINE_UNKNOWN;
free(file);
return srcline;
out:
dso->has_srcline = 0;
return SRCLINE_UNKNOWN;
}
void free_srcline(char *srcline)
{
if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
free(srcline);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "symbol.h" #include "symbol.h"
#include "debug.h" #include "debug.h"
#ifndef HAVE_ELF_GETPHDRNUM #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
static int elf_getphdrnum(Elf *elf, size_t *dst) static int elf_getphdrnum(Elf *elf, size_t *dst)
{ {
GElf_Ehdr gehdr; GElf_Ehdr gehdr;
...@@ -487,27 +487,27 @@ int filename__read_debuglink(const char *filename, char *debuglink, ...@@ -487,27 +487,27 @@ int filename__read_debuglink(const char *filename, char *debuglink,
ek = elf_kind(elf); ek = elf_kind(elf);
if (ek != ELF_K_ELF) if (ek != ELF_K_ELF)
goto out_close; goto out_elf_end;
if (gelf_getehdr(elf, &ehdr) == NULL) { if (gelf_getehdr(elf, &ehdr) == NULL) {
pr_err("%s: cannot get elf header.\n", __func__); pr_err("%s: cannot get elf header.\n", __func__);
goto out_close; goto out_elf_end;
} }
sec = elf_section_by_name(elf, &ehdr, &shdr, sec = elf_section_by_name(elf, &ehdr, &shdr,
".gnu_debuglink", NULL); ".gnu_debuglink", NULL);
if (sec == NULL) if (sec == NULL)
goto out_close; goto out_elf_end;
data = elf_getdata(sec, NULL); data = elf_getdata(sec, NULL);
if (data == NULL) if (data == NULL)
goto out_close; goto out_elf_end;
/* the start of this section is a zero-terminated string */ /* the start of this section is a zero-terminated string */
strncpy(debuglink, data->d_buf, size); strncpy(debuglink, data->d_buf, size);
out_elf_end:
elf_end(elf); elf_end(elf);
out_close: out_close:
close(fd); close(fd);
out: out:
...@@ -1018,6 +1018,601 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, ...@@ -1018,6 +1018,601 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
return err; return err;
} }
static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
{
ssize_t r;
size_t n;
int err = -1;
char *buf = malloc(page_size);
if (buf == NULL)
return -1;
if (lseek(to, to_offs, SEEK_SET) != to_offs)
goto out;
if (lseek(from, from_offs, SEEK_SET) != from_offs)
goto out;
while (len) {
n = page_size;
if (len < n)
n = len;
/* Use read because mmap won't work on proc files */
r = read(from, buf, n);
if (r < 0)
goto out;
if (!r)
break;
n = r;
r = write(to, buf, n);
if (r < 0)
goto out;
if ((size_t)r != n)
goto out;
len -= n;
}
err = 0;
out:
free(buf);
return err;
}
struct kcore {
int fd;
int elfclass;
Elf *elf;
GElf_Ehdr ehdr;
};
static int kcore__open(struct kcore *kcore, const char *filename)
{
GElf_Ehdr *ehdr;
kcore->fd = open(filename, O_RDONLY);
if (kcore->fd == -1)
return -1;
kcore->elf = elf_begin(kcore->fd, ELF_C_READ, NULL);
if (!kcore->elf)
goto out_close;
kcore->elfclass = gelf_getclass(kcore->elf);
if (kcore->elfclass == ELFCLASSNONE)
goto out_end;
ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
if (!ehdr)
goto out_end;
return 0;
out_end:
elf_end(kcore->elf);
out_close:
close(kcore->fd);
return -1;
}
static int kcore__init(struct kcore *kcore, char *filename, int elfclass,
bool temp)
{
GElf_Ehdr *ehdr;
kcore->elfclass = elfclass;
if (temp)
kcore->fd = mkstemp(filename);
else
kcore->fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400);
if (kcore->fd == -1)
return -1;
kcore->elf = elf_begin(kcore->fd, ELF_C_WRITE, NULL);
if (!kcore->elf)
goto out_close;
if (!gelf_newehdr(kcore->elf, elfclass))
goto out_end;
ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
if (!ehdr)
goto out_end;
return 0;
out_end:
elf_end(kcore->elf);
out_close:
close(kcore->fd);
unlink(filename);
return -1;
}
static void kcore__close(struct kcore *kcore)
{
elf_end(kcore->elf);
close(kcore->fd);
}
static int kcore__copy_hdr(struct kcore *from, struct kcore *to, size_t count)
{
GElf_Ehdr *ehdr = &to->ehdr;
GElf_Ehdr *kehdr = &from->ehdr;
memcpy(ehdr->e_ident, kehdr->e_ident, EI_NIDENT);
ehdr->e_type = kehdr->e_type;
ehdr->e_machine = kehdr->e_machine;
ehdr->e_version = kehdr->e_version;
ehdr->e_entry = 0;
ehdr->e_shoff = 0;
ehdr->e_flags = kehdr->e_flags;
ehdr->e_phnum = count;
ehdr->e_shentsize = 0;
ehdr->e_shnum = 0;
ehdr->e_shstrndx = 0;
if (from->elfclass == ELFCLASS32) {
ehdr->e_phoff = sizeof(Elf32_Ehdr);
ehdr->e_ehsize = sizeof(Elf32_Ehdr);
ehdr->e_phentsize = sizeof(Elf32_Phdr);
} else {
ehdr->e_phoff = sizeof(Elf64_Ehdr);
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
ehdr->e_phentsize = sizeof(Elf64_Phdr);
}
if (!gelf_update_ehdr(to->elf, ehdr))
return -1;
if (!gelf_newphdr(to->elf, count))
return -1;
return 0;
}
static int kcore__add_phdr(struct kcore *kcore, int idx, off_t offset,
u64 addr, u64 len)
{
GElf_Phdr gphdr;
GElf_Phdr *phdr;
phdr = gelf_getphdr(kcore->elf, idx, &gphdr);
if (!phdr)
return -1;
phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_offset = offset;
phdr->p_vaddr = addr;
phdr->p_paddr = 0;
phdr->p_filesz = len;
phdr->p_memsz = len;
phdr->p_align = page_size;
if (!gelf_update_phdr(kcore->elf, idx, phdr))
return -1;
return 0;
}
static off_t kcore__write(struct kcore *kcore)
{
return elf_update(kcore->elf, ELF_C_WRITE);
}
struct phdr_data {
off_t offset;
u64 addr;
u64 len;
};
struct kcore_copy_info {
u64 stext;
u64 etext;
u64 first_symbol;
u64 last_symbol;
u64 first_module;
u64 last_module_symbol;
struct phdr_data kernel_map;
struct phdr_data modules_map;
};
static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
u64 start)
{
struct kcore_copy_info *kci = arg;
if (!symbol_type__is_a(type, MAP__FUNCTION))
return 0;
if (strchr(name, '[')) {
if (start > kci->last_module_symbol)
kci->last_module_symbol = start;
return 0;
}
if (!kci->first_symbol || start < kci->first_symbol)
kci->first_symbol = start;
if (!kci->last_symbol || start > kci->last_symbol)
kci->last_symbol = start;
if (!strcmp(name, "_stext")) {
kci->stext = start;
return 0;
}
if (!strcmp(name, "_etext")) {
kci->etext = start;
return 0;
}
return 0;
}
static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci,
const char *dir)
{
char kallsyms_filename[PATH_MAX];
scnprintf(kallsyms_filename, PATH_MAX, "%s/kallsyms", dir);
if (symbol__restricted_filename(kallsyms_filename, "/proc/kallsyms"))
return -1;
if (kallsyms__parse(kallsyms_filename, kci,
kcore_copy__process_kallsyms) < 0)
return -1;
return 0;
}
static int kcore_copy__process_modules(void *arg,
const char *name __maybe_unused,
u64 start)
{
struct kcore_copy_info *kci = arg;
if (!kci->first_module || start < kci->first_module)
kci->first_module = start;
return 0;
}
static int kcore_copy__parse_modules(struct kcore_copy_info *kci,
const char *dir)
{
char modules_filename[PATH_MAX];
scnprintf(modules_filename, PATH_MAX, "%s/modules", dir);
if (symbol__restricted_filename(modules_filename, "/proc/modules"))
return -1;
if (modules__parse(modules_filename, kci,
kcore_copy__process_modules) < 0)
return -1;
return 0;
}
static void kcore_copy__map(struct phdr_data *p, u64 start, u64 end, u64 pgoff,
u64 s, u64 e)
{
if (p->addr || s < start || s >= end)
return;
p->addr = s;
p->offset = (s - start) + pgoff;
p->len = e < end ? e - s : end - s;
}
static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data)
{
struct kcore_copy_info *kci = data;
u64 end = start + len;
kcore_copy__map(&kci->kernel_map, start, end, pgoff, kci->stext,
kci->etext);
kcore_copy__map(&kci->modules_map, start, end, pgoff, kci->first_module,
kci->last_module_symbol);
return 0;
}
static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)
{
if (elf_read_maps(elf, true, kcore_copy__read_map, kci) < 0)
return -1;
return 0;
}
static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,
Elf *elf)
{
if (kcore_copy__parse_kallsyms(kci, dir))
return -1;
if (kcore_copy__parse_modules(kci, dir))
return -1;
if (kci->stext)
kci->stext = round_down(kci->stext, page_size);
else
kci->stext = round_down(kci->first_symbol, page_size);
if (kci->etext) {
kci->etext = round_up(kci->etext, page_size);
} else if (kci->last_symbol) {
kci->etext = round_up(kci->last_symbol, page_size);
kci->etext += page_size;
}
kci->first_module = round_down(kci->first_module, page_size);
if (kci->last_module_symbol) {
kci->last_module_symbol = round_up(kci->last_module_symbol,
page_size);
kci->last_module_symbol += page_size;
}
if (!kci->stext || !kci->etext)
return -1;
if (kci->first_module && !kci->last_module_symbol)
return -1;
return kcore_copy__read_maps(kci, elf);
}
static int kcore_copy__copy_file(const char *from_dir, const char *to_dir,
const char *name)
{
char from_filename[PATH_MAX];
char to_filename[PATH_MAX];
scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
return copyfile_mode(from_filename, to_filename, 0400);
}
static int kcore_copy__unlink(const char *dir, const char *name)
{
char filename[PATH_MAX];
scnprintf(filename, PATH_MAX, "%s/%s", dir, name);
return unlink(filename);
}
static int kcore_copy__compare_fds(int from, int to)
{
char *buf_from;
char *buf_to;
ssize_t ret;
size_t len;
int err = -1;
buf_from = malloc(page_size);
buf_to = malloc(page_size);
if (!buf_from || !buf_to)
goto out;
while (1) {
/* Use read because mmap won't work on proc files */
ret = read(from, buf_from, page_size);
if (ret < 0)
goto out;
if (!ret)
break;
len = ret;
if (readn(to, buf_to, len) != (int)len)
goto out;
if (memcmp(buf_from, buf_to, len))
goto out;
}
err = 0;
out:
free(buf_to);
free(buf_from);
return err;
}
static int kcore_copy__compare_files(const char *from_filename,
const char *to_filename)
{
int from, to, err = -1;
from = open(from_filename, O_RDONLY);
if (from < 0)
return -1;
to = open(to_filename, O_RDONLY);
if (to < 0)
goto out_close_from;
err = kcore_copy__compare_fds(from, to);
close(to);
out_close_from:
close(from);
return err;
}
static int kcore_copy__compare_file(const char *from_dir, const char *to_dir,
const char *name)
{
char from_filename[PATH_MAX];
char to_filename[PATH_MAX];
scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
return kcore_copy__compare_files(from_filename, to_filename);
}
/**
* kcore_copy - copy kallsyms, modules and kcore from one directory to another.
* @from_dir: from directory
* @to_dir: to directory
*
* This function copies kallsyms, modules and kcore files from one directory to
* another. kallsyms and modules are copied entirely. Only code segments are
* copied from kcore. It is assumed that two segments suffice: one for the
* kernel proper and one for all the modules. The code segments are determined
* from kallsyms and modules files. The kernel map starts at _stext or the
* lowest function symbol, and ends at _etext or the highest function symbol.
* The module map starts at the lowest module address and ends at the highest
* module symbol. Start addresses are rounded down to the nearest page. End
* addresses are rounded up to the nearest page. An extra page is added to the
* highest kernel symbol and highest module symbol to, hopefully, encompass that
* symbol too. Because it contains only code sections, the resulting kcore is
* unusual. One significant peculiarity is that the mapping (start -> pgoff)
* is not the same for the kernel map and the modules map. That happens because
* the data is copied adjacently whereas the original kcore has gaps. Finally,
* kallsyms and modules files are compared with their copies to check that
* modules have not been loaded or unloaded while the copies were taking place.
*
* Return: %0 on success, %-1 on failure.
*/
int kcore_copy(const char *from_dir, const char *to_dir)
{
struct kcore kcore;
struct kcore extract;
size_t count = 2;
int idx = 0, err = -1;
off_t offset = page_size, sz, modules_offset = 0;
struct kcore_copy_info kci = { .stext = 0, };
char kcore_filename[PATH_MAX];
char extract_filename[PATH_MAX];
if (kcore_copy__copy_file(from_dir, to_dir, "kallsyms"))
return -1;
if (kcore_copy__copy_file(from_dir, to_dir, "modules"))
goto out_unlink_kallsyms;
scnprintf(kcore_filename, PATH_MAX, "%s/kcore", from_dir);
scnprintf(extract_filename, PATH_MAX, "%s/kcore", to_dir);
if (kcore__open(&kcore, kcore_filename))
goto out_unlink_modules;
if (kcore_copy__calc_maps(&kci, from_dir, kcore.elf))
goto out_kcore_close;
if (kcore__init(&extract, extract_filename, kcore.elfclass, false))
goto out_kcore_close;
if (!kci.modules_map.addr)
count -= 1;
if (kcore__copy_hdr(&kcore, &extract, count))
goto out_extract_close;
if (kcore__add_phdr(&extract, idx++, offset, kci.kernel_map.addr,
kci.kernel_map.len))
goto out_extract_close;
if (kci.modules_map.addr) {
modules_offset = offset + kci.kernel_map.len;
if (kcore__add_phdr(&extract, idx, modules_offset,
kci.modules_map.addr, kci.modules_map.len))
goto out_extract_close;
}
sz = kcore__write(&extract);
if (sz < 0 || sz > offset)
goto out_extract_close;
if (copy_bytes(kcore.fd, kci.kernel_map.offset, extract.fd, offset,
kci.kernel_map.len))
goto out_extract_close;
if (modules_offset && copy_bytes(kcore.fd, kci.modules_map.offset,
extract.fd, modules_offset,
kci.modules_map.len))
goto out_extract_close;
if (kcore_copy__compare_file(from_dir, to_dir, "modules"))
goto out_extract_close;
if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms"))
goto out_extract_close;
err = 0;
out_extract_close:
kcore__close(&extract);
if (err)
unlink(extract_filename);
out_kcore_close:
kcore__close(&kcore);
out_unlink_modules:
if (err)
kcore_copy__unlink(to_dir, "modules");
out_unlink_kallsyms:
if (err)
kcore_copy__unlink(to_dir, "kallsyms");
return err;
}
int kcore_extract__create(struct kcore_extract *kce)
{
struct kcore kcore;
struct kcore extract;
size_t count = 1;
int idx = 0, err = -1;
off_t offset = page_size, sz;
if (kcore__open(&kcore, kce->kcore_filename))
return -1;
strcpy(kce->extract_filename, PERF_KCORE_EXTRACT);
if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true))
goto out_kcore_close;
if (kcore__copy_hdr(&kcore, &extract, count))
goto out_extract_close;
if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len))
goto out_extract_close;
sz = kcore__write(&extract);
if (sz < 0 || sz > offset)
goto out_extract_close;
if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len))
goto out_extract_close;
err = 0;
out_extract_close:
kcore__close(&extract);
if (err)
unlink(kce->extract_filename);
out_kcore_close:
kcore__close(&kcore);
return err;
}
void kcore_extract__delete(struct kcore_extract *kce)
{
unlink(kce->extract_filename);
}
void symbol__elf_init(void) void symbol__elf_init(void)
{ {
elf_version(EV_CURRENT); elf_version(EV_CURRENT);
......
...@@ -308,6 +308,21 @@ int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused, ...@@ -308,6 +308,21 @@ int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
return -1; return -1;
} }
int kcore_extract__create(struct kcore_extract *kce __maybe_unused)
{
return -1;
}
void kcore_extract__delete(struct kcore_extract *kce __maybe_unused)
{
}
int kcore_copy(const char *from_dir __maybe_unused,
const char *to_dir __maybe_unused)
{
return -1;
}
void symbol__elf_init(void) void symbol__elf_init(void)
{ {
} }
...@@ -51,6 +51,7 @@ static enum dso_binary_type binary_type_symtab[] = { ...@@ -51,6 +51,7 @@ static enum dso_binary_type binary_type_symtab[] = {
DSO_BINARY_TYPE__SYSTEM_PATH_DSO, DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE, DSO_BINARY_TYPE__GUEST_KMODULE,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__NOT_FOUND, DSO_BINARY_TYPE__NOT_FOUND,
}; };
...@@ -159,10 +160,12 @@ void symbols__fixup_duplicate(struct rb_root *symbols) ...@@ -159,10 +160,12 @@ void symbols__fixup_duplicate(struct rb_root *symbols)
if (choose_best_symbol(curr, next) == SYMBOL_A) { if (choose_best_symbol(curr, next) == SYMBOL_A) {
rb_erase(&next->rb_node, symbols); rb_erase(&next->rb_node, symbols);
symbol__delete(next);
goto again; goto again;
} else { } else {
nd = rb_next(&curr->rb_node); nd = rb_next(&curr->rb_node);
rb_erase(&curr->rb_node, symbols); rb_erase(&curr->rb_node, symbols);
symbol__delete(curr);
} }
} }
} }
...@@ -499,6 +502,64 @@ int kallsyms__parse(const char *filename, void *arg, ...@@ -499,6 +502,64 @@ int kallsyms__parse(const char *filename, void *arg,
return -1; return -1;
} }
int modules__parse(const char *filename, void *arg,
int (*process_module)(void *arg, const char *name,
u64 start))
{
char *line = NULL;
size_t n;
FILE *file;
int err = 0;
file = fopen(filename, "r");
if (file == NULL)
return -1;
while (1) {
char name[PATH_MAX];
u64 start;
char *sep;
ssize_t line_len;
line_len = getline(&line, &n, file);
if (line_len < 0) {
if (feof(file))
break;
err = -1;
goto out;
}
if (!line) {
err = -1;
goto out;
}
line[--line_len] = '\0'; /* \n */
sep = strrchr(line, 'x');
if (sep == NULL)
continue;
hex2u64(sep + 1, &start);
sep = strchr(line, ' ');
if (sep == NULL)
continue;
*sep = '\0';
scnprintf(name, sizeof(name), "[%s]", line);
err = process_module(arg, name, start);
if (err)
break;
}
out:
free(line);
fclose(file);
return err;
}
struct process_kallsyms_args { struct process_kallsyms_args {
struct map *map; struct map *map;
struct dso *dso; struct dso *dso;
...@@ -739,51 +800,242 @@ bool symbol__restricted_filename(const char *filename, ...@@ -739,51 +800,242 @@ bool symbol__restricted_filename(const char *filename,
return restricted; return restricted;
} }
struct kcore_mapfn_data { struct module_info {
struct dso *dso; struct rb_node rb_node;
enum map_type type; char *name;
struct list_head maps; u64 start;
}; };
static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) static void add_module(struct module_info *mi, struct rb_root *modules)
{ {
struct kcore_mapfn_data *md = data; struct rb_node **p = &modules->rb_node;
struct map *map; struct rb_node *parent = NULL;
struct module_info *m;
map = map__new2(start, md->dso, md->type); while (*p != NULL) {
if (map == NULL) parent = *p;
m = rb_entry(parent, struct module_info, rb_node);
if (strcmp(mi->name, m->name) < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&mi->rb_node, parent, p);
rb_insert_color(&mi->rb_node, modules);
}
static void delete_modules(struct rb_root *modules)
{
struct module_info *mi;
struct rb_node *next = rb_first(modules);
while (next) {
mi = rb_entry(next, struct module_info, rb_node);
next = rb_next(&mi->rb_node);
rb_erase(&mi->rb_node, modules);
free(mi->name);
free(mi);
}
}
static struct module_info *find_module(const char *name,
struct rb_root *modules)
{
struct rb_node *n = modules->rb_node;
while (n) {
struct module_info *m;
int cmp;
m = rb_entry(n, struct module_info, rb_node);
cmp = strcmp(name, m->name);
if (cmp < 0)
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
else
return m;
}
return NULL;
}
static int __read_proc_modules(void *arg, const char *name, u64 start)
{
struct rb_root *modules = arg;
struct module_info *mi;
mi = zalloc(sizeof(struct module_info));
if (!mi)
return -ENOMEM; return -ENOMEM;
map->end = map->start + len; mi->name = strdup(name);
map->pgoff = pgoff; mi->start = start;
list_add(&map->node, &md->maps); if (!mi->name) {
free(mi);
return -ENOMEM;
}
add_module(mi, modules);
return 0;
}
static int read_proc_modules(const char *filename, struct rb_root *modules)
{
if (symbol__restricted_filename(filename, "/proc/modules"))
return -1;
if (modules__parse(filename, modules, __read_proc_modules)) {
delete_modules(modules);
return -1;
}
return 0; return 0;
} }
int compare_proc_modules(const char *from, const char *to)
{
struct rb_root from_modules = RB_ROOT;
struct rb_root to_modules = RB_ROOT;
struct rb_node *from_node, *to_node;
struct module_info *from_m, *to_m;
int ret = -1;
if (read_proc_modules(from, &from_modules))
return -1;
if (read_proc_modules(to, &to_modules))
goto out_delete_from;
from_node = rb_first(&from_modules);
to_node = rb_first(&to_modules);
while (from_node) {
if (!to_node)
break;
from_m = rb_entry(from_node, struct module_info, rb_node);
to_m = rb_entry(to_node, struct module_info, rb_node);
if (from_m->start != to_m->start ||
strcmp(from_m->name, to_m->name))
break;
from_node = rb_next(from_node);
to_node = rb_next(to_node);
}
if (!from_node && !to_node)
ret = 0;
delete_modules(&to_modules);
out_delete_from:
delete_modules(&from_modules);
return ret;
}
static int do_validate_kcore_modules(const char *filename, struct map *map,
struct map_groups *kmaps)
{
struct rb_root modules = RB_ROOT;
struct map *old_map;
int err;
err = read_proc_modules(filename, &modules);
if (err)
return err;
old_map = map_groups__first(kmaps, map->type);
while (old_map) {
struct map *next = map_groups__next(old_map);
struct module_info *mi;
if (old_map == map || old_map->start == map->start) {
/* The kernel map */
old_map = next;
continue;
}
/* Module must be in memory at the same address */
mi = find_module(old_map->dso->short_name, &modules);
if (!mi || mi->start != old_map->start) {
err = -EINVAL;
goto out;
}
old_map = next;
}
out:
delete_modules(&modules);
return err;
}
/* /*
* If kallsyms is referenced by name then we look for kcore in the same * If kallsyms is referenced by name then we look for filename in the same
* directory. * directory.
*/ */
static bool kcore_filename_from_kallsyms_filename(char *kcore_filename, static bool filename_from_kallsyms_filename(char *filename,
const char *kallsyms_filename) const char *base_name,
const char *kallsyms_filename)
{ {
char *name; char *name;
strcpy(kcore_filename, kallsyms_filename); strcpy(filename, kallsyms_filename);
name = strrchr(kcore_filename, '/'); name = strrchr(filename, '/');
if (!name) if (!name)
return false; return false;
if (!strcmp(name, "/kallsyms")) { name += 1;
strcpy(name, "/kcore");
if (!strcmp(name, "kallsyms")) {
strcpy(name, base_name);
return true; return true;
} }
return false; return false;
} }
static int validate_kcore_modules(const char *kallsyms_filename,
struct map *map)
{
struct map_groups *kmaps = map__kmap(map)->kmaps;
char modules_filename[PATH_MAX];
if (!filename_from_kallsyms_filename(modules_filename, "modules",
kallsyms_filename))
return -EINVAL;
if (do_validate_kcore_modules(modules_filename, map, kmaps))
return -EINVAL;
return 0;
}
struct kcore_mapfn_data {
struct dso *dso;
enum map_type type;
struct list_head maps;
};
static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
{
struct kcore_mapfn_data *md = data;
struct map *map;
map = map__new2(start, md->dso, md->type);
if (map == NULL)
return -ENOMEM;
map->end = map->start + len;
map->pgoff = pgoff;
list_add(&map->node, &md->maps);
return 0;
}
static int dso__load_kcore(struct dso *dso, struct map *map, static int dso__load_kcore(struct dso *dso, struct map *map,
const char *kallsyms_filename) const char *kallsyms_filename)
{ {
...@@ -800,8 +1052,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -800,8 +1052,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
if (map != machine->vmlinux_maps[map->type]) if (map != machine->vmlinux_maps[map->type])
return -EINVAL; return -EINVAL;
if (!kcore_filename_from_kallsyms_filename(kcore_filename, if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
kallsyms_filename)) kallsyms_filename))
return -EINVAL;
/* All modules must be present at their original addresses */
if (validate_kcore_modules(kallsyms_filename, map))
return -EINVAL; return -EINVAL;
md.dso = dso; md.dso = dso;
...@@ -1188,6 +1444,105 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, ...@@ -1188,6 +1444,105 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
return err; return err;
} }
static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
{
char kallsyms_filename[PATH_MAX];
struct dirent *dent;
int ret = -1;
DIR *d;
d = opendir(dir);
if (!d)
return -1;
while (1) {
dent = readdir(d);
if (!dent)
break;
if (dent->d_type != DT_DIR)
continue;
scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
"%s/%s/kallsyms", dir, dent->d_name);
if (!validate_kcore_modules(kallsyms_filename, map)) {
strlcpy(dir, kallsyms_filename, dir_sz);
ret = 0;
break;
}
}
closedir(d);
return ret;
}
static char *dso__find_kallsyms(struct dso *dso, struct map *map)
{
u8 host_build_id[BUILD_ID_SIZE];
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
bool is_host = false;
char path[PATH_MAX];
if (!dso->has_build_id) {
/*
* Last resort, if we don't have a build-id and couldn't find
* any vmlinux file, try the running kernel kallsyms table.
*/
goto proc_kallsyms;
}
if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
sizeof(host_build_id)) == 0)
is_host = dso__build_id_equal(dso, host_build_id);
build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
/* Use /proc/kallsyms if possible */
if (is_host) {
DIR *d;
int fd;
/* If no cached kcore go with /proc/kallsyms */
scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
buildid_dir, sbuild_id);
d = opendir(path);
if (!d)
goto proc_kallsyms;
closedir(d);
/*
* Do not check the build-id cache, until we know we cannot use
* /proc/kcore.
*/
fd = open("/proc/kcore", O_RDONLY);
if (fd != -1) {
close(fd);
/* If module maps match go with /proc/kallsyms */
if (!validate_kcore_modules("/proc/kallsyms", map))
goto proc_kallsyms;
}
/* Find kallsyms in build-id cache with kcore */
if (!find_matching_kcore(map, path, sizeof(path)))
return strdup(path);
goto proc_kallsyms;
}
scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
buildid_dir, sbuild_id);
if (access(path, F_OK)) {
pr_err("No kallsyms or vmlinux with build-id %s was found\n",
sbuild_id);
return NULL;
}
return strdup(path);
proc_kallsyms:
return strdup("/proc/kallsyms");
}
static int dso__load_kernel_sym(struct dso *dso, struct map *map, static int dso__load_kernel_sym(struct dso *dso, struct map *map,
symbol_filter_t filter) symbol_filter_t filter)
{ {
...@@ -1214,7 +1569,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, ...@@ -1214,7 +1569,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
goto do_kallsyms; goto do_kallsyms;
} }
if (symbol_conf.vmlinux_name != NULL) { if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
err = dso__load_vmlinux(dso, map, err = dso__load_vmlinux(dso, map,
symbol_conf.vmlinux_name, filter); symbol_conf.vmlinux_name, filter);
if (err > 0) { if (err > 0) {
...@@ -1226,7 +1581,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, ...@@ -1226,7 +1581,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
return err; return err;
} }
if (vmlinux_path != NULL) { if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
err = dso__load_vmlinux_path(dso, map, filter); err = dso__load_vmlinux_path(dso, map, filter);
if (err > 0) if (err > 0)
return err; return err;
...@@ -1236,51 +1591,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, ...@@ -1236,51 +1591,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
if (symbol_conf.symfs[0] != 0) if (symbol_conf.symfs[0] != 0)
return -1; return -1;
/* kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
* Say the kernel DSO was created when processing the build-id header table, if (!kallsyms_allocated_filename)
* we have a build-id, so check if it is the same as the running kernel, return -1;
* using it if it is.
*/
if (dso->has_build_id) {
u8 kallsyms_build_id[BUILD_ID_SIZE];
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
sizeof(kallsyms_build_id)) == 0) {
if (dso__build_id_equal(dso, kallsyms_build_id)) {
kallsyms_filename = "/proc/kallsyms";
goto do_kallsyms;
}
}
/*
* Now look if we have it on the build-id cache in
* $HOME/.debug/[kernel.kallsyms].
*/
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
sbuild_id);
if (asprintf(&kallsyms_allocated_filename,
"%s/.debug/[kernel.kallsyms]/%s",
getenv("HOME"), sbuild_id) == -1) {
pr_err("Not enough memory for kallsyms file lookup\n");
return -1;
}
kallsyms_filename = kallsyms_allocated_filename;
if (access(kallsyms_filename, F_OK)) { kallsyms_filename = kallsyms_allocated_filename;
pr_err("No kallsyms or vmlinux with build-id %s "
"was found\n", sbuild_id);
free(kallsyms_allocated_filename);
return -1;
}
} else {
/*
* Last resort, if we don't have a build-id and couldn't find
* any vmlinux file, try the running kernel kallsyms table.
*/
kallsyms_filename = "/proc/kallsyms";
}
do_kallsyms: do_kallsyms:
err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <libgen.h> #include <libgen.h>
#include "build-id.h" #include "build-id.h"
#ifdef LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
#include <libelf.h> #include <libelf.h>
#include <gelf.h> #include <gelf.h>
#endif #endif
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "dso.h" #include "dso.h"
#ifdef HAVE_CPLUS_DEMANGLE #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
extern char *cplus_demangle(const char *, int); extern char *cplus_demangle(const char *, int);
static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
...@@ -46,7 +46,7 @@ static inline char *bfd_demangle(void __maybe_unused *v, ...@@ -46,7 +46,7 @@ static inline char *bfd_demangle(void __maybe_unused *v,
* libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
* for newer versions we can use mmap to reduce memory usage: * for newer versions we can use mmap to reduce memory usage:
*/ */
#ifdef LIBELF_MMAP #ifdef HAVE_LIBELF_MMAP_SUPPORT
# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP # define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
#else #else
# define PERF_ELF_C_READ_MMAP ELF_C_READ # define PERF_ELF_C_READ_MMAP ELF_C_READ
...@@ -85,6 +85,7 @@ struct symbol_conf { ...@@ -85,6 +85,7 @@ struct symbol_conf {
unsigned short priv_size; unsigned short priv_size;
unsigned short nr_events; unsigned short nr_events;
bool try_vmlinux_path, bool try_vmlinux_path,
ignore_vmlinux,
show_kernel_path, show_kernel_path,
use_modules, use_modules,
sort_by_name, sort_by_name,
...@@ -178,7 +179,7 @@ struct symsrc { ...@@ -178,7 +179,7 @@ struct symsrc {
int fd; int fd;
enum dso_binary_type type; enum dso_binary_type type;
#ifdef LIBELF_SUPPORT #ifdef HAVE_LIBELF_SUPPORT
Elf *elf; Elf *elf;
GElf_Ehdr ehdr; GElf_Ehdr ehdr;
...@@ -222,6 +223,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size); ...@@ -222,6 +223,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
int kallsyms__parse(const char *filename, void *arg, int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name, int (*process_symbol)(void *arg, const char *name,
char type, u64 start)); char type, u64 start));
int modules__parse(const char *filename, void *arg,
int (*process_module)(void *arg, const char *name,
u64 start));
int filename__read_debuglink(const char *filename, char *debuglink, int filename__read_debuglink(const char *filename, char *debuglink,
size_t size); size_t size);
...@@ -252,4 +256,21 @@ typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data); ...@@ -252,4 +256,21 @@ typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
bool *is_64_bit); bool *is_64_bit);
#define PERF_KCORE_EXTRACT "/tmp/perf-kcore-XXXXXX"
struct kcore_extract {
char *kcore_filename;
u64 addr;
u64 offs;
u64 len;
char extract_filename[sizeof(PERF_KCORE_EXTRACT)];
int fd;
};
int kcore_extract__create(struct kcore_extract *kce);
void kcore_extract__delete(struct kcore_extract *kce);
int kcore_copy(const char *from_dir, const char *to_dir);
int compare_proc_modules(const char *from, const char *to);
#endif /* __PERF_SYMBOL */ #endif /* __PERF_SYMBOL */
...@@ -120,42 +120,6 @@ raw_field_value(struct event_format *event, const char *name, void *data) ...@@ -120,42 +120,6 @@ raw_field_value(struct event_format *event, const char *name, void *data)
return val; return val;
} }
void *raw_field_ptr(struct event_format *event, const char *name, void *data)
{
struct format_field *field;
field = pevent_find_any_field(event, name);
if (!field)
return NULL;
if (field->flags & FIELD_IS_DYNAMIC) {
int offset;
offset = *(int *)(data + field->offset);
offset &= 0xffff;
return data + offset;
}
return data + field->offset;
}
int trace_parse_common_type(struct pevent *pevent, void *data)
{
struct pevent_record record;
record.data = data;
return pevent_data_type(pevent, &record);
}
int trace_parse_common_pid(struct pevent *pevent, void *data)
{
struct pevent_record record;
record.data = data;
return pevent_data_pid(pevent, &record);
}
unsigned long long read_size(struct event_format *event, void *ptr, int size) unsigned long long read_size(struct event_format *event, void *ptr, int size)
{ {
return pevent_read_number(event->pevent, ptr, size); return pevent_read_number(event->pevent, ptr, size);
......
...@@ -11,8 +11,6 @@ union perf_event; ...@@ -11,8 +11,6 @@ union perf_event;
struct perf_tool; struct perf_tool;
struct thread; struct thread;
extern struct pevent *perf_pevent;
int bigendian(void); int bigendian(void);
struct pevent *read_trace_init(int file_bigendian, int host_bigendian); struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
...@@ -23,26 +21,19 @@ int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); ...@@ -23,26 +21,19 @@ int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
int parse_event_file(struct pevent *pevent, int parse_event_file(struct pevent *pevent,
char *buf, unsigned long size, char *sys); char *buf, unsigned long size, char *sys);
struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu);
unsigned long long unsigned long long
raw_field_value(struct event_format *event, const char *name, void *data); raw_field_value(struct event_format *event, const char *name, void *data);
void *raw_field_ptr(struct event_format *event, const char *name, void *data);
void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
int trace_parse_common_type(struct pevent *pevent, void *data);
int trace_parse_common_pid(struct pevent *pevent, void *data);
struct event_format *trace_find_next_event(struct pevent *pevent, struct event_format *trace_find_next_event(struct pevent *pevent,
struct event_format *event); struct event_format *event);
unsigned long long read_size(struct event_format *event, void *ptr, int size); unsigned long long read_size(struct event_format *event, void *ptr, int size);
unsigned long long eval_flag(const char *flag); unsigned long long eval_flag(const char *flag);
struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
int read_tracing_data(int fd, struct list_head *pattrs); int read_tracing_data(int fd, struct list_head *pattrs);
struct tracing_data { struct tracing_data {
......
...@@ -13,7 +13,7 @@ struct unwind_entry { ...@@ -13,7 +13,7 @@ struct unwind_entry {
typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
#ifdef LIBUNWIND_SUPPORT #ifdef HAVE_LIBUNWIND_SUPPORT
int unwind__get_entries(unwind_entry_cb_t cb, void *arg, int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct machine *machine, struct machine *machine,
struct thread *thread, struct thread *thread,
...@@ -31,5 +31,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, ...@@ -31,5 +31,5 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
{ {
return 0; return 0;
} }
#endif /* LIBUNWIND_SUPPORT */ #endif /* HAVE_LIBUNWIND_SUPPORT */
#endif /* __UNWIND_H */ #endif /* __UNWIND_H */
#include "../perf.h" #include "../perf.h"
#include "util.h" #include "util.h"
#include <sys/mman.h> #include <sys/mman.h>
#ifdef BACKTRACE_SUPPORT #ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
...@@ -55,17 +55,20 @@ int mkdir_p(char *path, mode_t mode) ...@@ -55,17 +55,20 @@ int mkdir_p(char *path, mode_t mode)
return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
} }
static int slow_copyfile(const char *from, const char *to) static int slow_copyfile(const char *from, const char *to, mode_t mode)
{ {
int err = 0; int err = -1;
char *line = NULL; char *line = NULL;
size_t n; size_t n;
FILE *from_fp = fopen(from, "r"), *to_fp; FILE *from_fp = fopen(from, "r"), *to_fp;
mode_t old_umask;
if (from_fp == NULL) if (from_fp == NULL)
goto out; goto out;
old_umask = umask(mode ^ 0777);
to_fp = fopen(to, "w"); to_fp = fopen(to, "w");
umask(old_umask);
if (to_fp == NULL) if (to_fp == NULL)
goto out_fclose_from; goto out_fclose_from;
...@@ -82,7 +85,7 @@ static int slow_copyfile(const char *from, const char *to) ...@@ -82,7 +85,7 @@ static int slow_copyfile(const char *from, const char *to)
return err; return err;
} }
int copyfile(const char *from, const char *to) int copyfile_mode(const char *from, const char *to, mode_t mode)
{ {
int fromfd, tofd; int fromfd, tofd;
struct stat st; struct stat st;
...@@ -93,13 +96,13 @@ int copyfile(const char *from, const char *to) ...@@ -93,13 +96,13 @@ int copyfile(const char *from, const char *to)
goto out; goto out;
if (st.st_size == 0) /* /proc? do it slowly... */ if (st.st_size == 0) /* /proc? do it slowly... */
return slow_copyfile(from, to); return slow_copyfile(from, to, mode);
fromfd = open(from, O_RDONLY); fromfd = open(from, O_RDONLY);
if (fromfd < 0) if (fromfd < 0)
goto out; goto out;
tofd = creat(to, 0755); tofd = creat(to, mode);
if (tofd < 0) if (tofd < 0)
goto out_close_from; goto out_close_from;
...@@ -121,6 +124,11 @@ int copyfile(const char *from, const char *to) ...@@ -121,6 +124,11 @@ int copyfile(const char *from, const char *to)
return err; return err;
} }
int copyfile(const char *from, const char *to)
{
return copyfile_mode(from, to, 0755);
}
unsigned long convert_unit(unsigned long value, char *unit) unsigned long convert_unit(unsigned long value, char *unit)
{ {
*unit = ' '; *unit = ' ';
...@@ -204,7 +212,7 @@ int hex2u64(const char *ptr, u64 *long_val) ...@@ -204,7 +212,7 @@ int hex2u64(const char *ptr, u64 *long_val)
} }
/* Obtain a backtrace and print it to stdout. */ /* Obtain a backtrace and print it to stdout. */
#ifdef BACKTRACE_SUPPORT #ifdef HAVE_BACKTRACE_SUPPORT
void dump_stack(void) void dump_stack(void)
{ {
void *array[16]; void *array[16];
...@@ -361,3 +369,28 @@ int parse_nsec_time(const char *str, u64 *ptime) ...@@ -361,3 +369,28 @@ int parse_nsec_time(const char *str, u64 *ptime)
*ptime = time_sec * NSEC_PER_SEC + time_nsec; *ptime = time_sec * NSEC_PER_SEC + time_nsec;
return 0; return 0;
} }
unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
{
struct parse_tag *i = tags;
while (i->tag) {
char *s;
s = strchr(str, i->tag);
if (s) {
unsigned long int value;
char *endptr;
value = strtoul(str, &endptr, 10);
if (s != endptr)
break;
value *= i->mult;
return value;
}
i++;
}
return (unsigned long) -1;
}
...@@ -128,6 +128,8 @@ void put_tracing_file(char *file); ...@@ -128,6 +128,8 @@ void put_tracing_file(char *file);
#endif #endif
#endif #endif
#define PERF_GTK_DSO "libperf-gtk.so"
/* General helper functions */ /* General helper functions */
extern void usage(const char *err) NORETURN; extern void usage(const char *err) NORETURN;
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
...@@ -241,6 +243,7 @@ static inline int sane_case(int x, int high) ...@@ -241,6 +243,7 @@ static inline int sane_case(int x, int high)
int mkdir_p(char *path, mode_t mode); int mkdir_p(char *path, mode_t mode);
int copyfile(const char *from, const char *to); int copyfile(const char *from, const char *to);
int copyfile_mode(const char *from, const char *to, mode_t mode);
s64 perf_atoll(const char *str); s64 perf_atoll(const char *str);
char **argv_split(const char *str, int *argcp); char **argv_split(const char *str, int *argcp);
...@@ -270,6 +273,13 @@ bool is_power_of_2(unsigned long n) ...@@ -270,6 +273,13 @@ bool is_power_of_2(unsigned long n)
return (n != 0 && ((n & (n - 1)) == 0)); return (n != 0 && ((n & (n - 1)) == 0));
} }
static inline unsigned next_pow2(unsigned x)
{
if (!x)
return 1;
return 1ULL << (32 - __builtin_clz(x - 1));
}
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);
...@@ -281,4 +291,18 @@ void dump_stack(void); ...@@ -281,4 +291,18 @@ void dump_stack(void);
extern unsigned int page_size; extern unsigned int page_size;
void get_term_dimensions(struct winsize *ws); void get_term_dimensions(struct winsize *ws);
struct parse_tag {
char tag;
int mult;
};
unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
#define SRCLINE_UNKNOWN ((char *) "??:0")
struct dso;
char *get_srcline(struct dso *dso, unsigned long addr);
void free_srcline(char *srcline);
#endif /* GIT_COMPAT_UTIL_H */ #endif /* GIT_COMPAT_UTIL_H */
...@@ -59,21 +59,22 @@ QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir ...@@ -59,21 +59,22 @@ QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
QUIET_SUBDIR1 = QUIET_SUBDIR1 =
ifneq ($(findstring $(MAKEFLAGS),s),s) ifneq ($(findstring $(MAKEFLAGS),s),s)
ifneq ($(V),1) ifneq ($(V),1)
QUIET_CC = @echo ' ' CC $@; QUIET_CC = @echo ' CC '$@;
QUIET_AR = @echo ' ' AR $@; QUIET_AR = @echo ' AR '$@;
QUIET_LINK = @echo ' ' LINK $@; QUIET_LINK = @echo ' LINK '$@;
QUIET_MKDIR = @echo ' ' MKDIR $@; QUIET_MKDIR = @echo ' MKDIR '$@;
QUIET_GEN = @echo ' ' GEN $@; QUIET_GEN = @echo ' GEN '$@;
QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR0 = +@subdir=
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ QUIET_SUBDIR1 = ;$(NO_SUBDIR) \
echo ' SUBDIR '$$subdir; \
$(MAKE) $(PRINT_DIR) -C $$subdir $(MAKE) $(PRINT_DIR) -C $$subdir
QUIET_FLEX = @echo ' ' FLEX $@; QUIET_FLEX = @echo ' FLEX '$@;
QUIET_BISON = @echo ' ' BISON $@; QUIET_BISON = @echo ' BISON '$@;
descend = \ descend = \
+@echo ' ' DESCEND $(1); \ +@echo ' DESCEND '$(1); \
mkdir -p $(OUTPUT)$(1) && \ mkdir -p $(OUTPUT)$(1) && \
$(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
endif endif
endif endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册