Commit 29be2fe0 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

perf pmu-events: Hide pmu_events_map



Move usage of the table to pmu-events.c so it may be hidden. By
abstracting the table the implementation can later be changed.

Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Will Deacon <will@kernel.org>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20220812230949.683239-8-irogers@google.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent eeac7730
Loading
Loading
Loading
Loading
+79 −2
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
 * The test cpu/soc is provided for testing.
 */
#include "pmu-events/pmu-events.h"
#include "util/header.h"
#include "util/pmu.h"
#include <string.h>
#include <stddef.h>

@@ -110,7 +112,26 @@ static const struct pmu_event pme_test_soc_cpu[] = {
	},
};

const struct pmu_events_map pmu_events_map[] = {

/*
 * Map a CPU to its table of PMU events. The CPU is identified by the
 * cpuid field, which is an arch-specific identifier for the CPU.
 * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
 * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
 *
 * The  cpuid can contain any character other than the comma.
 */
struct pmu_events_map {
	const char *arch;
	const char *cpuid;
	const struct pmu_event *table;
};

/*
 * Global table mapping each known CPU for the architecture to its
 * table of PMU events.
 */
static const struct pmu_events_map pmu_events_map[] = {
	{
		.arch = "testarch",
		.cpuid = "testcpu",
@@ -162,6 +183,62 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
	},
};

const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
{
	const struct pmu_event *table = NULL;
	char *cpuid = perf_pmu__getcpuid(pmu);
	int i;

	/* on some platforms which uses cpus map, cpuid can be NULL for
	 * PMUs other than CORE PMUs.
	 */
	if (!cpuid)
		return NULL;

	i = 0;
	for (;;) {
		const struct pmu_events_map *map = &pmu_events_map[i++];

		if (!map->table)
			break;

		if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
			table = map->table;
			break;
		}
	}
	free(cpuid);
	return table;
}

const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
{
	for (const struct pmu_events_map *tables = &pmu_events_map[0];
	     tables->table;
	     tables++) {
		if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
			return tables->table;
	}
	return NULL;
}

int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
{
	for (const struct pmu_events_map *tables = &pmu_events_map[0];
	     tables->table;
	     tables++) {
		for (const struct pmu_event *pe = &tables->table[0];
		     pe->name || pe->metric_group || pe->metric_name;
		     pe++) {
			int ret = fn(pe, &tables->table[0], data);

			if (ret)
				return ret;
		}
	}
	return 0;
}

const struct pmu_event *find_sys_events_table(const char *name)
{
	for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -181,7 +258,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
		for (const struct pmu_event *pe = &tables->table[0];
		     pe->name || pe->metric_group || pe->metric_name;
		     pe++) {
			int ret = fn(pe, data);
			int ret = fn(pe, &tables->table[0], data);

			if (ret)
				return ret;
+79 −2
Original line number Diff line number Diff line
@@ -334,7 +334,27 @@ def process_one_file(parents: Sequence[str], item: os.DirEntry) -> None:

def print_mapping_table(archs: Sequence[str]) -> None:
  """Read the mapfile and generate the struct from cpuid string to event table."""
  _args.output_file.write('const struct pmu_events_map pmu_events_map[] = {\n')
  _args.output_file.write("""
/*
 * Map a CPU to its table of PMU events. The CPU is identified by the
 * cpuid field, which is an arch-specific identifier for the CPU.
 * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
 * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
 *
 * The  cpuid can contain any character other than the comma.
 */
struct pmu_events_map {
        const char *arch;
        const char *cpuid;
        const struct pmu_event *table;
};

/*
 * Global table mapping each known CPU for the architecture to its
 * table of PMU events.
 */
const struct pmu_events_map pmu_events_map[] = {
""")
  for arch in archs:
    if arch == 'test':
      _args.output_file.write("""{
@@ -390,6 +410,61 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
\t},
};

const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu)
{
        const struct pmu_event *table = NULL;
        char *cpuid = perf_pmu__getcpuid(pmu);
        int i;

        /* on some platforms which uses cpus map, cpuid can be NULL for
         * PMUs other than CORE PMUs.
         */
        if (!cpuid)
                return NULL;

        i = 0;
        for (;;) {
                const struct pmu_events_map *map = &pmu_events_map[i++];
                if (!map->table)
                        break;

                if (!strcmp_cpuid_str(map->cpuid, cpuid)) {
                        table = map->table;
                        break;
                }
        }
        free(cpuid);
        return table;
}

const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid)
{
        for (const struct pmu_events_map *tables = &pmu_events_map[0];
             tables->table;
             tables++) {
                if (!strcmp(tables->arch, arch) && !strcmp_cpuid_str(tables->cpuid, cpuid))
                        return tables->table;
        }
        return NULL;
}

int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
{
        for (const struct pmu_events_map *tables = &pmu_events_map[0];
             tables->table;
             tables++) {
                for (const struct pmu_event *pe = &tables->table[0];
                     pe->name || pe->metric_group || pe->metric_name;
                     pe++) {
                        int ret = fn(pe, &tables->table[0], data);

                        if (ret)
                                return ret;
                }
        }
        return 0;
}

const struct pmu_event *find_sys_events_table(const char *name)
{
        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -409,7 +484,7 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
                for (const struct pmu_event *pe = &tables->table[0];
                     pe->name || pe->metric_group || pe->metric_name;
                     pe++) {
                        int ret = fn(pe, data);
                        int ret = fn(pe, &tables->table[0], data);

                        if (ret)
                                return ret;
@@ -450,6 +525,8 @@ def main() -> None:

  _args.output_file.write("""
#include "pmu-events/pmu-events.h"
#include "util/header.h"
#include "util/pmu.h"
#include <string.h>
#include <stddef.h>

+8 −21
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
#ifndef PMU_EVENTS_H
#define PMU_EVENTS_H

struct perf_pmu;

enum aggr_mode_class {
	PerChip = 1,
	PerCore
@@ -28,30 +30,15 @@ struct pmu_event {
	const char *metric_constraint;
};

/*
 *
 * Map a CPU to its table of PMU events. The CPU is identified by the
 * cpuid field, which is an arch-specific identifier for the CPU.
 * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
 * must match the get_cpuid_str() in tools/perf/arch/xxx/util/header.c)
 *
 * The  cpuid can contain any character other than the comma.
 */
struct pmu_events_map {
	const char *arch;
	const char *cpuid;
	const struct pmu_event *table;
};
typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
				 const struct pmu_event *table,
				 void *data);

/*
 * Global table mapping each known CPU for the architecture to its
 * table of PMU events.
 */
extern const struct pmu_events_map pmu_events_map[];
const struct pmu_event *perf_pmu__find_table(struct perf_pmu *pmu);
const struct pmu_event *find_core_events_table(const char *arch, const char *cpuid);
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);

const struct pmu_event *find_sys_events_table(const char *name);

typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe, void *data);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);

#endif
+100 −118
Original line number Diff line number Diff line
@@ -272,18 +272,6 @@ static bool is_same(const char *reference, const char *test)
	return !strcmp(reference, test);
}

static const struct pmu_event *__test_pmu_get_events_table(void)
{
	for (const struct pmu_events_map *map = &pmu_events_map[0]; map->cpuid; map++) {
		if (!strcmp(map->cpuid, "testcpu"))
			return map->table;
	}

	pr_err("could not find test events map\n");

	return NULL;
}

static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
{
	if (!is_same(e1->name, e2->name)) {
@@ -438,7 +426,7 @@ static int test__pmu_event_table(struct test_suite *test __maybe_unused,
				 int subtest __maybe_unused)
{
	const struct pmu_event *sys_event_tables = find_sys_events_table("pme_test_soc_sys");
	const struct pmu_event *table = __test_pmu_get_events_table();
	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
	int map_events = 0, expected_events;

	/* ignore 3x sentinels */
@@ -534,7 +522,7 @@ static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
	struct perf_pmu *pmu;
	LIST_HEAD(aliases);
	int res = 0;
	const struct pmu_event *table = __test_pmu_get_events_table();
	const struct pmu_event *table = find_core_events_table("testarch", "testcpu");
	struct perf_pmu_alias *a, *tmp;

	if (!table)
@@ -591,7 +579,7 @@ static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
	LIST_HEAD(aliases);
	int res = 0;

	events_table = __test_pmu_get_events_table();
	events_table = find_core_events_table("testarch", "testcpu");
	if (!events_table)
		return -1;
	pmu_add_cpu_aliases_table(&aliases, pmu, events_table);
@@ -845,11 +833,6 @@ static int check_parse_fake(const char *id)
	return ret;
}

static void expr_failure(const char *msg, const struct pmu_event *pe)
{
	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
}

struct metric {
	struct list_head list;
	struct metric_ref metric_ref;
@@ -915,93 +898,100 @@ static int resolve_metric_simple(struct expr_parse_ctx *pctx,

}

static int test__parsing(struct test_suite *test __maybe_unused,
			 int subtest __maybe_unused)
static void expr_failure(const char *msg, const struct pmu_event *pe)
{
	const struct pmu_event *cpus_table = pmu_events_table__find();
	const struct pmu_event *pe;
	int i, j, k;
	int ret = 0;
	struct expr_parse_ctx *ctx;
	double result;

	ctx = expr__ctx_new();
	if (!ctx) {
		pr_debug("expr__ctx_new failed");
		return TEST_FAIL;
	pr_debug("%s\nOn metric %s\nOn expression %s\n", msg, pe->metric_name, pe->metric_expr);
}
	i = 0;
	for (;;) {
		const struct pmu_events_map *map = &pmu_events_map[i++];

		if (!map->table)
			break;
		j = 0;
		for (;;) {

struct test__parsing_data {
	const struct pmu_event *cpus_table;
	struct expr_parse_ctx *ctx;
	int failures;
};

static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_event *table,
				  void *vdata)
{
	struct test__parsing_data *data = vdata;
	struct metric *metric, *tmp;
	struct hashmap_entry *cur;
	LIST_HEAD(compound_list);
	size_t bkt;
	int k;
	double result;

			pe = &map->table[j++];
			if (!pe->name && !pe->metric_group && !pe->metric_name)
				break;
	if (!pe->metric_expr)
				continue;
			expr__ctx_clear(ctx);
			if (expr__find_ids(pe->metric_expr, NULL, ctx) < 0) {
		return 0;

	pr_debug("Found metric '%s'\n", pe->metric_name);

	expr__ctx_clear(data->ctx);
	if (expr__find_ids(pe->metric_expr, NULL, data->ctx) < 0) {
		expr_failure("Parse find ids failed", pe);
				ret++;
				continue;
		data->failures++;
		return 0;
	}

			if (resolve_metric_simple(ctx, &compound_list, map->table,
	if (resolve_metric_simple(data->ctx, &compound_list, table,
				  pe->metric_name)) {
		expr_failure("Could not resolve metrics", pe);
				ret++;
				goto exit; /* Don't tolerate errors due to severity */
		data->failures++;
		return TEST_FAIL; /* Don't tolerate errors due to severity */
	}

	/*
			 * Add all ids with a made up value. The value may
			 * trigger divide by zero when subtracted and so try to
			 * make them unique.
	 * Add all ids with a made up value. The value may trigger divide by
	 * zero when subtracted and so try to make them unique.
	 */
	k = 1;
			hashmap__for_each_entry(ctx->ids, cur, bkt)
				expr__add_id_val(ctx, strdup(cur->key), k++);
	hashmap__for_each_entry(data->ctx->ids, cur, bkt)
		expr__add_id_val(data->ctx, strdup(cur->key), k++);

			hashmap__for_each_entry(ctx->ids, cur, bkt) {
				if (check_parse_cpu(cur->key, map->table == cpus_table,
						   pe))
					ret++;
	hashmap__for_each_entry(data->ctx->ids, cur, bkt) {
		if (check_parse_cpu(cur->key, table == data->cpus_table, pe))
			data->failures++;
	}

	list_for_each_entry_safe(metric, tmp, &compound_list, list) {
				expr__add_ref(ctx, &metric->metric_ref);
		expr__add_ref(data->ctx, &metric->metric_ref);
		free(metric);
	}

			if (expr__parse(&result, ctx, pe->metric_expr)) {
	if (expr__parse(&result, data->ctx, pe->metric_expr)) {
		/*
				 * Parsing failed, make numbers go from large to
				 * small which can resolve divide by zero
				 * issues.
		 * Parsing failed, make numbers go from large to small which can
		 * resolve divide by zero issues.
		 */
		k = 1024;
				hashmap__for_each_entry(ctx->ids, cur, bkt)
					expr__add_id_val(ctx, strdup(cur->key), k--);
				if (expr__parse(&result, ctx, pe->metric_expr)) {
		hashmap__for_each_entry(data->ctx->ids, cur, bkt)
			expr__add_id_val(data->ctx, strdup(cur->key), k--);
		if (expr__parse(&result, data->ctx, pe->metric_expr)) {
			expr_failure("Parse failed", pe);
					ret++;
			data->failures++;
		}
	}
	return 0;
}

static int test__parsing(struct test_suite *test __maybe_unused,
			 int subtest __maybe_unused)
{
	struct test__parsing_data data = {
		.cpus_table = pmu_events_table__find(),
		.ctx = expr__ctx_new(),
		.failures = 0,
	};

	if (!data.ctx) {
		pr_debug("expr__ctx_new failed");
		return TEST_FAIL;
	}
	expr__ctx_free(ctx);
	/* TODO: fail when not ok */
exit:
	return ret == 0 ? TEST_OK : TEST_SKIP;
	pmu_for_each_core_event(test__parsing_callback, &data);
	pmu_for_each_sys_event(test__parsing_callback, &data);

	expr__ctx_free(data.ctx);
	return data.failures == 0 ? TEST_OK : TEST_FAIL;
}

struct test_metric {
@@ -1073,6 +1063,16 @@ static int metric_parse_fake(const char *str)
	return ret;
}

static int test__parsing_fake_callback(const struct pmu_event *pe,
				       const struct pmu_event *table __maybe_unused,
				       void *data __maybe_unused)
{
	if (!pe->metric_expr)
		return 0;

	return metric_parse_fake(pe->metric_expr);
}

/*
 * Parse all the metrics for current architecture,
 * or all defined cpus via the 'fake_pmu'
@@ -1081,37 +1081,19 @@ static int metric_parse_fake(const char *str)
static int test__parsing_fake(struct test_suite *test __maybe_unused,
			      int subtest __maybe_unused)
{
	unsigned int i, j;
	int err = 0;

	for (i = 0; i < ARRAY_SIZE(metrics); i++) {
	for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
		err = metric_parse_fake(metrics[i].str);
		if (err)
			return err;
	}

	i = 0;
	for (;;) {
		const struct pmu_events_map *map = &pmu_events_map[i++];

		if (!map->table)
			break;
		j = 0;
		for (;;) {
			const struct pmu_event *pe = &map->table[j++];

			if (!pe->name && !pe->metric_group && !pe->metric_name)
				break;
			if (!pe->metric_expr)
				continue;
			pr_debug("Found metric '%s' for '%s'\n", pe->metric_name, map->cpuid);
			err = metric_parse_fake(pe->metric_expr);
	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
	if (err)
		return err;
		}
	}

	return 0;
	return pmu_for_each_sys_event(test__parsing_fake_callback, NULL);
}

static struct test_case pmu_events_tests[] = {
+9 −6
Original line number Diff line number Diff line
@@ -502,14 +502,14 @@ struct metricgroup_print_sys_idata {
	bool details;
};

typedef int (*metricgroup_sys_event_iter_fn)(const struct pmu_event *pe, void *);

struct metricgroup_iter_data {
	metricgroup_sys_event_iter_fn fn;
	pmu_event_iter_fn fn;
	void *data;
};

static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
static int metricgroup__sys_event_iter(const struct pmu_event *pe,
				       const struct pmu_event *table __maybe_unused,
				       void *data)
{
	struct metricgroup_iter_data *d = data;
	struct perf_pmu *pmu = NULL;
@@ -522,13 +522,15 @@ static int metricgroup__sys_event_iter(const struct pmu_event *pe, void *data)
		if (!pmu->id || strcmp(pmu->id, pe->compat))
			continue;

		return d->fn(pe, d->data);
		return d->fn(pe, table, d->data);
	}

	return 0;
}

static int metricgroup__print_sys_event_iter(const struct pmu_event *pe, void *data)
static int metricgroup__print_sys_event_iter(const struct pmu_event *pe,
					     const struct pmu_event *table __maybe_unused,
					     void *data)
{
	struct metricgroup_print_sys_idata *d = data;

@@ -1101,6 +1103,7 @@ static int add_metric(struct list_head *metric_list,
}

static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
						  const struct pmu_event *table __maybe_unused,
						  void *data)
{
	struct metricgroup_add_iter_data *d = data;
Loading