From 553873e1df63a20559ac9c336765dc7055cfc3d4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 9 Dec 2013 17:14:23 +0100 Subject: tools/: Convert to new topic libraries Move debugfs.* to api/fs/. We have a common tools/lib/api/ place where the Makefile lives and then we place the headers in subdirs. For example, all the fs-related stuff goes to tools/lib/api/fs/ from which we get libapikfs.a (acme got almost the naming he wanted :-)) and we link it into the tools which need it - in this case perf and tools/vm/page-types. acme: "Looking at the implementation, I think some tools can even link directly to the .o files, avoiding the .a file altogether. But that is just an optimization/finer granularity tools/lib/ cherrypicking that toolers can make use of." Fixup documentation cleaning target while at it. Signed-off-by: Borislav Petkov Acked-by: Ingo Molnar Cc: Adrian Hunter Cc: Andi Kleen Cc: Arjan van de Ven Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Robert Richter Cc: Stanislav Fomichev Cc: Stephane Eranian Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1386605664-24041-2-git-send-email-bp@alien8.de Signed-off-by: Arnaldo Carvalho de Melo --- tools/Makefile | 12 ++--- tools/lib/api/Makefile | 42 ++++++++++++++++ tools/lib/api/fs/debugfs.c | 100 +++++++++++++++++++++++++++++++++++++ tools/lib/api/fs/debugfs.h | 29 +++++++++++ tools/lib/lk/Makefile | 38 -------------- tools/lib/lk/debugfs.c | 100 ------------------------------------- tools/lib/lk/debugfs.h | 29 ----------- tools/perf/Makefile.perf | 33 ++++++------ tools/perf/builtin-kvm.c | 2 +- tools/perf/builtin-probe.c | 2 +- tools/perf/perf.c | 2 +- tools/perf/tests/parse-events.c | 2 +- tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 2 +- tools/perf/util/parse-events.c | 2 +- tools/perf/util/probe-event.c | 2 +- tools/perf/util/setup.py | 4 +- tools/perf/util/trace-event-info.c | 2 +- tools/perf/util/util.h | 2 +- tools/vm/Makefile | 14 +++--- tools/vm/page-types.c | 2 +- 21 files changed, 213 insertions(+), 210 deletions(-) create mode 100644 tools/lib/api/Makefile create mode 100644 tools/lib/api/fs/debugfs.c create mode 100644 tools/lib/api/fs/debugfs.h delete mode 100644 tools/lib/lk/Makefile delete mode 100644 tools/lib/lk/debugfs.c delete mode 100644 tools/lib/lk/debugfs.h diff --git a/tools/Makefile b/tools/Makefile index a9b02008443..927cd46d36d 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -39,10 +39,10 @@ cpupower: FORCE cgroup firewire guest usb virtio vm net: FORCE $(call descend,$@) -liblk: FORCE - $(call descend,lib/lk) +libapikfs: FORCE + $(call descend,lib/api) -perf: liblk FORCE +perf: libapikfs FORCE $(call descend,$@) selftests: FORCE @@ -80,10 +80,10 @@ cpupower_clean: cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: $(call descend,$(@:_clean=),clean) -liblk_clean: - $(call descend,lib/lk,clean) +libapikfs_clean: + $(call descend,lib/api,clean) -perf_clean: liblk_clean +perf_clean: libapikfs_clean $(call descend,$(@:_clean=),clean) selftests_clean: diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile new file mode 100644 index 00000000000..ed2f51e11b8 --- /dev/null +++ b/tools/lib/api/Makefile @@ -0,0 +1,42 @@ +include ../../scripts/Makefile.include +include ../../perf/config/utilities.mak # QUIET_CLEAN + +CC = $(CROSS_COMPILE)gcc +AR = $(CROSS_COMPILE)ar + +# guard against environment variables +LIB_H= +LIB_OBJS= + +LIB_H += fs/debugfs.h + +LIB_OBJS += $(OUTPUT)fs/debugfs.o + +LIBFILE = libapikfs.a + +CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC +EXTLIBS = -lelf -lpthread -lrt -lm +ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +ALL_LDFLAGS = $(LDFLAGS) + +RM = rm -f + +$(LIBFILE): $(LIB_OBJS) + $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS) + +$(LIB_OBJS): $(LIB_H) + +libapi_dirs: + $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/ + +$(OUTPUT)%.o: %.c libapi_dirs + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< +$(OUTPUT)%.s: %.c libapi_dirs + $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< +$(OUTPUT)%.o: %.S libapi_dirs + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< + +clean: + $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE) + +.PHONY: clean diff --git a/tools/lib/api/fs/debugfs.c b/tools/lib/api/fs/debugfs.c new file mode 100644 index 00000000000..7c434796235 --- /dev/null +++ b/tools/lib/api/fs/debugfs.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debugfs.h" + +char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; + +static const char * const debugfs_known_mountpoints[] = { + "/sys/kernel/debug/", + "/debug/", + 0, +}; + +static bool debugfs_found; + +/* find the path to the mounted debugfs */ +const char *debugfs_find_mountpoint(void) +{ + const char * const *ptr; + char type[100]; + FILE *fp; + + if (debugfs_found) + return (const char *)debugfs_mountpoint; + + ptr = debugfs_known_mountpoints; + while (*ptr) { + if (debugfs_valid_mountpoint(*ptr) == 0) { + debugfs_found = true; + strcpy(debugfs_mountpoint, *ptr); + return debugfs_mountpoint; + } + ptr++; + } + + /* give up and parse /proc/mounts */ + fp = fopen("/proc/mounts", "r"); + if (fp == NULL) + return NULL; + + while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", + debugfs_mountpoint, type) == 2) { + if (strcmp(type, "debugfs") == 0) + break; + } + fclose(fp); + + if (strcmp(type, "debugfs") != 0) + return NULL; + + debugfs_found = true; + + return debugfs_mountpoint; +} + +/* verify that a mountpoint is actually a debugfs instance */ + +int debugfs_valid_mountpoint(const char *debugfs) +{ + struct statfs st_fs; + + if (statfs(debugfs, &st_fs) < 0) + return -ENOENT; + else if (st_fs.f_type != (long) DEBUGFS_MAGIC) + return -ENOENT; + + return 0; +} + +/* mount the debugfs somewhere if it's not mounted */ +char *debugfs_mount(const char *mountpoint) +{ + /* see if it's already mounted */ + if (debugfs_find_mountpoint()) + goto out; + + /* if not mounted and no argument */ + if (mountpoint == NULL) { + /* see if environment variable set */ + mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); + /* if no environment variable, use default */ + if (mountpoint == NULL) + mountpoint = "/sys/kernel/debug"; + } + + if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) + return NULL; + + /* save the mountpoint */ + debugfs_found = true; + strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); +out: + return debugfs_mountpoint; +} diff --git a/tools/lib/api/fs/debugfs.h b/tools/lib/api/fs/debugfs.h new file mode 100644 index 00000000000..f19d3df9609 --- /dev/null +++ b/tools/lib/api/fs/debugfs.h @@ -0,0 +1,29 @@ +#ifndef __API_DEBUGFS_H__ +#define __API_DEBUGFS_H__ + +#define _STR(x) #x +#define STR(x) _STR(x) + +/* + * On most systems would have given us this, but not on some systems + * (e.g. GNU/Hurd). + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#ifndef PERF_DEBUGFS_ENVIRONMENT +#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" +#endif + +const char *debugfs_find_mountpoint(void); +int debugfs_valid_mountpoint(const char *debugfs); +char *debugfs_mount(const char *mountpoint); + +extern char debugfs_mountpoint[]; + +#endif /* __API_DEBUGFS_H__ */ diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile deleted file mode 100644 index 3dba0a4aebb..00000000000 --- a/tools/lib/lk/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -include ../../scripts/Makefile.include - -CC = $(CROSS_COMPILE)gcc -AR = $(CROSS_COMPILE)ar - -# guard against environment variables -LIB_H= -LIB_OBJS= - -LIB_H += debugfs.h - -LIB_OBJS += $(OUTPUT)debugfs.o - -LIBFILE = liblk.a - -CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC -EXTLIBS = -lelf -lpthread -lrt -lm -ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ALL_LDFLAGS = $(LDFLAGS) - -RM = rm -f - -$(LIBFILE): $(LIB_OBJS) - $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS) - -$(LIB_OBJS): $(LIB_H) - -$(OUTPUT)%.o: %.c - $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< -$(OUTPUT)%.s: %.c - $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< -$(OUTPUT)%.o: %.S - $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< - -clean: - $(RM) $(LIB_OBJS) $(LIBFILE) - -.PHONY: clean diff --git a/tools/lib/lk/debugfs.c b/tools/lib/lk/debugfs.c deleted file mode 100644 index 7c434796235..00000000000 --- a/tools/lib/lk/debugfs.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debugfs.h" - -char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; - -static const char * const debugfs_known_mountpoints[] = { - "/sys/kernel/debug/", - "/debug/", - 0, -}; - -static bool debugfs_found; - -/* find the path to the mounted debugfs */ -const char *debugfs_find_mountpoint(void) -{ - const char * const *ptr; - char type[100]; - FILE *fp; - - if (debugfs_found) - return (const char *)debugfs_mountpoint; - - ptr = debugfs_known_mountpoints; - while (*ptr) { - if (debugfs_valid_mountpoint(*ptr) == 0) { - debugfs_found = true; - strcpy(debugfs_mountpoint, *ptr); - return debugfs_mountpoint; - } - ptr++; - } - - /* give up and parse /proc/mounts */ - fp = fopen("/proc/mounts", "r"); - if (fp == NULL) - return NULL; - - while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", - debugfs_mountpoint, type) == 2) { - if (strcmp(type, "debugfs") == 0) - break; - } - fclose(fp); - - if (strcmp(type, "debugfs") != 0) - return NULL; - - debugfs_found = true; - - return debugfs_mountpoint; -} - -/* verify that a mountpoint is actually a debugfs instance */ - -int debugfs_valid_mountpoint(const char *debugfs) -{ - struct statfs st_fs; - - if (statfs(debugfs, &st_fs) < 0) - return -ENOENT; - else if (st_fs.f_type != (long) DEBUGFS_MAGIC) - return -ENOENT; - - return 0; -} - -/* mount the debugfs somewhere if it's not mounted */ -char *debugfs_mount(const char *mountpoint) -{ - /* see if it's already mounted */ - if (debugfs_find_mountpoint()) - goto out; - - /* if not mounted and no argument */ - if (mountpoint == NULL) { - /* see if environment variable set */ - mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); - /* if no environment variable, use default */ - if (mountpoint == NULL) - mountpoint = "/sys/kernel/debug"; - } - - if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) - return NULL; - - /* save the mountpoint */ - debugfs_found = true; - strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); -out: - return debugfs_mountpoint; -} diff --git a/tools/lib/lk/debugfs.h b/tools/lib/lk/debugfs.h deleted file mode 100644 index 935c59bdb44..00000000000 --- a/tools/lib/lk/debugfs.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __LK_DEBUGFS_H__ -#define __LK_DEBUGFS_H__ - -#define _STR(x) #x -#define STR(x) _STR(x) - -/* - * On most systems would have given us this, but not on some systems - * (e.g. GNU/Hurd). - */ -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -#ifndef DEBUGFS_MAGIC -#define DEBUGFS_MAGIC 0x64626720 -#endif - -#ifndef PERF_DEBUGFS_ENVIRONMENT -#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" -#endif - -const char *debugfs_find_mountpoint(void); -int debugfs_valid_mountpoint(const char *debugfs); -char *debugfs_mount(const char *mountpoint); - -extern char debugfs_mountpoint[]; - -#endif /* __LK_DEBUGFS_H__ */ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index fad61079e79..97a2145e4cc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -86,7 +86,7 @@ FLEX = flex BISON = bison STRIP = strip -LK_DIR = $(srctree)/tools/lib/lk/ +LIB_DIR = $(srctree)/tools/lib/api/ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ # include config/Makefile by default and rule out @@ -127,20 +127,20 @@ strip-libs = $(filter-out -l%,$(1)) ifneq ($(OUTPUT),) TE_PATH=$(OUTPUT) ifneq ($(subdir),) - LK_PATH=$(OUTPUT)/../lib/lk/ + LIB_PATH=$(OUTPUT)/../lib/api/ else - LK_PATH=$(OUTPUT) + LIB_PATH=$(OUTPUT) endif else TE_PATH=$(TRACE_EVENT_DIR) - LK_PATH=$(LK_DIR) + LIB_PATH=$(LIB_DIR) endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a export LIBTRACEEVENT -LIBLK = $(LK_PATH)liblk.a -export LIBLK +LIBAPIKFS = $(LIB_PATH)libapikfs.a +export LIBAPIKFS # python extension build directories 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_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) $(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)builtin-mem.o -PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) +PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT) # We choose to avoid "if .. else if .. else .. endif endif" # because maintaining the nesting to match is a pain. If @@ -730,19 +730,19 @@ $(LIBTRACEEVENT)-clean: install-traceevent-plugins: $(LIBTRACEEVENT) $(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 # already -$(LIBLK): $(LIBLK_SOURCES) +$(LIBAPIKFS): $(LIBAPIKFS_SOURCES) ifeq ($(subdir),) - $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a + $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a endif -$(LIBLK)-clean: +$(LIBAPIKFS)-clean: ifeq ($(subdir),) - $(call QUIET_CLEAN, liblk) - @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null + $(call QUIET_CLEAN, libapikfs) + @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null endif help: @@ -881,12 +881,11 @@ config-clean: $(call QUIET_CLEAN, config) @$(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-progs) $(RM) $(ALL_PROGRAMS) perf $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* - $(call QUIET_CLEAN, Documentation) - @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null + $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean $(python-clean) # diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index c6fa3cbd45a..154b397a5d2 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -13,7 +13,7 @@ #include "util/parse-options.h" #include "util/trace-event.h" #include "util/debug.h" -#include +#include #include "util/tool.h" #include "util/stat.h" #include "util/top.h" diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 6ea9e85bdc0..c98ccb57050 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -37,7 +37,7 @@ #include "util/strfilter.h" #include "util/symbol.h" #include "util/debug.h" -#include +#include #include "util/parse-options.h" #include "util/probe-finder.h" #include "util/probe-event.h" diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 8b38b4e80ec..431798a4110 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -13,7 +13,7 @@ #include "util/quote.h" #include "util/run-command.h" #include "util/parse-events.h" -#include +#include #include const char perf_usage_string[] = diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 3cbd1049608..e4ce8aed29d 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -3,7 +3,7 @@ #include "evsel.h" #include "evlist.h" #include "fs.h" -#include +#include #include "tests.h" #include diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 0b31cee3487..da318291498 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -7,7 +7,7 @@ * Released under the GPL v2. (and only v2, not any later version) */ #include "util.h" -#include +#include #include #include "cpumap.h" #include "thread_map.h" diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7b510fd1f08..01ff4cfde1f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 969cb8f0d88..094c28ba2fa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -10,7 +10,7 @@ #include "symbol.h" #include "cache.h" #include "header.h" -#include +#include #include "parse-events-bison.h" #define YY_EXTRA_TYPE int #include "parse-events-flex.h" diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d7cff57945c..544ac1898a9 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -40,7 +40,7 @@ #include "color.h" #include "symbol.h" #include "thread.h" -#include +#include #include "trace-event.h" /* For __maybe_unused */ #include "probe-event.h" #include "probe-finder.h" diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 58ea5ca6c25..d0aee4b9dfd 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' build_lib = getenv('PYTHON_EXTBUILD_LIB') build_tmp = getenv('PYTHON_EXTBUILD_TMP') libtraceevent = getenv('LIBTRACEEVENT') -liblk = getenv('LIBLK') +libapikfs = getenv('LIBAPIKFS') ext_sources = [f.strip() for f in file('util/python-ext-sources') if len(f.strip()) > 0 and f[0] != '#'] @@ -34,7 +34,7 @@ perf = Extension('perf', sources = ext_sources, include_dirs = ['util/include'], extra_compile_args = cflags, - extra_objects = [libtraceevent, liblk], + extra_objects = [libtraceevent, libapikfs], ) setup(name='perf', diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index f3c9e551bd3..c354b95a234 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -38,7 +38,7 @@ #include "../perf.h" #include "trace-event.h" -#include +#include #include "evsel.h" #define VERSION "0.5" diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index a1eea3e809a..9a2c268ad71 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -71,7 +71,7 @@ #include #include "types.h" #include -#include +#include #include #include diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 24e9ddd93fa..3d907dacf2a 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile @@ -2,21 +2,21 @@ # TARGETS=page-types slabinfo -LK_DIR = ../lib/lk -LIBLK = $(LK_DIR)/liblk.a +LIB_DIR = ../lib/api +LIBS = $(LIB_DIR)/libapikfs.a CC = $(CROSS_COMPILE)gcc CFLAGS = -Wall -Wextra -I../lib/ -LDFLAGS = $(LIBLK) +LDFLAGS = $(LIBS) -$(TARGETS): liblk +$(TARGETS): $(LIBS) -liblk: - make -C $(LK_DIR) +$(LIBS): + make -C $(LIB_DIR) %: %.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) clean: $(RM) page-types slabinfo - make -C ../lib/lk clean + make -C $(LIB_DIR) clean diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index d5e9d6d185c..f9be24d9efa 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -36,7 +36,7 @@ #include #include "../../include/uapi/linux/magic.h" #include "../../include/uapi/linux/kernel-page-flags.h" -#include +#include #ifndef MAX_PATH # define MAX_PATH 256 -- cgit v1.2.3-18-g5258 From 8b6dcca017aa53fe13066411a653b5997c158a2c Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 2 Dec 2013 18:37:33 +0400 Subject: perf timechart: Add backtrace support to CPU info Add backtrace info to the CPU usage timechart. Signed-off-by: Stanislav Fomichev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Link: http://lkml.kernel.org/r/1385995056-20158-2-git-send-email-stfomichev@yandex-team.ru Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 10 ++++++++-- tools/perf/util/svghelper.c | 4 +++- tools/perf/util/svghelper.h | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 0bda620a717..d955095b6d6 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -837,8 +837,14 @@ static void draw_cpu_usage(struct timechart *tchart) while (c) { sample = c->samples; while (sample) { - if (sample->type == TYPE_RUNNING) - svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); + if (sample->type == TYPE_RUNNING) { + svg_process(sample->cpu, + sample->start_time, + sample->end_time, + "sample", + c->comm, + sample->backtrace); + } sample = sample->next; } diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 8b79d3ad124..740f0328fc1 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -285,7 +285,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) fprintf(svgfile, "\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, const char *type, const char *name, const char *backtrace) { double width; @@ -295,6 +295,8 @@ void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name fprintf(svgfile, "\n", time2pixels(start), cpu2y(cpu)); fprintf(svgfile, "%s %s\n", name, time_to_string(end - start)); + if (backtrace) + fprintf(svgfile, "Switched because:\n%s\n", backtrace); fprintf(svgfile, "\n", time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); width = time2pixels(end)-time2pixels(start); diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index fad79ceeac1..7db6ae98bf2 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -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_process(int cpu, u64 start, u64 end, const char *type, const char *name); +extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name, const char *backtrace); extern void svg_cstate(int cpu, u64 start, u64 end, int type); extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); -- cgit v1.2.3-18-g5258 From de996228dedc74d9e72b749bbc8225f5e2bf19d8 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 2 Dec 2013 18:37:34 +0400 Subject: perf timechart: Print pid along the name Add PID to the figures of CPU usage timechart. Signed-off-by: Stanislav Fomichev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Link: http://lkml.kernel.org/r/1385995056-20158-3-git-send-email-stfomichev@yandex-team.ru Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 1 + tools/perf/util/svghelper.c | 4 ++-- tools/perf/util/svghelper.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index d955095b6d6..99fe363f1de 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -841,6 +841,7 @@ static void draw_cpu_usage(struct timechart *tchart) svg_process(sample->cpu, sample->start_time, sample->end_time, + p->pid, "sample", c->comm, sample->backtrace); diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 740f0328fc1..927851d05d0 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -285,7 +285,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) fprintf(svgfile, "\n"); } -void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name, const char *backtrace) +void svg_process(int cpu, u64 start, u64 end, int pid, const char *type, const char *name, const char *backtrace) { double width; @@ -294,7 +294,7 @@ void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name fprintf(svgfile, "\n", time2pixels(start), cpu2y(cpu)); - fprintf(svgfile, "%s %s\n", name, time_to_string(end - start)); + fprintf(svgfile, "%d %s running %s\n", pid, name, time_to_string(end - start)); if (backtrace) fprintf(svgfile, "Switched because:\n%s\n", backtrace); fprintf(svgfile, "\n", diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index 7db6ae98bf2..8b77ca63168 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -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_process(int cpu, u64 start, u64 end, const char *type, const char *name, const char *backtrace); +extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *type, const char *name, const char *backtrace); extern void svg_cstate(int cpu, u64 start, u64 end, int type); extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); -- cgit v1.2.3-18-g5258 From 58b9a18ecd251cbd6e666ad792023ab77c7d100e Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 2 Dec 2013 18:37:35 +0400 Subject: perf timechart: Get number of CPUs from perf header Print all CPUs, even if there were no events (use perf header to get number of CPUs). This is required to support topology in the next patch. Signed-off-by: Stanislav Fomichev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Link: http://lkml.kernel.org/r/1385995056-20158-4-git-send-email-stfomichev@yandex-team.ru Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-timechart.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 99fe363f1de..db9c4c17258 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -531,12 +531,10 @@ static int process_sample_event(struct perf_tool *tool, tchart->last_time = sample->time; } - if (sample->cpu > tchart->numcpus) - tchart->numcpus = sample->cpu; - if (evsel->handler != NULL) { 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; @@ -1038,8 +1036,6 @@ static void write_svg_file(struct timechart *tchart, const char *filename) int count; int thresh = TIME_THRESH; - tchart->numcpus++; - if (tchart->power_only) tchart->proc_num = 0; @@ -1069,6 +1065,25 @@ static void write_svg_file(struct timechart *tchart, const char *filename) 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; + default: + break; + } + + return 0; +} + static int __cmd_timechart(struct timechart *tchart, const char *output_name) { const struct perf_evsel_str_handler power_tracepoints[] = { @@ -1094,6 +1109,11 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) if (session == NULL) 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")) goto out_delete; -- cgit v1.2.3-18-g5258 From c507999790438cde78b5618fa64daefd697035af Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 2 Dec 2013 18:37:36 +0400 Subject: perf timechart: Add support for topology Add -t switch to sort CPUs topologically. Signed-off-by: Stanislav Fomichev Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Link: http://lkml.kernel.org/r/1385995056-20158-5-git-send-email-stfomichev@yandex-team.ru Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-timechart.txt | 3 + tools/perf/builtin-timechart.c | 17 +++- tools/perf/util/svghelper.c | 132 +++++++++++++++++++++++++++- tools/perf/util/svghelper.h | 2 + 4 files changed, 151 insertions(+), 3 deletions(-) diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 271dd4ed5b0..367c1be0551 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt @@ -59,6 +59,9 @@ $ perf timechart -n:: --proc-num:: Print task info for at least given number of tasks. +-t:: +--topology:: + Sort CPUs according to topology. RECORD OPTIONS -------------- diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index db9c4c17258..8bde57c5c90 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -58,7 +58,8 @@ struct timechart { first_time, last_time; bool power_only, tasks_only, - with_backtrace; + with_backtrace, + topology; }; struct per_pidcomm; @@ -1077,6 +1078,18 @@ static int process_header(struct perf_file_section *section __maybe_unused, 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; } @@ -1267,6 +1280,8 @@ int cmd_timechart(int argc, const char **argv, "Look for files with symbols relative to this directory"), OPT_INTEGER('n', "proc-num", &tchart.proc_num, "min. number of tasks to print"), + OPT_BOOLEAN('t', "topology", &tchart.topology, + "sort CPUs according to topology"), OPT_END() }; const char * const timechart_usage[] = { diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 927851d05d0..9468136735c 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -17,8 +17,11 @@ #include #include #include +#include +#include "perf.h" #include "svghelper.h" +#include "cpumap.h" static u64 first_time, last_time; static u64 turbo_frequency, max_freq; @@ -39,9 +42,14 @@ static double cpu2slot(int cpu) return 2 * cpu + 1; } +static int *topology_map; + 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) @@ -275,7 +283,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) time2pixels(last_time)-time2pixels(first_time), cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); - sprintf(cpu_string, "CPU %i", (int)cpu+1); + sprintf(cpu_string, "CPU %i", (int)cpu); fprintf(svgfile, "%s\n", 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); @@ -568,3 +576,123 @@ void svg_close(void) 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; +} diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index 8b77ca63168..1df4fb6c3a4 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -23,6 +23,8 @@ 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_text(int Yslot, u64 start, const char *text); 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; -- cgit v1.2.3-18-g5258 From 631d34b5626a8de828f3ab8da54013293097e678 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Dec 2013 16:57:43 -0300 Subject: perf symbols: Remove needless static binary_type array There are no references to that array anywhere, it is only used to try a series of "binary" types in turn, always setting dso->data_type till one can be used. Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-4mw7xrbs12tln6v2uthg7sqc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 436922f1f9d..e7f4449088e 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -161,7 +161,7 @@ static int open_dso(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__SYSTEM_PATH_DSO, DSO_BINARY_TYPE__NOT_FOUND, -- cgit v1.2.3-18-g5258 From ee4e9625c8d4ec3a35322a882f7b6e035d2a1ad5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Dec 2013 17:03:18 -0300 Subject: perf symbols: Clarify method to get DSO binary_type filename Using dso__binary_type_file() make it look like this function will return a file, not just its filename, so rename it to: dso__read_binary_type_filename() to make its purpose clear, just like we have: dso__read_running_kernel_build_id() Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vkf3upzrfrxtr01wueej4xw4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 14 +++++++------- tools/perf/util/dso.h | 4 ++-- tools/perf/util/symbol.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index e7f4449088e..eef16621232 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -28,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso) return origin[dso->symtab_type]; } -int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type, - char *root_dir, char *filename, size_t size) +int dso__read_binary_type_filename(const struct dso *dso, + enum dso_binary_type type, + char *root_dir, char *filename, size_t size) { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; int ret = 0; @@ -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) { - char *root_dir = (char *) ""; - char *name; int fd; + char *root_dir = (char *)""; + char *name = malloc(PATH_MAX); - name = malloc(PATH_MAX); if (!name) return -ENOMEM; if (machine) root_dir = machine->root_dir; - if (dso__binary_type_file(dso, dso->data_type, - root_dir, name, PATH_MAX)) { + if (dso__read_binary_type_filename(dso, dso->data_type, + root_dir, name, PATH_MAX)) { free(name); return -EINVAL; } diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index e1cc5069813..aa3384745d7 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -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); char dso__symtab_origin(const struct dso *dso); -int dso__binary_type_file(const struct dso *dso, enum dso_binary_type type, - char *root_dir, char *filename, size_t size); +int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, + char *root_dir, char *filename, size_t size); int dso__data_fd(struct dso *dso, struct machine *machine); ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 61eb1cddf01..9ee4b80dac5 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -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]; - if (dso__binary_type_file(dso, symtab_type, - root_dir, name, PATH_MAX)) + if (dso__read_binary_type_filename(dso, symtab_type, + root_dir, name, PATH_MAX)) continue; /* Name is now the name of the next image to try */ -- cgit v1.2.3-18-g5258 From e57a2dffbc7e28cef5f4659b98a9d5595010ab4d Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Tue, 17 Dec 2013 19:53:49 +0400 Subject: perf timechart: Add --highlight option This option highlights tasks (using different color) that run more than given duration or tasks with given name. Signed-off-by: Stanislav Fomichev Acked-by: Ingo Molnar Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Link: http://lkml.kernel.org/r/20131217155349.GA13021@stfomichev-desktop Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-timechart.txt | 13 +++++++++++++ tools/perf/builtin-timechart.c | 21 ++++++++++++++++++++- tools/perf/util/svghelper.c | 23 ++++++++++++++++++++--- tools/perf/util/svghelper.h | 4 +++- 4 files changed, 56 insertions(+), 5 deletions(-) diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 367c1be0551..bc5990c33dc 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt @@ -56,12 +56,25 @@ $ perf timechart 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:: --proc-num:: Print task info for at least given number of tasks. -t:: --topology:: Sort CPUs according to topology. +--highlight=:: + 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 -------------- diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 8bde57c5c90..20d4212fa33 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -841,7 +841,6 @@ static void draw_cpu_usage(struct timechart *tchart) sample->start_time, sample->end_time, p->pid, - "sample", c->comm, sample->backtrace); } @@ -1252,6 +1251,23 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, 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, const char *prefix __maybe_unused) { @@ -1270,6 +1286,9 @@ int cmd_timechart(int argc, const char **argv, OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_STRING('o', "output", &output_name, "file", "output file name"), OPT_INTEGER('w', "width", &svg_page_width, "page width"), + OPT_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('T', "tasks-only", &tchart.tasks_only, "output processes data only"), diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 9468136735c..56a84f2cc46 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -31,6 +31,8 @@ static u64 turbo_frequency, max_freq; #define SLOT_HEIGHT 25.0 int svg_page_width = 1000; +u64 svg_highlight; +const char *svg_highlight_name; #define MIN_TEXT_SIZE 0.01 @@ -112,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.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_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.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"); @@ -155,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) { double text_size; + const char *type; + if (!svgfile) return; + if (svg_highlight && end - start > svg_highlight) + type = "sample_hi"; + else + type = "sample"; fprintf(svgfile, "\n"); fprintf(svgfile, "#%d running %s\n", cpu, time_to_string(end - start)); if (backtrace) fprintf(svgfile, "Switched because:\n%s\n", backtrace); - fprintf(svgfile, "\n", - time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); + fprintf(svgfile, "\n", + time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, + type); text_size = (time2pixels(end)-time2pixels(start)); if (cpu > 9) @@ -293,13 +303,20 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) fprintf(svgfile, "\n"); } -void svg_process(int cpu, u64 start, u64 end, int pid, const char *type, const char *name, const char *backtrace) +void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace) { double width; + const char *type; if (!svgfile) 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, "\n", time2pixels(start), cpu2y(cpu)); fprintf(svgfile, "%d %s running %s\n", pid, name, time_to_string(end - start)); diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index 1df4fb6c3a4..f7b4d6e699e 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -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_process(int cpu, u64 start, u64 end, int pid, const char *type, const char *name, const char *backtrace); +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_pstate(int cpu, u64 start, u64 end, u64 freq); @@ -27,5 +27,7 @@ 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 u64 svg_highlight; +extern const char *svg_highlight_name; #endif /* __PERF_SVGHELPER_H */ -- cgit v1.2.3-18-g5258 From 5f70619d67b99310be9aaf850293b7fd7f31d160 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 17 Dec 2013 16:14:07 -0300 Subject: perf symbols: Use consistent name for the DSO binary type member It was called "data_type", but in this context "data" is way too vague, it could mean the "data" ELF segment, or something else. Since we have dso__read_binary_type_filename() and the values this field receives are all DSO__BINARY_TYPE_ we may as well call it "binary_type" for consistency sake. It also seems more appropriate since it determines if we can do operations like annotation and DWARF unwinding, that needs more than just the symtab, requiring access to ELF text segments, CFI ELF sections, etc. Cc: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2lkbqrn23uc2uvnn9w9in379@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 10 +++++----- tools/perf/util/dso.h | 10 +++++----- tools/perf/util/symbol.c | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index eef16621232..4ddeecb9ff8 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -148,7 +148,7 @@ static int open_dso(struct dso *dso, struct machine *machine) if (machine) root_dir = machine->root_dir; - if (dso__read_binary_type_filename(dso, dso->data_type, + if (dso__read_binary_type_filename(dso, dso->binary_type, root_dir, name, PATH_MAX)) { free(name); return -EINVAL; @@ -168,19 +168,19 @@ int dso__data_fd(struct dso *dso, struct machine *machine) }; 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); do { int fd; - dso->data_type = binary_type_data[i++]; + dso->binary_type = binary_type_data[i++]; fd = open_dso(dso, machine); if (fd >= 0) return fd; - } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); + } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); return -EINVAL; } @@ -475,7 +475,7 @@ struct dso *dso__new(const char *name) dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; dso->cache = RB_ROOT; 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->rel = 0; dso->sorted_by_name = 0; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index aa3384745d7..cd7d6f078cd 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -83,7 +83,7 @@ struct dso { enum dso_kernel_type kernel; enum dso_swap_type needs_swap; enum dso_binary_type symtab_type; - enum dso_binary_type data_type; + enum dso_binary_type binary_type; u8 adjust_symbols:1; u8 has_build_id:1; u8 has_srcline:1; @@ -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) { - return dso->data_type == DSO_BINARY_TYPE__VMLINUX || - dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX; + return dso->binary_type == DSO_BINARY_TYPE__VMLINUX || + dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX; } static inline bool dso__is_kcore(struct dso *dso) { - return dso->data_type == DSO_BINARY_TYPE__KCORE || - dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; + return dso->binary_type == DSO_BINARY_TYPE__KCORE || + dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; } void dso__free_a2l(struct dso *dso); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 9ee4b80dac5..923d00040bb 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1089,9 +1089,9 @@ static int dso__load_kcore(struct dso *dso, struct map *map, * dso__data_read_addr(). */ if (dso->kernel == DSO_TYPE_GUEST_KERNEL) - dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; + dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; else - dso->data_type = DSO_BINARY_TYPE__KCORE; + dso->binary_type = DSO_BINARY_TYPE__KCORE; dso__set_long_name(dso, strdup(kcore_filename), true); close(fd); @@ -1368,9 +1368,9 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, if (err > 0) { if (dso->kernel == DSO_TYPE_GUEST_KERNEL) - dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; + dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 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_loaded(dso, map->type); pr_debug("Using %s for symbols\n", symfs_vmlinux); -- cgit v1.2.3-18-g5258 From f23b24f1bf90b56cfaeb2a1c9b77c46efe8916a6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 17 Dec 2013 09:02:36 +0900 Subject: tools lib traceevent: Get rid of die() in some string conversion functions Those functions stringify filter arguments. As caller of those functions handles NULL string properly, it seems that it's enough to return NULL rather than calling die(). Signed-off-by: Namhyung Kim Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/878uvkgx9f.fsf@sejong.aot.lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/parse-filter.c | 67 +++++++++++-------------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 9303c55128d..e2842b92675 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -1361,8 +1361,10 @@ enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, if (ret >= 0 && pevent->test_filters) { char *test; test = pevent_filter_make_string(filter, event->event->id); - printf(" '%s: %s'\n", event->event->name, test); - free(test); + if (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) int left_val = -1; int right_val = -1; int val; - int len; switch (arg->op.type) { case FILTER_OP_AND: @@ -2097,11 +2098,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) default: break; } - str = malloc_or_die(6); - if (val) - strcpy(str, "TRUE"); - else - strcpy(str, "FALSE"); + asprintf(&str, val ? "TRUE" : "FALSE"); break; } } @@ -2119,10 +2116,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) break; } - len = strlen(left) + strlen(right) + strlen(op) + 10; - str = malloc_or_die(len); - snprintf(str, len, "(%s) %s (%s)", - left, op, right); + asprintf(&str, "(%s) %s (%s)", left, op, right); break; case FILTER_OP_NOT: @@ -2138,16 +2132,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) right_val = 0; if (right_val >= 0) { /* just return the opposite */ - str = malloc_or_die(6); - if (right_val) - strcpy(str, "FALSE"); - else - strcpy(str, "TRUE"); + asprintf(&str, right_val ? "FALSE" : "TRUE"); break; } - len = strlen(right) + strlen(op) + 3; - str = malloc_or_die(len); - snprintf(str, len, "%s(%s)", op, right); + asprintf(&str, "%s(%s)", op, right); break; 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) { - char *str; - - str = malloc_or_die(30); + char *str = NULL; - snprintf(str, 30, "%lld", arg->value.val); + asprintf(&str, "%lld", arg->value.val); return str; } @@ -2181,7 +2167,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) char *rstr; char *op; char *str = NULL; - int len; lstr = arg_to_str(filter, arg->exp.left); 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 = "^"; break; default: - die("oops in exp"); + op = "[ERROR IN EXPRESSION TYPE]"; + break; } - len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; - str = malloc_or_die(len); - snprintf(str, len, "%s %s %s", lstr, op, rstr); + asprintf(&str, "%s %s %s", lstr, op, rstr); out: free(lstr); free(rstr); @@ -2239,7 +2223,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) char *rstr; char *str = NULL; char *op = NULL; - int len; lstr = arg_to_str(filter, arg->num.left); 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) op = "<="; - len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; - str = malloc_or_die(len); - sprintf(str, "%s %s %s", lstr, op, rstr); - + asprintf(&str, "%s %s %s", lstr, op, rstr); break; default: @@ -2291,7 +2271,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) { char *str = NULL; char *op = NULL; - int len; switch (arg->str.type) { case FILTER_CMP_MATCH: @@ -2309,12 +2288,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) if (!op) op = "!~"; - len = strlen(arg->str.field->name) + strlen(op) + - strlen(arg->str.val) + 6; - str = malloc_or_die(len); - snprintf(str, len, "%s %s \"%s\"", - arg->str.field->name, - op, arg->str.val); + asprintf(&str, "%s %s \"%s\"", + arg->str.field->name, op, arg->str.val); break; 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) { - char *str; + char *str = NULL; switch (arg->type) { case FILTER_ARG_BOOLEAN: - str = malloc_or_die(6); - if (arg->boolean.value) - strcpy(str, "TRUE"); - else - strcpy(str, "FALSE"); + asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE"); return str; 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. * 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 * pevent_filter_make_string(struct event_filter *filter, int event_id) -- cgit v1.2.3-18-g5258