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

perf pmu-events: Add separate metric from pmu_event



Create a new pmu_metric for the metric related variables from pmu_event
but that is initially just a clone of pmu_event. Add iterators for
pmu_metric and use in places that metrics are desired rather than
events. Make the event iterator skip metric only events, and the metric
iterator skip event only events.

Reviewed-by: default avatarJohn Garry <john.g.garry@oracle.com>
Reviewed-by: default avatarKajol Jain <kjain@linux.ibm.com>
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: Caleb Biggers <caleb.biggers@intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jing Zhang <renyu.zj@linux.alibaba.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Kang Minchul <tegongkang@gmail.com>
Cc: Kim Phillips <kim.phillips@amd.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: Perry Taylor <perry.taylor@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Sandipan Das <sandipan.das@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
Cc: linuxppc-dev@lists.ozlabs.org
Link: https://lore.kernel.org/r/20230126233645.200509-5-irogers@google.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent df5499dd
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -40,11 +40,11 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
	return bufp;
}

int arch_get_runtimeparam(const struct pmu_event *pe)
int arch_get_runtimeparam(const struct pmu_metric *pm)
{
	int count;
	char path[PATH_MAX] = "/devices/hv_24x7/interface/";

	atoi(pe->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
	atoi(pm->aggr_mode) == PerChip ? strcat(path, "sockets") : strcat(path, "coresperchip");
	return sysfs__read_int(path, &count) < 0 ? 1 : count;
}
+44 −5
Original line number Diff line number Diff line
@@ -181,6 +181,11 @@ struct pmu_events_table {
	const struct pmu_event *entries;
};

/* Struct used to make the PMU metric table implementation opaque to callers. */
struct pmu_metrics_table {
	const struct pmu_metric *entries;
};

/*
 * 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.
@@ -254,11 +259,29 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
				    void *data)
{
	for (const struct pmu_event *pe = &table->entries[0];
	     pe->name || pe->metric_group || pe->metric_name;
	     pe++) {
		int ret = fn(pe, table, data);
	for (const struct pmu_event *pe = &table->entries[0]; pe->name || pe->metric_expr; pe++) {
		int ret;

		if (!pe->name)
			continue;
		ret = fn(pe, table, data);
		if (ret)
			return ret;
	}
	return 0;
}

int pmu_events_table_for_each_metric(const struct pmu_events_table *etable, pmu_metric_iter_fn fn,
				     void *data)
{
	struct pmu_metrics_table *table = (struct pmu_metrics_table *)etable;

	for (const struct pmu_metric *pm = &table->entries[0]; pm->name || pm->metric_expr; pm++) {
		int ret;

		if (!pm->metric_expr)
			continue;
		ret = fn(pm, etable, data);
		if (ret)
			return ret;
	}
@@ -305,11 +328,22 @@ const struct pmu_events_table *find_core_events_table(const char *arch, const ch
}

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->arch; tables++) {
		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);

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

int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
{
	for (const struct pmu_events_map *tables = &pmu_events_map[0];
	     tables->arch;
	     tables++) {
		int ret = pmu_events_table_for_each_event(&tables->table, fn, data);
		int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);

		if (ret)
			return ret;
@@ -340,3 +374,8 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
	}
	return 0;
}

int pmu_for_each_sys_metric(pmu_metric_iter_fn fn __maybe_unused, void *data __maybe_unused)
{
	return 0;
}
+60 −2
Original line number Diff line number Diff line
@@ -564,7 +564,19 @@ static const struct pmu_sys_events pmu_sys_event_tables[] = {
\t},
};

static void decompress(int offset, struct pmu_event *pe)
static void decompress_event(int offset, struct pmu_event *pe)
{
\tconst char *p = &big_c_string[offset];
""")
  for attr in _json_event_attributes:
    _args.output_file.write(f"""
\tpe->{attr} = (*p == '\\0' ? NULL : p);
""")
    if attr == _json_event_attributes[-1]:
      continue
    _args.output_file.write('\twhile (*p++);')
  _args.output_file.write("""}
static void decompress_metric(int offset, struct pmu_metric *pe)
{
\tconst char *p = &big_c_string[offset];
""")
@@ -585,7 +597,9 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
                struct pmu_event pe;
                int ret;

                decompress(table->entries[i].offset, &pe);
                decompress_event(table->entries[i].offset, &pe);
                if (!pe.name)
                        continue;
                ret = fn(&pe, table, data);
                if (ret)
                        return ret;
@@ -593,6 +607,24 @@ int pmu_events_table_for_each_event(const struct pmu_events_table *table,
        return 0;
}

int pmu_events_table_for_each_metric(const struct pmu_events_table *table,
                                     pmu_metric_iter_fn fn,
                                     void *data)
{
        for (size_t i = 0; i < table->length; i++) {
                struct pmu_metric pm;
                int ret;

                decompress_metric(table->entries[i].offset, &pm);
                if (!pm.metric_expr)
                        continue;
                ret = fn(&pm, table, data);
                if (ret)
                        return ret;
        }
        return 0;
}

const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu)
{
        const struct pmu_events_table *table = NULL;
@@ -644,6 +676,19 @@ int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data)
        return 0;
}

int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data)
{
        for (const struct pmu_events_map *tables = &pmu_events_map[0];
             tables->arch;
             tables++) {
                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);

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

const struct pmu_events_table *find_sys_events_table(const char *name)
{
        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
@@ -667,6 +712,19 @@ int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data)
        }
        return 0;
}

int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data)
{
        for (const struct pmu_sys_events *tables = &pmu_sys_event_tables[0];
             tables->name;
             tables++) {
                int ret = pmu_events_table_for_each_metric(&tables->table, fn, data);

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


+26 −0
Original line number Diff line number Diff line
@@ -30,20 +30,46 @@ struct pmu_event {
	const char *metric_constraint;
};

struct pmu_metric {
	const char *name;
	const char *compat;
	const char *event;
	const char *desc;
	const char *topic;
	const char *long_desc;
	const char *pmu;
	const char *unit;
	const char *perpkg;
	const char *aggr_mode;
	const char *metric_expr;
	const char *metric_name;
	const char *metric_group;
	const char *deprecated;
	const char *metric_constraint;
};

struct pmu_events_table;

typedef int (*pmu_event_iter_fn)(const struct pmu_event *pe,
				 const struct pmu_events_table *table,
				 void *data);

typedef int (*pmu_metric_iter_fn)(const struct pmu_metric *pm,
				  const struct pmu_events_table *table,
				  void *data);

int pmu_events_table_for_each_event(const struct pmu_events_table *table, pmu_event_iter_fn fn,
				    void *data);
int pmu_events_table_for_each_metric(const struct pmu_events_table *table, pmu_metric_iter_fn fn,
				     void *data);

const struct pmu_events_table *perf_pmu__find_table(struct perf_pmu *pmu);
const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid);
int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data);
int pmu_for_each_core_metric(pmu_metric_iter_fn fn, void *data);

const struct pmu_events_table *find_sys_events_table(const char *name);
int pmu_for_each_sys_event(pmu_event_iter_fn fn, void *data);
int pmu_for_each_sys_metric(pmu_metric_iter_fn fn, void *data);

#endif
+16 −19
Original line number Diff line number Diff line
@@ -840,7 +840,7 @@ struct metric {
	struct metric_ref metric_ref;
};

static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_events_table *table,
static int test__parsing_callback(const struct pmu_metric *pm, const struct pmu_events_table *table,
				  void *data)
{
	int *failures = data;
@@ -854,10 +854,10 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
	};
	int err = 0;

	if (!pe->metric_expr)
	if (!pm->metric_expr)
		return 0;

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

	/*
@@ -877,14 +877,14 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
	perf_evlist__set_maps(&evlist->core, cpus, NULL);
	runtime_stat__init(&st);

	err = metricgroup__parse_groups_test(evlist, table, pe->metric_name,
	err = metricgroup__parse_groups_test(evlist, table, pm->metric_name,
					     false, false,
					     &metric_events);
	if (err) {
		if (!strcmp(pe->metric_name, "M1") || !strcmp(pe->metric_name, "M2") ||
		    !strcmp(pe->metric_name, "M3")) {
		if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
		    !strcmp(pm->metric_name, "M3")) {
			(*failures)--;
			pr_debug("Expected broken metric %s skipping\n", pe->metric_name);
			pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
			err = 0;
		}
		goto out_err;
@@ -912,7 +912,7 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
			struct metric_expr *mexp;

			list_for_each_entry (mexp, &me->head, nd) {
				if (strcmp(mexp->metric_name, pe->metric_name))
				if (strcmp(mexp->metric_name, pm->metric_name))
					continue;
				pr_debug("Result %f\n", test_generic_metric(mexp, 0, &st));
				err = 0;
@@ -921,11 +921,11 @@ static int test__parsing_callback(const struct pmu_event *pe, const struct pmu_e
			}
		}
	}
	pr_debug("Didn't find parsed metric %s", pe->metric_name);
	pr_debug("Didn't find parsed metric %s", pm->metric_name);
	err = 1;
out_err:
	if (err)
		pr_debug("Broken metric %s\n", pe->metric_name);
		pr_debug("Broken metric %s\n", pm->metric_name);

	/* ... cleanup. */
	metricgroup__rblist_exit(&metric_events);
@@ -941,8 +941,8 @@ static int test__parsing(struct test_suite *test __maybe_unused,
{
	int failures = 0;

	pmu_for_each_core_event(test__parsing_callback, &failures);
	pmu_for_each_sys_event(test__parsing_callback, &failures);
	pmu_for_each_core_metric(test__parsing_callback, &failures);
	pmu_for_each_sys_metric(test__parsing_callback, &failures);

	return failures == 0 ? TEST_OK : TEST_FAIL;
}
@@ -1021,14 +1021,11 @@ static int metric_parse_fake(const char *metric_name, const char *str)
	return ret;
}

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

	return metric_parse_fake(pe->metric_name, pe->metric_expr);
	return metric_parse_fake(pm->metric_name, pm->metric_expr);
}

/*
@@ -1047,11 +1044,11 @@ static int test__parsing_fake(struct test_suite *test __maybe_unused,
			return err;
	}

	err = pmu_for_each_core_event(test__parsing_fake_callback, NULL);
	err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
	if (err)
		return err;

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

static struct test_case pmu_events_tests[] = {
Loading