Commit 1ff9ecf7 authored by Ingo Molnar's avatar 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 426ee9e3 784f3390
...@@ -138,8 +138,8 @@ else ...@@ -138,8 +138,8 @@ else
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
...@@ -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,25 +184,28 @@ ifdef missing_tools ...@@ -183,25 +184,28 @@ 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_MAN5) $(DESTDIR)$(man5dir); \
# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) # $(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 ;\
...@@ -210,20 +214,13 @@ install-info: info ...@@ -210,20 +214,13 @@ install-info: info
fi fi
install-pdf: pdf install-pdf: pdf
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) $(call QUIET_INSTALL, Documentation-pdf) \
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir); \
$(INSTALL) -m 644 $(OUTPUT)user-manual.pdf $(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]
This diff is collapsed.
This diff is collapsed.
...@@ -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;
}
if (t == 0) {
td->pipe_read = pipe_1[0];
td->pipe_write = pipe_2[1];
} else { } else {
for (i = 0; i < loops; i++) { td->pipe_write = pipe_1[1];
ret = write(pipe_1[1], &m, sizeof(int)); td->pipe_read = pipe_2[0];
ret = read(pipe_2[0], &m, sizeof(int));
} }
} }
gettimeofday(&stop, NULL);
timersub(&stop, &start, &diff);
if (pid) { if (threaded) {
retpid = waitpid(pid, &wait_stat, 0);
assert((retpid == pid) && WIFEXITED(wait_stat)); 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 { } else {
pid = fork();
assert(pid >= 0);
if (!pid) {
worker_thread(threads + 0);
exit(0); exit(0);
} else {
worker_thread(threads + 1);
}
retpid = waitpid(pid, &wait_stat, 0);
assert((retpid == pid) && WIFEXITED(wait_stat));
} }
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);
ret = hist_entry__gtk_annotate(he, evsel, NULL); annotate = dlsym(perf_gtk_handle,
"hist_entry__gtk_annotate");
if (annotate == NULL) {
ui__error("GTK browser not found!\n");
return;
}
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 */
if ((select_key() != 0) || err = dump_info();
(read_events() != 0)) else {
return -1;
sort_result(); sort_result();
print_result(); print_result();
}
return 0; out_delete:
perf_session__delete(session);
return err;
} }
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,
......
This diff is collapsed.
This diff is collapsed.
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
This diff is collapsed.
#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;
}
This diff is collapsed.
#include <stdio.h>
int main(void)
{
return puts("hi");
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment