1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2014, Michael Ellerman, IBM Corp. |
4 | */ |
5 | |
6 | #define _GNU_SOURCE |
7 | |
8 | #include <elf.h> |
9 | #include <limits.h> |
10 | #include <stdio.h> |
11 | #include <stdbool.h> |
12 | #include <string.h> |
13 | #include <sys/prctl.h> |
14 | |
15 | #include "event.h" |
16 | #include "lib.h" |
17 | #include "utils.h" |
18 | |
19 | /* |
20 | * Test that per-event excludes work. |
21 | */ |
22 | |
23 | static int per_event_excludes(void) |
24 | { |
25 | struct event *e, events[4]; |
26 | int i; |
27 | |
28 | SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_2_07)); |
29 | |
30 | /* |
31 | * We need to create the events disabled, otherwise the running/enabled |
32 | * counts don't match up. |
33 | */ |
34 | e = &events[0]; |
35 | event_init_opts(e, config: PERF_COUNT_HW_INSTRUCTIONS, |
36 | type: PERF_TYPE_HARDWARE, name: "instructions" ); |
37 | e->attr.disabled = 1; |
38 | |
39 | e = &events[1]; |
40 | event_init_opts(e, config: PERF_COUNT_HW_INSTRUCTIONS, |
41 | type: PERF_TYPE_HARDWARE, name: "instructions(k)" ); |
42 | e->attr.disabled = 1; |
43 | e->attr.exclude_user = 1; |
44 | e->attr.exclude_hv = 1; |
45 | |
46 | e = &events[2]; |
47 | event_init_opts(e, config: PERF_COUNT_HW_INSTRUCTIONS, |
48 | type: PERF_TYPE_HARDWARE, name: "instructions(h)" ); |
49 | e->attr.disabled = 1; |
50 | e->attr.exclude_user = 1; |
51 | e->attr.exclude_kernel = 1; |
52 | |
53 | e = &events[3]; |
54 | event_init_opts(e, config: PERF_COUNT_HW_INSTRUCTIONS, |
55 | type: PERF_TYPE_HARDWARE, name: "instructions(u)" ); |
56 | e->attr.disabled = 1; |
57 | e->attr.exclude_hv = 1; |
58 | e->attr.exclude_kernel = 1; |
59 | |
60 | FAIL_IF(event_open(e: &events[0])); |
61 | |
62 | /* |
63 | * The open here will fail if we don't have per event exclude support, |
64 | * because the second event has an incompatible set of exclude settings |
65 | * and we're asking for the events to be in a group. |
66 | */ |
67 | for (i = 1; i < 4; i++) |
68 | FAIL_IF(event_open_with_group(e: &events[i], group_fd: events[0].fd)); |
69 | |
70 | /* |
71 | * Even though the above will fail without per-event excludes we keep |
72 | * testing in order to be thorough. |
73 | */ |
74 | prctl(PR_TASK_PERF_EVENTS_ENABLE); |
75 | |
76 | /* Spin for a while */ |
77 | for (i = 0; i < INT_MAX; i++) |
78 | asm volatile("" : : : "memory" ); |
79 | |
80 | prctl(PR_TASK_PERF_EVENTS_DISABLE); |
81 | |
82 | for (i = 0; i < 4; i++) { |
83 | FAIL_IF(event_read(e: &events[i])); |
84 | event_report(e: &events[i]); |
85 | } |
86 | |
87 | /* |
88 | * We should see that all events have enabled == running. That |
89 | * shows that they were all on the PMU at once. |
90 | */ |
91 | for (i = 0; i < 4; i++) |
92 | FAIL_IF(events[i].result.running != events[i].result.enabled); |
93 | |
94 | /* |
95 | * We can also check that the result for instructions is >= all the |
96 | * other counts. That's because it is counting all instructions while |
97 | * the others are counting a subset. |
98 | */ |
99 | for (i = 1; i < 4; i++) |
100 | FAIL_IF(events[0].result.value < events[i].result.value); |
101 | |
102 | for (i = 0; i < 4; i++) |
103 | event_close(e: &events[i]); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | int main(void) |
109 | { |
110 | return test_harness(per_event_excludes, "per_event_excludes" ); |
111 | } |
112 | |