xref: /xnu-8020.121.3/tests/monotonic_core.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941)
1*fdd8201dSApple OSS Distributions /*
2*fdd8201dSApple OSS Distributions  * Must come before including darwintest.h
3*fdd8201dSApple OSS Distributions  */
4*fdd8201dSApple OSS Distributions #ifdef T_NAMESPACE
5*fdd8201dSApple OSS Distributions #undef T_NAMESPACE
6*fdd8201dSApple OSS Distributions #endif /* defined(T_NAMESPACE) */
7*fdd8201dSApple OSS Distributions 
8*fdd8201dSApple OSS Distributions #include <darwintest.h>
9*fdd8201dSApple OSS Distributions #include <fcntl.h>
10*fdd8201dSApple OSS Distributions #include <inttypes.h>
11*fdd8201dSApple OSS Distributions #ifndef PRIVATE
12*fdd8201dSApple OSS Distributions /*
13*fdd8201dSApple OSS Distributions  * Need new CPU families.
14*fdd8201dSApple OSS Distributions  */
15*fdd8201dSApple OSS Distributions #define PRIVATE
16*fdd8201dSApple OSS Distributions #include <mach/machine.h>
17*fdd8201dSApple OSS Distributions #undef PRIVATE
18*fdd8201dSApple OSS Distributions #else /* !defined(PRIVATE) */
19*fdd8201dSApple OSS Distributions #include <mach/machine.h>
20*fdd8201dSApple OSS Distributions #endif /* defined(PRIVATE) */
21*fdd8201dSApple OSS Distributions #include <ktrace.h>
22*fdd8201dSApple OSS Distributions #include <mach/mach.h>
23*fdd8201dSApple OSS Distributions #include <stdint.h>
24*fdd8201dSApple OSS Distributions #include <System/sys/guarded.h>
25*fdd8201dSApple OSS Distributions #include <System/sys/monotonic.h>
26*fdd8201dSApple OSS Distributions #include <sys/ioctl.h>
27*fdd8201dSApple OSS Distributions #include <sys/kdebug.h>
28*fdd8201dSApple OSS Distributions #include <sys/resource.h>
29*fdd8201dSApple OSS Distributions #include <sys/resource_private.h>
30*fdd8201dSApple OSS Distributions #include <sys/sysctl.h>
31*fdd8201dSApple OSS Distributions #include <unistd.h>
32*fdd8201dSApple OSS Distributions 
33*fdd8201dSApple OSS Distributions T_GLOBAL_META(
34*fdd8201dSApple OSS Distributions 	T_META_NAMESPACE("xnu.monotonic"),
35*fdd8201dSApple OSS Distributions 	T_META_CHECK_LEAKS(false)
36*fdd8201dSApple OSS Distributions 	);
37*fdd8201dSApple OSS Distributions 
38*fdd8201dSApple OSS Distributions static void
skip_if_unsupported(void)39*fdd8201dSApple OSS Distributions skip_if_unsupported(void)
40*fdd8201dSApple OSS Distributions {
41*fdd8201dSApple OSS Distributions 	int r;
42*fdd8201dSApple OSS Distributions 	int supported = 0;
43*fdd8201dSApple OSS Distributions 	size_t supported_size = sizeof(supported);
44*fdd8201dSApple OSS Distributions 
45*fdd8201dSApple OSS Distributions 	r = sysctlbyname("kern.monotonic.supported", &supported, &supported_size,
46*fdd8201dSApple OSS Distributions 	    NULL, 0);
47*fdd8201dSApple OSS Distributions 	if (r < 0) {
48*fdd8201dSApple OSS Distributions 		T_WITH_ERRNO;
49*fdd8201dSApple OSS Distributions 		T_SKIP("could not find \"kern.monotonic.supported\" sysctl");
50*fdd8201dSApple OSS Distributions 	}
51*fdd8201dSApple OSS Distributions 
52*fdd8201dSApple OSS Distributions 	if (!supported) {
53*fdd8201dSApple OSS Distributions 		T_SKIP("monotonic is not supported on this platform");
54*fdd8201dSApple OSS Distributions 	}
55*fdd8201dSApple OSS Distributions }
56*fdd8201dSApple OSS Distributions 
57*fdd8201dSApple OSS Distributions static void
check_fixed_counts(struct thsc_cpi counts[2])58*fdd8201dSApple OSS Distributions check_fixed_counts(struct thsc_cpi counts[2])
59*fdd8201dSApple OSS Distributions {
60*fdd8201dSApple OSS Distributions 	T_QUIET;
61*fdd8201dSApple OSS Distributions 	T_EXPECT_GT(counts[0].tcpi_instructions, UINT64_C(0), "non-zero instructions");
62*fdd8201dSApple OSS Distributions 	T_QUIET;
63*fdd8201dSApple OSS Distributions 	T_EXPECT_GT(counts[0].tcpi_cycles, UINT64_C(0), "non-zero cycles");
64*fdd8201dSApple OSS Distributions 
65*fdd8201dSApple OSS Distributions 	T_EXPECT_GT(counts[1].tcpi_instructions, counts[0].tcpi_instructions,
66*fdd8201dSApple OSS Distributions 	    "monotonically-increasing instructions");
67*fdd8201dSApple OSS Distributions 	T_EXPECT_GT(counts[1].tcpi_cycles, counts[0].tcpi_cycles,
68*fdd8201dSApple OSS Distributions 	    "monotonically-increasing cycles");
69*fdd8201dSApple OSS Distributions }
70*fdd8201dSApple OSS Distributions 
71*fdd8201dSApple OSS Distributions T_DECL(core_fixed_thread_self, "check the current thread's fixed counters",
72*fdd8201dSApple OSS Distributions     T_META_ASROOT(true))
73*fdd8201dSApple OSS Distributions {
74*fdd8201dSApple OSS Distributions 	int err;
75*fdd8201dSApple OSS Distributions 	struct thsc_cpi counts[2] = { 0 };
76*fdd8201dSApple OSS Distributions 
77*fdd8201dSApple OSS Distributions 	T_SETUPBEGIN;
78*fdd8201dSApple OSS Distributions 	skip_if_unsupported();
79*fdd8201dSApple OSS Distributions 	T_SETUPEND;
80*fdd8201dSApple OSS Distributions 
81*fdd8201dSApple OSS Distributions 	err = thread_selfcounts_cpi(&counts[0]);
82*fdd8201dSApple OSS Distributions 	T_ASSERT_POSIX_ZERO(err, "thread_selfcounts");
83*fdd8201dSApple OSS Distributions 	err = thread_selfcounts_cpi(&counts[1]);
84*fdd8201dSApple OSS Distributions 	T_ASSERT_POSIX_ZERO(err, "thread_selfcounts");
85*fdd8201dSApple OSS Distributions 
86*fdd8201dSApple OSS Distributions 	check_fixed_counts(counts);
87*fdd8201dSApple OSS Distributions }
88*fdd8201dSApple OSS Distributions 
89*fdd8201dSApple OSS Distributions T_DECL(core_fixed_task, "check that task counting is working",
90*fdd8201dSApple OSS Distributions     T_META_ASROOT(true))
91*fdd8201dSApple OSS Distributions {
92*fdd8201dSApple OSS Distributions 	task_t task = mach_task_self();
93*fdd8201dSApple OSS Distributions 	kern_return_t kr;
94*fdd8201dSApple OSS Distributions 	mach_msg_type_number_t size = TASK_INSPECT_BASIC_COUNTS_COUNT;
95*fdd8201dSApple OSS Distributions 	struct thsc_cpi counts[2];
96*fdd8201dSApple OSS Distributions 
97*fdd8201dSApple OSS Distributions 	skip_if_unsupported();
98*fdd8201dSApple OSS Distributions 
99*fdd8201dSApple OSS Distributions 	kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
100*fdd8201dSApple OSS Distributions 	    (task_inspect_info_t)&counts[0], &size);
101*fdd8201dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr,
102*fdd8201dSApple OSS Distributions 	    "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
103*fdd8201dSApple OSS Distributions 
104*fdd8201dSApple OSS Distributions 	size = TASK_INSPECT_BASIC_COUNTS_COUNT;
105*fdd8201dSApple OSS Distributions 	kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
106*fdd8201dSApple OSS Distributions 	    (task_inspect_info_t)&counts[1], &size);
107*fdd8201dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr,
108*fdd8201dSApple OSS Distributions 	    "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
109*fdd8201dSApple OSS Distributions 
110*fdd8201dSApple OSS Distributions 	check_fixed_counts(counts);
111*fdd8201dSApple OSS Distributions }
112*fdd8201dSApple OSS Distributions 
113*fdd8201dSApple OSS Distributions T_DECL(core_fixed_kdebug, "check that the kdebug macros for monotonic work",
114*fdd8201dSApple OSS Distributions     T_META_ASROOT(true))
115*fdd8201dSApple OSS Distributions {
116*fdd8201dSApple OSS Distributions 	__block bool saw_events = false;
117*fdd8201dSApple OSS Distributions 	ktrace_session_t s;
118*fdd8201dSApple OSS Distributions 	int r;
119*fdd8201dSApple OSS Distributions 	int set = 1;
120*fdd8201dSApple OSS Distributions 
121*fdd8201dSApple OSS Distributions 	T_SETUPBEGIN;
122*fdd8201dSApple OSS Distributions 	skip_if_unsupported();
123*fdd8201dSApple OSS Distributions 
124*fdd8201dSApple OSS Distributions 	s = ktrace_session_create();
125*fdd8201dSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(s, "ktrace_session_create");
126*fdd8201dSApple OSS Distributions 
127*fdd8201dSApple OSS Distributions 	ktrace_events_single_paired(s,
128*fdd8201dSApple OSS Distributions 	    KDBG_EVENTID(DBG_MONOTONIC, DBG_MT_TMPCPU, 0x3fff),
129*fdd8201dSApple OSS Distributions 	    ^(struct trace_point *start, struct trace_point *end)
130*fdd8201dSApple OSS Distributions 	{
131*fdd8201dSApple OSS Distributions 		struct thsc_cpi counts[2];
132*fdd8201dSApple OSS Distributions 
133*fdd8201dSApple OSS Distributions 		saw_events = true;
134*fdd8201dSApple OSS Distributions 
135*fdd8201dSApple OSS Distributions 		counts[0].tcpi_instructions = start->arg1;
136*fdd8201dSApple OSS Distributions 		counts[0].tcpi_cycles = start->arg2;
137*fdd8201dSApple OSS Distributions 		counts[1].tcpi_instructions = end->arg1;
138*fdd8201dSApple OSS Distributions 		counts[1].tcpi_cycles = end->arg2;
139*fdd8201dSApple OSS Distributions 
140*fdd8201dSApple OSS Distributions 		check_fixed_counts(counts);
141*fdd8201dSApple OSS Distributions 	});
142*fdd8201dSApple OSS Distributions 
143*fdd8201dSApple OSS Distributions 	ktrace_set_completion_handler(s, ^{
144*fdd8201dSApple OSS Distributions 		T_ASSERT_TRUE(saw_events, "should see monotonic kdebug events");
145*fdd8201dSApple OSS Distributions 		T_END;
146*fdd8201dSApple OSS Distributions 	});
147*fdd8201dSApple OSS Distributions 	T_SETUPEND;
148*fdd8201dSApple OSS Distributions 
149*fdd8201dSApple OSS Distributions 	T_ASSERT_POSIX_ZERO(ktrace_start(s,
150*fdd8201dSApple OSS Distributions 	    dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)), NULL);
151*fdd8201dSApple OSS Distributions 
152*fdd8201dSApple OSS Distributions 	r = sysctlbyname("kern.monotonic.kdebug_test", NULL, NULL, &set,
153*fdd8201dSApple OSS Distributions 	    sizeof(set));
154*fdd8201dSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(r,
155*fdd8201dSApple OSS Distributions 	    "sysctlbyname(\"kern.monotonic.kdebug_test\", ...)");
156*fdd8201dSApple OSS Distributions 
157*fdd8201dSApple OSS Distributions 	ktrace_end(s, 0);
158*fdd8201dSApple OSS Distributions 	dispatch_main();
159*fdd8201dSApple OSS Distributions }
160*fdd8201dSApple OSS Distributions 
161*fdd8201dSApple OSS Distributions static void *
spin_thread_self_counts(__unused void * arg)162*fdd8201dSApple OSS Distributions spin_thread_self_counts(__unused void *arg)
163*fdd8201dSApple OSS Distributions {
164*fdd8201dSApple OSS Distributions 	struct thsc_cpi counts = { 0 };
165*fdd8201dSApple OSS Distributions 	while (true) {
166*fdd8201dSApple OSS Distributions 		(void)thread_selfcounts_cpi(&counts);
167*fdd8201dSApple OSS Distributions 	}
168*fdd8201dSApple OSS Distributions }
169*fdd8201dSApple OSS Distributions 
170*fdd8201dSApple OSS Distributions static void *
spin_task_inspect(__unused void * arg)171*fdd8201dSApple OSS Distributions spin_task_inspect(__unused void *arg)
172*fdd8201dSApple OSS Distributions {
173*fdd8201dSApple OSS Distributions 	task_t task = mach_task_self();
174*fdd8201dSApple OSS Distributions 	uint64_t counts[2] = { 0 };
175*fdd8201dSApple OSS Distributions 	unsigned int size = 0;
176*fdd8201dSApple OSS Distributions 	while (true) {
177*fdd8201dSApple OSS Distributions 		size = (unsigned int)sizeof(counts);
178*fdd8201dSApple OSS Distributions 		(void)task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
179*fdd8201dSApple OSS Distributions 		    (task_inspect_info_t)&counts[0], &size);
180*fdd8201dSApple OSS Distributions 		/*
181*fdd8201dSApple OSS Distributions 		 * Not realistic for a process to see count values with the high bit
182*fdd8201dSApple OSS Distributions 		 * set, but kernel pointers will be that high.
183*fdd8201dSApple OSS Distributions 		 */
184*fdd8201dSApple OSS Distributions 		T_QUIET; T_ASSERT_LT(counts[0], 1ULL << 63,
185*fdd8201dSApple OSS Distributions 		        "check for valid count entry 1");
186*fdd8201dSApple OSS Distributions 		T_QUIET; T_ASSERT_LT(counts[1], 1ULL << 63,
187*fdd8201dSApple OSS Distributions 		        "check for valid count entry 2");
188*fdd8201dSApple OSS Distributions 	}
189*fdd8201dSApple OSS Distributions }
190*fdd8201dSApple OSS Distributions 
191*fdd8201dSApple OSS Distributions T_DECL(core_fixed_stack_leak_race,
192*fdd8201dSApple OSS Distributions     "ensure no stack data is leaked by TASK_INSPECT_BASIC_COUNTS")
193*fdd8201dSApple OSS Distributions {
194*fdd8201dSApple OSS Distributions 	T_SETUPBEGIN;
195*fdd8201dSApple OSS Distributions 
196*fdd8201dSApple OSS Distributions 	int ncpus = 0;
197*fdd8201dSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("hw.logicalcpu_max", &ncpus,
198*fdd8201dSApple OSS Distributions 	    &(size_t){ sizeof(ncpus) }, NULL, 0), "get number of CPUs");
199*fdd8201dSApple OSS Distributions 	T_QUIET; T_ASSERT_GT(ncpus, 0, "got non-zero number of CPUs");
200*fdd8201dSApple OSS Distributions 	pthread_t *threads = calloc((unsigned long)ncpus, sizeof(*threads));
201*fdd8201dSApple OSS Distributions 
202*fdd8201dSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(threads, "allocated space for threads");
203*fdd8201dSApple OSS Distributions 
204*fdd8201dSApple OSS Distributions 	T_LOG("creating %d threads to attempt to race around task counts", ncpus);
205*fdd8201dSApple OSS Distributions 	/*
206*fdd8201dSApple OSS Distributions 	 * Have half the threads hammering thread_self_counts and the other half
207*fdd8201dSApple OSS Distributions 	 * trying to get an error to occur inside TASK_INSPECT_BASIC_COUNTS and see
208*fdd8201dSApple OSS Distributions 	 * uninitialized kernel memory.
209*fdd8201dSApple OSS Distributions 	 */
210*fdd8201dSApple OSS Distributions 	for (int i = 0; i < ncpus; i++) {
211*fdd8201dSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&threads[i], NULL,
212*fdd8201dSApple OSS Distributions 		    i & 1 ? spin_task_inspect : spin_thread_self_counts, NULL),
213*fdd8201dSApple OSS Distributions 		    NULL);
214*fdd8201dSApple OSS Distributions 	}
215*fdd8201dSApple OSS Distributions 
216*fdd8201dSApple OSS Distributions 	T_SETUPEND;
217*fdd8201dSApple OSS Distributions 
218*fdd8201dSApple OSS Distributions 	sleep(10);
219*fdd8201dSApple OSS Distributions 	T_PASS("ending test after 10 seconds");
220*fdd8201dSApple OSS Distributions }
221*fdd8201dSApple OSS Distributions 
222*fdd8201dSApple OSS Distributions static void
perf_sysctl_deltas(const char * sysctl_name,const char * stat_name)223*fdd8201dSApple OSS Distributions perf_sysctl_deltas(const char *sysctl_name, const char *stat_name)
224*fdd8201dSApple OSS Distributions {
225*fdd8201dSApple OSS Distributions 	uint64_t deltas[2];
226*fdd8201dSApple OSS Distributions 	size_t deltas_size;
227*fdd8201dSApple OSS Distributions 	int r;
228*fdd8201dSApple OSS Distributions 
229*fdd8201dSApple OSS Distributions 	T_SETUPBEGIN;
230*fdd8201dSApple OSS Distributions 	skip_if_unsupported();
231*fdd8201dSApple OSS Distributions 
232*fdd8201dSApple OSS Distributions 	dt_stat_t instrs = dt_stat_create("instructions", "%s_instrs",
233*fdd8201dSApple OSS Distributions 	    stat_name);
234*fdd8201dSApple OSS Distributions 	dt_stat_t cycles = dt_stat_create("cycles", "%s_cycles", stat_name);
235*fdd8201dSApple OSS Distributions 	T_SETUPEND;
236*fdd8201dSApple OSS Distributions 
237*fdd8201dSApple OSS Distributions 	while (!dt_stat_stable(instrs) || !dt_stat_stable(cycles)) {
238*fdd8201dSApple OSS Distributions 		deltas_size = sizeof(deltas);
239*fdd8201dSApple OSS Distributions 		r = sysctlbyname(sysctl_name, deltas, &deltas_size, NULL, 0);
240*fdd8201dSApple OSS Distributions 		T_QUIET;
241*fdd8201dSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"%s\", ...)", sysctl_name);
242*fdd8201dSApple OSS Distributions 		dt_stat_add(instrs, (double)deltas[0]);
243*fdd8201dSApple OSS Distributions 		dt_stat_add(cycles, (double)deltas[1]);
244*fdd8201dSApple OSS Distributions 	}
245*fdd8201dSApple OSS Distributions 
246*fdd8201dSApple OSS Distributions 	dt_stat_finalize(instrs);
247*fdd8201dSApple OSS Distributions 	dt_stat_finalize(cycles);
248*fdd8201dSApple OSS Distributions }
249*fdd8201dSApple OSS Distributions 
250*fdd8201dSApple OSS Distributions T_DECL(perf_core_fixed_cpu, "test the performance of fixed CPU counter access",
251*fdd8201dSApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_PERF)
252*fdd8201dSApple OSS Distributions {
253*fdd8201dSApple OSS Distributions 	perf_sysctl_deltas("kern.monotonic.fixed_cpu_perf", "fixed_cpu_counters");
254*fdd8201dSApple OSS Distributions }
255*fdd8201dSApple OSS Distributions 
256*fdd8201dSApple OSS Distributions T_DECL(perf_core_fixed_thread, "test the performance of fixed thread counter access",
257*fdd8201dSApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_PERF)
258*fdd8201dSApple OSS Distributions {
259*fdd8201dSApple OSS Distributions 	perf_sysctl_deltas("kern.monotonic.fixed_thread_perf",
260*fdd8201dSApple OSS Distributions 	    "fixed_thread_counters");
261*fdd8201dSApple OSS Distributions }
262*fdd8201dSApple OSS Distributions 
263*fdd8201dSApple OSS Distributions T_DECL(perf_core_fixed_task, "test the performance of fixed task counter access",
264*fdd8201dSApple OSS Distributions     T_META_ASROOT(true), T_META_TAG_PERF)
265*fdd8201dSApple OSS Distributions {
266*fdd8201dSApple OSS Distributions 	perf_sysctl_deltas("kern.monotonic.fixed_task_perf", "fixed_task_counters");
267*fdd8201dSApple OSS Distributions }
268*fdd8201dSApple OSS Distributions 
269*fdd8201dSApple OSS Distributions T_DECL(perf_core_fixed_thread_self, "test the performance of thread self counts",
270*fdd8201dSApple OSS Distributions     T_META_TAG_PERF)
271*fdd8201dSApple OSS Distributions {
272*fdd8201dSApple OSS Distributions 	struct thsc_cpi counts[2];
273*fdd8201dSApple OSS Distributions 
274*fdd8201dSApple OSS Distributions 	T_SETUPBEGIN;
275*fdd8201dSApple OSS Distributions 	dt_stat_t instrs = dt_stat_create("fixed_thread_self_instrs", "instructions");
276*fdd8201dSApple OSS Distributions 	dt_stat_t cycles = dt_stat_create("fixed_thread_self_cycles", "cycles");
277*fdd8201dSApple OSS Distributions 
278*fdd8201dSApple OSS Distributions 	skip_if_unsupported();
279*fdd8201dSApple OSS Distributions 	T_SETUPEND;
280*fdd8201dSApple OSS Distributions 
281*fdd8201dSApple OSS Distributions 	while (!dt_stat_stable(instrs) || !dt_stat_stable(cycles)) {
282*fdd8201dSApple OSS Distributions 		int r1, r2;
283*fdd8201dSApple OSS Distributions 
284*fdd8201dSApple OSS Distributions 		r1 = thread_selfcounts_cpi(&counts[0]);
285*fdd8201dSApple OSS Distributions 		r2 = thread_selfcounts_cpi(&counts[1]);
286*fdd8201dSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(r1, "thread_selfcounts");
287*fdd8201dSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(r2, "thread_selfcounts");
288*fdd8201dSApple OSS Distributions 
289*fdd8201dSApple OSS Distributions 		dt_stat_add(instrs, counts[1].tcpi_instructions - counts[0].tcpi_instructions);
290*fdd8201dSApple OSS Distributions 		dt_stat_add(cycles, counts[1].tcpi_cycles - counts[0].tcpi_cycles);
291*fdd8201dSApple OSS Distributions 	}
292*fdd8201dSApple OSS Distributions 
293*fdd8201dSApple OSS Distributions 	dt_stat_finalize(instrs);
294*fdd8201dSApple OSS Distributions 	dt_stat_finalize(cycles);
295*fdd8201dSApple OSS Distributions }
296