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