1*4f1223e8SApple OSS Distributions // Copyright (c) 2024 Apple Inc. All rights reserved.
2*4f1223e8SApple OSS Distributions
3*4f1223e8SApple OSS Distributions #include <unistd.h>
4*4f1223e8SApple OSS Distributions #include <stdlib.h>
5*4f1223e8SApple OSS Distributions #include <stdio.h>
6*4f1223e8SApple OSS Distributions #include <pthread.h>
7*4f1223e8SApple OSS Distributions #include <string.h>
8*4f1223e8SApple OSS Distributions #include <mach/mach.h>
9*4f1223e8SApple OSS Distributions #include <mach/mach_time.h>
10*4f1223e8SApple OSS Distributions #include <sys/resource_private.h>
11*4f1223e8SApple OSS Distributions #include <sys/stat.h>
12*4f1223e8SApple OSS Distributions #include <sys/sysctl.h>
13*4f1223e8SApple OSS Distributions #include <stdatomic.h>
14*4f1223e8SApple OSS Distributions #include <sys/work_interval.h>
15*4f1223e8SApple OSS Distributions #include <ktrace.h>
16*4f1223e8SApple OSS Distributions #include <sys/kdebug.h>
17*4f1223e8SApple OSS Distributions
18*4f1223e8SApple OSS Distributions #include <darwintest.h>
19*4f1223e8SApple OSS Distributions #include <darwintest_utils.h>
20*4f1223e8SApple OSS Distributions #include "test_utils.h"
21*4f1223e8SApple OSS Distributions
22*4f1223e8SApple OSS Distributions #define CONFIG_THREAD_GROUPS 1
23*4f1223e8SApple OSS Distributions typedef void *cluster_type_t;
24*4f1223e8SApple OSS Distributions #include "../../osfmk/kern/thread_group.h"
25*4f1223e8SApple OSS Distributions
26*4f1223e8SApple OSS Distributions #include "thread_group_flags_workload_config.h"
27*4f1223e8SApple OSS Distributions
28*4f1223e8SApple OSS Distributions
29*4f1223e8SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
30*4f1223e8SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
31*4f1223e8SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("scheduler"),
32*4f1223e8SApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.thread_groups_supported", 1));
33*4f1223e8SApple OSS Distributions
34*4f1223e8SApple OSS Distributions
35*4f1223e8SApple OSS Distributions static void
workload_config_load(void)36*4f1223e8SApple OSS Distributions workload_config_load(void)
37*4f1223e8SApple OSS Distributions {
38*4f1223e8SApple OSS Distributions int ret;
39*4f1223e8SApple OSS Distributions size_t len = 0;
40*4f1223e8SApple OSS Distributions ret = sysctlbyname("kern.workload_config", NULL, &len,
41*4f1223e8SApple OSS Distributions sched_thread_group_flags_workload_config_plist,
42*4f1223e8SApple OSS Distributions sched_thread_group_flags_workload_config_plist_len);
43*4f1223e8SApple OSS Distributions if (ret == -1 && errno == ENOENT) {
44*4f1223e8SApple OSS Distributions T_SKIP("kern.workload_config failed");
45*4f1223e8SApple OSS Distributions }
46*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kern.workload_config");
47*4f1223e8SApple OSS Distributions }
48*4f1223e8SApple OSS Distributions
49*4f1223e8SApple OSS Distributions static void
workload_config_cleanup(void)50*4f1223e8SApple OSS Distributions workload_config_cleanup(void)
51*4f1223e8SApple OSS Distributions {
52*4f1223e8SApple OSS Distributions size_t len = 0;
53*4f1223e8SApple OSS Distributions sysctlbyname("kern.workload_config", NULL, &len, "", 1);
54*4f1223e8SApple OSS Distributions }
55*4f1223e8SApple OSS Distributions
56*4f1223e8SApple OSS Distributions static void
set_work_interval_id(work_interval_t * handle,uint32_t work_interval_flags,char * workload_id)57*4f1223e8SApple OSS Distributions set_work_interval_id(work_interval_t *handle, uint32_t work_interval_flags, char *workload_id)
58*4f1223e8SApple OSS Distributions {
59*4f1223e8SApple OSS Distributions int ret;
60*4f1223e8SApple OSS Distributions mach_port_t port = MACH_PORT_NULL;
61*4f1223e8SApple OSS Distributions
62*4f1223e8SApple OSS Distributions ret = work_interval_copy_port(*handle, &port);
63*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "work_interval_copy_port");
64*4f1223e8SApple OSS Distributions
65*4f1223e8SApple OSS Distributions struct work_interval_workload_id_params wlid_params = {
66*4f1223e8SApple OSS Distributions .wlidp_flags = WORK_INTERVAL_WORKLOAD_ID_HAS_ID,
67*4f1223e8SApple OSS Distributions .wlidp_wicreate_flags = work_interval_flags,
68*4f1223e8SApple OSS Distributions .wlidp_name = (uintptr_t)workload_id,
69*4f1223e8SApple OSS Distributions };
70*4f1223e8SApple OSS Distributions
71*4f1223e8SApple OSS Distributions ret = __work_interval_ctl(WORK_INTERVAL_OPERATION_SET_WORKLOAD_ID, port, &wlid_params, sizeof(wlid_params));
72*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "WORK_INTERVAL_OPERATION_SET_WORKLOAD_ID");
73*4f1223e8SApple OSS Distributions }
74*4f1223e8SApple OSS Distributions
75*4f1223e8SApple OSS Distributions static void
make_work_interval(work_interval_t * handle,uint32_t work_type_flags,char * workload_id)76*4f1223e8SApple OSS Distributions make_work_interval(work_interval_t *handle, uint32_t work_type_flags, char *workload_id)
77*4f1223e8SApple OSS Distributions {
78*4f1223e8SApple OSS Distributions int ret;
79*4f1223e8SApple OSS Distributions uint32_t work_interval_flags = WORK_INTERVAL_FLAG_JOINABLE | WORK_INTERVAL_FLAG_GROUP | work_type_flags;
80*4f1223e8SApple OSS Distributions ret = work_interval_create(handle, work_interval_flags);
81*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create");
82*4f1223e8SApple OSS Distributions
83*4f1223e8SApple OSS Distributions if (work_type_flags & WORK_INTERVAL_FLAG_HAS_WORKLOAD_ID) {
84*4f1223e8SApple OSS Distributions set_work_interval_id(handle, work_interval_flags, workload_id);
85*4f1223e8SApple OSS Distributions }
86*4f1223e8SApple OSS Distributions }
87*4f1223e8SApple OSS Distributions
88*4f1223e8SApple OSS Distributions static uint64_t
get_thread_group_id(void)89*4f1223e8SApple OSS Distributions get_thread_group_id(void)
90*4f1223e8SApple OSS Distributions {
91*4f1223e8SApple OSS Distributions int ret;
92*4f1223e8SApple OSS Distributions uint64_t tg_id;
93*4f1223e8SApple OSS Distributions size_t tg_id_len = sizeof(tg_id);
94*4f1223e8SApple OSS Distributions ret = sysctlbyname("kern.thread_group_id", &tg_id, &tg_id_len, NULL, 0);
95*4f1223e8SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_SUCCESS(ret, "kern.thread_group_id");
96*4f1223e8SApple OSS Distributions return tg_id;
97*4f1223e8SApple OSS Distributions }
98*4f1223e8SApple OSS Distributions
99*4f1223e8SApple OSS Distributions struct thread_data {
100*4f1223e8SApple OSS Distributions work_interval_t wi_handle;
101*4f1223e8SApple OSS Distributions uint64_t tg_id;
102*4f1223e8SApple OSS Distributions };
103*4f1223e8SApple OSS Distributions
104*4f1223e8SApple OSS Distributions static void *
join_workload_fn(void * arg)105*4f1223e8SApple OSS Distributions join_workload_fn(void *arg)
106*4f1223e8SApple OSS Distributions {
107*4f1223e8SApple OSS Distributions int ret;
108*4f1223e8SApple OSS Distributions struct thread_data *data = (struct thread_data *)arg;
109*4f1223e8SApple OSS Distributions
110*4f1223e8SApple OSS Distributions uint64_t old_tg_id = get_thread_group_id();
111*4f1223e8SApple OSS Distributions
112*4f1223e8SApple OSS Distributions /* Join the thread group associated with the work interval handle */
113*4f1223e8SApple OSS Distributions ret = work_interval_join(data->wi_handle);
114*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "work_interval_join");
115*4f1223e8SApple OSS Distributions
116*4f1223e8SApple OSS Distributions data->tg_id = get_thread_group_id();
117*4f1223e8SApple OSS Distributions T_LOG("Joined TG %llx", data->tg_id);
118*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_NE(data->tg_id, old_tg_id, "Thread failed to join new TG");
119*4f1223e8SApple OSS Distributions return NULL;
120*4f1223e8SApple OSS Distributions }
121*4f1223e8SApple OSS Distributions
122*4f1223e8SApple OSS Distributions static pthread_t *
start_threads(void * (* func)(void *),struct thread_data * datas,int num_threads)123*4f1223e8SApple OSS Distributions start_threads(void *(*func)(void *), struct thread_data *datas, int num_threads)
124*4f1223e8SApple OSS Distributions {
125*4f1223e8SApple OSS Distributions int ret;
126*4f1223e8SApple OSS Distributions pthread_t *threads = (pthread_t *)malloc(sizeof(pthread_t) * num_threads);
127*4f1223e8SApple OSS Distributions pthread_attr_t attr;
128*4f1223e8SApple OSS Distributions ret = pthread_attr_init(&attr);
129*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "pthread_attr_init");
130*4f1223e8SApple OSS Distributions for (int i = 0; i < num_threads; i++) {
131*4f1223e8SApple OSS Distributions struct sched_param param = { .sched_priority = 31 };
132*4f1223e8SApple OSS Distributions ret = pthread_attr_setschedparam(&attr, ¶m);
133*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "pthread_attr_setschedparam");
134*4f1223e8SApple OSS Distributions ret = pthread_create(&threads[i], &attr, func, (void *)&datas[i]);
135*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "pthread_create");
136*4f1223e8SApple OSS Distributions }
137*4f1223e8SApple OSS Distributions return threads;
138*4f1223e8SApple OSS Distributions }
139*4f1223e8SApple OSS Distributions
140*4f1223e8SApple OSS Distributions static void
start_test(ktrace_session_t session,pthread_t * threads,int num_threads)141*4f1223e8SApple OSS Distributions start_test(ktrace_session_t session, pthread_t *threads, int num_threads)
142*4f1223e8SApple OSS Distributions {
143*4f1223e8SApple OSS Distributions dispatch_async(dispatch_get_main_queue(), ^{
144*4f1223e8SApple OSS Distributions /* Wait for threads to finish, as last test action */
145*4f1223e8SApple OSS Distributions for (int i = 0; i < num_threads; i++) {
146*4f1223e8SApple OSS Distributions int ret = pthread_join(threads[i], NULL);
147*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "pthread_join");
148*4f1223e8SApple OSS Distributions }
149*4f1223e8SApple OSS Distributions ktrace_end(session, 0);
150*4f1223e8SApple OSS Distributions });
151*4f1223e8SApple OSS Distributions dispatch_main();
152*4f1223e8SApple OSS Distributions }
153*4f1223e8SApple OSS Distributions
154*4f1223e8SApple OSS Distributions static char *trace_location = NULL;
155*4f1223e8SApple OSS Distributions
156*4f1223e8SApple OSS Distributions static void
delete_trace_file(void)157*4f1223e8SApple OSS Distributions delete_trace_file(void)
158*4f1223e8SApple OSS Distributions {
159*4f1223e8SApple OSS Distributions if (T_FAILCOUNT == 0) {
160*4f1223e8SApple OSS Distributions T_LOG("Test passed, so deleting \"%s\" to save memory", trace_location);
161*4f1223e8SApple OSS Distributions int ret;
162*4f1223e8SApple OSS Distributions /* Delete trace file in order to reclaim disk space on the test device */
163*4f1223e8SApple OSS Distributions ret = remove(trace_location);
164*4f1223e8SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_SUCCESS(ret, "remove trace file");
165*4f1223e8SApple OSS Distributions }
166*4f1223e8SApple OSS Distributions }
167*4f1223e8SApple OSS Distributions
168*4f1223e8SApple OSS Distributions static char *
make_ktrace_filepath(char * short_name)169*4f1223e8SApple OSS Distributions make_ktrace_filepath(char *short_name)
170*4f1223e8SApple OSS Distributions {
171*4f1223e8SApple OSS Distributions int ret;
172*4f1223e8SApple OSS Distributions char *filepath = (char *)malloc(sizeof(char) * MAXPATHLEN);
173*4f1223e8SApple OSS Distributions snprintf(filepath, MAXPATHLEN, "%s/%s.ktrace", dt_tmpdir(), short_name);
174*4f1223e8SApple OSS Distributions ret = remove(filepath);
175*4f1223e8SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_TRUE((ret == 0) || (errno == ENOENT), "remove");
176*4f1223e8SApple OSS Distributions return filepath;
177*4f1223e8SApple OSS Distributions }
178*4f1223e8SApple OSS Distributions
179*4f1223e8SApple OSS Distributions static const int num_workload_ids = 5;
180*4f1223e8SApple OSS Distributions static char *workload_ids[num_workload_ids] = {
181*4f1223e8SApple OSS Distributions "com.test.myapp.efficient",
182*4f1223e8SApple OSS Distributions "com.test.myapp.best_effort",
183*4f1223e8SApple OSS Distributions "com.test.myapp.application",
184*4f1223e8SApple OSS Distributions "com.test.myapp.critical",
185*4f1223e8SApple OSS Distributions "com.test.myapp.shared_flags",
186*4f1223e8SApple OSS Distributions };
187*4f1223e8SApple OSS Distributions
188*4f1223e8SApple OSS Distributions static uint64_t expected_tg_flags[num_workload_ids] = {
189*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_EFFICIENT,
190*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_BEST_EFFORT,
191*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_APPLICATION,
192*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_CRITICAL,
193*4f1223e8SApple OSS Distributions #if TARGET_OS_XR
194*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_MANAGED | THREAD_GROUP_FLAGS_STRICT_TIMERS | THREAD_GROUP_FLAGS_APPLICATION,
195*4f1223e8SApple OSS Distributions #else /* !TARGET_OS_XR */
196*4f1223e8SApple OSS Distributions THREAD_GROUP_FLAGS_APPLICATION,
197*4f1223e8SApple OSS Distributions #endif /* !TARGET_OS_XR */
198*4f1223e8SApple OSS Distributions };
199*4f1223e8SApple OSS Distributions
200*4f1223e8SApple OSS Distributions static int
tg_id_to_index(struct thread_data * datas,int num_datas,uint64_t tg_id)201*4f1223e8SApple OSS Distributions tg_id_to_index(struct thread_data *datas, int num_datas, uint64_t tg_id)
202*4f1223e8SApple OSS Distributions {
203*4f1223e8SApple OSS Distributions int index = -1;
204*4f1223e8SApple OSS Distributions for (int i = 0; i < num_datas; i++) {
205*4f1223e8SApple OSS Distributions if (tg_id == datas[i].tg_id) {
206*4f1223e8SApple OSS Distributions index = i;
207*4f1223e8SApple OSS Distributions break;
208*4f1223e8SApple OSS Distributions }
209*4f1223e8SApple OSS Distributions }
210*4f1223e8SApple OSS Distributions return index;
211*4f1223e8SApple OSS Distributions }
212*4f1223e8SApple OSS Distributions
213*4f1223e8SApple OSS Distributions static void
search_for_workload_id_tg_flags_tracepoints(char * trace_path,int num_workload_ids,struct thread_data * datas)214*4f1223e8SApple OSS Distributions search_for_workload_id_tg_flags_tracepoints(char *trace_path, int num_workload_ids, struct thread_data *datas)
215*4f1223e8SApple OSS Distributions {
216*4f1223e8SApple OSS Distributions __block int ret;
217*4f1223e8SApple OSS Distributions trace_location = trace_path;
218*4f1223e8SApple OSS Distributions T_ATEND(delete_trace_file);
219*4f1223e8SApple OSS Distributions ktrace_session_t read_session = ktrace_session_create();
220*4f1223e8SApple OSS Distributions ret = ktrace_set_file(read_session, trace_path);
221*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_set_file");
222*4f1223e8SApple OSS Distributions __block int num_validated_new_tgs = 0;
223*4f1223e8SApple OSS Distributions ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_THREAD_GROUP, MACH_THREAD_GROUP_NEW), ^(ktrace_event_t e) {
224*4f1223e8SApple OSS Distributions ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
225*4f1223e8SApple OSS Distributions KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
226*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
227*4f1223e8SApple OSS Distributions printf("\n"); // Flush output from ktrace_print_trace_point
228*4f1223e8SApple OSS Distributions uint64_t tg_id = e->arg1;
229*4f1223e8SApple OSS Distributions uint64_t tg_flags = e->arg2;
230*4f1223e8SApple OSS Distributions int workload_ind = tg_id_to_index(datas, num_workload_ids, tg_id);
231*4f1223e8SApple OSS Distributions if (workload_ind != -1) {
232*4f1223e8SApple OSS Distributions T_LOG("MACH_THREAD_GROUP_NEW tracepoint from TG %llx with flags %llx, expecting %llx", tg_id, tg_flags, expected_tg_flags[workload_ind]);
233*4f1223e8SApple OSS Distributions T_EXPECT_EQ(tg_flags, expected_tg_flags[workload_ind], "Correct new TG flags for \"%s\"", workload_ids[workload_ind]);
234*4f1223e8SApple OSS Distributions num_validated_new_tgs++;
235*4f1223e8SApple OSS Distributions }
236*4f1223e8SApple OSS Distributions });
237*4f1223e8SApple OSS Distributions __block int num_validated_flags = 0;
238*4f1223e8SApple OSS Distributions ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_THREAD_GROUP, MACH_THREAD_GROUP_FLAGS), ^(ktrace_event_t e) {
239*4f1223e8SApple OSS Distributions ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
240*4f1223e8SApple OSS Distributions KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
241*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
242*4f1223e8SApple OSS Distributions printf("\n"); // Flush output from ktrace_print_trace_point
243*4f1223e8SApple OSS Distributions uint64_t tg_id = e->arg1;
244*4f1223e8SApple OSS Distributions uint64_t tg_flags = e->arg2;
245*4f1223e8SApple OSS Distributions int workload_ind = tg_id_to_index(datas, num_workload_ids, tg_id);
246*4f1223e8SApple OSS Distributions if (workload_ind != -1) {
247*4f1223e8SApple OSS Distributions T_LOG("MACH_THREAD_GROUP_FLAGS tracepoint from TG %llx with flags %llx, expecting %llx", tg_id, tg_flags, expected_tg_flags[workload_ind]);
248*4f1223e8SApple OSS Distributions T_EXPECT_EQ(tg_flags, expected_tg_flags[workload_ind], "Correct TG flags for \"%s\"", workload_ids[workload_ind]);
249*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_EQ(e->arg3, 0ULL, "tracepoint not dropped at TG creation time");
250*4f1223e8SApple OSS Distributions num_validated_flags++;
251*4f1223e8SApple OSS Distributions }
252*4f1223e8SApple OSS Distributions });
253*4f1223e8SApple OSS Distributions __block int num_validated_joins = 0;
254*4f1223e8SApple OSS Distributions ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_THREAD_GROUP, MACH_THREAD_GROUP_SET), ^(ktrace_event_t e) {
255*4f1223e8SApple OSS Distributions uint64_t new_tg_id = e->arg2;
256*4f1223e8SApple OSS Distributions int workload_ind = tg_id_to_index(datas, num_workload_ids, new_tg_id);
257*4f1223e8SApple OSS Distributions if (workload_ind != -1) {
258*4f1223e8SApple OSS Distributions ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
259*4f1223e8SApple OSS Distributions KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
260*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
261*4f1223e8SApple OSS Distributions printf("\n"); // Flush output from ktrace_print_trace_point
262*4f1223e8SApple OSS Distributions T_LOG("MACH_THREAD_GROUP_SET tracepoint for joining TG %llx", new_tg_id);
263*4f1223e8SApple OSS Distributions num_validated_joins++;
264*4f1223e8SApple OSS Distributions }
265*4f1223e8SApple OSS Distributions });
266*4f1223e8SApple OSS Distributions ktrace_set_completion_handler(read_session, ^{
267*4f1223e8SApple OSS Distributions T_EXPECT_EQ(num_validated_new_tgs, num_workload_ids, "Found all expected MACH_THREAD_GROUP_NEW tracepoints");
268*4f1223e8SApple OSS Distributions T_EXPECT_EQ(num_validated_flags, num_workload_ids, "Found all expected MACH_THREAD_GROUP_FLAGS tracepoints");
269*4f1223e8SApple OSS Distributions T_EXPECT_EQ(num_validated_joins, num_workload_ids, "Found all expected MACH_THREAD_GROUP_SET tracepoints");
270*4f1223e8SApple OSS Distributions T_END;
271*4f1223e8SApple OSS Distributions });
272*4f1223e8SApple OSS Distributions ret = ktrace_start(read_session, dispatch_get_main_queue());
273*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start");
274*4f1223e8SApple OSS Distributions }
275*4f1223e8SApple OSS Distributions
276*4f1223e8SApple OSS Distributions static const char *THREAD_GROUP_FILTER = "S0x01A6";
277*4f1223e8SApple OSS Distributions
278*4f1223e8SApple OSS Distributions T_DECL(thread_group_flags_from_workload_properties,
279*4f1223e8SApple OSS Distributions "Verify that workload properties correctly propagate thread group flags",
280*4f1223e8SApple OSS Distributions T_META_ASROOT(true))
281*4f1223e8SApple OSS Distributions {
282*4f1223e8SApple OSS Distributions int ret;
283*4f1223e8SApple OSS Distributions T_ATEND(workload_config_cleanup);
284*4f1223e8SApple OSS Distributions workload_config_load();
285*4f1223e8SApple OSS Distributions
286*4f1223e8SApple OSS Distributions ktrace_session_t session = ktrace_session_create();
287*4f1223e8SApple OSS Distributions char *filepath = make_ktrace_filepath("thread_group_flags_from_workload_properties");
288*4f1223e8SApple OSS Distributions
289*4f1223e8SApple OSS Distributions ret = ktrace_events_filter(session, THREAD_GROUP_FILTER, ^(__unused ktrace_event_t event){});
290*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_events_filter");
291*4f1223e8SApple OSS Distributions __block struct thread_data *datas = (struct thread_data *)calloc(num_workload_ids, sizeof(struct thread_data));
292*4f1223e8SApple OSS Distributions ktrace_set_completion_handler(session, ^{
293*4f1223e8SApple OSS Distributions search_for_workload_id_tg_flags_tracepoints(filepath, num_workload_ids, datas);
294*4f1223e8SApple OSS Distributions });
295*4f1223e8SApple OSS Distributions ret = ktrace_start_writing_path(session, filepath, 0);
296*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start_writing_path");
297*4f1223e8SApple OSS Distributions T_LOG("Ktrace file being written to %s", filepath);
298*4f1223e8SApple OSS Distributions
299*4f1223e8SApple OSS Distributions /* Create a work interval for each test workload id */
300*4f1223e8SApple OSS Distributions work_interval_t wi_handles[num_workload_ids];
301*4f1223e8SApple OSS Distributions for (int w = 0; w < num_workload_ids; w++) {
302*4f1223e8SApple OSS Distributions make_work_interval(&wi_handles[w], WORK_INTERVAL_TYPE_DEFAULT | WORK_INTERVAL_FLAG_HAS_WORKLOAD_ID, workload_ids[w]);
303*4f1223e8SApple OSS Distributions }
304*4f1223e8SApple OSS Distributions for (int i = 0; i < num_workload_ids; i++) {
305*4f1223e8SApple OSS Distributions datas[i].wi_handle = wi_handles[i];
306*4f1223e8SApple OSS Distributions }
307*4f1223e8SApple OSS Distributions __block pthread_t *threads = start_threads(join_workload_fn, datas, num_workload_ids);
308*4f1223e8SApple OSS Distributions start_test(session, threads, num_workload_ids);
309*4f1223e8SApple OSS Distributions }
310*4f1223e8SApple OSS Distributions
311*4f1223e8SApple OSS Distributions static void *
join_leave_pid_based(void * arg)312*4f1223e8SApple OSS Distributions join_leave_pid_based(void *arg)
313*4f1223e8SApple OSS Distributions {
314*4f1223e8SApple OSS Distributions int ret;
315*4f1223e8SApple OSS Distributions struct thread_data *data = (struct thread_data *)arg;
316*4f1223e8SApple OSS Distributions data->tg_id = get_thread_group_id();
317*4f1223e8SApple OSS Distributions
318*4f1223e8SApple OSS Distributions ret = setpriority(PRIO_DARWIN_CARPLAY_MODE, 0, PRIO_DARWIN_CARPLAY_MODE_ON);
319*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "set_priority(PRIO_DARWIN_CARPLAY_MODE_ON)");
320*4f1223e8SApple OSS Distributions
321*4f1223e8SApple OSS Distributions ret = setpriority(PRIO_DARWIN_CARPLAY_MODE, 0, PRIO_DARWIN_CARPLAY_MODE_OFF);
322*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "set_priority(PRIO_DARWIN_CARPLAY_MODE_OFF)");
323*4f1223e8SApple OSS Distributions
324*4f1223e8SApple OSS Distributions ret = setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON);
325*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "set_priority(PRIO_DARWIN_GAME_MODE_ON)");
326*4f1223e8SApple OSS Distributions
327*4f1223e8SApple OSS Distributions ret = setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF);
328*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "set_priority(PRIO_DARWIN_GAME_MODE_OFF)");
329*4f1223e8SApple OSS Distributions
330*4f1223e8SApple OSS Distributions T_EXPECT_EQ(data->tg_id, get_thread_group_id(), "Unchanged TG");
331*4f1223e8SApple OSS Distributions return NULL;
332*4f1223e8SApple OSS Distributions }
333*4f1223e8SApple OSS Distributions
334*4f1223e8SApple OSS Distributions static void
search_for_pid_based_tg_flags_tracepoints(char * trace_path,int num_threads,struct thread_data * datas)335*4f1223e8SApple OSS Distributions search_for_pid_based_tg_flags_tracepoints(char *trace_path, int num_threads, struct thread_data *datas)
336*4f1223e8SApple OSS Distributions {
337*4f1223e8SApple OSS Distributions __block int ret;
338*4f1223e8SApple OSS Distributions trace_location = trace_path;
339*4f1223e8SApple OSS Distributions T_ATEND(delete_trace_file);
340*4f1223e8SApple OSS Distributions ktrace_session_t read_session = ktrace_session_create();
341*4f1223e8SApple OSS Distributions ret = ktrace_set_file(read_session, trace_path);
342*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_set_file");
343*4f1223e8SApple OSS Distributions __block int tracepoint_idx = 0;
344*4f1223e8SApple OSS Distributions ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_THREAD_GROUP, MACH_THREAD_GROUP_FLAGS), ^(ktrace_event_t e) {
345*4f1223e8SApple OSS Distributions ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
346*4f1223e8SApple OSS Distributions KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
347*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
348*4f1223e8SApple OSS Distributions printf("\n"); // Flush output from ktrace_print_trace_point
349*4f1223e8SApple OSS Distributions uint64_t tg_id = e->arg1;
350*4f1223e8SApple OSS Distributions uint64_t new_tg_flags = e->arg2;
351*4f1223e8SApple OSS Distributions uint64_t old_tg_flags = e->arg3;
352*4f1223e8SApple OSS Distributions int data = tg_id_to_index(datas, num_workload_ids, tg_id);
353*4f1223e8SApple OSS Distributions if (data != -1) {
354*4f1223e8SApple OSS Distributions T_LOG("MACH_THREAD_GROUP_FLAGS tracepoint from TG %llx with new flags %llx from old flags %llx", tg_id, new_tg_flags, old_tg_flags);
355*4f1223e8SApple OSS Distributions bool had_carplay = old_tg_flags & THREAD_GROUP_FLAGS_CARPLAY_MODE;
356*4f1223e8SApple OSS Distributions bool has_carplay = new_tg_flags & THREAD_GROUP_FLAGS_CARPLAY_MODE;
357*4f1223e8SApple OSS Distributions bool had_gamemode = old_tg_flags & THREAD_GROUP_FLAGS_GAME_MODE;
358*4f1223e8SApple OSS Distributions bool has_gamemode = new_tg_flags & THREAD_GROUP_FLAGS_GAME_MODE;
359*4f1223e8SApple OSS Distributions switch (tracepoint_idx) {
360*4f1223e8SApple OSS Distributions case 0:
361*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(!had_gamemode && !has_gamemode, "Game Mode on");
362*4f1223e8SApple OSS Distributions T_EXPECT_TRUE(!had_carplay && has_carplay, "Correct flags for Car Play");
363*4f1223e8SApple OSS Distributions break;
364*4f1223e8SApple OSS Distributions case 1:
365*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(!had_gamemode && !has_gamemode, "Game Mode on");
366*4f1223e8SApple OSS Distributions T_EXPECT_TRUE(had_carplay && !has_carplay, "Correct flags for disabled Car Play");
367*4f1223e8SApple OSS Distributions break;
368*4f1223e8SApple OSS Distributions case 2:
369*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(!had_carplay && !has_carplay, "Car Play on");
370*4f1223e8SApple OSS Distributions T_EXPECT_TRUE(!had_gamemode && has_gamemode, "Correct flags for Game Mode");
371*4f1223e8SApple OSS Distributions break;
372*4f1223e8SApple OSS Distributions case 3:
373*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_TRUE(!had_carplay && !has_carplay, "Car Play on");
374*4f1223e8SApple OSS Distributions T_EXPECT_TRUE(had_gamemode && !has_gamemode, "Correct flags for disabled Game Mode");
375*4f1223e8SApple OSS Distributions break;
376*4f1223e8SApple OSS Distributions }
377*4f1223e8SApple OSS Distributions T_QUIET; T_EXPECT_FALSE(new_tg_flags & THREAD_GROUP_FLAGS_EFFICIENT, "Test runner TG should not be efficient");
378*4f1223e8SApple OSS Distributions tracepoint_idx++;
379*4f1223e8SApple OSS Distributions }
380*4f1223e8SApple OSS Distributions });
381*4f1223e8SApple OSS Distributions ktrace_set_completion_handler(read_session, ^{
382*4f1223e8SApple OSS Distributions T_EXPECT_EQ(tracepoint_idx, 4, "Found all expected MACH_THREAD_GROUP_FLAGS tracepoints");
383*4f1223e8SApple OSS Distributions T_END;
384*4f1223e8SApple OSS Distributions });
385*4f1223e8SApple OSS Distributions ret = ktrace_start(read_session, dispatch_get_main_queue());
386*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start");
387*4f1223e8SApple OSS Distributions }
388*4f1223e8SApple OSS Distributions
389*4f1223e8SApple OSS Distributions T_DECL(thread_group_flags_from_pid_interfaces,
390*4f1223e8SApple OSS Distributions "Verify that Car Play and Game Mode correctly propagate thread group flags",
391*4f1223e8SApple OSS Distributions T_META_ASROOT(true))
392*4f1223e8SApple OSS Distributions {
393*4f1223e8SApple OSS Distributions int ret;
394*4f1223e8SApple OSS Distributions int num_threads = 1;
395*4f1223e8SApple OSS Distributions
396*4f1223e8SApple OSS Distributions ktrace_session_t session = ktrace_session_create();
397*4f1223e8SApple OSS Distributions char *filepath = make_ktrace_filepath("thread_group_flags_from_pid_interfaces");
398*4f1223e8SApple OSS Distributions
399*4f1223e8SApple OSS Distributions ret = ktrace_events_filter(session, THREAD_GROUP_FILTER, ^(__unused ktrace_event_t event){});
400*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_events_filter");
401*4f1223e8SApple OSS Distributions __block struct thread_data *datas = (struct thread_data *)calloc(num_threads, sizeof(struct thread_data));
402*4f1223e8SApple OSS Distributions ktrace_set_completion_handler(session, ^{
403*4f1223e8SApple OSS Distributions search_for_pid_based_tg_flags_tracepoints(filepath, num_threads, datas);
404*4f1223e8SApple OSS Distributions });
405*4f1223e8SApple OSS Distributions ret = ktrace_start_writing_path(session, filepath, 0);
406*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start_writing_path");
407*4f1223e8SApple OSS Distributions T_LOG("Ktrace file being written to %s", filepath);
408*4f1223e8SApple OSS Distributions
409*4f1223e8SApple OSS Distributions __block pthread_t *threads = start_threads(join_leave_pid_based, datas, num_threads);
410*4f1223e8SApple OSS Distributions start_test(session, threads, num_threads);
411*4f1223e8SApple OSS Distributions }
412