| /* |
| * 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"); |
| } |