hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 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");
}