* [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
* [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
* [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
* [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
* [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 +++
| 265 +++++++++++++++++++++++++++++++++++++++++++++++
| 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 */
--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 {
--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: [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
* [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 +++
| 265 +++++++++++++++++++++++++++++++++++++++++++++++
| 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 */
--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 {
--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 +++
| 267 +++++++++++++++++++++++++++++++++++++++++++++++
| 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 */
--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 {
--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] 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
* [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
* [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
* [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
* [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 +++
| 270 +++++++++++++++++++++++++++++++++++++++++++++++
| 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 */
--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 {
--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
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).