1 // Copyright (c) 2024 Apple Inc. All rights reserved.
2
3 #include <stdlib.h>
4 #include <stdio.h>
5
6 #include <darwintest.h>
7 #include <darwintest_utils.h>
8
9 #include "sched_migration_harness.h"
10 #include "sched_harness_impl.h"
11
12 void
init_migration_harness(test_hw_topology_t hw_topology)13 init_migration_harness(test_hw_topology_t hw_topology)
14 {
15 /* Sets up _log and ATEND to close it */
16 init_harness_logging(T_NAME);
17 assert(_log != NULL);
18 assert(hw_topology.num_psets > 0 && hw_topology.total_cpus > 0);
19
20 fprintf(_log, "\tinitializing migration harness\n");
21 set_hw_topology(hw_topology);
22 impl_init_migration_harness(hw_topology);
23 }
24
25 void
set_tg_sched_bucket_preferred_pset(struct thread_group * tg,int sched_bucket,int cluster_id)26 set_tg_sched_bucket_preferred_pset(struct thread_group *tg, int sched_bucket, int cluster_id)
27 {
28 fprintf(_log, "\tset TG %p bucket %d recommended for pset %d\n", (void *)tg, sched_bucket, cluster_id);
29 impl_set_tg_sched_bucket_preferred_pset(tg, sched_bucket, cluster_id);
30 }
31
32 void
set_thread_cluster_bound(test_thread_t thread,int cluster_id)33 set_thread_cluster_bound(test_thread_t thread, int cluster_id)
34 {
35 fprintf(_log, "\tset thread %p bound to cluster %d\n", (void *)thread, cluster_id);
36 impl_set_thread_cluster_bound(thread, cluster_id);
37 }
38
39 int
choose_pset_for_thread(test_thread_t thread)40 choose_pset_for_thread(test_thread_t thread)
41 {
42 int chosen_pset_id = impl_choose_pset_for_thread(thread);
43 fprintf(_log, "for thread %p we chose pset_id %d\n", (void *)thread, chosen_pset_id);
44 return chosen_pset_id;
45 }
46
47 bool
choose_pset_for_thread_expect(test_thread_t thread,int expected_cluster_id)48 choose_pset_for_thread_expect(test_thread_t thread, int expected_cluster_id)
49 {
50 int chosen_pset_id = choose_pset_for_thread(thread);
51 fprintf(_log, "%s: for thread %p we chose pset_id %d, expecting %d\n", chosen_pset_id == expected_cluster_id ?
52 "PASS" : "FAIL", (void *)thread, chosen_pset_id, expected_cluster_id);
53 return chosen_pset_id == expected_cluster_id;
54 }
55
56 bool
thread_avoid_processor_expect(test_thread_t thread,int cpu_id,bool quantum_expiry,bool avoid_expected)57 thread_avoid_processor_expect(test_thread_t thread, int cpu_id, bool quantum_expiry, bool avoid_expected)
58 {
59 bool avoiding = impl_thread_avoid_processor(thread, cpu_id, quantum_expiry);
60 fprintf(_log, "%s: thread %p would avoid cpu %d? %d, expecting to avoid? %d\n", avoiding == avoid_expected ?
61 "PASS" : "FAIL", (void *)thread, cpu_id, avoiding, avoid_expected);
62 return avoiding == avoid_expected;
63 }
64
65 void
cpu_expire_quantum(int cpu_id)66 cpu_expire_quantum(int cpu_id)
67 {
68 impl_cpu_expire_quantum(cpu_id);
69 fprintf(_log, "cpu %d expired quantum\n", cpu_id);
70 }
71
72 test_thread_t
cpu_steal_thread(int cpu_id)73 cpu_steal_thread(int cpu_id)
74 {
75 test_thread_t stolen_thread = impl_steal_thread(cpu_id);
76 fprintf(_log, "on cpu %d, stole thread %p\n", cpu_id, (void *)stolen_thread);
77 return stolen_thread;
78 }
79
80 bool
cpu_processor_balance(int cpu_id)81 cpu_processor_balance(int cpu_id)
82 {
83 bool doing_rebalance = impl_processor_balance(cpu_id);
84 fprintf(_log, "on cpu %d, doing rebalance? %d\n", cpu_id, doing_rebalance);
85 return doing_rebalance;
86 }
87
88 void
set_current_processor(int cpu_id)89 set_current_processor(int cpu_id)
90 {
91 fprintf(_log, "\tset current_processor() to cpu id %d\n", cpu_id);
92 impl_set_current_processor(cpu_id);
93 }
94
95 void
set_pset_load_avg(int cluster_id,int QoS,uint64_t load_avg)96 set_pset_load_avg(int cluster_id, int QoS, uint64_t load_avg)
97 {
98 fprintf(_log, "\tset pset_load_avg for cluster %d QoS %d to %llu\n", cluster_id, QoS, load_avg);
99 impl_set_pset_load_avg(cluster_id, QoS, load_avg);
100 }
101
102 void
set_pset_recommended(int cluster_id)103 set_pset_recommended(int cluster_id)
104 {
105 fprintf(_log, "\tset cluster %d as recommended\n", cluster_id);
106 impl_set_pset_recommended(cluster_id);
107 }
108
109 void
set_pset_derecommended(int cluster_id)110 set_pset_derecommended(int cluster_id)
111 {
112 fprintf(_log, "\tset cluster %d as derecommended\n", cluster_id);
113 impl_set_pset_derecommended(cluster_id);
114 }
115
116 bool
ipi_expect(int cpu_id,test_ipi_type_t ipi_type)117 ipi_expect(int cpu_id, test_ipi_type_t ipi_type)
118 {
119 int found_cpu_id = -1;
120 test_ipi_type_t found_ipi_type = TEST_IPI_NONE;
121 impl_pop_ipi(&found_cpu_id, &found_ipi_type);
122 bool pass = (cpu_id == found_cpu_id) && (ipi_type == found_ipi_type);
123 fprintf(_log, "%s: expected ipi to cpu %d type %u, found ipi to cpu %d type %u\n",
124 pass ? "PASS": "FAIL", cpu_id, ipi_type, found_cpu_id, found_ipi_type);
125 return pass;
126 }
127
128 bool
cpu_check_should_yield(int cpu_id,bool yield_expected)129 cpu_check_should_yield(int cpu_id, bool yield_expected)
130 {
131 bool yielding = impl_thread_should_yield(cpu_id);
132 fprintf(_log, "%s: would yield on cpu %d? %d, expecting to yield? %d\n",
133 yielding == yield_expected ? "PASS" : "FAIL", cpu_id, yielding, yield_expected);
134 return yielding == yield_expected;
135 }
136
137 void
cpu_send_ipi_for_thread(int cpu_id,test_thread_t thread,test_ipi_event_t event)138 cpu_send_ipi_for_thread(int cpu_id, test_thread_t thread, test_ipi_event_t event)
139 {
140 fprintf(_log, "requesting IPI to cpu %d thread %p event %u\n", cpu_id,
141 (void *)thread, event);
142 impl_send_ipi(cpu_id, thread, event);
143 }
144
145 bool
max_parallelism_expect(int qos,uint64_t options,uint32_t expected_parallelism)146 max_parallelism_expect(int qos, uint64_t options, uint32_t expected_parallelism)
147 {
148 uint32_t found_parallelism = impl_qos_max_parallelism(qos, options);
149 fprintf(_log, "expected parallelism %u for QoS %d options %llx, found parallelism %u\n",
150 expected_parallelism, qos, options, found_parallelism);
151 return found_parallelism == expected_parallelism;
152 }
153
154 int
iterate_pset_search_order_expect(int src_pset_id,uint64_t candidate_map,int sched_bucket,int * expected_pset_ids,int num_psets)155 iterate_pset_search_order_expect(int src_pset_id, uint64_t candidate_map, int sched_bucket,
156 int *expected_pset_ids, int num_psets)
157 {
158 int *search_order = impl_iterate_pset_search_order(src_pset_id, candidate_map, sched_bucket);
159 fprintf(_log, "for src pset %d candidate map %llx bucket %d, we found search order:\t",
160 src_pset_id, candidate_map, sched_bucket);
161 int first_failure_ind = -1;
162 for (int i = 0; (i < num_psets) && (search_order[i] != -1); i++) {
163 fprintf(_log, "%2d ", search_order[i]);
164 if ((expected_pset_ids[i] != search_order[i]) && (first_failure_ind == -1)) {
165 first_failure_ind = i;
166 }
167 }
168 fprintf(_log, "\n\t%s: expected search order:\t", (first_failure_ind == -1) ? "PASS" : "FAIL");
169 for (int i = 0; i < num_psets; i++) {
170 fprintf(_log, "%2d ", expected_pset_ids[i]);
171 }
172 fprintf(_log, "\n");
173 return first_failure_ind;
174 }
175