Commit fa6e8e5f authored by Ingo Molnar's avatar Ingo Molnar

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

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 9450d14f f23b24f1
...@@ -39,10 +39,10 @@ cpupower: FORCE ...@@ -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: ...@@ -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:
......
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 ...@@ -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) ...@@ -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
#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); ...@@ -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,8 +1361,10 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, ...@@ -1361,8 +1361,10 @@ 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);
printf(" '%s: %s'\n", event->event->name, test); if (test) {
free(test); printf(" '%s: %s'\n", event->event->name, test);
free(test);
}
} }
} }
...@@ -2050,7 +2052,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
snprintf(str, 30, "%lld", arg->value.val); asprintf(&str, "%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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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)) ...@@ -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 ...@@ -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 ...@@ -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: ...@@ -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: ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso) ...@@ -28,8 +28,9 @@ 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,
char *root_dir, char *filename, size_t size) enum dso_binary_type type,
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];
int ret = 0; int ret = 0;
...@@ -137,19 +138,18 @@ int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type, ...@@ -137,19 +138,18 @@ 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) ...@@ -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) ...@@ -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 { ...@@ -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,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso, ...@@ -128,8 +128,8 @@ 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);
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
...@@ -159,14 +159,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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' ...@@ -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', ...@@ -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 @@ ...@@ -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; ...@@ -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,9 +44,14 @@ static double cpu2slot(int cpu) ...@@ -39,9 +44,14 @@ 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)
{ {
return cpu2slot(cpu) * SLOT_MULT; if (topology_map)
return cpu2slot(topology_map[cpu]) * SLOT_MULT;
else
return cpu2slot(cpu) * SLOT_MULT;
} }
static double time2pixels(u64 __time) static double time2pixels(u64 __time)
...@@ -104,6 +114,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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,8 +1258,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1258,8 +1258,8 @@ 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;
/* Name is now the name of the next image to try */ /* Name is now the name of the next image to try */
...@@ -1368,9 +1368,9 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment