All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] perf header: Add die information in CPU topology
@ 2019-05-23 20:41 kan.liang
  2019-05-23 20:41 ` [PATCH 2/3] perf stat: Support per-die aggregation kan.liang
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: kan.liang @ 2019-05-23 20:41 UTC (permalink / raw)
  To: acme, jolsa, mingo, linux-kernel; +Cc: peterz, ak, Kan Liang

From: Kan Liang <kan.liang@linux.intel.com>

With the new CPUID.1F, a new level type of CPU topology, 'die', is
introduced. The 'die' information in CPU topology should be added in
perf header.

To be compatible with old perf.data, the patch checks the section size
before reading the die information. The new info is added at the end of
the cpu_topology section, the old perf tool ignores the extra data.
It never reads data crossing the section boundary.

The new perf tool with the patch can be used on legacy kernel. Add a
new function check_x86_die_exists() to check if die topology
information is supported by kernel. The function only check X86 and
CPU 0. Assuming other CPUs have same topology.

Use similar method for core and socket to support die id and sibling
dies string.

Add cpu_map__get_die_id() in cpumap.c to fetch die id information.

Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
---
 tools/perf/Documentation/perf.data-file-format.txt |   9 +-
 tools/perf/util/cpumap.c                           |   7 ++
 tools/perf/util/cpumap.h                           |   1 +
 tools/perf/util/cputopo.c                          |  83 ++++++++++++++--
 tools/perf/util/cputopo.h                          |   7 +-
 tools/perf/util/env.c                              |   1 +
 tools/perf/util/env.h                              |   3 +
 tools/perf/util/header.c                           | 104 +++++++++++++++++++--
 8 files changed, 193 insertions(+), 22 deletions(-)

diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
index 6967e9b..c731416 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -153,7 +153,7 @@ struct {
 
 String lists defining the core and CPU threads topology.
 The string lists are followed by a variable length array
-which contains core_id and socket_id of each cpu.
+which contains core_id, die_id (for x86) and socket_id of each cpu.
 The number of entries can be determined by the size of the
 section minus the sizes of both string lists.
 
@@ -162,14 +162,19 @@ struct {
        struct perf_header_string_list threads; /* Variable length */
        struct {
 	      uint32_t core_id;
+	      uint32_t die_id;
 	      uint32_t socket_id;
        } cpus[nr]; /* Variable length records */
 };
 
 Example:
-	sibling cores   : 0-3
+	sibling cores   : 0-8
+	sibling dies	: 0-3
+	sibling dies	: 4-7
 	sibling threads : 0-1
 	sibling threads : 2-3
+	sibling threads : 4-5
+	sibling threads : 6-7
 
 	HEADER_NUMA_TOPOLOGY = 14,
 
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 0b59922..7db1365 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -373,6 +373,13 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
 	return 0;
 }
 
+int cpu_map__get_die_id(int cpu)
+{
+	int value, ret = cpu__get_topology_int(cpu, "die_id", &value);
+
+	return ret ?: value;
+}
+
 int cpu_map__get_core_id(int cpu)
 {
 	int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index f00ce62..6762ff9 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -25,6 +25,7 @@ size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket_id(int cpu);
 int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
+int cpu_map__get_die_id(int cpu);
 int cpu_map__get_core_id(int cpu);
 int cpu_map__get_core(struct cpu_map *map, int idx, void *data);
 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c
index ece0710..f6e7db7 100644
--- a/tools/perf/util/cputopo.c
+++ b/tools/perf/util/cputopo.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <sys/param.h>
+#include <sys/utsname.h>
 #include <inttypes.h>
 #include <api/fs/fs.h>
 
@@ -8,9 +9,10 @@
 #include "util.h"
 #include "env.h"
 
-
 #define CORE_SIB_FMT \
 	"%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
+#define DIE_SIB_FMT \
+	"%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
 #define THRD_SIB_FMT \
 	"%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
 #define NODE_ONLINE_FMT \
@@ -20,7 +22,26 @@
 #define NODE_CPULIST_FMT \
 	"%s/devices/system/node/node%d/cpulist"
 
-static int build_cpu_topology(struct cpu_topology *tp, int cpu)
+bool check_x86_die_exists(void)
+{
+	char filename[MAXPATHLEN];
+	struct utsname uts;
+
+	if (uname(&uts) < 0)
+		return false;
+
+	if (strncmp(uts.machine, "x86_64", 6))
+		return false;
+
+	scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
+		  sysfs__mountpoint(), 0);
+	if (access(filename, F_OK) == -1)
+		return false;
+
+	return true;
+}
+
+static int build_cpu_topology(struct cpu_topology *tp, int cpu, bool has_die)
 {
 	FILE *fp;
 	char filename[MAXPATHLEN];
@@ -34,12 +55,12 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
 		  sysfs__mountpoint(), cpu);
 	fp = fopen(filename, "r");
 	if (!fp)
-		goto try_threads;
+		goto try_dies;
 
 	sret = getline(&buf, &len, fp);
 	fclose(fp);
 	if (sret <= 0)
-		goto try_threads;
+		goto try_dies;
 
 	p = strchr(buf, '\n');
 	if (p)
@@ -57,6 +78,35 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
 	}
 	ret = 0;
 
+try_dies:
+	if (has_die) {
+		scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
+			  sysfs__mountpoint(), cpu);
+		fp = fopen(filename, "r");
+		if (!fp)
+			goto try_threads;
+
+		sret = getline(&buf, &len, fp);
+		fclose(fp);
+		if (sret <= 0)
+			goto try_threads;
+
+		p = strchr(buf, '\n');
+		if (p)
+			*p = '\0';
+
+		for (i = 0; i < tp->die_sib; i++) {
+			if (!strcmp(buf, tp->die_siblings[i]))
+				break;
+		}
+		if (i == tp->die_sib) {
+			tp->die_siblings[i] = buf;
+			tp->die_sib++;
+			buf = NULL;
+			len = 0;
+		}
+		ret = 0;
+	}
 try_threads:
 	scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
 		  sysfs__mountpoint(), cpu);
@@ -88,7 +138,7 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
 	return ret;
 }
 
-void cpu_topology__delete(struct cpu_topology *tp)
+void cpu_topology__delete(struct cpu_topology *tp, bool has_die)
 {
 	u32 i;
 
@@ -98,17 +148,22 @@ void cpu_topology__delete(struct cpu_topology *tp)
 	for (i = 0 ; i < tp->core_sib; i++)
 		zfree(&tp->core_siblings[i]);
 
+	if (has_die) {
+		for (i = 0 ; i < tp->die_sib; i++)
+			zfree(&tp->die_siblings[i]);
+	}
+
 	for (i = 0 ; i < tp->thread_sib; i++)
 		zfree(&tp->thread_siblings[i]);
 
 	free(tp);
 }
 
-struct cpu_topology *cpu_topology__new(void)
+struct cpu_topology *cpu_topology__new(bool has_die)
 {
 	struct cpu_topology *tp = NULL;
 	void *addr;
-	u32 nr, i;
+	u32 nr, i, nr_addr;
 	size_t sz;
 	long ncpus;
 	int ret = -1;
@@ -126,7 +181,11 @@ struct cpu_topology *cpu_topology__new(void)
 	nr = (u32)(ncpus & UINT_MAX);
 
 	sz = nr * sizeof(char *);
-	addr = calloc(1, sizeof(*tp) + 2 * sz);
+	if (has_die)
+		nr_addr = 3;
+	else
+		nr_addr = 2;
+	addr = calloc(1, sizeof(*tp) + nr_addr * sz);
 	if (!addr)
 		goto out_free;
 
@@ -134,13 +193,17 @@ struct cpu_topology *cpu_topology__new(void)
 	addr += sizeof(*tp);
 	tp->core_siblings = addr;
 	addr += sz;
+	if (has_die) {
+		tp->die_siblings = addr;
+		addr += sz;
+	}
 	tp->thread_siblings = addr;
 
 	for (i = 0; i < nr; i++) {
 		if (!cpu_map__has(map, i))
 			continue;
 
-		ret = build_cpu_topology(tp, i);
+		ret = build_cpu_topology(tp, i, has_die);
 		if (ret < 0)
 			break;
 	}
@@ -148,7 +211,7 @@ struct cpu_topology *cpu_topology__new(void)
 out_free:
 	cpu_map__put(map);
 	if (ret) {
-		cpu_topology__delete(tp);
+		cpu_topology__delete(tp, has_die);
 		tp = NULL;
 	}
 	return tp;
diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h
index 47a97e7..cb4e6fe 100644
--- a/tools/perf/util/cputopo.h
+++ b/tools/perf/util/cputopo.h
@@ -7,8 +7,10 @@
 
 struct cpu_topology {
 	u32	  core_sib;
+	u32	  die_sib;
 	u32	  thread_sib;
 	char	**core_siblings;
+	char	**die_siblings;
 	char	**thread_siblings;
 };
 
@@ -24,8 +26,9 @@ struct numa_topology {
 	struct numa_topology_node	nodes[0];
 };
 
-struct cpu_topology *cpu_topology__new(void);
-void cpu_topology__delete(struct cpu_topology *tp);
+bool check_x86_die_exists(void);
+struct cpu_topology *cpu_topology__new(bool has_die);
+void cpu_topology__delete(struct cpu_topology *tp, bool has_die);
 
 struct numa_topology *numa_topology__new(void);
 void numa_topology__delete(struct numa_topology *tp);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 6a3eaf7..1cc7a18 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -246,6 +246,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
 	for (cpu = 0; cpu < nr_cpus; ++cpu) {
 		env->cpu[cpu].core_id	= cpu_map__get_core_id(cpu);
 		env->cpu[cpu].socket_id	= cpu_map__get_socket_id(cpu);
+		env->cpu[cpu].die_id	= cpu_map__get_die_id(cpu);
 	}
 
 	env->nr_cpus_avail = nr_cpus;
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 271a90b..d5d9865 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -9,6 +9,7 @@
 
 struct cpu_topology_map {
 	int	socket_id;
+	int	die_id;
 	int	core_id;
 };
 
@@ -49,6 +50,7 @@ struct perf_env {
 
 	int			nr_cmdline;
 	int			nr_sibling_cores;
+	int			nr_sibling_dies;
 	int			nr_sibling_threads;
 	int			nr_numa_nodes;
 	int			nr_memory_nodes;
@@ -57,6 +59,7 @@ struct perf_env {
 	char			*cmdline;
 	const char		**cmdline_argv;
 	char			*sibling_cores;
+	char			*sibling_dies;
 	char			*sibling_threads;
 	char			*pmu_mappings;
 	struct cpu_topology_map	*cpu;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 847ae51..faa1e38 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -561,8 +561,11 @@ static int write_cpu_topology(struct feat_fd *ff,
 	struct cpu_topology *tp;
 	u32 i;
 	int ret, j;
+	bool has_die;
 
-	tp = cpu_topology__new();
+	has_die = check_x86_die_exists();
+
+	tp = cpu_topology__new(has_die);
 	if (!tp)
 		return -1;
 
@@ -599,8 +602,29 @@ static int write_cpu_topology(struct feat_fd *ff,
 		if (ret < 0)
 			return ret;
 	}
+
+	if (!has_die)
+		goto done;
+
+	ret = do_write(ff, &tp->die_sib, sizeof(tp->die_sib));
+	if (ret < 0)
+		goto done;
+
+	for (i = 0; i < tp->die_sib; i++) {
+		ret = do_write_string(ff, tp->die_siblings[i]);
+		if (ret < 0)
+			goto done;
+	}
+
+	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
+		ret = do_write(ff, &perf_env.cpu[j].die_id,
+			       sizeof(perf_env.cpu[j].die_id));
+		if (ret < 0)
+			return ret;
+	}
+
 done:
-	cpu_topology__delete(tp);
+	cpu_topology__delete(tp, has_die);
 	return ret;
 }
 
@@ -1428,6 +1452,8 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp)
 	fputc('\n', fp);
 }
 
+static bool has_die;
+
 static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
 {
 	struct perf_header *ph = ff->ph;
@@ -1443,6 +1469,16 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
 		str += strlen(str) + 1;
 	}
 
+	if (has_die) {
+		nr = ph->env.nr_sibling_dies;
+		str = ph->env.sibling_dies;
+
+		for (i = 0; i < nr; i++) {
+			fprintf(fp, "# sibling dies    : %s\n", str);
+			str += strlen(str) + 1;
+		}
+	}
+
 	nr = ph->env.nr_sibling_threads;
 	str = ph->env.sibling_threads;
 
@@ -1451,12 +1487,28 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
 		str += strlen(str) + 1;
 	}
 
-	if (ph->env.cpu != NULL) {
-		for (i = 0; i < cpu_nr; i++)
-			fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
-				ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
-	} else
-		fprintf(fp, "# Core ID and Socket ID information is not available\n");
+	if (has_die) {
+		if (ph->env.cpu != NULL) {
+			for (i = 0; i < cpu_nr; i++)
+				fprintf(fp, "# CPU %d: Core ID %d, "
+					    "Die ID %d, Socket ID %d\n",
+					    i, ph->env.cpu[i].core_id,
+					    ph->env.cpu[i].die_id,
+					    ph->env.cpu[i].socket_id);
+		} else
+			fprintf(fp, "# Core ID, Die ID and Socket ID "
+				    "information is not available\n");
+	} else {
+		if (ph->env.cpu != NULL) {
+			for (i = 0; i < cpu_nr; i++)
+				fprintf(fp, "# CPU %d: Core ID %d, "
+					    "Socket ID %d\n",
+					    i, ph->env.cpu[i].core_id,
+					    ph->env.cpu[i].socket_id);
+		} else
+			fprintf(fp, "# Core ID and Socket ID "
+				    "information is not available\n");
+	}
 }
 
 static void print_clockid(struct feat_fd *ff, FILE *fp)
@@ -2214,6 +2266,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
 			goto free_cpu;
 
 		ph->env.cpu[i].core_id = nr;
+		size += sizeof(u32);
 
 		if (do_read_u32(ff, &nr))
 			goto free_cpu;
@@ -2225,7 +2278,42 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
 		}
 
 		ph->env.cpu[i].socket_id = nr;
+		size += sizeof(u32);
+	}
+
+	/*
+	 * The header may be from old perf,
+	 * which doesn't include die information.
+	 */
+	if (ff->size <= size)
+		return 0;
+
+	if (do_read_u32(ff, &nr))
+		return -1;
+
+	ph->env.nr_sibling_dies = nr;
+	size += sizeof(u32);
+
+	for (i = 0; i < nr; i++) {
+		str = do_read_string(ff);
+		if (!str)
+			goto error;
+
+		/* include a NULL character at the end */
+		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
+			goto error;
+		size += string_size(str);
+		free(str);
+	}
+	ph->env.sibling_dies = strbuf_detach(&sb, NULL);
+
+	for (i = 0; i < (u32)cpu_nr; i++) {
+		if (do_read_u32(ff, &nr))
+			goto free_cpu;
+
+		ph->env.cpu[i].die_id = nr;
 	}
+	has_die = true;
 
 	return 0;
 
-- 
2.7.4


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

* [PATCH 2/3] perf stat: Support per-die aggregation
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
@ 2019-05-23 20:41 ` kan.liang
  2019-05-28  9:00   ` Jiri Olsa
  2019-05-23 20:41 ` [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets" kan.liang
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: kan.liang @ 2019-05-23 20:41 UTC (permalink / raw)
  To: acme, jolsa, mingo, linux-kernel; +Cc: peterz, ak, Kan Liang

From: Kan Liang <kan.liang@linux.intel.com>

It is useful to aggregate counts per die. E.g. Uncore becomes die-scope
on Xeon Cascade Lake-AP.

Introduce a new option "--per-die" to support per-die aggregation.

The global id for each core has been changed to socket + die id + core
id. The global id for each die is socket + die id.

Add die information for per-core aggregation. The output of per-core
aggregation will be changed from "S0-C0" to "S0-D0-C0". Any scripts
which rely on the output format of per-core aggregation probably be
broken.

For perf stat record/report, there is no die information when processing
the old perf.data. The per-die result will be the same as per-socket.

Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
---
 tools/perf/Documentation/perf-stat.txt | 10 +++++
 tools/perf/builtin-stat.c              | 73 +++++++++++++++++++++++++++++++---
 tools/perf/util/cpumap.c               | 48 +++++++++++++++++++---
 tools/perf/util/cpumap.h               |  9 ++++-
 tools/perf/util/stat-display.c         | 27 +++++++++++--
 tools/perf/util/stat-shadow.c          |  1 +
 tools/perf/util/stat.c                 |  1 +
 tools/perf/util/stat.h                 |  1 +
 8 files changed, 155 insertions(+), 15 deletions(-)

diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 1e312c2..930c51c0 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -200,6 +200,13 @@ use --per-socket in addition to -a. (system-wide).  The output includes the
 socket number and the number of online processors on that socket. This is
 useful to gauge the amount of aggregation.
 
+--per-die::
+Aggregate counts per processor die for system-wide mode measurements.  This
+is a useful mode to detect imbalance between dies.  To enable this mode,
+use --per-die in addition to -a. (system-wide).  The output includes the
+die number and the number of online processors on that die. This is
+useful to gauge the amount of aggregation.
+
 --per-core::
 Aggregate counts per physical processor for system-wide mode measurements.  This
 is a useful mode to detect imbalance between physical cores.  To enable this mode,
@@ -239,6 +246,9 @@ Input file name.
 --per-socket::
 Aggregate counts per processor socket for system-wide mode measurements.
 
+--per-die::
+Aggregate counts per processor die for system-wide mode measurements.
+
 --per-core::
 Aggregate counts per physical processor for system-wide mode measurements.
 
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 24b8e69..305f6f3 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -777,6 +777,8 @@ static struct option stat_options[] = {
 		    "stop workload and print counts after a timeout period in ms (>= 10ms)"),
 	OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
 		     "aggregate counts per processor socket", AGGR_SOCKET),
+	OPT_SET_UINT(0, "per-die", &stat_config.aggr_mode,
+		     "aggregate counts per processor die", AGGR_DIE),
 	OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
 		     "aggregate counts per physical processor core", AGGR_CORE),
 	OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
@@ -801,6 +803,12 @@ static int perf_stat__get_socket(struct perf_stat_config *config __maybe_unused,
 	return cpu_map__get_socket(map, cpu, NULL);
 }
 
+static int perf_stat__get_die(struct perf_stat_config *config __maybe_unused,
+			      struct cpu_map *map, int cpu)
+{
+	return cpu_map__get_die(map, cpu, NULL);
+}
+
 static int perf_stat__get_core(struct perf_stat_config *config __maybe_unused,
 			       struct cpu_map *map, int cpu)
 {
@@ -841,6 +849,12 @@ static int perf_stat__get_socket_cached(struct perf_stat_config *config,
 	return perf_stat__get_aggr(config, perf_stat__get_socket, map, idx);
 }
 
+static int perf_stat__get_die_cached(struct perf_stat_config *config,
+					struct cpu_map *map, int idx)
+{
+	return perf_stat__get_aggr(config, perf_stat__get_die, map, idx);
+}
+
 static int perf_stat__get_core_cached(struct perf_stat_config *config,
 				      struct cpu_map *map, int idx)
 {
@@ -871,6 +885,13 @@ static int perf_stat_init_aggr_mode(void)
 		}
 		stat_config.aggr_get_id = perf_stat__get_socket_cached;
 		break;
+	case AGGR_DIE:
+		if (cpu_map__build_die_map(evsel_list->cpus, &stat_config.aggr_map)) {
+			perror("cannot build die map");
+			return -1;
+		}
+		stat_config.aggr_get_id = perf_stat__get_die_cached;
+		break;
 	case AGGR_CORE:
 		if (cpu_map__build_core_map(evsel_list->cpus, &stat_config.aggr_map)) {
 			perror("cannot build core map");
@@ -936,21 +957,41 @@ static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
 	return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
 }
 
+static int perf_env__get_die(struct cpu_map *map, int idx, void *data)
+{
+	struct perf_env *env = data;
+	int die = -1, cpu = perf_env__get_cpu(env, map, idx);
+
+	if (cpu != -1) {
+		/*
+		 * Encode socket in upper 8 bits
+		 * die_id is relative to socket,
+		 * we need a global id. So we combine
+		 * socket + die id
+		 */
+		die = (env->cpu[cpu].socket_id << 8) |
+		      (env->cpu[cpu].die_id & 0xff);
+	}
+
+	return die;
+}
+
 static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
 {
 	struct perf_env *env = data;
 	int core = -1, cpu = perf_env__get_cpu(env, map, idx);
 
 	if (cpu != -1) {
-		int socket_id = env->cpu[cpu].socket_id;
-
 		/*
-		 * Encode socket in upper 16 bits
-		 * core_id is relative to socket, and
+		 * Encode socket in upper 24 bits
+		 * encode die id in upper 16 bits
+		 * core_id is relative to socket and die,
 		 * we need a global id. So we combine
-		 * socket + core id.
+		 * socket + die id + core id
 		 */
-		core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
+		core = (env->cpu[cpu].socket_id << 24) |
+		       (env->cpu[cpu].die_id << 16) |
+		       (env->cpu[cpu].core_id & 0xffff);
 	}
 
 	return core;
@@ -962,6 +1003,12 @@ static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus
 	return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
 }
 
+static int perf_env__build_die_map(struct perf_env *env, struct cpu_map *cpus,
+				   struct cpu_map **diep)
+{
+	return cpu_map__build_map(cpus, diep, perf_env__get_die, env);
+}
+
 static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
 				    struct cpu_map **corep)
 {
@@ -973,6 +1020,11 @@ static int perf_stat__get_socket_file(struct perf_stat_config *config __maybe_un
 {
 	return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
 }
+static int perf_stat__get_die_file(struct perf_stat_config *config __maybe_unused,
+				   struct cpu_map *map, int idx)
+{
+	return perf_env__get_die(map, idx, &perf_stat.session->header.env);
+}
 
 static int perf_stat__get_core_file(struct perf_stat_config *config __maybe_unused,
 				    struct cpu_map *map, int idx)
@@ -992,6 +1044,13 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
 		}
 		stat_config.aggr_get_id = perf_stat__get_socket_file;
 		break;
+	case AGGR_DIE:
+		if (perf_env__build_die_map(env, evsel_list->cpus, &stat_config.aggr_map)) {
+			perror("cannot build die map");
+			return -1;
+		}
+		stat_config.aggr_get_id = perf_stat__get_die_file;
+		break;
 	case AGGR_CORE:
 		if (perf_env__build_core_map(env, evsel_list->cpus, &stat_config.aggr_map)) {
 			perror("cannot build core map");
@@ -1542,6 +1601,8 @@ static int __cmd_report(int argc, const char **argv)
 	OPT_STRING('i', "input", &input_name, "file", "input file name"),
 	OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
 		     "aggregate counts per processor socket", AGGR_SOCKET),
+	OPT_SET_UINT(0, "per-die", &perf_stat.aggr_mode,
+		     "aggregate counts per processor die", AGGR_DIE),
 	OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
 		     "aggregate counts per physical processor core", AGGR_CORE),
 	OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 7db1365..3346ad2 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -380,6 +380,33 @@ int cpu_map__get_die_id(int cpu)
 	return ret ?: value;
 }
 
+int cpu_map__get_die(struct cpu_map *map, int idx, void *data)
+{
+	int cpu, die, s;
+
+	if (idx > map->nr)
+		return -1;
+
+	cpu = map->map[idx];
+
+	die = cpu_map__get_die_id(cpu);
+	/* There is no die_id on legacy system. */
+	if (die == -1)
+		die = 0;
+
+	s = cpu_map__get_socket(map, idx, data);
+	if (s == -1)
+		return -1;
+
+	/*
+	 * encode socket in upper 8 bits
+	 * die_id is relative to socket, and
+	 * we need a global id. So we combine
+	 * socket + die id
+	 */
+	return (s << 8) | (die & 0xff);
+}
+
 int cpu_map__get_core_id(int cpu)
 {
 	int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
@@ -388,7 +415,7 @@ int cpu_map__get_core_id(int cpu)
 
 int cpu_map__get_core(struct cpu_map *map, int idx, void *data)
 {
-	int cpu, s;
+	int cpu, s, die;
 
 	if (idx > map->nr)
 		return -1;
@@ -397,17 +424,23 @@ int cpu_map__get_core(struct cpu_map *map, int idx, void *data)
 
 	cpu = cpu_map__get_core_id(cpu);
 
+	die = cpu_map__get_die(map, idx, data);
+	/* There is no die_id on legacy system. */
+	if (die == -1)
+		die = 0;
+
 	s = cpu_map__get_socket(map, idx, data);
 	if (s == -1)
 		return -1;
 
 	/*
-	 * encode socket in upper 16 bits
-	 * core_id is relative to socket, and
+	 * encode socket in upper 24 bits
+	 * encode die id in upper 16 bits
+	 * core_id is relative to socket and die,
 	 * we need a global id. So we combine
-	 * socket+ core id
+	 * socket + die id + core id
 	 */
-	return (s << 16) | (cpu & 0xffff);
+	return (s << 24) | (die << 16) | (cpu & 0xffff);
 }
 
 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
@@ -415,6 +448,11 @@ int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
 	return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL);
 }
 
+int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep)
+{
+	return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL);
+}
+
 int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
 {
 	return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL);
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 6762ff9..1265f0e 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -26,9 +26,11 @@ size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket_id(int cpu);
 int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
 int cpu_map__get_die_id(int cpu);
+int cpu_map__get_die(struct cpu_map *map, int idx, void *data);
 int cpu_map__get_core_id(int cpu);
 int cpu_map__get_core(struct cpu_map *map, int idx, void *data);
 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
+int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep);
 int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
 const struct cpu_map *cpu_map__online(void); /* thread unsafe */
 
@@ -44,7 +46,12 @@ static inline int cpu_map__socket(struct cpu_map *sock, int s)
 
 static inline int cpu_map__id_to_socket(int id)
 {
-	return id >> 16;
+	return id >> 24;
+}
+
+static inline int cpu_map__id_to_die(int id)
+{
+	return (id >> 16) & 0xff;
 }
 
 static inline int cpu_map__id_to_cpu(int id)
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index 4c53bae..cae1b43 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -69,8 +69,9 @@ static void aggr_printout(struct perf_stat_config *config,
 {
 	switch (config->aggr_mode) {
 	case AGGR_CORE:
-		fprintf(config->output, "S%d-C%*d%s%*d%s",
+		fprintf(config->output, "S%d-D%d-C%*d%s%*d%s",
 			cpu_map__id_to_socket(id),
+			cpu_map__id_to_die(id),
 			config->csv_output ? 0 : -8,
 			cpu_map__id_to_cpu(id),
 			config->csv_sep,
@@ -78,6 +79,16 @@ static void aggr_printout(struct perf_stat_config *config,
 			nr,
 			config->csv_sep);
 		break;
+	case AGGR_DIE:
+		fprintf(config->output, "S%d-D%*d%s%*d%s",
+			cpu_map__id_to_socket(id << 16),
+			config->csv_output ? 0 : -8,
+			cpu_map__id_to_die(id << 16),
+			config->csv_sep,
+			config->csv_output ? 0 : 4,
+			nr,
+			config->csv_sep);
+		break;
 	case AGGR_SOCKET:
 		fprintf(config->output, "S%*d%s%*d%s",
 			config->csv_output ? 0 : -5,
@@ -89,8 +100,9 @@ static void aggr_printout(struct perf_stat_config *config,
 			break;
 	case AGGR_NONE:
 		if (evsel->percore) {
-			fprintf(config->output, "S%d-C%*d%s",
+			fprintf(config->output, "S%d-D%d-C%*d%s",
 				cpu_map__id_to_socket(id),
+				cpu_map__id_to_die(id),
 				config->csv_output ? 0 : -5,
 				cpu_map__id_to_cpu(id), config->csv_sep);
 		} else {
@@ -407,6 +419,7 @@ static void printout(struct perf_stat_config *config, int id, int nr,
 			[AGGR_THREAD] = 1,
 			[AGGR_NONE] = 1,
 			[AGGR_SOCKET] = 2,
+			[AGGR_DIE] = 2,
 			[AGGR_CORE] = 2,
 		};
 
@@ -879,7 +892,8 @@ static void print_no_aggr_metric(struct perf_stat_config *config,
 }
 
 static int aggr_header_lens[] = {
-	[AGGR_CORE] = 18,
+	[AGGR_CORE] = 24,
+	[AGGR_DIE] = 18,
 	[AGGR_SOCKET] = 12,
 	[AGGR_NONE] = 6,
 	[AGGR_THREAD] = 24,
@@ -888,6 +902,7 @@ static int aggr_header_lens[] = {
 
 static const char *aggr_header_csv[] = {
 	[AGGR_CORE] 	= 	"core,cpus,",
+	[AGGR_DIE] 	= 	"die,cpus",
 	[AGGR_SOCKET] 	= 	"socket,cpus",
 	[AGGR_NONE] 	= 	"cpu,",
 	[AGGR_THREAD] 	= 	"comm-pid,",
@@ -954,6 +969,11 @@ static void print_interval(struct perf_stat_config *config,
 			if (!metric_only)
 				fprintf(output, "             counts %*s events\n", unit_width, "unit");
 			break;
+		case AGGR_DIE:
+			fprintf(output, "#           time die cpus");
+			if (!metric_only)
+				fprintf(output, "             counts %*s events\n", unit_width, "unit");
+			break;
 		case AGGR_CORE:
 			fprintf(output, "#           time core         cpus");
 			if (!metric_only)
@@ -1165,6 +1185,7 @@ perf_evlist__print_counters(struct perf_evlist *evlist,
 
 	switch (config->aggr_mode) {
 	case AGGR_CORE:
+	case AGGR_DIE:
 	case AGGR_SOCKET:
 		print_aggr(config, evlist, prefix);
 		break;
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 83d8094..027b09a 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -12,6 +12,7 @@
 /*
  * AGGR_GLOBAL: Use CPU 0
  * AGGR_SOCKET: Use first CPU of socket
+ * AGGR_DIE: Use first CPU of die
  * AGGR_CORE: Use first CPU of core
  * AGGR_NONE: Use matching CPU
  * AGGR_THREAD: Not supported?
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index c3115d9..d91fe75 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -272,6 +272,7 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel
 	switch (config->aggr_mode) {
 	case AGGR_THREAD:
 	case AGGR_CORE:
+	case AGGR_DIE:
 	case AGGR_SOCKET:
 	case AGGR_NONE:
 		if (!evsel->snapshot)
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 2f9c915..7032dd1 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -44,6 +44,7 @@ enum aggr_mode {
 	AGGR_NONE,
 	AGGR_GLOBAL,
 	AGGR_SOCKET,
+	AGGR_DIE,
 	AGGR_CORE,
 	AGGR_THREAD,
 	AGGR_UNSET,
-- 
2.7.4


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

* [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets"
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
  2019-05-23 20:41 ` [PATCH 2/3] perf stat: Support per-die aggregation kan.liang
@ 2019-05-23 20:41 ` kan.liang
  2019-05-28  8:59   ` Jiri Olsa
  2019-05-28  8:59 ` [PATCH 1/3] perf header: Add die information in CPU topology Jiri Olsa
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: kan.liang @ 2019-05-23 20:41 UTC (permalink / raw)
  To: acme, jolsa, mingo, linux-kernel; +Cc: peterz, ak, Kan Liang

From: Kan Liang <kan.liang@linux.intel.com>

The "sibling cores" actually shows the sibling CPUs of a socket.
The name "sibling cores" is very misleading.

Rename "sibling cores" to "sibling sockets"

Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
---
 tools/perf/Documentation/perf.data-file-format.txt | 2 +-
 tools/perf/util/header.c                           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
index c731416..dd85163 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -168,7 +168,7 @@ struct {
 };
 
 Example:
-	sibling cores   : 0-8
+	sibling sockets : 0-8
 	sibling dies	: 0-3
 	sibling dies	: 4-7
 	sibling threads : 0-1
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index faa1e38..eb79495 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1465,7 +1465,7 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
 	str = ph->env.sibling_cores;
 
 	for (i = 0; i < nr; i++) {
-		fprintf(fp, "# sibling cores   : %s\n", str);
+		fprintf(fp, "# sibling sockets : %s\n", str);
 		str += strlen(str) + 1;
 	}
 
-- 
2.7.4


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

* Re: [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets"
  2019-05-23 20:41 ` [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets" kan.liang
@ 2019-05-28  8:59   ` Jiri Olsa
  2019-05-28 19:05     ` Liang, Kan
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  8:59 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:21PM -0700, kan.liang@linux.intel.com wrote:
> From: Kan Liang <kan.liang@linux.intel.com>
> 
> The "sibling cores" actually shows the sibling CPUs of a socket.
> The name "sibling cores" is very misleading.
> 
> Rename "sibling cores" to "sibling sockets"

by checking on die topology, I found that thread_siblings_list
is deprecated/renamed to core_cpus_list.. we should keep that
in mind and support both

jirka

> 
> Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
> ---
>  tools/perf/Documentation/perf.data-file-format.txt | 2 +-
>  tools/perf/util/header.c                           | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
> index c731416..dd85163 100644
> --- a/tools/perf/Documentation/perf.data-file-format.txt
> +++ b/tools/perf/Documentation/perf.data-file-format.txt
> @@ -168,7 +168,7 @@ struct {
>  };
>  
>  Example:
> -	sibling cores   : 0-8
> +	sibling sockets : 0-8
>  	sibling dies	: 0-3
>  	sibling dies	: 4-7
>  	sibling threads : 0-1
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index faa1e38..eb79495 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -1465,7 +1465,7 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>  	str = ph->env.sibling_cores;
>  
>  	for (i = 0; i < nr; i++) {
> -		fprintf(fp, "# sibling cores   : %s\n", str);
> +		fprintf(fp, "# sibling sockets : %s\n", str);
>  		str += strlen(str) + 1;
>  	}
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
  2019-05-23 20:41 ` [PATCH 2/3] perf stat: Support per-die aggregation kan.liang
  2019-05-23 20:41 ` [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets" kan.liang
@ 2019-05-28  8:59 ` Jiri Olsa
  2019-05-28  8:59 ` Jiri Olsa
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  8:59 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:

SNIP

> @@ -88,7 +138,7 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>  	return ret;
>  }
>  
> -void cpu_topology__delete(struct cpu_topology *tp)
> +void cpu_topology__delete(struct cpu_topology *tp, bool has_die)
>  {
>  	u32 i;
>  
> @@ -98,17 +148,22 @@ void cpu_topology__delete(struct cpu_topology *tp)
>  	for (i = 0 ; i < tp->core_sib; i++)
>  		zfree(&tp->core_siblings[i]);
>  
> +	if (has_die) {

I think there's no need for has_die check in here,
tp->die_sib will be zero, and also will tp->die_siblings[i]

jirka

> +		for (i = 0 ; i < tp->die_sib; i++)
> +			zfree(&tp->die_siblings[i]);
> +	}
> +
>  	for (i = 0 ; i < tp->thread_sib; i++)
>  		zfree(&tp->thread_siblings[i]);
>  
>  	free(tp);
>  }

SNIP

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
                   ` (2 preceding siblings ...)
  2019-05-28  8:59 ` [PATCH 1/3] perf header: Add die information in CPU topology Jiri Olsa
@ 2019-05-28  8:59 ` Jiri Olsa
  2019-05-28  9:00 ` Jiri Olsa
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  8:59 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:

SNIP

> 
> Add cpu_map__get_die_id() in cpumap.c to fetch die id information.
> 
> Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
> ---
>  tools/perf/Documentation/perf.data-file-format.txt |   9 +-
>  tools/perf/util/cpumap.c                           |   7 ++
>  tools/perf/util/cpumap.h                           |   1 +
>  tools/perf/util/cputopo.c                          |  83 ++++++++++++++--
>  tools/perf/util/cputopo.h                          |   7 +-
>  tools/perf/util/env.c                              |   1 +
>  tools/perf/util/env.h                              |   3 +
>  tools/perf/util/header.c                           | 104 +++++++++++++++++++--
>  8 files changed, 193 insertions(+), 22 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
> index 6967e9b..c731416 100644
> --- a/tools/perf/Documentation/perf.data-file-format.txt
> +++ b/tools/perf/Documentation/perf.data-file-format.txt
> @@ -153,7 +153,7 @@ struct {
>  
>  String lists defining the core and CPU threads topology.
>  The string lists are followed by a variable length array
> -which contains core_id and socket_id of each cpu.
> +which contains core_id, die_id (for x86) and socket_id of each cpu.
>  The number of entries can be determined by the size of the
>  section minus the sizes of both string lists.
>  
> @@ -162,14 +162,19 @@ struct {
>         struct perf_header_string_list threads; /* Variable length */
>         struct {
>  	      uint32_t core_id;
> +	      uint32_t die_id;
>  	      uint32_t socket_id;
>         } cpus[nr]; /* Variable length records */
>  };
>  
>  Example:
> -	sibling cores   : 0-3
> +	sibling cores   : 0-8
> +	sibling dies	: 0-3
> +	sibling dies	: 4-7
>  	sibling threads : 0-1
>  	sibling threads : 2-3
> +	sibling threads : 4-5
> +	sibling threads : 6-7
>  
>  	HEADER_NUMA_TOPOLOGY = 14,
>  
> diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
> index 0b59922..7db1365 100644
> --- a/tools/perf/util/cpumap.c
> +++ b/tools/perf/util/cpumap.c
> @@ -373,6 +373,13 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
>  	return 0;
>  }
>  
> +int cpu_map__get_die_id(int cpu)
> +{
> +	int value, ret = cpu__get_topology_int(cpu, "die_id", &value);
> +
> +	return ret ?: value;
> +}

please put 'adding cpu_map__get_die_id function' into separate patch

thanks,
jirka

> +
>  int cpu_map__get_core_id(int cpu)
>  {
>  	int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
> diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
> index f00ce62..6762ff9 100644
> --- a/tools/perf/util/cpumap.h
> +++ b/tools/perf/util/cpumap.h
> @@ -25,6 +25,7 @@ size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size);
>  size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
>  int cpu_map__get_socket_id(int cpu);
>  int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
> +int cpu_map__get_die_id(int cpu);
>  int cpu_map__get_core_id(int cpu);
>  int cpu_map__get_core(struct cpu_map *map, int idx, void *data);
>  int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
> diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c

SNIP

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
                   ` (3 preceding siblings ...)
  2019-05-28  8:59 ` Jiri Olsa
@ 2019-05-28  9:00 ` Jiri Olsa
  2019-05-28 19:06   ` Liang, Kan
  2019-05-28  9:00 ` Jiri Olsa
  2019-05-28  9:00 ` Jiri Olsa
  6 siblings, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  9:00 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:

SNIP

> diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c
> index ece0710..f6e7db7 100644
> --- a/tools/perf/util/cputopo.c
> +++ b/tools/perf/util/cputopo.c
> @@ -1,5 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0
>  #include <sys/param.h>
> +#include <sys/utsname.h>
>  #include <inttypes.h>
>  #include <api/fs/fs.h>
>  
> @@ -8,9 +9,10 @@
>  #include "util.h"
>  #include "env.h"
>  
> -
>  #define CORE_SIB_FMT \
>  	"%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
> +#define DIE_SIB_FMT \
> +	"%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
>  #define THRD_SIB_FMT \
>  	"%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
>  #define NODE_ONLINE_FMT \
> @@ -20,7 +22,26 @@
>  #define NODE_CPULIST_FMT \
>  	"%s/devices/system/node/node%d/cpulist"
>  
> -static int build_cpu_topology(struct cpu_topology *tp, int cpu)
> +bool check_x86_die_exists(void)
> +{
> +	char filename[MAXPATHLEN];
> +	struct utsname uts;
> +
> +	if (uname(&uts) < 0)
> +		return false;
> +
> +	if (strncmp(uts.machine, "x86_64", 6))
> +		return false;
> +
> +	scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
> +		  sysfs__mountpoint(), 0);
> +	if (access(filename, F_OK) == -1)
> +		return false;
> +
> +	return true;
> +}

we could rename this to:

static bool has_die(void)
{
	static bool has_die;

	if (initialized)
		return has_die;

	has_die = ...
	initialized = true;
}

and got rid of all those 'has_die' arguments below

> +
> +static int build_cpu_topology(struct cpu_topology *tp, int cpu, bool has_die)
>  {
>  	FILE *fp;
>  	char filename[MAXPATHLEN];
> @@ -34,12 +55,12 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>  		  sysfs__mountpoint(), cpu);
>  	fp = fopen(filename, "r");
>  	if (!fp)
> -		goto try_threads;
> +		goto try_dies;
>  
>  	sret = getline(&buf, &len, fp);
>  	fclose(fp);
>  	if (sret <= 0)
> -		goto try_threads;
> +		goto try_dies;
>  
>  	p = strchr(buf, '\n');
>  	if (p)
> @@ -57,6 +78,35 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>  	}
>  	ret = 0;
>  
> +try_dies:
> +	if (has_die) {
> +		scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
> +			  sysfs__mountpoint(), cpu);
> +		fp = fopen(filename, "r");
> +		if (!fp)
> +			goto try_threads;
> +
> +		sret = getline(&buf, &len, fp);
> +		fclose(fp);
> +		if (sret <= 0)
> +			goto try_threads;
> +
> +		p = strchr(buf, '\n');
> +		if (p)
> +			*p = '\0';
> +
> +		for (i = 0; i < tp->die_sib; i++) {
> +			if (!strcmp(buf, tp->die_siblings[i]))
> +				break;
> +		}
> +		if (i == tp->die_sib) {
> +			tp->die_siblings[i] = buf;
> +			tp->die_sib++;
> +			buf = NULL;
> +			len = 0;
> +		}
> +		ret = 0;
> +	}
>  try_threads:
>  	scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
>  		  sysfs__mountpoint(), cpu);
> @@ -88,7 +138,7 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>  	return ret;
>  }
>  
> -void cpu_topology__delete(struct cpu_topology *tp)
> +void cpu_topology__delete(struct cpu_topology *tp, bool has_die)
>  {
>  	u32 i;
>  
> @@ -98,17 +148,22 @@ void cpu_topology__delete(struct cpu_topology *tp)
>  	for (i = 0 ; i < tp->core_sib; i++)
>  		zfree(&tp->core_siblings[i]);
>  
> +	if (has_die) {
> +		for (i = 0 ; i < tp->die_sib; i++)
> +			zfree(&tp->die_siblings[i]);
> +	}
> +
>  	for (i = 0 ; i < tp->thread_sib; i++)
>  		zfree(&tp->thread_siblings[i]);
>  
>  	free(tp);
>  }
>  
> -struct cpu_topology *cpu_topology__new(void)
> +struct cpu_topology *cpu_topology__new(bool has_die)
>  {
>  	struct cpu_topology *tp = NULL;
>  	void *addr;
> -	u32 nr, i;
> +	u32 nr, i, nr_addr;
>  	size_t sz;
>  	long ncpus;
>  	int ret = -1;
> @@ -126,7 +181,11 @@ struct cpu_topology *cpu_topology__new(void)
>  	nr = (u32)(ncpus & UINT_MAX);
>  
>  	sz = nr * sizeof(char *);
> -	addr = calloc(1, sizeof(*tp) + 2 * sz);
> +	if (has_die)
> +		nr_addr = 3;
> +	else
> +		nr_addr = 2;
> +	addr = calloc(1, sizeof(*tp) + nr_addr * sz);
>  	if (!addr)
>  		goto out_free;
>  
> @@ -134,13 +193,17 @@ struct cpu_topology *cpu_topology__new(void)
>  	addr += sizeof(*tp);
>  	tp->core_siblings = addr;
>  	addr += sz;
> +	if (has_die) {
> +		tp->die_siblings = addr;
> +		addr += sz;
> +	}
>  	tp->thread_siblings = addr;
>  
>  	for (i = 0; i < nr; i++) {
>  		if (!cpu_map__has(map, i))
>  			continue;
>  
> -		ret = build_cpu_topology(tp, i);
> +		ret = build_cpu_topology(tp, i, has_die);
>  		if (ret < 0)
>  			break;
>  	}
> @@ -148,7 +211,7 @@ struct cpu_topology *cpu_topology__new(void)
>  out_free:
>  	cpu_map__put(map);
>  	if (ret) {
> -		cpu_topology__delete(tp);
> +		cpu_topology__delete(tp, has_die);
>  		tp = NULL;
>  	}
>  	return tp;
> diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h
> index 47a97e7..cb4e6fe 100644
> --- a/tools/perf/util/cputopo.h
> +++ b/tools/perf/util/cputopo.h
> @@ -7,8 +7,10 @@
>  
>  struct cpu_topology {
>  	u32	  core_sib;
> +	u32	  die_sib;
>  	u32	  thread_sib;
>  	char	**core_siblings;
> +	char	**die_siblings;
>  	char	**thread_siblings;
>  };
>  
> @@ -24,8 +26,9 @@ struct numa_topology {
>  	struct numa_topology_node	nodes[0];
>  };
>  
> -struct cpu_topology *cpu_topology__new(void);
> -void cpu_topology__delete(struct cpu_topology *tp);
> +bool check_x86_die_exists(void);
> +struct cpu_topology *cpu_topology__new(bool has_die);
> +void cpu_topology__delete(struct cpu_topology *tp, bool has_die);
>  
>  struct numa_topology *numa_topology__new(void);
>  void numa_topology__delete(struct numa_topology *tp);
> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
> index 6a3eaf7..1cc7a18 100644
> --- a/tools/perf/util/env.c
> +++ b/tools/perf/util/env.c
> @@ -246,6 +246,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
>  	for (cpu = 0; cpu < nr_cpus; ++cpu) {
>  		env->cpu[cpu].core_id	= cpu_map__get_core_id(cpu);
>  		env->cpu[cpu].socket_id	= cpu_map__get_socket_id(cpu);
> +		env->cpu[cpu].die_id	= cpu_map__get_die_id(cpu);
>  	}
>  
>  	env->nr_cpus_avail = nr_cpus;
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index 271a90b..d5d9865 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -9,6 +9,7 @@
>  
>  struct cpu_topology_map {
>  	int	socket_id;
> +	int	die_id;
>  	int	core_id;
>  };
>  
> @@ -49,6 +50,7 @@ struct perf_env {
>  
>  	int			nr_cmdline;
>  	int			nr_sibling_cores;
> +	int			nr_sibling_dies;
>  	int			nr_sibling_threads;
>  	int			nr_numa_nodes;
>  	int			nr_memory_nodes;
> @@ -57,6 +59,7 @@ struct perf_env {
>  	char			*cmdline;
>  	const char		**cmdline_argv;
>  	char			*sibling_cores;
> +	char			*sibling_dies;
>  	char			*sibling_threads;
>  	char			*pmu_mappings;
>  	struct cpu_topology_map	*cpu;
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index 847ae51..faa1e38 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -561,8 +561,11 @@ static int write_cpu_topology(struct feat_fd *ff,
>  	struct cpu_topology *tp;
>  	u32 i;
>  	int ret, j;
> +	bool has_die;
>  
> -	tp = cpu_topology__new();
> +	has_die = check_x86_die_exists();
> +
> +	tp = cpu_topology__new(has_die);
>  	if (!tp)
>  		return -1;
>  
> @@ -599,8 +602,29 @@ static int write_cpu_topology(struct feat_fd *ff,
>  		if (ret < 0)
>  			return ret;
>  	}
> +
> +	if (!has_die)
> +		goto done;

also the has_die() could stay static in util/cputopo.c,
we can get the 'has_die state' from tp->die_sib != 0

> +
> +	ret = do_write(ff, &tp->die_sib, sizeof(tp->die_sib));
> +	if (ret < 0)
> +		goto done;
> +
> +	for (i = 0; i < tp->die_sib; i++) {
> +		ret = do_write_string(ff, tp->die_siblings[i]);
> +		if (ret < 0)
> +			goto done;
> +	}
> +
> +	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
> +		ret = do_write(ff, &perf_env.cpu[j].die_id,
> +			       sizeof(perf_env.cpu[j].die_id));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
>  done:
> -	cpu_topology__delete(tp);
> +	cpu_topology__delete(tp, has_die);
>  	return ret;
>  }
>  
> @@ -1428,6 +1452,8 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp)
>  	fputc('\n', fp);
>  }
>  
> +static bool has_die;

same here.. you can use env->nr_sibling_dies instead of static bool

> +
>  static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>  {
>  	struct perf_header *ph = ff->ph;
> @@ -1443,6 +1469,16 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>  		str += strlen(str) + 1;
>  	}
>  
> +	if (has_die) {
> +		nr = ph->env.nr_sibling_dies;
> +		str = ph->env.sibling_dies;
> +
> +		for (i = 0; i < nr; i++) {
> +			fprintf(fp, "# sibling dies    : %s\n", str);
> +			str += strlen(str) + 1;
> +		}
> +	}
> +
>  	nr = ph->env.nr_sibling_threads;
>  	str = ph->env.sibling_threads;
>  
> @@ -1451,12 +1487,28 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>  		str += strlen(str) + 1;
>  	}
>  
> -	if (ph->env.cpu != NULL) {
> -		for (i = 0; i < cpu_nr; i++)
> -			fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
> -				ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
> -	} else
> -		fprintf(fp, "# Core ID and Socket ID information is not available\n");
> +	if (has_die) {
> +		if (ph->env.cpu != NULL) {
> +			for (i = 0; i < cpu_nr; i++)
> +				fprintf(fp, "# CPU %d: Core ID %d, "
> +					    "Die ID %d, Socket ID %d\n",
> +					    i, ph->env.cpu[i].core_id,
> +					    ph->env.cpu[i].die_id,
> +					    ph->env.cpu[i].socket_id);
> +		} else
> +			fprintf(fp, "# Core ID, Die ID and Socket ID "
> +				    "information is not available\n");
> +	} else {
> +		if (ph->env.cpu != NULL) {
> +			for (i = 0; i < cpu_nr; i++)
> +				fprintf(fp, "# CPU %d: Core ID %d, "
> +					    "Socket ID %d\n",
> +					    i, ph->env.cpu[i].core_id,
> +					    ph->env.cpu[i].socket_id);
> +		} else
> +			fprintf(fp, "# Core ID and Socket ID "
> +				    "information is not available\n");
> +	}
>  }

SNIP

thanks,
jirka

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
                   ` (4 preceding siblings ...)
  2019-05-28  9:00 ` Jiri Olsa
@ 2019-05-28  9:00 ` Jiri Olsa
  2019-05-28  9:00 ` Jiri Olsa
  6 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  9:00 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:

SNIP

>  	if (sret <= 0)
> -		goto try_threads;
> +		goto try_dies;
>  
>  	p = strchr(buf, '\n');
>  	if (p)
> @@ -57,6 +78,35 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>  	}
>  	ret = 0;
>  
> +try_dies:
> +	if (has_die) {

less depth..

	if (!has_die())
		goto try_threads;


	scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
		  sysfs__mountpoint(), cpu);
	...

> +		scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
> +			  sysfs__mountpoint(), cpu);
> +		fp = fopen(filename, "r");
> +		if (!fp)
> +			goto try_threads;
> +
> +		sret = getline(&buf, &len, fp);
> +		fclose(fp);
> +		if (sret <= 0)
> +			goto try_threads;
> +
> +		p = strchr(buf, '\n');
> +		if (p)
> +			*p = '\0';
> +
> +		for (i = 0; i < tp->die_sib; i++) {
> +			if (!strcmp(buf, tp->die_siblings[i]))
> +				break;
> +		}
> +		if (i == tp->die_sib) {
> +			tp->die_siblings[i] = buf;
> +			tp->die_sib++;
> +			buf = NULL;
> +			len = 0;
> +		}
> +		ret = 0;
> +	}
>  try_threads:
>  	scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,

SNIP

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
                   ` (5 preceding siblings ...)
  2019-05-28  9:00 ` Jiri Olsa
@ 2019-05-28  9:00 ` Jiri Olsa
  6 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  9:00 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:
> From: Kan Liang <kan.liang@linux.intel.com>
> 
> With the new CPUID.1F, a new level type of CPU topology, 'die', is
> introduced. The 'die' information in CPU topology should be added in
> perf header.
> 
> To be compatible with old perf.data, the patch checks the section size
> before reading the die information. The new info is added at the end of
> the cpu_topology section, the old perf tool ignores the extra data.
> It never reads data crossing the section boundary.
> 
> The new perf tool with the patch can be used on legacy kernel. Add a
> new function check_x86_die_exists() to check if die topology
> information is supported by kernel. The function only check X86 and
> CPU 0. Assuming other CPUs have same topology.

[jolsa@dell-r440-01 perf]$ sudo ./perf stat -e cycles --per-die -a -I 1000
#           time die cpus             counts unit events
     1.000526089 S0-D0          20          6,828,029      cycles
     1.000526089 S1-D0          20          2,609,924      cycles
     2.002578005 S0-D0          20          5,280,361      cycles


the title is shifted from the values

jirka

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

* Re: [PATCH 2/3] perf stat: Support per-die aggregation
  2019-05-23 20:41 ` [PATCH 2/3] perf stat: Support per-die aggregation kan.liang
@ 2019-05-28  9:00   ` Jiri Olsa
  0 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28  9:00 UTC (permalink / raw)
  To: kan.liang; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Thu, May 23, 2019 at 01:41:20PM -0700, kan.liang@linux.intel.com wrote:

SNIP

>  		if (cpu_map__build_core_map(evsel_list->cpus, &stat_config.aggr_map)) {
>  			perror("cannot build core map");
> @@ -936,21 +957,41 @@ static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
>  	return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
>  }
>  
> +static int perf_env__get_die(struct cpu_map *map, int idx, void *data)
> +{
> +	struct perf_env *env = data;
> +	int die = -1, cpu = perf_env__get_cpu(env, map, idx);
> +
> +	if (cpu != -1) {
> +		/*
> +		 * Encode socket in upper 8 bits
> +		 * die_id is relative to socket,
> +		 * we need a global id. So we combine
> +		 * socket + die id
> +		 */
> +		die = (env->cpu[cpu].socket_id << 8) |
> +		      (env->cpu[cpu].die_id & 0xff);
> +	}
> +
> +	return die;
> +}
> +
>  static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
>  {
>  	struct perf_env *env = data;
>  	int core = -1, cpu = perf_env__get_cpu(env, map, idx);
>  
>  	if (cpu != -1) {
> -		int socket_id = env->cpu[cpu].socket_id;
> -
>  		/*
> -		 * Encode socket in upper 16 bits
> -		 * core_id is relative to socket, and
> +		 * Encode socket in upper 24 bits
> +		 * encode die id in upper 16 bits
> +		 * core_id is relative to socket and die,
>  		 * we need a global id. So we combine
> -		 * socket + core id.
> +		 * socket + die id + core id
>  		 */
> -		core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
> +		core = (env->cpu[cpu].socket_id << 24) |
> +		       (env->cpu[cpu].die_id << 16) |
> +		       (env->cpu[cpu].core_id & 0xffff);

I guess we're still safe with 1 byte for socket and die id,
but could we still check the size fits, and warn and bail
out otherwise?

thanks,
jirka

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

* Re: [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets"
  2019-05-28  8:59   ` Jiri Olsa
@ 2019-05-28 19:05     ` Liang, Kan
  0 siblings, 0 replies; 13+ messages in thread
From: Liang, Kan @ 2019-05-28 19:05 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak



On 5/28/2019 4:59 AM, Jiri Olsa wrote:
> On Thu, May 23, 2019 at 01:41:21PM -0700, kan.liang@linux.intel.com wrote:
>> From: Kan Liang <kan.liang@linux.intel.com>
>>
>> The "sibling cores" actually shows the sibling CPUs of a socket.
>> The name "sibling cores" is very misleading.
>>
>> Rename "sibling cores" to "sibling sockets"
> 
> by checking on die topology, I found that thread_siblings_list
> is deprecated/renamed to core_cpus_list.. we should keep that
> in mind and support both
>

Sure, I will introduce THRD_SIB_FMT_NEW for the new name.
#define THRD_SIB_FMT_NEW \
	"%s/devices/system/cpu/cpu%d/topology/core_cpus_list"

I will check new name first, (if N/A, then check the old name), before 
parsing the topology information.

I will add the change in V2.

Thanks,
Kan



> jirka
> 
>>
>> Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
>> ---
>>   tools/perf/Documentation/perf.data-file-format.txt | 2 +-
>>   tools/perf/util/header.c                           | 2 +-
>>   2 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
>> index c731416..dd85163 100644
>> --- a/tools/perf/Documentation/perf.data-file-format.txt
>> +++ b/tools/perf/Documentation/perf.data-file-format.txt
>> @@ -168,7 +168,7 @@ struct {
>>   };
>>   
>>   Example:
>> -	sibling cores   : 0-8
>> +	sibling sockets : 0-8
>>   	sibling dies	: 0-3
>>   	sibling dies	: 4-7
>>   	sibling threads : 0-1
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index faa1e38..eb79495 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -1465,7 +1465,7 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>>   	str = ph->env.sibling_cores;
>>   
>>   	for (i = 0; i < nr; i++) {
>> -		fprintf(fp, "# sibling cores   : %s\n", str);
>> +		fprintf(fp, "# sibling sockets : %s\n", str);
>>   		str += strlen(str) + 1;
>>   	}
>>   
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-28  9:00 ` Jiri Olsa
@ 2019-05-28 19:06   ` Liang, Kan
  2019-05-28 19:29     ` Jiri Olsa
  0 siblings, 1 reply; 13+ messages in thread
From: Liang, Kan @ 2019-05-28 19:06 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak



On 5/28/2019 5:00 AM, Jiri Olsa wrote:
> On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:
> 
> SNIP
> 
>> diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c
>> index ece0710..f6e7db7 100644
>> --- a/tools/perf/util/cputopo.c
>> +++ b/tools/perf/util/cputopo.c
>> @@ -1,5 +1,6 @@
>>   // SPDX-License-Identifier: GPL-2.0
>>   #include <sys/param.h>
>> +#include <sys/utsname.h>
>>   #include <inttypes.h>
>>   #include <api/fs/fs.h>
>>   
>> @@ -8,9 +9,10 @@
>>   #include "util.h"
>>   #include "env.h"
>>   
>> -
>>   #define CORE_SIB_FMT \
>>   	"%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
>> +#define DIE_SIB_FMT \
>> +	"%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
>>   #define THRD_SIB_FMT \
>>   	"%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
>>   #define NODE_ONLINE_FMT \
>> @@ -20,7 +22,26 @@
>>   #define NODE_CPULIST_FMT \
>>   	"%s/devices/system/node/node%d/cpulist"
>>   
>> -static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>> +bool check_x86_die_exists(void)
>> +{
>> +	char filename[MAXPATHLEN];
>> +	struct utsname uts;
>> +
>> +	if (uname(&uts) < 0)
>> +		return false;
>> +
>> +	if (strncmp(uts.machine, "x86_64", 6))
>> +		return false;
>> +
>> +	scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
>> +		  sysfs__mountpoint(), 0);
>> +	if (access(filename, F_OK) == -1)
>> +		return false;
>> +
>> +	return true;
>> +}
> 
> we could rename this to:
> 
> static bool has_die(void)
> {
> 	static bool has_die;
> 
> 	if (initialized)
> 		return has_die;
> 
> 	has_die = ...
> 	initialized = true;
> }
> 
> and got rid of all those 'has_die' arguments below

Yes, we can rename the function to has_die(). It looks like all the 
'has_die' arguments can be replaced either.

But why we want a "initialized" here? to cache the value? It looks like 
we only need to call has_die() once.

Thanks,
Kan

> 
>> +
>> +static int build_cpu_topology(struct cpu_topology *tp, int cpu, bool has_die)
>>   {
>>   	FILE *fp;
>>   	char filename[MAXPATHLEN];
>> @@ -34,12 +55,12 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>>   		  sysfs__mountpoint(), cpu);
>>   	fp = fopen(filename, "r");
>>   	if (!fp)
>> -		goto try_threads;
>> +		goto try_dies;
>>   
>>   	sret = getline(&buf, &len, fp);
>>   	fclose(fp);
>>   	if (sret <= 0)
>> -		goto try_threads;
>> +		goto try_dies;
>>   
>>   	p = strchr(buf, '\n');
>>   	if (p)
>> @@ -57,6 +78,35 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>>   	}
>>   	ret = 0;
>>   
>> +try_dies:
>> +	if (has_die) {
>> +		scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
>> +			  sysfs__mountpoint(), cpu);
>> +		fp = fopen(filename, "r");
>> +		if (!fp)
>> +			goto try_threads;
>> +
>> +		sret = getline(&buf, &len, fp);
>> +		fclose(fp);
>> +		if (sret <= 0)
>> +			goto try_threads;
>> +
>> +		p = strchr(buf, '\n');
>> +		if (p)
>> +			*p = '\0';
>> +
>> +		for (i = 0; i < tp->die_sib; i++) {
>> +			if (!strcmp(buf, tp->die_siblings[i]))
>> +				break;
>> +		}
>> +		if (i == tp->die_sib) {
>> +			tp->die_siblings[i] = buf;
>> +			tp->die_sib++;
>> +			buf = NULL;
>> +			len = 0;
>> +		}
>> +		ret = 0;
>> +	}
>>   try_threads:
>>   	scnprintf(filename, MAXPATHLEN, THRD_SIB_FMT,
>>   		  sysfs__mountpoint(), cpu);
>> @@ -88,7 +138,7 @@ static int build_cpu_topology(struct cpu_topology *tp, int cpu)
>>   	return ret;
>>   }
>>   
>> -void cpu_topology__delete(struct cpu_topology *tp)
>> +void cpu_topology__delete(struct cpu_topology *tp, bool has_die)
>>   {
>>   	u32 i;
>>   
>> @@ -98,17 +148,22 @@ void cpu_topology__delete(struct cpu_topology *tp)
>>   	for (i = 0 ; i < tp->core_sib; i++)
>>   		zfree(&tp->core_siblings[i]);
>>   
>> +	if (has_die) {
>> +		for (i = 0 ; i < tp->die_sib; i++)
>> +			zfree(&tp->die_siblings[i]);
>> +	}
>> +
>>   	for (i = 0 ; i < tp->thread_sib; i++)
>>   		zfree(&tp->thread_siblings[i]);
>>   
>>   	free(tp);
>>   }
>>   
>> -struct cpu_topology *cpu_topology__new(void)
>> +struct cpu_topology *cpu_topology__new(bool has_die)
>>   {
>>   	struct cpu_topology *tp = NULL;
>>   	void *addr;
>> -	u32 nr, i;
>> +	u32 nr, i, nr_addr;
>>   	size_t sz;
>>   	long ncpus;
>>   	int ret = -1;
>> @@ -126,7 +181,11 @@ struct cpu_topology *cpu_topology__new(void)
>>   	nr = (u32)(ncpus & UINT_MAX);
>>   
>>   	sz = nr * sizeof(char *);
>> -	addr = calloc(1, sizeof(*tp) + 2 * sz);
>> +	if (has_die)
>> +		nr_addr = 3;
>> +	else
>> +		nr_addr = 2;
>> +	addr = calloc(1, sizeof(*tp) + nr_addr * sz);
>>   	if (!addr)
>>   		goto out_free;
>>   
>> @@ -134,13 +193,17 @@ struct cpu_topology *cpu_topology__new(void)
>>   	addr += sizeof(*tp);
>>   	tp->core_siblings = addr;
>>   	addr += sz;
>> +	if (has_die) {
>> +		tp->die_siblings = addr;
>> +		addr += sz;
>> +	}
>>   	tp->thread_siblings = addr;
>>   
>>   	for (i = 0; i < nr; i++) {
>>   		if (!cpu_map__has(map, i))
>>   			continue;
>>   
>> -		ret = build_cpu_topology(tp, i);
>> +		ret = build_cpu_topology(tp, i, has_die);
>>   		if (ret < 0)
>>   			break;
>>   	}
>> @@ -148,7 +211,7 @@ struct cpu_topology *cpu_topology__new(void)
>>   out_free:
>>   	cpu_map__put(map);
>>   	if (ret) {
>> -		cpu_topology__delete(tp);
>> +		cpu_topology__delete(tp, has_die);
>>   		tp = NULL;
>>   	}
>>   	return tp;
>> diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h
>> index 47a97e7..cb4e6fe 100644
>> --- a/tools/perf/util/cputopo.h
>> +++ b/tools/perf/util/cputopo.h
>> @@ -7,8 +7,10 @@
>>   
>>   struct cpu_topology {
>>   	u32	  core_sib;
>> +	u32	  die_sib;
>>   	u32	  thread_sib;
>>   	char	**core_siblings;
>> +	char	**die_siblings;
>>   	char	**thread_siblings;
>>   };
>>   
>> @@ -24,8 +26,9 @@ struct numa_topology {
>>   	struct numa_topology_node	nodes[0];
>>   };
>>   
>> -struct cpu_topology *cpu_topology__new(void);
>> -void cpu_topology__delete(struct cpu_topology *tp);
>> +bool check_x86_die_exists(void);
>> +struct cpu_topology *cpu_topology__new(bool has_die);
>> +void cpu_topology__delete(struct cpu_topology *tp, bool has_die);
>>   
>>   struct numa_topology *numa_topology__new(void);
>>   void numa_topology__delete(struct numa_topology *tp);
>> diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
>> index 6a3eaf7..1cc7a18 100644
>> --- a/tools/perf/util/env.c
>> +++ b/tools/perf/util/env.c
>> @@ -246,6 +246,7 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
>>   	for (cpu = 0; cpu < nr_cpus; ++cpu) {
>>   		env->cpu[cpu].core_id	= cpu_map__get_core_id(cpu);
>>   		env->cpu[cpu].socket_id	= cpu_map__get_socket_id(cpu);
>> +		env->cpu[cpu].die_id	= cpu_map__get_die_id(cpu);
>>   	}
>>   
>>   	env->nr_cpus_avail = nr_cpus;
>> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
>> index 271a90b..d5d9865 100644
>> --- a/tools/perf/util/env.h
>> +++ b/tools/perf/util/env.h
>> @@ -9,6 +9,7 @@
>>   
>>   struct cpu_topology_map {
>>   	int	socket_id;
>> +	int	die_id;
>>   	int	core_id;
>>   };
>>   
>> @@ -49,6 +50,7 @@ struct perf_env {
>>   
>>   	int			nr_cmdline;
>>   	int			nr_sibling_cores;
>> +	int			nr_sibling_dies;
>>   	int			nr_sibling_threads;
>>   	int			nr_numa_nodes;
>>   	int			nr_memory_nodes;
>> @@ -57,6 +59,7 @@ struct perf_env {
>>   	char			*cmdline;
>>   	const char		**cmdline_argv;
>>   	char			*sibling_cores;
>> +	char			*sibling_dies;
>>   	char			*sibling_threads;
>>   	char			*pmu_mappings;
>>   	struct cpu_topology_map	*cpu;
>> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
>> index 847ae51..faa1e38 100644
>> --- a/tools/perf/util/header.c
>> +++ b/tools/perf/util/header.c
>> @@ -561,8 +561,11 @@ static int write_cpu_topology(struct feat_fd *ff,
>>   	struct cpu_topology *tp;
>>   	u32 i;
>>   	int ret, j;
>> +	bool has_die;
>>   
>> -	tp = cpu_topology__new();
>> +	has_die = check_x86_die_exists();
>> +
>> +	tp = cpu_topology__new(has_die);
>>   	if (!tp)
>>   		return -1;
>>   
>> @@ -599,8 +602,29 @@ static int write_cpu_topology(struct feat_fd *ff,
>>   		if (ret < 0)
>>   			return ret;
>>   	}
>> +
>> +	if (!has_die)
>> +		goto done;
> 
> also the has_die() could stay static in util/cputopo.c,
> we can get the 'has_die state' from tp->die_sib != 0
> 
>> +
>> +	ret = do_write(ff, &tp->die_sib, sizeof(tp->die_sib));
>> +	if (ret < 0)
>> +		goto done;
>> +
>> +	for (i = 0; i < tp->die_sib; i++) {
>> +		ret = do_write_string(ff, tp->die_siblings[i]);
>> +		if (ret < 0)
>> +			goto done;
>> +	}
>> +
>> +	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
>> +		ret = do_write(ff, &perf_env.cpu[j].die_id,
>> +			       sizeof(perf_env.cpu[j].die_id));
>> +		if (ret < 0)
>> +			return ret;
>> +	}
>> +
>>   done:
>> -	cpu_topology__delete(tp);
>> +	cpu_topology__delete(tp, has_die);
>>   	return ret;
>>   }
>>   
>> @@ -1428,6 +1452,8 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp)
>>   	fputc('\n', fp);
>>   }
>>   
>> +static bool has_die;
> 
> same here.. you can use env->nr_sibling_dies instead of static bool
> 
>> +
>>   static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>>   {
>>   	struct perf_header *ph = ff->ph;
>> @@ -1443,6 +1469,16 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>>   		str += strlen(str) + 1;
>>   	}
>>   
>> +	if (has_die) {
>> +		nr = ph->env.nr_sibling_dies;
>> +		str = ph->env.sibling_dies;
>> +
>> +		for (i = 0; i < nr; i++) {
>> +			fprintf(fp, "# sibling dies    : %s\n", str);
>> +			str += strlen(str) + 1;
>> +		}
>> +	}
>> +
>>   	nr = ph->env.nr_sibling_threads;
>>   	str = ph->env.sibling_threads;
>>   
>> @@ -1451,12 +1487,28 @@ static void print_cpu_topology(struct feat_fd *ff, FILE *fp)
>>   		str += strlen(str) + 1;
>>   	}
>>   
>> -	if (ph->env.cpu != NULL) {
>> -		for (i = 0; i < cpu_nr; i++)
>> -			fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i,
>> -				ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id);
>> -	} else
>> -		fprintf(fp, "# Core ID and Socket ID information is not available\n");
>> +	if (has_die) {
>> +		if (ph->env.cpu != NULL) {
>> +			for (i = 0; i < cpu_nr; i++)
>> +				fprintf(fp, "# CPU %d: Core ID %d, "
>> +					    "Die ID %d, Socket ID %d\n",
>> +					    i, ph->env.cpu[i].core_id,
>> +					    ph->env.cpu[i].die_id,
>> +					    ph->env.cpu[i].socket_id);
>> +		} else
>> +			fprintf(fp, "# Core ID, Die ID and Socket ID "
>> +				    "information is not available\n");
>> +	} else {
>> +		if (ph->env.cpu != NULL) {
>> +			for (i = 0; i < cpu_nr; i++)
>> +				fprintf(fp, "# CPU %d: Core ID %d, "
>> +					    "Socket ID %d\n",
>> +					    i, ph->env.cpu[i].core_id,
>> +					    ph->env.cpu[i].socket_id);
>> +		} else
>> +			fprintf(fp, "# Core ID and Socket ID "
>> +				    "information is not available\n");
>> +	}
>>   }
> 
> SNIP
> 
> thanks,
> jirka
> 

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

* Re: [PATCH 1/3] perf header: Add die information in CPU topology
  2019-05-28 19:06   ` Liang, Kan
@ 2019-05-28 19:29     ` Jiri Olsa
  0 siblings, 0 replies; 13+ messages in thread
From: Jiri Olsa @ 2019-05-28 19:29 UTC (permalink / raw)
  To: Liang, Kan; +Cc: acme, jolsa, mingo, linux-kernel, peterz, ak

On Tue, May 28, 2019 at 03:06:16PM -0400, Liang, Kan wrote:
> 
> 
> On 5/28/2019 5:00 AM, Jiri Olsa wrote:
> > On Thu, May 23, 2019 at 01:41:19PM -0700, kan.liang@linux.intel.com wrote:
> > 
> > SNIP
> > 
> > > diff --git a/tools/perf/util/cputopo.c b/tools/perf/util/cputopo.c
> > > index ece0710..f6e7db7 100644
> > > --- a/tools/perf/util/cputopo.c
> > > +++ b/tools/perf/util/cputopo.c
> > > @@ -1,5 +1,6 @@
> > >   // SPDX-License-Identifier: GPL-2.0
> > >   #include <sys/param.h>
> > > +#include <sys/utsname.h>
> > >   #include <inttypes.h>
> > >   #include <api/fs/fs.h>
> > > @@ -8,9 +9,10 @@
> > >   #include "util.h"
> > >   #include "env.h"
> > > -
> > >   #define CORE_SIB_FMT \
> > >   	"%s/devices/system/cpu/cpu%d/topology/core_siblings_list"
> > > +#define DIE_SIB_FMT \
> > > +	"%s/devices/system/cpu/cpu%d/topology/die_cpus_list"
> > >   #define THRD_SIB_FMT \
> > >   	"%s/devices/system/cpu/cpu%d/topology/thread_siblings_list"
> > >   #define NODE_ONLINE_FMT \
> > > @@ -20,7 +22,26 @@
> > >   #define NODE_CPULIST_FMT \
> > >   	"%s/devices/system/node/node%d/cpulist"
> > > -static int build_cpu_topology(struct cpu_topology *tp, int cpu)
> > > +bool check_x86_die_exists(void)
> > > +{
> > > +	char filename[MAXPATHLEN];
> > > +	struct utsname uts;
> > > +
> > > +	if (uname(&uts) < 0)
> > > +		return false;
> > > +
> > > +	if (strncmp(uts.machine, "x86_64", 6))
> > > +		return false;
> > > +
> > > +	scnprintf(filename, MAXPATHLEN, DIE_SIB_FMT,
> > > +		  sysfs__mountpoint(), 0);
> > > +	if (access(filename, F_OK) == -1)
> > > +		return false;
> > > +
> > > +	return true;
> > > +}
> > 
> > we could rename this to:
> > 
> > static bool has_die(void)
> > {
> > 	static bool has_die;
> > 
> > 	if (initialized)
> > 		return has_die;
> > 
> > 	has_die = ...
> > 	initialized = true;
> > }
> > 
> > and got rid of all those 'has_die' arguments below
> 
> Yes, we can rename the function to has_die(). It looks like all the
> 'has_die' arguments can be replaced either.
> 
> But why we want a "initialized" here? to cache the value? It looks like we
> only need to call has_die() once.

right, if it's called from one place then it's ok

thanks,
jirka

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

end of thread, other threads:[~2019-05-28 19:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-23 20:41 [PATCH 1/3] perf header: Add die information in CPU topology kan.liang
2019-05-23 20:41 ` [PATCH 2/3] perf stat: Support per-die aggregation kan.liang
2019-05-28  9:00   ` Jiri Olsa
2019-05-23 20:41 ` [PATCH 3/3] perf header: Rename "sibling cores" to "sibling sockets" kan.liang
2019-05-28  8:59   ` Jiri Olsa
2019-05-28 19:05     ` Liang, Kan
2019-05-28  8:59 ` [PATCH 1/3] perf header: Add die information in CPU topology Jiri Olsa
2019-05-28  8:59 ` Jiri Olsa
2019-05-28  9:00 ` Jiri Olsa
2019-05-28 19:06   ` Liang, Kan
2019-05-28 19:29     ` Jiri Olsa
2019-05-28  9:00 ` Jiri Olsa
2019-05-28  9:00 ` Jiri Olsa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.