You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"This tree includes some late late perf items that missed the first
round:
tools:
- Bash auto completion improvements, now we can auto complete the
tools long options, tracepoint event names, etc, from Namhyung Kim.
- Look up thread using tid instead of pid in 'perf sched'.
- Move global variables into a perf_kvm struct, from David Ahern.
- Hists refactorings, preparatory for improved 'diff' command, from
Jiri Olsa.
- Hists refactorings, preparatory for event group viewieng work, from
Namhyung Kim.
- Remove double negation on optional feature macro definitions, from
Namhyung Kim.
- Remove several cases of needless global variables, on most
builtins.
- misc fixes
kernel:
- sysfs support for IBS on AMD CPUs, from Robert Richter.
- Support for an upcoming Intel CPU, the Xeon-Phi / Knights Corner
HPC blade PMU, from Vince Weaver.
- misc fixes"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (46 commits)
perf: Fix perf_cgroup_switch for sw-events
perf: Clarify perf_cpu_context::active_pmu usage by renaming it to ::unique_pmu
perf/AMD/IBS: Add sysfs support
perf hists: Add more helpers for hist entry stat
perf hists: Move he->stat.nr_events initialization to a template
perf hists: Introduce struct he_stat
perf diff: Removing the total_period argument from output code
perf tool: Add hpp interface to enable/disable hpp column
perf tools: Removing hists pair argument from output path
perf hists: Separate overhead and baseline columns
perf diff: Refactor diff displacement possition info
perf hists: Add struct hists pointer to struct hist_entry
perf tools: Complete tracepoint event names
perf/x86: Add support for Intel Xeon-Phi Knights Corner PMU
perf evlist: Remove some unused methods
perf evlist: Introduce add_newtp method
perf kvm: Move global variables into a perf_kvm struct
perf tools: Convert to BACKTRACE_SUPPORT
perf tools: Long option completion support for each subcommands
perf tools: Complete long option names of perf command
...
This commit is contained in:
+29
-54
@@ -45,6 +45,8 @@ include config/utilities.mak
|
||||
#
|
||||
# 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
|
||||
|
||||
$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
||||
@$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
|
||||
@@ -185,7 +187,7 @@ strip-libs = $(filter-out -l%,$(1))
|
||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
|
||||
|
||||
$(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
||||
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
||||
$(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
|
||||
--quiet build_ext; \
|
||||
mkdir -p $(OUTPUT)python && \
|
||||
@@ -447,20 +449,6 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
|
||||
|
||||
PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
|
||||
|
||||
# Files needed for the python binding, perf.so
|
||||
# pyrf is just an internal name needed for all those wrappers.
|
||||
# This has to be in sync with what is in the 'sources' variable in
|
||||
# tools/perf/util/setup.py
|
||||
|
||||
PYRF_OBJS += $(OUTPUT)util/cpumap.o
|
||||
PYRF_OBJS += $(OUTPUT)util/ctype.o
|
||||
PYRF_OBJS += $(OUTPUT)util/evlist.o
|
||||
PYRF_OBJS += $(OUTPUT)util/evsel.o
|
||||
PYRF_OBJS += $(OUTPUT)util/python.o
|
||||
PYRF_OBJS += $(OUTPUT)util/thread_map.o
|
||||
PYRF_OBJS += $(OUTPUT)util/util.o
|
||||
PYRF_OBJS += $(OUTPUT)util/xyarray.o
|
||||
|
||||
#
|
||||
# Platform specific tweaks
|
||||
#
|
||||
@@ -487,7 +475,13 @@ ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
|
||||
NO_DWARF := 1
|
||||
NO_DEMANGLE := 1
|
||||
endif
|
||||
endif
|
||||
else
|
||||
FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
|
||||
ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),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);
|
||||
NO_DWARF := 1
|
||||
endif # Dwarf support
|
||||
endif # SOURCE_LIBELF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifndef NO_LIBUNWIND
|
||||
@@ -512,8 +506,6 @@ ifneq ($(OUTPUT),)
|
||||
endif
|
||||
|
||||
ifdef NO_LIBELF
|
||||
BASIC_CFLAGS += -DNO_LIBELF_SUPPORT
|
||||
|
||||
EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
|
||||
|
||||
# Remove ELF/DWARF dependent codes
|
||||
@@ -528,17 +520,12 @@ BUILTIN_OBJS := $(filter-out $(OUTPUT)builtin-probe.o,$(BUILTIN_OBJS))
|
||||
LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
|
||||
|
||||
else # NO_LIBELF
|
||||
BASIC_CFLAGS += -DLIBELF_SUPPORT
|
||||
|
||||
ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
|
||||
BASIC_CFLAGS += -DLIBELF_NO_MMAP
|
||||
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
|
||||
BASIC_CFLAGS += -DLIBELF_MMAP
|
||||
endif
|
||||
|
||||
FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
|
||||
ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),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);
|
||||
NO_DWARF := 1
|
||||
endif # Dwarf support
|
||||
|
||||
ifndef NO_DWARF
|
||||
ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
|
||||
msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
|
||||
@@ -551,38 +538,33 @@ endif # PERF_HAVE_DWARF_REGS
|
||||
endif # NO_DWARF
|
||||
endif # NO_LIBELF
|
||||
|
||||
ifdef NO_LIBUNWIND
|
||||
BASIC_CFLAGS += -DNO_LIBUNWIND_SUPPORT
|
||||
else
|
||||
ifndef NO_LIBUNWIND
|
||||
BASIC_CFLAGS += -DLIBUNWIND_SUPPORT
|
||||
EXTLIBS += $(LIBUNWIND_LIBS)
|
||||
BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
|
||||
BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
|
||||
LIB_OBJS += $(OUTPUT)util/unwind.o
|
||||
endif
|
||||
|
||||
ifdef NO_LIBAUDIT
|
||||
BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
|
||||
else
|
||||
ifndef NO_LIBAUDIT
|
||||
FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y)
|
||||
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
|
||||
BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
|
||||
else
|
||||
BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
|
||||
EXTLIBS += -laudit
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NO_NEWT
|
||||
BASIC_CFLAGS += -DNO_NEWT_SUPPORT
|
||||
else
|
||||
ifndef NO_NEWT
|
||||
FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
|
||||
ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
|
||||
msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
|
||||
BASIC_CFLAGS += -DNO_NEWT_SUPPORT
|
||||
else
|
||||
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
|
||||
BASIC_CFLAGS += -I/usr/include/slang
|
||||
BASIC_CFLAGS += -DNEWT_SUPPORT
|
||||
EXTLIBS += -lnewt -lslang
|
||||
LIB_OBJS += $(OUTPUT)ui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/browser.o
|
||||
@@ -604,17 +586,15 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NO_GTK2
|
||||
BASIC_CFLAGS += -DNO_GTK2_SUPPORT
|
||||
else
|
||||
ifndef NO_GTK2
|
||||
FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
|
||||
ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y)
|
||||
msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
|
||||
BASIC_CFLAGS += -DNO_GTK2_SUPPORT
|
||||
else
|
||||
ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
|
||||
BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
|
||||
endif
|
||||
BASIC_CFLAGS += -DGTK2_SUPPORT
|
||||
BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
|
||||
EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
|
||||
@@ -622,7 +602,7 @@ else
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
|
||||
# Make sure that it'd be included only once.
|
||||
ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
|
||||
ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
|
||||
LIB_OBJS += $(OUTPUT)ui/setup.o
|
||||
LIB_OBJS += $(OUTPUT)ui/util.o
|
||||
endif
|
||||
@@ -763,23 +743,18 @@ ifeq ($(NO_PERF_REGS),0)
|
||||
ifeq ($(ARCH),x86)
|
||||
LIB_H += arch/x86/include/perf_regs.h
|
||||
endif
|
||||
else
|
||||
BASIC_CFLAGS += -DNO_PERF_REGS
|
||||
BASIC_CFLAGS += -DHAVE_PERF_REGS
|
||||
endif
|
||||
|
||||
ifdef NO_STRLCPY
|
||||
BASIC_CFLAGS += -DNO_STRLCPY
|
||||
else
|
||||
ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y)
|
||||
BASIC_CFLAGS += -DNO_STRLCPY
|
||||
ifndef NO_STRLCPY
|
||||
ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y)
|
||||
BASIC_CFLAGS += -DHAVE_STRLCPY
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NO_BACKTRACE
|
||||
BASIC_CFLAGS += -DNO_BACKTRACE
|
||||
else
|
||||
ifneq ($(call try-cc,$(SOURCE_BACKTRACE),),y)
|
||||
BASIC_CFLAGS += -DNO_BACKTRACE
|
||||
ifndef NO_BACKTRACE
|
||||
ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y)
|
||||
BASIC_CFLAGS += -DBACKTRACE_SUPPORT
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,23 +1,59 @@
|
||||
# perf completion
|
||||
|
||||
function_exists()
|
||||
{
|
||||
declare -F $1 > /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
function_exists __ltrim_colon_completions ||
|
||||
__ltrim_colon_completions()
|
||||
{
|
||||
if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
|
||||
# Remove colon-word prefix from COMPREPLY items
|
||||
local colon_word=${1%${1##*:}}
|
||||
local i=${#COMPREPLY[*]}
|
||||
while [[ $((--i)) -ge 0 ]]; do
|
||||
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
have perf &&
|
||||
_perf()
|
||||
{
|
||||
local cur cmd
|
||||
local cur prev cmd
|
||||
|
||||
COMPREPLY=()
|
||||
_get_comp_words_by_ref cur prev
|
||||
if function_exists _get_comp_words_by_ref; then
|
||||
_get_comp_words_by_ref -n : cur prev
|
||||
else
|
||||
cur=$(_get_cword :)
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
fi
|
||||
|
||||
cmd=${COMP_WORDS[0]}
|
||||
|
||||
# List perf subcommands
|
||||
# List perf subcommands or long options
|
||||
if [ $COMP_CWORD -eq 1 ]; then
|
||||
cmds=$($cmd --list-cmds)
|
||||
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
|
||||
if [[ $cur == --* ]]; then
|
||||
COMPREPLY=( $( compgen -W '--help --version \
|
||||
--exec-path --html-path --paginate --no-pager \
|
||||
--perf-dir --work-tree --debugfs-dir' -- "$cur" ) )
|
||||
else
|
||||
cmds=$($cmd --list-cmds)
|
||||
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
|
||||
fi
|
||||
# List possible events for -e option
|
||||
elif [[ $prev == "-e" && "${COMP_WORDS[1]}" == @(record|stat|top) ]]; then
|
||||
cmds=$($cmd list --raw-dump)
|
||||
COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) )
|
||||
evts=$($cmd list --raw-dump)
|
||||
COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) )
|
||||
__ltrim_colon_completions $cur
|
||||
# List long option names
|
||||
elif [[ $cur == --* ]]; then
|
||||
subcmd=${COMP_WORDS[1]}
|
||||
opts=$($cmd $subcmd --list-opts)
|
||||
COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) )
|
||||
# Fall down to list regular files
|
||||
else
|
||||
_filedir
|
||||
|
||||
@@ -15,22 +15,6 @@
|
||||
#include "util/strlist.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
static char const *add_name_list_str, *remove_name_list_str;
|
||||
|
||||
static const char * const buildid_cache_usage[] = {
|
||||
"perf buildid-cache [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option buildid_cache_options[] = {
|
||||
OPT_STRING('a', "add", &add_name_list_str,
|
||||
"file list", "file(s) to add"),
|
||||
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
|
||||
"file(s) to remove"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static int build_id_cache__add_file(const char *filename, const char *debugdir)
|
||||
{
|
||||
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||
@@ -51,8 +35,8 @@ static int build_id_cache__add_file(const char *filename, const char *debugdir)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int build_id_cache__remove_file(const char *filename __maybe_unused,
|
||||
const char *debugdir __maybe_unused)
|
||||
static int build_id_cache__remove_file(const char *filename,
|
||||
const char *debugdir)
|
||||
{
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||
@@ -73,11 +57,34 @@ static int build_id_cache__remove_file(const char *filename __maybe_unused,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __cmd_buildid_cache(void)
|
||||
int cmd_buildid_cache(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
{
|
||||
struct strlist *list;
|
||||
struct str_node *pos;
|
||||
char debugdir[PATH_MAX];
|
||||
char const *add_name_list_str = NULL,
|
||||
*remove_name_list_str = NULL;
|
||||
const struct option buildid_cache_options[] = {
|
||||
OPT_STRING('a', "add", &add_name_list_str,
|
||||
"file list", "file(s) to add"),
|
||||
OPT_STRING('r', "remove", &remove_name_list_str, "file list",
|
||||
"file(s) to remove"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const buildid_cache_usage[] = {
|
||||
"perf buildid-cache [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, buildid_cache_options,
|
||||
buildid_cache_usage, 0);
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
setup_pager();
|
||||
|
||||
snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
|
||||
|
||||
@@ -119,16 +126,3 @@ static int __cmd_buildid_cache(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_buildid_cache(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
{
|
||||
argc = parse_options(argc, argv, buildid_cache_options,
|
||||
buildid_cache_usage, 0);
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
setup_pager();
|
||||
return __cmd_buildid_cache();
|
||||
}
|
||||
|
||||
@@ -16,27 +16,6 @@
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
static const char *input_name;
|
||||
static bool force;
|
||||
static bool show_kernel;
|
||||
static bool with_hits;
|
||||
|
||||
static const char * const buildid_list_usage[] = {
|
||||
"perf buildid-list [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"input file name"),
|
||||
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
||||
OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static int sysfs__fprintf_build_id(FILE *fp)
|
||||
{
|
||||
u8 kallsyms_build_id[BUILD_ID_SIZE];
|
||||
@@ -65,7 +44,8 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
|
||||
return fprintf(fp, "%s\n", sbuild_id);
|
||||
}
|
||||
|
||||
static int perf_session__list_build_ids(void)
|
||||
static int perf_session__list_build_ids(const char *input_name,
|
||||
bool force, bool with_hits)
|
||||
{
|
||||
struct perf_session *session;
|
||||
|
||||
@@ -95,18 +75,31 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __cmd_buildid_list(void)
|
||||
{
|
||||
if (show_kernel)
|
||||
return sysfs__fprintf_build_id(stdout);
|
||||
|
||||
return perf_session__list_build_ids();
|
||||
}
|
||||
|
||||
int cmd_buildid_list(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
{
|
||||
bool show_kernel = false;
|
||||
bool with_hits = false;
|
||||
bool force = false;
|
||||
const char *input_name = NULL;
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
||||
OPT_BOOLEAN('k', "kernel", &show_kernel, "Show current kernel build id"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const buildid_list_usage[] = {
|
||||
"perf buildid-list [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, options, buildid_list_usage, 0);
|
||||
setup_pager();
|
||||
return __cmd_buildid_list();
|
||||
|
||||
if (show_kernel)
|
||||
return sysfs__fprintf_build_id(stdout);
|
||||
|
||||
return perf_session__list_build_ids(input_name, force, with_hits);
|
||||
}
|
||||
|
||||
+49
-19
@@ -70,8 +70,8 @@ static struct perf_tool tool = {
|
||||
.ordering_requires_timestamps = true,
|
||||
};
|
||||
|
||||
static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
||||
struct hist_entry *he)
|
||||
static void insert_hist_entry_by_name(struct rb_root *root,
|
||||
struct hist_entry *he)
|
||||
{
|
||||
struct rb_node **p = &root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
@@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
||||
rb_insert_color(&he->rb_node, root);
|
||||
}
|
||||
|
||||
static void hists__resort_entries(struct hists *self)
|
||||
static void hists__name_resort(struct hists *self, bool sort)
|
||||
{
|
||||
unsigned long position = 1;
|
||||
struct rb_root tmp = RB_ROOT;
|
||||
@@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self)
|
||||
struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
|
||||
|
||||
next = rb_next(&n->rb_node);
|
||||
rb_erase(&n->rb_node, &self->entries);
|
||||
n->position = position++;
|
||||
perf_session__insert_hist_entry_by_name(&tmp, n);
|
||||
|
||||
if (sort) {
|
||||
rb_erase(&n->rb_node, &self->entries);
|
||||
insert_hist_entry_by_name(&tmp, n);
|
||||
}
|
||||
}
|
||||
|
||||
self->entries = tmp;
|
||||
if (sort)
|
||||
self->entries = tmp;
|
||||
}
|
||||
|
||||
static struct hist_entry *hists__find_entry(struct hists *self,
|
||||
@@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self,
|
||||
n = n->rb_left;
|
||||
else if (cmp > 0)
|
||||
n = n->rb_right;
|
||||
else
|
||||
else
|
||||
return iter;
|
||||
}
|
||||
|
||||
@@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
struct hists *hists = &evsel->hists;
|
||||
|
||||
hists__output_resort(hists);
|
||||
|
||||
/*
|
||||
* The hists__name_resort only sets possition
|
||||
* if name is false.
|
||||
*/
|
||||
if (name || ((!name) && show_displacement))
|
||||
hists__name_resort(hists, name);
|
||||
}
|
||||
}
|
||||
|
||||
static int __cmd_diff(void)
|
||||
{
|
||||
int ret, i;
|
||||
@@ -176,15 +198,8 @@ static int __cmd_diff(void)
|
||||
evlist_old = older->evlist;
|
||||
evlist_new = newer->evlist;
|
||||
|
||||
list_for_each_entry(evsel, &evlist_new->entries, node)
|
||||
hists__output_resort(&evsel->hists);
|
||||
|
||||
list_for_each_entry(evsel, &evlist_old->entries, node) {
|
||||
hists__output_resort(&evsel->hists);
|
||||
|
||||
if (show_displacement)
|
||||
hists__resort_entries(&evsel->hists);
|
||||
}
|
||||
perf_evlist__resort_hists(evlist_old, true);
|
||||
perf_evlist__resort_hists(evlist_new, false);
|
||||
|
||||
list_for_each_entry(evsel, &evlist_new->entries, node) {
|
||||
struct perf_evsel *evsel_old;
|
||||
@@ -199,8 +214,7 @@ static int __cmd_diff(void)
|
||||
first = false;
|
||||
|
||||
hists__match(&evsel_old->hists, &evsel->hists);
|
||||
hists__fprintf(&evsel->hists, &evsel_old->hists,
|
||||
show_displacement, true, 0, 0, stdout);
|
||||
hists__fprintf(&evsel->hists, true, 0, 0, stdout);
|
||||
}
|
||||
|
||||
out_delete:
|
||||
@@ -242,6 +256,21 @@ static const struct option options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static void ui_init(void)
|
||||
{
|
||||
perf_hpp__init();
|
||||
|
||||
/* No overhead column. */
|
||||
perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
|
||||
|
||||
/* Display baseline/delta/displacement columns. */
|
||||
perf_hpp__column_enable(PERF_HPP__BASELINE, true);
|
||||
perf_hpp__column_enable(PERF_HPP__DELTA, true);
|
||||
|
||||
if (show_displacement)
|
||||
perf_hpp__column_enable(PERF_HPP__DISPL, true);
|
||||
}
|
||||
|
||||
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
sort_order = diff__default_sort_order;
|
||||
@@ -264,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
perf_hpp__init(true, show_displacement);
|
||||
ui_init();
|
||||
|
||||
setup_sorting(diff_usage, options);
|
||||
setup_pager();
|
||||
|
||||
|
||||
@@ -108,23 +108,20 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const evlist_usage[] = {
|
||||
"perf evlist [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
struct perf_attr_details details = { .verbose = false, };
|
||||
const char *input_name = NULL;
|
||||
const struct option options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"Input file name"),
|
||||
OPT_BOOLEAN('F', "freq", &details.freq,
|
||||
"Show the sample frequency"),
|
||||
OPT_BOOLEAN('v', "verbose", &details.verbose,
|
||||
"Show all event attr details"),
|
||||
OPT_END()
|
||||
OPT_STRING('i', "input", &input_name, "file", "Input file name"),
|
||||
OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
|
||||
OPT_BOOLEAN('v', "verbose", &details.verbose,
|
||||
"Show all event attr details"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const evlist_usage[] = {
|
||||
"perf evlist [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, options, evlist_usage, 0);
|
||||
|
||||
+20
-20
@@ -30,23 +30,6 @@ enum help_format {
|
||||
HELP_FORMAT_WEB,
|
||||
};
|
||||
|
||||
static bool show_all = false;
|
||||
static enum help_format help_format = HELP_FORMAT_NONE;
|
||||
static struct option builtin_help_options[] = {
|
||||
OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
|
||||
OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
|
||||
OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
|
||||
HELP_FORMAT_WEB),
|
||||
OPT_SET_UINT('i', "info", &help_format, "show info page",
|
||||
HELP_FORMAT_INFO),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
static const char * const builtin_help_usage[] = {
|
||||
"perf help [--all] [--man|--web|--info] [command]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static enum help_format parse_help_format(const char *format)
|
||||
{
|
||||
if (!strcmp(format, "man"))
|
||||
@@ -258,11 +241,13 @@ static int add_man_viewer_info(const char *var, const char *value)
|
||||
|
||||
static int perf_help_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
enum help_format *help_formatp = cb;
|
||||
|
||||
if (!strcmp(var, "help.format")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
help_format = parse_help_format(value);
|
||||
if (help_format == HELP_FORMAT_NONE)
|
||||
*help_formatp = parse_help_format(value);
|
||||
if (*help_formatp == HELP_FORMAT_NONE)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -428,12 +413,27 @@ static int show_html_page(const char *perf_cmd)
|
||||
|
||||
int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
bool show_all = false;
|
||||
enum help_format help_format = HELP_FORMAT_NONE;
|
||||
struct option builtin_help_options[] = {
|
||||
OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
|
||||
OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
|
||||
OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
|
||||
HELP_FORMAT_WEB),
|
||||
OPT_SET_UINT('i', "info", &help_format, "show info page",
|
||||
HELP_FORMAT_INFO),
|
||||
OPT_END(),
|
||||
};
|
||||
const char * const builtin_help_usage[] = {
|
||||
"perf help [--all] [--man|--web|--info] [command]",
|
||||
NULL
|
||||
};
|
||||
const char *alias;
|
||||
int rc = 0;
|
||||
|
||||
load_command_list("perf-", &main_cmds, &other_cmds);
|
||||
|
||||
perf_config(perf_help_config, NULL);
|
||||
perf_config(perf_help_config, &help_format);
|
||||
|
||||
argc = parse_options(argc, argv, builtin_help_options,
|
||||
builtin_help_usage, 0);
|
||||
|
||||
+45
-43
@@ -14,8 +14,10 @@
|
||||
|
||||
#include "util/parse-options.h"
|
||||
|
||||
static char const *input_name = "-";
|
||||
static bool inject_build_ids;
|
||||
struct perf_inject {
|
||||
struct perf_tool tool;
|
||||
bool build_ids;
|
||||
};
|
||||
|
||||
static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
@@ -194,7 +196,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
|
||||
* account this as unresolved.
|
||||
*/
|
||||
} else {
|
||||
#ifndef NO_LIBELF_SUPPORT
|
||||
#ifdef LIBELF_SUPPORT
|
||||
pr_warning("no symbols found in %s, maybe "
|
||||
"install a debug package?\n",
|
||||
al.map->dso->long_name);
|
||||
@@ -208,22 +210,6 @@ repipe:
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct perf_tool perf_inject = {
|
||||
.sample = perf_event__repipe_sample,
|
||||
.mmap = perf_event__repipe,
|
||||
.comm = perf_event__repipe,
|
||||
.fork = perf_event__repipe,
|
||||
.exit = perf_event__repipe,
|
||||
.lost = perf_event__repipe,
|
||||
.read = perf_event__repipe_sample,
|
||||
.throttle = perf_event__repipe,
|
||||
.unthrottle = perf_event__repipe,
|
||||
.attr = perf_event__repipe_attr,
|
||||
.event_type = perf_event__repipe_event_type_synth,
|
||||
.tracing_data = perf_event__repipe_tracing_data_synth,
|
||||
.build_id = perf_event__repipe_op2_synth,
|
||||
};
|
||||
|
||||
extern volatile int session_done;
|
||||
|
||||
static void sig_handler(int sig __maybe_unused)
|
||||
@@ -231,56 +217,72 @@ static void sig_handler(int sig __maybe_unused)
|
||||
session_done = 1;
|
||||
}
|
||||
|
||||
static int __cmd_inject(void)
|
||||
static int __cmd_inject(struct perf_inject *inject)
|
||||
{
|
||||
struct perf_session *session;
|
||||
int ret = -EINVAL;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
if (inject_build_ids) {
|
||||
perf_inject.sample = perf_event__inject_buildid;
|
||||
perf_inject.mmap = perf_event__repipe_mmap;
|
||||
perf_inject.fork = perf_event__repipe_task;
|
||||
perf_inject.tracing_data = perf_event__repipe_tracing_data;
|
||||
if (inject->build_ids) {
|
||||
inject->tool.sample = perf_event__inject_buildid;
|
||||
inject->tool.mmap = perf_event__repipe_mmap;
|
||||
inject->tool.fork = perf_event__repipe_task;
|
||||
inject->tool.tracing_data = perf_event__repipe_tracing_data;
|
||||
}
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject);
|
||||
session = perf_session__new("-", O_RDONLY, false, true, &inject->tool);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = perf_session__process_events(session, &perf_inject);
|
||||
ret = perf_session__process_events(session, &inject->tool);
|
||||
|
||||
perf_session__delete(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char * const report_usage[] = {
|
||||
"perf inject [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
|
||||
"Inject build-ids into the output stream"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show build ids, etc)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
argc = parse_options(argc, argv, options, report_usage, 0);
|
||||
struct perf_inject inject = {
|
||||
.tool = {
|
||||
.sample = perf_event__repipe_sample,
|
||||
.mmap = perf_event__repipe,
|
||||
.comm = perf_event__repipe,
|
||||
.fork = perf_event__repipe,
|
||||
.exit = perf_event__repipe,
|
||||
.lost = perf_event__repipe,
|
||||
.read = perf_event__repipe_sample,
|
||||
.throttle = perf_event__repipe,
|
||||
.unthrottle = perf_event__repipe,
|
||||
.attr = perf_event__repipe_attr,
|
||||
.event_type = perf_event__repipe_event_type_synth,
|
||||
.tracing_data = perf_event__repipe_tracing_data_synth,
|
||||
.build_id = perf_event__repipe_op2_synth,
|
||||
},
|
||||
};
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
|
||||
"Inject build-ids into the output stream"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show build ids, etc)"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const inject_usage[] = {
|
||||
"perf inject [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, options, inject_usage, 0);
|
||||
|
||||
/*
|
||||
* Any (unrecognized) arguments left?
|
||||
*/
|
||||
if (argc)
|
||||
usage_with_options(report_usage, options);
|
||||
usage_with_options(inject_usage, options);
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
return __cmd_inject();
|
||||
return __cmd_inject(&inject);
|
||||
}
|
||||
|
||||
+26
-40
@@ -21,8 +21,6 @@
|
||||
struct alloc_stat;
|
||||
typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
|
||||
|
||||
static const char *input_name;
|
||||
|
||||
static int alloc_flag;
|
||||
static int caller_flag;
|
||||
|
||||
@@ -31,8 +29,6 @@ static int caller_lines = -1;
|
||||
|
||||
static bool raw_ip;
|
||||
|
||||
static char default_sort_order[] = "frag,hit,bytes";
|
||||
|
||||
static int *cpunode_map;
|
||||
static int max_cpu_num;
|
||||
|
||||
@@ -481,7 +477,7 @@ static void sort_result(void)
|
||||
__sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
|
||||
}
|
||||
|
||||
static int __cmd_kmem(void)
|
||||
static int __cmd_kmem(const char *input_name)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct perf_session *session;
|
||||
@@ -520,11 +516,6 @@ out_delete:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char * const kmem_usage[] = {
|
||||
"perf kmem [<options>] {record|stat}",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r)
|
||||
{
|
||||
if (l->ptr < r->ptr)
|
||||
@@ -720,41 +711,17 @@ static int parse_line_opt(const struct option *opt __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct option kmem_options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"input file name"),
|
||||
OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
|
||||
"show per-callsite statistics",
|
||||
parse_caller_opt),
|
||||
OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
|
||||
"show per-allocation statistics",
|
||||
parse_alloc_opt),
|
||||
OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
|
||||
"sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
|
||||
parse_sort_opt),
|
||||
OPT_CALLBACK('l', "line", NULL, "num",
|
||||
"show n lines",
|
||||
parse_line_opt),
|
||||
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static const char *record_args[] = {
|
||||
"record",
|
||||
"-a",
|
||||
"-R",
|
||||
"-f",
|
||||
"-c", "1",
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
{
|
||||
const char * const record_args[] = {
|
||||
"record", "-a", "-R", "-f", "-c", "1",
|
||||
"-e", "kmem:kmalloc",
|
||||
"-e", "kmem:kmalloc_node",
|
||||
"-e", "kmem:kfree",
|
||||
"-e", "kmem:kmem_cache_alloc",
|
||||
"-e", "kmem:kmem_cache_alloc_node",
|
||||
"-e", "kmem:kmem_cache_free",
|
||||
};
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
{
|
||||
};
|
||||
unsigned int rec_argc, i, j;
|
||||
const char **rec_argv;
|
||||
|
||||
@@ -775,6 +742,25 @@ static int __cmd_record(int argc, const char **argv)
|
||||
|
||||
int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const char * const default_sort_order = "frag,hit,bytes";
|
||||
const char *input_name = NULL;
|
||||
const struct option kmem_options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
|
||||
"show per-callsite statistics", parse_caller_opt),
|
||||
OPT_CALLBACK_NOOPT(0, "alloc", NULL, NULL,
|
||||
"show per-allocation statistics", parse_alloc_opt),
|
||||
OPT_CALLBACK('s', "sort", NULL, "key[,key2...]",
|
||||
"sort by keys: ptr, call_site, bytes, hit, pingpong, frag",
|
||||
parse_sort_opt),
|
||||
OPT_CALLBACK('l', "line", NULL, "num", "show n lines", parse_line_opt),
|
||||
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const kmem_usage[] = {
|
||||
"perf kmem [<options>] {record|stat}",
|
||||
NULL
|
||||
};
|
||||
argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
|
||||
|
||||
if (!argc)
|
||||
@@ -793,7 +779,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (list_empty(&alloc_sort))
|
||||
setup_sorting(&alloc_sort, default_sort_order);
|
||||
|
||||
return __cmd_kmem();
|
||||
return __cmd_kmem(input_name);
|
||||
} else
|
||||
usage_with_options(kmem_usage, kmem_options);
|
||||
|
||||
|
||||
+254
-208
File diff suppressed because it is too large
Load Diff
+39
-51
@@ -823,12 +823,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct perf_tool eops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
|
||||
static const struct perf_evsel_str_handler lock_tracepoints[] = {
|
||||
{ "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
|
||||
{ "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
|
||||
@@ -838,6 +832,11 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = {
|
||||
|
||||
static int read_events(void)
|
||||
{
|
||||
struct perf_tool eops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
|
||||
if (!session) {
|
||||
pr_err("Initializing perf session failed\n");
|
||||
@@ -878,53 +877,11 @@ static int __cmd_report(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const report_usage[] = {
|
||||
"perf lock report [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option report_options[] = {
|
||||
OPT_STRING('k', "key", &sort_key, "acquired",
|
||||
"key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
|
||||
/* TODO: type */
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static const char * const info_usage[] = {
|
||||
"perf lock info [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option info_options[] = {
|
||||
OPT_BOOLEAN('t', "threads", &info_threads,
|
||||
"dump thread list in perf.data"),
|
||||
OPT_BOOLEAN('m', "map", &info_map,
|
||||
"map of lock instances (address:name table)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static const char * const lock_usage[] = {
|
||||
"perf lock [<options>] {record|report|script|info}",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option lock_options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static const char *record_args[] = {
|
||||
"record",
|
||||
"-R",
|
||||
"-f",
|
||||
"-m", "1024",
|
||||
"-c", "1",
|
||||
};
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
{
|
||||
const char *record_args[] = {
|
||||
"record", "-R", "-f", "-m", "1024", "-c", "1",
|
||||
};
|
||||
unsigned int rec_argc, i, j;
|
||||
const char **rec_argv;
|
||||
|
||||
@@ -963,6 +920,37 @@ static int __cmd_record(int argc, const char **argv)
|
||||
|
||||
int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const struct option info_options[] = {
|
||||
OPT_BOOLEAN('t', "threads", &info_threads,
|
||||
"dump thread list in perf.data"),
|
||||
OPT_BOOLEAN('m', "map", &info_map,
|
||||
"map of lock instances (address:name table)"),
|
||||
OPT_END()
|
||||
};
|
||||
const struct option lock_options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
|
||||
OPT_END()
|
||||
};
|
||||
const struct option report_options[] = {
|
||||
OPT_STRING('k', "key", &sort_key, "acquired",
|
||||
"key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
|
||||
/* TODO: type */
|
||||
OPT_END()
|
||||
};
|
||||
const char * const info_usage[] = {
|
||||
"perf lock info [<options>]",
|
||||
NULL
|
||||
};
|
||||
const char * const lock_usage[] = {
|
||||
"perf lock [<options>] {record|report|script|info}",
|
||||
NULL
|
||||
};
|
||||
const char * const report_usage[] = {
|
||||
"perf lock report [<options>]",
|
||||
NULL
|
||||
};
|
||||
unsigned int i;
|
||||
int rc = 0;
|
||||
|
||||
|
||||
+12
-14
@@ -250,19 +250,20 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const probe_usage[] = {
|
||||
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
|
||||
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
||||
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
|
||||
"perf probe --list",
|
||||
int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const char * const probe_usage[] = {
|
||||
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
|
||||
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
||||
"perf probe [<options>] --del '[GROUP:]EVENT' ...",
|
||||
"perf probe --list",
|
||||
#ifdef DWARF_SUPPORT
|
||||
"perf probe [<options>] --line 'LINEDESC'",
|
||||
"perf probe [<options>] --vars 'PROBEPOINT'",
|
||||
"perf probe [<options>] --line 'LINEDESC'",
|
||||
"perf probe [<options>] --vars 'PROBEPOINT'",
|
||||
#endif
|
||||
NULL
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
const struct option options[] = {
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show parsed arguments, etc)"),
|
||||
OPT_BOOLEAN('l', "list", ¶ms.list_events,
|
||||
@@ -325,10 +326,7 @@ static const struct option options[] = {
|
||||
OPT_CALLBACK('x', "exec", NULL, "executable|path",
|
||||
"target executable name or path", opt_set_target),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
};
|
||||
int ret;
|
||||
|
||||
argc = parse_options(argc, argv, options, probe_usage,
|
||||
|
||||
+14
-13
@@ -31,15 +31,6 @@
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
|
||||
|
||||
#ifdef NO_LIBUNWIND_SUPPORT
|
||||
static char callchain_help[] = CALLCHAIN_HELP "[fp]";
|
||||
#else
|
||||
static unsigned long default_stack_dump_size = 8192;
|
||||
static char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
|
||||
#endif
|
||||
|
||||
enum write_mode_t {
|
||||
WRITE_FORCE,
|
||||
WRITE_APPEND
|
||||
@@ -800,7 +791,7 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef NO_LIBUNWIND_SUPPORT
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
static int get_stack_size(char *str, unsigned long *_size)
|
||||
{
|
||||
char *endptr;
|
||||
@@ -826,7 +817,7 @@ static int get_stack_size(char *str, unsigned long *_size)
|
||||
max_size, str);
|
||||
return -1;
|
||||
}
|
||||
#endif /* !NO_LIBUNWIND_SUPPORT */
|
||||
#endif /* LIBUNWIND_SUPPORT */
|
||||
|
||||
static int
|
||||
parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
|
||||
@@ -865,9 +856,11 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
|
||||
"needed for -g fp\n");
|
||||
break;
|
||||
|
||||
#ifndef NO_LIBUNWIND_SUPPORT
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
/* Dwarf style */
|
||||
} else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
|
||||
const unsigned long default_stack_dump_size = 8192;
|
||||
|
||||
ret = 0;
|
||||
rec->opts.call_graph = CALLCHAIN_DWARF;
|
||||
rec->opts.stack_dump_size = default_stack_dump_size;
|
||||
@@ -883,7 +876,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
|
||||
if (!ret)
|
||||
pr_debug("callchain: stack dump size %d\n",
|
||||
rec->opts.stack_dump_size);
|
||||
#endif /* !NO_LIBUNWIND_SUPPORT */
|
||||
#endif /* LIBUNWIND_SUPPORT */
|
||||
} else {
|
||||
pr_err("callchain: Unknown -g option "
|
||||
"value: %s\n", arg);
|
||||
@@ -930,6 +923,14 @@ static struct perf_record record = {
|
||||
.file_new = true,
|
||||
};
|
||||
|
||||
#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
|
||||
|
||||
#ifdef LIBUNWIND_SUPPORT
|
||||
static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
|
||||
#else
|
||||
static const char callchain_help[] = CALLCHAIN_HELP "[fp]";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XXX Will stay a global variable till we fix builtin-script.c to stop messing
|
||||
* with it and switch to use the library functions in perf_evlist that came
|
||||
|
||||
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
|
||||
const char *evname = perf_evsel__name(pos);
|
||||
|
||||
hists__fprintf_nr_sample_events(hists, evname, stdout);
|
||||
hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
|
||||
hists__fprintf(hists, true, 0, 0, stdout);
|
||||
fprintf(stdout, "\n\n");
|
||||
}
|
||||
|
||||
@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
setup_browser(true);
|
||||
else {
|
||||
use_browser = 0;
|
||||
perf_hpp__init(false, false);
|
||||
perf_hpp__init();
|
||||
}
|
||||
|
||||
setup_sorting(report_usage, options);
|
||||
|
||||
@@ -1426,7 +1426,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
|
||||
struct perf_evsel *evsel,
|
||||
struct machine *machine)
|
||||
{
|
||||
struct thread *thread = machine__findnew_thread(machine, sample->pid);
|
||||
struct thread *thread = machine__findnew_thread(machine, sample->tid);
|
||||
int err = 0;
|
||||
|
||||
if (thread == NULL) {
|
||||
|
||||
+53
-59
@@ -24,7 +24,6 @@ static u64 last_timestamp;
|
||||
static u64 nr_unordered;
|
||||
extern const struct option record_options[];
|
||||
static bool no_callchain;
|
||||
static bool show_full_info;
|
||||
static bool system_wide;
|
||||
static const char *cpu_list;
|
||||
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
|
||||
@@ -473,8 +472,6 @@ static int cleanup_scripting(void)
|
||||
return scripting_ops->stop_script();
|
||||
}
|
||||
|
||||
static const char *input_name;
|
||||
|
||||
static int process_sample_event(struct perf_tool *tool __maybe_unused,
|
||||
union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
@@ -1156,62 +1153,6 @@ out:
|
||||
return n_args;
|
||||
}
|
||||
|
||||
static const char * const script_usage[] = {
|
||||
"perf script [<options>]",
|
||||
"perf script [<options>] record <script> [<record-options>] <command>",
|
||||
"perf script [<options>] report <script> [script-args]",
|
||||
"perf script [<options>] <script> [<record-options>] <command>",
|
||||
"perf script [<options>] <top-script> [script-args]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||
"dump raw trace in ASCII"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show symbol address, etc)"),
|
||||
OPT_BOOLEAN('L', "Latency", &latency_format,
|
||||
"show latency attributes (irqs/preemption disabled, etc)"),
|
||||
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
|
||||
list_available_scripts),
|
||||
OPT_CALLBACK('s', "script", NULL, "name",
|
||||
"script file name (lang:script name, script name, or *)",
|
||||
parse_scriptname),
|
||||
OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
|
||||
"generate perf-script.xx script in specified language"),
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"input file name"),
|
||||
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
|
||||
"do various checks like samples ordering and lost events"),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
|
||||
"file", "kallsyms pathname"),
|
||||
OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
|
||||
"When printing symbols do not display call chain"),
|
||||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||
"Look for files with symbols relative to this directory"),
|
||||
OPT_CALLBACK('f', "fields", NULL, "str",
|
||||
"comma separated output fields prepend with 'type:'. "
|
||||
"Valid types: hw,sw,trace,raw. "
|
||||
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
|
||||
"addr,symoff",
|
||||
parse_output_fields),
|
||||
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
|
||||
"only consider these symbols"),
|
||||
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
|
||||
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
|
||||
"only display events for these comms"),
|
||||
OPT_BOOLEAN('I', "show-info", &show_full_info,
|
||||
"display extended information from perf.data file"),
|
||||
OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
|
||||
"Show the path of [kernel.kallsyms]"),
|
||||
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static int have_cmd(int argc, const char **argv)
|
||||
{
|
||||
char **__argv = malloc(sizeof(const char *) * argc);
|
||||
@@ -1233,12 +1174,65 @@ static int have_cmd(int argc, const char **argv)
|
||||
|
||||
int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
bool show_full_info = false;
|
||||
const char *input_name = NULL;
|
||||
char *rec_script_path = NULL;
|
||||
char *rep_script_path = NULL;
|
||||
struct perf_session *session;
|
||||
char *script_path = NULL;
|
||||
const char **__argv;
|
||||
int i, j, err;
|
||||
const struct option options[] = {
|
||||
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
|
||||
"dump raw trace in ASCII"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show symbol address, etc)"),
|
||||
OPT_BOOLEAN('L', "Latency", &latency_format,
|
||||
"show latency attributes (irqs/preemption disabled, etc)"),
|
||||
OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
|
||||
list_available_scripts),
|
||||
OPT_CALLBACK('s', "script", NULL, "name",
|
||||
"script file name (lang:script name, script name, or *)",
|
||||
parse_scriptname),
|
||||
OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
|
||||
"generate perf-script.xx script in specified language"),
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
|
||||
"do various checks like samples ordering and lost events"),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"file", "vmlinux pathname"),
|
||||
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
|
||||
"file", "kallsyms pathname"),
|
||||
OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
|
||||
"When printing symbols do not display call chain"),
|
||||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||
"Look for files with symbols relative to this directory"),
|
||||
OPT_CALLBACK('f', "fields", NULL, "str",
|
||||
"comma separated output fields prepend with 'type:'. "
|
||||
"Valid types: hw,sw,trace,raw. "
|
||||
"Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
|
||||
"addr,symoff", parse_output_fields),
|
||||
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
|
||||
"only consider these symbols"),
|
||||
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
|
||||
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
|
||||
"only display events for these comms"),
|
||||
OPT_BOOLEAN('I', "show-info", &show_full_info,
|
||||
"display extended information from perf.data file"),
|
||||
OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
|
||||
"Show the path of [kernel.kallsyms]"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const script_usage[] = {
|
||||
"perf script [<options>]",
|
||||
"perf script [<options>] record <script> [<record-options>] <command>",
|
||||
"perf script [<options>] report <script> [script-args]",
|
||||
"perf script [<options>] <script> [<record-options>] <command>",
|
||||
"perf script [<options>] <top-script> [script-args]",
|
||||
NULL
|
||||
};
|
||||
|
||||
setup_scripting();
|
||||
|
||||
|
||||
+159
-169
@@ -64,122 +64,12 @@
|
||||
#define CNTR_NOT_SUPPORTED "<not supported>"
|
||||
#define CNTR_NOT_COUNTED "<not counted>"
|
||||
|
||||
static struct perf_event_attr default_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
|
||||
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Detailed stats (-d), covering the L1 and last level data caches:
|
||||
*/
|
||||
static struct perf_event_attr detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_LL << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_LL << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
};
|
||||
|
||||
/*
|
||||
* Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
|
||||
*/
|
||||
static struct perf_event_attr very_detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1I << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1I << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_DTLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_DTLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_ITLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_ITLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Very, very detailed stats (-d -d -d), adding prefetch events:
|
||||
*/
|
||||
static struct perf_event_attr very_very_detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
};
|
||||
|
||||
|
||||
|
||||
static struct perf_evlist *evsel_list;
|
||||
|
||||
static struct perf_target target = {
|
||||
.uid = UINT_MAX,
|
||||
};
|
||||
|
||||
static int run_idx = 0;
|
||||
static int run_count = 1;
|
||||
static bool no_inherit = false;
|
||||
static bool scale = true;
|
||||
@@ -187,15 +77,12 @@ static bool no_aggr = false;
|
||||
static pid_t child_pid = -1;
|
||||
static bool null_run = false;
|
||||
static int detailed_run = 0;
|
||||
static bool sync_run = false;
|
||||
static bool big_num = true;
|
||||
static int big_num_opt = -1;
|
||||
static const char *csv_sep = NULL;
|
||||
static bool csv_output = false;
|
||||
static bool group = false;
|
||||
static const char *output_name = NULL;
|
||||
static FILE *output = NULL;
|
||||
static int output_fd;
|
||||
|
||||
static volatile int done = 0;
|
||||
|
||||
@@ -1028,11 +915,6 @@ static void sig_atexit(void)
|
||||
kill(getpid(), signr);
|
||||
}
|
||||
|
||||
static const char * const stat_usage[] = {
|
||||
"perf stat [<options>] [<command>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int stat__set_big_num(const struct option *opt __maybe_unused,
|
||||
const char *s __maybe_unused, int unset)
|
||||
{
|
||||
@@ -1040,62 +922,119 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool append_file;
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_CALLBACK('e', "event", &evsel_list, "event",
|
||||
"event selector. use 'perf list' to list available events",
|
||||
parse_events_option),
|
||||
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
|
||||
"event filter", parse_filter),
|
||||
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
|
||||
"child tasks do not inherit counters"),
|
||||
OPT_STRING('p', "pid", &target.pid, "pid",
|
||||
"stat events on existing process id"),
|
||||
OPT_STRING('t', "tid", &target.tid, "tid",
|
||||
"stat events on existing thread id"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_BOOLEAN('g', "group", &group,
|
||||
"put the counters into a counter group"),
|
||||
OPT_BOOLEAN('c', "scale", &scale,
|
||||
"scale/normalize counters"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_INTEGER('r', "repeat", &run_count,
|
||||
"repeat command and print average + stddev (max: 100)"),
|
||||
OPT_BOOLEAN('n', "null", &null_run,
|
||||
"null run - dont start any counters"),
|
||||
OPT_INCR('d', "detailed", &detailed_run,
|
||||
"detailed run - start a lot of events"),
|
||||
OPT_BOOLEAN('S', "sync", &sync_run,
|
||||
"call sync() before starting a run"),
|
||||
OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
|
||||
"print large numbers with thousands\' separators",
|
||||
stat__set_big_num),
|
||||
OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
|
||||
"list of cpus to monitor in system-wide"),
|
||||
OPT_BOOLEAN('A', "no-aggr", &no_aggr,
|
||||
"disable CPU count aggregation"),
|
||||
OPT_STRING('x', "field-separator", &csv_sep, "separator",
|
||||
"print counts with custom separator"),
|
||||
OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
|
||||
"monitor event in cgroup name only",
|
||||
parse_cgroups),
|
||||
OPT_STRING('o', "output", &output_name, "file",
|
||||
"output file name"),
|
||||
OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
|
||||
OPT_INTEGER(0, "log-fd", &output_fd,
|
||||
"log output to fd, instead of stderr"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
/*
|
||||
* Add default attributes, if there were no attributes specified or
|
||||
* if -d/--detailed, -d -d or -d -d -d is used:
|
||||
*/
|
||||
static int add_default_attributes(void)
|
||||
{
|
||||
struct perf_event_attr default_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
|
||||
{ .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
|
||||
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
|
||||
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Detailed stats (-d), covering the L1 and last level data caches:
|
||||
*/
|
||||
struct perf_event_attr detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_LL << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_LL << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
};
|
||||
|
||||
/*
|
||||
* Very detailed stats (-d -d), covering the instruction cache and the TLB caches:
|
||||
*/
|
||||
struct perf_event_attr very_detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1I << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1I << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_DTLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_DTLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_ITLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_ITLB << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Very, very detailed stats (-d -d -d), adding prefetch events:
|
||||
*/
|
||||
struct perf_event_attr very_very_detailed_attrs[] = {
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) },
|
||||
|
||||
{ .type = PERF_TYPE_HW_CACHE,
|
||||
.config =
|
||||
PERF_COUNT_HW_CACHE_L1D << 0 |
|
||||
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
|
||||
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
|
||||
};
|
||||
|
||||
/* Set attrs if no event is selected and !null_run: */
|
||||
if (null_run)
|
||||
return 0;
|
||||
@@ -1130,8 +1069,59 @@ static int add_default_attributes(void)
|
||||
|
||||
int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
bool append_file = false,
|
||||
sync_run = false;
|
||||
int output_fd = 0;
|
||||
const char *output_name = NULL;
|
||||
const struct option options[] = {
|
||||
OPT_CALLBACK('e', "event", &evsel_list, "event",
|
||||
"event selector. use 'perf list' to list available events",
|
||||
parse_events_option),
|
||||
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
|
||||
"event filter", parse_filter),
|
||||
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
|
||||
"child tasks do not inherit counters"),
|
||||
OPT_STRING('p', "pid", &target.pid, "pid",
|
||||
"stat events on existing process id"),
|
||||
OPT_STRING('t', "tid", &target.tid, "tid",
|
||||
"stat events on existing thread id"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_BOOLEAN('g', "group", &group,
|
||||
"put the counters into a counter group"),
|
||||
OPT_BOOLEAN('c', "scale", &scale, "scale/normalize counters"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_INTEGER('r', "repeat", &run_count,
|
||||
"repeat command and print average + stddev (max: 100)"),
|
||||
OPT_BOOLEAN('n', "null", &null_run,
|
||||
"null run - dont start any counters"),
|
||||
OPT_INCR('d', "detailed", &detailed_run,
|
||||
"detailed run - start a lot of events"),
|
||||
OPT_BOOLEAN('S', "sync", &sync_run,
|
||||
"call sync() before starting a run"),
|
||||
OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
|
||||
"print large numbers with thousands\' separators",
|
||||
stat__set_big_num),
|
||||
OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
|
||||
"list of cpus to monitor in system-wide"),
|
||||
OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"),
|
||||
OPT_STRING('x', "field-separator", &csv_sep, "separator",
|
||||
"print counts with custom separator"),
|
||||
OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
|
||||
"monitor event in cgroup name only", parse_cgroups),
|
||||
OPT_STRING('o', "output", &output_name, "file", "output file name"),
|
||||
OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
|
||||
OPT_INTEGER(0, "log-fd", &output_fd,
|
||||
"log output to fd, instead of stderr"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const stat_usage[] = {
|
||||
"perf stat [<options>] [<command>]",
|
||||
NULL
|
||||
};
|
||||
struct perf_evsel *pos;
|
||||
int status = -ENOMEM;
|
||||
int status = -ENOMEM, run_idx;
|
||||
const char *mode;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
@@ -38,9 +38,6 @@
|
||||
#define PWR_EVENT_EXIT -1
|
||||
|
||||
|
||||
static const char *input_name;
|
||||
static const char *output_name = "output.svg";
|
||||
|
||||
static unsigned int numcpus;
|
||||
static u64 min_freq; /* Lowest CPU frequency seen */
|
||||
static u64 max_freq; /* Highest CPU frequency seen */
|
||||
@@ -968,16 +965,15 @@ static void write_svg_file(const char *filename)
|
||||
svg_close();
|
||||
}
|
||||
|
||||
static struct perf_tool perf_timechart = {
|
||||
.comm = process_comm_event,
|
||||
.fork = process_fork_event,
|
||||
.exit = process_exit_event,
|
||||
.sample = process_sample_event,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
|
||||
static int __cmd_timechart(void)
|
||||
static int __cmd_timechart(const char *input_name, const char *output_name)
|
||||
{
|
||||
struct perf_tool perf_timechart = {
|
||||
.comm = process_comm_event,
|
||||
.fork = process_fork_event,
|
||||
.exit = process_exit_event,
|
||||
.sample = process_sample_event,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
|
||||
0, false, &perf_timechart);
|
||||
int ret = -EINVAL;
|
||||
@@ -1005,40 +1001,25 @@ out_delete:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char * const timechart_usage[] = {
|
||||
"perf timechart [<options>] {record}",
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef SUPPORT_OLD_POWER_EVENTS
|
||||
static const char * const record_old_args[] = {
|
||||
"record",
|
||||
"-a",
|
||||
"-R",
|
||||
"-f",
|
||||
"-c", "1",
|
||||
"-e", "power:power_start",
|
||||
"-e", "power:power_end",
|
||||
"-e", "power:power_frequency",
|
||||
"-e", "sched:sched_wakeup",
|
||||
"-e", "sched:sched_switch",
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char * const record_new_args[] = {
|
||||
"record",
|
||||
"-a",
|
||||
"-R",
|
||||
"-f",
|
||||
"-c", "1",
|
||||
"-e", "power:cpu_frequency",
|
||||
"-e", "power:cpu_idle",
|
||||
"-e", "sched:sched_wakeup",
|
||||
"-e", "sched:sched_switch",
|
||||
};
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
{
|
||||
#ifdef SUPPORT_OLD_POWER_EVENTS
|
||||
const char * const record_old_args[] = {
|
||||
"record", "-a", "-R", "-f", "-c", "1",
|
||||
"-e", "power:power_start",
|
||||
"-e", "power:power_end",
|
||||
"-e", "power:power_frequency",
|
||||
"-e", "sched:sched_wakeup",
|
||||
"-e", "sched:sched_switch",
|
||||
};
|
||||
#endif
|
||||
const char * const record_new_args[] = {
|
||||
"record", "-a", "-R", "-f", "-c", "1",
|
||||
"-e", "power:cpu_frequency",
|
||||
"-e", "power:cpu_idle",
|
||||
"-e", "sched:sched_wakeup",
|
||||
"-e", "sched:sched_switch",
|
||||
};
|
||||
unsigned int rec_argc, i, j;
|
||||
const char **rec_argv;
|
||||
const char * const *record_args = record_new_args;
|
||||
@@ -1077,27 +1058,28 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct option options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file",
|
||||
"input file name"),
|
||||
OPT_STRING('o', "output", &output_name, "file",
|
||||
"output file name"),
|
||||
OPT_INTEGER('w', "width", &svg_page_width,
|
||||
"page width"),
|
||||
OPT_BOOLEAN('P', "power-only", &power_only,
|
||||
"output power data only"),
|
||||
int cmd_timechart(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
{
|
||||
const char *input_name;
|
||||
const char *output_name = "output.svg";
|
||||
const struct option options[] = {
|
||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||
OPT_STRING('o', "output", &output_name, "file", "output file name"),
|
||||
OPT_INTEGER('w', "width", &svg_page_width, "page width"),
|
||||
OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"),
|
||||
OPT_CALLBACK('p', "process", NULL, "process",
|
||||
"process selector. Pass a pid or process name.",
|
||||
parse_process),
|
||||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||
"Look for files with symbols relative to this directory"),
|
||||
OPT_END()
|
||||
};
|
||||
};
|
||||
const char * const timechart_usage[] = {
|
||||
"perf timechart [<options>] {record}",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
int cmd_timechart(int argc, const char **argv,
|
||||
const char *prefix __maybe_unused)
|
||||
{
|
||||
argc = parse_options(argc, argv, options, timechart_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
@@ -1110,5 +1092,5 @@ int cmd_timechart(int argc, const char **argv,
|
||||
|
||||
setup_pager();
|
||||
|
||||
return __cmd_timechart();
|
||||
return __cmd_timechart(input_name, output_name);
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
|
||||
hists__output_recalc_col_len(&top->sym_evsel->hists,
|
||||
top->winsize.ws_row - 3);
|
||||
putchar('\n');
|
||||
hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
|
||||
hists__fprintf(&top->sym_evsel->hists, false,
|
||||
top->winsize.ws_row - 4 - printed, win_width, stdout);
|
||||
}
|
||||
|
||||
@@ -1159,11 +1159,6 @@ setup:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const top_usage[] = {
|
||||
"perf top [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
struct perf_evsel *pos;
|
||||
@@ -1250,6 +1245,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const top_usage[] = {
|
||||
"perf top [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
top.evlist = perf_evlist__new(NULL, NULL);
|
||||
if (top.evlist == NULL)
|
||||
|
||||
+82
-52
@@ -114,10 +114,85 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL
|
||||
return printed;
|
||||
}
|
||||
|
||||
typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
|
||||
struct perf_sample *sample);
|
||||
|
||||
static struct syscall *trace__syscall_info(struct trace *trace,
|
||||
struct perf_evsel *evsel,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
int id = perf_evsel__intval(evsel, sample, "id");
|
||||
|
||||
if (id < 0) {
|
||||
printf("Invalid syscall %d id, skipping...\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
|
||||
trace__read_syscall_info(trace, id))
|
||||
goto out_cant_read;
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
|
||||
goto out_cant_read;
|
||||
|
||||
return &trace->syscalls.table[id];
|
||||
|
||||
out_cant_read:
|
||||
printf("Problems reading syscall %d information\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
void *args;
|
||||
struct syscall *sc = trace__syscall_info(trace, evsel, sample);
|
||||
|
||||
if (sc == NULL)
|
||||
return -1;
|
||||
|
||||
args = perf_evsel__rawptr(evsel, sample, "args");
|
||||
if (args == NULL) {
|
||||
printf("Problems reading syscall arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%s(", sc->name);
|
||||
syscall__fprintf_args(sc, args, stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
int ret;
|
||||
struct syscall *sc = trace__syscall_info(trace, evsel, sample);
|
||||
|
||||
if (sc == NULL)
|
||||
return -1;
|
||||
|
||||
ret = perf_evsel__intval(evsel, sample, "ret");
|
||||
|
||||
if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
|
||||
char bf[256];
|
||||
const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
|
||||
*e = audit_errno_to_name(-ret);
|
||||
|
||||
printf(") = -1 %s %s", e, emsg);
|
||||
} else if (ret == 0 && sc->fmt && sc->fmt->timeout)
|
||||
printf(") = 0 Timeout");
|
||||
else
|
||||
printf(") = %d", ret);
|
||||
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trace__run(struct trace *trace)
|
||||
{
|
||||
struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
|
||||
struct perf_evsel *evsel, *evsel_enter, *evsel_exit;
|
||||
struct perf_evsel *evsel;
|
||||
int err = -1, i, nr_events = 0, before;
|
||||
|
||||
if (evlist == NULL) {
|
||||
@@ -125,22 +200,12 @@ static int trace__run(struct trace *trace)
|
||||
goto out;
|
||||
}
|
||||
|
||||
evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0);
|
||||
if (evsel_enter == NULL) {
|
||||
printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n");
|
||||
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)) {
|
||||
printf("Couldn't read the raw_syscalls tracepoints information!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__add(evlist, evsel_enter);
|
||||
|
||||
evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1);
|
||||
if (evsel_exit == NULL) {
|
||||
printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__add(evlist, evsel_exit);
|
||||
|
||||
err = perf_evlist__create_maps(evlist, &trace->opts.target);
|
||||
if (err < 0) {
|
||||
printf("Problems parsing the target to trace, check your options!\n");
|
||||
@@ -170,9 +235,8 @@ again:
|
||||
|
||||
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
|
||||
const u32 type = event->header.type;
|
||||
struct syscall *sc;
|
||||
tracepoint_handler handler;
|
||||
struct perf_sample sample;
|
||||
int id;
|
||||
|
||||
++nr_events;
|
||||
|
||||
@@ -200,45 +264,11 @@ again:
|
||||
continue;
|
||||
}
|
||||
|
||||
id = perf_evsel__intval(evsel, &sample, "id");
|
||||
if (id < 0) {
|
||||
printf("Invalid syscall %d id, skipping...\n", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
|
||||
trace__read_syscall_info(trace, id))
|
||||
continue;
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
|
||||
continue;
|
||||
|
||||
sc = &trace->syscalls.table[id];
|
||||
|
||||
if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1)
|
||||
printf("%d ", sample.tid);
|
||||
|
||||
if (evsel == evsel_enter) {
|
||||
void *args = perf_evsel__rawptr(evsel, &sample, "args");
|
||||
|
||||
printf("%s(", sc->name);
|
||||
syscall__fprintf_args(sc, args, stdout);
|
||||
} else if (evsel == evsel_exit) {
|
||||
int ret = perf_evsel__intval(evsel, &sample, "ret");
|
||||
|
||||
if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
|
||||
char bf[256];
|
||||
const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
|
||||
*e = audit_errno_to_name(-ret);
|
||||
|
||||
printf(") = -1 %s %s", e, emsg);
|
||||
} else if (ret == 0 && sc->fmt && sc->fmt->timeout)
|
||||
printf(") = 0 Timeout");
|
||||
else
|
||||
printf(") = %d", ret);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
handler = evsel->handler.func;
|
||||
handler(trace, evsel, &sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user