| // SPDX-License-Identifier: GPL-2.0-only | 
| /* | 
|  * Copyright 2014, Michael Ellerman, IBM Corp. | 
|  */ | 
|   | 
| #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]; | 
|     int i; | 
|   | 
|     SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07)); | 
|   | 
|     /* | 
|      * 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"); | 
| } |