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