xref: /xnu-8792.61.2/bsd/kern/counter_test.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1*42e22086SApple OSS Distributions /* * Copyright (c) 2020 Apple Inc. All rights reserved.
2*42e22086SApple OSS Distributions  *
3*42e22086SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
4*42e22086SApple OSS Distributions  *
5*42e22086SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
6*42e22086SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
7*42e22086SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
8*42e22086SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
9*42e22086SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
10*42e22086SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
11*42e22086SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
12*42e22086SApple OSS Distributions  * terms of an Apple operating system software license agreement.
13*42e22086SApple OSS Distributions  *
14*42e22086SApple OSS Distributions  * Please obtain a copy of the License at
15*42e22086SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
16*42e22086SApple OSS Distributions  *
17*42e22086SApple OSS Distributions  * The Original Code and all software distributed under the License are
18*42e22086SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
19*42e22086SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
20*42e22086SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
21*42e22086SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
22*42e22086SApple OSS Distributions  * Please see the License for the specific language governing rights and
23*42e22086SApple OSS Distributions  * limitations under the License.
24*42e22086SApple OSS Distributions  *
25*42e22086SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
26*42e22086SApple OSS Distributions  */
27*42e22086SApple OSS Distributions 
28*42e22086SApple OSS Distributions /* sysctl interface for testing percpu counters in DEBUG or DEVELOPMENT kernel only. */
29*42e22086SApple OSS Distributions #if !(DEVELOPMENT || DEBUG)
30*42e22086SApple OSS Distributions #error "Counter testing is not enabled on RELEASE configurations"
31*42e22086SApple OSS Distributions #endif
32*42e22086SApple OSS Distributions 
33*42e22086SApple OSS Distributions #include <sys/sysctl.h>
34*42e22086SApple OSS Distributions #include <kern/counter.h>
35*42e22086SApple OSS Distributions #include <machine/atomic.h>
36*42e22086SApple OSS Distributions #include <libkern/libkern.h>
37*42e22086SApple OSS Distributions #include <machine/machine_routines.h>
38*42e22086SApple OSS Distributions #include <kern/cpu_data.h>
39*42e22086SApple OSS Distributions 
40*42e22086SApple OSS Distributions #include <os/log.h>
41*42e22086SApple OSS Distributions 
42*42e22086SApple OSS Distributions #ifdef CONFIG_XNUPOST
43*42e22086SApple OSS Distributions #include <tests/xnupost.h>
44*42e22086SApple OSS Distributions #endif /* CONFIG_XNUPOST */
45*42e22086SApple OSS Distributions 
46*42e22086SApple OSS Distributions static _Atomic boolean_t scalable_counter_test_running = FALSE;
47*42e22086SApple OSS Distributions scalable_counter_t test_scalable_counter;
48*42e22086SApple OSS Distributions 
49*42e22086SApple OSS Distributions SCALABLE_COUNTER_DEFINE(test_static_scalable_counter);
50*42e22086SApple OSS Distributions 
51*42e22086SApple OSS Distributions #ifdef CONFIG_XNUPOST
52*42e22086SApple OSS Distributions kern_return_t counter_tests(void);
53*42e22086SApple OSS Distributions /*
54*42e22086SApple OSS Distributions  * Sanity test that a counter can be modified before zalloc is initialized.
55*42e22086SApple OSS Distributions  */
56*42e22086SApple OSS Distributions static void
bump_static_counter(void * arg)57*42e22086SApple OSS Distributions bump_static_counter(void* arg)
58*42e22086SApple OSS Distributions {
59*42e22086SApple OSS Distributions 	(void) arg;
60*42e22086SApple OSS Distributions 	counter_inc(&test_static_scalable_counter);
61*42e22086SApple OSS Distributions }
62*42e22086SApple OSS Distributions 
63*42e22086SApple OSS Distributions STARTUP_ARG(PMAP_STEAL, STARTUP_RANK_MIDDLE, bump_static_counter, NULL);
64*42e22086SApple OSS Distributions 
65*42e22086SApple OSS Distributions kern_return_t
counter_tests()66*42e22086SApple OSS Distributions counter_tests()
67*42e22086SApple OSS Distributions {
68*42e22086SApple OSS Distributions 	T_ASSERT_EQ_ULLONG(counter_load(&test_static_scalable_counter), 1, "Counter was incremented");
69*42e22086SApple OSS Distributions 	return KERN_SUCCESS;
70*42e22086SApple OSS Distributions }
71*42e22086SApple OSS Distributions #endif /* CONFIG_XNUPOST */
72*42e22086SApple OSS Distributions 
73*42e22086SApple OSS Distributions static int
74*42e22086SApple OSS Distributions sysctl_scalable_counter_test_start SYSCTL_HANDLER_ARGS
75*42e22086SApple OSS Distributions {
76*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
77*42e22086SApple OSS Distributions 	int ret_val = 1;
78*42e22086SApple OSS Distributions 	int error = 0;
79*42e22086SApple OSS Distributions 	boolean_t exclusive;
80*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, ret_val, sizeof(int), &ret_val, NULL);
81*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
82*42e22086SApple OSS Distributions 		return error;
83*42e22086SApple OSS Distributions 	}
84*42e22086SApple OSS Distributions 	/* The test doesn't support being run multiple times in parallel. */
85*42e22086SApple OSS Distributions 	exclusive = os_atomic_cmpxchg(&scalable_counter_test_running, FALSE, TRUE, seq_cst);
86*42e22086SApple OSS Distributions 	if (!exclusive) {
87*42e22086SApple OSS Distributions 		os_log(OS_LOG_DEFAULT, "scalable_counter_test: Caught attempt to run the test in parallel.");
88*42e22086SApple OSS Distributions 		return EINVAL;
89*42e22086SApple OSS Distributions 	}
90*42e22086SApple OSS Distributions 	counter_alloc(&test_scalable_counter);
91*42e22086SApple OSS Distributions 	return 0;
92*42e22086SApple OSS Distributions }
93*42e22086SApple OSS Distributions 
94*42e22086SApple OSS Distributions static int
95*42e22086SApple OSS Distributions sysctl_scalable_counter_test_finish SYSCTL_HANDLER_ARGS
96*42e22086SApple OSS Distributions {
97*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
98*42e22086SApple OSS Distributions 	boolean_t exclusive;
99*42e22086SApple OSS Distributions 	int ret_val = 0;
100*42e22086SApple OSS Distributions 	int error = 0;
101*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, ret_val, sizeof(int), &ret_val, NULL);
102*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
103*42e22086SApple OSS Distributions 		return error;
104*42e22086SApple OSS Distributions 	}
105*42e22086SApple OSS Distributions 
106*42e22086SApple OSS Distributions 	/* The test doesn't support being run multiple times in parallel. */
107*42e22086SApple OSS Distributions 	exclusive = os_atomic_cmpxchg(&scalable_counter_test_running, TRUE, FALSE, seq_cst);
108*42e22086SApple OSS Distributions 	if (!exclusive) {
109*42e22086SApple OSS Distributions 		/* Finish called without start. */
110*42e22086SApple OSS Distributions 		return EINVAL;
111*42e22086SApple OSS Distributions 	}
112*42e22086SApple OSS Distributions 	return 0;
113*42e22086SApple OSS Distributions }
114*42e22086SApple OSS Distributions 
115*42e22086SApple OSS Distributions static int
116*42e22086SApple OSS Distributions sysctl_scalable_counter_add SYSCTL_HANDLER_ARGS
117*42e22086SApple OSS Distributions {
118*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
119*42e22086SApple OSS Distributions 	int64_t value = 0;
120*42e22086SApple OSS Distributions 	int error = 0;
121*42e22086SApple OSS Distributions 	if (!os_atomic_load(&scalable_counter_test_running, seq_cst)) {
122*42e22086SApple OSS Distributions 		/* Must call start */
123*42e22086SApple OSS Distributions 		return EINVAL;
124*42e22086SApple OSS Distributions 	}
125*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, value, sizeof(int64_t), &value, NULL);
126*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
127*42e22086SApple OSS Distributions 		return error;
128*42e22086SApple OSS Distributions 	}
129*42e22086SApple OSS Distributions 	counter_add(&test_scalable_counter, value);
130*42e22086SApple OSS Distributions 	return 0;
131*42e22086SApple OSS Distributions }
132*42e22086SApple OSS Distributions 
133*42e22086SApple OSS Distributions static int
134*42e22086SApple OSS Distributions sysctl_static_scalable_counter_add SYSCTL_HANDLER_ARGS
135*42e22086SApple OSS Distributions {
136*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
137*42e22086SApple OSS Distributions 	int64_t value = 0;
138*42e22086SApple OSS Distributions 	int error = 0;
139*42e22086SApple OSS Distributions 	if (!os_atomic_load(&scalable_counter_test_running, seq_cst)) {
140*42e22086SApple OSS Distributions 		/* Must call start */
141*42e22086SApple OSS Distributions 		return EINVAL;
142*42e22086SApple OSS Distributions 	}
143*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, value, sizeof(int64_t), &value, NULL);
144*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
145*42e22086SApple OSS Distributions 		return error;
146*42e22086SApple OSS Distributions 	}
147*42e22086SApple OSS Distributions 	counter_add(&test_static_scalable_counter, value);
148*42e22086SApple OSS Distributions 	return 0;
149*42e22086SApple OSS Distributions }
150*42e22086SApple OSS Distributions 
151*42e22086SApple OSS Distributions static int
152*42e22086SApple OSS Distributions sysctl_scalable_counter_load SYSCTL_HANDLER_ARGS
153*42e22086SApple OSS Distributions {
154*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
155*42e22086SApple OSS Distributions 	uint64_t value;
156*42e22086SApple OSS Distributions 	if (!os_atomic_load(&scalable_counter_test_running, seq_cst)) {
157*42e22086SApple OSS Distributions 		/* Must call start */
158*42e22086SApple OSS Distributions 		return EINVAL;
159*42e22086SApple OSS Distributions 	}
160*42e22086SApple OSS Distributions 	value = counter_load(&test_scalable_counter);
161*42e22086SApple OSS Distributions 	return SYSCTL_OUT(req, &value, sizeof(value));
162*42e22086SApple OSS Distributions }
163*42e22086SApple OSS Distributions 
164*42e22086SApple OSS Distributions static int
165*42e22086SApple OSS Distributions sysctl_scalable_counter_write_benchmark SYSCTL_HANDLER_ARGS
166*42e22086SApple OSS Distributions {
167*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
168*42e22086SApple OSS Distributions 	int error;
169*42e22086SApple OSS Distributions 	int64_t iterations;
170*42e22086SApple OSS Distributions 	int ret_val = 0;
171*42e22086SApple OSS Distributions 	if (!os_atomic_load(&scalable_counter_test_running, seq_cst)) {
172*42e22086SApple OSS Distributions 		/* Must call start */
173*42e22086SApple OSS Distributions 		return EINVAL;
174*42e22086SApple OSS Distributions 	}
175*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, ret_val, sizeof(int), &iterations, NULL);
176*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
177*42e22086SApple OSS Distributions 		return error;
178*42e22086SApple OSS Distributions 	}
179*42e22086SApple OSS Distributions 	for (int64_t i = 0; i < iterations; i++) {
180*42e22086SApple OSS Distributions 		counter_inc(&test_scalable_counter);
181*42e22086SApple OSS Distributions 	}
182*42e22086SApple OSS Distributions 	return 0;
183*42e22086SApple OSS Distributions }
184*42e22086SApple OSS Distributions 
185*42e22086SApple OSS Distributions static volatile uint64_t racy_counter;
186*42e22086SApple OSS Distributions 
187*42e22086SApple OSS Distributions static int
188*42e22086SApple OSS Distributions sysctl_racy_counter_write_benchmark SYSCTL_HANDLER_ARGS
189*42e22086SApple OSS Distributions {
190*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
191*42e22086SApple OSS Distributions 	int error;
192*42e22086SApple OSS Distributions 	int64_t iterations;
193*42e22086SApple OSS Distributions 	int ret_val = 0;
194*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, ret_val, sizeof(int), &iterations, NULL);
195*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
196*42e22086SApple OSS Distributions 		return error;
197*42e22086SApple OSS Distributions 	}
198*42e22086SApple OSS Distributions 	for (int64_t i = 0; i < iterations; i++) {
199*42e22086SApple OSS Distributions 		racy_counter++;
200*42e22086SApple OSS Distributions 	}
201*42e22086SApple OSS Distributions 	return 0;
202*42e22086SApple OSS Distributions }
203*42e22086SApple OSS Distributions 
204*42e22086SApple OSS Distributions static int
205*42e22086SApple OSS Distributions sysctl_racy_counter_load SYSCTL_HANDLER_ARGS
206*42e22086SApple OSS Distributions {
207*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
208*42e22086SApple OSS Distributions 	uint64_t value = racy_counter;
209*42e22086SApple OSS Distributions 	return SYSCTL_OUT(req, &value, sizeof(value));
210*42e22086SApple OSS Distributions }
211*42e22086SApple OSS Distributions 
212*42e22086SApple OSS Distributions static _Atomic uint64_t atomic_counter;
213*42e22086SApple OSS Distributions 
214*42e22086SApple OSS Distributions static int
215*42e22086SApple OSS Distributions sysctl_atomic_counter_write_benchmark SYSCTL_HANDLER_ARGS
216*42e22086SApple OSS Distributions {
217*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
218*42e22086SApple OSS Distributions 	int error;
219*42e22086SApple OSS Distributions 	int64_t iterations;
220*42e22086SApple OSS Distributions 	int ret_val = 0;
221*42e22086SApple OSS Distributions 	error = sysctl_io_number(req, ret_val, sizeof(int), &iterations, NULL);
222*42e22086SApple OSS Distributions 	if (error || !req->newptr) {
223*42e22086SApple OSS Distributions 		return error;
224*42e22086SApple OSS Distributions 	}
225*42e22086SApple OSS Distributions 	for (int64_t i = 0; i < iterations; i++) {
226*42e22086SApple OSS Distributions 		os_atomic_add(&atomic_counter, 1, relaxed);
227*42e22086SApple OSS Distributions 	}
228*42e22086SApple OSS Distributions 	return 0;
229*42e22086SApple OSS Distributions }
230*42e22086SApple OSS Distributions 
231*42e22086SApple OSS Distributions static int
232*42e22086SApple OSS Distributions sysctl_atomic_counter_load SYSCTL_HANDLER_ARGS
233*42e22086SApple OSS Distributions {
234*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
235*42e22086SApple OSS Distributions 	uint64_t value = os_atomic_load_wide(&atomic_counter, relaxed);
236*42e22086SApple OSS Distributions 	return SYSCTL_OUT(req, &value, sizeof(value));
237*42e22086SApple OSS Distributions }
238*42e22086SApple OSS Distributions 
239*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_test_start,
240*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
241*42e22086SApple OSS Distributions     0, 0, sysctl_scalable_counter_test_start, "I", "Setup per-cpu counter test");
242*42e22086SApple OSS Distributions 
243*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_test_finish,
244*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
245*42e22086SApple OSS Distributions     0, 0, sysctl_scalable_counter_test_finish, "I", "Finish per-cpu counter test");
246*42e22086SApple OSS Distributions 
247*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_test_add,
248*42e22086SApple OSS Distributions     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
249*42e22086SApple OSS Distributions     0, 0, sysctl_scalable_counter_add, "I", "Perform an add on the per-cpu counter");
250*42e22086SApple OSS Distributions 
251*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, static_scalable_counter_test_add,
252*42e22086SApple OSS Distributions     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
253*42e22086SApple OSS Distributions     0, 0, sysctl_static_scalable_counter_add, "I", "Perform an add on the static per-cpu counter");
254*42e22086SApple OSS Distributions 
255*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_test_load,
256*42e22086SApple OSS Distributions     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
257*42e22086SApple OSS Distributions     0, 0, sysctl_scalable_counter_load, "I", "Load the current per-cpu counter value.");
258*42e22086SApple OSS Distributions 
259*42e22086SApple OSS Distributions SYSCTL_SCALABLE_COUNTER(_kern, static_scalable_counter_test_load,
260*42e22086SApple OSS Distributions     test_static_scalable_counter, "Load the current static per-cpu counter value.");
261*42e22086SApple OSS Distributions 
262*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_write_benchmark,
263*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
264*42e22086SApple OSS Distributions     0, 0, sysctl_scalable_counter_write_benchmark, "I", "Per-cpu counter write benchmark");
265*42e22086SApple OSS Distributions 
266*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_racy_counter_benchmark,
267*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
268*42e22086SApple OSS Distributions     0, 0, sysctl_racy_counter_write_benchmark, "I", "Global counter racy benchmark");
269*42e22086SApple OSS Distributions 
270*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_racy_counter_load,
271*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
272*42e22086SApple OSS Distributions     0, 0, sysctl_racy_counter_load, "I", "Global counter racy load");
273*42e22086SApple OSS Distributions 
274*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_atomic_counter_write_benchmark,
275*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
276*42e22086SApple OSS Distributions     0, 0, sysctl_atomic_counter_write_benchmark, "I", "Atomic counter write benchmark");
277*42e22086SApple OSS Distributions 
278*42e22086SApple OSS Distributions SYSCTL_PROC(_kern, OID_AUTO, scalable_counter_atomic_counter_load,
279*42e22086SApple OSS Distributions     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MASKED | CTLFLAG_LOCKED,
280*42e22086SApple OSS Distributions     0, 0, sysctl_atomic_counter_load, "I", "Atomic counter load");
281