xref: /xnu-12377.81.4/tests/sched/clutch_runqueue.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1*043036a2SApple OSS Distributions // Copyright (c) 2023 Apple Inc.  All rights reserved.
2*043036a2SApple OSS Distributions 
3*043036a2SApple OSS Distributions #include <string.h>
4*043036a2SApple OSS Distributions 
5*043036a2SApple OSS Distributions #include "sched_test_harness/sched_policy_darwintest.h"
6*043036a2SApple OSS Distributions #include "sched_test_harness/sched_clutch_harness.h"
7*043036a2SApple OSS Distributions 
8*043036a2SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
9*043036a2SApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
10*043036a2SApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("scheduler"),
11*043036a2SApple OSS Distributions     T_META_RUN_CONCURRENTLY(true),
12*043036a2SApple OSS Distributions     T_META_OWNER("emily_peterson"));
13*043036a2SApple OSS Distributions 
14*043036a2SApple OSS Distributions #define NUM_RAND_SEEDS 5
15*043036a2SApple OSS Distributions static unsigned int rand_seeds[NUM_RAND_SEEDS] = {377111, 2738572, 1717171, 4990221, 777777};
16*043036a2SApple OSS Distributions 
17*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_processor_bound,
18*043036a2SApple OSS Distributions     "Processor-bound threads vs. Regular threads")
19*043036a2SApple OSS Distributions {
20*043036a2SApple OSS Distributions 	int ret;
21*043036a2SApple OSS Distributions 	init_runqueue_harness();
22*043036a2SApple OSS Distributions 
23*043036a2SApple OSS Distributions 	struct thread_group *high_tg = create_tg(clutch_interactivity_score_max);
24*043036a2SApple OSS Distributions 	struct thread_group *low_tg = create_tg(0);
25*043036a2SApple OSS Distributions 
26*043036a2SApple OSS Distributions 	test_thread_t lowest_bound = create_thread(TH_BUCKET_SHARE_BG, low_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_BG]);
27*043036a2SApple OSS Distributions 	set_thread_processor_bound(lowest_bound, get_default_cpu());
28*043036a2SApple OSS Distributions 	test_thread_t highest_bound = create_thread(TH_BUCKET_SHARE_IN, high_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_IN]);
29*043036a2SApple OSS Distributions 	set_thread_processor_bound(highest_bound, get_default_cpu());
30*043036a2SApple OSS Distributions 	test_thread_t lowest_unbound = create_thread(TH_BUCKET_SHARE_BG, low_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_BG]);
31*043036a2SApple OSS Distributions 	test_thread_t highest_unbound = create_thread(TH_BUCKET_SHARE_IN, high_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_IN]);
32*043036a2SApple OSS Distributions 
33*043036a2SApple OSS Distributions 	for (int i = 0; i < NUM_RAND_SEEDS; i++) {
34*043036a2SApple OSS Distributions 		enqueue_threads_rand_order(default_target, rand_seeds[i], 4, lowest_bound, highest_bound, lowest_unbound, highest_unbound);
35*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered(default_target, 4, highest_bound, highest_unbound, lowest_bound, lowest_unbound);
36*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "Processor-bound failed to win tie-break");
37*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
38*043036a2SApple OSS Distributions 	}
39*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Processor-bound threads win priority tie-breaker");
40*043036a2SApple OSS Distributions 
41*043036a2SApple OSS Distributions 	test_thread_t bound = create_thread(TH_BUCKET_SHARE_DF, low_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF] - 1);
42*043036a2SApple OSS Distributions 	set_thread_processor_bound(bound, get_default_cpu());
43*043036a2SApple OSS Distributions 	test_thread_t higherpri_unbound = create_thread(TH_BUCKET_SHARE_DF, low_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
44*043036a2SApple OSS Distributions 	test_thread_t interactive_higherpri_unbound = create_thread(TH_BUCKET_SHARE_DF, high_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
45*043036a2SApple OSS Distributions 	test_thread_t interactive_lowerpri_unbound = create_thread(TH_BUCKET_SHARE_DF, high_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF] - 2);
46*043036a2SApple OSS Distributions 	for (int i = 0; i < NUM_RAND_SEEDS; i++) {
47*043036a2SApple OSS Distributions 		enqueue_threads_rand_order(default_target, rand_seeds[i], 4, bound, higherpri_unbound, interactive_higherpri_unbound, interactive_lowerpri_unbound);
48*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered(default_target, 4, interactive_higherpri_unbound, bound, interactive_lowerpri_unbound, higherpri_unbound);
49*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "Priority and Clutch interactivity score not factored correctly against processor-bound thread");
50*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
51*043036a2SApple OSS Distributions 	}
52*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Clutch root represented against processor-bound threads by highest pri thread in the highest pri Clutch bucket");
53*043036a2SApple OSS Distributions }
54*043036a2SApple OSS Distributions 
55*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_aboveui,
56*043036a2SApple OSS Distributions     "Above UI vs. timeshare FG root buckets")
57*043036a2SApple OSS Distributions {
58*043036a2SApple OSS Distributions 	int ret;
59*043036a2SApple OSS Distributions 	init_runqueue_harness();
60*043036a2SApple OSS Distributions 
61*043036a2SApple OSS Distributions 	struct thread_group *same_tg = create_tg(clutch_interactivity_score_max);
62*043036a2SApple OSS Distributions 	test_thread_t aboveui = create_thread(TH_BUCKET_FIXPRI, same_tg, root_bucket_to_highest_pri[TH_BUCKET_FIXPRI]);
63*043036a2SApple OSS Distributions 	set_thread_sched_mode(aboveui, TH_MODE_FIXED);
64*043036a2SApple OSS Distributions 	test_thread_t low_fg = create_thread(TH_BUCKET_SHARE_FG, same_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_FG]);
65*043036a2SApple OSS Distributions 	test_thread_t high_fg = create_thread(TH_BUCKET_SHARE_FG, same_tg, root_bucket_to_highest_pri[TH_BUCKET_FIXPRI] + 1);
66*043036a2SApple OSS Distributions 
67*043036a2SApple OSS Distributions 	for (int i = 0; i < NUM_RAND_SEEDS; i++) {
68*043036a2SApple OSS Distributions 		enqueue_threads_rand_order(default_target, rand_seeds[i], 3, aboveui, low_fg, high_fg);
69*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered(default_target, 3, high_fg, aboveui, low_fg);
70*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "Aboveui vs. foreground threads dequeued out of order");
71*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
72*043036a2SApple OSS Distributions 	}
73*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Aboveui vs. foreground ordered according to priority");
74*043036a2SApple OSS Distributions }
75*043036a2SApple OSS Distributions 
76*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_diff_root_bucket,
77*043036a2SApple OSS Distributions     "Different root buckets (EDF, Starvation Avoidance Mode, and Warp)")
78*043036a2SApple OSS Distributions {
79*043036a2SApple OSS Distributions 	int ret;
80*043036a2SApple OSS Distributions 	init_runqueue_harness();
81*043036a2SApple OSS Distributions 
82*043036a2SApple OSS Distributions 	struct thread_group *same_tg = create_tg(0);
83*043036a2SApple OSS Distributions 	int num_threads = TH_BUCKET_SCHED_MAX - 1;
84*043036a2SApple OSS Distributions 	test_thread_t threads[num_threads];
85*043036a2SApple OSS Distributions 	test_thread_t rev_threads[num_threads];
86*043036a2SApple OSS Distributions 	test_thread_t warper_threads[num_threads];
87*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
88*043036a2SApple OSS Distributions 		threads[bucket - 1] = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
89*043036a2SApple OSS Distributions 		rev_threads[num_threads - bucket] = threads[bucket - 1];
90*043036a2SApple OSS Distributions 		warper_threads[bucket - 1] = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
91*043036a2SApple OSS Distributions 	}
92*043036a2SApple OSS Distributions 
93*043036a2SApple OSS Distributions 	/* Validate natural EDF between root buckets */
94*043036a2SApple OSS Distributions 	for (int i = 0; i < NUM_RAND_SEEDS; i++) {
95*043036a2SApple OSS Distributions 		enqueue_threads_arr_rand_order(default_target, rand_seeds[i], num_threads, threads);
96*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered_arr(default_target, num_threads, threads);
97*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "Root buckets dequeued out of EDF order, after the first %d threads dequeued were correct", ret);
98*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
99*043036a2SApple OSS Distributions 	}
100*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Basic EDF root bucket order respected");
101*043036a2SApple OSS Distributions 
102*043036a2SApple OSS Distributions 	/* Warp lets high root buckets win despite reverse ordering of root bucket deadlines */
103*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_BG; bucket >= TH_BUCKET_SHARE_FG; bucket--) {
104*043036a2SApple OSS Distributions 		if (bucket < TH_BUCKET_SHARE_BG) {
105*043036a2SApple OSS Distributions 			increment_mock_time_us(clutch_root_bucket_wcel_us[bucket + 1] - clutch_root_bucket_wcel_us[bucket] + 1);
106*043036a2SApple OSS Distributions 		}
107*043036a2SApple OSS Distributions 		enqueue_thread(default_target, warper_threads[bucket - 1]);
108*043036a2SApple OSS Distributions 		enqueue_thread(default_target, threads[bucket - 1]);
109*043036a2SApple OSS Distributions 	}
110*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
111*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, warper_threads[bucket - 1]);
112*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Root bucket %d failed to warp ahead", bucket);
113*043036a2SApple OSS Distributions 		increment_mock_time_us(clutch_root_bucket_warp_us[bucket] / 2);
114*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, threads[bucket - 1]);
115*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Root bucket %d's warp window failed to stay open", bucket);
116*043036a2SApple OSS Distributions 		increment_mock_time_us(clutch_root_bucket_warp_us[bucket] / 2 + 1);
117*043036a2SApple OSS Distributions 	}
118*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
119*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Warping and Warp Windows respected");
120*043036a2SApple OSS Distributions 
121*043036a2SApple OSS Distributions 	/* After Warp is exhausted, Starvation Avoidance Mode kicks in to choose the buckets in EDF order */
122*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_BG; bucket >= TH_BUCKET_SHARE_FG; bucket--) {
123*043036a2SApple OSS Distributions 		if (bucket < TH_BUCKET_SHARE_BG) {
124*043036a2SApple OSS Distributions 			increment_mock_time_us(clutch_root_bucket_wcel_us[bucket + 1] - clutch_root_bucket_wcel_us[bucket] + 1);
125*043036a2SApple OSS Distributions 		}
126*043036a2SApple OSS Distributions 		enqueue_thread(default_target, threads[bucket - 1]);
127*043036a2SApple OSS Distributions 	}
128*043036a2SApple OSS Distributions 	ret = dequeue_threads_expect_ordered_arr(default_target, num_threads, rev_threads);
129*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ(ret, -1, "Starvation avoidance failed to kick in, after the first %d threads dequeued were correct", ret);
130*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
131*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Starvation Avoidance Mode respected");
132*043036a2SApple OSS Distributions }
133*043036a2SApple OSS Distributions 
134*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_diff_clutch_bucket,
135*043036a2SApple OSS Distributions     "Same root bucket, different TGs")
136*043036a2SApple OSS Distributions {
137*043036a2SApple OSS Distributions 	int ret;
138*043036a2SApple OSS Distributions 	init_runqueue_harness();
139*043036a2SApple OSS Distributions 
140*043036a2SApple OSS Distributions 	int num_tgs = clutch_interactivity_score_max + 1;
141*043036a2SApple OSS Distributions 	struct thread_group *tgs[num_tgs];
142*043036a2SApple OSS Distributions 	for (int i = 0; i < num_tgs; i++) {
143*043036a2SApple OSS Distributions 		tgs[i] = create_tg(i);
144*043036a2SApple OSS Distributions 	}
145*043036a2SApple OSS Distributions 
146*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
147*043036a2SApple OSS Distributions 		test_thread_t threads[num_tgs];
148*043036a2SApple OSS Distributions 		for (int i = 0; i < num_tgs; i++) {
149*043036a2SApple OSS Distributions 			threads[i] = create_thread(bucket, tgs[clutch_interactivity_score_max - i], root_bucket_to_highest_pri[bucket]);
150*043036a2SApple OSS Distributions 		}
151*043036a2SApple OSS Distributions 
152*043036a2SApple OSS Distributions 		for (int i = 0; i < NUM_RAND_SEEDS; i++) {
153*043036a2SApple OSS Distributions 			enqueue_threads_arr_rand_order(default_target, rand_seeds[i], num_tgs, threads);
154*043036a2SApple OSS Distributions 			ret = dequeue_threads_expect_ordered_arr(default_target, num_tgs, threads);
155*043036a2SApple OSS Distributions 			T_QUIET; T_EXPECT_EQ(ret, -1, "Unique interactivity scores dequeued out-of-order, after the first %d threads dequeued were correct", ret);
156*043036a2SApple OSS Distributions 			T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
157*043036a2SApple OSS Distributions 		}
158*043036a2SApple OSS Distributions 	}
159*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Interactivity scores between Clutch buckets respected");
160*043036a2SApple OSS Distributions 
161*043036a2SApple OSS Distributions 	struct thread_group *low_tg = create_tg(clutch_interactivity_score_max / 2);
162*043036a2SApple OSS Distributions 	struct thread_group *high_tg = create_tg((clutch_interactivity_score_max / 2) + 2);
163*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
164*043036a2SApple OSS Distributions 		test_thread_t lowpri_but_interactive = create_thread(bucket, high_tg, root_bucket_to_highest_pri[bucket] - 1);
165*043036a2SApple OSS Distributions 		test_thread_t highpri = create_thread(bucket, low_tg, root_bucket_to_highest_pri[bucket]);
166*043036a2SApple OSS Distributions 
167*043036a2SApple OSS Distributions 		for (int order = 0; order < 2; order++) {
168*043036a2SApple OSS Distributions 			enqueue_threads(default_target, 2, (order == 0 ? lowpri_but_interactive : highpri), (order == 0 ? highpri : lowpri_but_interactive));
169*043036a2SApple OSS Distributions 			ret = dequeue_threads_expect_ordered(default_target, 2, lowpri_but_interactive, highpri);
170*043036a2SApple OSS Distributions 			T_QUIET; T_EXPECT_EQ(ret, -1, "Pri %d and i-score %d dequeued before pri %d and i-score %d, enqueue-order %d", root_bucket_to_highest_pri[bucket] - 1, (clutch_interactivity_score_max / 2) + 2, root_bucket_to_highest_pri[bucket], clutch_interactivity_score_max / 2, order);
171*043036a2SApple OSS Distributions 		}
172*043036a2SApple OSS Distributions 
173*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
174*043036a2SApple OSS Distributions 	}
175*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Priority correctly combined with interactivity scores to order Clutch buckets");
176*043036a2SApple OSS Distributions 
177*043036a2SApple OSS Distributions 	struct thread_group *first_tg = create_tg(clutch_interactivity_score_max / 2);
178*043036a2SApple OSS Distributions 	struct thread_group *second_tg = create_tg(clutch_interactivity_score_max / 2);
179*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
180*043036a2SApple OSS Distributions 		test_thread_t first = create_thread(bucket, first_tg, root_bucket_to_highest_pri[bucket]);
181*043036a2SApple OSS Distributions 		test_thread_t second = create_thread(bucket, second_tg, root_bucket_to_highest_pri[bucket]);
182*043036a2SApple OSS Distributions 		enqueue_threads(default_target, 2, first, second);
183*043036a2SApple OSS Distributions 
184*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered(default_target, 2, first, second);
185*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "FIFO order disrespected for threads in two Clutch buckets of equal priority");
186*043036a2SApple OSS Distributions 
187*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
188*043036a2SApple OSS Distributions 	}
189*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Clutch bucket FIFO order respected, for Clutch buckets with the same priority");
190*043036a2SApple OSS Distributions }
191*043036a2SApple OSS Distributions 
192*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_diff_priority,
193*043036a2SApple OSS Distributions     "Same root bucket, same TG, different priorities")
194*043036a2SApple OSS Distributions {
195*043036a2SApple OSS Distributions 	int ret;
196*043036a2SApple OSS Distributions 	init_runqueue_harness();
197*043036a2SApple OSS Distributions 
198*043036a2SApple OSS Distributions 	struct thread_group *same_tg = create_tg(0);
199*043036a2SApple OSS Distributions 
200*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
201*043036a2SApple OSS Distributions 		test_thread_t lowpri = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket] - 1);
202*043036a2SApple OSS Distributions 		test_thread_t highpri = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
203*043036a2SApple OSS Distributions 
204*043036a2SApple OSS Distributions 		for (int order = 0; order < 2; order++) {
205*043036a2SApple OSS Distributions 			enqueue_threads(default_target, 2, (order == 0 ? lowpri : highpri), (order == 0 ? highpri : lowpri));
206*043036a2SApple OSS Distributions 			ret = dequeue_threads_expect_ordered(default_target, 2, highpri, lowpri);
207*043036a2SApple OSS Distributions 			T_QUIET; T_EXPECT_EQ(ret, -1, "Pri %d dequeued before pri %d, enqueue-order %d", root_bucket_to_highest_pri[bucket] - 1, root_bucket_to_highest_pri[bucket], order);
208*043036a2SApple OSS Distributions 		}
209*043036a2SApple OSS Distributions 
210*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
211*043036a2SApple OSS Distributions 	}
212*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("sched_pri order respected, for threads in the same Clutch bucket");
213*043036a2SApple OSS Distributions 
214*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
215*043036a2SApple OSS Distributions 		int num_threads = 10;
216*043036a2SApple OSS Distributions 		test_thread_t threads[num_threads];
217*043036a2SApple OSS Distributions 		for (int i = 0; i < num_threads; i++) {
218*043036a2SApple OSS Distributions 			threads[i] = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
219*043036a2SApple OSS Distributions 			increment_mock_time_us(5);
220*043036a2SApple OSS Distributions 			enqueue_thread(default_target, threads[i]);
221*043036a2SApple OSS Distributions 		}
222*043036a2SApple OSS Distributions 		ret = dequeue_threads_expect_ordered_arr(default_target, num_threads, threads);
223*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(ret, -1, "FIFO order disrespected for %d threads at pri %d", num_threads, root_bucket_to_highest_pri[bucket]);
224*043036a2SApple OSS Distributions 		T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
225*043036a2SApple OSS Distributions 	}
226*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Thread FIFO order respected, for threads in the same Clutch bucket with the same sched_pri");
227*043036a2SApple OSS Distributions }
228*043036a2SApple OSS Distributions 
229*043036a2SApple OSS Distributions /*
230*043036a2SApple OSS Distributions  * 64 bits of fourth argument to CLUTCH_THREAD_SELECT expected to
231*043036a2SApple OSS Distributions  * match the following layout, ordered from most to least significant bit:
232*043036a2SApple OSS Distributions  *
233*043036a2SApple OSS Distributions  * (reserved 23)                 (selection_opened_starvation_avoidance_window 1)
234*043036a2SApple OSS Distributions  *        |      (starvation_avoidance_window_close 12)   | (selection_was_edf 1)
235*043036a2SApple OSS Distributions  *        |                                  |            | |   (traverse mode 3)
236*043036a2SApple OSS Distributions  *        v                                  v            v v      v
237*043036a2SApple OSS Distributions  *        r----------------------wc----------sc----------wsbec-----t--v---
238*043036a2SApple OSS Distributions  *                               ^                       ^ ^ ^        ^
239*043036a2SApple OSS Distributions  *                               |                       | | |       (version 4)
240*043036a2SApple OSS Distributions  *                  (warp_window_close 12)               | | (cluster_id 6)
241*043036a2SApple OSS Distributions  *                                                       | (selection_was_cluster_bound 1)
242*043036a2SApple OSS Distributions  *                                   (selection_opened_warp_window 1)
243*043036a2SApple OSS Distributions  */
244*043036a2SApple OSS Distributions #define CTS_VERSION 1ULL
245*043036a2SApple OSS Distributions #define TRAVERSE_MODE_REMOVE_CONSIDER_CURRENT (1ULL << 4)
246*043036a2SApple OSS Distributions #define TRAVERSE_MODE_CHECK_PREEMPT (2ULL << 4)
247*043036a2SApple OSS Distributions #define CLUSTER_ID(id) (id << 7)
248*043036a2SApple OSS Distributions #define SELECTION_WAS_EDF (1ULL << 13)
249*043036a2SApple OSS Distributions #define SELECTION_WAS_CLUSTER_BOUND (1ULL << 14)
250*043036a2SApple OSS Distributions #define SELECTION_OPENED_STARVATION_AVOIDANCE_WINDOW (1ULL << 15) | SELECTION_WAS_EDF
251*043036a2SApple OSS Distributions #define SELECTION_OPENED_WARP_WINDOW (1ULL << 16)
252*043036a2SApple OSS Distributions #define WINDOW_MASK(bucket, cluster_bound) ( 1ULL << (bucket + cluster_bound * TH_BUCKET_SCHED_MAX) )
253*043036a2SApple OSS Distributions #define STARVATION_AVOIDANCE_WINDOW_CLOSE(bucket, cluster_bound) (WINDOW_MASK(bucket, cluster_bound) << 17)
254*043036a2SApple OSS Distributions #define WARP_WINDOW_CLOSE(bucket, cluster_bound) (WINDOW_MASK(bucket, cluster_bound) << 29)
255*043036a2SApple OSS Distributions 
256*043036a2SApple OSS Distributions /*
257*043036a2SApple OSS Distributions  * We test the selection_was_cluster_bound bit and cluster_id field gated
258*043036a2SApple OSS Distributions  * on the Edge version of this test case.
259*043036a2SApple OSS Distributions  */
260*043036a2SApple OSS Distributions 
261*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_tracepoint_thread_select,
262*043036a2SApple OSS Distributions     "Validate emitted MACH_SCHED_CLUTCH_THREAD_SELECT tracepoints")
263*043036a2SApple OSS Distributions {
264*043036a2SApple OSS Distributions 	int ret;
265*043036a2SApple OSS Distributions 	uint64_t root_bucket_arg;
266*043036a2SApple OSS Distributions 	uint64_t bucket_is_bound = false;
267*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
268*043036a2SApple OSS Distributions 	init_migration_harness(basic_amp);
269*043036a2SApple OSS Distributions 	bucket_is_bound = true;
270*043036a2SApple OSS Distributions #else /* !CONFIG_SCHED_EDGE */
271*043036a2SApple OSS Distributions 	init_runqueue_harness();
272*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
273*043036a2SApple OSS Distributions 	disable_auto_current_thread();
274*043036a2SApple OSS Distributions 
275*043036a2SApple OSS Distributions 	struct thread_group *same_tg = create_tg(0);
276*043036a2SApple OSS Distributions 	int num_threads = TH_BUCKET_SCHED_MAX - 1;
277*043036a2SApple OSS Distributions 	test_thread_t threads[num_threads];
278*043036a2SApple OSS Distributions 	test_thread_t rev_threads[num_threads];
279*043036a2SApple OSS Distributions 	test_thread_t warper_threads[num_threads];
280*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
281*043036a2SApple OSS Distributions 		threads[bucket - 1] = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
282*043036a2SApple OSS Distributions 		rev_threads[num_threads - bucket] = threads[bucket - 1];
283*043036a2SApple OSS Distributions 		warper_threads[bucket - 1] = create_thread(bucket, same_tg, root_bucket_to_highest_pri[bucket]);
284*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
285*043036a2SApple OSS Distributions 		set_thread_cluster_bound(threads[bucket - 1], 0);
286*043036a2SApple OSS Distributions 		set_thread_cluster_bound(warper_threads[bucket - 1], 0);
287*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
288*043036a2SApple OSS Distributions 	}
289*043036a2SApple OSS Distributions 
290*043036a2SApple OSS Distributions 	/* Natural EDF */
291*043036a2SApple OSS Distributions 	enqueue_threads_arr(default_target, num_threads, threads);
292*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
293*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, threads[bucket - 1]);
294*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Root bucket %d failed to warp ahead", bucket);
295*043036a2SApple OSS Distributions 		root_bucket_arg = SELECTION_WAS_EDF | CTS_VERSION;
296*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
297*043036a2SApple OSS Distributions 		root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
298*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
299*043036a2SApple OSS Distributions 		ret = tracepoint_expect(CLUTCH_THREAD_SELECT, (bucket - 1) * 2, 0, bucket, root_bucket_arg);
300*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "EDF CLUTCH_THREAD_SELECT tracepoint");
301*043036a2SApple OSS Distributions 	}
302*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(runqueue_empty(default_target), true, "runqueue_empty");
303*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Correct CLUTCH_THREAD_SELECT tracepoint info for EDF selections");
304*043036a2SApple OSS Distributions 
305*043036a2SApple OSS Distributions 	/* Warp windows */
306*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_BG; bucket >= TH_BUCKET_SHARE_FG; bucket--) {
307*043036a2SApple OSS Distributions 		if (bucket < TH_BUCKET_SHARE_BG) {
308*043036a2SApple OSS Distributions 			increment_mock_time_us(clutch_root_bucket_wcel_us[bucket + 1] - clutch_root_bucket_wcel_us[bucket] + 1);
309*043036a2SApple OSS Distributions 		}
310*043036a2SApple OSS Distributions 		enqueue_thread(default_target, warper_threads[bucket - 1]);
311*043036a2SApple OSS Distributions 		enqueue_thread(default_target, threads[bucket - 1]);
312*043036a2SApple OSS Distributions 	}
313*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
314*043036a2SApple OSS Distributions 		/* Opens a new warp window */
315*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, warper_threads[bucket - 1]);
316*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Root bucket %d failed to warp ahead", bucket);
317*043036a2SApple OSS Distributions 		root_bucket_arg = (bucket < TH_BUCKET_SHARE_BG ? SELECTION_OPENED_WARP_WINDOW : SELECTION_WAS_EDF) | CTS_VERSION;
318*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
319*043036a2SApple OSS Distributions 		root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
320*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
321*043036a2SApple OSS Distributions 		ret = tracepoint_expect(CLUTCH_THREAD_SELECT, bucket * 2 - 1, 0, bucket, root_bucket_arg);
322*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Open warp window CLUTCH_THREAD_SELECT tracepoint");
323*043036a2SApple OSS Distributions 
324*043036a2SApple OSS Distributions 		/* Makes use of the opened warp window */
325*043036a2SApple OSS Distributions 		increment_mock_time_us(clutch_root_bucket_warp_us[bucket] / 2);
326*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, threads[bucket - 1]);
327*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Root bucket %d's warp window failed to stay open", bucket);
328*043036a2SApple OSS Distributions 		root_bucket_arg = (bucket < TH_BUCKET_SHARE_BG ? 0 : SELECTION_WAS_EDF) | CTS_VERSION;
329*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
330*043036a2SApple OSS Distributions 		root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
331*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
332*043036a2SApple OSS Distributions 		ret = tracepoint_expect(CLUTCH_THREAD_SELECT, bucket * 2 - 2, 0, bucket, root_bucket_arg);
333*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Active warp window CLUTCH_THREAD_SELECT tracepoint");
334*043036a2SApple OSS Distributions 
335*043036a2SApple OSS Distributions 		increment_mock_time_us(clutch_root_bucket_warp_us[bucket] / 2 + 1);
336*043036a2SApple OSS Distributions 	}
337*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
338*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Correct CLUTCH_THREAD_SELECT tracepoint info for warp windows");
339*043036a2SApple OSS Distributions 
340*043036a2SApple OSS Distributions 	/* Starvation avoidance windows */
341*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_BG; bucket >= TH_BUCKET_SHARE_FG; bucket--) {
342*043036a2SApple OSS Distributions 		if (bucket < TH_BUCKET_SHARE_BG) {
343*043036a2SApple OSS Distributions 			increment_mock_time_us(clutch_root_bucket_wcel_us[bucket + 1] - clutch_root_bucket_wcel_us[bucket] + 1);
344*043036a2SApple OSS Distributions 		}
345*043036a2SApple OSS Distributions 		enqueue_thread(default_target, threads[bucket - 1]);
346*043036a2SApple OSS Distributions 	}
347*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_BG; bucket >= TH_BUCKET_SHARE_FG; bucket--) {
348*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, threads[bucket - 1]);
349*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Starvation avoidance failed to kick in for bucket %d", bucket);
350*043036a2SApple OSS Distributions 		root_bucket_arg = SELECTION_WAS_EDF | CTS_VERSION;
351*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
352*043036a2SApple OSS Distributions 		root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
353*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
354*043036a2SApple OSS Distributions 		if (bucket == TH_BUCKET_SHARE_BG) {
355*043036a2SApple OSS Distributions 			/* Enough time has passed for the warp windows opened in the last phase to be closed in one go */
356*043036a2SApple OSS Distributions 			for (int warping_bucket = TH_BUCKET_SHARE_FG; warping_bucket < TH_BUCKET_SHARE_BG; warping_bucket++) {
357*043036a2SApple OSS Distributions 				root_bucket_arg |= WARP_WINDOW_CLOSE(warping_bucket, bucket_is_bound);
358*043036a2SApple OSS Distributions 			}
359*043036a2SApple OSS Distributions 		}
360*043036a2SApple OSS Distributions 		if (bucket > TH_BUCKET_SHARE_FG) {
361*043036a2SApple OSS Distributions 			root_bucket_arg |= SELECTION_OPENED_STARVATION_AVOIDANCE_WINDOW;
362*043036a2SApple OSS Distributions 		}
363*043036a2SApple OSS Distributions 		ret = tracepoint_expect(CLUTCH_THREAD_SELECT, (bucket - 1) * 2, 0, bucket, root_bucket_arg);
364*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Open starvation avoidance window CLUTCH_THREAD_SELECT tracepoint");
365*043036a2SApple OSS Distributions 	}
366*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_BG]);
367*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
368*043036a2SApple OSS Distributions 		enqueue_thread(default_target, threads[bucket - 1]);
369*043036a2SApple OSS Distributions 	}
370*043036a2SApple OSS Distributions 	for (int bucket = TH_BUCKET_SHARE_FG; bucket < TH_BUCKET_SCHED_MAX; bucket++) {
371*043036a2SApple OSS Distributions 		ret = dequeue_thread_expect(default_target, threads[bucket - 1]);
372*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "EDF dequeue for bucket %d", bucket);
373*043036a2SApple OSS Distributions 		root_bucket_arg = SELECTION_WAS_EDF | CTS_VERSION;
374*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
375*043036a2SApple OSS Distributions 		root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
376*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
377*043036a2SApple OSS Distributions 		if (bucket == TH_BUCKET_SHARE_FG) {
378*043036a2SApple OSS Distributions 			/* Enough time has passed for the starvation avoidance windows opened in the last phase to be closed in one go */
379*043036a2SApple OSS Distributions 			for (int starved_bucket = TH_BUCKET_SHARE_BG; starved_bucket > TH_BUCKET_SHARE_FG; starved_bucket--) {
380*043036a2SApple OSS Distributions 				root_bucket_arg |= STARVATION_AVOIDANCE_WINDOW_CLOSE(starved_bucket, bucket_is_bound);
381*043036a2SApple OSS Distributions 			}
382*043036a2SApple OSS Distributions 		}
383*043036a2SApple OSS Distributions 		ret = tracepoint_expect(CLUTCH_THREAD_SELECT, (bucket - 1) * 2, 0, bucket, root_bucket_arg);
384*043036a2SApple OSS Distributions 		T_QUIET; T_EXPECT_TRUE(ret, "Closing starvation avoidance window or EDF CLUTCH_THREAD_SELECT tracepoint");
385*043036a2SApple OSS Distributions 	}
386*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(runqueue_empty(default_target), "runqueue_empty");
387*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Correct CLUTCH_THREAD_SELECT tracepoint info for starvation avoidance windows");
388*043036a2SApple OSS Distributions 
389*043036a2SApple OSS Distributions 	/* Different runq traverse modes */
390*043036a2SApple OSS Distributions 	cpu_set_thread_current(get_default_cpu(), threads[0]);
391*043036a2SApple OSS Distributions 	enqueue_thread(default_target, threads[1]);
392*043036a2SApple OSS Distributions 	ret = cpu_dequeue_thread_expect_compare_current(get_default_cpu(), threads[0]);
393*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "EDF dequeue current thread for bucket");
394*043036a2SApple OSS Distributions 	root_bucket_arg = TRAVERSE_MODE_REMOVE_CONSIDER_CURRENT | SELECTION_WAS_EDF | CTS_VERSION;
395*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
396*043036a2SApple OSS Distributions 	root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
397*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
398*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 0, 0, TH_BUCKET_SHARE_FG, root_bucket_arg);
399*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "Current thread EDF CLUTCH_THREAD_SELECT tracepoint");
400*043036a2SApple OSS Distributions 	ret = cpu_check_preempt_current(get_default_cpu(), false);
401*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "Current thread check preempt");
402*043036a2SApple OSS Distributions 	root_bucket_arg = TRAVERSE_MODE_CHECK_PREEMPT | SELECTION_WAS_EDF | CTS_VERSION;
403*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
404*043036a2SApple OSS Distributions 	root_bucket_arg |= SELECTION_WAS_CLUSTER_BOUND;
405*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
406*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 0, 0, TH_BUCKET_SHARE_FG, root_bucket_arg);
407*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "Current thread check preempt CLUTCH_THREAD_SELECT tracepoint");
408*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Correct CLUTCH_THREAD_SELECT tracepoint info for current thread (traverse modes)");
409*043036a2SApple OSS Distributions #if CONFIG_SCHED_EDGE
410*043036a2SApple OSS Distributions 	/* Test the cluster_id field */
411*043036a2SApple OSS Distributions 	test_thread_t bound_thread = create_thread(TH_BUCKET_SHARE_DF, same_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
412*043036a2SApple OSS Distributions 	set_thread_cluster_bound(bound_thread, 1);
413*043036a2SApple OSS Distributions 	enqueue_thread(pset_target(1), bound_thread);
414*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(pset_target(1), bound_thread);
415*043036a2SApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(ret, "Dequeue single thread on cluster 1");
416*043036a2SApple OSS Distributions 	root_bucket_arg = SELECTION_WAS_EDF | CTS_VERSION | SELECTION_WAS_CLUSTER_BOUND | CLUSTER_ID(1);
417*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 10, 0, TH_BUCKET_SHARE_DF, root_bucket_arg);
418*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "Cluster-bound CLUTCH_THREAD_SELECT tracepoint");
419*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("CLUTCH_THREAD_SELECT tracepoint handles non-zero cluster id");
420*043036a2SApple OSS Distributions #endif /* CONFIG_SCHED_EDGE */
421*043036a2SApple OSS Distributions }
422*043036a2SApple OSS Distributions 
423*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_root_bucket_expired_windows,
424*043036a2SApple OSS Distributions     "Root bucket warp and starvation avoidance windows should expire at the right time")
425*043036a2SApple OSS Distributions {
426*043036a2SApple OSS Distributions 	int ret;
427*043036a2SApple OSS Distributions 	uint64_t root_bucket_arg;
428*043036a2SApple OSS Distributions 	init_runqueue_harness();
429*043036a2SApple OSS Distributions 	disable_auto_current_thread();
430*043036a2SApple OSS Distributions 
431*043036a2SApple OSS Distributions 	struct thread_group *same_tg = create_tg(0);
432*043036a2SApple OSS Distributions 	test_thread_t def_thread = create_thread(TH_BUCKET_SHARE_DF, same_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
433*043036a2SApple OSS Distributions 	test_thread_t in_thread = create_thread(TH_BUCKET_SHARE_IN, same_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_IN]);
434*043036a2SApple OSS Distributions 
435*043036a2SApple OSS Distributions 	/* Expect user_initiated bucket to warp ahread of starved default bucket */
436*043036a2SApple OSS Distributions 	enqueue_thread(default_target, def_thread);
437*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_DF] + 1);
438*043036a2SApple OSS Distributions 	enqueue_thread(default_target, in_thread);
439*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, in_thread);
440*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
441*043036a2SApple OSS Distributions 	root_bucket_arg = SELECTION_OPENED_WARP_WINDOW | CTS_VERSION;
442*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 1, 0, TH_BUCKET_SHARE_IN, root_bucket_arg);
443*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "IN warped ahead, tracepoint");
444*043036a2SApple OSS Distributions 
445*043036a2SApple OSS Distributions 	/* Expect warp window to close and default starvation avoidance window to begin */
446*043036a2SApple OSS Distributions 	enqueue_thread(default_target, in_thread);
447*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_warp_us[TH_BUCKET_SHARE_IN] + 1);
448*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, def_thread);
449*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
450*043036a2SApple OSS Distributions 	root_bucket_arg = WARP_WINDOW_CLOSE(TH_BUCKET_SHARE_IN, false) | SELECTION_OPENED_STARVATION_AVOIDANCE_WINDOW | CTS_VERSION;
451*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 0, 0, TH_BUCKET_SHARE_DF, root_bucket_arg);
452*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "IN closed warp and DEF opened starvation avoidance, tracepoint");
453*043036a2SApple OSS Distributions 
454*043036a2SApple OSS Distributions 	/* Expect default starvation avoidance window to close and refresh warp for user_initiated with natural EDF */
455*043036a2SApple OSS Distributions 	enqueue_thread(default_target, def_thread);
456*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_DF] + 1);
457*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, in_thread);
458*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
459*043036a2SApple OSS Distributions 	root_bucket_arg = STARVATION_AVOIDANCE_WINDOW_CLOSE(TH_BUCKET_SHARE_DF, false) | SELECTION_WAS_EDF | CTS_VERSION;
460*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 1, 0, TH_BUCKET_SHARE_IN, root_bucket_arg);
461*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "DEF closed starvation avoidance window and IN refreshed warp, tracepoint");
462*043036a2SApple OSS Distributions 
463*043036a2SApple OSS Distributions 	/* Expect foreground to warp ahead of starved default bucket */
464*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_DF] + 1);
465*043036a2SApple OSS Distributions 	test_thread_t fg_thread = create_thread(TH_BUCKET_SHARE_FG, same_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_FG]);
466*043036a2SApple OSS Distributions 	enqueue_thread(default_target, fg_thread);
467*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, fg_thread);
468*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
469*043036a2SApple OSS Distributions 	root_bucket_arg = SELECTION_OPENED_WARP_WINDOW | CTS_VERSION;
470*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 2, 0, TH_BUCKET_SHARE_FG, root_bucket_arg);
471*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "FG opened warp window, tracepoint");
472*043036a2SApple OSS Distributions 
473*043036a2SApple OSS Distributions 	/* Expect foreground to close warp window and default to open starvation avoidance window */
474*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_warp_us[TH_BUCKET_SHARE_FG] + 1);
475*043036a2SApple OSS Distributions 	enqueue_thread(default_target, fg_thread);
476*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, def_thread);
477*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
478*043036a2SApple OSS Distributions 	root_bucket_arg = WARP_WINDOW_CLOSE(TH_BUCKET_SHARE_FG, false) | SELECTION_OPENED_STARVATION_AVOIDANCE_WINDOW | CTS_VERSION;
479*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 0, 0, TH_BUCKET_SHARE_DF, root_bucket_arg);
480*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "FG closed warp window and DEF opened starvation avoidance window, tracepoint");
481*043036a2SApple OSS Distributions 
482*043036a2SApple OSS Distributions 	/* Expect default to close starvation avoidance window */
483*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_DF] + 1);
484*043036a2SApple OSS Distributions 	enqueue_thread(default_target, def_thread);
485*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, fg_thread);
486*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
487*043036a2SApple OSS Distributions 	root_bucket_arg = STARVATION_AVOIDANCE_WINDOW_CLOSE(TH_BUCKET_SHARE_DF, false) | SELECTION_WAS_EDF | CTS_VERSION;
488*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 2, 0, TH_BUCKET_SHARE_FG, root_bucket_arg);
489*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "DEF closed starvation avoidance window and FG refreshed warp, tracepoint");
490*043036a2SApple OSS Distributions 
491*043036a2SApple OSS Distributions 	/*
492*043036a2SApple OSS Distributions 	 * Expect user_initiated to experience a full-length warp window
493*043036a2SApple OSS Distributions 	 * (none spent on expired default starvation avoidance window rdar://120562509)
494*043036a2SApple OSS Distributions 	 */
495*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_wcel_us[TH_BUCKET_SHARE_DF] + 1);
496*043036a2SApple OSS Distributions 	enqueue_thread(default_target, in_thread);
497*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, in_thread);
498*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
499*043036a2SApple OSS Distributions 	root_bucket_arg = SELECTION_OPENED_WARP_WINDOW | CTS_VERSION;
500*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 1, 0, TH_BUCKET_SHARE_IN, root_bucket_arg);
501*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "IN opened warp window, tracepoint");
502*043036a2SApple OSS Distributions 	enqueue_thread(default_target, in_thread);
503*043036a2SApple OSS Distributions 	increment_mock_time_us(clutch_root_bucket_warp_us[TH_BUCKET_SHARE_IN] - 1);
504*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, in_thread);
505*043036a2SApple OSS Distributions 	T_QUIET; T_EXPECT_TRUE(ret, "unexpected bucket");
506*043036a2SApple OSS Distributions 	root_bucket_arg = CTS_VERSION;
507*043036a2SApple OSS Distributions 	ret = tracepoint_expect(CLUTCH_THREAD_SELECT, 1, 0, TH_BUCKET_SHARE_IN, root_bucket_arg);
508*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "IN had full-length warp window, tracepoint");
509*043036a2SApple OSS Distributions 
510*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Correct warp/starvation avoidance window expiration");
511*043036a2SApple OSS Distributions }
512*043036a2SApple OSS Distributions 
513*043036a2SApple OSS Distributions SCHED_POLICY_T_DECL(runq_interactivity_starts_maxed,
514*043036a2SApple OSS Distributions     "A new Clutch bucket group should start with max interactivity score")
515*043036a2SApple OSS Distributions {
516*043036a2SApple OSS Distributions 	int ret;
517*043036a2SApple OSS Distributions 	init_runqueue_harness();
518*043036a2SApple OSS Distributions 
519*043036a2SApple OSS Distributions 	struct thread_group *non_interactive_tg = create_tg(clutch_interactivity_score_max - 1);
520*043036a2SApple OSS Distributions 	test_thread_t non_interactive_tg_thread = create_thread(TH_BUCKET_SHARE_DF, non_interactive_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
521*043036a2SApple OSS Distributions 	enqueue_thread(default_target, non_interactive_tg_thread);
522*043036a2SApple OSS Distributions 
523*043036a2SApple OSS Distributions 	struct thread_group *new_tg = create_tg(INITIAL_INTERACTIVITY_SCORE);
524*043036a2SApple OSS Distributions 	test_thread_t new_tg_thread = create_thread(TH_BUCKET_SHARE_DF, new_tg, root_bucket_to_highest_pri[TH_BUCKET_SHARE_DF]);
525*043036a2SApple OSS Distributions 	enqueue_thread(default_target, new_tg_thread);
526*043036a2SApple OSS Distributions 
527*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, new_tg_thread);
528*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "New TG Clutch bucket is interactive");
529*043036a2SApple OSS Distributions 
530*043036a2SApple OSS Distributions 	ret = dequeue_thread_expect(default_target, non_interactive_tg_thread);
531*043036a2SApple OSS Distributions 	T_EXPECT_TRUE(ret, "Non-interactive thread comes second");
532*043036a2SApple OSS Distributions 
533*043036a2SApple OSS Distributions 	SCHED_POLICY_PASS("Interactivity score initialized correctly");
534*043036a2SApple OSS Distributions }
535