1*aca3beaaSApple OSS Distributions /*
2*aca3beaaSApple OSS Distributions * Test to validate that we can schedule threads on all hw.ncpus cores according to _os_cpu_number
3*aca3beaaSApple OSS Distributions *
4*aca3beaaSApple OSS Distributions * <rdar://problem/29545645>
5*aca3beaaSApple OSS Distributions * <rdar://problem/30445216>
6*aca3beaaSApple OSS Distributions *
7*aca3beaaSApple OSS Distributions * xcrun -sdk macosx.internal clang -o cpucount cpucount.c -ldarwintest -g -Weverything
8*aca3beaaSApple OSS Distributions * xcrun -sdk iphoneos.internal clang -arch arm64 -o cpucount-ios cpucount.c -ldarwintest -g -Weverything
9*aca3beaaSApple OSS Distributions * xcrun -sdk macosx.internal clang -o cpucount cpucount.c -ldarwintest -arch arm64e -Weverything
10*aca3beaaSApple OSS Distributions */
11*aca3beaaSApple OSS Distributions
12*aca3beaaSApple OSS Distributions #include <darwintest.h>
13*aca3beaaSApple OSS Distributions #include "test_utils.h"
14*aca3beaaSApple OSS Distributions
15*aca3beaaSApple OSS Distributions #include <stdio.h>
16*aca3beaaSApple OSS Distributions #include <stdlib.h>
17*aca3beaaSApple OSS Distributions #include <unistd.h>
18*aca3beaaSApple OSS Distributions #include <pthread.h>
19*aca3beaaSApple OSS Distributions #include <sys/sysctl.h>
20*aca3beaaSApple OSS Distributions #include <sys/proc_info.h>
21*aca3beaaSApple OSS Distributions #include <libproc.h>
22*aca3beaaSApple OSS Distributions
23*aca3beaaSApple OSS Distributions #include <mach/mach.h>
24*aca3beaaSApple OSS Distributions #include <mach/mach_time.h>
25*aca3beaaSApple OSS Distributions
26*aca3beaaSApple OSS Distributions #include <os/tsd.h> /* private header for _os_cpu_number */
27*aca3beaaSApple OSS Distributions
28*aca3beaaSApple OSS Distributions T_GLOBAL_META(
29*aca3beaaSApple OSS Distributions T_META_RUN_CONCURRENTLY(false),
30*aca3beaaSApple OSS Distributions T_META_BOOTARGS_SET("enable_skstb=1"),
31*aca3beaaSApple OSS Distributions T_META_CHECK_LEAKS(false),
32*aca3beaaSApple OSS Distributions T_META_ASROOT(true),
33*aca3beaaSApple OSS Distributions T_META_ALL_VALID_ARCHS(true),
34*aca3beaaSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
35*aca3beaaSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("scheduler")
36*aca3beaaSApple OSS Distributions );
37*aca3beaaSApple OSS Distributions
38*aca3beaaSApple OSS Distributions #define KERNEL_BOOTARGS_MAX_SIZE 1024
39*aca3beaaSApple OSS Distributions static char kernel_bootargs[KERNEL_BOOTARGS_MAX_SIZE];
40*aca3beaaSApple OSS Distributions
41*aca3beaaSApple OSS Distributions #define KERNEL_VERSION_MAX_SIZE 1024
42*aca3beaaSApple OSS Distributions static char kernel_version[KERNEL_VERSION_MAX_SIZE];
43*aca3beaaSApple OSS Distributions
44*aca3beaaSApple OSS Distributions static mach_timebase_info_data_t timebase_info;
45*aca3beaaSApple OSS Distributions
46*aca3beaaSApple OSS Distributions static uint64_t
abs_to_nanos(uint64_t abs)47*aca3beaaSApple OSS Distributions abs_to_nanos(uint64_t abs)
48*aca3beaaSApple OSS Distributions {
49*aca3beaaSApple OSS Distributions return abs * timebase_info.numer / timebase_info.denom;
50*aca3beaaSApple OSS Distributions }
51*aca3beaaSApple OSS Distributions
52*aca3beaaSApple OSS Distributions static int32_t
get_csw_count()53*aca3beaaSApple OSS Distributions get_csw_count()
54*aca3beaaSApple OSS Distributions {
55*aca3beaaSApple OSS Distributions struct proc_taskinfo taskinfo;
56*aca3beaaSApple OSS Distributions int rv;
57*aca3beaaSApple OSS Distributions
58*aca3beaaSApple OSS Distributions rv = proc_pidinfo(getpid(), PROC_PIDTASKINFO, 0, &taskinfo, sizeof(taskinfo));
59*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "PROC_PIDTASKINFO");
60*aca3beaaSApple OSS Distributions
61*aca3beaaSApple OSS Distributions return taskinfo.pti_csw;
62*aca3beaaSApple OSS Distributions }
63*aca3beaaSApple OSS Distributions
64*aca3beaaSApple OSS Distributions // noinline hopefully keeps the optimizer from hoisting it out of the loop
65*aca3beaaSApple OSS Distributions // until rdar://68253516 is fixed.
66*aca3beaaSApple OSS Distributions __attribute__((noinline))
67*aca3beaaSApple OSS Distributions static uint32_t
fixed_os_cpu_number(void)68*aca3beaaSApple OSS Distributions fixed_os_cpu_number(void)
69*aca3beaaSApple OSS Distributions {
70*aca3beaaSApple OSS Distributions uint32_t cpu_number = _os_cpu_number();
71*aca3beaaSApple OSS Distributions
72*aca3beaaSApple OSS Distributions return cpu_number;
73*aca3beaaSApple OSS Distributions }
74*aca3beaaSApple OSS Distributions
75*aca3beaaSApple OSS Distributions
76*aca3beaaSApple OSS Distributions T_DECL(count_cpus, "Tests we can schedule bound threads on all hw.ncpus cores and that _os_cpu_number matches", XNU_T_META_SOC_SPECIFIC)
77*aca3beaaSApple OSS Distributions {
78*aca3beaaSApple OSS Distributions int rv;
79*aca3beaaSApple OSS Distributions
80*aca3beaaSApple OSS Distributions setvbuf(stdout, NULL, _IONBF, 0);
81*aca3beaaSApple OSS Distributions setvbuf(stderr, NULL, _IONBF, 0);
82*aca3beaaSApple OSS Distributions
83*aca3beaaSApple OSS Distributions /* Validate what kind of kernel we're on */
84*aca3beaaSApple OSS Distributions size_t kernel_version_size = sizeof(kernel_version);
85*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.version", kernel_version, &kernel_version_size, NULL, 0);
86*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kern.version");
87*aca3beaaSApple OSS Distributions
88*aca3beaaSApple OSS Distributions T_LOG("kern.version: %s\n", kernel_version);
89*aca3beaaSApple OSS Distributions
90*aca3beaaSApple OSS Distributions /* Double check that darwintest set the boot arg we requested */
91*aca3beaaSApple OSS Distributions size_t kernel_bootargs_size = sizeof(kernel_bootargs);
92*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.bootargs", kernel_bootargs, &kernel_bootargs_size, NULL, 0);
93*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kern.bootargs");
94*aca3beaaSApple OSS Distributions
95*aca3beaaSApple OSS Distributions T_LOG("kern.bootargs: %s\n", kernel_bootargs);
96*aca3beaaSApple OSS Distributions
97*aca3beaaSApple OSS Distributions if (NULL == strstr(kernel_bootargs, "enable_skstb=1")) {
98*aca3beaaSApple OSS Distributions T_FAIL("enable_skstb=1 boot-arg is missing");
99*aca3beaaSApple OSS Distributions }
100*aca3beaaSApple OSS Distributions
101*aca3beaaSApple OSS Distributions kern_return_t kr;
102*aca3beaaSApple OSS Distributions kr = mach_timebase_info(&timebase_info);
103*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_timebase_info");
104*aca3beaaSApple OSS Distributions
105*aca3beaaSApple OSS Distributions int bound_cpu_out = 0;
106*aca3beaaSApple OSS Distributions size_t bound_cpu_out_size = sizeof(bound_cpu_out);
107*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.sched_thread_bind_cpu", &bound_cpu_out, &bound_cpu_out_size, NULL, 0);
108*aca3beaaSApple OSS Distributions
109*aca3beaaSApple OSS Distributions if (rv == -1) {
110*aca3beaaSApple OSS Distributions if (errno == ENOENT) {
111*aca3beaaSApple OSS Distributions T_FAIL("kern.sched_thread_bind_cpu doesn't exist, must set enable_skstb=1 boot-arg on development kernel");
112*aca3beaaSApple OSS Distributions }
113*aca3beaaSApple OSS Distributions if (errno == EPERM) {
114*aca3beaaSApple OSS Distributions T_FAIL("must run as root");
115*aca3beaaSApple OSS Distributions }
116*aca3beaaSApple OSS Distributions }
117*aca3beaaSApple OSS Distributions
118*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "read kern.sched_thread_bind_cpu");
119*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_EQ(bound_cpu_out, -1, "kern.sched_thread_bind_cpu should exist, start unbound");
120*aca3beaaSApple OSS Distributions
121*aca3beaaSApple OSS Distributions struct sched_param param = {.sched_priority = 63};
122*aca3beaaSApple OSS Distributions
123*aca3beaaSApple OSS Distributions rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
124*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_setschedparam");
125*aca3beaaSApple OSS Distributions
126*aca3beaaSApple OSS Distributions uint32_t sysctl_ncpu = 0;
127*aca3beaaSApple OSS Distributions size_t ncpu_size = sizeof(sysctl_ncpu);
128*aca3beaaSApple OSS Distributions rv = sysctlbyname("hw.ncpu", &sysctl_ncpu, &ncpu_size, NULL, 0);
129*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sysctlbyname(hw.ncpu)");
130*aca3beaaSApple OSS Distributions
131*aca3beaaSApple OSS Distributions T_LOG("hw.ncpu: %2d\n", sysctl_ncpu);
132*aca3beaaSApple OSS Distributions
133*aca3beaaSApple OSS Distributions T_ASSERT_GT(sysctl_ncpu, 0, "at least one CPU exists");
134*aca3beaaSApple OSS Distributions
135*aca3beaaSApple OSS Distributions for (uint32_t cpu_to_bind = 0; cpu_to_bind < sysctl_ncpu; cpu_to_bind++) {
136*aca3beaaSApple OSS Distributions int32_t before_csw_count = get_csw_count();
137*aca3beaaSApple OSS Distributions T_LOG("(csw %4d) attempting to bind to cpu %2d\n", before_csw_count, cpu_to_bind);
138*aca3beaaSApple OSS Distributions
139*aca3beaaSApple OSS Distributions uint64_t start = mach_absolute_time();
140*aca3beaaSApple OSS Distributions
141*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.sched_thread_bind_cpu", NULL, 0, &cpu_to_bind, sizeof(cpu_to_bind));
142*aca3beaaSApple OSS Distributions
143*aca3beaaSApple OSS Distributions uint64_t end = mach_absolute_time();
144*aca3beaaSApple OSS Distributions
145*aca3beaaSApple OSS Distributions if (rv == -1 && errno == ENOTSUP) {
146*aca3beaaSApple OSS Distributions T_SKIP("Binding is available, but this process doesn't support binding (e.g. Rosetta on Aruba)");
147*aca3beaaSApple OSS Distributions }
148*aca3beaaSApple OSS Distributions
149*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kern.sched_thread_bind_cpu(%u)", cpu_to_bind);
150*aca3beaaSApple OSS Distributions
151*aca3beaaSApple OSS Distributions uint32_t os_cpu_number_reported = fixed_os_cpu_number();
152*aca3beaaSApple OSS Distributions
153*aca3beaaSApple OSS Distributions bound_cpu_out = 0;
154*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.sched_thread_bind_cpu", &bound_cpu_out, &bound_cpu_out_size, NULL, 0);
155*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "read kern.sched_thread_bind_cpu");
156*aca3beaaSApple OSS Distributions
157*aca3beaaSApple OSS Distributions T_QUIET; T_EXPECT_EQ((int)cpu_to_bind, bound_cpu_out,
158*aca3beaaSApple OSS Distributions "should report bound cpu id matching requested bind target");
159*aca3beaaSApple OSS Distributions
160*aca3beaaSApple OSS Distributions uint64_t delta_abs = end - start;
161*aca3beaaSApple OSS Distributions uint64_t delta_ns = abs_to_nanos(delta_abs);
162*aca3beaaSApple OSS Distributions
163*aca3beaaSApple OSS Distributions int32_t after_csw_count = get_csw_count();
164*aca3beaaSApple OSS Distributions
165*aca3beaaSApple OSS Distributions T_LOG("(csw %4d) bound to cpu %2d in %f milliseconds\n",
166*aca3beaaSApple OSS Distributions after_csw_count, cpu_to_bind,
167*aca3beaaSApple OSS Distributions ((double)delta_ns / 1000000.0));
168*aca3beaaSApple OSS Distributions
169*aca3beaaSApple OSS Distributions if (cpu_to_bind > 0) {
170*aca3beaaSApple OSS Distributions T_QUIET; T_EXPECT_LT(before_csw_count, after_csw_count,
171*aca3beaaSApple OSS Distributions "should have had to context switch to execute the bind");
172*aca3beaaSApple OSS Distributions }
173*aca3beaaSApple OSS Distributions
174*aca3beaaSApple OSS Distributions T_LOG("cpu %2d reported id %2d\n",
175*aca3beaaSApple OSS Distributions cpu_to_bind, os_cpu_number_reported);
176*aca3beaaSApple OSS Distributions
177*aca3beaaSApple OSS Distributions T_QUIET;
178*aca3beaaSApple OSS Distributions T_EXPECT_EQ(cpu_to_bind, os_cpu_number_reported,
179*aca3beaaSApple OSS Distributions "should report same CPU number as was bound to");
180*aca3beaaSApple OSS Distributions }
181*aca3beaaSApple OSS Distributions
182*aca3beaaSApple OSS Distributions int unbind = -1; /* pass -1 in order to unbind the thread */
183*aca3beaaSApple OSS Distributions
184*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.sched_thread_bind_cpu", NULL, 0, &unbind, sizeof(unbind));
185*aca3beaaSApple OSS Distributions
186*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kern.sched_thread_bind_cpu(%u)", unbind);
187*aca3beaaSApple OSS Distributions
188*aca3beaaSApple OSS Distributions rv = sysctlbyname("kern.sched_thread_bind_cpu", &bound_cpu_out, &bound_cpu_out_size, NULL, 0);
189*aca3beaaSApple OSS Distributions
190*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "read kern.sched_thread_bind_cpu");
191*aca3beaaSApple OSS Distributions T_QUIET; T_ASSERT_EQ(bound_cpu_out, -1, "thread should be unbound at the end");
192*aca3beaaSApple OSS Distributions
193*aca3beaaSApple OSS Distributions T_PASS("test has run threads on all CPUS");
194*aca3beaaSApple OSS Distributions }
195