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