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