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