xref: /xnu-8796.101.5/tests/counter/counter.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1*aca3beaaSApple OSS Distributions #include <stdatomic.h>
2*aca3beaaSApple OSS Distributions #include <sys/kern_sysctl.h>
3*aca3beaaSApple OSS Distributions 
4*aca3beaaSApple OSS Distributions #include <darwintest_utils.h>
5*aca3beaaSApple OSS Distributions #include <darwintest.h>
6*aca3beaaSApple OSS Distributions 
7*aca3beaaSApple OSS Distributions #include "counter/common.h"
8*aca3beaaSApple OSS Distributions #include "test_utils.h"
9*aca3beaaSApple OSS Distributions 
10*aca3beaaSApple OSS Distributions static unsigned int ncpu(void);
11*aca3beaaSApple OSS Distributions 
12*aca3beaaSApple OSS Distributions static uint64_t
sysctl_read(const char * name)13*aca3beaaSApple OSS Distributions sysctl_read(const char *name)
14*aca3beaaSApple OSS Distributions {
15*aca3beaaSApple OSS Distributions 	int result;
16*aca3beaaSApple OSS Distributions 	uint64_t value;
17*aca3beaaSApple OSS Distributions 	size_t size = sizeof(value);
18*aca3beaaSApple OSS Distributions 	result = sysctlbyname(name, &value, &size, NULL, 0);
19*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(result, "Read from %s", name);
20*aca3beaaSApple OSS Distributions 	return value;
21*aca3beaaSApple OSS Distributions }
22*aca3beaaSApple OSS Distributions 
23*aca3beaaSApple OSS Distributions static void
sysctl_write(const char * name,int64_t amount)24*aca3beaaSApple OSS Distributions sysctl_write(const char* name, int64_t amount)
25*aca3beaaSApple OSS Distributions {
26*aca3beaaSApple OSS Distributions 	kern_return_t result;
27*aca3beaaSApple OSS Distributions 	result = sysctlbyname(name, NULL, NULL, &amount, sizeof(int64_t));
28*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(result, "Write to %s", name);
29*aca3beaaSApple OSS Distributions }
30*aca3beaaSApple OSS Distributions 
31*aca3beaaSApple OSS Distributions static void
scalable_counter_add(int64_t amount)32*aca3beaaSApple OSS Distributions scalable_counter_add(int64_t amount)
33*aca3beaaSApple OSS Distributions {
34*aca3beaaSApple OSS Distributions 	sysctl_write("kern.scalable_counter_test_add", amount);
35*aca3beaaSApple OSS Distributions }
36*aca3beaaSApple OSS Distributions 
37*aca3beaaSApple OSS Distributions static void
static_scalable_counter_add(int64_t amount)38*aca3beaaSApple OSS Distributions static_scalable_counter_add(int64_t amount)
39*aca3beaaSApple OSS Distributions {
40*aca3beaaSApple OSS Distributions 	sysctl_write("kern.static_scalable_counter_test_add", amount);
41*aca3beaaSApple OSS Distributions }
42*aca3beaaSApple OSS Distributions 
43*aca3beaaSApple OSS Distributions static int64_t
scalable_counter_load(void)44*aca3beaaSApple OSS Distributions scalable_counter_load(void)
45*aca3beaaSApple OSS Distributions {
46*aca3beaaSApple OSS Distributions 	return (int64_t) sysctl_read("kern.scalable_counter_test_load");
47*aca3beaaSApple OSS Distributions }
48*aca3beaaSApple OSS Distributions 
49*aca3beaaSApple OSS Distributions static int64_t
static_scalable_counter_load(void)50*aca3beaaSApple OSS Distributions static_scalable_counter_load(void)
51*aca3beaaSApple OSS Distributions {
52*aca3beaaSApple OSS Distributions 	return (int64_t) sysctl_read("kern.static_scalable_counter_test_load");
53*aca3beaaSApple OSS Distributions }
54*aca3beaaSApple OSS Distributions 
55*aca3beaaSApple OSS Distributions /*
56*aca3beaaSApple OSS Distributions  * A background thread that bangs on the percpu counter and then exits.
57*aca3beaaSApple OSS Distributions  * @param num_iterations How many times to bang on the counter. Each iteration makes the counter
58*aca3beaaSApple OSS Distributions  * bigger by 100.
59*aca3beaaSApple OSS Distributions  */
60*aca3beaaSApple OSS Distributions static void*
background_scalable_counter_thread(void * num_iterations_ptr)61*aca3beaaSApple OSS Distributions background_scalable_counter_thread(void* num_iterations_ptr)
62*aca3beaaSApple OSS Distributions {
63*aca3beaaSApple OSS Distributions 	int64_t i, num_iterations;
64*aca3beaaSApple OSS Distributions 	num_iterations = (int64_t)(num_iterations_ptr);
65*aca3beaaSApple OSS Distributions 	for (i = 0; i < num_iterations; i++) {
66*aca3beaaSApple OSS Distributions 		scalable_counter_add(-25);
67*aca3beaaSApple OSS Distributions 		scalable_counter_add(75);
68*aca3beaaSApple OSS Distributions 		scalable_counter_add(-100);
69*aca3beaaSApple OSS Distributions 		scalable_counter_add(150);
70*aca3beaaSApple OSS Distributions 	}
71*aca3beaaSApple OSS Distributions 	atomic_thread_fence(memory_order_release);
72*aca3beaaSApple OSS Distributions 	return 0;
73*aca3beaaSApple OSS Distributions }
74*aca3beaaSApple OSS Distributions 
75*aca3beaaSApple OSS Distributions static
76*aca3beaaSApple OSS Distributions void
darwin_test_fini_scalable_counter_test()77*aca3beaaSApple OSS Distributions darwin_test_fini_scalable_counter_test()
78*aca3beaaSApple OSS Distributions {
79*aca3beaaSApple OSS Distributions 	int ret = fini_scalable_counter_test();
80*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "fini_scalable_counter_test");
81*aca3beaaSApple OSS Distributions }
82*aca3beaaSApple OSS Distributions 
83*aca3beaaSApple OSS Distributions static
84*aca3beaaSApple OSS Distributions void
darwin_test_setup(void)85*aca3beaaSApple OSS Distributions darwin_test_setup(void)
86*aca3beaaSApple OSS Distributions {
87*aca3beaaSApple OSS Distributions 	T_SETUPBEGIN;
88*aca3beaaSApple OSS Distributions 	int dev_kernel = is_development_kernel();
89*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(dev_kernel, "sysctlbyname kern.development");
90*aca3beaaSApple OSS Distributions 	if (is_development_kernel() != 1) {
91*aca3beaaSApple OSS Distributions 		T_SKIP("Skipping test on non development kernel.");
92*aca3beaaSApple OSS Distributions 	}
93*aca3beaaSApple OSS Distributions 	init_scalable_counter_test();
94*aca3beaaSApple OSS Distributions 	T_SETUPEND;
95*aca3beaaSApple OSS Distributions 	T_ATEND(darwin_test_fini_scalable_counter_test);
96*aca3beaaSApple OSS Distributions }
97*aca3beaaSApple OSS Distributions 
98*aca3beaaSApple OSS Distributions T_DECL(test_scalable_counters_single_threaded, "Test single threaded operations on scalable_counters", T_META_ASROOT(true))
99*aca3beaaSApple OSS Distributions {
100*aca3beaaSApple OSS Distributions 	static int64_t kNumIterations = 100, i, expected_value = 0;
101*aca3beaaSApple OSS Distributions 	darwin_test_setup();
102*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(scalable_counter_load(), 0LL, "Counter starts at zero");
103*aca3beaaSApple OSS Distributions 
104*aca3beaaSApple OSS Distributions 	/* Simple add, subtract, and read */
105*aca3beaaSApple OSS Distributions 	scalable_counter_add(1);
106*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(scalable_counter_load(), 1LL, "0 + 1 == 1");
107*aca3beaaSApple OSS Distributions 	scalable_counter_add(-1);
108*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(scalable_counter_load(), 0LL, "1 - 1 == 0");
109*aca3beaaSApple OSS Distributions 	for (i = 0; i < kNumIterations; i++) {
110*aca3beaaSApple OSS Distributions 		scalable_counter_add(i);
111*aca3beaaSApple OSS Distributions 		expected_value += i;
112*aca3beaaSApple OSS Distributions 	}
113*aca3beaaSApple OSS Distributions 	for (i = 0; i < kNumIterations / 2; i++) {
114*aca3beaaSApple OSS Distributions 		scalable_counter_add(-i);
115*aca3beaaSApple OSS Distributions 		expected_value -= i;
116*aca3beaaSApple OSS Distributions 	}
117*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(scalable_counter_load(), expected_value, "Counter value is correct.");
118*aca3beaaSApple OSS Distributions 	T_END;
119*aca3beaaSApple OSS Distributions }
120*aca3beaaSApple OSS Distributions 
121*aca3beaaSApple OSS Distributions T_DECL(test_static_counter, "Test staticly declared counter", T_META_ASROOT(true))
122*aca3beaaSApple OSS Distributions {
123*aca3beaaSApple OSS Distributions 	static size_t kNumIterations = 100;
124*aca3beaaSApple OSS Distributions 	int64_t start_value;
125*aca3beaaSApple OSS Distributions 	darwin_test_setup();
126*aca3beaaSApple OSS Distributions 	start_value = static_scalable_counter_load();
127*aca3beaaSApple OSS Distributions 	for (size_t i = 0; i < kNumIterations; i++) {
128*aca3beaaSApple OSS Distributions 		static_scalable_counter_add(1);
129*aca3beaaSApple OSS Distributions 	}
130*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(static_scalable_counter_load(), (long long) kNumIterations + start_value, "Counter value is correct");
131*aca3beaaSApple OSS Distributions 	T_END;
132*aca3beaaSApple OSS Distributions }
133*aca3beaaSApple OSS Distributions 
134*aca3beaaSApple OSS Distributions T_DECL(test_scalable_counters_multithreaded, "Test multi-threaded operations on scalable_counters", T_META_ASROOT(true))
135*aca3beaaSApple OSS Distributions {
136*aca3beaaSApple OSS Distributions 	unsigned int kNumThreads = ncpu() * 5;
137*aca3beaaSApple OSS Distributions 	int ret;
138*aca3beaaSApple OSS Distributions 	int64_t i;
139*aca3beaaSApple OSS Distributions 	pthread_attr_t pthread_attr;
140*aca3beaaSApple OSS Distributions 	pthread_t *threads;
141*aca3beaaSApple OSS Distributions 
142*aca3beaaSApple OSS Distributions 	darwin_test_setup();
143*aca3beaaSApple OSS Distributions 
144*aca3beaaSApple OSS Distributions 	threads = malloc(sizeof(pthread_t) * kNumThreads);
145*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(threads, "Out of memory");
146*aca3beaaSApple OSS Distributions 
147*aca3beaaSApple OSS Distributions 	ret = pthread_attr_init(&pthread_attr);
148*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_attr_init");
149*aca3beaaSApple OSS Distributions 
150*aca3beaaSApple OSS Distributions 	int64_t expected_value = 0;
151*aca3beaaSApple OSS Distributions 	for (i = 0; i < kNumThreads; i++) {
152*aca3beaaSApple OSS Distributions 		ret = pthread_create(&threads[i], &pthread_attr, background_scalable_counter_thread, (void*)(i));
153*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_create");
154*aca3beaaSApple OSS Distributions 		expected_value += 100 * i;
155*aca3beaaSApple OSS Distributions 	}
156*aca3beaaSApple OSS Distributions 
157*aca3beaaSApple OSS Distributions 	for (i = 0; i < kNumThreads; i++) {
158*aca3beaaSApple OSS Distributions 		void *exit_code;
159*aca3beaaSApple OSS Distributions 		ret = pthread_join(threads[i], &exit_code);
160*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_join");
161*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_EQ((ptrdiff_t) exit_code, (ptrdiff_t) 0, "Background thread exited sucessfully.");
162*aca3beaaSApple OSS Distributions 	}
163*aca3beaaSApple OSS Distributions 	atomic_thread_fence(memory_order_acquire);
164*aca3beaaSApple OSS Distributions 
165*aca3beaaSApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(scalable_counter_load(), expected_value, "Counter value is correct.");
166*aca3beaaSApple OSS Distributions 
167*aca3beaaSApple OSS Distributions 	ret = pthread_attr_destroy(&pthread_attr);
168*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "pthread_attr_destroy");
169*aca3beaaSApple OSS Distributions 	free(threads);
170*aca3beaaSApple OSS Distributions }
171*aca3beaaSApple OSS Distributions 
172*aca3beaaSApple OSS Distributions static unsigned int
ncpu()173*aca3beaaSApple OSS Distributions ncpu()
174*aca3beaaSApple OSS Distributions {
175*aca3beaaSApple OSS Distributions 	kern_return_t result;
176*aca3beaaSApple OSS Distributions 	int ncpu;
177*aca3beaaSApple OSS Distributions 	size_t size = sizeof(ncpu);
178*aca3beaaSApple OSS Distributions 	result = sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0);
179*aca3beaaSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(result, "hw.npu");
180*aca3beaaSApple OSS Distributions 	return (unsigned int) ncpu;
181*aca3beaaSApple OSS Distributions }
182