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 refactorings from Arnaldo Carvalho de Melo: New features: . In perf timechart: - Add backtrace support to CPU info . Print pid along the name . Add support for CPU topology . Add new option --highlight'ing threads, be it by name or, if a numeric value is provided, that run more than given duration. From Stanislav Fomichev. Refactorings: . Rename some struct DSO binary_type related members and methods, to clarify its purpose and need for differentiation from symtab_type, i.e. one is about the files .text, CFI, etc, i.e. its binary contents, and the other is about where the symbol table came from. . Convert to new topic libraries, starting with an API one (sysfs, debugfs, etc), renaming liblk in the process, from Borislav Petkov. . Get rid of some more panic() like error handling in libtraceevent, from Namhyung Kim. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
fa6e8e5f7c
26 changed files with 344 additions and 142 deletions
|
@ -39,10 +39,10 @@ cpupower: FORCE
|
||||||
cgroup firewire guest usb virtio vm net: FORCE
|
cgroup firewire guest usb virtio vm net: FORCE
|
||||||
$(call descend,$@)
|
$(call descend,$@)
|
||||||
|
|
||||||
liblk: FORCE
|
libapikfs: FORCE
|
||||||
$(call descend,lib/lk)
|
$(call descend,lib/api)
|
||||||
|
|
||||||
perf: liblk FORCE
|
perf: libapikfs FORCE
|
||||||
$(call descend,$@)
|
$(call descend,$@)
|
||||||
|
|
||||||
selftests: FORCE
|
selftests: FORCE
|
||||||
|
@ -80,10 +80,10 @@ cpupower_clean:
|
||||||
cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
|
cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
|
||||||
$(call descend,$(@:_clean=),clean)
|
$(call descend,$(@:_clean=),clean)
|
||||||
|
|
||||||
liblk_clean:
|
libapikfs_clean:
|
||||||
$(call descend,lib/lk,clean)
|
$(call descend,lib/api,clean)
|
||||||
|
|
||||||
perf_clean: liblk_clean
|
perf_clean: libapikfs_clean
|
||||||
$(call descend,$(@:_clean=),clean)
|
$(call descend,$(@:_clean=),clean)
|
||||||
|
|
||||||
selftests_clean:
|
selftests_clean:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
include ../../scripts/Makefile.include
|
include ../../scripts/Makefile.include
|
||||||
|
include ../../perf/config/utilities.mak # QUIET_CLEAN
|
||||||
|
|
||||||
CC = $(CROSS_COMPILE)gcc
|
CC = $(CROSS_COMPILE)gcc
|
||||||
AR = $(CROSS_COMPILE)ar
|
AR = $(CROSS_COMPILE)ar
|
||||||
|
@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar
|
||||||
LIB_H=
|
LIB_H=
|
||||||
LIB_OBJS=
|
LIB_OBJS=
|
||||||
|
|
||||||
LIB_H += debugfs.h
|
LIB_H += fs/debugfs.h
|
||||||
|
|
||||||
LIB_OBJS += $(OUTPUT)debugfs.o
|
LIB_OBJS += $(OUTPUT)fs/debugfs.o
|
||||||
|
|
||||||
LIBFILE = liblk.a
|
LIBFILE = libapikfs.a
|
||||||
|
|
||||||
CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
|
CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
|
||||||
EXTLIBS = -lelf -lpthread -lrt -lm
|
EXTLIBS = -lelf -lpthread -lrt -lm
|
||||||
|
@ -25,14 +26,17 @@ $(LIBFILE): $(LIB_OBJS)
|
||||||
|
|
||||||
$(LIB_OBJS): $(LIB_H)
|
$(LIB_OBJS): $(LIB_H)
|
||||||
|
|
||||||
$(OUTPUT)%.o: %.c
|
libapi_dirs:
|
||||||
|
$(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
|
||||||
|
|
||||||
|
$(OUTPUT)%.o: %.c libapi_dirs
|
||||||
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
|
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
|
||||||
$(OUTPUT)%.s: %.c
|
$(OUTPUT)%.s: %.c libapi_dirs
|
||||||
$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
|
$(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
|
||||||
$(OUTPUT)%.o: %.S
|
$(OUTPUT)%.o: %.S libapi_dirs
|
||||||
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
|
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(LIB_OBJS) $(LIBFILE)
|
$(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef __LK_DEBUGFS_H__
|
#ifndef __API_DEBUGFS_H__
|
||||||
#define __LK_DEBUGFS_H__
|
#define __API_DEBUGFS_H__
|
||||||
|
|
||||||
#define _STR(x) #x
|
#define _STR(x) #x
|
||||||
#define STR(x) _STR(x)
|
#define STR(x) _STR(x)
|
||||||
|
@ -26,4 +26,4 @@ char *debugfs_mount(const char *mountpoint);
|
||||||
|
|
||||||
extern char debugfs_mountpoint[];
|
extern char debugfs_mountpoint[];
|
||||||
|
|
||||||
#endif /* __LK_DEBUGFS_H__ */
|
#endif /* __API_DEBUGFS_H__ */
|
|
@ -1361,10 +1361,12 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
||||||
if (ret >= 0 && pevent->test_filters) {
|
if (ret >= 0 && pevent->test_filters) {
|
||||||
char *test;
|
char *test;
|
||||||
test = pevent_filter_make_string(filter, event->event->id);
|
test = pevent_filter_make_string(filter, event->event->id);
|
||||||
|
if (test) {
|
||||||
printf(" '%s: %s'\n", event->event->name, test);
|
printf(" '%s: %s'\n", event->event->name, test);
|
||||||
free(test);
|
free(test);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free_events(events);
|
free_events(events);
|
||||||
|
|
||||||
|
@ -2050,7 +2052,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
int left_val = -1;
|
int left_val = -1;
|
||||||
int right_val = -1;
|
int right_val = -1;
|
||||||
int val;
|
int val;
|
||||||
int len;
|
|
||||||
|
|
||||||
switch (arg->op.type) {
|
switch (arg->op.type) {
|
||||||
case FILTER_OP_AND:
|
case FILTER_OP_AND:
|
||||||
|
@ -2097,11 +2098,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str = malloc_or_die(6);
|
asprintf(&str, val ? "TRUE" : "FALSE");
|
||||||
if (val)
|
|
||||||
strcpy(str, "TRUE");
|
|
||||||
else
|
|
||||||
strcpy(str, "FALSE");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2119,10 +2116,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(left) + strlen(right) + strlen(op) + 10;
|
asprintf(&str, "(%s) %s (%s)", left, op, right);
|
||||||
str = malloc_or_die(len);
|
|
||||||
snprintf(str, len, "(%s) %s (%s)",
|
|
||||||
left, op, right);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FILTER_OP_NOT:
|
case FILTER_OP_NOT:
|
||||||
|
@ -2138,16 +2132,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
right_val = 0;
|
right_val = 0;
|
||||||
if (right_val >= 0) {
|
if (right_val >= 0) {
|
||||||
/* just return the opposite */
|
/* just return the opposite */
|
||||||
str = malloc_or_die(6);
|
asprintf(&str, right_val ? "FALSE" : "TRUE");
|
||||||
if (right_val)
|
|
||||||
strcpy(str, "FALSE");
|
|
||||||
else
|
|
||||||
strcpy(str, "TRUE");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len = strlen(right) + strlen(op) + 3;
|
asprintf(&str, "%s(%s)", op, right);
|
||||||
str = malloc_or_die(len);
|
|
||||||
snprintf(str, len, "%s(%s)", op, right);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2161,11 +2149,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
|
|
||||||
static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
|
static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str = NULL;
|
||||||
|
|
||||||
str = malloc_or_die(30);
|
asprintf(&str, "%lld", arg->value.val);
|
||||||
|
|
||||||
snprintf(str, 30, "%lld", arg->value.val);
|
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -2181,7 +2167,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
char *rstr;
|
char *rstr;
|
||||||
char *op;
|
char *op;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
int len;
|
|
||||||
|
|
||||||
lstr = arg_to_str(filter, arg->exp.left);
|
lstr = arg_to_str(filter, arg->exp.left);
|
||||||
rstr = arg_to_str(filter, arg->exp.right);
|
rstr = arg_to_str(filter, arg->exp.right);
|
||||||
|
@ -2220,12 +2205,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
op = "^";
|
op = "^";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
die("oops in exp");
|
op = "[ERROR IN EXPRESSION TYPE]";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
|
asprintf(&str, "%s %s %s", lstr, op, rstr);
|
||||||
str = malloc_or_die(len);
|
|
||||||
snprintf(str, len, "%s %s %s", lstr, op, rstr);
|
|
||||||
out:
|
out:
|
||||||
free(lstr);
|
free(lstr);
|
||||||
free(rstr);
|
free(rstr);
|
||||||
|
@ -2239,7 +2223,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
char *rstr;
|
char *rstr;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *op = NULL;
|
char *op = NULL;
|
||||||
int len;
|
|
||||||
|
|
||||||
lstr = arg_to_str(filter, arg->num.left);
|
lstr = arg_to_str(filter, arg->num.left);
|
||||||
rstr = arg_to_str(filter, arg->num.right);
|
rstr = arg_to_str(filter, arg->num.right);
|
||||||
|
@ -2270,10 +2253,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
if (!op)
|
if (!op)
|
||||||
op = "<=";
|
op = "<=";
|
||||||
|
|
||||||
len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
|
asprintf(&str, "%s %s %s", lstr, op, rstr);
|
||||||
str = malloc_or_die(len);
|
|
||||||
sprintf(str, "%s %s %s", lstr, op, rstr);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2291,7 +2271,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
{
|
{
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *op = NULL;
|
char *op = NULL;
|
||||||
int len;
|
|
||||||
|
|
||||||
switch (arg->str.type) {
|
switch (arg->str.type) {
|
||||||
case FILTER_CMP_MATCH:
|
case FILTER_CMP_MATCH:
|
||||||
|
@ -2309,12 +2288,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
if (!op)
|
if (!op)
|
||||||
op = "!~";
|
op = "!~";
|
||||||
|
|
||||||
len = strlen(arg->str.field->name) + strlen(op) +
|
asprintf(&str, "%s %s \"%s\"",
|
||||||
strlen(arg->str.val) + 6;
|
arg->str.field->name, op, arg->str.val);
|
||||||
str = malloc_or_die(len);
|
|
||||||
snprintf(str, len, "%s %s \"%s\"",
|
|
||||||
arg->str.field->name,
|
|
||||||
op, arg->str.val);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2326,15 +2301,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
|
|
||||||
static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str = NULL;
|
||||||
|
|
||||||
switch (arg->type) {
|
switch (arg->type) {
|
||||||
case FILTER_ARG_BOOLEAN:
|
case FILTER_ARG_BOOLEAN:
|
||||||
str = malloc_or_die(6);
|
asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE");
|
||||||
if (arg->boolean.value)
|
|
||||||
strcpy(str, "TRUE");
|
|
||||||
else
|
|
||||||
strcpy(str, "FALSE");
|
|
||||||
return str;
|
return str;
|
||||||
|
|
||||||
case FILTER_ARG_OP:
|
case FILTER_ARG_OP:
|
||||||
|
@ -2369,7 +2340,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
||||||
*
|
*
|
||||||
* Returns a string that displays the filter contents.
|
* Returns a string that displays the filter contents.
|
||||||
* This string must be freed with free(str).
|
* This string must be freed with free(str).
|
||||||
* NULL is returned if no filter is found.
|
* NULL is returned if no filter is found or allocation failed.
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
pevent_filter_make_string(struct event_filter *filter, int event_id)
|
pevent_filter_make_string(struct event_filter *filter, int event_id)
|
||||||
|
|
|
@ -56,9 +56,25 @@ $ perf timechart
|
||||||
|
|
||||||
Written 10.2 seconds of trace to output.svg.
|
Written 10.2 seconds of trace to output.svg.
|
||||||
|
|
||||||
|
Record system-wide timechart:
|
||||||
|
|
||||||
|
$ perf timechart record
|
||||||
|
|
||||||
|
then generate timechart and highlight 'gcc' tasks:
|
||||||
|
|
||||||
|
$ perf timechart --highlight gcc
|
||||||
|
|
||||||
-n::
|
-n::
|
||||||
--proc-num::
|
--proc-num::
|
||||||
Print task info for at least given number of tasks.
|
Print task info for at least given number of tasks.
|
||||||
|
-t::
|
||||||
|
--topology::
|
||||||
|
Sort CPUs according to topology.
|
||||||
|
--highlight=<duration_nsecs|task_name>::
|
||||||
|
Highlight tasks (using different color) that run more than given
|
||||||
|
duration or tasks with given name. If number is given it's interpreted
|
||||||
|
as number of nanoseconds. If non-numeric string is given it's
|
||||||
|
interpreted as task name.
|
||||||
|
|
||||||
RECORD OPTIONS
|
RECORD OPTIONS
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -86,7 +86,7 @@ FLEX = flex
|
||||||
BISON = bison
|
BISON = bison
|
||||||
STRIP = strip
|
STRIP = strip
|
||||||
|
|
||||||
LK_DIR = $(srctree)/tools/lib/lk/
|
LIB_DIR = $(srctree)/tools/lib/api/
|
||||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||||
|
|
||||||
# include config/Makefile by default and rule out
|
# include config/Makefile by default and rule out
|
||||||
|
@ -127,20 +127,20 @@ strip-libs = $(filter-out -l%,$(1))
|
||||||
ifneq ($(OUTPUT),)
|
ifneq ($(OUTPUT),)
|
||||||
TE_PATH=$(OUTPUT)
|
TE_PATH=$(OUTPUT)
|
||||||
ifneq ($(subdir),)
|
ifneq ($(subdir),)
|
||||||
LK_PATH=$(OUTPUT)/../lib/lk/
|
LIB_PATH=$(OUTPUT)/../lib/api/
|
||||||
else
|
else
|
||||||
LK_PATH=$(OUTPUT)
|
LIB_PATH=$(OUTPUT)
|
||||||
endif
|
endif
|
||||||
else
|
else
|
||||||
TE_PATH=$(TRACE_EVENT_DIR)
|
TE_PATH=$(TRACE_EVENT_DIR)
|
||||||
LK_PATH=$(LK_DIR)
|
LIB_PATH=$(LIB_DIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
|
||||||
export LIBTRACEEVENT
|
export LIBTRACEEVENT
|
||||||
|
|
||||||
LIBLK = $(LK_PATH)liblk.a
|
LIBAPIKFS = $(LIB_PATH)libapikfs.a
|
||||||
export LIBLK
|
export LIBAPIKFS
|
||||||
|
|
||||||
# python extension build directories
|
# python extension build directories
|
||||||
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
|
||||||
|
@ -151,7 +151,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
|
||||||
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
|
python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
|
||||||
|
|
||||||
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
|
||||||
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK)
|
PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS)
|
||||||
|
|
||||||
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
|
||||||
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
|
$(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
|
||||||
|
@ -441,7 +441,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
|
||||||
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
|
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
|
||||||
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
|
BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
|
||||||
|
|
||||||
PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
|
PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT)
|
||||||
|
|
||||||
# We choose to avoid "if .. else if .. else .. endif endif"
|
# We choose to avoid "if .. else if .. else .. endif endif"
|
||||||
# because maintaining the nesting to match is a pain. If
|
# because maintaining the nesting to match is a pain. If
|
||||||
|
@ -730,19 +730,19 @@ $(LIBTRACEEVENT)-clean:
|
||||||
install-traceevent-plugins: $(LIBTRACEEVENT)
|
install-traceevent-plugins: $(LIBTRACEEVENT)
|
||||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
|
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
|
||||||
|
|
||||||
LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
|
LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
|
||||||
|
|
||||||
# if subdir is set, we've been called from above so target has been built
|
# if subdir is set, we've been called from above so target has been built
|
||||||
# already
|
# already
|
||||||
$(LIBLK): $(LIBLK_SOURCES)
|
$(LIBAPIKFS): $(LIBAPIKFS_SOURCES)
|
||||||
ifeq ($(subdir),)
|
ifeq ($(subdir),)
|
||||||
$(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
|
$(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(LIBLK)-clean:
|
$(LIBAPIKFS)-clean:
|
||||||
ifeq ($(subdir),)
|
ifeq ($(subdir),)
|
||||||
$(call QUIET_CLEAN, liblk)
|
$(call QUIET_CLEAN, libapikfs)
|
||||||
@$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null
|
@$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
|
||||||
endif
|
endif
|
||||||
|
|
||||||
help:
|
help:
|
||||||
|
@ -881,12 +881,11 @@ config-clean:
|
||||||
$(call QUIET_CLEAN, config)
|
$(call QUIET_CLEAN, config)
|
||||||
@$(MAKE) -C config/feature-checks clean >/dev/null
|
@$(MAKE) -C config/feature-checks clean >/dev/null
|
||||||
|
|
||||||
clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean
|
clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
|
||||||
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
|
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
|
||||||
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
|
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
|
||||||
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
|
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
|
||||||
$(call QUIET_CLEAN, Documentation)
|
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||||
@$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
|
|
||||||
$(python-clean)
|
$(python-clean)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "util/parse-options.h"
|
#include "util/parse-options.h"
|
||||||
#include "util/trace-event.h"
|
#include "util/trace-event.h"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "util/tool.h"
|
#include "util/tool.h"
|
||||||
#include "util/stat.h"
|
#include "util/stat.h"
|
||||||
#include "util/top.h"
|
#include "util/top.h"
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include "util/strfilter.h"
|
#include "util/strfilter.h"
|
||||||
#include "util/symbol.h"
|
#include "util/symbol.h"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "util/parse-options.h"
|
#include "util/parse-options.h"
|
||||||
#include "util/probe-finder.h"
|
#include "util/probe-finder.h"
|
||||||
#include "util/probe-event.h"
|
#include "util/probe-event.h"
|
||||||
|
|
|
@ -58,7 +58,8 @@ struct timechart {
|
||||||
first_time, last_time;
|
first_time, last_time;
|
||||||
bool power_only,
|
bool power_only,
|
||||||
tasks_only,
|
tasks_only,
|
||||||
with_backtrace;
|
with_backtrace,
|
||||||
|
topology;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct per_pidcomm;
|
struct per_pidcomm;
|
||||||
|
@ -531,12 +532,10 @@ static int process_sample_event(struct perf_tool *tool,
|
||||||
tchart->last_time = sample->time;
|
tchart->last_time = sample->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample->cpu > tchart->numcpus)
|
|
||||||
tchart->numcpus = sample->cpu;
|
|
||||||
|
|
||||||
if (evsel->handler != NULL) {
|
if (evsel->handler != NULL) {
|
||||||
tracepoint_handler f = evsel->handler;
|
tracepoint_handler f = evsel->handler;
|
||||||
return f(tchart, evsel, sample, cat_backtrace(event, sample, machine));
|
return f(tchart, evsel, sample,
|
||||||
|
cat_backtrace(event, sample, machine));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -837,8 +836,14 @@ static void draw_cpu_usage(struct timechart *tchart)
|
||||||
while (c) {
|
while (c) {
|
||||||
sample = c->samples;
|
sample = c->samples;
|
||||||
while (sample) {
|
while (sample) {
|
||||||
if (sample->type == TYPE_RUNNING)
|
if (sample->type == TYPE_RUNNING) {
|
||||||
svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
|
svg_process(sample->cpu,
|
||||||
|
sample->start_time,
|
||||||
|
sample->end_time,
|
||||||
|
p->pid,
|
||||||
|
c->comm,
|
||||||
|
sample->backtrace);
|
||||||
|
}
|
||||||
|
|
||||||
sample = sample->next;
|
sample = sample->next;
|
||||||
}
|
}
|
||||||
|
@ -1031,8 +1036,6 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
|
||||||
int count;
|
int count;
|
||||||
int thresh = TIME_THRESH;
|
int thresh = TIME_THRESH;
|
||||||
|
|
||||||
tchart->numcpus++;
|
|
||||||
|
|
||||||
if (tchart->power_only)
|
if (tchart->power_only)
|
||||||
tchart->proc_num = 0;
|
tchart->proc_num = 0;
|
||||||
|
|
||||||
|
@ -1062,6 +1065,37 @@ static void write_svg_file(struct timechart *tchart, const char *filename)
|
||||||
svg_close();
|
svg_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int process_header(struct perf_file_section *section __maybe_unused,
|
||||||
|
struct perf_header *ph,
|
||||||
|
int feat,
|
||||||
|
int fd __maybe_unused,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct timechart *tchart = data;
|
||||||
|
|
||||||
|
switch (feat) {
|
||||||
|
case HEADER_NRCPUS:
|
||||||
|
tchart->numcpus = ph->env.nr_cpus_avail;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_CPU_TOPOLOGY:
|
||||||
|
if (!tchart->topology)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (svg_build_topology_map(ph->env.sibling_cores,
|
||||||
|
ph->env.nr_sibling_cores,
|
||||||
|
ph->env.sibling_threads,
|
||||||
|
ph->env.nr_sibling_threads))
|
||||||
|
fprintf(stderr, "problem building topology\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __cmd_timechart(struct timechart *tchart, const char *output_name)
|
static int __cmd_timechart(struct timechart *tchart, const char *output_name)
|
||||||
{
|
{
|
||||||
const struct perf_evsel_str_handler power_tracepoints[] = {
|
const struct perf_evsel_str_handler power_tracepoints[] = {
|
||||||
|
@ -1087,6 +1121,11 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name)
|
||||||
if (session == NULL)
|
if (session == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
(void)perf_header__process_sections(&session->header,
|
||||||
|
perf_data_file__fd(session->file),
|
||||||
|
tchart,
|
||||||
|
process_header);
|
||||||
|
|
||||||
if (!perf_session__has_traces(session, "timechart record"))
|
if (!perf_session__has_traces(session, "timechart record"))
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
|
|
||||||
|
@ -1212,6 +1251,23 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_highlight(const struct option *opt __maybe_unused, const char *arg,
|
||||||
|
int __maybe_unused unset)
|
||||||
|
{
|
||||||
|
unsigned long duration = strtoul(arg, NULL, 0);
|
||||||
|
|
||||||
|
if (svg_highlight || svg_highlight_name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (duration)
|
||||||
|
svg_highlight = duration;
|
||||||
|
else
|
||||||
|
svg_highlight_name = strdup(arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_timechart(int argc, const char **argv,
|
int cmd_timechart(int argc, const char **argv,
|
||||||
const char *prefix __maybe_unused)
|
const char *prefix __maybe_unused)
|
||||||
{
|
{
|
||||||
|
@ -1230,6 +1286,9 @@ int cmd_timechart(int argc, const char **argv,
|
||||||
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
OPT_STRING('i', "input", &input_name, "file", "input file name"),
|
||||||
OPT_STRING('o', "output", &output_name, "file", "output file name"),
|
OPT_STRING('o', "output", &output_name, "file", "output file name"),
|
||||||
OPT_INTEGER('w', "width", &svg_page_width, "page width"),
|
OPT_INTEGER('w', "width", &svg_page_width, "page width"),
|
||||||
|
OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
|
||||||
|
"highlight tasks. Pass duration in ns or process name.",
|
||||||
|
parse_highlight),
|
||||||
OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
|
OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
|
||||||
OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
|
OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
|
||||||
"output processes data only"),
|
"output processes data only"),
|
||||||
|
@ -1240,6 +1299,8 @@ int cmd_timechart(int argc, const char **argv,
|
||||||
"Look for files with symbols relative to this directory"),
|
"Look for files with symbols relative to this directory"),
|
||||||
OPT_INTEGER('n', "proc-num", &tchart.proc_num,
|
OPT_INTEGER('n', "proc-num", &tchart.proc_num,
|
||||||
"min. number of tasks to print"),
|
"min. number of tasks to print"),
|
||||||
|
OPT_BOOLEAN('t', "topology", &tchart.topology,
|
||||||
|
"sort CPUs according to topology"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
const char * const timechart_usage[] = {
|
const char * const timechart_usage[] = {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "util/quote.h"
|
#include "util/quote.h"
|
||||||
#include "util/run-command.h"
|
#include "util/run-command.h"
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
const char perf_usage_string[] =
|
const char perf_usage_string[] =
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include <linux/hw_breakpoint.h>
|
#include <linux/hw_breakpoint.h>
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ char dso__symtab_origin(const struct dso *dso)
|
||||||
return origin[dso->symtab_type];
|
return origin[dso->symtab_type];
|
||||||
}
|
}
|
||||||
|
|
||||||
int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type,
|
int dso__read_binary_type_filename(const struct dso *dso,
|
||||||
|
enum dso_binary_type type,
|
||||||
char *root_dir, char *filename, size_t size)
|
char *root_dir, char *filename, size_t size)
|
||||||
{
|
{
|
||||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||||
|
@ -137,18 +138,17 @@ int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type,
|
||||||
|
|
||||||
static int open_dso(struct dso *dso, struct machine *machine)
|
static int open_dso(struct dso *dso, struct machine *machine)
|
||||||
{
|
{
|
||||||
char *root_dir = (char *) "";
|
|
||||||
char *name;
|
|
||||||
int fd;
|
int fd;
|
||||||
|
char *root_dir = (char *)"";
|
||||||
|
char *name = malloc(PATH_MAX);
|
||||||
|
|
||||||
name = malloc(PATH_MAX);
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (machine)
|
if (machine)
|
||||||
root_dir = machine->root_dir;
|
root_dir = machine->root_dir;
|
||||||
|
|
||||||
if (dso__binary_type_file(dso, dso->data_type,
|
if (dso__read_binary_type_filename(dso, dso->binary_type,
|
||||||
root_dir, name, PATH_MAX)) {
|
root_dir, name, PATH_MAX)) {
|
||||||
free(name);
|
free(name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -161,26 +161,26 @@ static int open_dso(struct dso *dso, struct machine *machine)
|
||||||
|
|
||||||
int dso__data_fd(struct dso *dso, struct machine *machine)
|
int dso__data_fd(struct dso *dso, struct machine *machine)
|
||||||
{
|
{
|
||||||
static enum dso_binary_type binary_type_data[] = {
|
enum dso_binary_type binary_type_data[] = {
|
||||||
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
||||||
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
||||||
DSO_BINARY_TYPE__NOT_FOUND,
|
DSO_BINARY_TYPE__NOT_FOUND,
|
||||||
};
|
};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
|
if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND)
|
||||||
return open_dso(dso, machine);
|
return open_dso(dso, machine);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
dso->data_type = binary_type_data[i++];
|
dso->binary_type = binary_type_data[i++];
|
||||||
|
|
||||||
fd = open_dso(dso, machine);
|
fd = open_dso(dso, machine);
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
} while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
|
} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -475,7 +475,7 @@ struct dso *dso__new(const char *name)
|
||||||
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
||||||
dso->cache = RB_ROOT;
|
dso->cache = RB_ROOT;
|
||||||
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
|
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||||
dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
|
dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||||
dso->loaded = 0;
|
dso->loaded = 0;
|
||||||
dso->rel = 0;
|
dso->rel = 0;
|
||||||
dso->sorted_by_name = 0;
|
dso->sorted_by_name = 0;
|
||||||
|
|
|
@ -83,7 +83,7 @@ struct dso {
|
||||||
enum dso_kernel_type kernel;
|
enum dso_kernel_type kernel;
|
||||||
enum dso_swap_type needs_swap;
|
enum dso_swap_type needs_swap;
|
||||||
enum dso_binary_type symtab_type;
|
enum dso_binary_type symtab_type;
|
||||||
enum dso_binary_type data_type;
|
enum dso_binary_type binary_type;
|
||||||
u8 adjust_symbols:1;
|
u8 adjust_symbols:1;
|
||||||
u8 has_build_id:1;
|
u8 has_build_id:1;
|
||||||
u8 has_srcline:1;
|
u8 has_srcline:1;
|
||||||
|
@ -128,7 +128,7 @@ void dso__read_running_kernel_build_id(struct dso *dso,
|
||||||
int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
|
int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
|
||||||
|
|
||||||
char dso__symtab_origin(const struct dso *dso);
|
char dso__symtab_origin(const struct dso *dso);
|
||||||
int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type,
|
int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
|
||||||
char *root_dir, char *filename, size_t size);
|
char *root_dir, char *filename, size_t size);
|
||||||
|
|
||||||
int dso__data_fd(struct dso *dso, struct machine *machine);
|
int dso__data_fd(struct dso *dso, struct machine *machine);
|
||||||
|
@ -159,14 +159,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
|
||||||
|
|
||||||
static inline bool dso__is_vmlinux(struct dso *dso)
|
static inline bool dso__is_vmlinux(struct dso *dso)
|
||||||
{
|
{
|
||||||
return dso->data_type == DSO_BINARY_TYPE__VMLINUX ||
|
return dso->binary_type == DSO_BINARY_TYPE__VMLINUX ||
|
||||||
dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
|
dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool dso__is_kcore(struct dso *dso)
|
static inline bool dso__is_kcore(struct dso *dso)
|
||||||
{
|
{
|
||||||
return dso->data_type == DSO_BINARY_TYPE__KCORE ||
|
return dso->binary_type == DSO_BINARY_TYPE__KCORE ||
|
||||||
dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
|
dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dso__free_a2l(struct dso *dso);
|
void dso__free_a2l(struct dso *dso);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Released under the GPL v2. (and only v2, not any later version)
|
* Released under the GPL v2. (and only v2, not any later version)
|
||||||
*/
|
*/
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include "cpumap.h"
|
#include "cpumap.h"
|
||||||
#include "thread_map.h"
|
#include "thread_map.h"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include <traceevent/event-parse.h>
|
#include <traceevent/event-parse.h>
|
||||||
#include <linux/hw_breakpoint.h>
|
#include <linux/hw_breakpoint.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "parse-events-bison.h"
|
#include "parse-events-bison.h"
|
||||||
#define YY_EXTRA_TYPE int
|
#define YY_EXTRA_TYPE int
|
||||||
#include "parse-events-flex.h"
|
#include "parse-events-flex.h"
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "trace-event.h" /* For __maybe_unused */
|
#include "trace-event.h" /* For __maybe_unused */
|
||||||
#include "probe-event.h"
|
#include "probe-event.h"
|
||||||
#include "probe-finder.h"
|
#include "probe-finder.h"
|
||||||
|
|
|
@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter'
|
||||||
build_lib = getenv('PYTHON_EXTBUILD_LIB')
|
build_lib = getenv('PYTHON_EXTBUILD_LIB')
|
||||||
build_tmp = getenv('PYTHON_EXTBUILD_TMP')
|
build_tmp = getenv('PYTHON_EXTBUILD_TMP')
|
||||||
libtraceevent = getenv('LIBTRACEEVENT')
|
libtraceevent = getenv('LIBTRACEEVENT')
|
||||||
liblk = getenv('LIBLK')
|
libapikfs = getenv('LIBAPIKFS')
|
||||||
|
|
||||||
ext_sources = [f.strip() for f in file('util/python-ext-sources')
|
ext_sources = [f.strip() for f in file('util/python-ext-sources')
|
||||||
if len(f.strip()) > 0 and f[0] != '#']
|
if len(f.strip()) > 0 and f[0] != '#']
|
||||||
|
@ -34,7 +34,7 @@ perf = Extension('perf',
|
||||||
sources = ext_sources,
|
sources = ext_sources,
|
||||||
include_dirs = ['util/include'],
|
include_dirs = ['util/include'],
|
||||||
extra_compile_args = cflags,
|
extra_compile_args = cflags,
|
||||||
extra_objects = [libtraceevent, liblk],
|
extra_objects = [libtraceevent, libapikfs],
|
||||||
)
|
)
|
||||||
|
|
||||||
setup(name='perf',
|
setup(name='perf',
|
||||||
|
|
|
@ -17,8 +17,11 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
#include "perf.h"
|
||||||
#include "svghelper.h"
|
#include "svghelper.h"
|
||||||
|
#include "cpumap.h"
|
||||||
|
|
||||||
static u64 first_time, last_time;
|
static u64 first_time, last_time;
|
||||||
static u64 turbo_frequency, max_freq;
|
static u64 turbo_frequency, max_freq;
|
||||||
|
@ -28,6 +31,8 @@ static u64 turbo_frequency, max_freq;
|
||||||
#define SLOT_HEIGHT 25.0
|
#define SLOT_HEIGHT 25.0
|
||||||
|
|
||||||
int svg_page_width = 1000;
|
int svg_page_width = 1000;
|
||||||
|
u64 svg_highlight;
|
||||||
|
const char *svg_highlight_name;
|
||||||
|
|
||||||
#define MIN_TEXT_SIZE 0.01
|
#define MIN_TEXT_SIZE 0.01
|
||||||
|
|
||||||
|
@ -39,8 +44,13 @@ static double cpu2slot(int cpu)
|
||||||
return 2 * cpu + 1;
|
return 2 * cpu + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int *topology_map;
|
||||||
|
|
||||||
static double cpu2y(int cpu)
|
static double cpu2y(int cpu)
|
||||||
{
|
{
|
||||||
|
if (topology_map)
|
||||||
|
return cpu2slot(topology_map[cpu]) * SLOT_MULT;
|
||||||
|
else
|
||||||
return cpu2slot(cpu) * SLOT_MULT;
|
return cpu2slot(cpu) * SLOT_MULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +114,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
|
||||||
fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
|
||||||
fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
|
fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
|
||||||
|
@ -147,17 +158,24 @@ void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
|
||||||
void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
|
void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
|
||||||
{
|
{
|
||||||
double text_size;
|
double text_size;
|
||||||
|
const char *type;
|
||||||
|
|
||||||
if (!svgfile)
|
if (!svgfile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (svg_highlight && end - start > svg_highlight)
|
||||||
|
type = "sample_hi";
|
||||||
|
else
|
||||||
|
type = "sample";
|
||||||
fprintf(svgfile, "<g>\n");
|
fprintf(svgfile, "<g>\n");
|
||||||
|
|
||||||
fprintf(svgfile, "<title>#%d running %s</title>\n",
|
fprintf(svgfile, "<title>#%d running %s</title>\n",
|
||||||
cpu, time_to_string(end - start));
|
cpu, time_to_string(end - start));
|
||||||
if (backtrace)
|
if (backtrace)
|
||||||
fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
|
fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
|
||||||
fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n",
|
fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
|
||||||
time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT);
|
time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
|
||||||
|
type);
|
||||||
|
|
||||||
text_size = (time2pixels(end)-time2pixels(start));
|
text_size = (time2pixels(end)-time2pixels(start));
|
||||||
if (cpu > 9)
|
if (cpu > 9)
|
||||||
|
@ -275,7 +293,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
|
||||||
time2pixels(last_time)-time2pixels(first_time),
|
time2pixels(last_time)-time2pixels(first_time),
|
||||||
cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
|
cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
|
||||||
|
|
||||||
sprintf(cpu_string, "CPU %i", (int)cpu+1);
|
sprintf(cpu_string, "CPU %i", (int)cpu);
|
||||||
fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
|
fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
|
||||||
10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
|
10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
|
||||||
|
|
||||||
|
@ -285,16 +303,25 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
|
||||||
fprintf(svgfile, "</g>\n");
|
fprintf(svgfile, "</g>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name)
|
void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
|
||||||
{
|
{
|
||||||
double width;
|
double width;
|
||||||
|
const char *type;
|
||||||
|
|
||||||
if (!svgfile)
|
if (!svgfile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (svg_highlight && end - start >= svg_highlight)
|
||||||
|
type = "sample_hi";
|
||||||
|
else if (svg_highlight_name && strstr(name, svg_highlight_name))
|
||||||
|
type = "sample_hi";
|
||||||
|
else
|
||||||
|
type = "sample";
|
||||||
|
|
||||||
fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
|
fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
|
||||||
fprintf(svgfile, "<title>%s %s</title>\n", name, time_to_string(end - start));
|
fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
|
||||||
|
if (backtrace)
|
||||||
|
fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
|
||||||
fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
|
fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
|
||||||
time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
|
time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
|
||||||
width = time2pixels(end)-time2pixels(start);
|
width = time2pixels(end)-time2pixels(start);
|
||||||
|
@ -566,3 +593,123 @@ void svg_close(void)
|
||||||
svgfile = NULL;
|
svgfile = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define cpumask_bits(maskp) ((maskp)->bits)
|
||||||
|
typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
|
||||||
|
|
||||||
|
struct topology {
|
||||||
|
cpumask_t *sib_core;
|
||||||
|
int sib_core_nr;
|
||||||
|
cpumask_t *sib_thr;
|
||||||
|
int sib_thr_nr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int thr;
|
||||||
|
|
||||||
|
for (i = 0; i < t->sib_thr_nr; i++) {
|
||||||
|
if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for_each_set_bit(thr,
|
||||||
|
cpumask_bits(&t->sib_thr[i]),
|
||||||
|
MAX_NR_CPUS)
|
||||||
|
if (map[thr] == -1)
|
||||||
|
map[thr] = (*pos)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scan_core_topology(int *map, struct topology *t)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
int i;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
for (i = 0; i < t->sib_core_nr; i++)
|
||||||
|
for_each_set_bit(cpu,
|
||||||
|
cpumask_bits(&t->sib_core[i]),
|
||||||
|
MAX_NR_CPUS)
|
||||||
|
scan_thread_topology(map, t, cpu, &pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int str_to_bitmap(char *s, cpumask_t *b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret = 0;
|
||||||
|
struct cpu_map *m;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
m = cpu_map__new(s);
|
||||||
|
if (!m)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < m->nr; i++) {
|
||||||
|
c = m->map[i];
|
||||||
|
if (c >= MAX_NR_CPUS) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bit(c, cpumask_bits(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_map__delete(m);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int svg_build_topology_map(char *sib_core, int sib_core_nr,
|
||||||
|
char *sib_thr, int sib_thr_nr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct topology t;
|
||||||
|
|
||||||
|
t.sib_core_nr = sib_core_nr;
|
||||||
|
t.sib_thr_nr = sib_thr_nr;
|
||||||
|
t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
|
||||||
|
t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));
|
||||||
|
|
||||||
|
if (!t.sib_core || !t.sib_thr) {
|
||||||
|
fprintf(stderr, "topology: no memory\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sib_core_nr; i++) {
|
||||||
|
if (str_to_bitmap(sib_core, &t.sib_core[i])) {
|
||||||
|
fprintf(stderr, "topology: can't parse siblings map\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
sib_core += strlen(sib_core) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sib_thr_nr; i++) {
|
||||||
|
if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
|
||||||
|
fprintf(stderr, "topology: can't parse siblings map\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
sib_thr += strlen(sib_thr) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
|
||||||
|
if (!topology_map) {
|
||||||
|
fprintf(stderr, "topology: no memory\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_NR_CPUS; i++)
|
||||||
|
topology_map[i] = -1;
|
||||||
|
|
||||||
|
scan_core_topology(topology_map, &t);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
free(t.sib_core);
|
||||||
|
free(t.sib_thr);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *back
|
||||||
extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
|
extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
|
||||||
|
|
||||||
|
|
||||||
extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name);
|
extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace);
|
||||||
extern void svg_cstate(int cpu, u64 start, u64 end, int type);
|
extern void svg_cstate(int cpu, u64 start, u64 end, int type);
|
||||||
extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
|
extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
|
||||||
|
|
||||||
|
@ -23,7 +23,11 @@ extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, cha
|
||||||
extern void svg_interrupt(u64 start, int row, const char *backtrace);
|
extern void svg_interrupt(u64 start, int row, const char *backtrace);
|
||||||
extern void svg_text(int Yslot, u64 start, const char *text);
|
extern void svg_text(int Yslot, u64 start, const char *text);
|
||||||
extern void svg_close(void);
|
extern void svg_close(void);
|
||||||
|
extern int svg_build_topology_map(char *sib_core, int sib_core_nr,
|
||||||
|
char *sib_thr, int sib_thr_nr);
|
||||||
|
|
||||||
extern int svg_page_width;
|
extern int svg_page_width;
|
||||||
|
extern u64 svg_highlight;
|
||||||
|
extern const char *svg_highlight_name;
|
||||||
|
|
||||||
#endif /* __PERF_SVGHELPER_H */
|
#endif /* __PERF_SVGHELPER_H */
|
||||||
|
|
|
@ -1089,9 +1089,9 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||||
* dso__data_read_addr().
|
* dso__data_read_addr().
|
||||||
*/
|
*/
|
||||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||||
dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
|
dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
|
||||||
else
|
else
|
||||||
dso->data_type = DSO_BINARY_TYPE__KCORE;
|
dso->binary_type = DSO_BINARY_TYPE__KCORE;
|
||||||
dso__set_long_name(dso, strdup(kcore_filename), true);
|
dso__set_long_name(dso, strdup(kcore_filename), true);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
@ -1258,7 +1258,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||||
|
|
||||||
enum dso_binary_type symtab_type = binary_type_symtab[i];
|
enum dso_binary_type symtab_type = binary_type_symtab[i];
|
||||||
|
|
||||||
if (dso__binary_type_file(dso, symtab_type,
|
if (dso__read_binary_type_filename(dso, symtab_type,
|
||||||
root_dir, name, PATH_MAX))
|
root_dir, name, PATH_MAX))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1368,9 +1368,9 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
|
||||||
|
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||||
dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
|
dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
|
||||||
else
|
else
|
||||||
dso->data_type = DSO_BINARY_TYPE__VMLINUX;
|
dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
|
||||||
dso__set_long_name(dso, vmlinux, vmlinux_allocated);
|
dso__set_long_name(dso, vmlinux, vmlinux_allocated);
|
||||||
dso__set_loaded(dso, map->type);
|
dso__set_loaded(dso, map->type);
|
||||||
pr_debug("Using %s for symbols\n", symfs_vmlinux);
|
pr_debug("Using %s for symbols\n", symfs_vmlinux);
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
#include "../perf.h"
|
#include "../perf.h"
|
||||||
#include "trace-event.h"
|
#include "trace-event.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
|
|
||||||
#define VERSION "0.5"
|
#define VERSION "0.5"
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <sys/ttydefaults.h>
|
#include <sys/ttydefaults.h>
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,21 @@
|
||||||
#
|
#
|
||||||
TARGETS=page-types slabinfo
|
TARGETS=page-types slabinfo
|
||||||
|
|
||||||
LK_DIR = ../lib/lk
|
LIB_DIR = ../lib/api
|
||||||
LIBLK = $(LK_DIR)/liblk.a
|
LIBS = $(LIB_DIR)/libapikfs.a
|
||||||
|
|
||||||
CC = $(CROSS_COMPILE)gcc
|
CC = $(CROSS_COMPILE)gcc
|
||||||
CFLAGS = -Wall -Wextra -I../lib/
|
CFLAGS = -Wall -Wextra -I../lib/
|
||||||
LDFLAGS = $(LIBLK)
|
LDFLAGS = $(LIBS)
|
||||||
|
|
||||||
$(TARGETS): liblk
|
$(TARGETS): $(LIBS)
|
||||||
|
|
||||||
liblk:
|
$(LIBS):
|
||||||
make -C $(LK_DIR)
|
make -C $(LIB_DIR)
|
||||||
|
|
||||||
%: %.c
|
%: %.c
|
||||||
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) page-types slabinfo
|
$(RM) page-types slabinfo
|
||||||
make -C ../lib/lk clean
|
make -C $(LIB_DIR) clean
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#include <sys/statfs.h>
|
#include <sys/statfs.h>
|
||||||
#include "../../include/uapi/linux/magic.h"
|
#include "../../include/uapi/linux/magic.h"
|
||||||
#include "../../include/uapi/linux/kernel-page-flags.h"
|
#include "../../include/uapi/linux/kernel-page-flags.h"
|
||||||
#include <lk/debugfs.h>
|
#include <api/fs/debugfs.h>
|
||||||
|
|
||||||
#ifndef MAX_PATH
|
#ifndef MAX_PATH
|
||||||
# define MAX_PATH 256
|
# define MAX_PATH 256
|
||||||
|
|
Loading…
Add table
Reference in a new issue