Thread (9 messages) flat view 9 messages, 4 authors, 2015-05-04

Re: [RFC][PATCH 4/4] perf: Create aliases for PMU events

From: Vineet Gupta <hidden>
Date: 2015-05-02 07:04:25
Also in: lkml

On Friday 01 May 2015 12:35 PM, Sukadev Bhattiprolu wrote:=0A=
Using the tables of Power7 and Power8 events, create aliases for the=0A=
Power PMU events. This would allow us to specify all Power events by=0A=
name rather than by raw code:=0A=
=0A=
	$ /tmp/perf stat -e PM_1PLUS_PPC_CMPL sleep 1=0A=
=0A=
	 Performance counter stats for 'sleep 1':=0A=
=0A=
		   757,661      PM_1PLUS_PPC_CMPL=0A=
=0A=
	       1.001620145 seconds time elapsed=0A=
=0A=
The perf binary built on Power8 can be copied to Power7 and it will use=
=0A=
the Power7 events (if arch/powerpc/util/pmu-events.h knows the CPU string=
).=0A=
=0A=
Hopefully other architecutres can also implement arch_get_events_table()=
=0A=
and take advantage of this.=0A=
=0A=
Signed-off-by: Sukadev Bhattiprolu <redacted>=0A=
---=0A=
 tools/perf/arch/powerpc/util/Build        |    2 +-=0A=
 tools/perf/arch/powerpc/util/pmu-events.c |   52 +++++++++++++++++++=0A=
 tools/perf/arch/powerpc/util/pmu-events.h |   17 +++++++=0A=
 tools/perf/util/pmu.c                     |   77 +++++++++++++++++++++++=
++++++=0A=
quoted hunk ↗ jump to hunk
 tools/perf/util/pmu.h                     |   10 ++++=0A=
 5 files changed, 157 insertions(+), 1 deletion(-)=0A=
 create mode 100644 tools/perf/arch/powerpc/util/pmu-events.c=0A=
 create mode 100644 tools/perf/arch/powerpc/util/pmu-events.h=0A=
=0A=
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc=
/util/Build=0A=
quoted hunk ↗ jump to hunk
index 0af6e9b..52fbc7f 100644=0A=
--- a/tools/perf/arch/powerpc/util/Build=0A=
+++ b/tools/perf/arch/powerpc/util/Build=0A=
@@ -1,4 +1,4 @@=0A=
-libperf-y +=3D header.o=0A=
+libperf-y +=3D header.o pmu-events.o=0A=
 =0A=
 libperf-$(CONFIG_DWARF) +=3D dwarf-regs.o=0A=
 libperf-$(CONFIG_DWARF) +=3D skip-callchain-idx.o=0A=
diff --git a/tools/perf/arch/powerpc/util/pmu-events.c b/tools/perf/arch/=
powerpc/util/pmu-events.c=0A=
quoted hunk ↗ jump to hunk
new file mode 100644=0A=
index 0000000..7036f6d=0A=
--- /dev/null=0A=
+++ b/tools/perf/arch/powerpc/util/pmu-events.c=0A=
@@ -0,0 +1,52 @@=0A=
+#include <stdio.h>=0A=
+#include <unistd.h>=0A=
+#include <sys/types.h>=0A=
+#include "pmu.h"=0A=
+#include "pmu-events.h"=0A=
+#include "../../util/debug.h"			/* verbose */=0A=
+#include "header.h"				/* mfspr */=0A=
+=0A=
+static char *get_cpu_str(void)=0A=
+{=0A=
+	char *bufp;=0A=
+=0A=
+	if (asprintf(&bufp, "%.8lx-core", mfspr(SPRN_PVR)) < 0)=0A=
+		bufp =3D NULL;=0A=
+=0A=
+	return bufp;=0A=
+}=0A=
+=0A=
+struct perf_pmu_event *arch_get_events_table(char *cpustr)=0A=
+{=0A=
+	int i, nmaps, must_free;=0A=
+	struct  perf_pmu_event *table;=0A=
+=0A=
+	must_free =3D 0;=0A=
+	if (!cpustr) {=0A=
+		cpustr =3D get_cpu_str();=0A=
+		if (!cpustr)=0A=
+			return NULL;=0A=
+		must_free =3D 1;=0A=
+	}=0A=
+=0A=
+	nmaps =3D sizeof(pvr_events_map) / sizeof(struct pvr_events_map_entry);=
=0A=
quoted hunk ↗ jump to hunk
+=0A=
+	for (i =3D 0; i < nmaps; i++) {=0A=
+		if (!strcmp(pvr_events_map[i].pvr, cpustr))=0A=
+			break;=0A=
+	}=0A=
+=0A=
+	table =3D NULL;=0A=
+	if (i < nmaps) {=0A=
+		/* pvr_events_map is a const; cast to override */=0A=
+		table =3D (struct perf_pmu_event *)pvr_events_map[i].pmu_events;=0A=
+	} else if (verbose) {=0A=
+		printf("Unknown CPU %s, ignoring aliases\n", cpustr);=0A=
+	}=0A=
+=0A=
+	if (must_free)=0A=
+		free(cpustr);=0A=
+=0A=
+	return table;=0A=
+}=0A=
+=0A=
diff --git a/tools/perf/arch/powerpc/util/pmu-events.h b/tools/perf/arch/=
powerpc/util/pmu-events.h=0A=
quoted hunk ↗ jump to hunk
new file mode 100644=0A=
index 0000000..1daf8e5=0A=
--- /dev/null=0A=
+++ b/tools/perf/arch/powerpc/util/pmu-events.h=0A=
@@ -0,0 +1,17 @@=0A=
+/*=0A=
+ * Include all Power processor tables that we care about.=0A=
+ */=0A=
+#include "power7-events.h"=0A=
+#include "power8-events.h"=0A=
+=0A=
+/*=0A=
+ * Map a processor version (PVR) to its table of events.=0A=
+ */=0A=
+struct pvr_events_map_entry {=0A=
+	const char *pvr;=0A=
+	const struct perf_pmu_event *pmu_events;=0A=
+} pvr_events_map[] =3D {=0A=
+	{ .pvr =3D "004d0100-core",	.pmu_events =3D power8_pmu_events },=0A=
+	{ .pvr =3D "003f0201-core",	.pmu_events =3D power7_pmu_events }=0A=
+};=0A=
=0A=
Do u really need the header - this could go in the .c file ?=0A=
=0A=
quoted hunk ↗ jump to hunk
+=0A=
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c=0A=
index 4841167..f998d91 100644=0A=
--- a/tools/perf/util/pmu.c=0A=
+++ b/tools/perf/util/pmu.c=0A=
@@ -435,6 +435,80 @@ perf_pmu__get_default_config(struct perf_pmu *pmu __=
maybe_unused)=0A=
 	return NULL;=0A=
 }=0A=
 =0A=
+/*=0A=
+ * Default arch_get_events_table() is empty.=0A=
+ *=0A=
+ * Actual implementation is in arch/$(ARCH)/util/pmu-events.c. This=0A=
+ * allows architectures could choose what set(s) of events to a) include=
=0A=
+ * in perf binary b) consider for _this_ invocation of perf.=0A=
+ *=0A=
+ * Eg: For Power, we include both Power7 and Power8 event tables in the=
=0A=
+ * 	perf binary. But depending on the processor where perf is executed,=
=0A=
quoted hunk ↗ jump to hunk
+ * 	either the Power7 or Power8 table is returned.=0A=
+ */=0A=
+struct perf_pmu_event * __attribute__ ((weak))=0A=
+arch_get_events_table(char *cpustr __maybe_unused)=0A=
+{=0A=
+	return NULL;=0A=
+}=0A=
+=0A=
+static int pmu_add_cpu_aliases(char *cpustr, void *data)=0A=
+{=0A=
+	struct list_head *head =3D (struct list_head *)data;=0A=
+	struct perf_pmu_alias *alias;=0A=
+	int i;=0A=
+	struct perf_pmu_event *events_table, *event;=0A=
+	struct parse_events_term *term;=0A=
+=0A=
+	events_table =3D arch_get_events_table(cpustr);=0A=
+	if (!events_table)=0A=
+		return 0;=0A=
+=0A=
+	for (i =3D 0; events_table[i].name !=3D NULL; i++) {=0A=
+		event =3D &events_table[i];=0A=
+=0A=
+		alias =3D malloc(sizeof(*alias));=0A=
+		if (!alias)=0A=
+			return -ENOMEM;=0A=
+=0A=
+		term =3D malloc(sizeof(*term));=0A=
+		if (!term) {=0A=
+			/*=0A=
+			 * TODO: cleanup aliases allocated so far?=0A=
+			 */=0A=
+			free(alias);=0A=
+			return -ENOMEM;=0A=
+		}=0A=
+=0A=
+		/* ->config is not const; cast to override */=0A=
+		term->config =3D (char *)"event";=0A=
+		term->val.num =3D event->code;=0A=
+		term->type_val =3D PARSE_EVENTS__TERM_TYPE_NUM;=0A=
+		term->type_term =3D PARSE_EVENTS__TERM_TYPE_USER;=0A=
+		INIT_LIST_HEAD(&term->list);=0A=
+		term->used =3D 0;=0A=
+=0A=
+		INIT_LIST_HEAD(&alias->terms);=0A=
+		list_add_tail(&alias->terms, &term->list);=0A=
+=0A=
+		alias->scale =3D 1.0;=0A=
+		alias->unit[0] =3D '\0';=0A=
+		alias->per_pkg =3D false;=0A=
+=0A=
+		alias->name =3D strdup(event->name);=0A=
+#if 0=0A=
+		/*=0A=
+		 * TODO: Need Andi Kleen's patch for ->desc=0A=
+		 */=0A=
+		alias->desc =3D event->short_desc ?=0A=
+					strdup(event->short_desc) : NULL;=0A=
+#endif=0A=
+		list_add_tail(&alias->list, head);=0A=
+	}=0A=
+=0A=
+	return 0;=0A=
+}=0A=
+=0A=
 static struct perf_pmu *pmu_lookup(const char *name)=0A=
 {=0A=
 	struct perf_pmu *pmu;=0A=
@@ -453,6 +527,9 @@ static struct perf_pmu *pmu_lookup(const char *name)=
=0A=
quoted hunk ↗ jump to hunk
 	if (pmu_aliases(name, &aliases))=0A=
 		return NULL;=0A=
 =0A=
+	if (!strcmp(name, "cpu"))=0A=
+		(void)pmu_add_cpu_aliases(NULL, &aliases);=0A=
+=0A=
 	if (pmu_type(name, &type))=0A=
 		return NULL;=0A=
 =0A=
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h=0A=
index 6b1249f..ca3e7a0 100644=0A=
--- a/tools/perf/util/pmu.h=0A=
+++ b/tools/perf/util/pmu.h=0A=
@@ -45,6 +45,14 @@ struct perf_pmu_alias {=0A=
 	bool snapshot;=0A=
 };=0A=
 =0A=
+struct perf_pmu_event {=0A=
+	const char *name;=0A=
+	const unsigned long code;=0A=
+	const char *short_desc;=0A=
+	const char *long_desc;=0A=
+	/* add unit, mask etc as needed here */=0A=
+};=0A=
+=0A=
 struct perf_pmu *perf_pmu__find(const char *name);=0A=
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,=
=0A=
quoted hunk ↗ jump to hunk
 		     struct list_head *head_terms);=0A=
@@ -76,4 +84,6 @@ int perf_pmu__test(void);=0A=
 =0A=
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pm=
u);=0A=
 =0A=
+struct perf_pmu_event *arch_get_events_table(char *cpustr);=0A=
+=0A=
 #endif /* __PMU_H */=0A=
=0A=
=0A=
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help