1*d4514f0bSApple OSS Distributions // Copyright (c) 2023 Apple Inc. All rights reserved.
2*d4514f0bSApple OSS Distributions
3*d4514f0bSApple OSS Distributions #include <unistd.h>
4*d4514f0bSApple OSS Distributions #include <stdlib.h>
5*d4514f0bSApple OSS Distributions #include <stdio.h>
6*d4514f0bSApple OSS Distributions #include <pthread.h>
7*d4514f0bSApple OSS Distributions #include <string.h>
8*d4514f0bSApple OSS Distributions #include <mach/mach.h>
9*d4514f0bSApple OSS Distributions #include <mach/mach_time.h>
10*d4514f0bSApple OSS Distributions #include <sys/stat.h>
11*d4514f0bSApple OSS Distributions #include <sys/sysctl.h>
12*d4514f0bSApple OSS Distributions #include <stdatomic.h>
13*d4514f0bSApple OSS Distributions #include <sys/work_interval.h>
14*d4514f0bSApple OSS Distributions #include <ktrace.h>
15*d4514f0bSApple OSS Distributions #include <sys/kdebug.h>
16*d4514f0bSApple OSS Distributions
17*d4514f0bSApple OSS Distributions #include <darwintest.h>
18*d4514f0bSApple OSS Distributions #include <darwintest_utils.h>
19*d4514f0bSApple OSS Distributions #include "test_utils.h"
20*d4514f0bSApple OSS Distributions #include "sched_test_utils.h"
21*d4514f0bSApple OSS Distributions
22*d4514f0bSApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
23*d4514f0bSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
24*d4514f0bSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("scheduler"),
25*d4514f0bSApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE,
26*d4514f0bSApple OSS Distributions T_META_REQUIRES_SYSCTL_NE("debug.sched_hygiene_debug_available", 0));
27*d4514f0bSApple OSS Distributions
28*d4514f0bSApple OSS Distributions static int BACKGROUND_PRI;
29*d4514f0bSApple OSS Distributions static int NUM_THREADS;
30*d4514f0bSApple OSS Distributions static uint64_t SLEEP_SECONDS;
31*d4514f0bSApple OSS Distributions static uint64_t INTERRUPT_DISABLE_TIMEOUT_NS;
32*d4514f0bSApple OSS Distributions
33*d4514f0bSApple OSS Distributions static uint64_t start_timestamp = 0ULL;
34*d4514f0bSApple OSS Distributions static volatile int sum = 0; // Keeps the spin-loop below from compiling-out
35*d4514f0bSApple OSS Distributions
36*d4514f0bSApple OSS Distributions static void *
make_tg_and_spin(__unused void * arg)37*d4514f0bSApple OSS Distributions make_tg_and_spin(__unused void *arg)
38*d4514f0bSApple OSS Distributions {
39*d4514f0bSApple OSS Distributions int ret;
40*d4514f0bSApple OSS Distributions assert(SLEEP_SECONDS > 2);
41*d4514f0bSApple OSS Distributions
42*d4514f0bSApple OSS Distributions /* Create and join a new thread group (TG) */
43*d4514f0bSApple OSS Distributions work_interval_t wi_handle;
44*d4514f0bSApple OSS Distributions ret = work_interval_create(&wi_handle, WORK_INTERVAL_FLAG_GROUP);
45*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, 0, "work_interval_create");
46*d4514f0bSApple OSS Distributions
47*d4514f0bSApple OSS Distributions /* Allow other threads a chance to get on-core and create/join their own TGs */
48*d4514f0bSApple OSS Distributions uint64_t yield_deadline = start_timestamp + nanos_to_abs(1 * NSEC_PER_SEC);
49*d4514f0bSApple OSS Distributions while (mach_absolute_time() < yield_deadline) {
50*d4514f0bSApple OSS Distributions sched_yield();
51*d4514f0bSApple OSS Distributions }
52*d4514f0bSApple OSS Distributions
53*d4514f0bSApple OSS Distributions /*
54*d4514f0bSApple OSS Distributions * Remain runnable long enough for the sched_maintenance_thread to scan the
55*d4514f0bSApple OSS Distributions * many created TGs all at the same time in one scheduler tick.
56*d4514f0bSApple OSS Distributions */
57*d4514f0bSApple OSS Distributions uint64_t spin_deadline = start_timestamp + nanos_to_abs((SLEEP_SECONDS - 2) * NSEC_PER_SEC);
58*d4514f0bSApple OSS Distributions while (mach_absolute_time() < spin_deadline) {
59*d4514f0bSApple OSS Distributions sum++;
60*d4514f0bSApple OSS Distributions }
61*d4514f0bSApple OSS Distributions
62*d4514f0bSApple OSS Distributions /*
63*d4514f0bSApple OSS Distributions * Terminate with about a second to spare of SLEEP_SECONDS, so that we have
64*d4514f0bSApple OSS Distributions * time to bring down the number of runnable thread groups before the test
65*d4514f0bSApple OSS Distributions * case reenables the previous kern.interrupt_masked_debug_mode value.
66*d4514f0bSApple OSS Distributions * Otherwise, a system failing this test could panic.
67*d4514f0bSApple OSS Distributions */
68*d4514f0bSApple OSS Distributions return NULL;
69*d4514f0bSApple OSS Distributions }
70*d4514f0bSApple OSS Distributions
71*d4514f0bSApple OSS Distributions static void
start_threads(pthread_t * threads,void * (* start_routine)(void *),int priority,int num_threads)72*d4514f0bSApple OSS Distributions start_threads(pthread_t *threads, void *(*start_routine)(void *), int priority, int num_threads)
73*d4514f0bSApple OSS Distributions {
74*d4514f0bSApple OSS Distributions int rv;
75*d4514f0bSApple OSS Distributions pthread_attr_t attr;
76*d4514f0bSApple OSS Distributions
77*d4514f0bSApple OSS Distributions rv = pthread_attr_init(&attr);
78*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_init");
79*d4514f0bSApple OSS Distributions
80*d4514f0bSApple OSS Distributions for (int i = 0; i < num_threads; i++) {
81*d4514f0bSApple OSS Distributions struct sched_param param = { .sched_priority = priority };
82*d4514f0bSApple OSS Distributions
83*d4514f0bSApple OSS Distributions rv = pthread_attr_setschedparam(&attr, ¶m);
84*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setschedparam");
85*d4514f0bSApple OSS Distributions
86*d4514f0bSApple OSS Distributions rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
87*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setdetachstate");
88*d4514f0bSApple OSS Distributions
89*d4514f0bSApple OSS Distributions /* Make the thread stacks smaller, so pthread will let us make more */
90*d4514f0bSApple OSS Distributions rv = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
91*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setstacksize");
92*d4514f0bSApple OSS Distributions
93*d4514f0bSApple OSS Distributions rv = pthread_create(&threads[i], &attr, start_routine, NULL);
94*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_create");
95*d4514f0bSApple OSS Distributions }
96*d4514f0bSApple OSS Distributions
97*d4514f0bSApple OSS Distributions rv = pthread_attr_destroy(&attr);
98*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_destroy");
99*d4514f0bSApple OSS Distributions }
100*d4514f0bSApple OSS Distributions
101*d4514f0bSApple OSS Distributions static uint64_t old_preemption_debug_mode = 0;
102*d4514f0bSApple OSS Distributions static size_t old_preemption_debug_mode_size = sizeof(old_preemption_debug_mode);
103*d4514f0bSApple OSS Distributions
104*d4514f0bSApple OSS Distributions static void
restore_preemption_disable_debug_mode(void)105*d4514f0bSApple OSS Distributions restore_preemption_disable_debug_mode(void)
106*d4514f0bSApple OSS Distributions {
107*d4514f0bSApple OSS Distributions int ret = sysctlbyname("kern.sched_preemption_disable_debug_mode", NULL, NULL,
108*d4514f0bSApple OSS Distributions &old_preemption_debug_mode, old_preemption_debug_mode_size);
109*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.sched_preemption_disable_debug_mode");
110*d4514f0bSApple OSS Distributions T_LOG("kern.sched_preemption_disable_debug_mode restored to previous value: %llu", old_preemption_debug_mode);
111*d4514f0bSApple OSS Distributions }
112*d4514f0bSApple OSS Distributions
113*d4514f0bSApple OSS Distributions static uint64_t old_interrupt_debug_mode = 0;
114*d4514f0bSApple OSS Distributions static size_t old_interrupt_debug_mode_size = sizeof(old_interrupt_debug_mode);
115*d4514f0bSApple OSS Distributions
116*d4514f0bSApple OSS Distributions static void
restore_interrupt_disable_debug_mode(void)117*d4514f0bSApple OSS Distributions restore_interrupt_disable_debug_mode(void)
118*d4514f0bSApple OSS Distributions {
119*d4514f0bSApple OSS Distributions int ret = sysctlbyname("kern.interrupt_masked_debug_mode", NULL, NULL,
120*d4514f0bSApple OSS Distributions &old_interrupt_debug_mode, old_interrupt_debug_mode_size);
121*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_debug_mode");
122*d4514f0bSApple OSS Distributions T_LOG("kern.interrupt_masked_debug_mode restored to previous value: %llu", old_interrupt_debug_mode);
123*d4514f0bSApple OSS Distributions }
124*d4514f0bSApple OSS Distributions
125*d4514f0bSApple OSS Distributions static uint64_t old_interrupt_disable_timeout = 0;
126*d4514f0bSApple OSS Distributions static size_t old_interrupt_disable_timeout_size = sizeof(old_interrupt_disable_timeout);
127*d4514f0bSApple OSS Distributions
128*d4514f0bSApple OSS Distributions static void
restore_interrupt_disable_timeout(void)129*d4514f0bSApple OSS Distributions restore_interrupt_disable_timeout(void)
130*d4514f0bSApple OSS Distributions {
131*d4514f0bSApple OSS Distributions int ret = sysctlbyname("kern.interrupt_masked_threshold_mt", NULL, NULL,
132*d4514f0bSApple OSS Distributions &old_interrupt_disable_timeout, old_interrupt_disable_timeout_size);
133*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_threshold_mt");
134*d4514f0bSApple OSS Distributions T_LOG("kern.interrupt_masked_threshold_mt restored to previous value: %llu", old_interrupt_disable_timeout);
135*d4514f0bSApple OSS Distributions }
136*d4514f0bSApple OSS Distributions
137*d4514f0bSApple OSS Distributions static char *trace_location = NULL;
138*d4514f0bSApple OSS Distributions
139*d4514f0bSApple OSS Distributions static void
delete_trace_file(void)140*d4514f0bSApple OSS Distributions delete_trace_file(void)
141*d4514f0bSApple OSS Distributions {
142*d4514f0bSApple OSS Distributions int ret;
143*d4514f0bSApple OSS Distributions /* Delete trace file in order to reclaim disk space on the test device */
144*d4514f0bSApple OSS Distributions ret = remove(trace_location);
145*d4514f0bSApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_SUCCESS(ret, "remove trace file");
146*d4514f0bSApple OSS Distributions }
147*d4514f0bSApple OSS Distributions
148*d4514f0bSApple OSS Distributions static const char *ktrace_file_short_name = "overload_runqueue_with_thread_groups.ktrace";
149*d4514f0bSApple OSS Distributions
150*d4514f0bSApple OSS Distributions static void
save_collected_ktrace(char * trace_path)151*d4514f0bSApple OSS Distributions save_collected_ktrace(char *trace_path)
152*d4514f0bSApple OSS Distributions {
153*d4514f0bSApple OSS Distributions int ret;
154*d4514f0bSApple OSS Distributions
155*d4514f0bSApple OSS Distributions T_LOG("ktrace file saved at \"%s\"", trace_path);
156*d4514f0bSApple OSS Distributions ret = chmod(trace_path, 0666);
157*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "chmod");
158*d4514f0bSApple OSS Distributions
159*d4514f0bSApple OSS Distributions char compressed_path[MAXPATHLEN];
160*d4514f0bSApple OSS Distributions snprintf(compressed_path, MAXPATHLEN, "%s.tar.gz", ktrace_file_short_name);
161*d4514f0bSApple OSS Distributions ret = dt_resultfile(compressed_path, sizeof(compressed_path));
162*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dt_resultfile marking \"%s\" for collection", compressed_path);
163*d4514f0bSApple OSS Distributions T_LOG("\"%s\" marked for upload", compressed_path);
164*d4514f0bSApple OSS Distributions
165*d4514f0bSApple OSS Distributions char *tar_args[] = {"/usr/bin/tar", "-czvf", compressed_path, trace_path, NULL};
166*d4514f0bSApple OSS Distributions pid_t tar_pid = dt_launch_tool_pipe(tar_args, false, NULL,
167*d4514f0bSApple OSS Distributions ^bool (__unused char *data, __unused size_t data_size, __unused dt_pipe_data_handler_context_t *context) {
168*d4514f0bSApple OSS Distributions return true;
169*d4514f0bSApple OSS Distributions },
170*d4514f0bSApple OSS Distributions ^bool (char *data, __unused size_t data_size, __unused dt_pipe_data_handler_context_t *context) {
171*d4514f0bSApple OSS Distributions T_LOG("[tar] Error msg: %s", data);
172*d4514f0bSApple OSS Distributions return true;
173*d4514f0bSApple OSS Distributions },
174*d4514f0bSApple OSS Distributions BUFFER_PATTERN_LINE, NULL);
175*d4514f0bSApple OSS Distributions
176*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_TRUE(tar_pid, "[tar] pid %d", tar_pid);
177*d4514f0bSApple OSS Distributions ret = dt_waitpid(tar_pid, NULL, NULL, 0);
178*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dt_waitpid");
179*d4514f0bSApple OSS Distributions
180*d4514f0bSApple OSS Distributions ret = chmod(compressed_path, 0666);
181*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "chmod");
182*d4514f0bSApple OSS Distributions }
183*d4514f0bSApple OSS Distributions
184*d4514f0bSApple OSS Distributions /*
185*d4514f0bSApple OSS Distributions * Parse the recorded ktrace file to see if we crossed the set interrupt-disabled
186*d4514f0bSApple OSS Distributions * timeout and thus failed the test.
187*d4514f0bSApple OSS Distributions */
188*d4514f0bSApple OSS Distributions static void
search_for_interrupt_disable_timeout_tracepoint(char * trace_path)189*d4514f0bSApple OSS Distributions search_for_interrupt_disable_timeout_tracepoint(char *trace_path)
190*d4514f0bSApple OSS Distributions {
191*d4514f0bSApple OSS Distributions __block int ret;
192*d4514f0bSApple OSS Distributions trace_location = trace_path;
193*d4514f0bSApple OSS Distributions T_ATEND(delete_trace_file);
194*d4514f0bSApple OSS Distributions ktrace_session_t read_session = ktrace_session_create();
195*d4514f0bSApple OSS Distributions ret = ktrace_set_file(read_session, trace_path);
196*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_set_file");
197*d4514f0bSApple OSS Distributions __block const char *offending_thread = NULL;
198*d4514f0bSApple OSS Distributions
199*d4514f0bSApple OSS Distributions ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_SCHED, MACH_INT_MASKED_EXPIRED), ^(ktrace_event_t e) {
200*d4514f0bSApple OSS Distributions if (offending_thread == NULL) {
201*d4514f0bSApple OSS Distributions T_LOG("Interrupts were held disabled for %llu ns, crossing the %llu ns threshold:", abs_to_nanos(e->arg1), INTERRUPT_DISABLE_TIMEOUT_NS);
202*d4514f0bSApple OSS Distributions ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
203*d4514f0bSApple OSS Distributions KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
204*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
205*d4514f0bSApple OSS Distributions printf("\n"); // Flush output from ktrace_print_trace_point
206*d4514f0bSApple OSS Distributions offending_thread = ktrace_get_name_for_thread(read_session, e->threadid);
207*d4514f0bSApple OSS Distributions ktrace_end(read_session, 0);
208*d4514f0bSApple OSS Distributions }
209*d4514f0bSApple OSS Distributions });
210*d4514f0bSApple OSS Distributions
211*d4514f0bSApple OSS Distributions ktrace_set_completion_handler(read_session, ^{
212*d4514f0bSApple OSS Distributions if (offending_thread == NULL) {
213*d4514f0bSApple OSS Distributions T_PASS("Scheduler survived %d simulatenously runnable thread groups without disabling interrupts for more than %llu ns!", NUM_THREADS, INTERRUPT_DISABLE_TIMEOUT_NS);
214*d4514f0bSApple OSS Distributions } else {
215*d4514f0bSApple OSS Distributions save_collected_ktrace(trace_path);
216*d4514f0bSApple OSS Distributions T_FAIL("Interrupts held disabled for more than %llu ns by thread \"%s\"", INTERRUPT_DISABLE_TIMEOUT_NS, offending_thread);
217*d4514f0bSApple OSS Distributions }
218*d4514f0bSApple OSS Distributions T_END;
219*d4514f0bSApple OSS Distributions });
220*d4514f0bSApple OSS Distributions
221*d4514f0bSApple OSS Distributions ret = ktrace_start(read_session, dispatch_get_main_queue());
222*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start");
223*d4514f0bSApple OSS Distributions }
224*d4514f0bSApple OSS Distributions
225*d4514f0bSApple OSS Distributions T_DECL(overload_runqueue_with_thread_groups,
226*d4514f0bSApple OSS Distributions "Overload the runqueue with distinct thread groups to verify that the scheduler"
227*d4514f0bSApple OSS Distributions "does not trip an interrupts-disabled timeout whenever it scans the runqueue",
228*d4514f0bSApple OSS Distributions T_META_ASROOT(true),
229*d4514f0bSApple OSS Distributions XNU_T_META_SOC_SPECIFIC,
230*d4514f0bSApple OSS Distributions T_META_ENABLED(TARGET_OS_IOS))
231*d4514f0bSApple OSS Distributions {
232*d4514f0bSApple OSS Distributions if (platform_is_virtual_machine()) {
233*d4514f0bSApple OSS Distributions T_SKIP("Test not supposed to run on virtual machine. rdar://132930927");
234*d4514f0bSApple OSS Distributions }
235*d4514f0bSApple OSS Distributions
236*d4514f0bSApple OSS Distributions BACKGROUND_PRI = 4;
237*d4514f0bSApple OSS Distributions NUM_THREADS = 1000;
238*d4514f0bSApple OSS Distributions SLEEP_SECONDS = 20;
239*d4514f0bSApple OSS Distributions /* Matches DEFAULT_INTERRUPT_MASKED_TIMEOUT value in XNU */
240*d4514f0bSApple OSS Distributions INTERRUPT_DISABLE_TIMEOUT_NS = 500 * NSEC_PER_USEC; // 500 microseconds
241*d4514f0bSApple OSS Distributions
242*d4514f0bSApple OSS Distributions __block int ret;
243*d4514f0bSApple OSS Distributions
244*d4514f0bSApple OSS Distributions /* Configure interrupts-disabled timeout to drop a ktracepoint */
245*d4514f0bSApple OSS Distributions uint64_t emit_tracepoint_mode = 1;
246*d4514f0bSApple OSS Distributions ret = sysctlbyname("kern.interrupt_masked_debug_mode",
247*d4514f0bSApple OSS Distributions &old_interrupt_debug_mode, &old_interrupt_debug_mode_size,
248*d4514f0bSApple OSS Distributions &emit_tracepoint_mode, sizeof(emit_tracepoint_mode));
249*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_debug_mode");
250*d4514f0bSApple OSS Distributions T_ATEND(restore_interrupt_disable_debug_mode);
251*d4514f0bSApple OSS Distributions /* Configure the preemption-disabled debug mode as well, to avoid panicking if the test fails */
252*d4514f0bSApple OSS Distributions ret = sysctlbyname("kern.sched_preemption_disable_debug_mode",
253*d4514f0bSApple OSS Distributions &old_preemption_debug_mode, &old_preemption_debug_mode_size,
254*d4514f0bSApple OSS Distributions &emit_tracepoint_mode, sizeof(emit_tracepoint_mode));
255*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.sched_preemption_disable_debug_mode");
256*d4514f0bSApple OSS Distributions T_ATEND(restore_preemption_disable_debug_mode);
257*d4514f0bSApple OSS Distributions
258*d4514f0bSApple OSS Distributions /* Set interrupts-disabled timeout threshold */
259*d4514f0bSApple OSS Distributions uint64_t disable_timeout = nanos_to_abs(INTERRUPT_DISABLE_TIMEOUT_NS);
260*d4514f0bSApple OSS Distributions ret = sysctlbyname("kern.interrupt_masked_threshold_mt",
261*d4514f0bSApple OSS Distributions &old_interrupt_disable_timeout, &old_interrupt_disable_timeout_size,
262*d4514f0bSApple OSS Distributions &disable_timeout, sizeof(disable_timeout));
263*d4514f0bSApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_threshold_mt");
264*d4514f0bSApple OSS Distributions T_ATEND(restore_interrupt_disable_timeout);
265*d4514f0bSApple OSS Distributions
266*d4514f0bSApple OSS Distributions /* Use ktrace to observe if the interrupt-disable timeout drops a tracepoint */
267*d4514f0bSApple OSS Distributions ktrace_session_t session = ktrace_session_create();
268*d4514f0bSApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(session, "ktrace_session_create");
269*d4514f0bSApple OSS Distributions char filepath_arr[MAXPATHLEN] = "";
270*d4514f0bSApple OSS Distributions const char *tmp_dir = dt_tmpdir();
271*d4514f0bSApple OSS Distributions strlcpy(filepath_arr, tmp_dir, sizeof(filepath_arr));
272*d4514f0bSApple OSS Distributions strlcat(filepath_arr, "/", sizeof(filepath_arr));
273*d4514f0bSApple OSS Distributions strlcat(filepath_arr, ktrace_file_short_name, sizeof(filepath_arr));
274*d4514f0bSApple OSS Distributions ret = remove(filepath_arr);
275*d4514f0bSApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_TRUE((ret == 0) || (errno == ENOENT), "remove");
276*d4514f0bSApple OSS Distributions char *filepath = filepath_arr;
277*d4514f0bSApple OSS Distributions ret = ktrace_events_filter(session, "C0x01", ^(__unused ktrace_event_t event){}); // records scheduler tracepoints
278*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_events_filter");
279*d4514f0bSApple OSS Distributions ktrace_set_completion_handler(session, ^{
280*d4514f0bSApple OSS Distributions search_for_interrupt_disable_timeout_tracepoint(filepath);
281*d4514f0bSApple OSS Distributions });
282*d4514f0bSApple OSS Distributions ret = ktrace_start_writing_path(session, filepath, 0);
283*d4514f0bSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start_writing_path");
284*d4514f0bSApple OSS Distributions
285*d4514f0bSApple OSS Distributions /* Spin up lots of threads, each creating and joining its own thread group */
286*d4514f0bSApple OSS Distributions T_LOG("Creating %d threads at pri %d, each with a unique thread group", NUM_THREADS, BACKGROUND_PRI);
287*d4514f0bSApple OSS Distributions start_timestamp = mach_absolute_time();
288*d4514f0bSApple OSS Distributions pthread_t *bg_threads = malloc(sizeof(pthread_t) * (size_t)NUM_THREADS);
289*d4514f0bSApple OSS Distributions start_threads(bg_threads, make_tg_and_spin, BACKGROUND_PRI, NUM_THREADS);
290*d4514f0bSApple OSS Distributions
291*d4514f0bSApple OSS Distributions T_LOG("Waiting %llu seconds to see if the scheduler can handle it...", SLEEP_SECONDS);
292*d4514f0bSApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SLEEP_SECONDS * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
293*d4514f0bSApple OSS Distributions ktrace_end(session, 0);
294*d4514f0bSApple OSS Distributions });
295*d4514f0bSApple OSS Distributions dispatch_main();
296*d4514f0bSApple OSS Distributions }
297