|
@@ -0,0 +1,114 @@
|
|
|
+/*
|
|
|
+ * Copyright 2014, Michael Ellerman, IBM Corp.
|
|
|
+ * Licensed under GPLv2.
|
|
|
+ */
|
|
|
+
|
|
|
+#define _GNU_SOURCE
|
|
|
+
|
|
|
+#include <elf.h>
|
|
|
+#include <limits.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdbool.h>
|
|
|
+#include <string.h>
|
|
|
+#include <sys/prctl.h>
|
|
|
+
|
|
|
+#include "event.h"
|
|
|
+#include "lib.h"
|
|
|
+#include "utils.h"
|
|
|
+
|
|
|
+/*
|
|
|
+ * Test that per-event excludes work.
|
|
|
+ */
|
|
|
+
|
|
|
+static int per_event_excludes(void)
|
|
|
+{
|
|
|
+ struct event *e, events[4];
|
|
|
+ char *platform;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
|
|
|
+ FAIL_IF(!platform);
|
|
|
+ SKIP_IF(strcmp(platform, "power8") != 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We need to create the events disabled, otherwise the running/enabled
|
|
|
+ * counts don't match up.
|
|
|
+ */
|
|
|
+ e = &events[0];
|
|
|
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
|
|
|
+ PERF_TYPE_HARDWARE, "instructions");
|
|
|
+ e->attr.disabled = 1;
|
|
|
+
|
|
|
+ e = &events[1];
|
|
|
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
|
|
|
+ PERF_TYPE_HARDWARE, "instructions(k)");
|
|
|
+ e->attr.disabled = 1;
|
|
|
+ e->attr.exclude_user = 1;
|
|
|
+ e->attr.exclude_hv = 1;
|
|
|
+
|
|
|
+ e = &events[2];
|
|
|
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
|
|
|
+ PERF_TYPE_HARDWARE, "instructions(h)");
|
|
|
+ e->attr.disabled = 1;
|
|
|
+ e->attr.exclude_user = 1;
|
|
|
+ e->attr.exclude_kernel = 1;
|
|
|
+
|
|
|
+ e = &events[3];
|
|
|
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
|
|
|
+ PERF_TYPE_HARDWARE, "instructions(u)");
|
|
|
+ e->attr.disabled = 1;
|
|
|
+ e->attr.exclude_hv = 1;
|
|
|
+ e->attr.exclude_kernel = 1;
|
|
|
+
|
|
|
+ FAIL_IF(event_open(&events[0]));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The open here will fail if we don't have per event exclude support,
|
|
|
+ * because the second event has an incompatible set of exclude settings
|
|
|
+ * and we're asking for the events to be in a group.
|
|
|
+ */
|
|
|
+ for (i = 1; i < 4; i++)
|
|
|
+ FAIL_IF(event_open_with_group(&events[i], events[0].fd));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Even though the above will fail without per-event excludes we keep
|
|
|
+ * testing in order to be thorough.
|
|
|
+ */
|
|
|
+ prctl(PR_TASK_PERF_EVENTS_ENABLE);
|
|
|
+
|
|
|
+ /* Spin for a while */
|
|
|
+ for (i = 0; i < INT_MAX; i++)
|
|
|
+ asm volatile("" : : : "memory");
|
|
|
+
|
|
|
+ prctl(PR_TASK_PERF_EVENTS_DISABLE);
|
|
|
+
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
+ FAIL_IF(event_read(&events[i]));
|
|
|
+ event_report(&events[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We should see that all events have enabled == running. That
|
|
|
+ * shows that they were all on the PMU at once.
|
|
|
+ */
|
|
|
+ for (i = 0; i < 4; i++)
|
|
|
+ FAIL_IF(events[i].result.running != events[i].result.enabled);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We can also check that the result for instructions is >= all the
|
|
|
+ * other counts. That's because it is counting all instructions while
|
|
|
+ * the others are counting a subset.
|
|
|
+ */
|
|
|
+ for (i = 1; i < 4; i++)
|
|
|
+ FAIL_IF(events[0].result.value < events[i].result.value);
|
|
|
+
|
|
|
+ for (i = 0; i < 4; i++)
|
|
|
+ event_close(&events[i]);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int main(void)
|
|
|
+{
|
|
|
+ return test_harness(per_event_excludes, "per_event_excludes");
|
|
|
+}
|