[PATCH v1 2/3] perf record: apply affinity masks when reading mmap buffers

Alexey Budankov
2018-12-12T07:40:32Z

Build node cpu masks for mmap data buffers. Bind AIO data buffers
to nodes according to kernel data buffers location. Apply node cpu
masks to trace reading thread every time it references memory cross
node or cross cpu.

Signed-off-by: Alexey Budankov <alexey.budankov@linux.intel.com>
---
tools/perf/builtin-record.c | 9 +++++++++
tools/perf/util/evlist.c | 6 +++++-
tools/perf/util/mmap.c | 38 ++++++++++++++++++++++++++++++++++++-
tools/perf/util/mmap.h | 1 +
4 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4979719e54ae..1a1438c73f96 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -532,6 +532,9 @@ static int record__mmap_evlist(struct record *rec,
struct record_opts *opts = &rec->opts;
char msg[512];

+ if (opts->affinity != PERF_AFFINITY_SYS)
+ cpu__setup_cpunode_map();
+
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages,
opts->auxtrace_mmap_pages,
opts->auxtrace_snapshot_mode,
@@ -751,6 +754,12 @@ static int record__mmap_read_evlist(struct record *rec, struct perf_evlist *evli
struct perf_mmap *map = &maps[i];

if (map->base) {
+ if (rec->opts.affinity != PERF_AFFINITY_SYS &&
+ !CPU_EQUAL(&rec->affinity_mask, &map->affinity_mask)) {
+ CPU_ZERO(&rec->affinity_mask);
+ CPU_OR(&rec->affinity_mask, &rec->affinity_mask, &map->affinity_mask);
+ sched_setaffinity(0, sizeof(rec->affinity_mask), &rec->affinity_mask);
+ }
if (!record__aio_enabled(rec)) {
if (perf_mmap__push(map, rec, record__pushfn) != 0) {
rc = -1;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 60e825be944a..5ca5bb5ea0db 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1028,7 +1028,11 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
* Its value is decided by evsel's write_backward.
* So &mp should not be passed through const pointer.
*/
- struct mmap_params mp = { .nr_cblocks = nr_cblocks, .affinity = affinity };
+ struct mmap_params mp = {
+ .nr_cblocks = nr_cblocks,
+ .affinity = affinity,
+ .cpu_map = cpus
+ };

if (!evlist->mmap)
evlist->mmap = perf_evlist__alloc_mmap(evlist, false);
diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c
index e68ba754a8e2..0d017ea85dcb 100644
--- a/tools/perf/util/mmap.c
+++ b/tools/perf/util/mmap.c
@@ -10,6 +10,9 @@
#include <sys/mman.h>
#include <inttypes.h>
#include <asm/bug.h>
+#ifdef HAVE_LIBNUMA_SUPPORT
+#include <numaif.h>
+#endif
#include "debug.h"
#include "event.h"
#include "mmap.h"
@@ -177,11 +180,27 @@ static int perf_mmap__aio_mmap(struct perf_mmap *map, struct mmap_params *mp)
}
delta_max = sysconf(_SC_AIO_PRIO_DELTA_MAX);
for (i = 0; i < map->aio.nr_cblocks; ++i) {
+#ifndef HAVE_LIBNUMA_SUPPORT
map->aio.data[i] = malloc(perf_mmap__mmap_len(map));
+#else
+ size_t mmap_len = perf_mmap__mmap_len(map);
+ map->aio.data[i] = mmap(NULL, mmap_len,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+#endif
if (!map->aio.data[i]) {
pr_debug2("failed to allocate data buffer area, error %m");
return -1;
}
+#ifdef HAVE_LIBNUMA_SUPPORT
+ if (mp->affinity != PERF_AFFINITY_SYS && cpu__max_node() > 1) {
+ unsigned long node_mask = 1UL << cpu__get_node(map->cpu);
+ if (mbind(map->aio.data[i], mmap_len, MPOL_BIND, &node_mask, 1, 0)) {
+ pr_debug2("failed to bind [%p-%p] to node %d\n",
+ map->aio.data[i], map->aio.data[i] + mmap_len,
+ cpu__get_node(map->cpu));
+ }
+ }
+#endif
/*
* Use cblock.aio_fildes value different from -1
* to denote started aio write operation on the
@@ -209,8 +228,13 @@ static void perf_mmap__aio_munmap(struct perf_mmap *map)
{
int i;

- for (i = 0; i < map->aio.nr_cblocks; ++i)
+ for (i = 0; i < map->aio.nr_cblocks; ++i) {
+#ifndef HAVE_LIBNUMA_SUPPORT
zfree(&map->aio.data[i]);
+#else
+ munmap(map->aio.data[i], perf_mmap__mmap_len(map));
+#endif
+ }
if (map->aio.data)
zfree(&map->aio.data);
zfree(&map->aio.cblocks);
@@ -316,6 +340,7 @@ void perf_mmap__munmap(struct perf_mmap *map)

int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu)
{
+ int c, nr_cpus, node;
/*
* The last one will be done at perf_mmap__consume(), so that we
* make sure we don't prevent tools from consuming every last event in
@@ -344,6 +369,17 @@ int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int c
map->cpu = cpu;

CPU_ZERO(&map->affinity_mask);
+ if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1) {
+ nr_cpus = cpu_map__nr(mp->cpu_map);
+ node = cpu__get_node(map->cpu);
+ for (c = 0; c < nr_cpus; c++) {
+ if (cpu__get_node(c) == node) {
+ CPU_SET(c, &map->affinity_mask);
+ }
+ }
+ } else if (mp->affinity == PERF_AFFINITY_CPU) {
+ CPU_SET(map->cpu, &map->affinity_mask);
+ }

if (auxtrace_mmap__mmap(&map->auxtrace_mmap,
&mp->auxtrace_mp, map->base, fd))
diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h
index e566c19b242b..b3f724fad22e 100644
--- a/tools/perf/util/mmap.h
+++ b/tools/perf/util/mmap.h
@@ -72,6 +72,7 @@ enum bkw_mmap_state {
struct mmap_params {
int prot, mask, nr_cblocks, affinity;
struct auxtrace_mmap_params auxtrace_mp;
+ const struct cpu_map *cpu_map;
};

int perf_mmap__mmap(struct perf_mmap *map, struct mmap_params *mp, int fd, int cpu);