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