1*a1e26a70SApple OSS Distributions // Copyright (c) 2021-2022 Apple Inc. All rights reserved.
2*a1e26a70SApple OSS Distributions
3*a1e26a70SApple OSS Distributions #include <darwintest.h>
4*a1e26a70SApple OSS Distributions #include "test_utils.h"
5*a1e26a70SApple OSS Distributions #include <fcntl.h>
6*a1e26a70SApple OSS Distributions #include <inttypes.h>
7*a1e26a70SApple OSS Distributions #ifndef PRIVATE
8*a1e26a70SApple OSS Distributions /*
9*a1e26a70SApple OSS Distributions * Need new CPU families.
10*a1e26a70SApple OSS Distributions */
11*a1e26a70SApple OSS Distributions #define PRIVATE
12*a1e26a70SApple OSS Distributions #include <mach/machine.h>
13*a1e26a70SApple OSS Distributions #undef PRIVATE
14*a1e26a70SApple OSS Distributions #else /* !defined(PRIVATE) */
15*a1e26a70SApple OSS Distributions #include <mach/machine.h>
16*a1e26a70SApple OSS Distributions #endif /* defined(PRIVATE) */
17*a1e26a70SApple OSS Distributions #include <stdint.h>
18*a1e26a70SApple OSS Distributions #include <System/sys/guarded.h>
19*a1e26a70SApple OSS Distributions #include <System/sys/monotonic.h>
20*a1e26a70SApple OSS Distributions #include <sys/ioctl.h>
21*a1e26a70SApple OSS Distributions #include <sys/sysctl.h>
22*a1e26a70SApple OSS Distributions #include <unistd.h>
23*a1e26a70SApple OSS Distributions
24*a1e26a70SApple OSS Distributions T_GLOBAL_META(
25*a1e26a70SApple OSS Distributions T_META_NAMESPACE("xnu.monotonic"),
26*a1e26a70SApple OSS Distributions T_META_CHECK_LEAKS(false),
27*a1e26a70SApple OSS Distributions XNU_T_META_REQUIRES_DEVELOPMENT_KERNEL
28*a1e26a70SApple OSS Distributions );
29*a1e26a70SApple OSS Distributions
30*a1e26a70SApple OSS Distributions static bool
device_supports_uncore(void)31*a1e26a70SApple OSS Distributions device_supports_uncore(void)
32*a1e26a70SApple OSS Distributions {
33*a1e26a70SApple OSS Distributions int r;
34*a1e26a70SApple OSS Distributions int type, subtype;
35*a1e26a70SApple OSS Distributions unsigned int family;
36*a1e26a70SApple OSS Distributions size_t size = sizeof(type);
37*a1e26a70SApple OSS Distributions
38*a1e26a70SApple OSS Distributions /*
39*a1e26a70SApple OSS Distributions * Only arm64 Monsoon devices support uncore counters.
40*a1e26a70SApple OSS Distributions */
41*a1e26a70SApple OSS Distributions
42*a1e26a70SApple OSS Distributions r = sysctlbyname("hw.cputype", &type, &size, NULL, 0);
43*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"hw.cputype\")");
44*a1e26a70SApple OSS Distributions r = sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
45*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"hw.cpusubtype\")");
46*a1e26a70SApple OSS Distributions r = sysctlbyname("hw.cpufamily", &family, &size, NULL, 0);
47*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"hw.cpufamily\")");
48*a1e26a70SApple OSS Distributions
49*a1e26a70SApple OSS Distributions if (type == CPU_TYPE_ARM64 &&
50*a1e26a70SApple OSS Distributions subtype == CPU_SUBTYPE_ARM64_V8 &&
51*a1e26a70SApple OSS Distributions (family == CPUFAMILY_ARM_MONSOON_MISTRAL ||
52*a1e26a70SApple OSS Distributions family == CPUFAMILY_ARM_VORTEX_TEMPEST)) {
53*a1e26a70SApple OSS Distributions return true;
54*a1e26a70SApple OSS Distributions }
55*a1e26a70SApple OSS Distributions
56*a1e26a70SApple OSS Distributions return false;
57*a1e26a70SApple OSS Distributions }
58*a1e26a70SApple OSS Distributions
59*a1e26a70SApple OSS Distributions #define UNCORE_DEV_PATH "/dev/monotonic/uncore"
60*a1e26a70SApple OSS Distributions
61*a1e26a70SApple OSS Distributions static int
open_uncore_error(int * error)62*a1e26a70SApple OSS Distributions open_uncore_error(int *error)
63*a1e26a70SApple OSS Distributions {
64*a1e26a70SApple OSS Distributions guardid_t guard;
65*a1e26a70SApple OSS Distributions int fd;
66*a1e26a70SApple OSS Distributions
67*a1e26a70SApple OSS Distributions guard = 0xa5adcafe;
68*a1e26a70SApple OSS Distributions
69*a1e26a70SApple OSS Distributions T_SETUPBEGIN;
70*a1e26a70SApple OSS Distributions
71*a1e26a70SApple OSS Distributions fd = guarded_open_np(UNCORE_DEV_PATH, &guard,
72*a1e26a70SApple OSS Distributions GUARD_CLOSE | GUARD_DUP | GUARD_WRITE, O_CLOEXEC | O_EXCL);
73*a1e26a70SApple OSS Distributions if (fd < 0 && errno == ENOENT) {
74*a1e26a70SApple OSS Distributions T_ASSERT_FALSE(device_supports_uncore(),
75*a1e26a70SApple OSS Distributions "lack of dev node implies no uncore support");
76*a1e26a70SApple OSS Distributions T_SKIP("uncore counters are unsupported");
77*a1e26a70SApple OSS Distributions __builtin_unreachable();
78*a1e26a70SApple OSS Distributions }
79*a1e26a70SApple OSS Distributions
80*a1e26a70SApple OSS Distributions if (error == NULL) {
81*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(fd, "open '%s'", UNCORE_DEV_PATH);
82*a1e26a70SApple OSS Distributions } else {
83*a1e26a70SApple OSS Distributions *error = errno;
84*a1e26a70SApple OSS Distributions }
85*a1e26a70SApple OSS Distributions
86*a1e26a70SApple OSS Distributions T_SETUPEND;
87*a1e26a70SApple OSS Distributions
88*a1e26a70SApple OSS Distributions return fd;
89*a1e26a70SApple OSS Distributions }
90*a1e26a70SApple OSS Distributions
91*a1e26a70SApple OSS Distributions static void
uncore_counts(int fd,uint64_t ctr_mask,uint64_t * counts)92*a1e26a70SApple OSS Distributions uncore_counts(int fd, uint64_t ctr_mask, uint64_t *counts)
93*a1e26a70SApple OSS Distributions {
94*a1e26a70SApple OSS Distributions int r;
95*a1e26a70SApple OSS Distributions union monotonic_ctl_counts *cts_ctl;
96*a1e26a70SApple OSS Distributions
97*a1e26a70SApple OSS Distributions cts_ctl = (union monotonic_ctl_counts *)counts;
98*a1e26a70SApple OSS Distributions cts_ctl->in.ctr_mask = ctr_mask;
99*a1e26a70SApple OSS Distributions
100*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_COUNTS, cts_ctl);
101*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "MT_IOC_COUNTS got counter values");
102*a1e26a70SApple OSS Distributions }
103*a1e26a70SApple OSS Distributions
104*a1e26a70SApple OSS Distributions #define REF_TIMEBASE_EVENT 0x3
105*a1e26a70SApple OSS Distributions #define CTRS_MAX 128
106*a1e26a70SApple OSS Distributions
107*a1e26a70SApple OSS Distributions T_DECL(uncore_max_counters,
108*a1e26a70SApple OSS Distributions "ensure that the maximum number of uncore countes is sane",
109*a1e26a70SApple OSS Distributions XNU_T_META_SOC_SPECIFIC,
110*a1e26a70SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
111*a1e26a70SApple OSS Distributions {
112*a1e26a70SApple OSS Distributions int nctrs = 0;
113*a1e26a70SApple OSS Distributions int fd;
114*a1e26a70SApple OSS Distributions
115*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
116*a1e26a70SApple OSS Distributions
117*a1e26a70SApple OSS Distributions do {
118*a1e26a70SApple OSS Distributions union monotonic_ctl_add add_ctl;
119*a1e26a70SApple OSS Distributions int r;
120*a1e26a70SApple OSS Distributions
121*a1e26a70SApple OSS Distributions add_ctl.in.config.event = REF_TIMEBASE_EVENT;
122*a1e26a70SApple OSS Distributions add_ctl.in.config.allowed_ctr_mask = UINT64_MAX;
123*a1e26a70SApple OSS Distributions
124*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_ADD, &add_ctl);
125*a1e26a70SApple OSS Distributions if (r < 0 && errno == E2BIG) {
126*a1e26a70SApple OSS Distributions break;
127*a1e26a70SApple OSS Distributions }
128*a1e26a70SApple OSS Distributions
129*a1e26a70SApple OSS Distributions T_QUIET;
130*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r, "added reference timebase event to counters");
131*a1e26a70SApple OSS Distributions nctrs++;
132*a1e26a70SApple OSS Distributions } while (nctrs < CTRS_MAX);
133*a1e26a70SApple OSS Distributions
134*a1e26a70SApple OSS Distributions T_EXPECT_LT(nctrs, CTRS_MAX, "able to allocate %d uncore PMCs", nctrs);
135*a1e26a70SApple OSS Distributions }
136*a1e26a70SApple OSS Distributions
137*a1e26a70SApple OSS Distributions static uint32_t
uncore_add(int fd,uint64_t event,uint64_t allowed_ctrs,int error)138*a1e26a70SApple OSS Distributions uncore_add(int fd, uint64_t event, uint64_t allowed_ctrs, int error)
139*a1e26a70SApple OSS Distributions {
140*a1e26a70SApple OSS Distributions int save_errno;
141*a1e26a70SApple OSS Distributions int r;
142*a1e26a70SApple OSS Distributions uint32_t ctr;
143*a1e26a70SApple OSS Distributions union monotonic_ctl_add add_ctl;
144*a1e26a70SApple OSS Distributions
145*a1e26a70SApple OSS Distributions add_ctl.in.config.event = event;
146*a1e26a70SApple OSS Distributions add_ctl.in.config.allowed_ctr_mask = allowed_ctrs;
147*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_ADD, &add_ctl);
148*a1e26a70SApple OSS Distributions if (error) {
149*a1e26a70SApple OSS Distributions save_errno = errno;
150*a1e26a70SApple OSS Distributions T_EXPECT_LT(r, 0, "adding event to counter should fail");
151*a1e26a70SApple OSS Distributions T_EXPECT_EQ(save_errno, error,
152*a1e26a70SApple OSS Distributions "adding event to counter should fail with %d: %s",
153*a1e26a70SApple OSS Distributions error, strerror(error));
154*a1e26a70SApple OSS Distributions return UINT32_MAX;
155*a1e26a70SApple OSS Distributions } else {
156*a1e26a70SApple OSS Distributions T_QUIET;
157*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r,
158*a1e26a70SApple OSS Distributions "added event %#" PRIx64 " to counters", event);
159*a1e26a70SApple OSS Distributions }
160*a1e26a70SApple OSS Distributions
161*a1e26a70SApple OSS Distributions ctr = add_ctl.out.ctr;
162*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_LT(ctr, (uint32_t)CTRS_MAX, "counter returned should be sane");
163*a1e26a70SApple OSS Distributions return ctr;
164*a1e26a70SApple OSS Distributions }
165*a1e26a70SApple OSS Distributions
166*a1e26a70SApple OSS Distributions T_DECL(uncore_collision,
167*a1e26a70SApple OSS Distributions "ensure that trying to add an event on the same counter fails",
168*a1e26a70SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
169*a1e26a70SApple OSS Distributions {
170*a1e26a70SApple OSS Distributions int fd;
171*a1e26a70SApple OSS Distributions uint32_t ctr;
172*a1e26a70SApple OSS Distributions
173*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
174*a1e26a70SApple OSS Distributions
175*a1e26a70SApple OSS Distributions ctr = uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_MAX, 0);
176*a1e26a70SApple OSS Distributions T_LOG("added event to uncore counter %d\n", ctr);
177*a1e26a70SApple OSS Distributions
178*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_C(1) << ctr, ENOSPC);
179*a1e26a70SApple OSS Distributions }
180*a1e26a70SApple OSS Distributions
181*a1e26a70SApple OSS Distributions static void
uncore_enable(int fd)182*a1e26a70SApple OSS Distributions uncore_enable(int fd)
183*a1e26a70SApple OSS Distributions {
184*a1e26a70SApple OSS Distributions union monotonic_ctl_enable en_ctl = {
185*a1e26a70SApple OSS Distributions .in = { .enable = true }
186*a1e26a70SApple OSS Distributions };
187*a1e26a70SApple OSS Distributions
188*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ioctl(fd, MT_IOC_ENABLE, &en_ctl),
189*a1e26a70SApple OSS Distributions "enabling counters");
190*a1e26a70SApple OSS Distributions }
191*a1e26a70SApple OSS Distributions
192*a1e26a70SApple OSS Distributions T_DECL(uncore_enabled_busy,
193*a1e26a70SApple OSS Distributions "ensure that trying to add an event while enabled fails",
194*a1e26a70SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
195*a1e26a70SApple OSS Distributions {
196*a1e26a70SApple OSS Distributions int fd;
197*a1e26a70SApple OSS Distributions
198*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
199*a1e26a70SApple OSS Distributions
200*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_MAX, 0);
201*a1e26a70SApple OSS Distributions
202*a1e26a70SApple OSS Distributions uncore_enable(fd);
203*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_MAX, EBUSY);
204*a1e26a70SApple OSS Distributions }
205*a1e26a70SApple OSS Distributions
206*a1e26a70SApple OSS Distributions T_DECL(uncore_reset,
207*a1e26a70SApple OSS Distributions "ensure that resetting the counters works", T_META_TAG_VM_NOT_ELIGIBLE)
208*a1e26a70SApple OSS Distributions {
209*a1e26a70SApple OSS Distributions int fd;
210*a1e26a70SApple OSS Distributions int r;
211*a1e26a70SApple OSS Distributions
212*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
213*a1e26a70SApple OSS Distributions
214*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_C(1), 0);
215*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_C(1), ENOSPC);
216*a1e26a70SApple OSS Distributions
217*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_RESET);
218*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r, "resetting succeeds");
219*a1e26a70SApple OSS Distributions
220*a1e26a70SApple OSS Distributions T_LOG("adding event to same counter after reset");
221*a1e26a70SApple OSS Distributions (void)uncore_add(fd, REF_TIMEBASE_EVENT, UINT64_C(1), 0);
222*a1e26a70SApple OSS Distributions }
223*a1e26a70SApple OSS Distributions
224*a1e26a70SApple OSS Distributions #define SLEEP_USECS (500 * 1000)
225*a1e26a70SApple OSS Distributions
226*a1e26a70SApple OSS Distributions static int
uncore_add_all(int fd,uint64_t event,int * nmonitors)227*a1e26a70SApple OSS Distributions uncore_add_all(int fd, uint64_t event, int *nmonitors)
228*a1e26a70SApple OSS Distributions {
229*a1e26a70SApple OSS Distributions int nctrs = 0;
230*a1e26a70SApple OSS Distributions int r;
231*a1e26a70SApple OSS Distributions
232*a1e26a70SApple OSS Distributions do {
233*a1e26a70SApple OSS Distributions union monotonic_ctl_add add_ctl;
234*a1e26a70SApple OSS Distributions
235*a1e26a70SApple OSS Distributions add_ctl.in.config.event = event;
236*a1e26a70SApple OSS Distributions add_ctl.in.config.allowed_ctr_mask = UINT64_MAX;
237*a1e26a70SApple OSS Distributions
238*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_ADD, &add_ctl);
239*a1e26a70SApple OSS Distributions if (r < 0 && errno == E2BIG) {
240*a1e26a70SApple OSS Distributions break;
241*a1e26a70SApple OSS Distributions }
242*a1e26a70SApple OSS Distributions
243*a1e26a70SApple OSS Distributions T_QUIET;
244*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r, "added event %#" PRIx64 " to counters",
245*a1e26a70SApple OSS Distributions event);
246*a1e26a70SApple OSS Distributions nctrs++;
247*a1e26a70SApple OSS Distributions } while (nctrs < CTRS_MAX);
248*a1e26a70SApple OSS Distributions
249*a1e26a70SApple OSS Distributions if (nmonitors) {
250*a1e26a70SApple OSS Distributions union monotonic_ctl_info info_ctl;
251*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_GET_INFO, &info_ctl);
252*a1e26a70SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "got info about uncore counters");
253*a1e26a70SApple OSS Distributions
254*a1e26a70SApple OSS Distributions *nmonitors = (int)info_ctl.out.nmonitors;
255*a1e26a70SApple OSS Distributions }
256*a1e26a70SApple OSS Distributions
257*a1e26a70SApple OSS Distributions return nctrs;
258*a1e26a70SApple OSS Distributions }
259*a1e26a70SApple OSS Distributions
260*a1e26a70SApple OSS Distributions T_DECL(uncore_accuracy,
261*a1e26a70SApple OSS Distributions "ensure that the uncore counters count accurately",
262*a1e26a70SApple OSS Distributions T_META_ASROOT(true),
263*a1e26a70SApple OSS Distributions XNU_T_META_SOC_SPECIFIC,
264*a1e26a70SApple OSS Distributions T_META_MAYFAIL("rdar://88973518, threads need to be forced onto clusters"), T_META_TAG_VM_NOT_ELIGIBLE)
265*a1e26a70SApple OSS Distributions {
266*a1e26a70SApple OSS Distributions int fd;
267*a1e26a70SApple OSS Distributions int nctrs = 0;
268*a1e26a70SApple OSS Distributions int nmonitors = 0;
269*a1e26a70SApple OSS Distributions uint64_t ctr_mask;
270*a1e26a70SApple OSS Distributions uint64_t counts[2][CTRS_MAX];
271*a1e26a70SApple OSS Distributions uint64_t times[2];
272*a1e26a70SApple OSS Distributions
273*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
274*a1e26a70SApple OSS Distributions
275*a1e26a70SApple OSS Distributions /*
276*a1e26a70SApple OSS Distributions * The reference timebase event counts the same as mach_continuous_time
277*a1e26a70SApple OSS Distributions * (on hardware supporting uncore counters). Make sure that the counter
278*a1e26a70SApple OSS Distributions * is close to the values returned from the trap.
279*a1e26a70SApple OSS Distributions *
280*a1e26a70SApple OSS Distributions * Fill all the counters with this event.
281*a1e26a70SApple OSS Distributions */
282*a1e26a70SApple OSS Distributions nctrs = uncore_add_all(fd, REF_TIMEBASE_EVENT, &nmonitors);
283*a1e26a70SApple OSS Distributions ctr_mask = (UINT64_C(1) << nctrs) - 1;
284*a1e26a70SApple OSS Distributions
285*a1e26a70SApple OSS Distributions T_LOG("added %d counters to check", nctrs);
286*a1e26a70SApple OSS Distributions
287*a1e26a70SApple OSS Distributions uncore_enable(fd);
288*a1e26a70SApple OSS Distributions
289*a1e26a70SApple OSS Distributions /*
290*a1e26a70SApple OSS Distributions * First, make sure there's an upper bound on the counter -- take the
291*a1e26a70SApple OSS Distributions * time around getting the counter values.
292*a1e26a70SApple OSS Distributions */
293*a1e26a70SApple OSS Distributions
294*a1e26a70SApple OSS Distributions times[0] = mach_absolute_time();
295*a1e26a70SApple OSS Distributions uncore_counts(fd, ctr_mask, counts[0]);
296*a1e26a70SApple OSS Distributions
297*a1e26a70SApple OSS Distributions usleep(SLEEP_USECS);
298*a1e26a70SApple OSS Distributions
299*a1e26a70SApple OSS Distributions uncore_counts(fd, ctr_mask, counts[1]);
300*a1e26a70SApple OSS Distributions times[1] = mach_absolute_time();
301*a1e26a70SApple OSS Distributions
302*a1e26a70SApple OSS Distributions T_QUIET; T_EXPECT_GT(times[1], times[0],
303*a1e26a70SApple OSS Distributions "mach_continuous_time is monotonically increasing");
304*a1e26a70SApple OSS Distributions for (int i = 0; i < nctrs; i++) {
305*a1e26a70SApple OSS Distributions T_EXPECT_GT(counts[1][i], counts[0][i],
306*a1e26a70SApple OSS Distributions "uncore counter %d value is monotonically increasing", i);
307*a1e26a70SApple OSS Distributions T_EXPECT_LT(counts[1][i] - counts[0][i], times[1] - times[0],
308*a1e26a70SApple OSS Distributions "reference timebase on uncore counter %d satisfies upper bound "
309*a1e26a70SApple OSS Distributions "from mach_absolute_time", i);
310*a1e26a70SApple OSS Distributions }
311*a1e26a70SApple OSS Distributions
312*a1e26a70SApple OSS Distributions /*
313*a1e26a70SApple OSS Distributions * Next, the lower bound -- put mach_absolute_time inside getting the
314*a1e26a70SApple OSS Distributions * counter values.
315*a1e26a70SApple OSS Distributions */
316*a1e26a70SApple OSS Distributions
317*a1e26a70SApple OSS Distributions uncore_counts(fd, ctr_mask, counts[0]);
318*a1e26a70SApple OSS Distributions times[0] = mach_absolute_time();
319*a1e26a70SApple OSS Distributions
320*a1e26a70SApple OSS Distributions volatile int iterations = 100000;
321*a1e26a70SApple OSS Distributions while (iterations--) {
322*a1e26a70SApple OSS Distributions ;
323*a1e26a70SApple OSS Distributions }
324*a1e26a70SApple OSS Distributions
325*a1e26a70SApple OSS Distributions times[1] = mach_absolute_time();
326*a1e26a70SApple OSS Distributions uncore_counts(fd, ctr_mask, counts[1]);
327*a1e26a70SApple OSS Distributions
328*a1e26a70SApple OSS Distributions for (int mon = 0; mon < nmonitors; mon++) {
329*a1e26a70SApple OSS Distributions for (int i = 0; i < nctrs; i++) {
330*a1e26a70SApple OSS Distributions uint64_t after = counts[1][i * mon];
331*a1e26a70SApple OSS Distributions uint64_t before = counts[0][i * mon];
332*a1e26a70SApple OSS Distributions uint64_t delta = after - before;
333*a1e26a70SApple OSS Distributions T_LOG("%d,%2d: %12" PRIu64 "%12" PRIu64 " = %10" PRIu64, mon, i,
334*a1e26a70SApple OSS Distributions before, after, delta);
335*a1e26a70SApple OSS Distributions T_QUIET;
336*a1e26a70SApple OSS Distributions T_EXPECT_GT(after, before,
337*a1e26a70SApple OSS Distributions "uncore %d counter %d value is monotonically increasing",
338*a1e26a70SApple OSS Distributions mon, i);
339*a1e26a70SApple OSS Distributions T_QUIET;
340*a1e26a70SApple OSS Distributions T_EXPECT_GT(counts[1][i * mon] - counts[0][i * mon],
341*a1e26a70SApple OSS Distributions times[1] - times[0],
342*a1e26a70SApple OSS Distributions "reference timebase on uncore %d counter %d satisfies "
343*a1e26a70SApple OSS Distributions "lower bound from mach_absolute_time", mon, i);
344*a1e26a70SApple OSS Distributions }
345*a1e26a70SApple OSS Distributions }
346*a1e26a70SApple OSS Distributions }
347*a1e26a70SApple OSS Distributions
348*a1e26a70SApple OSS Distributions T_DECL(uncore_ownership,
349*a1e26a70SApple OSS Distributions "ensure the dev node cannot be open in two places",
350*a1e26a70SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_VM_NOT_ELIGIBLE)
351*a1e26a70SApple OSS Distributions {
352*a1e26a70SApple OSS Distributions int fd;
353*a1e26a70SApple OSS Distributions int other_fd;
354*a1e26a70SApple OSS Distributions int error;
355*a1e26a70SApple OSS Distributions
356*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
357*a1e26a70SApple OSS Distributions
358*a1e26a70SApple OSS Distributions other_fd = open_uncore_error(&error);
359*a1e26a70SApple OSS Distributions T_ASSERT_LT(other_fd, 0, "opening a second uncore fd should fail");
360*a1e26a70SApple OSS Distributions }
361*a1e26a70SApple OSS Distributions
362*a1e26a70SApple OSS Distributions T_DECL(uncore_root_required,
363*a1e26a70SApple OSS Distributions "ensure the dev node cannot be opened by non-root users",
364*a1e26a70SApple OSS Distributions T_META_ASROOT(false), T_META_TAG_VM_NOT_ELIGIBLE)
365*a1e26a70SApple OSS Distributions {
366*a1e26a70SApple OSS Distributions int fd;
367*a1e26a70SApple OSS Distributions int error = 0;
368*a1e26a70SApple OSS Distributions
369*a1e26a70SApple OSS Distributions T_SKIP("libdarwintest doesn't drop privileges properly");
370*a1e26a70SApple OSS Distributions
371*a1e26a70SApple OSS Distributions fd = open_uncore_error(&error);
372*a1e26a70SApple OSS Distributions T_ASSERT_LT(fd, 0, "opening dev node should not return an fd");
373*a1e26a70SApple OSS Distributions T_ASSERT_EQ(error, EPERM,
374*a1e26a70SApple OSS Distributions "opening dev node as non-root user should fail with EPERM");
375*a1e26a70SApple OSS Distributions }
376*a1e26a70SApple OSS Distributions
377*a1e26a70SApple OSS Distributions T_DECL(perf_uncore,
378*a1e26a70SApple OSS Distributions "measure the latency of accessing the counters",
379*a1e26a70SApple OSS Distributions XNU_T_META_SOC_SPECIFIC,
380*a1e26a70SApple OSS Distributions T_META_TAG_PERF, T_META_TAG_VM_NOT_ELIGIBLE)
381*a1e26a70SApple OSS Distributions {
382*a1e26a70SApple OSS Distributions int fd;
383*a1e26a70SApple OSS Distributions int nctrs;
384*a1e26a70SApple OSS Distributions int nmonitors;
385*a1e26a70SApple OSS Distributions int r;
386*a1e26a70SApple OSS Distributions uint64_t ctr_mask;
387*a1e26a70SApple OSS Distributions dt_stat_thread_instructions_t counts_instrs;
388*a1e26a70SApple OSS Distributions dt_stat_t counter_deltas;
389*a1e26a70SApple OSS Distributions
390*a1e26a70SApple OSS Distributions counts_instrs = dt_stat_thread_instructions_create("ioctl_counts");
391*a1e26a70SApple OSS Distributions counter_deltas = dt_stat_create("abs_time", "between_each_counter");
392*a1e26a70SApple OSS Distributions
393*a1e26a70SApple OSS Distributions fd = open_uncore_error(NULL);
394*a1e26a70SApple OSS Distributions
395*a1e26a70SApple OSS Distributions nctrs = uncore_add_all(fd, REF_TIMEBASE_EVENT, &nmonitors);
396*a1e26a70SApple OSS Distributions ctr_mask = (UINT64_C(1) << nctrs) - 1;
397*a1e26a70SApple OSS Distributions
398*a1e26a70SApple OSS Distributions uncore_enable(fd);
399*a1e26a70SApple OSS Distributions
400*a1e26a70SApple OSS Distributions do {
401*a1e26a70SApple OSS Distributions dt_stat_token token;
402*a1e26a70SApple OSS Distributions uint64_t counts[nctrs * nmonitors];
403*a1e26a70SApple OSS Distributions union monotonic_ctl_counts *cts_ctl;
404*a1e26a70SApple OSS Distributions
405*a1e26a70SApple OSS Distributions cts_ctl = (union monotonic_ctl_counts *)counts;
406*a1e26a70SApple OSS Distributions cts_ctl->in.ctr_mask = ctr_mask;
407*a1e26a70SApple OSS Distributions
408*a1e26a70SApple OSS Distributions token = dt_stat_thread_instructions_begin(counts_instrs);
409*a1e26a70SApple OSS Distributions r = ioctl(fd, MT_IOC_COUNTS, cts_ctl);
410*a1e26a70SApple OSS Distributions dt_stat_thread_instructions_end(counts_instrs, token);
411*a1e26a70SApple OSS Distributions T_QUIET;
412*a1e26a70SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r,
413*a1e26a70SApple OSS Distributions "getting uncore counter values %#" PRIx64, ctr_mask);
414*a1e26a70SApple OSS Distributions
415*a1e26a70SApple OSS Distributions for (int i = 0; i < (nctrs - 1); i++) {
416*a1e26a70SApple OSS Distributions dt_stat_add(counter_deltas, (double)(counts[i + 1] - counts[i]));
417*a1e26a70SApple OSS Distributions }
418*a1e26a70SApple OSS Distributions } while (!dt_stat_stable(counts_instrs) || !dt_stat_stable(counter_deltas));
419*a1e26a70SApple OSS Distributions
420*a1e26a70SApple OSS Distributions dt_stat_finalize(counts_instrs);
421*a1e26a70SApple OSS Distributions dt_stat_finalize(counter_deltas);
422*a1e26a70SApple OSS Distributions }
423