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