Skip to contentSkip to conversation

perf tools: Store CPU cache details under perf data

PATCH In review Jiri Olsa 7 participants 18 messages Feb 14, 2016 – Feb 17, 2016 perf events

lore
Share & tools
lore

Jiri Olsa

author reviewer
#0 lore raw

cover perf tools: Store CPU cache details under perf data

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
author reviewer
#1 lore raw

PATCH 1/5 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

---
 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
tools/lib/api/Build +1 -0
index e8b8a23b9bf4..954c644f7ad9 100644
@@ -1,3 +1,4 @@
 libapi-y += fd/
 libapi-y += fs/
 libapi-y += cpu.o
+libapi-y += debug.o
tools/lib/api/Makefile +1 -0
index d85904dc9b38..bbc82c614bee 100644
@@ -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
 
tools/lib/api/debug-internal.h new file +20 -0
new file mode 100644
index 000000000000..188f7880eafe
@@ -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__ */
tools/lib/api/debug.c new file +28 -0
new file mode 100644
index 000000000000..5fa5cf500a1f
@@ -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;
+}
tools/lib/api/debug.h new file +10 -0
new file mode 100644
index 000000000000..a0872f68fc56
@@ -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__ */
Signature · 1 line
2.4.3
#2 lore raw

[tip:perf/core] tools lib api: Add debug output support

tools lib api: Add debug output support
Commit-ID:  975f14fa8f2996604f248552eee4403def34bf5e
Gitweb:     http://git.kernel.org/tip/975f14fa8f2996604f248552eee4403def34bf5e
Author:     Jiri Olsa <[email protected]>
AuthorDate: Sun, 14 Feb 2016 17:03:42 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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

---
 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(+)
tools/lib/api/Build +1 -0
index e8b8a23..954c644 100644
@@ -1,3 +1,4 @@
 libapi-y += fd/
 libapi-y += fs/
 libapi-y += cpu.o
+libapi-y += debug.o
tools/lib/api/Makefile +1 -0
index d85904d..bbc82c6 100644
@@ -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
 
tools/lib/api/debug-internal.h new file +20 -0
new file mode 100644
index 0000000..188f788
@@ -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__ */
tools/lib/api/debug.c new file +28 -0
new file mode 100644
index 0000000..5fa5cf5
@@ -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;
+}
tools/lib/api/debug.h new file +10 -0
new file mode 100644
index 0000000..a0872f6
@@ -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__ */
author reviewer
#3 lore raw

PATCH 2/5 tools lib api fs: Move filename__read_str into api/fs/fs.c

In reply to Jiri Olsa

We already moved similar functions in here,
also it'll be useful for sysfs__read_str
addition in following patch.

---
 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(-)
tools/lib/api/fs/fs.c +51 -0
index 459599d1b6c4..2cbf6773ca5d 100644
@@ -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];
tools/lib/api/fs/fs.h +2 -0
index d024a7f682f6..858922b61141 100644
@@ -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);
tools/perf/util/trace-event.c +1 -0
index 802bb868d446..8ae051e0ec79 100644
@@ -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"
tools/perf/util/util.c +0 -48

54 lines not on this page · raw message

tools/perf/util/util.h +0 -1
index a8615816a00d..3dd04089e8be 100644
@@ -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);
Signature · 1 line
2.4.3
#4 lore raw

[tip:perf/core] tools lib api fs: Adopt filename__read_str from perf

tools lib api fs: Adopt filename__read_str from perf
Commit-ID:  607bfbd7ffc60156ae0831c917497dc91a57dd8d
Gitweb:     http://git.kernel.org/tip/607bfbd7ffc60156ae0831c917497dc91a57dd8d
Author:     Jiri Olsa <[email protected]>
AuthorDate: Sun, 14 Feb 2016 17:03:43 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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.

---
 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(-)
tools/lib/api/fs/fs.c +51 -0
index 459599d..2cbf677 100644
@@ -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];
tools/lib/api/fs/fs.h +2 -0
index d024a7f..858922b 100644
@@ -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);
tools/perf/util/trace-event.c +1 -0
index 802bb86..8ae051e 100644
@@ -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"
tools/perf/util/util.c +0 -48

54 lines not on this page · raw message

tools/perf/util/util.h +0 -1
index a861581..3dd0408 100644
@@ -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);
author reviewer
#5 lore raw

PATCH 3/5 tools lib api fs: Add sysfs__read_str function

In reply to Jiri Olsa

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);
---
 tools/lib/api/fs/fs.c | 13 +++++++++++++
 tools/lib/api/fs/fs.h |  1 +
 2 files changed, 14 insertions(+)
tools/lib/api/fs/fs.c +13 -0
index 2cbf6773ca5d..ef78c22ff44d 100644
@@ -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];
tools/lib/api/fs/fs.h +1 -0
index 858922b61141..9f6598098dc5 100644
@@ -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__ */
Signature · 1 line
2.4.3
#6 lore raw

[tip:perf/core] tools lib api fs: Add sysfs__read_str function

tools lib api fs: Add sysfs__read_str function
Commit-ID:  51c0396c600f49de9c3ff8f6fd83055de3709c3d
Gitweb:     http://git.kernel.org/tip/51c0396c600f49de9c3ff8f6fd83055de3709c3d
Author:     Jiri Olsa <[email protected]>
AuthorDate: Sun, 14 Feb 2016 17:03:44 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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);
---
 tools/lib/api/fs/fs.c | 13 +++++++++++++
 tools/lib/api/fs/fs.h |  1 +
 2 files changed, 14 insertions(+)
tools/lib/api/fs/fs.c +13 -0
index 2cbf677..ef78c22 100644
@@ -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];
tools/lib/api/fs/fs.h +1 -0
index 858922b..9f65980 100644
@@ -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__ */
author reviewer
#7 lore raw

PATCH 4/5 perf tools: Initialize libapi debug output

In reply to Jiri Olsa

Setting libapi debug output functions
to use perf functions.

---
 tools/perf/perf.c       |  2 ++
 tools/perf/util/debug.c | 21 +++++++++++++++++++++
 tools/perf/util/debug.h |  1 +
 3 files changed, 24 insertions(+)
tools/perf/perf.c +2 -0
index a929618b8eb6..144047c396f0 100644
@@ -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);
tools/perf/util/debug.c +21 -0
index 86d9c7302598..152c2e32975f 100644
@@ -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);
+}
tools/perf/util/debug.h +1 -0
index 8b9a088c32ab..14bafda79eda 100644
@@ -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 */
Signature · 1 line
2.4.3
#8 lore raw

[tip:perf/core] perf tools: Initialize libapi debug output

perf tools: Initialize libapi debug output
Commit-ID:  dd629cc0975349c99d5483402bca1ef16313c209
Gitweb:     http://git.kernel.org/tip/dd629cc0975349c99d5483402bca1ef16313c209
Author:     Jiri Olsa <[email protected]>
AuthorDate: Sun, 14 Feb 2016 17:03:45 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 16 Feb 2016 17:12:59 -0300

perf tools: Initialize libapi debug output

Setting libapi debug output functions to use perf functions.

---
 tools/perf/perf.c       |  2 ++
 tools/perf/util/debug.c | 21 +++++++++++++++++++++
 tools/perf/util/debug.h |  1 +
 3 files changed, 24 insertions(+)
tools/perf/perf.c +2 -0
index a929618..144047c 100644
@@ -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);
tools/perf/util/debug.c +21 -0
index d6c8d2b..ff7e86a 100644
@@ -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);
+}
tools/perf/util/debug.h +1 -0
index 8b9a088..14bafda 100644
@@ -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 */
author reviewer
#9 lore raw

PATCH 5/5 perf tools: Add perf data cache feature

In reply to Jiri Olsa

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.

---
 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(+)
tools/perf/util/env.c +13 -0
index 7dd5939dea2e..02a6970f2495 100644
@@ -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);
+}
tools/perf/util/env.h +15 -0
index 0132b9557c02..9963499820e7 100644
@@ -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 */
tools/perf/util/header.c +265 -0

295 lines not on this page · raw message

tools/perf/util/header.h +1 -0
index cff9892452ee..3d87ca823c0a 100644
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
Signature · 1 line
2.4.3
#10 lore raw

PATCH v2 5/5 perf tools: Add perf data cache feature

Quoted 4 lines · Jiri Olsa

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:

Quoted 12 lines
  $ 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.

---
 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(+)
tools/perf/util/env.c +13 -0
index 7dd5939dea2e..02a6970f2495 100644
@@ -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);
+}
tools/perf/util/env.h +15 -0
index 0132b9557c02..9963499820e7 100644
@@ -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 */
tools/perf/util/header.c +265 -0

295 lines not on this page · raw message

tools/perf/util/header.h +1 -0
index cff9892452ee..3d87ca823c0a 100644
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
Signature · 1 line
2.4.3
maintainer
#11 lore raw

Re: [PATCHv2 5/5] perf tools: Add perf data cache feature

Hi Jiri,

Quoted 49 lines · Jiri Olsa
Quoted 4 lines · Jiri Olsa

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:

Quoted 12 lines
  $ 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.

---

[SNIP]

Quoted 22 lines
tools/perf/util/header.c +22 -0
+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;
+

tools/perf/util/header.c static int write_auxtrace(int fd, struct perf_header *h, · line 999

Quoted 10 lines
tools/perf/util/header.c +10 -0
+			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

Quoted 9 lines
tools/perf/util/header.c +9 -0
+
+			if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
+				goto out;
+		}
+	}
+ out:
+	*cntp = cnt;
+	return 0;
+}
#12 lore raw

PATCH v3 5/5 perf tools: Add perf data cache feature

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

SNIP

Quoted 37 lines

[SNIP]

Quoted 22 lines
(quoted diff) +22 -0
+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;
+

Review

Quoted 10 lines
(quoted diff) +10 -0
+			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);
Quoted 1 line

???

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.

---
 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(+)
tools/perf/util/env.c +13 -0
index 7dd5939dea2e..02a6970f2495 100644
@@ -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);
+}
tools/perf/util/env.h +15 -0
index 0132b9557c02..9963499820e7 100644
@@ -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 */
tools/perf/util/header.c +267 -0

297 lines not on this page · raw message

tools/perf/util/header.h +1 -0
index cff9892452ee..3d87ca823c0a 100644
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
Signature · 1 line
2.4.3
#13 lore raw

Re: [PATCHv3 5/5] perf tools: Add perf data cache feature

Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu:

Quoted 413 lines · Namhyung Kim

SNIP

Quoted 37 lines

[SNIP]

Quoted 22 lines
tools/perf/util/header.c +22 -0
+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;
+

tools/perf/util/header.c static int write_auxtrace(int fd, struct perf_header *h, · line 999

Quoted 10 lines
tools/perf/util/header.c +10 -0
+			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);
Quoted 1 line

???

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.

---
 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(+)
tools/perf/util/env.c +13 -0
index 7dd5939dea2e..02a6970f2495 100644
@@ -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);
+}
tools/perf/util/env.h +15 -0
index 0132b9557c02..9963499820e7 100644
@@ -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 */
tools/perf/util/header.c +229 -0
index f50b7235ecb6..f5803fa3dc63 100644
@@ -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);
+

tools/perf/util/header.c static int process_auxtrace(struct perf_file_section *section, · line 2161

Quoted 10 lines
tools/perf/util/header.c +10 -0
+	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?

tools/perf/util/header.c static int process_auxtrace(struct perf_file_section *section, · line 2173

Quoted 12 lines
tools/perf/util/header.c +12 -0
+			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.

tools/perf/util/header.c static int process_auxtrace(struct perf_file_section *section, · line 2182

Quoted 9 lines
tools/perf/util/header.c +9 -0
+				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

Quoted 30 lines
tools/perf/util/header.c +6 -0
+	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 {
tools/perf/util/header.h +1 -0
index cff9892452ee..3d87ca823c0a 100644
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
Signature · 1 line
2.4.3
#14 lore raw

Re: [PATCHv3 5/5] perf tools: Add perf data cache feature

Em Tue, Feb 16, 2016 at 12:29:36PM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 14 lines

Em Tue, Feb 16, 2016 at 04:01:43PM +0100, Jiri Olsa escreveu:

tools/perf/util/header.c static int process_auxtrace(struct perf_file_section *section, · line 2161

Quoted 10 lines
tools/perf/util/header.c +10 -0
+	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

#15 lore raw

[tip:perf/core] perf tools: Add perf data cache feature

In reply to Jiri Olsa
perf tools: Add perf data cache feature
Commit-ID:  720e98b5faf10cfd12b7821dbdcc41c9747bd13e
Gitweb:     http://git.kernel.org/tip/720e98b5faf10cfd12b7821dbdcc41c9747bd13e
Author:     Jiri Olsa <[email protected]>
AuthorDate: Tue, 16 Feb 2016 16:01:43 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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.

Cc David Ahern <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Peter Zijlstra <[email protected]>
[ Fixed leak on process_caches(), s/cache_level/cpu_cache_level/g ]
---
 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(+)
tools/perf/util/env.c +13 -0
index 7dd5939..49a11d9 100644
@@ -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);
+}
tools/perf/util/env.h +15 -0
index 0132b95..56cffb6 100644
@@ -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 */
tools/perf/util/header.c +270 -0

300 lines not on this page · raw message

tools/perf/util/header.h +1 -0
index cff9892..3d87ca8 100644
@@ -32,6 +32,7 @@ enum {
 	HEADER_GROUP_DESC,
 	HEADER_AUXTRACE,
 	HEADER_STAT,
+	HEADER_CACHE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
#16 lore raw
In reply to Jiri Olsa
Quoted 13 lines · Jiri Olsa

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:

Quoted 8 lines

# 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

#17 lore raw
Quoted 29 lines · Ingo Molnar
Quoted 13 lines · Jiri Olsa

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:

Quoted 8 lines

# 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]
Quoted 2 lines

(Also note that it says 'CPU cache info' - there are a lot of caches in the system.)

yep, looks better.. will change

thanks,
jirka