* [PATCH 0/5] perf tools: Store CPU cache details under perf data @ 2016-02-14 16:03 Jiri Olsa 2016-02-14 16:03 ` [PATCH 1/5] tools lib api: Add debug output support Jiri Olsa ` (5 more replies) 0 siblings, 6 replies; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra hi, adding support to store CPU cache details under perf data. $ perf report --header-only -I ... # cache info: # L1 Data 32K [0-1] # L1 Instruction 32K [0-1] # L1 Data 32K [2-3] # L1 Instruction 32K [2-3] # L2 Unified 256K [0-1] # L2 Unified 256K [2-3] # L3 Unified 4096K [0-3] ... Plus some libapi additions. Also available in here: git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git perf/cache thanks, jirka --- Jiri Olsa (5): tools lib api: Add debug output support tools lib api fs: Move filename__read_str into api/fs/fs.c tools lib api fs: Add sysfs__read_str function perf tools: Initialize libapi debug output perf tools: Add perf data cache feature tools/lib/api/Build | 1 + tools/lib/api/Makefile | 1 + tools/lib/api/debug-internal.h | 20 +++++++++ tools/lib/api/debug.c | 28 +++++++++++++ tools/lib/api/debug.h | 10 +++++ tools/lib/api/fs/fs.c | 64 +++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 3 ++ tools/perf/perf.c | 2 + tools/perf/util/debug.c | 21 ++++++++++ tools/perf/util/debug.h | 1 + tools/perf/util/env.c | 13 ++++++ tools/perf/util/env.h | 15 +++++++ tools/perf/util/header.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + tools/perf/util/trace-event.c | 1 + tools/perf/util/util.c | 48 ---------------------- tools/perf/util/util.h | 1 - 17 files changed, 446 insertions(+), 49 deletions(-) create mode 100644 tools/lib/api/debug-internal.h create mode 100644 tools/lib/api/debug.c create mode 100644 tools/lib/api/debug.h ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 1/5] tools lib api: Add debug output support 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa @ 2016-02-14 16:03 ` Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 2/5] tools lib api fs: Move filename__read_str into api/fs/fs.c Jiri Olsa ` (4 subsequent siblings) 5 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra Adding support for warning/info/debug output within libapi code. Adding following macros: pr_warning(fmt, ...) pr_info(fmt, ...) pr_debug(fmt, ...) Also adding libapi_set_print function to set above functions. This will be used in perf to set standard debug handlers for libapi. Adding 2 header files: debug.h - to be used outside libapi, contains libapi_set_print interface debug-internal.h - to be used within libapi, contains pr_warning/pr_info/pr_debug definitions Link: http://lkml.kernel.org/n/tip-ul9hftog2mwuwsnyx7gm0445@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/lib/api/Build | 1 + tools/lib/api/Makefile | 1 + tools/lib/api/debug-internal.h | 20 ++++++++++++++++++++ tools/lib/api/debug.c | 28 ++++++++++++++++++++++++++++ tools/lib/api/debug.h | 10 ++++++++++ 5 files changed, 60 insertions(+) create mode 100644 tools/lib/api/debug-internal.h create mode 100644 tools/lib/api/debug.c create mode 100644 tools/lib/api/debug.h diff --git a/tools/lib/api/Build b/tools/lib/api/Build index e8b8a23b9bf4..954c644f7ad9 100644 --- a/tools/lib/api/Build +++ b/tools/lib/api/Build @@ -1,3 +1,4 @@ libapi-y += fd/ libapi-y += fs/ libapi-y += cpu.o +libapi-y += debug.o diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index d85904dc9b38..bbc82c614bee 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -18,6 +18,7 @@ LIBFILE = $(OUTPUT)libapi.a CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +CFLAGS += -I$(srctree)/tools/lib/api RM = rm -f diff --git a/tools/lib/api/debug-internal.h b/tools/lib/api/debug-internal.h new file mode 100644 index 000000000000..188f7880eafe --- /dev/null +++ b/tools/lib/api/debug-internal.h @@ -0,0 +1,20 @@ +#ifndef __API_DEBUG_INTERNAL_H__ +#define __API_DEBUG_INTERNAL_H__ + +#include "debug.h" + +#define __pr(func, fmt, ...) \ +do { \ + if ((func)) \ + (func)("libapi: " fmt, ##__VA_ARGS__); \ +} while (0) + +extern libapi_print_fn_t __pr_warning; +extern libapi_print_fn_t __pr_info; +extern libapi_print_fn_t __pr_debug; + +#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__) +#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__) + +#endif /* __API_DEBUG_INTERNAL_H__ */ diff --git a/tools/lib/api/debug.c b/tools/lib/api/debug.c new file mode 100644 index 000000000000..5fa5cf500a1f --- /dev/null +++ b/tools/lib/api/debug.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdarg.h> +#include "debug.h" +#include "debug-internal.h" + +static int __base_pr(const char *format, ...) +{ + va_list args; + int err; + + va_start(args, format); + err = vfprintf(stderr, format, args); + va_end(args); + return err; +} + +libapi_print_fn_t __pr_warning = __base_pr; +libapi_print_fn_t __pr_info = __base_pr; +libapi_print_fn_t __pr_debug; + +void libapi_set_print(libapi_print_fn_t warn, + libapi_print_fn_t info, + libapi_print_fn_t debug) +{ + __pr_warning = warn; + __pr_info = info; + __pr_debug = debug; +} diff --git a/tools/lib/api/debug.h b/tools/lib/api/debug.h new file mode 100644 index 000000000000..a0872f68fc56 --- /dev/null +++ b/tools/lib/api/debug.h @@ -0,0 +1,10 @@ +#ifndef __API_DEBUG_H__ +#define __API_DEBUG_H__ + +typedef int (*libapi_print_fn_t)(const char *, ...); + +void libapi_set_print(libapi_print_fn_t warn, + libapi_print_fn_t info, + libapi_print_fn_t debug); + +#endif /* __API_DEBUG_H__ */ -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [tip:perf/core] tools lib api: Add debug output support 2016-02-14 16:03 ` [PATCH 1/5] tools lib api: Add debug output support Jiri Olsa @ 2016-02-17 12:07 ` tip-bot for Jiri Olsa 0 siblings, 0 replies; 18+ messages in thread From: tip-bot for Jiri Olsa @ 2016-02-17 12:07 UTC (permalink / raw) To: linux-tip-commits Cc: acme, dsahern, namhyung, hpa, mingo, a.p.zijlstra, jolsa, tglx, linux-kernel Commit-ID: 975f14fa8f2996604f248552eee4403def34bf5e Gitweb: http://git.kernel.org/tip/975f14fa8f2996604f248552eee4403def34bf5e Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 14 Feb 2016 17:03:42 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 16 Feb 2016 17:12:56 -0300 tools lib api: Add debug output support Adding support for warning/info/debug output within libapi code. Adding following macros: pr_warning(fmt, ...) pr_info(fmt, ...) pr_debug(fmt, ...) Also adding libapi_set_print function to set above functions. This will be used in perf to set standard debug handlers for libapi. Adding 2 header files: debug.h - to be used outside libapi, contains libapi_set_print interface debug-internal.h - to be used within libapi, contains pr_warning/pr_info/pr_debug definitions Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1455465826-8426-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/lib/api/Build | 1 + tools/lib/api/Makefile | 1 + tools/lib/api/debug-internal.h | 20 ++++++++++++++++++++ tools/lib/api/debug.c | 28 ++++++++++++++++++++++++++++ tools/lib/api/debug.h | 10 ++++++++++ 5 files changed, 60 insertions(+) diff --git a/tools/lib/api/Build b/tools/lib/api/Build index e8b8a23..954c644 100644 --- a/tools/lib/api/Build +++ b/tools/lib/api/Build @@ -1,3 +1,4 @@ libapi-y += fd/ libapi-y += fs/ libapi-y += cpu.o +libapi-y += debug.o diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index d85904d..bbc82c6 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -18,6 +18,7 @@ LIBFILE = $(OUTPUT)libapi.a CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +CFLAGS += -I$(srctree)/tools/lib/api RM = rm -f diff --git a/tools/lib/api/debug-internal.h b/tools/lib/api/debug-internal.h new file mode 100644 index 0000000..188f788 --- /dev/null +++ b/tools/lib/api/debug-internal.h @@ -0,0 +1,20 @@ +#ifndef __API_DEBUG_INTERNAL_H__ +#define __API_DEBUG_INTERNAL_H__ + +#include "debug.h" + +#define __pr(func, fmt, ...) \ +do { \ + if ((func)) \ + (func)("libapi: " fmt, ##__VA_ARGS__); \ +} while (0) + +extern libapi_print_fn_t __pr_warning; +extern libapi_print_fn_t __pr_info; +extern libapi_print_fn_t __pr_debug; + +#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__) +#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__) +#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__) + +#endif /* __API_DEBUG_INTERNAL_H__ */ diff --git a/tools/lib/api/debug.c b/tools/lib/api/debug.c new file mode 100644 index 0000000..5fa5cf5 --- /dev/null +++ b/tools/lib/api/debug.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdarg.h> +#include "debug.h" +#include "debug-internal.h" + +static int __base_pr(const char *format, ...) +{ + va_list args; + int err; + + va_start(args, format); + err = vfprintf(stderr, format, args); + va_end(args); + return err; +} + +libapi_print_fn_t __pr_warning = __base_pr; +libapi_print_fn_t __pr_info = __base_pr; +libapi_print_fn_t __pr_debug; + +void libapi_set_print(libapi_print_fn_t warn, + libapi_print_fn_t info, + libapi_print_fn_t debug) +{ + __pr_warning = warn; + __pr_info = info; + __pr_debug = debug; +} diff --git a/tools/lib/api/debug.h b/tools/lib/api/debug.h new file mode 100644 index 0000000..a0872f6 --- /dev/null +++ b/tools/lib/api/debug.h @@ -0,0 +1,10 @@ +#ifndef __API_DEBUG_H__ +#define __API_DEBUG_H__ + +typedef int (*libapi_print_fn_t)(const char *, ...); + +void libapi_set_print(libapi_print_fn_t warn, + libapi_print_fn_t info, + libapi_print_fn_t debug); + +#endif /* __API_DEBUG_H__ */ ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 2/5] tools lib api fs: Move filename__read_str into api/fs/fs.c 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa 2016-02-14 16:03 ` [PATCH 1/5] tools lib api: Add debug output support Jiri Olsa @ 2016-02-14 16:03 ` Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] tools lib api fs: Adopt filename__read_str from perf tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 3/5] tools lib api fs: Add sysfs__read_str function Jiri Olsa ` (3 subsequent siblings) 5 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra We already moved similar functions in here, also it'll be useful for sysfs__read_str addition in following patch. Link: http://lkml.kernel.org/n/tip-azxqdrdsw6fpfpk9ycmyp5eb@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/lib/api/fs/fs.c | 51 +++++++++++++++++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 2 ++ tools/perf/util/trace-event.c | 1 + tools/perf/util/util.c | 48 ---------------------------------------- tools/perf/util/util.h | 1 - 5 files changed, 54 insertions(+), 49 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 459599d1b6c4..2cbf6773ca5d 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -13,6 +13,7 @@ #include <sys/mount.h> #include "fs.h" +#include "debug-internal.h" #define _STR(x) #x #define STR(x) _STR(x) @@ -300,6 +301,56 @@ int filename__read_ull(const char *filename, unsigned long long *value) return err; } +#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ + +int filename__read_str(const char *filename, char **buf, size_t *sizep) +{ + size_t size = 0, alloc_size = 0; + void *bf = NULL, *nbf; + int fd, n, err = 0; + char sbuf[STRERR_BUFSIZE]; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -errno; + + do { + if (size == alloc_size) { + alloc_size += BUFSIZ; + nbf = realloc(bf, alloc_size); + if (!nbf) { + err = -ENOMEM; + break; + } + + bf = nbf; + } + + n = read(fd, bf + size, alloc_size - size); + if (n < 0) { + if (size) { + pr_warning("read failed %d: %s\n", errno, + strerror_r(errno, sbuf, sizeof(sbuf))); + err = 0; + } else + err = -errno; + + break; + } + + size += n; + } while (n > 0); + + if (!err) { + *sizep = size; + *buf = bf; + } else + free(bf); + + close(fd); + return err; +} + int sysfs__read_ull(const char *entry, unsigned long long *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index d024a7f682f6..858922b61141 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -2,6 +2,7 @@ #define __API_FS__ #include <stdbool.h> +#include <unistd.h> /* * On most systems <limits.h> would have given us this, but not on some systems @@ -26,6 +27,7 @@ FS(tracefs) int filename__read_int(const char *filename, int *value); int filename__read_ull(const char *filename, unsigned long long *value); +int filename__read_str(const char *filename, char **buf, size_t *sizep); int sysctl__read_int(const char *sysctl, int *value); int sysfs__read_int(const char *entry, int *value); diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 802bb868d446..8ae051e0ec79 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <traceevent/event-parse.h> #include <api/fs/tracing_path.h> +#include <api/fs/fs.h> #include "trace-event.h" #include "machine.h" #include "util.h" diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b9e2843cfbe7..35b20dd454de 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -507,54 +507,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) return ret; } -int filename__read_str(const char *filename, char **buf, size_t *sizep) -{ - size_t size = 0, alloc_size = 0; - void *bf = NULL, *nbf; - int fd, n, err = 0; - char sbuf[STRERR_BUFSIZE]; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return -errno; - - do { - if (size == alloc_size) { - alloc_size += BUFSIZ; - nbf = realloc(bf, alloc_size); - if (!nbf) { - err = -ENOMEM; - break; - } - - bf = nbf; - } - - n = read(fd, bf + size, alloc_size - size); - if (n < 0) { - if (size) { - pr_warning("read failed %d: %s\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); - err = 0; - } else - err = -errno; - - break; - } - - size += n; - } while (n > 0); - - if (!err) { - *sizep = size; - *buf = bf; - } else - free(bf); - - close(fd); - return err; -} - const char *get_filename_for_perf_kvm(void) { const char *filename; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index a8615816a00d..3dd04089e8be 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -303,7 +303,6 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, bool show_sym, bool unwind_inlines); void free_srcline(char *srcline); -int filename__read_str(const char *filename, char **buf, size_t *sizep); int perf_event_paranoid(void); void mem_bswap_64(void *src, int byte_size); -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [tip:perf/core] tools lib api fs: Adopt filename__read_str from perf 2016-02-14 16:03 ` [PATCH 2/5] tools lib api fs: Move filename__read_str into api/fs/fs.c Jiri Olsa @ 2016-02-17 12:07 ` tip-bot for Jiri Olsa 0 siblings, 0 replies; 18+ messages in thread From: tip-bot for Jiri Olsa @ 2016-02-17 12:07 UTC (permalink / raw) To: linux-tip-commits Cc: a.p.zijlstra, namhyung, jolsa, hpa, mingo, dsahern, linux-kernel, tglx, acme Commit-ID: 607bfbd7ffc60156ae0831c917497dc91a57dd8d Gitweb: http://git.kernel.org/tip/607bfbd7ffc60156ae0831c917497dc91a57dd8d Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 14 Feb 2016 17:03:43 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 16 Feb 2016 17:12:56 -0300 tools lib api fs: Adopt filename__read_str from perf We already moved similar functions in here, also it'll be useful for sysfs__read_str addition in following patch. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1455465826-8426-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/lib/api/fs/fs.c | 51 +++++++++++++++++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 2 ++ tools/perf/util/trace-event.c | 1 + tools/perf/util/util.c | 48 ---------------------------------------- tools/perf/util/util.h | 1 - 5 files changed, 54 insertions(+), 49 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 459599d..2cbf677 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -13,6 +13,7 @@ #include <sys/mount.h> #include "fs.h" +#include "debug-internal.h" #define _STR(x) #x #define STR(x) _STR(x) @@ -300,6 +301,56 @@ int filename__read_ull(const char *filename, unsigned long long *value) return err; } +#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ + +int filename__read_str(const char *filename, char **buf, size_t *sizep) +{ + size_t size = 0, alloc_size = 0; + void *bf = NULL, *nbf; + int fd, n, err = 0; + char sbuf[STRERR_BUFSIZE]; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return -errno; + + do { + if (size == alloc_size) { + alloc_size += BUFSIZ; + nbf = realloc(bf, alloc_size); + if (!nbf) { + err = -ENOMEM; + break; + } + + bf = nbf; + } + + n = read(fd, bf + size, alloc_size - size); + if (n < 0) { + if (size) { + pr_warning("read failed %d: %s\n", errno, + strerror_r(errno, sbuf, sizeof(sbuf))); + err = 0; + } else + err = -errno; + + break; + } + + size += n; + } while (n > 0); + + if (!err) { + *sizep = size; + *buf = bf; + } else + free(bf); + + close(fd); + return err; +} + int sysfs__read_ull(const char *entry, unsigned long long *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index d024a7f..858922b 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -2,6 +2,7 @@ #define __API_FS__ #include <stdbool.h> +#include <unistd.h> /* * On most systems <limits.h> would have given us this, but not on some systems @@ -26,6 +27,7 @@ FS(tracefs) int filename__read_int(const char *filename, int *value); int filename__read_ull(const char *filename, unsigned long long *value); +int filename__read_str(const char *filename, char **buf, size_t *sizep); int sysctl__read_int(const char *sysctl, int *value); int sysfs__read_int(const char *entry, int *value); diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 802bb86..8ae051e 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -10,6 +10,7 @@ #include <linux/err.h> #include <traceevent/event-parse.h> #include <api/fs/tracing_path.h> +#include <api/fs/fs.h> #include "trace-event.h" #include "machine.h" #include "util.h" diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b9e2843..35b20dd 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -507,54 +507,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) return ret; } -int filename__read_str(const char *filename, char **buf, size_t *sizep) -{ - size_t size = 0, alloc_size = 0; - void *bf = NULL, *nbf; - int fd, n, err = 0; - char sbuf[STRERR_BUFSIZE]; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return -errno; - - do { - if (size == alloc_size) { - alloc_size += BUFSIZ; - nbf = realloc(bf, alloc_size); - if (!nbf) { - err = -ENOMEM; - break; - } - - bf = nbf; - } - - n = read(fd, bf + size, alloc_size - size); - if (n < 0) { - if (size) { - pr_warning("read failed %d: %s\n", errno, - strerror_r(errno, sbuf, sizeof(sbuf))); - err = 0; - } else - err = -errno; - - break; - } - - size += n; - } while (n > 0); - - if (!err) { - *sizep = size; - *buf = bf; - } else - free(bf); - - close(fd); - return err; -} - const char *get_filename_for_perf_kvm(void) { const char *filename; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index a861581..3dd0408 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -303,7 +303,6 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, bool show_sym, bool unwind_inlines); void free_srcline(char *srcline); -int filename__read_str(const char *filename, char **buf, size_t *sizep); int perf_event_paranoid(void); void mem_bswap_64(void *src, int byte_size); ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 3/5] tools lib api fs: Add sysfs__read_str function 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa 2016-02-14 16:03 ` [PATCH 1/5] tools lib api: Add debug output support Jiri Olsa 2016-02-14 16:03 ` [PATCH 2/5] tools lib api fs: Move filename__read_str into api/fs/fs.c Jiri Olsa @ 2016-02-14 16:03 ` Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 4/5] perf tools: Initialize libapi debug output Jiri Olsa ` (2 subsequent siblings) 5 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra Adding sysfs__read_str function to ease up reading string files from sysfs. New interface is: int sysfs__read_str(const char *entry, char **buf, size_t *sizep); Link: http://lkml.kernel.org/n/tip-em9nb2r0dnbggdxrnyf6wnb9@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/lib/api/fs/fs.c | 13 +++++++++++++ tools/lib/api/fs/fs.h | 1 + 2 files changed, 14 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 2cbf6773ca5d..ef78c22ff44d 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -377,6 +377,19 @@ int sysfs__read_int(const char *entry, int *value) return filename__read_int(path, value); } +int sysfs__read_str(const char *entry, char **buf, size_t *sizep) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_str(path, buf, sizep); +} + int sysctl__read_int(const char *sysctl, int *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 858922b61141..9f6598098dc5 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -32,4 +32,5 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep); int sysctl__read_int(const char *sysctl, int *value); int sysfs__read_int(const char *entry, int *value); int sysfs__read_ull(const char *entry, unsigned long long *value); +int sysfs__read_str(const char *entry, char **buf, size_t *sizep); #endif /* __API_FS__ */ -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [tip:perf/core] tools lib api fs: Add sysfs__read_str function 2016-02-14 16:03 ` [PATCH 3/5] tools lib api fs: Add sysfs__read_str function Jiri Olsa @ 2016-02-17 12:07 ` tip-bot for Jiri Olsa 0 siblings, 0 replies; 18+ messages in thread From: tip-bot for Jiri Olsa @ 2016-02-17 12:07 UTC (permalink / raw) To: linux-tip-commits Cc: mingo, dsahern, linux-kernel, a.p.zijlstra, acme, jolsa, tglx, hpa, namhyung Commit-ID: 51c0396c600f49de9c3ff8f6fd83055de3709c3d Gitweb: http://git.kernel.org/tip/51c0396c600f49de9c3ff8f6fd83055de3709c3d Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 14 Feb 2016 17:03:44 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 16 Feb 2016 17:12:57 -0300 tools lib api fs: Add sysfs__read_str function Adding sysfs__read_str function to ease up reading string files from sysfs. New interface is: int sysfs__read_str(const char *entry, char **buf, size_t *sizep); Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1455465826-8426-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/lib/api/fs/fs.c | 13 +++++++++++++ tools/lib/api/fs/fs.h | 1 + 2 files changed, 14 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 2cbf677..ef78c22 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -377,6 +377,19 @@ int sysfs__read_int(const char *entry, int *value) return filename__read_int(path, value); } +int sysfs__read_str(const char *entry, char **buf, size_t *sizep) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_str(path, buf, sizep); +} + int sysctl__read_int(const char *sysctl, int *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 858922b..9f65980 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -32,4 +32,5 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep); int sysctl__read_int(const char *sysctl, int *value); int sysfs__read_int(const char *entry, int *value); int sysfs__read_ull(const char *entry, unsigned long long *value); +int sysfs__read_str(const char *entry, char **buf, size_t *sizep); #endif /* __API_FS__ */ ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 4/5] perf tools: Initialize libapi debug output 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa ` (2 preceding siblings ...) 2016-02-14 16:03 ` [PATCH 3/5] tools lib api fs: Add sysfs__read_str function Jiri Olsa @ 2016-02-14 16:03 ` Jiri Olsa 2016-02-17 12:08 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 5/5] perf tools: Add perf data cache feature Jiri Olsa 2016-02-16 8:14 ` [PATCH 0/5] perf tools: Store CPU cache details under perf data Ingo Molnar 5 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra Setting libapi debug output functions to use perf functions. Link: http://lkml.kernel.org/n/tip-apyen6qfzzwkqjhi1tzv72ju@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/perf.c | 2 ++ tools/perf/util/debug.c | 21 +++++++++++++++++++++ tools/perf/util/debug.h | 1 + 3 files changed, 24 insertions(+) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index a929618b8eb6..144047c396f0 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -613,6 +613,8 @@ int main(int argc, const char **argv) */ pthread__block_sigwinch(); + perf_debug_setup(); + while (1) { static int done_help; int was_alias = run_argv(&argc, &argv); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 86d9c7302598..152c2e32975f 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -5,6 +5,7 @@ #include <string.h> #include <stdarg.h> #include <stdio.h> +#include <api/debug.h> #include "cache.h" #include "color.h" @@ -192,3 +193,23 @@ int perf_debug_option(const char *str) free(s); return 0; } + +#define FUNC(__n, __l) \ +static int pr_ ## __n ## _func(const char *fmt, ...) \ +{ \ + va_list args; \ + int ret; \ + \ + va_start(args, fmt); \ + ret = _eprintf(__l, verbose, fmt, args); \ + va_end(args); \ + return ret; \ +} + +FUNC(warning, 0); +FUNC(debug, 1); + +void perf_debug_setup(void) +{ + libapi_set_print(pr_warning_func, pr_warning_func, pr_debug_func); +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8b9a088c32ab..14bafda79eda 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -53,5 +53,6 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__( int veprintf(int level, int var, const char *fmt, va_list args); int perf_debug_option(const char *str); +void perf_debug_setup(void); #endif /* __PERF_DEBUG_H */ -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [tip:perf/core] perf tools: Initialize libapi debug output 2016-02-14 16:03 ` [PATCH 4/5] perf tools: Initialize libapi debug output Jiri Olsa @ 2016-02-17 12:08 ` tip-bot for Jiri Olsa 0 siblings, 0 replies; 18+ messages in thread From: tip-bot for Jiri Olsa @ 2016-02-17 12:08 UTC (permalink / raw) To: linux-tip-commits Cc: linux-kernel, mingo, acme, tglx, namhyung, a.p.zijlstra, hpa, dsahern, jolsa Commit-ID: dd629cc0975349c99d5483402bca1ef16313c209 Gitweb: http://git.kernel.org/tip/dd629cc0975349c99d5483402bca1ef16313c209 Author: Jiri Olsa <jolsa@kernel.org> AuthorDate: Sun, 14 Feb 2016 17:03:45 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 16 Feb 2016 17:12:59 -0300 perf tools: Initialize libapi debug output Setting libapi debug output functions to use perf functions. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: David Ahern <dsahern@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1455465826-8426-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/perf.c | 2 ++ tools/perf/util/debug.c | 21 +++++++++++++++++++++ tools/perf/util/debug.h | 1 + 3 files changed, 24 insertions(+) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index a929618..144047c 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -613,6 +613,8 @@ int main(int argc, const char **argv) */ pthread__block_sigwinch(); + perf_debug_setup(); + while (1) { static int done_help; int was_alias = run_argv(&argc, &argv); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index d6c8d2b..ff7e86a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -5,6 +5,7 @@ #include <string.h> #include <stdarg.h> #include <stdio.h> +#include <api/debug.h> #include "cache.h" #include "color.h" @@ -187,3 +188,23 @@ int perf_debug_option(const char *str) free(s); return 0; } + +#define DEBUG_WRAPPER(__n, __l) \ +static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ +{ \ + va_list args; \ + int ret; \ + \ + va_start(args, fmt); \ + ret = veprintf(__l, verbose, fmt, args); \ + va_end(args); \ + return ret; \ +} + +DEBUG_WRAPPER(warning, 0); +DEBUG_WRAPPER(debug, 1); + +void perf_debug_setup(void) +{ + libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); +} diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 8b9a088..14bafda 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -53,5 +53,6 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__( int veprintf(int level, int var, const char *fmt, va_list args); int perf_debug_option(const char *str); +void perf_debug_setup(void); #endif /* __PERF_DEBUG_H */ ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH 5/5] perf tools: Add perf data cache feature 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa ` (3 preceding siblings ...) 2016-02-14 16:03 ` [PATCH 4/5] perf tools: Initialize libapi debug output Jiri Olsa @ 2016-02-14 16:03 ` Jiri Olsa 2016-02-16 12:11 ` [PATCHv2 " Jiri Olsa 2016-02-16 8:14 ` [PATCH 0/5] perf tools: Store CPU cache details under perf data Ingo Molnar 5 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-14 16:03 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra Storing CPU cache details under perf data. It's stored as new HEADER_CACHE feature and it's displayed under header info with -I option: $ perf report --header-only -I ... # cache info: # L1 Data 32K [0-1] # L1 Instruction 32K [0-1] # L1 Data 32K [2-3] # L1 Instruction 32K [2-3] # L2 Unified 256K [0-1] # L2 Unified 256K [2-3] # L3 Unified 4096K [0-3] ... All distinct caches are stored/displayed. Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 15 +++ tools/perf/util/header.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 4 files changed, 294 insertions(+) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 7dd5939dea2e..02a6970f2495 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -6,6 +6,8 @@ struct perf_env perf_env; void perf_env__exit(struct perf_env *env) { + int i; + zfree(&env->hostname); zfree(&env->os_release); zfree(&env->version); @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env) zfree(&env->numa_nodes); zfree(&env->pmu_mappings); zfree(&env->cpu); + + for (i = 0; i < env->caches_cnt; i++) + cache_level__free(&env->caches[i]); + zfree(&env->caches); } int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) env->nr_cpus_avail = nr_cpus; return 0; } + +void cache_level__free(struct cache_level *cache) +{ + free(cache->type); + free(cache->map); + free(cache->size); +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 0132b9557c02..9963499820e7 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -1,11 +1,23 @@ #ifndef __PERF_ENV_H #define __PERF_ENV_H +#include <linux/types.h> + struct cpu_topology_map { int socket_id; int core_id; }; +struct cache_level { + u32 level; + u32 line_size; + u32 sets; + u32 ways; + char *type; + char *size; + char *map; +}; + struct perf_env { char *hostname; char *os_release; @@ -31,6 +43,8 @@ struct perf_env { char *numa_nodes; char *pmu_mappings; struct cpu_topology_map *cpu; + struct cache_level *caches; + int caches_cnt; }; extern struct perf_env perf_env; @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); int perf_env__read_cpu_topology_map(struct perf_env *env); +void cache_level__free(struct cache_level *cache); #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f50b7235ecb6..55d5a7ff25f6 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -23,6 +23,8 @@ #include "strbuf.h" #include "build-id.h" #include "data.h" +#include <api/fs/fs.h> +#include "asm/bug.h" /* * magic2 = "PERFILE2" @@ -868,6 +870,197 @@ static int write_auxtrace(int fd, struct perf_header *h, return err; } +static int cache_level__sort(const void *a, const void *b) +{ + struct cache_level *cache_a = (struct cache_level *) a; + struct cache_level *cache_b = (struct cache_level *) b; + + return cache_a->level - cache_b->level; +} + +static bool cache_level__cmp(struct cache_level *a, struct cache_level *b) +{ + if (a->level != b->level) + return false; + + if (a->line_size != b->line_size) + return false; + + if (a->sets != b->sets) + return false; + + if (a->ways != b->ways) + return false; + + if (strcmp(a->type, b->type)) + return false; + + if (strcmp(a->size, b->size)) + return false; + + if (strcmp(a->map, b->map)) + return false; + + return true; +} + +static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level) +{ + char path[PATH_MAX], file[PATH_MAX]; + struct stat st; + size_t len; + + scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); + scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); + + if (stat(file, &st)) + return 1; + + scnprintf(file, PATH_MAX, "%s/level", path); + if (sysfs__read_int(file, (int *) &cache->level)) + return -1; + + scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); + if (sysfs__read_int(file, (int *) &cache->line_size)) + return -1; + + scnprintf(file, PATH_MAX, "%s/number_of_sets", path); + if (sysfs__read_int(file, (int *) &cache->sets)) + return -1; + + scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); + if (sysfs__read_int(file, (int *) &cache->ways)) + return -1; + + scnprintf(file, PATH_MAX, "%s/type", path); + if (sysfs__read_str(file, &cache->type, &len)) + return -1; + + cache->type[len] = 0; + cache->type = rtrim(cache->type); + + scnprintf(file, PATH_MAX, "%s/size", path); + if (sysfs__read_str(file, &cache->size, &len)) { + free(cache->type); + return -1; + } + + cache->size[len] = 0; + cache->size = rtrim(cache->size); + + scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); + if (sysfs__read_str(file, &cache->map, &len)) { + free(cache->map); + free(cache->type); + return -1; + } + + cache->map[len] = 0; + cache->map = rtrim(cache->map); + return 0; +} + +static void cache_level__fprintf(FILE *out, struct cache_level *c) +{ + fprintf(out, "L%d %s %s [%s]\n", c->level, c->type, c->size, c->map); +} + +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) +{ + u32 i, cnt = 0; + long ncpus; + u32 nr, cpu; + u16 level; + + ncpus = sysconf(_SC_NPROCESSORS_CONF); + if (ncpus < 0) + return -1; + + nr = (u32)(ncpus & UINT_MAX); + + for (cpu = 0; cpu < nr; cpu++) { + for (level = 0; level < 10; level++) { + struct cache_level c; + int err; + + err = cache_level__read(&c, cpu, level); + if (err < 0) + return err; + + if (err == 1) + break; + + for (i = 0; i < cnt; i++) { + if (cache_level__cmp(&c, &caches[i])) + break; + } + + if (i == cnt) + caches[cnt++] = c; + + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) + goto out; + } + } + out: + *cntp = cnt; + return 0; +} + +#define MAX_CACHES 2000 + +static int write_cache(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist __maybe_unused) +{ + struct cache_level caches[MAX_CACHES]; + u32 cnt = 0, i, version = 1; + int ret; + + ret = build_caches(caches, MAX_CACHES, &cnt); + if (ret) + goto out; + + qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort); + + ret = do_write(fd, &version, sizeof(u32)); + if (ret < 0) + goto out; + + ret = do_write(fd, &cnt, sizeof(u32)); + if (ret < 0) + goto out; + + for (i = 0; i < cnt; i++) { + struct cache_level *c = &caches[i]; + + #define _W(v) \ + ret = do_write(fd, &c->v, sizeof(u32)); \ + if (ret < 0) \ + goto out; + + _W(level) + _W(line_size) + _W(sets) + _W(ways) + #undef _W + + #define _W(v) \ + ret = do_write_string(fd, (const char *) c->v); \ + if (ret < 0) \ + goto out; + + _W(type) + _W(size) + _W(map) + #undef _W + } + +out: + for (i = 0; i < cnt; i++) + cache_level__free(&caches[i]); + return ret; +} + static int write_stat(int fd __maybe_unused, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) @@ -1172,6 +1365,18 @@ static void print_stat(struct perf_header *ph __maybe_unused, fprintf(fp, "# contains stat data\n"); } +static void print_cache(struct perf_header *ph __maybe_unused, + int fd __maybe_unused, FILE *fp __maybe_unused) +{ + int i; + + fprintf(fp, "# cache info:\n"); + for (i = 0; i < ph->env.caches_cnt; i++) { + fprintf(fp, "# "); + cache_level__fprintf(fp, &ph->env.caches[i]); + } +} + static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, FILE *fp) { @@ -1920,6 +2125,65 @@ static int process_auxtrace(struct perf_file_section *section, return err; } +static int process_cache(struct perf_file_section *section __maybe_unused, + struct perf_header *ph __maybe_unused, int fd __maybe_unused, + void *data __maybe_unused) +{ + struct cache_level *caches; + u32 cnt, i, version; + + if (readn(fd, &version, sizeof(version)) != sizeof(version)) + return -1; + + if (ph->needs_swap) + version = bswap_32(version); + + if (version != 1) + return -1; + + if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) + return -1; + + if (ph->needs_swap) + cnt = bswap_32(cnt); + + caches = zalloc(sizeof(struct cache_level) * cnt); + if (!caches) + return -1; + + for (i = 0; i < cnt; i++) { + struct cache_level c; + + #define _R(v) \ + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + return -1; \ + if (ph->needs_swap) \ + c.v = bswap_32(c.v); \ + + _R(level) + _R(line_size) + _R(sets) + _R(ways) + #undef _R + + #define _R(v) \ + c.v = do_read_string(fd, ph); \ + if (!c.v) \ + return -1; + + _R(type) + _R(size) + _R(map) + #undef _R + + caches[i] = c; + } + + ph->env.caches = caches; + ph->env.caches_cnt = cnt; + return 0; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -1962,6 +2226,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPP(HEADER_GROUP_DESC, group_desc), FEAT_OPP(HEADER_AUXTRACE, auxtrace), FEAT_OPA(HEADER_STAT, stat), + FEAT_OPF(HEADER_CACHE, cache), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index cff9892452ee..3d87ca823c0a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -32,6 +32,7 @@ enum { HEADER_GROUP_DESC, HEADER_AUXTRACE, HEADER_STAT, + HEADER_CACHE, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCHv2 5/5] perf tools: Add perf data cache feature 2016-02-14 16:03 ` [PATCH 5/5] perf tools: Add perf data cache feature Jiri Olsa @ 2016-02-16 12:11 ` Jiri Olsa 2016-02-16 14:22 ` Namhyung Kim 0 siblings, 1 reply; 18+ messages in thread From: Jiri Olsa @ 2016-02-16 12:11 UTC (permalink / raw) To: Arnaldo Carvalho de Melo Cc: Jiri Olsa, lkml, David Ahern, Ingo Molnar, Namhyung Kim, Peter Zijlstra On Sun, Feb 14, 2016 at 05:03:46PM +0100, Jiri Olsa wrote: > Storing CPU cache details under perf data. It's stored > as new HEADER_CACHE feature and it's displayed under > header info with -I option: > > $ perf report --header-only -I > ... > # cache info: > # L1 Data 32K [0-1] > # L1 Instruction 32K [0-1] > # L1 Data 32K [2-3] > # L1 Instruction 32K [2-3] > # L2 Unified 256K [0-1] > # L2 Unified 256K [2-3] > # L3 Unified 4096K [0-3] > ... > changing the output based on Ingo's comment v2 attached, the rest of the patchset stays my perf/cache branch is updated thanks, jirka --- Storing CPU cache details under perf data. It's stored as new HEADER_CACHE feature and it's displayed under header info with -I option: $ perf report --header-only -I ... # CPU cache info: # L1 Data 32K [0-1] # L1 Instruction 32K [0-1] # L1 Data 32K [2-3] # L1 Instruction 32K [2-3] # L2 Unified 256K [0-1] # L2 Unified 256K [2-3] # L3 Unified 4096K [0-3] ... All distinct caches are stored/displayed. Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 15 +++ tools/perf/util/header.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 4 files changed, 294 insertions(+) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 7dd5939dea2e..02a6970f2495 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -6,6 +6,8 @@ struct perf_env perf_env; void perf_env__exit(struct perf_env *env) { + int i; + zfree(&env->hostname); zfree(&env->os_release); zfree(&env->version); @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env) zfree(&env->numa_nodes); zfree(&env->pmu_mappings); zfree(&env->cpu); + + for (i = 0; i < env->caches_cnt; i++) + cache_level__free(&env->caches[i]); + zfree(&env->caches); } int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) env->nr_cpus_avail = nr_cpus; return 0; } + +void cache_level__free(struct cache_level *cache) +{ + free(cache->type); + free(cache->map); + free(cache->size); +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 0132b9557c02..9963499820e7 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -1,11 +1,23 @@ #ifndef __PERF_ENV_H #define __PERF_ENV_H +#include <linux/types.h> + struct cpu_topology_map { int socket_id; int core_id; }; +struct cache_level { + u32 level; + u32 line_size; + u32 sets; + u32 ways; + char *type; + char *size; + char *map; +}; + struct perf_env { char *hostname; char *os_release; @@ -31,6 +43,8 @@ struct perf_env { char *numa_nodes; char *pmu_mappings; struct cpu_topology_map *cpu; + struct cache_level *caches; + int caches_cnt; }; extern struct perf_env perf_env; @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); int perf_env__read_cpu_topology_map(struct perf_env *env); +void cache_level__free(struct cache_level *cache); #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f50b7235ecb6..5706c630071b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -23,6 +23,8 @@ #include "strbuf.h" #include "build-id.h" #include "data.h" +#include <api/fs/fs.h> +#include "asm/bug.h" /* * magic2 = "PERFILE2" @@ -868,6 +870,197 @@ static int write_auxtrace(int fd, struct perf_header *h, return err; } +static int cache_level__sort(const void *a, const void *b) +{ + struct cache_level *cache_a = (struct cache_level *) a; + struct cache_level *cache_b = (struct cache_level *) b; + + return cache_a->level - cache_b->level; +} + +static bool cache_level__cmp(struct cache_level *a, struct cache_level *b) +{ + if (a->level != b->level) + return false; + + if (a->line_size != b->line_size) + return false; + + if (a->sets != b->sets) + return false; + + if (a->ways != b->ways) + return false; + + if (strcmp(a->type, b->type)) + return false; + + if (strcmp(a->size, b->size)) + return false; + + if (strcmp(a->map, b->map)) + return false; + + return true; +} + +static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level) +{ + char path[PATH_MAX], file[PATH_MAX]; + struct stat st; + size_t len; + + scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); + scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); + + if (stat(file, &st)) + return 1; + + scnprintf(file, PATH_MAX, "%s/level", path); + if (sysfs__read_int(file, (int *) &cache->level)) + return -1; + + scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); + if (sysfs__read_int(file, (int *) &cache->line_size)) + return -1; + + scnprintf(file, PATH_MAX, "%s/number_of_sets", path); + if (sysfs__read_int(file, (int *) &cache->sets)) + return -1; + + scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); + if (sysfs__read_int(file, (int *) &cache->ways)) + return -1; + + scnprintf(file, PATH_MAX, "%s/type", path); + if (sysfs__read_str(file, &cache->type, &len)) + return -1; + + cache->type[len] = 0; + cache->type = rtrim(cache->type); + + scnprintf(file, PATH_MAX, "%s/size", path); + if (sysfs__read_str(file, &cache->size, &len)) { + free(cache->type); + return -1; + } + + cache->size[len] = 0; + cache->size = rtrim(cache->size); + + scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); + if (sysfs__read_str(file, &cache->map, &len)) { + free(cache->map); + free(cache->type); + return -1; + } + + cache->map[len] = 0; + cache->map = rtrim(cache->map); + return 0; +} + +static void cache_level__fprintf(FILE *out, struct cache_level *c) +{ + fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); +} + +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) +{ + u32 i, cnt = 0; + long ncpus; + u32 nr, cpu; + u16 level; + + ncpus = sysconf(_SC_NPROCESSORS_CONF); + if (ncpus < 0) + return -1; + + nr = (u32)(ncpus & UINT_MAX); + + for (cpu = 0; cpu < nr; cpu++) { + for (level = 0; level < 10; level++) { + struct cache_level c; + int err; + + err = cache_level__read(&c, cpu, level); + if (err < 0) + return err; + + if (err == 1) + break; + + for (i = 0; i < cnt; i++) { + if (cache_level__cmp(&c, &caches[i])) + break; + } + + if (i == cnt) + caches[cnt++] = c; + + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) + goto out; + } + } + out: + *cntp = cnt; + return 0; +} + +#define MAX_CACHES 2000 + +static int write_cache(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist __maybe_unused) +{ + struct cache_level caches[MAX_CACHES]; + u32 cnt = 0, i, version = 1; + int ret; + + ret = build_caches(caches, MAX_CACHES, &cnt); + if (ret) + goto out; + + qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort); + + ret = do_write(fd, &version, sizeof(u32)); + if (ret < 0) + goto out; + + ret = do_write(fd, &cnt, sizeof(u32)); + if (ret < 0) + goto out; + + for (i = 0; i < cnt; i++) { + struct cache_level *c = &caches[i]; + + #define _W(v) \ + ret = do_write(fd, &c->v, sizeof(u32)); \ + if (ret < 0) \ + goto out; + + _W(level) + _W(line_size) + _W(sets) + _W(ways) + #undef _W + + #define _W(v) \ + ret = do_write_string(fd, (const char *) c->v); \ + if (ret < 0) \ + goto out; + + _W(type) + _W(size) + _W(map) + #undef _W + } + +out: + for (i = 0; i < cnt; i++) + cache_level__free(&caches[i]); + return ret; +} + static int write_stat(int fd __maybe_unused, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) @@ -1172,6 +1365,18 @@ static void print_stat(struct perf_header *ph __maybe_unused, fprintf(fp, "# contains stat data\n"); } +static void print_cache(struct perf_header *ph __maybe_unused, + int fd __maybe_unused, FILE *fp __maybe_unused) +{ + int i; + + fprintf(fp, "# CPU cache info:\n"); + for (i = 0; i < ph->env.caches_cnt; i++) { + fprintf(fp, "# "); + cache_level__fprintf(fp, &ph->env.caches[i]); + } +} + static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, FILE *fp) { @@ -1920,6 +2125,65 @@ static int process_auxtrace(struct perf_file_section *section, return err; } +static int process_cache(struct perf_file_section *section __maybe_unused, + struct perf_header *ph __maybe_unused, int fd __maybe_unused, + void *data __maybe_unused) +{ + struct cache_level *caches; + u32 cnt, i, version; + + if (readn(fd, &version, sizeof(version)) != sizeof(version)) + return -1; + + if (ph->needs_swap) + version = bswap_32(version); + + if (version != 1) + return -1; + + if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) + return -1; + + if (ph->needs_swap) + cnt = bswap_32(cnt); + + caches = zalloc(sizeof(struct cache_level) * cnt); + if (!caches) + return -1; + + for (i = 0; i < cnt; i++) { + struct cache_level c; + + #define _R(v) \ + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + return -1; \ + if (ph->needs_swap) \ + c.v = bswap_32(c.v); \ + + _R(level) + _R(line_size) + _R(sets) + _R(ways) + #undef _R + + #define _R(v) \ + c.v = do_read_string(fd, ph); \ + if (!c.v) \ + return -1; + + _R(type) + _R(size) + _R(map) + #undef _R + + caches[i] = c; + } + + ph->env.caches = caches; + ph->env.caches_cnt = cnt; + return 0; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -1962,6 +2226,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPP(HEADER_GROUP_DESC, group_desc), FEAT_OPP(HEADER_AUXTRACE, auxtrace), FEAT_OPA(HEADER_STAT, stat), + FEAT_OPF(HEADER_CACHE, cache), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index cff9892452ee..3d87ca823c0a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -32,6 +32,7 @@ enum { HEADER_GROUP_DESC, HEADER_AUXTRACE, HEADER_STAT, + HEADER_CACHE, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCHv2 5/5] perf tools: Add perf data cache feature 2016-02-16 12:11 ` [PATCHv2 " Jiri Olsa @ 2016-02-16 14:22 ` Namhyung Kim 2016-02-16 15:01 ` [PATCHv3 " Jiri Olsa 0 siblings, 1 reply; 18+ messages in thread From: Namhyung Kim @ 2016-02-16 14:22 UTC (permalink / raw) To: Jiri Olsa Cc: Arnaldo Carvalho de Melo, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra Hi Jiri, On Tue, Feb 16, 2016 at 01:11:30PM +0100, Jiri Olsa wrote: > On Sun, Feb 14, 2016 at 05:03:46PM +0100, Jiri Olsa wrote: > > Storing CPU cache details under perf data. It's stored > > as new HEADER_CACHE feature and it's displayed under > > header info with -I option: > > > > $ perf report --header-only -I > > ... > > # cache info: > > # L1 Data 32K [0-1] > > # L1 Instruction 32K [0-1] > > # L1 Data 32K [2-3] > > # L1 Instruction 32K [2-3] > > # L2 Unified 256K [0-1] > > # L2 Unified 256K [2-3] > > # L3 Unified 4096K [0-3] > > ... > > > > changing the output based on Ingo's comment > v2 attached, the rest of the patchset stays > > my perf/cache branch is updated > > thanks, > jirka > > > --- > Storing CPU cache details under perf data. It's stored > as new HEADER_CACHE feature and it's displayed under > header info with -I option: > > $ perf report --header-only -I > ... > # CPU cache info: > # L1 Data 32K [0-1] > # L1 Instruction 32K [0-1] > # L1 Data 32K [2-3] > # L1 Instruction 32K [2-3] > # L2 Unified 256K [0-1] > # L2 Unified 256K [2-3] > # L3 Unified 4096K [0-3] > ... > > All distinct caches are stored/displayed. > > Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- [SNIP] > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) > +{ > + u32 i, cnt = 0; > + long ncpus; > + u32 nr, cpu; > + u16 level; > + > + ncpus = sysconf(_SC_NPROCESSORS_CONF); > + if (ncpus < 0) > + return -1; > + > + nr = (u32)(ncpus & UINT_MAX); > + > + for (cpu = 0; cpu < nr; cpu++) { > + for (level = 0; level < 10; level++) { > + struct cache_level c; > + int err; > + > + err = cache_level__read(&c, cpu, level); > + if (err < 0) > + return err; > + > + if (err == 1) > + break; > + > + for (i = 0; i < cnt; i++) { > + if (cache_level__cmp(&c, &caches[i])) > + break; > + } > + > + if (i == cnt) > + caches[cnt++] = c; else cache_level__free(&c); ??? Thanks, Namhyung > + > + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) > + goto out; > + } > + } > + out: > + *cntp = cnt; > + return 0; > +} ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCHv3 5/5] perf tools: Add perf data cache feature 2016-02-16 14:22 ` Namhyung Kim @ 2016-02-16 15:01 ` Jiri Olsa 2016-02-16 15:29 ` Arnaldo Carvalho de Melo 2016-02-17 12:08 ` [tip:perf/core] " tip-bot for Jiri Olsa 0 siblings, 2 replies; 18+ messages in thread From: Jiri Olsa @ 2016-02-16 15:01 UTC (permalink / raw) To: Namhyung Kim Cc: Arnaldo Carvalho de Melo, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra On Tue, Feb 16, 2016 at 11:22:19PM +0900, Namhyung Kim wrote: SNIP > > [SNIP] > > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) > > +{ > > + u32 i, cnt = 0; > > + long ncpus; > > + u32 nr, cpu; > > + u16 level; > > + > > + ncpus = sysconf(_SC_NPROCESSORS_CONF); > > + if (ncpus < 0) > > + return -1; > > + > > + nr = (u32)(ncpus & UINT_MAX); > > + > > + for (cpu = 0; cpu < nr; cpu++) { > > + for (level = 0; level < 10; level++) { > > + struct cache_level c; > > + int err; > > + > > + err = cache_level__read(&c, cpu, level); > > + if (err < 0) > > + return err; > > + > > + if (err == 1) > > + break; > > + > > + for (i = 0; i < cnt; i++) { > > + if (cache_level__cmp(&c, &caches[i])) > > + break; > > + } > > + > > + if (i == cnt) > > + caches[cnt++] = c; > > else > cache_level__free(&c); > ??? ouch right.. v3 attached thanks, jirka --- Storing CPU cache details under perf data. It's stored as new HEADER_CACHE feature and it's displayed under header info with -I option: $ perf report --header-only -I ... # CPU cache info: # L1 Data 32K [0-1] # L1 Instruction 32K [0-1] # L1 Data 32K [2-3] # L1 Instruction 32K [2-3] # L2 Unified 256K [0-1] # L2 Unified 256K [2-3] # L3 Unified 4096K [0-3] ... All distinct caches are stored/displayed. Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org> --- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 15 +++ tools/perf/util/header.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 4 files changed, 296 insertions(+) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 7dd5939dea2e..02a6970f2495 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -6,6 +6,8 @@ struct perf_env perf_env; void perf_env__exit(struct perf_env *env) { + int i; + zfree(&env->hostname); zfree(&env->os_release); zfree(&env->version); @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env) zfree(&env->numa_nodes); zfree(&env->pmu_mappings); zfree(&env->cpu); + + for (i = 0; i < env->caches_cnt; i++) + cache_level__free(&env->caches[i]); + zfree(&env->caches); } int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) env->nr_cpus_avail = nr_cpus; return 0; } + +void cache_level__free(struct cache_level *cache) +{ + free(cache->type); + free(cache->map); + free(cache->size); +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 0132b9557c02..9963499820e7 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -1,11 +1,23 @@ #ifndef __PERF_ENV_H #define __PERF_ENV_H +#include <linux/types.h> + struct cpu_topology_map { int socket_id; int core_id; }; +struct cache_level { + u32 level; + u32 line_size; + u32 sets; + u32 ways; + char *type; + char *size; + char *map; +}; + struct perf_env { char *hostname; char *os_release; @@ -31,6 +43,8 @@ struct perf_env { char *numa_nodes; char *pmu_mappings; struct cpu_topology_map *cpu; + struct cache_level *caches; + int caches_cnt; }; extern struct perf_env perf_env; @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); int perf_env__read_cpu_topology_map(struct perf_env *env); +void cache_level__free(struct cache_level *cache); #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f50b7235ecb6..f5803fa3dc63 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -23,6 +23,8 @@ #include "strbuf.h" #include "build-id.h" #include "data.h" +#include <api/fs/fs.h> +#include "asm/bug.h" /* * magic2 = "PERFILE2" @@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h, return err; } +static int cache_level__sort(const void *a, const void *b) +{ + struct cache_level *cache_a = (struct cache_level *) a; + struct cache_level *cache_b = (struct cache_level *) b; + + return cache_a->level - cache_b->level; +} + +static bool cache_level__cmp(struct cache_level *a, struct cache_level *b) +{ + if (a->level != b->level) + return false; + + if (a->line_size != b->line_size) + return false; + + if (a->sets != b->sets) + return false; + + if (a->ways != b->ways) + return false; + + if (strcmp(a->type, b->type)) + return false; + + if (strcmp(a->size, b->size)) + return false; + + if (strcmp(a->map, b->map)) + return false; + + return true; +} + +static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level) +{ + char path[PATH_MAX], file[PATH_MAX]; + struct stat st; + size_t len; + + scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); + scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); + + if (stat(file, &st)) + return 1; + + scnprintf(file, PATH_MAX, "%s/level", path); + if (sysfs__read_int(file, (int *) &cache->level)) + return -1; + + scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); + if (sysfs__read_int(file, (int *) &cache->line_size)) + return -1; + + scnprintf(file, PATH_MAX, "%s/number_of_sets", path); + if (sysfs__read_int(file, (int *) &cache->sets)) + return -1; + + scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); + if (sysfs__read_int(file, (int *) &cache->ways)) + return -1; + + scnprintf(file, PATH_MAX, "%s/type", path); + if (sysfs__read_str(file, &cache->type, &len)) + return -1; + + cache->type[len] = 0; + cache->type = rtrim(cache->type); + + scnprintf(file, PATH_MAX, "%s/size", path); + if (sysfs__read_str(file, &cache->size, &len)) { + free(cache->type); + return -1; + } + + cache->size[len] = 0; + cache->size = rtrim(cache->size); + + scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); + if (sysfs__read_str(file, &cache->map, &len)) { + free(cache->map); + free(cache->type); + return -1; + } + + cache->map[len] = 0; + cache->map = rtrim(cache->map); + return 0; +} + +static void cache_level__fprintf(FILE *out, struct cache_level *c) +{ + fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); +} + +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) +{ + u32 i, cnt = 0; + long ncpus; + u32 nr, cpu; + u16 level; + + ncpus = sysconf(_SC_NPROCESSORS_CONF); + if (ncpus < 0) + return -1; + + nr = (u32)(ncpus & UINT_MAX); + + for (cpu = 0; cpu < nr; cpu++) { + for (level = 0; level < 10; level++) { + struct cache_level c; + int err; + + err = cache_level__read(&c, cpu, level); + if (err < 0) + return err; + + if (err == 1) + break; + + for (i = 0; i < cnt; i++) { + if (cache_level__cmp(&c, &caches[i])) + break; + } + + if (i == cnt) + caches[cnt++] = c; + else + cache_level__free(&c); + + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) + goto out; + } + } + out: + *cntp = cnt; + return 0; +} + +#define MAX_CACHES 2000 + +static int write_cache(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist __maybe_unused) +{ + struct cache_level caches[MAX_CACHES]; + u32 cnt = 0, i, version = 1; + int ret; + + ret = build_caches(caches, MAX_CACHES, &cnt); + if (ret) + goto out; + + qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort); + + ret = do_write(fd, &version, sizeof(u32)); + if (ret < 0) + goto out; + + ret = do_write(fd, &cnt, sizeof(u32)); + if (ret < 0) + goto out; + + for (i = 0; i < cnt; i++) { + struct cache_level *c = &caches[i]; + + #define _W(v) \ + ret = do_write(fd, &c->v, sizeof(u32)); \ + if (ret < 0) \ + goto out; + + _W(level) + _W(line_size) + _W(sets) + _W(ways) + #undef _W + + #define _W(v) \ + ret = do_write_string(fd, (const char *) c->v); \ + if (ret < 0) \ + goto out; + + _W(type) + _W(size) + _W(map) + #undef _W + } + +out: + for (i = 0; i < cnt; i++) + cache_level__free(&caches[i]); + return ret; +} + static int write_stat(int fd __maybe_unused, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) @@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused, fprintf(fp, "# contains stat data\n"); } +static void print_cache(struct perf_header *ph __maybe_unused, + int fd __maybe_unused, FILE *fp __maybe_unused) +{ + int i; + + fprintf(fp, "# CPU cache info:\n"); + for (i = 0; i < ph->env.caches_cnt; i++) { + fprintf(fp, "# "); + cache_level__fprintf(fp, &ph->env.caches[i]); + } +} + static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, FILE *fp) { @@ -1920,6 +2127,65 @@ static int process_auxtrace(struct perf_file_section *section, return err; } +static int process_cache(struct perf_file_section *section __maybe_unused, + struct perf_header *ph __maybe_unused, int fd __maybe_unused, + void *data __maybe_unused) +{ + struct cache_level *caches; + u32 cnt, i, version; + + if (readn(fd, &version, sizeof(version)) != sizeof(version)) + return -1; + + if (ph->needs_swap) + version = bswap_32(version); + + if (version != 1) + return -1; + + if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) + return -1; + + if (ph->needs_swap) + cnt = bswap_32(cnt); + + caches = zalloc(sizeof(struct cache_level) * cnt); + if (!caches) + return -1; + + for (i = 0; i < cnt; i++) { + struct cache_level c; + + #define _R(v) \ + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + return -1; \ + if (ph->needs_swap) \ + c.v = bswap_32(c.v); \ + + _R(level) + _R(line_size) + _R(sets) + _R(ways) + #undef _R + + #define _R(v) \ + c.v = do_read_string(fd, ph); \ + if (!c.v) \ + return -1; + + _R(type) + _R(size) + _R(map) + #undef _R + + caches[i] = c; + } + + ph->env.caches = caches; + ph->env.caches_cnt = cnt; + return 0; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -1962,6 +2228,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPP(HEADER_GROUP_DESC, group_desc), FEAT_OPP(HEADER_AUXTRACE, auxtrace), FEAT_OPA(HEADER_STAT, stat), + FEAT_OPF(HEADER_CACHE, cache), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index cff9892452ee..3d87ca823c0a 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -32,6 +32,7 @@ enum { HEADER_GROUP_DESC, HEADER_AUXTRACE, HEADER_STAT, + HEADER_CACHE, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; -- 2.4.3 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCHv3 5/5] perf tools: Add perf data cache feature 2016-02-16 15:01 ` [PATCHv3 " Jiri Olsa @ 2016-02-16 15:29 ` Arnaldo Carvalho de Melo 2016-02-16 15:48 ` Arnaldo Carvalho de Melo 2016-02-17 12:08 ` [tip:perf/core] " tip-bot for Jiri Olsa 1 sibling, 1 reply; 18+ messages in thread From: Arnaldo Carvalho de Melo @ 2016-02-16 15:29 UTC (permalink / raw) To: Jiri Olsa Cc: Namhyung Kim, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu: > On Tue, Feb 16, 2016 at 11:22:19PM +0900, Namhyung Kim wrote: > > SNIP > > > > > [SNIP] > > > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) > > > +{ > > > + u32 i, cnt = 0; > > > + long ncpus; > > > + u32 nr, cpu; > > > + u16 level; > > > + > > > + ncpus = sysconf(_SC_NPROCESSORS_CONF); > > > + if (ncpus < 0) > > > + return -1; > > > + > > > + nr = (u32)(ncpus & UINT_MAX); > > > + > > > + for (cpu = 0; cpu < nr; cpu++) { > > > + for (level = 0; level < 10; level++) { > > > + struct cache_level c; > > > + int err; > > > + > > > + err = cache_level__read(&c, cpu, level); > > > + if (err < 0) > > > + return err; > > > + > > > + if (err == 1) > > > + break; > > > + > > > + for (i = 0; i < cnt; i++) { > > > + if (cache_level__cmp(&c, &caches[i])) > > > + break; > > > + } > > > + > > > + if (i == cnt) > > > + caches[cnt++] = c; > > > > else > > cache_level__free(&c); > > ??? > > ouch right.. v3 attached > > thanks, > jirka > > > --- > Storing CPU cache details under perf data. It's stored > as new HEADER_CACHE feature and it's displayed under > header info with -I option: > > $ perf report --header-only -I > ... > # CPU cache info: > # L1 Data 32K [0-1] > # L1 Instruction 32K [0-1] > # L1 Data 32K [2-3] > # L1 Instruction 32K [2-3] > # L2 Unified 256K [0-1] > # L2 Unified 256K [2-3] > # L3 Unified 4096K [0-3] > ... > > All distinct caches are stored/displayed. > > Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > tools/perf/util/env.c | 13 +++ > tools/perf/util/env.h | 15 +++ > tools/perf/util/header.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++ > tools/perf/util/header.h | 1 + > 4 files changed, 296 insertions(+) > > diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c > index 7dd5939dea2e..02a6970f2495 100644 > --- a/tools/perf/util/env.c > +++ b/tools/perf/util/env.c > @@ -6,6 +6,8 @@ struct perf_env perf_env; > > void perf_env__exit(struct perf_env *env) > { > + int i; > + > zfree(&env->hostname); > zfree(&env->os_release); > zfree(&env->version); > @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env) > zfree(&env->numa_nodes); > zfree(&env->pmu_mappings); > zfree(&env->cpu); > + > + for (i = 0; i < env->caches_cnt; i++) > + cache_level__free(&env->caches[i]); > + zfree(&env->caches); > } > > int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) > @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) > env->nr_cpus_avail = nr_cpus; > return 0; > } > + > +void cache_level__free(struct cache_level *cache) > +{ > + free(cache->type); > + free(cache->map); > + free(cache->size); > +} > diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h > index 0132b9557c02..9963499820e7 100644 > --- a/tools/perf/util/env.h > +++ b/tools/perf/util/env.h > @@ -1,11 +1,23 @@ > #ifndef __PERF_ENV_H > #define __PERF_ENV_H > > +#include <linux/types.h> > + > struct cpu_topology_map { > int socket_id; > int core_id; > }; > > +struct cache_level { > + u32 level; > + u32 line_size; > + u32 sets; > + u32 ways; > + char *type; > + char *size; > + char *map; > +}; > + > struct perf_env { > char *hostname; > char *os_release; > @@ -31,6 +43,8 @@ struct perf_env { > char *numa_nodes; > char *pmu_mappings; > struct cpu_topology_map *cpu; > + struct cache_level *caches; > + int caches_cnt; > }; > > extern struct perf_env perf_env; > @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); > > int perf_env__read_cpu_topology_map(struct perf_env *env); > > +void cache_level__free(struct cache_level *cache); > #endif /* __PERF_ENV_H */ > diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c > index f50b7235ecb6..f5803fa3dc63 100644 > --- a/tools/perf/util/header.c > +++ b/tools/perf/util/header.c > @@ -23,6 +23,8 @@ > #include "strbuf.h" > #include "build-id.h" > #include "data.h" > +#include <api/fs/fs.h> > +#include "asm/bug.h" > > /* > * magic2 = "PERFILE2" > @@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h, > return err; > } > > +static int cache_level__sort(const void *a, const void *b) > +{ > + struct cache_level *cache_a = (struct cache_level *) a; > + struct cache_level *cache_b = (struct cache_level *) b; > + > + return cache_a->level - cache_b->level; > +} > + > +static bool cache_level__cmp(struct cache_level *a, struct cache_level *b) > +{ > + if (a->level != b->level) > + return false; > + > + if (a->line_size != b->line_size) > + return false; > + > + if (a->sets != b->sets) > + return false; > + > + if (a->ways != b->ways) > + return false; > + > + if (strcmp(a->type, b->type)) > + return false; > + > + if (strcmp(a->size, b->size)) > + return false; > + > + if (strcmp(a->map, b->map)) > + return false; > + > + return true; > +} > + > +static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level) > +{ > + char path[PATH_MAX], file[PATH_MAX]; > + struct stat st; > + size_t len; > + > + scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); > + scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); > + > + if (stat(file, &st)) > + return 1; > + > + scnprintf(file, PATH_MAX, "%s/level", path); > + if (sysfs__read_int(file, (int *) &cache->level)) > + return -1; > + > + scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); > + if (sysfs__read_int(file, (int *) &cache->line_size)) > + return -1; > + > + scnprintf(file, PATH_MAX, "%s/number_of_sets", path); > + if (sysfs__read_int(file, (int *) &cache->sets)) > + return -1; > + > + scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); > + if (sysfs__read_int(file, (int *) &cache->ways)) > + return -1; > + > + scnprintf(file, PATH_MAX, "%s/type", path); > + if (sysfs__read_str(file, &cache->type, &len)) > + return -1; > + > + cache->type[len] = 0; > + cache->type = rtrim(cache->type); > + > + scnprintf(file, PATH_MAX, "%s/size", path); > + if (sysfs__read_str(file, &cache->size, &len)) { > + free(cache->type); > + return -1; > + } > + > + cache->size[len] = 0; > + cache->size = rtrim(cache->size); > + > + scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); > + if (sysfs__read_str(file, &cache->map, &len)) { > + free(cache->map); > + free(cache->type); > + return -1; > + } > + > + cache->map[len] = 0; > + cache->map = rtrim(cache->map); > + return 0; > +} > + > +static void cache_level__fprintf(FILE *out, struct cache_level *c) > +{ > + fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); > +} > + > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp) > +{ > + u32 i, cnt = 0; > + long ncpus; > + u32 nr, cpu; > + u16 level; > + > + ncpus = sysconf(_SC_NPROCESSORS_CONF); > + if (ncpus < 0) > + return -1; > + > + nr = (u32)(ncpus & UINT_MAX); > + > + for (cpu = 0; cpu < nr; cpu++) { > + for (level = 0; level < 10; level++) { > + struct cache_level c; > + int err; > + > + err = cache_level__read(&c, cpu, level); > + if (err < 0) > + return err; > + > + if (err == 1) > + break; > + > + for (i = 0; i < cnt; i++) { > + if (cache_level__cmp(&c, &caches[i])) > + break; > + } > + > + if (i == cnt) > + caches[cnt++] = c; > + else > + cache_level__free(&c); > + > + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) > + goto out; > + } > + } > + out: > + *cntp = cnt; > + return 0; > +} > + > +#define MAX_CACHES 2000 > + > +static int write_cache(int fd, struct perf_header *h __maybe_unused, > + struct perf_evlist *evlist __maybe_unused) > +{ > + struct cache_level caches[MAX_CACHES]; > + u32 cnt = 0, i, version = 1; > + int ret; > + > + ret = build_caches(caches, MAX_CACHES, &cnt); > + if (ret) > + goto out; > + > + qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort); > + > + ret = do_write(fd, &version, sizeof(u32)); > + if (ret < 0) > + goto out; > + > + ret = do_write(fd, &cnt, sizeof(u32)); > + if (ret < 0) > + goto out; > + > + for (i = 0; i < cnt; i++) { > + struct cache_level *c = &caches[i]; > + > + #define _W(v) \ > + ret = do_write(fd, &c->v, sizeof(u32)); \ > + if (ret < 0) \ > + goto out; > + > + _W(level) > + _W(line_size) > + _W(sets) > + _W(ways) > + #undef _W > + > + #define _W(v) \ > + ret = do_write_string(fd, (const char *) c->v); \ > + if (ret < 0) \ > + goto out; > + > + _W(type) > + _W(size) > + _W(map) > + #undef _W > + } > + > +out: > + for (i = 0; i < cnt; i++) > + cache_level__free(&caches[i]); > + return ret; > +} > + > static int write_stat(int fd __maybe_unused, > struct perf_header *h __maybe_unused, > struct perf_evlist *evlist __maybe_unused) > @@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused, > fprintf(fp, "# contains stat data\n"); > } > > +static void print_cache(struct perf_header *ph __maybe_unused, > + int fd __maybe_unused, FILE *fp __maybe_unused) > +{ > + int i; > + > + fprintf(fp, "# CPU cache info:\n"); > + for (i = 0; i < ph->env.caches_cnt; i++) { > + fprintf(fp, "# "); > + cache_level__fprintf(fp, &ph->env.caches[i]); > + } > +} > + > static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, > FILE *fp) > { > @@ -1920,6 +2127,65 @@ static int process_auxtrace(struct perf_file_section *section, > return err; > } > > +static int process_cache(struct perf_file_section *section __maybe_unused, > + struct perf_header *ph __maybe_unused, int fd __maybe_unused, > + void *data __maybe_unused) > +{ > + struct cache_level *caches; > + u32 cnt, i, version; > + > + if (readn(fd, &version, sizeof(version)) != sizeof(version)) > + return -1; > + > + if (ph->needs_swap) > + version = bswap_32(version); > + > + if (version != 1) > + return -1; > + > + if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) > + return -1; > + > + if (ph->needs_swap) > + cnt = bswap_32(cnt); > + > + caches = zalloc(sizeof(struct cache_level) * cnt); > + if (!caches) > + return -1; > + > + for (i = 0; i < cnt; i++) { > + struct cache_level c; > + > + #define _R(v) \ > + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ > + return -1; \ So in this case that 'caches' variable leaks? > + if (ph->needs_swap) \ > + c.v = bswap_32(c.v); \ > + > + _R(level) > + _R(line_size) > + _R(sets) > + _R(ways) > + #undef _R > + > + #define _R(v) \ > + c.v = do_read_string(fd, ph); \ > + if (!c.v) \ Ditto. > + return -1; > + > + _R(type) > + _R(size) > + _R(map) > + #undef _R > + > + caches[i] = c; > + } Because it is only here that you assign it to something outside this function. Also, as discussed on IRC, please s/cache_level/cpu_cache_level/g, as per Ingo's comment. - Arnaldo > + ph->env.caches = caches; > + ph->env.caches_cnt = cnt; > + return 0; > +} > + > struct feature_ops { > int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); > void (*print)(struct perf_header *h, int fd, FILE *fp); > @@ -1962,6 +2228,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { > FEAT_OPP(HEADER_GROUP_DESC, group_desc), > FEAT_OPP(HEADER_AUXTRACE, auxtrace), > FEAT_OPA(HEADER_STAT, stat), > + FEAT_OPF(HEADER_CACHE, cache), > }; > > struct header_print_data { > diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h > index cff9892452ee..3d87ca823c0a 100644 > --- a/tools/perf/util/header.h > +++ b/tools/perf/util/header.h > @@ -32,6 +32,7 @@ enum { > HEADER_GROUP_DESC, > HEADER_AUXTRACE, > HEADER_STAT, > + HEADER_CACHE, > HEADER_LAST_FEATURE, > HEADER_FEAT_BITS = 256, > }; > -- > 2.4.3 ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCHv3 5/5] perf tools: Add perf data cache feature 2016-02-16 15:29 ` Arnaldo Carvalho de Melo @ 2016-02-16 15:48 ` Arnaldo Carvalho de Melo 0 siblings, 0 replies; 18+ messages in thread From: Arnaldo Carvalho de Melo @ 2016-02-16 15:48 UTC (permalink / raw) To: Jiri Olsa Cc: Namhyung Kim, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra Em Tue, Feb 16, 2016 at 12:29:36PM -0300, Arnaldo Carvalho de Melo escreveu: > Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu: > > + caches = zalloc(sizeof(struct cache_level) * cnt); > > + if (!caches) > > + return -1; > > + > > + for (i = 0; i < cnt; i++) { > > + struct cache_level c; > > + > > + #define _R(v) \ > > + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ > > + return -1; \ > > So in this case that 'caches' variable leaks? > Ok, I fixed this and did the rename to cpu_cache_level, tested and merged it, going to the next patchkit. Thanks! Useful feature, we should use it in other places, like: record same workload in different machines, say Ivy Bridge and Broadwell, do 'perf diff' and see the CPU cache topology difference in addition to other symbolic, per DSO, etc diffs. - Arnaldo ^ permalink raw reply [flat|nested] 18+ messages in thread
* [tip:perf/core] perf tools: Add perf data cache feature 2016-02-16 15:01 ` [PATCHv3 " Jiri Olsa 2016-02-16 15:29 ` Arnaldo Carvalho de Melo @ 2016-02-17 12:08 ` tip-bot for Jiri Olsa 1 sibling, 0 replies; 18+ messages in thread From: tip-bot for Jiri Olsa @ 2016-02-17 12:08 UTC (permalink / raw) To: linux-tip-commits Cc: jolsa, namhyung, jolsa, hpa, dsahern, acme, mingo, linux-kernel, a.p.zijlstra, tglx Commit-ID: 720e98b5faf10cfd12b7821dbdcc41c9747bd13e Gitweb: http://git.kernel.org/tip/720e98b5faf10cfd12b7821dbdcc41c9747bd13e Author: Jiri Olsa <jolsa@redhat.com> AuthorDate: Tue, 16 Feb 2016 16:01:43 +0100 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Tue, 16 Feb 2016 17:13:00 -0300 perf tools: Add perf data cache feature Storing CPU cache details under perf data. It's stored as new HEADER_CACHE feature and it's displayed under header info with -I option: $ perf report --header-only -I ... # CPU cache info: # L1 Data 32K [0-1] # L1 Instruction 32K [0-1] # L1 Data 32K [2-3] # L1 Instruction 32K [2-3] # L2 Unified 256K [0-1] # L2 Unified 256K [2-3] # L3 Unified 4096K [0-3] ... All distinct caches are stored/displayed. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/20160216150143.GA7119@krava.brq.redhat.com [ Fixed leak on process_caches(), s/cache_level/cpu_cache_level/g ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/util/env.c | 13 +++ tools/perf/util/env.h | 15 +++ tools/perf/util/header.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 1 + 4 files changed, 299 insertions(+) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 7dd5939..49a11d9 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -6,6 +6,8 @@ struct perf_env perf_env; void perf_env__exit(struct perf_env *env) { + int i; + zfree(&env->hostname); zfree(&env->os_release); zfree(&env->version); @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env) zfree(&env->numa_nodes); zfree(&env->pmu_mappings); zfree(&env->cpu); + + for (i = 0; i < env->caches_cnt; i++) + cpu_cache_level__free(&env->caches[i]); + zfree(&env->caches); } int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) env->nr_cpus_avail = nr_cpus; return 0; } + +void cpu_cache_level__free(struct cpu_cache_level *cache) +{ + free(cache->type); + free(cache->map); + free(cache->size); +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 0132b95..56cffb6 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -1,11 +1,23 @@ #ifndef __PERF_ENV_H #define __PERF_ENV_H +#include <linux/types.h> + struct cpu_topology_map { int socket_id; int core_id; }; +struct cpu_cache_level { + u32 level; + u32 line_size; + u32 sets; + u32 ways; + char *type; + char *size; + char *map; +}; + struct perf_env { char *hostname; char *os_release; @@ -31,6 +43,8 @@ struct perf_env { char *numa_nodes; char *pmu_mappings; struct cpu_topology_map *cpu; + struct cpu_cache_level *caches; + int caches_cnt; }; extern struct perf_env perf_env; @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); int perf_env__read_cpu_topology_map(struct perf_env *env); +void cpu_cache_level__free(struct cpu_cache_level *cache); #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f50b723..73e38e4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -23,6 +23,8 @@ #include "strbuf.h" #include "build-id.h" #include "data.h" +#include <api/fs/fs.h> +#include "asm/bug.h" /* * magic2 = "PERFILE2" @@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h, return err; } +static int cpu_cache_level__sort(const void *a, const void *b) +{ + struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; + struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b; + + return cache_a->level - cache_b->level; +} + +static bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b) +{ + if (a->level != b->level) + return false; + + if (a->line_size != b->line_size) + return false; + + if (a->sets != b->sets) + return false; + + if (a->ways != b->ways) + return false; + + if (strcmp(a->type, b->type)) + return false; + + if (strcmp(a->size, b->size)) + return false; + + if (strcmp(a->map, b->map)) + return false; + + return true; +} + +static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level) +{ + char path[PATH_MAX], file[PATH_MAX]; + struct stat st; + size_t len; + + scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); + scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); + + if (stat(file, &st)) + return 1; + + scnprintf(file, PATH_MAX, "%s/level", path); + if (sysfs__read_int(file, (int *) &cache->level)) + return -1; + + scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); + if (sysfs__read_int(file, (int *) &cache->line_size)) + return -1; + + scnprintf(file, PATH_MAX, "%s/number_of_sets", path); + if (sysfs__read_int(file, (int *) &cache->sets)) + return -1; + + scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); + if (sysfs__read_int(file, (int *) &cache->ways)) + return -1; + + scnprintf(file, PATH_MAX, "%s/type", path); + if (sysfs__read_str(file, &cache->type, &len)) + return -1; + + cache->type[len] = 0; + cache->type = rtrim(cache->type); + + scnprintf(file, PATH_MAX, "%s/size", path); + if (sysfs__read_str(file, &cache->size, &len)) { + free(cache->type); + return -1; + } + + cache->size[len] = 0; + cache->size = rtrim(cache->size); + + scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); + if (sysfs__read_str(file, &cache->map, &len)) { + free(cache->map); + free(cache->type); + return -1; + } + + cache->map[len] = 0; + cache->map = rtrim(cache->map); + return 0; +} + +static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c) +{ + fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); +} + +static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) +{ + u32 i, cnt = 0; + long ncpus; + u32 nr, cpu; + u16 level; + + ncpus = sysconf(_SC_NPROCESSORS_CONF); + if (ncpus < 0) + return -1; + + nr = (u32)(ncpus & UINT_MAX); + + for (cpu = 0; cpu < nr; cpu++) { + for (level = 0; level < 10; level++) { + struct cpu_cache_level c; + int err; + + err = cpu_cache_level__read(&c, cpu, level); + if (err < 0) + return err; + + if (err == 1) + break; + + for (i = 0; i < cnt; i++) { + if (cpu_cache_level__cmp(&c, &caches[i])) + break; + } + + if (i == cnt) + caches[cnt++] = c; + else + cpu_cache_level__free(&c); + + if (WARN_ONCE(cnt == size, "way too many cpu caches..")) + goto out; + } + } + out: + *cntp = cnt; + return 0; +} + +#define MAX_CACHES 2000 + +static int write_cache(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist __maybe_unused) +{ + struct cpu_cache_level caches[MAX_CACHES]; + u32 cnt = 0, i, version = 1; + int ret; + + ret = build_caches(caches, MAX_CACHES, &cnt); + if (ret) + goto out; + + qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort); + + ret = do_write(fd, &version, sizeof(u32)); + if (ret < 0) + goto out; + + ret = do_write(fd, &cnt, sizeof(u32)); + if (ret < 0) + goto out; + + for (i = 0; i < cnt; i++) { + struct cpu_cache_level *c = &caches[i]; + + #define _W(v) \ + ret = do_write(fd, &c->v, sizeof(u32)); \ + if (ret < 0) \ + goto out; + + _W(level) + _W(line_size) + _W(sets) + _W(ways) + #undef _W + + #define _W(v) \ + ret = do_write_string(fd, (const char *) c->v); \ + if (ret < 0) \ + goto out; + + _W(type) + _W(size) + _W(map) + #undef _W + } + +out: + for (i = 0; i < cnt; i++) + cpu_cache_level__free(&caches[i]); + return ret; +} + static int write_stat(int fd __maybe_unused, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) @@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused, fprintf(fp, "# contains stat data\n"); } +static void print_cache(struct perf_header *ph __maybe_unused, + int fd __maybe_unused, FILE *fp __maybe_unused) +{ + int i; + + fprintf(fp, "# CPU cache info:\n"); + for (i = 0; i < ph->env.caches_cnt; i++) { + fprintf(fp, "# "); + cpu_cache_level__fprintf(fp, &ph->env.caches[i]); + } +} + static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, FILE *fp) { @@ -1920,6 +2127,68 @@ static int process_auxtrace(struct perf_file_section *section, return err; } +static int process_cache(struct perf_file_section *section __maybe_unused, + struct perf_header *ph __maybe_unused, int fd __maybe_unused, + void *data __maybe_unused) +{ + struct cpu_cache_level *caches; + u32 cnt, i, version; + + if (readn(fd, &version, sizeof(version)) != sizeof(version)) + return -1; + + if (ph->needs_swap) + version = bswap_32(version); + + if (version != 1) + return -1; + + if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt)) + return -1; + + if (ph->needs_swap) + cnt = bswap_32(cnt); + + caches = zalloc(sizeof(*caches) * cnt); + if (!caches) + return -1; + + for (i = 0; i < cnt; i++) { + struct cpu_cache_level c; + + #define _R(v) \ + if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + goto out_free_caches; \ + if (ph->needs_swap) \ + c.v = bswap_32(c.v); \ + + _R(level) + _R(line_size) + _R(sets) + _R(ways) + #undef _R + + #define _R(v) \ + c.v = do_read_string(fd, ph); \ + if (!c.v) \ + goto out_free_caches; + + _R(type) + _R(size) + _R(map) + #undef _R + + caches[i] = c; + } + + ph->env.caches = caches; + ph->env.caches_cnt = cnt; + return 0; +out_free_caches: + free(caches); + return -1; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -1962,6 +2231,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPP(HEADER_GROUP_DESC, group_desc), FEAT_OPP(HEADER_AUXTRACE, auxtrace), FEAT_OPA(HEADER_STAT, stat), + FEAT_OPF(HEADER_CACHE, cache), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index cff9892..3d87ca8 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -32,6 +32,7 @@ enum { HEADER_GROUP_DESC, HEADER_AUXTRACE, HEADER_STAT, + HEADER_CACHE, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH 0/5] perf tools: Store CPU cache details under perf data 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa ` (4 preceding siblings ...) 2016-02-14 16:03 ` [PATCH 5/5] perf tools: Add perf data cache feature Jiri Olsa @ 2016-02-16 8:14 ` Ingo Molnar 2016-02-16 11:28 ` Jiri Olsa 5 siblings, 1 reply; 18+ messages in thread From: Ingo Molnar @ 2016-02-16 8:14 UTC (permalink / raw) To: Jiri Olsa Cc: Arnaldo Carvalho de Melo, lkml, David Ahern, Namhyung Kim, Peter Zijlstra * Jiri Olsa <jolsa@kernel.org> wrote: > hi, > adding support to store CPU cache details under perf data. > > $ perf report --header-only -I > ... > # cache info: > # L1 Data 32K [0-1] > # L1 Instruction 32K [0-1] > # L1 Data 32K [2-3] > # L1 Instruction 32K [2-3] > # L2 Unified 256K [0-1] > # L2 Unified 256K [2-3] > # L3 Unified 4096K [0-3] Very small UI nit, wouldn't it be nicer if this displayed tabular output, and if numbers were adjusted to their decimal point, i.e. something like: > # CPU cache info: > # L1 Data 32K [0-1] > # L1 Instruction 32K [0-1] > # L1 Data 32K [2-3] > # L1 Instruction 32K [2-3] > # L2 Unified 256K [0-1] > # L2 Unified 256K [2-3] > # L3 Unified 4096K [0-3] (Also note that it says 'CPU cache info' - there are a lot of caches in the system.) Thanks, Ingo ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 0/5] perf tools: Store CPU cache details under perf data 2016-02-16 8:14 ` [PATCH 0/5] perf tools: Store CPU cache details under perf data Ingo Molnar @ 2016-02-16 11:28 ` Jiri Olsa 0 siblings, 0 replies; 18+ messages in thread From: Jiri Olsa @ 2016-02-16 11:28 UTC (permalink / raw) To: Ingo Molnar Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, David Ahern, Namhyung Kim, Peter Zijlstra On Tue, Feb 16, 2016 at 09:14:13AM +0100, Ingo Molnar wrote: > > * Jiri Olsa <jolsa@kernel.org> wrote: > > > hi, > > adding support to store CPU cache details under perf data. > > > > $ perf report --header-only -I > > ... > > # cache info: > > # L1 Data 32K [0-1] > > # L1 Instruction 32K [0-1] > > # L1 Data 32K [2-3] > > # L1 Instruction 32K [2-3] > > # L2 Unified 256K [0-1] > > # L2 Unified 256K [2-3] > > # L3 Unified 4096K [0-3] > > Very small UI nit, wouldn't it be nicer if this displayed tabular output, and if > numbers were adjusted to their decimal point, i.e. something like: > > > # CPU cache info: > > # L1 Data 32K [0-1] > > # L1 Instruction 32K [0-1] > > # L1 Data 32K [2-3] > > # L1 Instruction 32K [2-3] > > # L2 Unified 256K [0-1] > > # L2 Unified 256K [2-3] > > # L3 Unified 4096K [0-3] > > (Also note that it says 'CPU cache info' - there are a lot of caches in the > system.) yep, looks better.. will change thanks, jirka ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2016-02-17 12:09 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-02-14 16:03 [PATCH 0/5] perf tools: Store CPU cache details under perf data Jiri Olsa 2016-02-14 16:03 ` [PATCH 1/5] tools lib api: Add debug output support Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 2/5] tools lib api fs: Move filename__read_str into api/fs/fs.c Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] tools lib api fs: Adopt filename__read_str from perf tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 3/5] tools lib api fs: Add sysfs__read_str function Jiri Olsa 2016-02-17 12:07 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 4/5] perf tools: Initialize libapi debug output Jiri Olsa 2016-02-17 12:08 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-14 16:03 ` [PATCH 5/5] perf tools: Add perf data cache feature Jiri Olsa 2016-02-16 12:11 ` [PATCHv2 " Jiri Olsa 2016-02-16 14:22 ` Namhyung Kim 2016-02-16 15:01 ` [PATCHv3 " Jiri Olsa 2016-02-16 15:29 ` Arnaldo Carvalho de Melo 2016-02-16 15:48 ` Arnaldo Carvalho de Melo 2016-02-17 12:08 ` [tip:perf/core] " tip-bot for Jiri Olsa 2016-02-16 8:14 ` [PATCH 0/5] perf tools: Store CPU cache details under perf data Ingo Molnar 2016-02-16 11:28 ` Jiri Olsa
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).