2 #include <sys/kern_sysctl.h>
4 #include <darwintest_utils.h>
5 #include <darwintest.h>
7 #include "counter/common.h"
8 #include "test_utils.h"
10 static unsigned int ncpu(void);
13 sysctl_read(const char *name
)
17 size_t size
= sizeof(value
);
18 result
= sysctlbyname(name
, &value
, &size
, NULL
, 0);
19 T_QUIET
; T_ASSERT_POSIX_SUCCESS(result
, "Read from %s", name
);
24 sysctl_write(const char* name
, int64_t amount
)
27 result
= sysctlbyname(name
, NULL
, NULL
, &amount
, sizeof(int64_t));
28 T_QUIET
; T_ASSERT_POSIX_SUCCESS(result
, "Write to %s", name
);
32 scalable_counter_add(int64_t amount
)
34 sysctl_write("kern.scalable_counter_test_add", amount
);
38 static_scalable_counter_add(int64_t amount
)
40 sysctl_write("kern.static_scalable_counter_test_add", amount
);
44 scalable_counter_load(void)
46 return (int64_t) sysctl_read("kern.scalable_counter_test_load");
50 static_scalable_counter_load(void)
52 return (int64_t) sysctl_read("kern.static_scalable_counter_test_load");
56 * A background thread that bangs on the percpu counter and then exits.
57 * @param num_iterations How many times to bang on the counter. Each iteration makes the counter
61 background_scalable_counter_thread(void* num_iterations_ptr
)
63 int64_t i
, num_iterations
;
64 num_iterations
= (int64_t)(num_iterations_ptr
);
65 for (i
= 0; i
< num_iterations
; i
++) {
66 scalable_counter_add(-25);
67 scalable_counter_add(75);
68 scalable_counter_add(-100);
69 scalable_counter_add(150);
71 atomic_thread_fence(memory_order_release
);
77 darwin_test_fini_scalable_counter_test()
79 int ret
= fini_scalable_counter_test();
80 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "fini_scalable_counter_test");
85 darwin_test_setup(void)
88 int dev_kernel
= is_development_kernel();
89 T_QUIET
; T_ASSERT_POSIX_SUCCESS(dev_kernel
, "sysctlbyname kern.development");
90 if (is_development_kernel() != 1) {
91 T_SKIP("Skipping test on non development kernel.");
93 init_scalable_counter_test();
95 T_ATEND(darwin_test_fini_scalable_counter_test
);
98 T_DECL(test_scalable_counters_single_threaded
, "Test single threaded operations on scalable_counters", T_META_ASROOT(true))
100 static int64_t kNumIterations
= 100, i
, expected_value
= 0;
102 T_QUIET
; T_EXPECT_EQ(scalable_counter_load(), 0LL, "Counter starts at zero");
104 /* Simple add, subtract, and read */
105 scalable_counter_add(1);
106 T_QUIET
; T_EXPECT_EQ(scalable_counter_load(), 1LL, "0 + 1 == 1");
107 scalable_counter_add(-1);
108 T_QUIET
; T_EXPECT_EQ(scalable_counter_load(), 0LL, "1 - 1 == 0");
109 for (i
= 0; i
< kNumIterations
; i
++) {
110 scalable_counter_add(i
);
113 for (i
= 0; i
< kNumIterations
/ 2; i
++) {
114 scalable_counter_add(-i
);
117 T_QUIET
; T_EXPECT_EQ(scalable_counter_load(), expected_value
, "Counter value is correct.");
121 T_DECL(test_static_counter
, "Test staticly declared counter", T_META_ASROOT(true))
123 static size_t kNumIterations
= 100;
126 start_value
= static_scalable_counter_load();
127 for (size_t i
= 0; i
< kNumIterations
; i
++) {
128 static_scalable_counter_add(1);
130 T_QUIET
; T_EXPECT_EQ(static_scalable_counter_load(), (long long) kNumIterations
+ start_value
, "Counter value is correct");
134 T_DECL(test_scalable_counters_multithreaded
, "Test multi-threaded operations on scalable_counters", T_META_ASROOT(true))
136 unsigned int kNumThreads
= ncpu() * 5;
139 pthread_attr_t pthread_attr
;
144 threads
= malloc(sizeof(pthread_t
) * kNumThreads
);
145 T_QUIET
; T_ASSERT_NOTNULL(threads
, "Out of memory");
147 ret
= pthread_attr_init(&pthread_attr
);
148 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "pthread_attr_init");
150 int64_t expected_value
= 0;
151 for (i
= 0; i
< kNumThreads
; i
++) {
152 ret
= pthread_create(&threads
[i
], &pthread_attr
, background_scalable_counter_thread
, (void*)(i
));
153 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "pthread_create");
154 expected_value
+= 100 * i
;
157 for (i
= 0; i
< kNumThreads
; i
++) {
159 ret
= pthread_join(threads
[i
], &exit_code
);
160 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "pthread_join");
161 T_QUIET
; T_ASSERT_EQ((ptrdiff_t) exit_code
, (ptrdiff_t) 0, "Background thread exited sucessfully.");
163 atomic_thread_fence(memory_order_acquire
);
165 T_QUIET
; T_EXPECT_EQ(scalable_counter_load(), expected_value
, "Counter value is correct.");
167 ret
= pthread_attr_destroy(&pthread_attr
);
168 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "pthread_attr_destroy");
175 kern_return_t result
;
177 size_t size
= sizeof(ncpu
);
178 result
= sysctlbyname("hw.ncpu", &ncpu
, &size
, NULL
, 0);
179 T_QUIET
; T_ASSERT_MACH_SUCCESS(result
, "hw.npu");
180 return (unsigned int) ncpu
;