linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Jiri Olsa <jolsa@kernel.org>
Cc: lkml <linux-kernel@vger.kernel.org>,
	Ingo Molnar <mingo@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>,
	David Ahern <dsahern@gmail.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Peter Zijlstra <a.p.zijlstra@chello.nl>
Subject: Re: [PATCH 07/19] perf tools: Add MEM_TOPOLOGY feature to perf data file
Date: Wed, 7 Mar 2018 16:28:38 -0300	[thread overview]
Message-ID: <20180307192838.GU3701@kernel.org> (raw)
In-Reply-To: <20180307155020.32613-8-jolsa@kernel.org>

Em Wed, Mar 07, 2018 at 04:50:08PM +0100, Jiri Olsa escreveu:
> Adding MEM_TOPOLOGY feature to perf data file,
> that will carry physical memory map and its
> node assignments.

Good addition, applied 1-7 in this series, skipping a few after this,
processing the rest.

- Arnaldo
 
> The format of data in MEM_TOPOLOGY is as follows:
> 
>   0 - version          | for future changes
>   8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes
>  16 - count            | number of nodes
> 
>  For each node we store map of physical indexes for
>  each node:
> 
>  32 - node id          | node index
>  40 - size             | size of bitmap
>  48 - bitmap           | bitmap of memory indexes that belongs to node
>                        | /sys/devices/system/node/node<NODE>/memory<INDEX>
> 
> The MEM_TOPOLOGY could be displayed with following
> report command:
> 
>   $ perf report --header-only -I
>   ...
>   # memory nodes (nr 1, block size 0x8000000):
>   #    0 [7G]: 0-23,32-69
> 
> Link: http://lkml.kernel.org/n/tip-qq7sohu774wxq154n3my037z@git.kernel.org
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  tools/include/linux/bitmap.h |   2 +-
>  tools/perf/util/env.h        |   9 ++
>  tools/perf/util/header.c     | 305 +++++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/header.h     |   1 +
>  4 files changed, 316 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
> index ca160270fdfa..63440cc8d618 100644
> --- a/tools/include/linux/bitmap.h
> +++ b/tools/include/linux/bitmap.h
> @@ -98,7 +98,7 @@ static inline int test_and_set_bit(int nr, unsigned long *addr)
>  
>  /**
>   * bitmap_alloc - Allocate bitmap
> - * @nr: Bit to set
> + * @nbits: Number of bits
>   */
>  static inline unsigned long *bitmap_alloc(int nbits)
>  {
> diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
> index bf970f57dce0..c4ef2e523367 100644
> --- a/tools/perf/util/env.h
> +++ b/tools/perf/util/env.h
> @@ -27,6 +27,12 @@ struct numa_node {
>  	struct cpu_map	*map;
>  };
>  
> +struct memory_node {
> +	u64		 node;
> +	u64		 size;
> +	unsigned long	*set;
> +};
> +
>  struct perf_env {
>  	char			*hostname;
>  	char			*os_release;
> @@ -43,6 +49,7 @@ struct perf_env {
>  	int			nr_sibling_cores;
>  	int			nr_sibling_threads;
>  	int			nr_numa_nodes;
> +	int			nr_memory_nodes;
>  	int			nr_pmu_mappings;
>  	int			nr_groups;
>  	char			*cmdline;
> @@ -54,6 +61,8 @@ struct perf_env {
>  	struct cpu_cache_level	*caches;
>  	int			 caches_cnt;
>  	struct numa_node	*numa_nodes;
> +	struct memory_node	*memory_nodes;
> +	unsigned long long	 memory_bsize;
>  };
>  
>  extern struct perf_env perf_env;
> diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
> index e0c3cad0fd8d..3a107e7ac135 100644
> --- a/tools/perf/util/header.c
> +++ b/tools/perf/util/header.c
> @@ -17,6 +17,7 @@
>  #include <sys/stat.h>
>  #include <sys/utsname.h>
>  #include <linux/time64.h>
> +#include <dirent.h>
>  
>  #include "evlist.h"
>  #include "evsel.h"
> @@ -37,6 +38,7 @@
>  #include "asm/bug.h"
>  #include "tool.h"
>  #include "time-utils.h"
> +#include "units.h"
>  
>  #include "sane_ctype.h"
>  
> @@ -132,6 +134,25 @@ int do_write(struct feat_fd *ff, const void *buf, size_t size)
>  }
>  
>  /* Return: 0 if succeded, -ERR if failed. */
> +static int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size)
> +{
> +	u64 *p = (u64 *) set;
> +	int i, ret;
> +
> +	ret = do_write(ff, &size, sizeof(size));
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
> +		ret = do_write(ff, p + i, sizeof(*p));
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Return: 0 if succeded, -ERR if failed. */
>  int write_padded(struct feat_fd *ff, const void *bf,
>  		 size_t count, size_t count_aligned)
>  {
> @@ -243,6 +264,38 @@ static char *do_read_string(struct feat_fd *ff)
>  	return NULL;
>  }
>  
> +/* Return: 0 if succeded, -ERR if failed. */
> +static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize)
> +{
> +	unsigned long *set;
> +	u64 size, *p;
> +	int i, ret;
> +
> +	ret = do_read_u64(ff, &size);
> +	if (ret)
> +		return ret;
> +
> +	set = bitmap_alloc(size);
> +	if (!set)
> +		return -ENOMEM;
> +
> +	bitmap_zero(set, size);
> +
> +	p = (u64 *) set;
> +
> +	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
> +		ret = do_read_u64(ff, p + i);
> +		if (ret < 0) {
> +			free(set);
> +			return ret;
> +		}
> +	}
> +
> +	*pset  = set;
> +	*psize = size;
> +	return 0;
> +}
> +
>  static int write_tracing_data(struct feat_fd *ff,
>  			      struct perf_evlist *evlist)
>  {
> @@ -1196,6 +1249,176 @@ static int write_sample_time(struct feat_fd *ff,
>  			sizeof(evlist->last_sample_time));
>  }
>  
> +
> +static int memory_node__read(struct memory_node *n, unsigned long index)
> +{
> +	unsigned int phys, size = 0;
> +	char path[PATH_MAX];
> +	struct dirent *ent;
> +	DIR *dir;
> +
> +#define for_each_memory(mem, dir)					\
> +	while ((ent = readdir(dir)))					\
> +		if (strcmp(ent->d_name, ".") &&				\
> +		    strcmp(ent->d_name, "..") &&			\
> +		    sscanf(ent->d_name, "memory%u", &mem) == 1)
> +
> +	scnprintf(path, PATH_MAX,
> +		  "%s/devices/system/node/node%lu",
> +		  sysfs__mountpoint(), index);
> +
> +	dir = opendir(path);
> +	if (!dir) {
> +		pr_warning("failed: cant' open memory sysfs data\n");
> +		return -1;
> +	}
> +
> +	for_each_memory(phys, dir) {
> +		size = max(phys, size);
> +	}
> +
> +	size++;
> +
> +	n->set = bitmap_alloc(size);
> +	if (!n->set) {
> +		closedir(dir);
> +		return -ENOMEM;
> +	}
> +
> +	bitmap_zero(n->set, size);
> +	n->node = index;
> +	n->size = size;
> +
> +	rewinddir(dir);
> +
> +	for_each_memory(phys, dir) {
> +		set_bit(phys, n->set);
> +	}
> +
> +	closedir(dir);
> +	return 0;
> +}
> +
> +static int memory_node__sort(const void *a, const void *b)
> +{
> +	const struct memory_node *na = a;
> +	const struct memory_node *nb = b;
> +
> +	return na->node - nb->node;
> +}
> +
> +static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp)
> +{
> +	char path[PATH_MAX];
> +	struct dirent *ent;
> +	DIR *dir;
> +	u64 cnt = 0;
> +	int ret = 0;
> +
> +	scnprintf(path, PATH_MAX, "%s/devices/system/node/",
> +		  sysfs__mountpoint());
> +
> +	dir = opendir(path);
> +	if (!dir) {
> +		pr_warning("failed: can't open node sysfs data\n");
> +		return -1;
> +	}
> +
> +	while (!ret && (ent = readdir(dir))) {
> +		unsigned int index;
> +		int r;
> +
> +		if (!strcmp(ent->d_name, ".") ||
> +		    !strcmp(ent->d_name, ".."))
> +			continue;
> +
> +		r = sscanf(ent->d_name, "node%u", &index);
> +		if (r != 1)
> +			continue;
> +
> +		if (WARN_ONCE(cnt >= size,
> +			      "failed to write MEM_TOPOLOGY, way too many nodes\n"))
> +			return -1;
> +
> +		ret = memory_node__read(&nodes[cnt++], index);
> +	}
> +
> +	*cntp = cnt;
> +	closedir(dir);
> +
> +	if (!ret)
> +		qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort);
> +
> +	return ret;
> +}
> +
> +#define MAX_MEMORY_NODES 2000
> +
> +/*
> + * The MEM_TOPOLOGY holds physical memory map for every
> + * node in system. The format of data is as follows:
> + *
> + *  0 - version          | for future changes
> + *  8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes
> + * 16 - count            | number of nodes
> + *
> + * For each node we store map of physical indexes for
> + * each node:
> + *
> + * 32 - node id          | node index
> + * 40 - size             | size of bitmap
> + * 48 - bitmap           | bitmap of memory indexes that belongs to node
> + */
> +static int write_mem_topology(struct feat_fd *ff __maybe_unused,
> +			      struct perf_evlist *evlist __maybe_unused)
> +{
> +	static struct memory_node nodes[MAX_MEMORY_NODES];
> +	u64 bsize, version = 1, i, nr;
> +	int ret;
> +
> +	ret = sysfs__read_xll("devices/system/memory/block_size_bytes",
> +			      (unsigned long long *) &bsize);
> +	if (ret)
> +		return ret;
> +
> +	ret = build_mem_topology(&nodes[0], MAX_MEMORY_NODES, &nr);
> +	if (ret)
> +		return ret;
> +
> +	ret = do_write(ff, &version, sizeof(version));
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = do_write(ff, &bsize, sizeof(bsize));
> +	if (ret < 0)
> +		goto out;
> +
> +	ret = do_write(ff, &nr, sizeof(nr));
> +	if (ret < 0)
> +		goto out;
> +
> +	for (i = 0; i < nr; i++) {
> +		struct memory_node *n = &nodes[i];
> +
> +		#define _W(v)						\
> +			ret = do_write(ff, &n->v, sizeof(n->v));	\
> +			if (ret < 0)					\
> +				goto out;
> +
> +		_W(node)
> +		_W(size)
> +
> +		#undef _W
> +
> +		ret = do_write_bitmap(ff, n->set, n->size);
> +		if (ret < 0)
> +			goto out;
> +	}
> +
> +out:
> +	return ret;
> +}
> +
>  static void print_hostname(struct feat_fd *ff, FILE *fp)
>  {
>  	fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
> @@ -1543,6 +1766,35 @@ static void print_sample_time(struct feat_fd *ff, FILE *fp)
>  	fprintf(fp, "# sample duration : %10.3f ms\n", d);
>  }
>  
> +static void memory_node__fprintf(struct memory_node *n,
> +				 unsigned long long bsize, FILE *fp)
> +{
> +	char buf_map[100], buf_size[50];
> +	unsigned long long size;
> +
> +	size = bsize * bitmap_weight(n->set, n->size);
> +	unit_number__scnprintf(buf_size, 50, size);
> +
> +	bitmap_scnprintf(n->set, n->size, buf_map, 100);
> +	fprintf(fp, "#  %3" PRIu64 " [%s]: %s\n", n->node, buf_size, buf_map);
> +}
> +
> +static void print_mem_topology(struct feat_fd *ff, FILE *fp)
> +{
> +	struct memory_node *nodes;
> +	int i, nr;
> +
> +	nodes = ff->ph->env.memory_nodes;
> +	nr    = ff->ph->env.nr_memory_nodes;
> +
> +	fprintf(fp, "# memory nodes (nr %d, block size 0x%llx):\n",
> +		nr, ff->ph->env.memory_bsize);
> +
> +	for (i = 0; i < nr; i++) {
> +		memory_node__fprintf(&nodes[i], ff->ph->env.memory_bsize, fp);
> +	}
> +}
> +
>  static int __event_process_build_id(struct build_id_event *bev,
>  				    char *filename,
>  				    struct perf_session *session)
> @@ -2205,6 +2457,58 @@ static int process_sample_time(struct feat_fd *ff, void *data __maybe_unused)
>  	return 0;
>  }
>  
> +static int process_mem_topology(struct feat_fd *ff,
> +				void *data __maybe_unused)
> +{
> +	struct memory_node *nodes;
> +	u64 version, i, nr, bsize;
> +	int ret = -1;
> +
> +	if (do_read_u64(ff, &version))
> +		return -1;
> +
> +	if (version != 1)
> +		return -1;
> +
> +	if (do_read_u64(ff, &bsize))
> +		return -1;
> +
> +	if (do_read_u64(ff, &nr))
> +		return -1;
> +
> +	nodes = zalloc(sizeof(*nodes) * nr);
> +	if (!nodes)
> +		return -1;
> +
> +	for (i = 0; i < nr; i++) {
> +		struct memory_node n;
> +
> +		#define _R(v)				\
> +			if (do_read_u64(ff, &n.v))	\
> +				goto out;		\
> +
> +		_R(node)
> +		_R(size)
> +
> +		#undef _R
> +
> +		if (do_read_bitmap(ff, &n.set, &n.size))
> +			goto out;
> +
> +		nodes[i] = n;
> +	}
> +
> +	ff->ph->env.memory_bsize    = bsize;
> +	ff->ph->env.memory_nodes    = nodes;
> +	ff->ph->env.nr_memory_nodes = nr;
> +	ret = 0;
> +
> +out:
> +	if (ret)
> +		free(nodes);
> +	return ret;
> +}
> +
>  struct feature_ops {
>  	int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
>  	void (*print)(struct feat_fd *ff, FILE *fp);
> @@ -2263,6 +2567,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
>  	FEAT_OPN(STAT,		stat,		false),
>  	FEAT_OPN(CACHE,		cache,		true),
>  	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
> +	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
>  };
>  
>  struct header_print_data {
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index 942bdec6d70d..90d4577a92dc 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -36,6 +36,7 @@ enum {
>  	HEADER_STAT,
>  	HEADER_CACHE,
>  	HEADER_SAMPLE_TIME,
> +	HEADER_MEM_TOPOLOGY,
>  	HEADER_LAST_FEATURE,
>  	HEADER_FEAT_BITS	= 256,
>  };
> -- 
> 2.13.6

  reply	other threads:[~2018-03-07 19:28 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-07 15:50 [PATCH 00/19] perf tools: Assorted fixes Jiri Olsa
2018-03-07 15:50 ` [PATCH 01/19] perf report: Fix the output for stdio events list Jiri Olsa
2018-03-09  8:51   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 02/19] perf report: Display perf.data header info Jiri Olsa
2018-03-09  8:52   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 03/19] perf record: Move machine variable down the function Jiri Olsa
2018-03-09  8:52   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 04/19] perf record: Remove progname from struct record Jiri Olsa
2018-03-09  8:53   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 05/19] perf tools: Add refcnt into struct mem_info Jiri Olsa
2018-03-07 18:56   ` Arnaldo Carvalho de Melo
2018-03-08 10:59     ` Jiri Olsa
2018-03-09  8:53   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 06/19] perf c2c: Use mem_info refcnt logic Jiri Olsa
2018-03-09  8:54   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 07/19] perf tools: Add MEM_TOPOLOGY feature to perf data file Jiri Olsa
2018-03-07 19:28   ` Arnaldo Carvalho de Melo [this message]
2018-03-09  8:54   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 08/19] perf tools: Add mem2node object Jiri Olsa
2018-03-07 19:27   ` Arnaldo Carvalho de Melo
2018-03-08 11:03     ` Jiri Olsa
2018-03-08 12:58       ` Arnaldo Carvalho de Melo
2018-03-08 13:00         ` Arnaldo Carvalho de Melo
2018-03-08 13:18         ` Jiri Olsa
2018-03-07 15:50 ` [PATCH 09/19] perf tests: Add mem2node object test Jiri Olsa
2018-03-07 15:50 ` [PATCH 10/19] perf c2c record: Record physical addresses in samples Jiri Olsa
2018-03-07 15:50 ` [PATCH 11/19] perf c2c report: Make calc_width work with struct c2c_hist_entry Jiri Olsa
2018-03-07 15:50 ` [PATCH 12/19] perf c2c report: Call calc_width only for displayed entries Jiri Olsa
2018-03-07 15:50 ` [PATCH 13/19] perf c2c report: Display node for cacheline address Jiri Olsa
2018-03-07 15:50 ` [PATCH 14/19] perf c2c report: Add span header over cacheline data Jiri Olsa
2018-03-07 15:50 ` [PATCH 15/19] perf c2c report: Add cacheline address count column Jiri Olsa
2018-03-07 15:50 ` [PATCH 16/19] perf tools: Update tags with .cpp files Jiri Olsa
2018-03-07 19:28   ` Arnaldo Carvalho de Melo
2018-03-09  8:55   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 17/19] perf build: Add llvm/clang/cxx make tests into FEATURE_TESTS_EXTRA Jiri Olsa
2018-03-09  8:55   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 18/19] perf build: Add llvm/clang make targets to FILES Jiri Olsa
2018-03-09  8:56   ` [tip:perf/core] " tip-bot for Jiri Olsa
2018-03-07 15:50 ` [PATCH 19/19] perf build: Force llvm/clang test compile output to .make.output Jiri Olsa
2018-03-07 19:30   ` Arnaldo Carvalho de Melo
2018-03-09  8:56   ` [tip:perf/core] " tip-bot for Jiri Olsa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180307192838.GU3701@kernel.org \
    --to=acme@kernel.org \
    --cc=a.p.zijlstra@chello.nl \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=dsahern@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=namhyung@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).