xref: /xnu-10063.101.15/tests/sched_yield_aggressor.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
1*94d3b452SApple OSS Distributions #include <unistd.h>
2*94d3b452SApple OSS Distributions #include <stdlib.h>
3*94d3b452SApple OSS Distributions #include <pthread.h>
4*94d3b452SApple OSS Distributions #include <spawn.h>
5*94d3b452SApple OSS Distributions #include <string.h>
6*94d3b452SApple OSS Distributions #include <mach/mach.h>
7*94d3b452SApple OSS Distributions #include <mach/mach_time.h>
8*94d3b452SApple OSS Distributions #include <TargetConditionals.h>
9*94d3b452SApple OSS Distributions #include <sys/work_interval.h>
10*94d3b452SApple OSS Distributions #include <sys/stat.h>
11*94d3b452SApple OSS Distributions #include <sys/sysctl.h>
12*94d3b452SApple OSS Distributions #include <sys/time.h>
13*94d3b452SApple OSS Distributions #include <stdatomic.h>
14*94d3b452SApple OSS Distributions #include <time.h>
15*94d3b452SApple OSS Distributions 
16*94d3b452SApple OSS Distributions #include <darwintest.h>
17*94d3b452SApple OSS Distributions #include <darwintest_utils.h>
18*94d3b452SApple OSS Distributions #include <perfdata/perfdata.h>
19*94d3b452SApple OSS Distributions 
20*94d3b452SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
21*94d3b452SApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
22*94d3b452SApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("scheduler"),
23*94d3b452SApple OSS Distributions     T_META_TAG_PERF);
24*94d3b452SApple OSS Distributions 
25*94d3b452SApple OSS Distributions /* Code and logic taken from Daniel Chimene's yield-aggressor.c test (rdar://47327537) */
26*94d3b452SApple OSS Distributions 
27*94d3b452SApple OSS Distributions static const size_t MAX_PDJ_PATH_LEN = 256;
28*94d3b452SApple OSS Distributions 
29*94d3b452SApple OSS Distributions static void
sched_yield_loop(uint64_t iterations)30*94d3b452SApple OSS Distributions sched_yield_loop(uint64_t iterations)
31*94d3b452SApple OSS Distributions {
32*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
33*94d3b452SApple OSS Distributions 		sched_yield();
34*94d3b452SApple OSS Distributions 	}
35*94d3b452SApple OSS Distributions }
36*94d3b452SApple OSS Distributions 
37*94d3b452SApple OSS Distributions static void
swtch_loop(uint64_t iterations)38*94d3b452SApple OSS Distributions swtch_loop(uint64_t iterations)
39*94d3b452SApple OSS Distributions {
40*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
41*94d3b452SApple OSS Distributions 		swtch();
42*94d3b452SApple OSS Distributions 	}
43*94d3b452SApple OSS Distributions }
44*94d3b452SApple OSS Distributions 
45*94d3b452SApple OSS Distributions static void
swtch_pri_loop(uint64_t iterations)46*94d3b452SApple OSS Distributions swtch_pri_loop(uint64_t iterations)
47*94d3b452SApple OSS Distributions {
48*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
49*94d3b452SApple OSS Distributions 		swtch_pri(0);
50*94d3b452SApple OSS Distributions 	}
51*94d3b452SApple OSS Distributions }
52*94d3b452SApple OSS Distributions 
53*94d3b452SApple OSS Distributions static void
thread_switch_loop(uint64_t iterations)54*94d3b452SApple OSS Distributions thread_switch_loop(uint64_t iterations)
55*94d3b452SApple OSS Distributions {
56*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
57*94d3b452SApple OSS Distributions 		thread_switch(MACH_PORT_NULL, SWITCH_OPTION_NONE, MACH_MSG_TIMEOUT_NONE);
58*94d3b452SApple OSS Distributions 	}
59*94d3b452SApple OSS Distributions }
60*94d3b452SApple OSS Distributions 
61*94d3b452SApple OSS Distributions static void
thread_switch_wait_loop(uint64_t iterations)62*94d3b452SApple OSS Distributions thread_switch_wait_loop(uint64_t iterations)
63*94d3b452SApple OSS Distributions {
64*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
65*94d3b452SApple OSS Distributions 		thread_switch(MACH_PORT_NULL, SWITCH_OPTION_WAIT, MACH_MSG_TIMEOUT_NONE);
66*94d3b452SApple OSS Distributions 	}
67*94d3b452SApple OSS Distributions }
68*94d3b452SApple OSS Distributions 
69*94d3b452SApple OSS Distributions static void
thread_switch_depress_loop(uint64_t iterations)70*94d3b452SApple OSS Distributions thread_switch_depress_loop(uint64_t iterations)
71*94d3b452SApple OSS Distributions {
72*94d3b452SApple OSS Distributions 	for (uint64_t i = 0; i < iterations; i++) {
73*94d3b452SApple OSS Distributions 		thread_switch(MACH_PORT_NULL, SWITCH_OPTION_DEPRESS, MACH_MSG_TIMEOUT_NONE);
74*94d3b452SApple OSS Distributions 	}
75*94d3b452SApple OSS Distributions }
76*94d3b452SApple OSS Distributions 
77*94d3b452SApple OSS Distributions typedef enum yield_type {
78*94d3b452SApple OSS Distributions 	SCHED_YIELD = 0,
79*94d3b452SApple OSS Distributions 	SWTCH = 1,
80*94d3b452SApple OSS Distributions 	SWTCH_PRI = 2,
81*94d3b452SApple OSS Distributions 	THREAD_SWITCH = 3,
82*94d3b452SApple OSS Distributions 	THREAD_SWITCH_WAIT = 4,
83*94d3b452SApple OSS Distributions 	THREAD_SWITCH_DEPRESS = 5
84*94d3b452SApple OSS Distributions } yield_type_t;
85*94d3b452SApple OSS Distributions 
86*94d3b452SApple OSS Distributions static const int NUM_YIELD_TYPES = 6;
87*94d3b452SApple OSS Distributions 
88*94d3b452SApple OSS Distributions static char* name_table[NUM_YIELD_TYPES] = {
89*94d3b452SApple OSS Distributions 	[SCHED_YIELD]           = "sched_yield",
90*94d3b452SApple OSS Distributions 	[SWTCH]                 = "swtch",
91*94d3b452SApple OSS Distributions 	[SWTCH_PRI]             = "swtch_pri",
92*94d3b452SApple OSS Distributions 	[THREAD_SWITCH]         = "thread_switch(none)",
93*94d3b452SApple OSS Distributions 	[THREAD_SWITCH_WAIT]    = "thread_switch(wait)",
94*94d3b452SApple OSS Distributions 	[THREAD_SWITCH_DEPRESS] = "thread_switch(depress)",
95*94d3b452SApple OSS Distributions };
96*94d3b452SApple OSS Distributions 
97*94d3b452SApple OSS Distributions static void (*fn_table[NUM_YIELD_TYPES])(uint64_t) = {
98*94d3b452SApple OSS Distributions 	[SCHED_YIELD]           = sched_yield_loop,
99*94d3b452SApple OSS Distributions 	[SWTCH]                 = swtch_loop,
100*94d3b452SApple OSS Distributions 	[SWTCH_PRI]             = swtch_pri_loop,
101*94d3b452SApple OSS Distributions 	[THREAD_SWITCH]         = thread_switch_loop,
102*94d3b452SApple OSS Distributions 	[THREAD_SWITCH_WAIT]    = thread_switch_wait_loop,
103*94d3b452SApple OSS Distributions 	[THREAD_SWITCH_DEPRESS] = thread_switch_depress_loop,
104*94d3b452SApple OSS Distributions };
105*94d3b452SApple OSS Distributions 
106*94d3b452SApple OSS Distributions static semaphore_t ready_sem, go_sem;
107*94d3b452SApple OSS Distributions static unsigned int num_iterations, num_threads;
108*94d3b452SApple OSS Distributions static _Atomic unsigned int done_threads;
109*94d3b452SApple OSS Distributions static yield_type_t curr_yield_type;
110*94d3b452SApple OSS Distributions 
111*94d3b452SApple OSS Distributions static void *
thread_fn(__unused void * arg)112*94d3b452SApple OSS Distributions thread_fn(__unused void *arg)
113*94d3b452SApple OSS Distributions {
114*94d3b452SApple OSS Distributions 	kern_return_t kr;
115*94d3b452SApple OSS Distributions 
116*94d3b452SApple OSS Distributions 	kr = semaphore_wait_signal(go_sem, ready_sem);
117*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait_signal");
118*94d3b452SApple OSS Distributions 
119*94d3b452SApple OSS Distributions 	fn_table[curr_yield_type](num_iterations);
120*94d3b452SApple OSS Distributions 
121*94d3b452SApple OSS Distributions 	if (atomic_fetch_add(&done_threads, 1) == num_threads - 1) {
122*94d3b452SApple OSS Distributions 		kr = semaphore_wait_signal(go_sem, ready_sem);
123*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait_signal");
124*94d3b452SApple OSS Distributions 	} else {
125*94d3b452SApple OSS Distributions 		kr = semaphore_wait(go_sem);
126*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait");
127*94d3b452SApple OSS Distributions 	}
128*94d3b452SApple OSS Distributions 	return NULL;
129*94d3b452SApple OSS Distributions }
130*94d3b452SApple OSS Distributions 
131*94d3b452SApple OSS Distributions static void
start_threads(pthread_t * threads,void * (* start_routine)(void *),int priority)132*94d3b452SApple OSS Distributions start_threads(pthread_t *threads, void *(*start_routine)(void *), int priority)
133*94d3b452SApple OSS Distributions {
134*94d3b452SApple OSS Distributions 	int rv;
135*94d3b452SApple OSS Distributions 	pthread_attr_t attr;
136*94d3b452SApple OSS Distributions 
137*94d3b452SApple OSS Distributions 	rv = pthread_attr_init(&attr);
138*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_init");
139*94d3b452SApple OSS Distributions 
140*94d3b452SApple OSS Distributions 	for (unsigned int i = 0; i < num_threads; i++) {
141*94d3b452SApple OSS Distributions 		struct sched_param param = { .sched_priority = (int)priority };
142*94d3b452SApple OSS Distributions 
143*94d3b452SApple OSS Distributions 		rv = pthread_attr_setschedparam(&attr, &param);
144*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setschedparam");
145*94d3b452SApple OSS Distributions 
146*94d3b452SApple OSS Distributions 		rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
147*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setdetachstate");
148*94d3b452SApple OSS Distributions 
149*94d3b452SApple OSS Distributions 		rv = pthread_create(&threads[i], &attr, start_routine, NULL);
150*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_create");
151*94d3b452SApple OSS Distributions 	}
152*94d3b452SApple OSS Distributions 
153*94d3b452SApple OSS Distributions 	rv = pthread_attr_destroy(&attr);
154*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_destroy");
155*94d3b452SApple OSS Distributions }
156*94d3b452SApple OSS Distributions 
157*94d3b452SApple OSS Distributions struct cpu_time {
158*94d3b452SApple OSS Distributions 	natural_t sys;
159*94d3b452SApple OSS Distributions 	natural_t user;
160*94d3b452SApple OSS Distributions 	natural_t idle;
161*94d3b452SApple OSS Distributions };
162*94d3b452SApple OSS Distributions 
163*94d3b452SApple OSS Distributions static void
record_cpu_time(struct cpu_time * cpu_time)164*94d3b452SApple OSS Distributions record_cpu_time(struct cpu_time *cpu_time)
165*94d3b452SApple OSS Distributions {
166*94d3b452SApple OSS Distributions 	host_cpu_load_info_data_t load;
167*94d3b452SApple OSS Distributions 	kern_return_t kr;
168*94d3b452SApple OSS Distributions 	mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
169*94d3b452SApple OSS Distributions 
170*94d3b452SApple OSS Distributions 	kr = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (int *)&load, &count);
171*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "host_statistics");
172*94d3b452SApple OSS Distributions 
173*94d3b452SApple OSS Distributions 	cpu_time->sys = load.cpu_ticks[CPU_STATE_SYSTEM];
174*94d3b452SApple OSS Distributions 	cpu_time->user = load.cpu_ticks[CPU_STATE_USER] + load.cpu_ticks[CPU_STATE_NICE];
175*94d3b452SApple OSS Distributions 	cpu_time->idle = load.cpu_ticks[CPU_STATE_IDLE];
176*94d3b452SApple OSS Distributions }
177*94d3b452SApple OSS Distributions 
178*94d3b452SApple OSS Distributions static void
write_independent_variables(pdwriter_t writer)179*94d3b452SApple OSS Distributions write_independent_variables(pdwriter_t writer)
180*94d3b452SApple OSS Distributions {
181*94d3b452SApple OSS Distributions 	pdwriter_record_variable_str(writer, "yield_variant", name_table[curr_yield_type]);
182*94d3b452SApple OSS Distributions 	pdwriter_record_variable_dbl(writer, "num_iterations", num_iterations);
183*94d3b452SApple OSS Distributions 	pdwriter_record_variable_dbl(writer, "num_threads", num_threads);
184*94d3b452SApple OSS Distributions }
185*94d3b452SApple OSS Distributions 
186*94d3b452SApple OSS Distributions static const double MS_PER_CPU_TICK = 10.0;
187*94d3b452SApple OSS Distributions 
188*94d3b452SApple OSS Distributions static void
write_time_values(pdwriter_t writer,struct cpu_time * delta_times,uint64_t elapsed_usecs,double idle_ratio)189*94d3b452SApple OSS Distributions write_time_values(pdwriter_t writer, struct cpu_time *delta_times, uint64_t elapsed_usecs, double idle_ratio)
190*94d3b452SApple OSS Distributions {
191*94d3b452SApple OSS Distributions 	pdwriter_new_value(writer, "system_time", pdunit_milliseconds_cpu, delta_times->sys * MS_PER_CPU_TICK);
192*94d3b452SApple OSS Distributions 	write_independent_variables(writer);
193*94d3b452SApple OSS Distributions 
194*94d3b452SApple OSS Distributions 	pdwriter_new_value(writer, "user_time", pdunit_milliseconds_cpu, delta_times->user * MS_PER_CPU_TICK);
195*94d3b452SApple OSS Distributions 	write_independent_variables(writer);
196*94d3b452SApple OSS Distributions 
197*94d3b452SApple OSS Distributions 	pdwriter_new_value(writer, "idle_time", pdunit_milliseconds_cpu, delta_times->idle * MS_PER_CPU_TICK);
198*94d3b452SApple OSS Distributions 	write_independent_variables(writer);
199*94d3b452SApple OSS Distributions 
200*94d3b452SApple OSS Distributions 	pdwriter_new_value(writer, "wall_clock_time", pdunit_microseconds, elapsed_usecs);
201*94d3b452SApple OSS Distributions 	write_independent_variables(writer);
202*94d3b452SApple OSS Distributions 
203*94d3b452SApple OSS Distributions 	/* Main metric of note, with a threshold in perfmeta to guard against regression */
204*94d3b452SApple OSS Distributions 	pdwriter_new_value(writer, "idle_time_ratio", pdunit_percent_cpus, idle_ratio);
205*94d3b452SApple OSS Distributions 	write_independent_variables(writer);
206*94d3b452SApple OSS Distributions }
207*94d3b452SApple OSS Distributions 
208*94d3b452SApple OSS Distributions static void
run_yielding_test(yield_type_t yield_type,unsigned int num_iters,unsigned int thread_count,int thread_pri,pdwriter_t writer)209*94d3b452SApple OSS Distributions run_yielding_test(yield_type_t yield_type, unsigned int num_iters, unsigned int thread_count,
210*94d3b452SApple OSS Distributions     int thread_pri, pdwriter_t writer)
211*94d3b452SApple OSS Distributions {
212*94d3b452SApple OSS Distributions 	T_SETUPBEGIN;
213*94d3b452SApple OSS Distributions 
214*94d3b452SApple OSS Distributions 	T_LOG("===== Yield Variety: %s", name_table[yield_type]);
215*94d3b452SApple OSS Distributions 
216*94d3b452SApple OSS Distributions 	kern_return_t kr;
217*94d3b452SApple OSS Distributions 
218*94d3b452SApple OSS Distributions 	num_iterations = num_iters;
219*94d3b452SApple OSS Distributions 	num_threads = thread_count;
220*94d3b452SApple OSS Distributions 	curr_yield_type = yield_type;
221*94d3b452SApple OSS Distributions 	done_threads = 0;
222*94d3b452SApple OSS Distributions 
223*94d3b452SApple OSS Distributions 	kr = semaphore_create(mach_task_self(), &ready_sem, SYNC_POLICY_FIFO, 0);
224*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_create");
225*94d3b452SApple OSS Distributions 	kr = semaphore_create(mach_task_self(), &go_sem, SYNC_POLICY_FIFO, 0);
226*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_create");
227*94d3b452SApple OSS Distributions 
228*94d3b452SApple OSS Distributions 	pthread_t threads[num_threads];
229*94d3b452SApple OSS Distributions 	start_threads(threads, &thread_fn, thread_pri);
230*94d3b452SApple OSS Distributions 
231*94d3b452SApple OSS Distributions 	for (uint32_t i = 0; i < num_threads; i++) {
232*94d3b452SApple OSS Distributions 		kr = semaphore_wait(ready_sem);
233*94d3b452SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait");
234*94d3b452SApple OSS Distributions 	}
235*94d3b452SApple OSS Distributions 
236*94d3b452SApple OSS Distributions 	/* Wait 100ms for the system to settle down */
237*94d3b452SApple OSS Distributions 	usleep(100000);
238*94d3b452SApple OSS Distributions 
239*94d3b452SApple OSS Distributions 	T_SETUPEND;
240*94d3b452SApple OSS Distributions 
241*94d3b452SApple OSS Distributions 	struct cpu_time start_times, finish_times, delta_times;
242*94d3b452SApple OSS Distributions 	uint64_t before_nsec, after_nsec;
243*94d3b452SApple OSS Distributions 
244*94d3b452SApple OSS Distributions 	record_cpu_time(&start_times);
245*94d3b452SApple OSS Distributions 	before_nsec = clock_gettime_nsec_np(CLOCK_REALTIME);
246*94d3b452SApple OSS Distributions 
247*94d3b452SApple OSS Distributions 	/* Signal threads to begin yielding "work" */
248*94d3b452SApple OSS Distributions 	kr = semaphore_signal_all(go_sem);
249*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_signal_all");
250*94d3b452SApple OSS Distributions 
251*94d3b452SApple OSS Distributions 	kr = semaphore_wait(ready_sem);
252*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait");
253*94d3b452SApple OSS Distributions 
254*94d3b452SApple OSS Distributions 	/* Capture cpu stats after yielding "work" has finished */
255*94d3b452SApple OSS Distributions 	after_nsec = clock_gettime_nsec_np(CLOCK_REALTIME);
256*94d3b452SApple OSS Distributions 	record_cpu_time(&finish_times);
257*94d3b452SApple OSS Distributions 
258*94d3b452SApple OSS Distributions 	uint64_t elapsed_usecs = (after_nsec - before_nsec) / 1000;
259*94d3b452SApple OSS Distributions 	T_LOG("All %u threads finished yielding %u times each", num_threads, num_iterations);
260*94d3b452SApple OSS Distributions 	T_LOG("Elapsed Runtime: %f seconds", ((double) elapsed_usecs) / USEC_PER_SEC);
261*94d3b452SApple OSS Distributions 
262*94d3b452SApple OSS Distributions 	delta_times.sys = finish_times.sys - start_times.sys;
263*94d3b452SApple OSS Distributions 	delta_times.user = finish_times.user - start_times.user;
264*94d3b452SApple OSS Distributions 	delta_times.idle = finish_times.idle - start_times.idle;
265*94d3b452SApple OSS Distributions 	T_LOG("System CPU ticks: %d", delta_times.sys);
266*94d3b452SApple OSS Distributions 	T_LOG("User CPU ticks: %d", delta_times.user);
267*94d3b452SApple OSS Distributions 	T_LOG("Idle CPU ticks: %d", delta_times.idle);
268*94d3b452SApple OSS Distributions 
269*94d3b452SApple OSS Distributions 	natural_t total_ticks = delta_times.sys + delta_times.user + delta_times.idle;
270*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_GT(total_ticks, 0, "CPU load stats failed to update, likely due to host_statistics() rate limit");
271*94d3b452SApple OSS Distributions 
272*94d3b452SApple OSS Distributions 	double cpu_idle_ratio = delta_times.idle * 1.0 / total_ticks;
273*94d3b452SApple OSS Distributions 	T_LOG("*** Ratio of Idle CPU time: %f\n\n", cpu_idle_ratio);
274*94d3b452SApple OSS Distributions 
275*94d3b452SApple OSS Distributions 	write_time_values(writer, &delta_times, elapsed_usecs, cpu_idle_ratio);
276*94d3b452SApple OSS Distributions }
277*94d3b452SApple OSS Distributions 
278*94d3b452SApple OSS Distributions static const int DEFAULT_THREAD_PRI = 31;
279*94d3b452SApple OSS Distributions static const int DEFAULT_NUM_ITERS = 100000;
280*94d3b452SApple OSS Distributions 
281*94d3b452SApple OSS Distributions #define KERNEL_BOOTARGS_MAX_SIZE 1024
282*94d3b452SApple OSS Distributions static char kernel_bootargs[KERNEL_BOOTARGS_MAX_SIZE];
283*94d3b452SApple OSS Distributions 
284*94d3b452SApple OSS Distributions T_DECL(yield_aggressor,
285*94d3b452SApple OSS Distributions     "Ensure that CPUs do not go idle when there are many threads all yielding "
286*94d3b452SApple OSS Distributions     "in a loop (for different varieties of yield)",
287*94d3b452SApple OSS Distributions     /* Required to get around the rate limit for host_statistics() */
288*94d3b452SApple OSS Distributions     T_META_BOOTARGS_SET("amfi_get_out_of_my_way=1"),
289*94d3b452SApple OSS Distributions     T_META_ASROOT(true))
290*94d3b452SApple OSS Distributions {
291*94d3b452SApple OSS Distributions 	/* Warn if amfi_get_out_of_my_way is not set and fail later on if we actually run into the rate limit */
292*94d3b452SApple OSS Distributions 	size_t kernel_bootargs_size = sizeof(kernel_bootargs);
293*94d3b452SApple OSS Distributions 	int rv = sysctlbyname("kern.bootargs", kernel_bootargs, &kernel_bootargs_size, NULL, 0);
294*94d3b452SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kern.bootargs");
295*94d3b452SApple OSS Distributions 	if (strstr(kernel_bootargs, "amfi_get_out_of_my_way=1") == NULL) {
296*94d3b452SApple OSS Distributions 		T_LOG("WARNING: amfi_get_out_of_my_way=1 boot-arg is missing, required to reliably capture CPU load data");
297*94d3b452SApple OSS Distributions 	}
298*94d3b452SApple OSS Distributions 
299*94d3b452SApple OSS Distributions 	char pdj_path[MAX_PDJ_PATH_LEN];
300*94d3b452SApple OSS Distributions 	pdwriter_t writer = pdwriter_open_tmp("xnu", "scheduler.yield_aggressor", 0, 0, pdj_path, MAX_PDJ_PATH_LEN);
301*94d3b452SApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(writer, "pdwriter_open_tmp");
302*94d3b452SApple OSS Distributions 
303*94d3b452SApple OSS Distributions 	/*
304*94d3b452SApple OSS Distributions 	 * Thread count is NCPU * 3 in order to ensure that there are enough yielding threads
305*94d3b452SApple OSS Distributions 	 * to keep all of the cores busy context-switching between them. NCPU * 1 threads would
306*94d3b452SApple OSS Distributions 	 * not be sufficient to guarantee this, because a core temporarily keeps two threads
307*94d3b452SApple OSS Distributions 	 * off of the run-queues at a time while performing a context-switch (rather than only
308*94d3b452SApple OSS Distributions 	 * the one thread it is running during normal execution). Lastly, we choose NCPU * 3
309*94d3b452SApple OSS Distributions 	 * rather than NCPU * 2 because doing so empirically reduces the variance of values
310*94d3b452SApple OSS Distributions 	 * betweens runs.
311*94d3b452SApple OSS Distributions 	 */
312*94d3b452SApple OSS Distributions 	unsigned int thread_count = (unsigned int) dt_ncpu() * 3;
313*94d3b452SApple OSS Distributions 
314*94d3b452SApple OSS Distributions 	for (yield_type_t yield_type = SCHED_YIELD; yield_type <= THREAD_SWITCH_DEPRESS; yield_type++) {
315*94d3b452SApple OSS Distributions 		run_yielding_test(yield_type, DEFAULT_NUM_ITERS, thread_count, DEFAULT_THREAD_PRI, writer);
316*94d3b452SApple OSS Distributions 	}
317*94d3b452SApple OSS Distributions 
318*94d3b452SApple OSS Distributions 	T_LOG("Perfdata file written to: %s", pdj_path);
319*94d3b452SApple OSS Distributions 	pdwriter_close(writer);
320*94d3b452SApple OSS Distributions 
321*94d3b452SApple OSS Distributions 	T_END;
322*94d3b452SApple OSS Distributions }
323