linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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 +++
 tools/perf/util/header.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |   1 +
 4 files changed, 294 insertions(+)

diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939dea2e..02a6970f2495 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env)
 {
+	int i;
+
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->numa_nodes);
 	zfree(&env->pmu_mappings);
 	zfree(&env->cpu);
+
+	for (i = 0; i < env->caches_cnt; i++)
+		cache_level__free(&env->caches[i]);
+	zfree(&env->caches);
 }
 
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 	env->nr_cpus_avail = nr_cpus;
 	return 0;
 }
+
+void cache_level__free(struct cache_level *cache)
+{
+	free(cache->type);
+	free(cache->map);
+	free(cache->size);
+}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b9557c02..9963499820e7 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
 #ifndef __PERF_ENV_H
 #define __PERF_ENV_H
 
+#include <linux/types.h>
+
 struct cpu_topology_map {
 	int	socket_id;
 	int	core_id;
 };
 
+struct cache_level {
+	u32	level;
+	u32	line_size;
+	u32	sets;
+	u32	ways;
+	char	*type;
+	char	*size;
+	char	*map;
+};
+
 struct perf_env {
 	char			*hostname;
 	char			*os_release;
@@ -31,6 +43,8 @@ struct perf_env {
 	char			*numa_nodes;
 	char			*pmu_mappings;
 	struct cpu_topology_map	*cpu;
+	struct cache_level	*caches;
+	int			 caches_cnt;
 };
 
 extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
 
 int perf_env__read_cpu_topology_map(struct perf_env *env);
 
+void cache_level__free(struct cache_level *cache);
 #endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..55d5a7ff25f6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
 #include "strbuf.h"
 #include "build-id.h"
 #include "data.h"
+#include <api/fs/fs.h>
+#include "asm/bug.h"
 
 /*
  * magic2 = "PERFILE2"
@@ -868,6 +870,197 @@ static int write_auxtrace(int fd, struct perf_header *h,
 	return err;
 }
 
+static int cache_level__sort(const void *a, const void *b)
+{
+	struct cache_level *cache_a = (struct cache_level *) a;
+	struct cache_level *cache_b = (struct cache_level *) b;
+
+	return cache_a->level - cache_b->level;
+}
+
+static bool cache_level__cmp(struct cache_level *a, struct cache_level *b)
+{
+	if (a->level != b->level)
+		return false;
+
+	if (a->line_size != b->line_size)
+		return false;
+
+	if (a->sets != b->sets)
+		return false;
+
+	if (a->ways != b->ways)
+		return false;
+
+	if (strcmp(a->type, b->type))
+		return false;
+
+	if (strcmp(a->size, b->size))
+		return false;
+
+	if (strcmp(a->map, b->map))
+		return false;
+
+	return true;
+}
+
+static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level)
+{
+	char path[PATH_MAX], file[PATH_MAX];
+	struct stat st;
+	size_t len;
+
+	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
+	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
+
+	if (stat(file, &st))
+		return 1;
+
+	scnprintf(file, PATH_MAX, "%s/level", path);
+	if (sysfs__read_int(file, (int *) &cache->level))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
+	if (sysfs__read_int(file, (int *) &cache->line_size))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
+	if (sysfs__read_int(file, (int *) &cache->sets))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
+	if (sysfs__read_int(file, (int *) &cache->ways))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/type", path);
+	if (sysfs__read_str(file, &cache->type, &len))
+		return -1;
+
+	cache->type[len] = 0;
+	cache->type = rtrim(cache->type);
+
+	scnprintf(file, PATH_MAX, "%s/size", path);
+	if (sysfs__read_str(file, &cache->size, &len)) {
+		free(cache->type);
+		return -1;
+	}
+
+	cache->size[len] = 0;
+	cache->size = rtrim(cache->size);
+
+	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
+	if (sysfs__read_str(file, &cache->map, &len)) {
+		free(cache->map);
+		free(cache->type);
+		return -1;
+	}
+
+	cache->map[len] = 0;
+	cache->map = rtrim(cache->map);
+	return 0;
+}
+
+static void cache_level__fprintf(FILE *out, struct cache_level *c)
+{
+	fprintf(out, "L%d %s %s [%s]\n", c->level, c->type, c->size, c->map);
+}
+
+static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
+{
+	u32 i, cnt = 0;
+	long ncpus;
+	u32 nr, cpu;
+	u16 level;
+
+	ncpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (ncpus < 0)
+		return -1;
+
+	nr = (u32)(ncpus & UINT_MAX);
+
+	for (cpu = 0; cpu < nr; cpu++) {
+		for (level = 0; level < 10; level++) {
+			struct cache_level c;
+			int err;
+
+			err = cache_level__read(&c, cpu, level);
+			if (err < 0)
+				return err;
+
+			if (err == 1)
+				break;
+
+			for (i = 0; i < cnt; i++) {
+				if (cache_level__cmp(&c, &caches[i]))
+					break;
+			}
+
+			if (i == cnt)
+				caches[cnt++] = c;
+
+			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
+				goto out;
+		}
+	}
+ out:
+	*cntp = cnt;
+	return 0;
+}
+
+#define MAX_CACHES 2000
+
+static int write_cache(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
+{
+	struct cache_level caches[MAX_CACHES];
+	u32 cnt = 0, i, version = 1;
+	int ret;
+
+	ret = build_caches(caches, MAX_CACHES, &cnt);
+	if (ret)
+		goto out;
+
+	qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort);
+
+	ret = do_write(fd, &version, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	ret = do_write(fd, &cnt, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level *c = &caches[i];
+
+		#define _W(v)					\
+			ret = do_write(fd, &c->v, sizeof(u32));	\
+			if (ret < 0)				\
+				goto out;
+
+		_W(level)
+		_W(line_size)
+		_W(sets)
+		_W(ways)
+		#undef _W
+
+		#define _W(v)						\
+			ret = do_write_string(fd, (const char *) c->v);	\
+			if (ret < 0)					\
+				goto out;
+
+		_W(type)
+		_W(size)
+		_W(map)
+		#undef _W
+	}
+
+out:
+	for (i = 0; i < cnt; i++)
+		cache_level__free(&caches[i]);
+	return ret;
+}
+
 static int write_stat(int fd __maybe_unused,
 		      struct perf_header *h __maybe_unused,
 		      struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1365,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
 	fprintf(fp, "# contains stat data\n");
 }
 
+static void print_cache(struct perf_header *ph __maybe_unused,
+			int fd __maybe_unused, FILE *fp __maybe_unused)
+{
+	int i;
+
+	fprintf(fp, "# cache info:\n");
+	for (i = 0; i < ph->env.caches_cnt; i++) {
+		fprintf(fp, "#  ");
+		cache_level__fprintf(fp, &ph->env.caches[i]);
+	}
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
 			       FILE *fp)
 {
@@ -1920,6 +2125,65 @@ static int process_auxtrace(struct perf_file_section *section,
 	return err;
 }
 
+static int process_cache(struct perf_file_section *section __maybe_unused,
+			 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
+			 void *data __maybe_unused)
+{
+	struct cache_level *caches;
+	u32 cnt, i, version;
+
+	if (readn(fd, &version, sizeof(version)) != sizeof(version))
+		return -1;
+
+	if (ph->needs_swap)
+		version = bswap_32(version);
+
+	if (version != 1)
+		return -1;
+
+	if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
+		return -1;
+
+	if (ph->needs_swap)
+		cnt = bswap_32(cnt);
+
+	caches = zalloc(sizeof(struct cache_level) * cnt);
+	if (!caches)
+		return -1;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level c;
+
+		#define _R(v)						\
+			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
+				return -1;				\
+			if (ph->needs_swap)				\
+				c.v = bswap_32(c.v);			\
+
+		_R(level)
+		_R(line_size)
+		_R(sets)
+		_R(ways)
+		#undef _R
+
+		#define _R(v)				\
+			c.v = do_read_string(fd, ph);	\
+			if (!c.v)			\
+				return -1;
+
+		_R(type)
+		_R(size)
+		_R(map)
+		#undef _R
+
+		caches[i] = c;
+	}
+
+	ph->env.caches = caches;
+	ph->env.caches_cnt = cnt;
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2226,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
 	FEAT_OPP(HEADER_AUXTRACE,	auxtrace),
 	FEAT_OPA(HEADER_STAT,		stat),
+	FEAT_OPF(HEADER_CACHE,		cache),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892452ee..3d87ca823c0a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* 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 +++
 tools/perf/util/header.c | 265 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |   1 +
 4 files changed, 294 insertions(+)

diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939dea2e..02a6970f2495 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env)
 {
+	int i;
+
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->numa_nodes);
 	zfree(&env->pmu_mappings);
 	zfree(&env->cpu);
+
+	for (i = 0; i < env->caches_cnt; i++)
+		cache_level__free(&env->caches[i]);
+	zfree(&env->caches);
 }
 
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 	env->nr_cpus_avail = nr_cpus;
 	return 0;
 }
+
+void cache_level__free(struct cache_level *cache)
+{
+	free(cache->type);
+	free(cache->map);
+	free(cache->size);
+}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b9557c02..9963499820e7 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
 #ifndef __PERF_ENV_H
 #define __PERF_ENV_H
 
+#include <linux/types.h>
+
 struct cpu_topology_map {
 	int	socket_id;
 	int	core_id;
 };
 
+struct cache_level {
+	u32	level;
+	u32	line_size;
+	u32	sets;
+	u32	ways;
+	char	*type;
+	char	*size;
+	char	*map;
+};
+
 struct perf_env {
 	char			*hostname;
 	char			*os_release;
@@ -31,6 +43,8 @@ struct perf_env {
 	char			*numa_nodes;
 	char			*pmu_mappings;
 	struct cpu_topology_map	*cpu;
+	struct cache_level	*caches;
+	int			 caches_cnt;
 };
 
 extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
 
 int perf_env__read_cpu_topology_map(struct perf_env *env);
 
+void cache_level__free(struct cache_level *cache);
 #endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..5706c630071b 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
 #include "strbuf.h"
 #include "build-id.h"
 #include "data.h"
+#include <api/fs/fs.h>
+#include "asm/bug.h"
 
 /*
  * magic2 = "PERFILE2"
@@ -868,6 +870,197 @@ static int write_auxtrace(int fd, struct perf_header *h,
 	return err;
 }
 
+static int cache_level__sort(const void *a, const void *b)
+{
+	struct cache_level *cache_a = (struct cache_level *) a;
+	struct cache_level *cache_b = (struct cache_level *) b;
+
+	return cache_a->level - cache_b->level;
+}
+
+static bool cache_level__cmp(struct cache_level *a, struct cache_level *b)
+{
+	if (a->level != b->level)
+		return false;
+
+	if (a->line_size != b->line_size)
+		return false;
+
+	if (a->sets != b->sets)
+		return false;
+
+	if (a->ways != b->ways)
+		return false;
+
+	if (strcmp(a->type, b->type))
+		return false;
+
+	if (strcmp(a->size, b->size))
+		return false;
+
+	if (strcmp(a->map, b->map))
+		return false;
+
+	return true;
+}
+
+static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level)
+{
+	char path[PATH_MAX], file[PATH_MAX];
+	struct stat st;
+	size_t len;
+
+	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
+	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
+
+	if (stat(file, &st))
+		return 1;
+
+	scnprintf(file, PATH_MAX, "%s/level", path);
+	if (sysfs__read_int(file, (int *) &cache->level))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
+	if (sysfs__read_int(file, (int *) &cache->line_size))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
+	if (sysfs__read_int(file, (int *) &cache->sets))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
+	if (sysfs__read_int(file, (int *) &cache->ways))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/type", path);
+	if (sysfs__read_str(file, &cache->type, &len))
+		return -1;
+
+	cache->type[len] = 0;
+	cache->type = rtrim(cache->type);
+
+	scnprintf(file, PATH_MAX, "%s/size", path);
+	if (sysfs__read_str(file, &cache->size, &len)) {
+		free(cache->type);
+		return -1;
+	}
+
+	cache->size[len] = 0;
+	cache->size = rtrim(cache->size);
+
+	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
+	if (sysfs__read_str(file, &cache->map, &len)) {
+		free(cache->map);
+		free(cache->type);
+		return -1;
+	}
+
+	cache->map[len] = 0;
+	cache->map = rtrim(cache->map);
+	return 0;
+}
+
+static void cache_level__fprintf(FILE *out, struct cache_level *c)
+{
+	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
+}
+
+static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
+{
+	u32 i, cnt = 0;
+	long ncpus;
+	u32 nr, cpu;
+	u16 level;
+
+	ncpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (ncpus < 0)
+		return -1;
+
+	nr = (u32)(ncpus & UINT_MAX);
+
+	for (cpu = 0; cpu < nr; cpu++) {
+		for (level = 0; level < 10; level++) {
+			struct cache_level c;
+			int err;
+
+			err = cache_level__read(&c, cpu, level);
+			if (err < 0)
+				return err;
+
+			if (err == 1)
+				break;
+
+			for (i = 0; i < cnt; i++) {
+				if (cache_level__cmp(&c, &caches[i]))
+					break;
+			}
+
+			if (i == cnt)
+				caches[cnt++] = c;
+
+			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
+				goto out;
+		}
+	}
+ out:
+	*cntp = cnt;
+	return 0;
+}
+
+#define MAX_CACHES 2000
+
+static int write_cache(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
+{
+	struct cache_level caches[MAX_CACHES];
+	u32 cnt = 0, i, version = 1;
+	int ret;
+
+	ret = build_caches(caches, MAX_CACHES, &cnt);
+	if (ret)
+		goto out;
+
+	qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort);
+
+	ret = do_write(fd, &version, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	ret = do_write(fd, &cnt, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level *c = &caches[i];
+
+		#define _W(v)					\
+			ret = do_write(fd, &c->v, sizeof(u32));	\
+			if (ret < 0)				\
+				goto out;
+
+		_W(level)
+		_W(line_size)
+		_W(sets)
+		_W(ways)
+		#undef _W
+
+		#define _W(v)						\
+			ret = do_write_string(fd, (const char *) c->v);	\
+			if (ret < 0)					\
+				goto out;
+
+		_W(type)
+		_W(size)
+		_W(map)
+		#undef _W
+	}
+
+out:
+	for (i = 0; i < cnt; i++)
+		cache_level__free(&caches[i]);
+	return ret;
+}
+
 static int write_stat(int fd __maybe_unused,
 		      struct perf_header *h __maybe_unused,
 		      struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1365,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
 	fprintf(fp, "# contains stat data\n");
 }
 
+static void print_cache(struct perf_header *ph __maybe_unused,
+			int fd __maybe_unused, FILE *fp __maybe_unused)
+{
+	int i;
+
+	fprintf(fp, "# CPU cache info:\n");
+	for (i = 0; i < ph->env.caches_cnt; i++) {
+		fprintf(fp, "#  ");
+		cache_level__fprintf(fp, &ph->env.caches[i]);
+	}
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
 			       FILE *fp)
 {
@@ -1920,6 +2125,65 @@ static int process_auxtrace(struct perf_file_section *section,
 	return err;
 }
 
+static int process_cache(struct perf_file_section *section __maybe_unused,
+			 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
+			 void *data __maybe_unused)
+{
+	struct cache_level *caches;
+	u32 cnt, i, version;
+
+	if (readn(fd, &version, sizeof(version)) != sizeof(version))
+		return -1;
+
+	if (ph->needs_swap)
+		version = bswap_32(version);
+
+	if (version != 1)
+		return -1;
+
+	if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
+		return -1;
+
+	if (ph->needs_swap)
+		cnt = bswap_32(cnt);
+
+	caches = zalloc(sizeof(struct cache_level) * cnt);
+	if (!caches)
+		return -1;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level c;
+
+		#define _R(v)						\
+			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
+				return -1;				\
+			if (ph->needs_swap)				\
+				c.v = bswap_32(c.v);			\
+
+		_R(level)
+		_R(line_size)
+		_R(sets)
+		_R(ways)
+		#undef _R
+
+		#define _R(v)				\
+			c.v = do_read_string(fd, ph);	\
+			if (!c.v)			\
+				return -1;
+
+		_R(type)
+		_R(size)
+		_R(map)
+		#undef _R
+
+		caches[i] = c;
+	}
+
+	ph->env.caches = caches;
+	ph->env.caches_cnt = cnt;
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2226,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
 	FEAT_OPP(HEADER_AUXTRACE,	auxtrace),
 	FEAT_OPA(HEADER_STAT,		stat),
+	FEAT_OPF(HEADER_CACHE,		cache),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892452ee..3d87ca823c0a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCHv2 5/5] perf tools: Add perf data cache feature
  2016-02-16 12:11   ` [PATCHv2 " Jiri Olsa
@ 2016-02-16 14:22     ` Namhyung Kim
  2016-02-16 15:01       ` [PATCHv3 " Jiri Olsa
  0 siblings, 1 reply; 18+ messages in thread
From: Namhyung Kim @ 2016-02-16 14:22 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, lkml, David Ahern,
	Ingo Molnar, Peter Zijlstra

Hi Jiri,

On Tue, Feb 16, 2016 at 01:11:30PM +0100, Jiri Olsa wrote:
> On Sun, Feb 14, 2016 at 05:03:46PM +0100, Jiri Olsa wrote:
> > Storing CPU cache details under perf data. It's stored
> > as new HEADER_CACHE feature and it's displayed under
> > header info with -I option:
> > 
> >   $ perf report --header-only -I
> >   ...
> >   # cache info:
> >   #  L1 Data 32K [0-1]
> >   #  L1 Instruction 32K [0-1]
> >   #  L1 Data 32K [2-3]
> >   #  L1 Instruction 32K [2-3]
> >   #  L2 Unified 256K [0-1]
> >   #  L2 Unified 256K [2-3]
> >   #  L3 Unified 4096K [0-3]
> >   ...
> > 
> 
> changing the output based on Ingo's comment
> v2 attached, the rest of the patchset stays
> 
> my perf/cache branch is updated
> 
> thanks,
> jirka
> 
> 
> ---
> Storing CPU cache details under perf data. It's stored
> as new HEADER_CACHE feature and it's displayed under
> header info with -I option:
> 
>   $ perf report --header-only -I
>   ...
>   # CPU cache info:
>   #  L1 Data                 32K [0-1]
>   #  L1 Instruction          32K [0-1]
>   #  L1 Data                 32K [2-3]
>   #  L1 Instruction          32K [2-3]
>   #  L2 Unified             256K [0-1]
>   #  L2 Unified             256K [2-3]
>   #  L3 Unified            4096K [0-3]
>   ...
> 
> All distinct caches are stored/displayed.
> 
> Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---

[SNIP]
> +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
> +{
> +	u32 i, cnt = 0;
> +	long ncpus;
> +	u32 nr, cpu;
> +	u16 level;
> +
> +	ncpus = sysconf(_SC_NPROCESSORS_CONF);
> +	if (ncpus < 0)
> +		return -1;
> +
> +	nr = (u32)(ncpus & UINT_MAX);
> +
> +	for (cpu = 0; cpu < nr; cpu++) {
> +		for (level = 0; level < 10; level++) {
> +			struct cache_level c;
> +			int err;
> +
> +			err = cache_level__read(&c, cpu, level);
> +			if (err < 0)
> +				return err;
> +
> +			if (err == 1)
> +				break;
> +
> +			for (i = 0; i < cnt; i++) {
> +				if (cache_level__cmp(&c, &caches[i]))
> +					break;
> +			}
> +
> +			if (i == cnt)
> +				caches[cnt++] = c;

			else
				cache_level__free(&c);
???

Thanks,
Namhyung


> +
> +			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
> +				goto out;
> +		}
> +	}
> + out:
> +	*cntp = cnt;
> +	return 0;
> +}

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCHv3 5/5] perf tools: Add perf data cache feature
  2016-02-16 14:22     ` Namhyung Kim
@ 2016-02-16 15:01       ` Jiri Olsa
  2016-02-16 15:29         ` Arnaldo Carvalho de Melo
  2016-02-17 12:08         ` [tip:perf/core] " tip-bot for Jiri Olsa
  0 siblings, 2 replies; 18+ messages in thread
From: Jiri Olsa @ 2016-02-16 15:01 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Jiri Olsa, lkml, David Ahern,
	Ingo Molnar, Peter Zijlstra

On Tue, Feb 16, 2016 at 11:22:19PM +0900, Namhyung Kim wrote:

SNIP

> 
> [SNIP]
> > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
> > +{
> > +	u32 i, cnt = 0;
> > +	long ncpus;
> > +	u32 nr, cpu;
> > +	u16 level;
> > +
> > +	ncpus = sysconf(_SC_NPROCESSORS_CONF);
> > +	if (ncpus < 0)
> > +		return -1;
> > +
> > +	nr = (u32)(ncpus & UINT_MAX);
> > +
> > +	for (cpu = 0; cpu < nr; cpu++) {
> > +		for (level = 0; level < 10; level++) {
> > +			struct cache_level c;
> > +			int err;
> > +
> > +			err = cache_level__read(&c, cpu, level);
> > +			if (err < 0)
> > +				return err;
> > +
> > +			if (err == 1)
> > +				break;
> > +
> > +			for (i = 0; i < cnt; i++) {
> > +				if (cache_level__cmp(&c, &caches[i]))
> > +					break;
> > +			}
> > +
> > +			if (i == cnt)
> > +				caches[cnt++] = c;
> 
> 			else
> 				cache_level__free(&c);
> ???

ouch right.. v3 attached

thanks,
jirka


---
Storing CPU cache details under perf data. It's stored
as new HEADER_CACHE feature and it's displayed under
header info with -I option:

  $ perf report --header-only -I
  ...
  # CPU cache info:
  #  L1 Data                 32K [0-1]
  #  L1 Instruction          32K [0-1]
  #  L1 Data                 32K [2-3]
  #  L1 Instruction          32K [2-3]
  #  L2 Unified             256K [0-1]
  #  L2 Unified             256K [2-3]
  #  L3 Unified            4096K [0-3]
  ...

All distinct caches are stored/displayed.

Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/env.c    |  13 +++
 tools/perf/util/env.h    |  15 +++
 tools/perf/util/header.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |   1 +
 4 files changed, 296 insertions(+)

diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939dea2e..02a6970f2495 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env)
 {
+	int i;
+
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->numa_nodes);
 	zfree(&env->pmu_mappings);
 	zfree(&env->cpu);
+
+	for (i = 0; i < env->caches_cnt; i++)
+		cache_level__free(&env->caches[i]);
+	zfree(&env->caches);
 }
 
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 	env->nr_cpus_avail = nr_cpus;
 	return 0;
 }
+
+void cache_level__free(struct cache_level *cache)
+{
+	free(cache->type);
+	free(cache->map);
+	free(cache->size);
+}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b9557c02..9963499820e7 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
 #ifndef __PERF_ENV_H
 #define __PERF_ENV_H
 
+#include <linux/types.h>
+
 struct cpu_topology_map {
 	int	socket_id;
 	int	core_id;
 };
 
+struct cache_level {
+	u32	level;
+	u32	line_size;
+	u32	sets;
+	u32	ways;
+	char	*type;
+	char	*size;
+	char	*map;
+};
+
 struct perf_env {
 	char			*hostname;
 	char			*os_release;
@@ -31,6 +43,8 @@ struct perf_env {
 	char			*numa_nodes;
 	char			*pmu_mappings;
 	struct cpu_topology_map	*cpu;
+	struct cache_level	*caches;
+	int			 caches_cnt;
 };
 
 extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
 
 int perf_env__read_cpu_topology_map(struct perf_env *env);
 
+void cache_level__free(struct cache_level *cache);
 #endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..f5803fa3dc63 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
 #include "strbuf.h"
 #include "build-id.h"
 #include "data.h"
+#include <api/fs/fs.h>
+#include "asm/bug.h"
 
 /*
  * magic2 = "PERFILE2"
@@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
 	return err;
 }
 
+static int cache_level__sort(const void *a, const void *b)
+{
+	struct cache_level *cache_a = (struct cache_level *) a;
+	struct cache_level *cache_b = (struct cache_level *) b;
+
+	return cache_a->level - cache_b->level;
+}
+
+static bool cache_level__cmp(struct cache_level *a, struct cache_level *b)
+{
+	if (a->level != b->level)
+		return false;
+
+	if (a->line_size != b->line_size)
+		return false;
+
+	if (a->sets != b->sets)
+		return false;
+
+	if (a->ways != b->ways)
+		return false;
+
+	if (strcmp(a->type, b->type))
+		return false;
+
+	if (strcmp(a->size, b->size))
+		return false;
+
+	if (strcmp(a->map, b->map))
+		return false;
+
+	return true;
+}
+
+static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level)
+{
+	char path[PATH_MAX], file[PATH_MAX];
+	struct stat st;
+	size_t len;
+
+	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
+	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
+
+	if (stat(file, &st))
+		return 1;
+
+	scnprintf(file, PATH_MAX, "%s/level", path);
+	if (sysfs__read_int(file, (int *) &cache->level))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
+	if (sysfs__read_int(file, (int *) &cache->line_size))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
+	if (sysfs__read_int(file, (int *) &cache->sets))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
+	if (sysfs__read_int(file, (int *) &cache->ways))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/type", path);
+	if (sysfs__read_str(file, &cache->type, &len))
+		return -1;
+
+	cache->type[len] = 0;
+	cache->type = rtrim(cache->type);
+
+	scnprintf(file, PATH_MAX, "%s/size", path);
+	if (sysfs__read_str(file, &cache->size, &len)) {
+		free(cache->type);
+		return -1;
+	}
+
+	cache->size[len] = 0;
+	cache->size = rtrim(cache->size);
+
+	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
+	if (sysfs__read_str(file, &cache->map, &len)) {
+		free(cache->map);
+		free(cache->type);
+		return -1;
+	}
+
+	cache->map[len] = 0;
+	cache->map = rtrim(cache->map);
+	return 0;
+}
+
+static void cache_level__fprintf(FILE *out, struct cache_level *c)
+{
+	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
+}
+
+static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
+{
+	u32 i, cnt = 0;
+	long ncpus;
+	u32 nr, cpu;
+	u16 level;
+
+	ncpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (ncpus < 0)
+		return -1;
+
+	nr = (u32)(ncpus & UINT_MAX);
+
+	for (cpu = 0; cpu < nr; cpu++) {
+		for (level = 0; level < 10; level++) {
+			struct cache_level c;
+			int err;
+
+			err = cache_level__read(&c, cpu, level);
+			if (err < 0)
+				return err;
+
+			if (err == 1)
+				break;
+
+			for (i = 0; i < cnt; i++) {
+				if (cache_level__cmp(&c, &caches[i]))
+					break;
+			}
+
+			if (i == cnt)
+				caches[cnt++] = c;
+			else
+				cache_level__free(&c);
+
+			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
+				goto out;
+		}
+	}
+ out:
+	*cntp = cnt;
+	return 0;
+}
+
+#define MAX_CACHES 2000
+
+static int write_cache(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
+{
+	struct cache_level caches[MAX_CACHES];
+	u32 cnt = 0, i, version = 1;
+	int ret;
+
+	ret = build_caches(caches, MAX_CACHES, &cnt);
+	if (ret)
+		goto out;
+
+	qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort);
+
+	ret = do_write(fd, &version, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	ret = do_write(fd, &cnt, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level *c = &caches[i];
+
+		#define _W(v)					\
+			ret = do_write(fd, &c->v, sizeof(u32));	\
+			if (ret < 0)				\
+				goto out;
+
+		_W(level)
+		_W(line_size)
+		_W(sets)
+		_W(ways)
+		#undef _W
+
+		#define _W(v)						\
+			ret = do_write_string(fd, (const char *) c->v);	\
+			if (ret < 0)					\
+				goto out;
+
+		_W(type)
+		_W(size)
+		_W(map)
+		#undef _W
+	}
+
+out:
+	for (i = 0; i < cnt; i++)
+		cache_level__free(&caches[i]);
+	return ret;
+}
+
 static int write_stat(int fd __maybe_unused,
 		      struct perf_header *h __maybe_unused,
 		      struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
 	fprintf(fp, "# contains stat data\n");
 }
 
+static void print_cache(struct perf_header *ph __maybe_unused,
+			int fd __maybe_unused, FILE *fp __maybe_unused)
+{
+	int i;
+
+	fprintf(fp, "# CPU cache info:\n");
+	for (i = 0; i < ph->env.caches_cnt; i++) {
+		fprintf(fp, "#  ");
+		cache_level__fprintf(fp, &ph->env.caches[i]);
+	}
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
 			       FILE *fp)
 {
@@ -1920,6 +2127,65 @@ static int process_auxtrace(struct perf_file_section *section,
 	return err;
 }
 
+static int process_cache(struct perf_file_section *section __maybe_unused,
+			 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
+			 void *data __maybe_unused)
+{
+	struct cache_level *caches;
+	u32 cnt, i, version;
+
+	if (readn(fd, &version, sizeof(version)) != sizeof(version))
+		return -1;
+
+	if (ph->needs_swap)
+		version = bswap_32(version);
+
+	if (version != 1)
+		return -1;
+
+	if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
+		return -1;
+
+	if (ph->needs_swap)
+		cnt = bswap_32(cnt);
+
+	caches = zalloc(sizeof(struct cache_level) * cnt);
+	if (!caches)
+		return -1;
+
+	for (i = 0; i < cnt; i++) {
+		struct cache_level c;
+
+		#define _R(v)						\
+			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
+				return -1;				\
+			if (ph->needs_swap)				\
+				c.v = bswap_32(c.v);			\
+
+		_R(level)
+		_R(line_size)
+		_R(sets)
+		_R(ways)
+		#undef _R
+
+		#define _R(v)				\
+			c.v = do_read_string(fd, ph);	\
+			if (!c.v)			\
+				return -1;
+
+		_R(type)
+		_R(size)
+		_R(map)
+		#undef _R
+
+		caches[i] = c;
+	}
+
+	ph->env.caches = caches;
+	ph->env.caches_cnt = cnt;
+	return 0;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2228,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
 	FEAT_OPP(HEADER_AUXTRACE,	auxtrace),
 	FEAT_OPA(HEADER_STAT,		stat),
+	FEAT_OPF(HEADER_CACHE,		cache),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892452ee..3d87ca823c0a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCHv3 5/5] perf tools: Add perf data cache feature
  2016-02-16 15:01       ` [PATCHv3 " Jiri Olsa
@ 2016-02-16 15:29         ` Arnaldo Carvalho de Melo
  2016-02-16 15:48           ` Arnaldo Carvalho de Melo
  2016-02-17 12:08         ` [tip:perf/core] " tip-bot for Jiri Olsa
  1 sibling, 1 reply; 18+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-16 15:29 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Namhyung Kim, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra

Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu:
> On Tue, Feb 16, 2016 at 11:22:19PM +0900, Namhyung Kim wrote:
> 
> SNIP
> 
> > 
> > [SNIP]
> > > +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
> > > +{
> > > +	u32 i, cnt = 0;
> > > +	long ncpus;
> > > +	u32 nr, cpu;
> > > +	u16 level;
> > > +
> > > +	ncpus = sysconf(_SC_NPROCESSORS_CONF);
> > > +	if (ncpus < 0)
> > > +		return -1;
> > > +
> > > +	nr = (u32)(ncpus & UINT_MAX);
> > > +
> > > +	for (cpu = 0; cpu < nr; cpu++) {
> > > +		for (level = 0; level < 10; level++) {
> > > +			struct cache_level c;
> > > +			int err;
> > > +
> > > +			err = cache_level__read(&c, cpu, level);
> > > +			if (err < 0)
> > > +				return err;
> > > +
> > > +			if (err == 1)
> > > +				break;
> > > +
> > > +			for (i = 0; i < cnt; i++) {
> > > +				if (cache_level__cmp(&c, &caches[i]))
> > > +					break;
> > > +			}
> > > +
> > > +			if (i == cnt)
> > > +				caches[cnt++] = c;
> > 
> > 			else
> > 				cache_level__free(&c);
> > ???
> 
> ouch right.. v3 attached
> 
> thanks,
> jirka
> 
> 
> ---
> Storing CPU cache details under perf data. It's stored
> as new HEADER_CACHE feature and it's displayed under
> header info with -I option:
> 
>   $ perf report --header-only -I
>   ...
>   # CPU cache info:
>   #  L1 Data                 32K [0-1]
>   #  L1 Instruction          32K [0-1]
>   #  L1 Data                 32K [2-3]
>   #  L1 Instruction          32K [2-3]
>   #  L2 Unified             256K [0-1]
>   #  L2 Unified             256K [2-3]
>   #  L3 Unified            4096K [0-3]
>   ...
> 
> All distinct caches are stored/displayed.
> 
> Link: http://lkml.kernel.org/n/tip-byxl1gwto8z9d5hyozprtaty@git.kernel.org
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/perf/util/env.c    |  13 +++
>  tools/perf/util/env.h    |  15 +++
>  tools/perf/util/header.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/header.h |   1 +
>  4 files changed, 296 insertions(+)
> 
> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
> index 7dd5939dea2e..02a6970f2495 100644
> --- a/tools/perf/util/env.c
> +++ b/tools/perf/util/env.c
> @@ -6,6 +6,8 @@ struct perf_env perf_env;
>  
>  void perf_env__exit(struct perf_env *env)
>  {
> +	int i;
> +
>  	zfree(&env->hostname);
>  	zfree(&env->os_release);
>  	zfree(&env->version);
> @@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
>  	zfree(&env->numa_nodes);
>  	zfree(&env->pmu_mappings);
>  	zfree(&env->cpu);
> +
> +	for (i = 0; i < env->caches_cnt; i++)
> +		cache_level__free(&env->caches[i]);
> +	zfree(&env->caches);
>  }
>  
>  int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
> @@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
>  	env->nr_cpus_avail = nr_cpus;
>  	return 0;
>  }
> +
> +void cache_level__free(struct cache_level *cache)
> +{
> +	free(cache->type);
> +	free(cache->map);
> +	free(cache->size);
> +}
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index 0132b9557c02..9963499820e7 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -1,11 +1,23 @@
>  #ifndef __PERF_ENV_H
>  #define __PERF_ENV_H
>  
> +#include <linux/types.h>
> +
>  struct cpu_topology_map {
>  	int	socket_id;
>  	int	core_id;
>  };
>  
> +struct cache_level {
> +	u32	level;
> +	u32	line_size;
> +	u32	sets;
> +	u32	ways;
> +	char	*type;
> +	char	*size;
> +	char	*map;
> +};
> +
>  struct perf_env {
>  	char			*hostname;
>  	char			*os_release;
> @@ -31,6 +43,8 @@ struct perf_env {
>  	char			*numa_nodes;
>  	char			*pmu_mappings;
>  	struct cpu_topology_map	*cpu;
> +	struct cache_level	*caches;
> +	int			 caches_cnt;
>  };
>  
>  extern struct perf_env perf_env;
> @@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
>  
>  int perf_env__read_cpu_topology_map(struct perf_env *env);
>  
> +void cache_level__free(struct cache_level *cache);
>  #endif /* __PERF_ENV_H */
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index f50b7235ecb6..f5803fa3dc63 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -23,6 +23,8 @@
>  #include "strbuf.h"
>  #include "build-id.h"
>  #include "data.h"
> +#include <api/fs/fs.h>
> +#include "asm/bug.h"
>  
>  /*
>   * magic2 = "PERFILE2"
> @@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
>  	return err;
>  }
>  
> +static int cache_level__sort(const void *a, const void *b)
> +{
> +	struct cache_level *cache_a = (struct cache_level *) a;
> +	struct cache_level *cache_b = (struct cache_level *) b;
> +
> +	return cache_a->level - cache_b->level;
> +}
> +
> +static bool cache_level__cmp(struct cache_level *a, struct cache_level *b)
> +{
> +	if (a->level != b->level)
> +		return false;
> +
> +	if (a->line_size != b->line_size)
> +		return false;
> +
> +	if (a->sets != b->sets)
> +		return false;
> +
> +	if (a->ways != b->ways)
> +		return false;
> +
> +	if (strcmp(a->type, b->type))
> +		return false;
> +
> +	if (strcmp(a->size, b->size))
> +		return false;
> +
> +	if (strcmp(a->map, b->map))
> +		return false;
> +
> +	return true;
> +}
> +
> +static int cache_level__read(struct cache_level *cache, u32 cpu, u16 level)
> +{
> +	char path[PATH_MAX], file[PATH_MAX];
> +	struct stat st;
> +	size_t len;
> +
> +	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
> +	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
> +
> +	if (stat(file, &st))
> +		return 1;
> +
> +	scnprintf(file, PATH_MAX, "%s/level", path);
> +	if (sysfs__read_int(file, (int *) &cache->level))
> +		return -1;
> +
> +	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
> +	if (sysfs__read_int(file, (int *) &cache->line_size))
> +		return -1;
> +
> +	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
> +	if (sysfs__read_int(file, (int *) &cache->sets))
> +		return -1;
> +
> +	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
> +	if (sysfs__read_int(file, (int *) &cache->ways))
> +		return -1;
> +
> +	scnprintf(file, PATH_MAX, "%s/type", path);
> +	if (sysfs__read_str(file, &cache->type, &len))
> +		return -1;
> +
> +	cache->type[len] = 0;
> +	cache->type = rtrim(cache->type);
> +
> +	scnprintf(file, PATH_MAX, "%s/size", path);
> +	if (sysfs__read_str(file, &cache->size, &len)) {
> +		free(cache->type);
> +		return -1;
> +	}
> +
> +	cache->size[len] = 0;
> +	cache->size = rtrim(cache->size);
> +
> +	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
> +	if (sysfs__read_str(file, &cache->map, &len)) {
> +		free(cache->map);
> +		free(cache->type);
> +		return -1;
> +	}
> +
> +	cache->map[len] = 0;
> +	cache->map = rtrim(cache->map);
> +	return 0;
> +}
> +
> +static void cache_level__fprintf(FILE *out, struct cache_level *c)
> +{
> +	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
> +}
> +
> +static int build_caches(struct cache_level caches[], u32 size, u32 *cntp)
> +{
> +	u32 i, cnt = 0;
> +	long ncpus;
> +	u32 nr, cpu;
> +	u16 level;
> +
> +	ncpus = sysconf(_SC_NPROCESSORS_CONF);
> +	if (ncpus < 0)
> +		return -1;
> +
> +	nr = (u32)(ncpus & UINT_MAX);
> +
> +	for (cpu = 0; cpu < nr; cpu++) {
> +		for (level = 0; level < 10; level++) {
> +			struct cache_level c;
> +			int err;
> +
> +			err = cache_level__read(&c, cpu, level);
> +			if (err < 0)
> +				return err;
> +
> +			if (err == 1)
> +				break;
> +
> +			for (i = 0; i < cnt; i++) {
> +				if (cache_level__cmp(&c, &caches[i]))
> +					break;
> +			}
> +
> +			if (i == cnt)
> +				caches[cnt++] = c;
> +			else
> +				cache_level__free(&c);
> +
> +			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
> +				goto out;
> +		}
> +	}
> + out:
> +	*cntp = cnt;
> +	return 0;
> +}
> +
> +#define MAX_CACHES 2000
> +
> +static int write_cache(int fd, struct perf_header *h __maybe_unused,
> +			  struct perf_evlist *evlist __maybe_unused)
> +{
> +	struct cache_level caches[MAX_CACHES];
> +	u32 cnt = 0, i, version = 1;
> +	int ret;
> +
> +	ret = build_caches(caches, MAX_CACHES, &cnt);
> +	if (ret)
> +		goto out;
> +
> +	qsort(&caches, cnt, sizeof(struct cache_level), cache_level__sort);
> +
> +	ret = do_write(fd, &version, sizeof(u32));
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = do_write(fd, &cnt, sizeof(u32));
> +	if (ret < 0)
> +		goto out;
> +
> +	for (i = 0; i < cnt; i++) {
> +		struct cache_level *c = &caches[i];
> +
> +		#define _W(v)					\
> +			ret = do_write(fd, &c->v, sizeof(u32));	\
> +			if (ret < 0)				\
> +				goto out;
> +
> +		_W(level)
> +		_W(line_size)
> +		_W(sets)
> +		_W(ways)
> +		#undef _W
> +
> +		#define _W(v)						\
> +			ret = do_write_string(fd, (const char *) c->v);	\
> +			if (ret < 0)					\
> +				goto out;
> +
> +		_W(type)
> +		_W(size)
> +		_W(map)
> +		#undef _W
> +	}
> +
> +out:
> +	for (i = 0; i < cnt; i++)
> +		cache_level__free(&caches[i]);
> +	return ret;
> +}
> +
>  static int write_stat(int fd __maybe_unused,
>  		      struct perf_header *h __maybe_unused,
>  		      struct perf_evlist *evlist __maybe_unused)
> @@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
>  	fprintf(fp, "# contains stat data\n");
>  }
>  
> +static void print_cache(struct perf_header *ph __maybe_unused,
> +			int fd __maybe_unused, FILE *fp __maybe_unused)
> +{
> +	int i;
> +
> +	fprintf(fp, "# CPU cache info:\n");
> +	for (i = 0; i < ph->env.caches_cnt; i++) {
> +		fprintf(fp, "#  ");
> +		cache_level__fprintf(fp, &ph->env.caches[i]);
> +	}
> +}
> +
>  static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
>  			       FILE *fp)
>  {
> @@ -1920,6 +2127,65 @@ static int process_auxtrace(struct perf_file_section *section,
>  	return err;
>  }
>  
> +static int process_cache(struct perf_file_section *section __maybe_unused,
> +			 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
> +			 void *data __maybe_unused)
> +{
> +	struct cache_level *caches;
> +	u32 cnt, i, version;
> +
> +	if (readn(fd, &version, sizeof(version)) != sizeof(version))
> +		return -1;
> +
> +	if (ph->needs_swap)
> +		version = bswap_32(version);
> +
> +	if (version != 1)
> +		return -1;
> +
> +	if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
> +		return -1;
> +
> +	if (ph->needs_swap)
> +		cnt = bswap_32(cnt);
> +
> +	caches = zalloc(sizeof(struct cache_level) * cnt);
> +	if (!caches)
> +		return -1;
> +
> +	for (i = 0; i < cnt; i++) {
> +		struct cache_level c;
> +
> +		#define _R(v)						\
> +			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
> +				return -1;				\

So in this case that 'caches' variable leaks?

> +			if (ph->needs_swap)				\
> +				c.v = bswap_32(c.v);			\
> +
> +		_R(level)
> +		_R(line_size)
> +		_R(sets)
> +		_R(ways)
> +		#undef _R
> +
> +		#define _R(v)				\
> +			c.v = do_read_string(fd, ph);	\
> +			if (!c.v)			\

Ditto.

> +				return -1;
> +
> +		_R(type)
> +		_R(size)
> +		_R(map)
> +		#undef _R
> +
> +		caches[i] = c;
> +	}

Because it is only here that you assign it to something outside this
function.

Also, as discussed on IRC, please s/cache_level/cpu_cache_level/g, as
per Ingo's comment.

- Arnaldo

> +	ph->env.caches = caches;
> +	ph->env.caches_cnt = cnt;
> +	return 0;
> +}
> +
>  struct feature_ops {
>  	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
>  	void (*print)(struct perf_header *h, int fd, FILE *fp);
> @@ -1962,6 +2228,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
>  	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
>  	FEAT_OPP(HEADER_AUXTRACE,	auxtrace),
>  	FEAT_OPA(HEADER_STAT,		stat),
> +	FEAT_OPF(HEADER_CACHE,		cache),
>  };
>  
>  struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index cff9892452ee..3d87ca823c0a 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -32,6 +32,7 @@ enum {
>  	HEADER_GROUP_DESC,
>  	HEADER_AUXTRACE,
>  	HEADER_STAT,
> +	HEADER_CACHE,
>  	HEADER_LAST_FEATURE,
>  	HEADER_FEAT_BITS	= 256,
>  };
> -- 
> 2.4.3

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCHv3 5/5] perf tools: Add perf data cache feature
  2016-02-16 15:29         ` Arnaldo Carvalho de Melo
@ 2016-02-16 15:48           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 18+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-02-16 15:48 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Namhyung Kim, Jiri Olsa, lkml, David Ahern, Ingo Molnar, Peter Zijlstra

Em Tue, Feb 16, 2016 at 12:29:36PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu:
> > +	caches = zalloc(sizeof(struct cache_level) * cnt);
> > +	if (!caches)
> > +		return -1;
> > +
> > +	for (i = 0; i < cnt; i++) {
> > +		struct cache_level c;
> > +
> > +		#define _R(v)						\
> > +			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
> > +				return -1;				\
> 
> So in this case that 'caches' variable leaks?
> 

Ok, I fixed this and did the rename to cpu_cache_level, tested and
merged it, going to the next patchkit.

Thanks! Useful feature, we should use it in other places, like: record
same workload in different machines, say Ivy Bridge and Broadwell, do
'perf diff' and see the CPU cache topology difference in addition to
other symbolic, per DSO, etc diffs.

- Arnaldo

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [tip:perf/core] 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 +++
 tools/perf/util/header.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h |   1 +
 4 files changed, 299 insertions(+)

diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939..49a11d9 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
 
 void perf_env__exit(struct perf_env *env)
 {
+	int i;
+
 	zfree(&env->hostname);
 	zfree(&env->os_release);
 	zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
 	zfree(&env->numa_nodes);
 	zfree(&env->pmu_mappings);
 	zfree(&env->cpu);
+
+	for (i = 0; i < env->caches_cnt; i++)
+		cpu_cache_level__free(&env->caches[i]);
+	zfree(&env->caches);
 }
 
 int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 	env->nr_cpus_avail = nr_cpus;
 	return 0;
 }
+
+void cpu_cache_level__free(struct cpu_cache_level *cache)
+{
+	free(cache->type);
+	free(cache->map);
+	free(cache->size);
+}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b95..56cffb6 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
 #ifndef __PERF_ENV_H
 #define __PERF_ENV_H
 
+#include <linux/types.h>
+
 struct cpu_topology_map {
 	int	socket_id;
 	int	core_id;
 };
 
+struct cpu_cache_level {
+	u32	level;
+	u32	line_size;
+	u32	sets;
+	u32	ways;
+	char	*type;
+	char	*size;
+	char	*map;
+};
+
 struct perf_env {
 	char			*hostname;
 	char			*os_release;
@@ -31,6 +43,8 @@ struct perf_env {
 	char			*numa_nodes;
 	char			*pmu_mappings;
 	struct cpu_topology_map	*cpu;
+	struct cpu_cache_level	*caches;
+	int			 caches_cnt;
 };
 
 extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
 
 int perf_env__read_cpu_topology_map(struct perf_env *env);
 
+void cpu_cache_level__free(struct cpu_cache_level *cache);
 #endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b723..73e38e4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
 #include "strbuf.h"
 #include "build-id.h"
 #include "data.h"
+#include <api/fs/fs.h>
+#include "asm/bug.h"
 
 /*
  * magic2 = "PERFILE2"
@@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
 	return err;
 }
 
+static int cpu_cache_level__sort(const void *a, const void *b)
+{
+	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
+	struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
+
+	return cache_a->level - cache_b->level;
+}
+
+static bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
+{
+	if (a->level != b->level)
+		return false;
+
+	if (a->line_size != b->line_size)
+		return false;
+
+	if (a->sets != b->sets)
+		return false;
+
+	if (a->ways != b->ways)
+		return false;
+
+	if (strcmp(a->type, b->type))
+		return false;
+
+	if (strcmp(a->size, b->size))
+		return false;
+
+	if (strcmp(a->map, b->map))
+		return false;
+
+	return true;
+}
+
+static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
+{
+	char path[PATH_MAX], file[PATH_MAX];
+	struct stat st;
+	size_t len;
+
+	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
+	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
+
+	if (stat(file, &st))
+		return 1;
+
+	scnprintf(file, PATH_MAX, "%s/level", path);
+	if (sysfs__read_int(file, (int *) &cache->level))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
+	if (sysfs__read_int(file, (int *) &cache->line_size))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
+	if (sysfs__read_int(file, (int *) &cache->sets))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
+	if (sysfs__read_int(file, (int *) &cache->ways))
+		return -1;
+
+	scnprintf(file, PATH_MAX, "%s/type", path);
+	if (sysfs__read_str(file, &cache->type, &len))
+		return -1;
+
+	cache->type[len] = 0;
+	cache->type = rtrim(cache->type);
+
+	scnprintf(file, PATH_MAX, "%s/size", path);
+	if (sysfs__read_str(file, &cache->size, &len)) {
+		free(cache->type);
+		return -1;
+	}
+
+	cache->size[len] = 0;
+	cache->size = rtrim(cache->size);
+
+	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
+	if (sysfs__read_str(file, &cache->map, &len)) {
+		free(cache->map);
+		free(cache->type);
+		return -1;
+	}
+
+	cache->map[len] = 0;
+	cache->map = rtrim(cache->map);
+	return 0;
+}
+
+static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
+{
+	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
+}
+
+static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
+{
+	u32 i, cnt = 0;
+	long ncpus;
+	u32 nr, cpu;
+	u16 level;
+
+	ncpus = sysconf(_SC_NPROCESSORS_CONF);
+	if (ncpus < 0)
+		return -1;
+
+	nr = (u32)(ncpus & UINT_MAX);
+
+	for (cpu = 0; cpu < nr; cpu++) {
+		for (level = 0; level < 10; level++) {
+			struct cpu_cache_level c;
+			int err;
+
+			err = cpu_cache_level__read(&c, cpu, level);
+			if (err < 0)
+				return err;
+
+			if (err == 1)
+				break;
+
+			for (i = 0; i < cnt; i++) {
+				if (cpu_cache_level__cmp(&c, &caches[i]))
+					break;
+			}
+
+			if (i == cnt)
+				caches[cnt++] = c;
+			else
+				cpu_cache_level__free(&c);
+
+			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
+				goto out;
+		}
+	}
+ out:
+	*cntp = cnt;
+	return 0;
+}
+
+#define MAX_CACHES 2000
+
+static int write_cache(int fd, struct perf_header *h __maybe_unused,
+			  struct perf_evlist *evlist __maybe_unused)
+{
+	struct cpu_cache_level caches[MAX_CACHES];
+	u32 cnt = 0, i, version = 1;
+	int ret;
+
+	ret = build_caches(caches, MAX_CACHES, &cnt);
+	if (ret)
+		goto out;
+
+	qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
+
+	ret = do_write(fd, &version, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	ret = do_write(fd, &cnt, sizeof(u32));
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < cnt; i++) {
+		struct cpu_cache_level *c = &caches[i];
+
+		#define _W(v)					\
+			ret = do_write(fd, &c->v, sizeof(u32));	\
+			if (ret < 0)				\
+				goto out;
+
+		_W(level)
+		_W(line_size)
+		_W(sets)
+		_W(ways)
+		#undef _W
+
+		#define _W(v)						\
+			ret = do_write_string(fd, (const char *) c->v);	\
+			if (ret < 0)					\
+				goto out;
+
+		_W(type)
+		_W(size)
+		_W(map)
+		#undef _W
+	}
+
+out:
+	for (i = 0; i < cnt; i++)
+		cpu_cache_level__free(&caches[i]);
+	return ret;
+}
+
 static int write_stat(int fd __maybe_unused,
 		      struct perf_header *h __maybe_unused,
 		      struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
 	fprintf(fp, "# contains stat data\n");
 }
 
+static void print_cache(struct perf_header *ph __maybe_unused,
+			int fd __maybe_unused, FILE *fp __maybe_unused)
+{
+	int i;
+
+	fprintf(fp, "# CPU cache info:\n");
+	for (i = 0; i < ph->env.caches_cnt; i++) {
+		fprintf(fp, "#  ");
+		cpu_cache_level__fprintf(fp, &ph->env.caches[i]);
+	}
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
 			       FILE *fp)
 {
@@ -1920,6 +2127,68 @@ static int process_auxtrace(struct perf_file_section *section,
 	return err;
 }
 
+static int process_cache(struct perf_file_section *section __maybe_unused,
+			 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
+			 void *data __maybe_unused)
+{
+	struct cpu_cache_level *caches;
+	u32 cnt, i, version;
+
+	if (readn(fd, &version, sizeof(version)) != sizeof(version))
+		return -1;
+
+	if (ph->needs_swap)
+		version = bswap_32(version);
+
+	if (version != 1)
+		return -1;
+
+	if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
+		return -1;
+
+	if (ph->needs_swap)
+		cnt = bswap_32(cnt);
+
+	caches = zalloc(sizeof(*caches) * cnt);
+	if (!caches)
+		return -1;
+
+	for (i = 0; i < cnt; i++) {
+		struct cpu_cache_level c;
+
+		#define _R(v)						\
+			if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
+				goto out_free_caches;			\
+			if (ph->needs_swap)				\
+				c.v = bswap_32(c.v);			\
+
+		_R(level)
+		_R(line_size)
+		_R(sets)
+		_R(ways)
+		#undef _R
+
+		#define _R(v)				\
+			c.v = do_read_string(fd, ph);	\
+			if (!c.v)			\
+				goto out_free_caches;
+
+		_R(type)
+		_R(size)
+		_R(map)
+		#undef _R
+
+		caches[i] = c;
+	}
+
+	ph->env.caches = caches;
+	ph->env.caches_cnt = cnt;
+	return 0;
+out_free_caches:
+	free(caches);
+	return -1;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2231,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
 	FEAT_OPP(HEADER_AUXTRACE,	auxtrace),
 	FEAT_OPA(HEADER_STAT,		stat),
+	FEAT_OPF(HEADER_CACHE,		cache),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892..3d87ca8 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };

^ permalink raw reply related	[flat|nested] 18+ messages in thread

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).