Unverified Commit de7b5c73 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!12162 【OLK-5.10】Workaround ARM PMUs cpu maps having offline cpus

Merge Pull Request from: @zhangqizhi3 
 
1.Returns true if the second argument is a subset of the first
2.The merge function gives the union of two cpu maps. Add an intersect
function which is necessary, for example, when intersecting a PMUs
supported CPUs with user requested.
3.A typical "cpu" PMU has no "cpus" or "cpumask" file meaning the CPU
map is set to NULL, which also encodes an empty CPU map. Update
pmu_cpumask so that if the "cpu" PMU fails to load a CPU map, use a
default of all online PMUs.
4.When PMUs have a cpu map in the 'cpus' or 'cpumask' file, perf will
try to open events on those CPUs. ARM doesn't remove offline CPUs
meaning taking a CPU offline will cause perf commands to fail unless a
CPU map is passed on the command line.

Ian Rogers (3):
  perf cpumap: Add is_subset function
  perf cpumap: Add intersect function
  perf arm: Workaround ARM PMUs cpu maps having offline cpus

Wan Jiabing (1):
  perf pmu: Add CPU map for "cpu" PMUs

 tools/lib/perf/cpumap.c                  | 55 ++++++++++++++++++++++++
 tools/lib/perf/include/internal/cpumap.h |  3 +-
 tools/lib/perf/include/perf/cpumap.h     |  2 +
 tools/perf/arch/arm/util/pmu.c           | 14 ++++--
 tools/perf/tests/cpumap.c                | 45 +++++++++++++++++++
 tools/perf/util/cpumap.c                 |  4 +-
 tools/perf/util/cpumap.h                 | 10 ++++-
 tools/perf/util/pmu.c                    |  2 +-
 8 files changed, 127 insertions(+), 8 deletions(-)


 
 
Link:https://gitee.com/openeuler/kernel/pulls/12162

 

Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parents 22b314fe 0989d0af
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -287,6 +287,26 @@ int perf_cpu_map__max(struct perf_cpu_map *map)
	return max;
}

/** Is 'b' a subset of 'a'. */
bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct perf_cpu_map *b)
{
	if (a == b || !b)
		return true;
	if (!a || b->nr > a->nr)
		return false;

	for (int i = 0, j = 0; i < a->nr; i++) {
		if (a->map[i].cpu > b->map[j].cpu)
			return false;
		if (a->map[i].cpu == b->map[j].cpu) {
			j++;
			if (j == b->nr)
				return true;
		}
	}
	return false;
}

/*
 * Merge two cpumaps
 *
@@ -343,3 +363,38 @@ struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
	perf_cpu_map__put(orig);
	return merged;
}

struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
					     struct perf_cpu_map *other)
{
	struct perf_cpu *tmp_cpus;
	int tmp_len;
	int i, j, k;
	struct perf_cpu_map *merged = NULL;

	if (perf_cpu_map__is_subset(other, orig))
		return perf_cpu_map__get(orig);
	if (perf_cpu_map__is_subset(orig, other))
		return perf_cpu_map__get(other);

	tmp_len = max(orig->nr, other->nr);
	tmp_cpus = malloc(tmp_len * sizeof(struct perf_cpu));
	if (!tmp_cpus)
		return NULL;

	i = j = k = 0;
	while (i < orig->nr && j < other->nr) {
		if (orig->map[i].cpu < other->map[j].cpu)
			i++;
		else if (orig->map[i].cpu > other->map[j].cpu)
			j++;
		else {
			j++;
			tmp_cpus[k++] = orig->map[i++];
		}
	}
	if (k)
		merged = cpu_map__trim_new(k, tmp_cpus);
	free(tmp_cpus);
	return merged;
}
+2 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ struct perf_cpu_map {
#define MAX_NR_CPUS	2048
#endif

int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu);
int perf_cpu_map__idx(const struct perf_cpu_map *cpus, struct perf_cpu cpu);
bool perf_cpu_map__is_subset(const struct perf_cpu_map *a, const struct perf_cpu_map *b);

#endif /* __LIBPERF_INTERNAL_CPUMAP_H */
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig,
						     struct perf_cpu_map *other);
LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
							 struct perf_cpu_map *other);
LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
+11 −3
Original line number Diff line number Diff line
@@ -11,11 +11,16 @@

#include "arm-spe.h"
#include "hisi-ptt.h"
#include "../../../util/cpumap.h"
#include "../../../util/pmu.h"
#include "../../../util/cs-etm.h"
#include "../../arm64/util/mem-events.h"

struct perf_event_attr
*perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
*perf_pmu__get_default_config(struct perf_pmu *pmu)
{
	        struct perf_cpu_map *intersect;

#ifdef HAVE_AUXTRACE_SUPPORT
	if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) {
		/* add ETM default config here */
@@ -27,7 +32,10 @@ struct perf_event_attr
		pmu->selectable = true;
#endif
	}

#endif
	return NULL;
	/* Workaround some ARM PMU's failing to correctly set CPU maps for online processors. */
        intersect = perf_cpu_map__intersect(cpu_map__online(), pmu->cpus);
        perf_cpu_map__put(pmu->cpus);
        pmu->cpus = intersect;

}
+45 −0
Original line number Diff line number Diff line
@@ -135,3 +135,48 @@ int test__cpu_map_merge(struct test *test __maybe_unused, int subtest __maybe_un
	perf_cpu_map__put(c);
	return 0;
}

static int __test__cpu_map_intersect(const char *lhs, const char *rhs, int nr, const char *expected)
{
	struct perf_cpu_map *a = perf_cpu_map__new(lhs);
	struct perf_cpu_map *b = perf_cpu_map__new(rhs);
	struct perf_cpu_map *c = perf_cpu_map__intersect(a, b);
	char buf[100];

	TEST_ASSERT_EQUAL("failed to intersect map: bad nr", perf_cpu_map__nr(c), nr);
	cpu_map__snprint(c, buf, sizeof(buf));
	TEST_ASSERT_VAL("failed to intersect map: bad result", !strcmp(buf, expected));
	perf_cpu_map__put(a);
	perf_cpu_map__put(b);
	perf_cpu_map__put(c);
	return 0;
}

static int test__cpu_map_intersect(struct test_suite *test __maybe_unused,
				   int subtest __maybe_unused)
{
	int ret;

	ret = __test__cpu_map_intersect("4,2,1", "4,5,7", 1, "4");
	if (ret)
		return ret;
	ret = __test__cpu_map_intersect("1-8", "6-9", 3, "6-8");
	if (ret)
		return ret;
	ret = __test__cpu_map_intersect("1-8,12-20", "6-9,15", 4, "6-8,15");
	if (ret)
		return ret;
	ret = __test__cpu_map_intersect("4,2,1", "1", 1, "1");
	if (ret)
		return ret;
	ret = __test__cpu_map_intersect("1", "4,2,1", 1, "1");
	if (ret)
		return ret;
	ret = __test__cpu_map_intersect("1", "1", 1, "1");
	return ret;
}

DEFINE_SUITE("Synthesize cpu map", cpu_map_synthesize);
DEFINE_SUITE("Print cpu map", cpu_map_print);
DEFINE_SUITE("Merge cpu map", cpu_map_merge);
DEFINE_SUITE("Intersect cpu map", cpu_map_intersect);
Loading