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