==> tests/place.c <==1/* sched_tests.rs: placement_respects_constraints, same_inputs_same_decisions, reservations_are_admission,
2 * a_member_down_is_replaced_after_the_grace, and node_shape_filters_members' placement. */
3#include "fixture.h"
4#include "mesh/check.h"
5
6static void node_shape(void) {
7 msm_member ms[4];
8 fleet4(ms);
9 mfd_doc d = doc_new();
10 mesh_needs n = needs("cuda", "metal", NULL);
11 n.warps = 16;
12 n.shared = 48 << 10;
13 mfd_prog_put(&d, "pt", prog_of(n));
14 msm_perfs perf = {0};
15 msw_weights w = msw_default();
16 msp_input in = {&d, ms, 4, &perf, &w};
17 mt_strs ch;
18 msp_explains ex;
19 mfd_doc out = msp_place(&in, &ch, &ex);
20 const msp_explain *e = msp_explains_get(&ex, "pt");
21 bool ok3 = true, rejected3 = false;
22 for (size_t i = 0; i < e->nrows; i++) {
23 if (e->rows[i].k < 3 && !e->rows[i].ok) ok3 = false;
24 if (e->rows[i].k == 3 && !e->rows[i].ok) rejected3 = true;
25 }
26 CHECK(ok3 && rejected3);
27 mfd_doc_free(&out), mfd_doc_free(&d);
28 mt_strs_free(&ch);
29 msp_explains_free(&ex);
30 free_members(ms, 4);
31}
32
33static void constraints(void) {
34 msm_member ms[4];
35 fleet4(ms);
36 mfd_doc d = doc_new();
37 mesh_needs n;
38 n = needs("metal", NULL, NULL), n.replicas = (mesh_replicas){false, 1}, mfd_prog_put(&d, "m", prog_of(n));
39 n = needs("cuda", "metal", "wasm"), n.replicas = (mesh_replicas){false, 2}, mfd_prog_put(&d, "r2", prog_of(n));
40 n = needs("wasm", NULL, NULL), n.replicas = (mesh_replicas){false, 1}, n.arch = mt_strdup("x86_64"), mfd_prog_put(&d, "x86", prog_of(n));
41 n = needs("wasm", NULL, NULL), n.replicas = (mesh_replicas){false, 1};
42 for (uint32_t k = 0; k < 4; k++) msn_terms_push(&n.avoid, &n.navoid, term(MESH_TERM_SYSTEM, NULL, k));
43 mfd_prog_put(&d, "never", prog_of(n));
44 n = needs("cuda", NULL, NULL), mfd_prog_put(&d, "all", prog_of(n));
45 n = needs("wasm", NULL, NULL), n.replicas = (mesh_replicas){false, 1}, n.view_bytes = 8 << 20, mfd_prog_put(&d, "huge", prog_of(n));
46 mfd_doc p = placed(ms, 4, &d);
47 CHECK(at_is(&p, "m", (uint32_t[]){3}, 1));
48 const mfd_prog *r2 = mfd_prog_get(&p, "r2");
49 CHECK(r2->at.some && r2->at.l.n == 2 && r2->at.l.v[0] != r2->at.l.v[1]);
50 CHECK(at_is(&p, "x86", (uint32_t[]){2}, 1));
51 CHECK(at_is(&p, "never", NULL, 0));
52 CHECK(mt_starts(mfd_prog_get(&p, "never")->why, "unplaced"));
53 CHECK(!mfd_prog_get(&p, "all")->at.some);
54 CHECK(at_is(&p, "huge", NULL, 0));
55 CHECK(mt_contains(mfd_prog_get(&p, "huge")->why, "view heap"));
56 /* A second pass changes nothing (a valid placement is kept). */
57 msm_perfs perf = {0};
58 msw_weights w = msw_default();
59 msp_input in = {&p, ms, 4, &perf, &w};
60 mt_strs ch;
61 msp_explains ex;
62 mfd_doc q = msp_place(&in, &ch, &ex);
63 CHECK_U(ch.n, 0);
64 CHECK(mfd_doc_eq(&q, &p));
65 char *t = msp_explain_text(msp_explains_get(&ex, "m"));
66 CHECK(mt_contains(t, "system 0 rejected backends metal"));
67 free(t);
68 mt_strs_free(&ch);
69 msp_explains_free(&ex);
70 mfd_doc_free(&q);
71 /* A member where it failed is filtered (the leader remembers it), and the program moves off it. */
72 ms_set(&ms[3].fails, "m", "load m: no image", true);
73 q = placed(ms, 4, &p);
74 CHECK(at_is(&q, "m", NULL, 0));
75 CHECK(mt_contains(mfd_prog_get(&q, "m")->why, "failed here"));
76 mfd_doc_free(&q), mfd_doc_free(&p), mfd_doc_free(&d);
77 free_members(ms, 4);
78}
79
80static void same_inputs(void) {
81 msm_member ms[4];
82 for (uint32_t k = 0; k < 4; k++) {
83 ms[k] = member(0, "cuda", "h");
84 ms[k].id = k;
85 }
86 mfd_doc d = doc_new();
87 mesh_needs n = needs("cuda", NULL, NULL);
88 n.replicas = (mesh_replicas){false, 2};
89 mfd_prog_put(&d, "a", prog_of(n));
90 n = needs("cuda", NULL, NULL);
91 n.replicas = (mesh_replicas){false, 1};
92 mfd_prog_put(&d, "b", prog_of(n));
93 mfd_doc p1 = placed(ms, 4, &d), p2 = placed(ms, 4, &d);
94 CHECK(mfd_doc_eq(&p1, &p2));
95 CHECK(at_is(&p1, "a", (uint32_t[]){0, 1}, 2));
96 CHECK(at_is(&p1, "b", (uint32_t[]){2}, 1));
97 mfd_doc dp = mfd_doc_clone(&d);
98 mfd_prog_get(&dp, "b")->needs.pack = true;
99 mfd_doc pp = placed(ms, 4, &dp);
100 CHECK(at_is(&pp, "b", (uint32_t[]){0}, 1));
101 mfd_doc_free(&p1), mfd_doc_free(&p2), mfd_doc_free(&dp), mfd_doc_free(&pp), mfd_doc_free(&d);
102 free_members(ms, 4);
103}
104
105static void reservations(void) {
106 msm_member ms[4];
107 fleet4(ms);
108 for (int i = 0; i < 4; i++) ms[i].cpus = 4;
109 mfd_doc d = doc_new();
110 const char *names[] = {"p0", "p1", "p2", "p3", "p4"};
111 for (int i = 0; i < 5; i++) {
112 mesh_needs n = needs("wasm", NULL, NULL);
113 n.replicas = (mesh_replicas){false, 1};
114 n.cpu = 2.0f;
115 n.pack = true;
116 mfd_prog_put(&d, names[i], prog_of(n));
117 }
118 mfd_doc p = placed(ms, 4, &d);
119 uint32_t used = 0;
120 for (int i = 0; i < 4; i++) {
121 const mfd_prog *x = mfd_prog_get(&p, names[i]);
122 CHECK(x->at.some && x->at.l.n == 1);
123 CHECK(!(used >> x->at.l.v[0] & 1));
124 used |= 1u << x->at.l.v[0];
125 }
126 CHECK(at_is(&p, "p4", NULL, 0));
127 CHECK(mt_contains(mfd_prog_get(&p, "p4")->why, "reserved"));
128 mfd_doc_free(&p), mfd_doc_free(&d);
129 free_members(ms, 4);
130 /* Views: two of 4 MiB do not fit one member's 7000 KiB heap run. */
131 fleet4(ms);
132 d = doc_new();
133 for (int i = 0; i < 2; i++) {
134 mesh_needs n = needs("wasm", NULL, NULL);
135 n.replicas = (mesh_replicas){false, 1};
136 n.view_bytes = 4 << 20;
137 n.pack = true;
138 mfd_prog_put(&d, i ? "v1" : "v0", prog_of(n));
139 }
140 p = placed(ms, 4, &d);
141 CHECK(!ml_opt_eq(&mfd_prog_get(&p, "v0")->at, &mfd_prog_get(&p, "v1")->at));
142 mfd_doc_free(&p), mfd_doc_free(&d);
143 free_members(ms, 4);
144}
145
146static void member_down_replaced(void) {
147 msm_member ms[4];
148 fleet4(ms);
149 mfd_doc d0 = doc_new();
150 mesh_needs n = needs("cuda", NULL, NULL);
151 n.replicas = (mesh_replicas){false, 1};
152 msn_terms_push(&n.prefer, &n.nprefer, term(MESH_TERM_SYSTEM, NULL, 1));
153 mfd_prog_put(&d0, "a", prog_of(n));
154 mfd_doc d = placed(ms, 4, &d0);
155 CHECK(at_is(&d, "a", (uint32_t[]){1}, 1));
156 ms[1].up = false;
157 ms[1].down_ms = 1000;
158 mfd_doc q = placed(ms, 4, &d);
159 CHECK(at_is(&q, "a", (uint32_t[]){1}, 1));
160 mfd_doc_free(&q);
161 ms[1].down_ms = 3000;
162 mfd_doc p = placed(ms, 4, &d);
163 const mfd_prog *a = mfd_prog_get(&p, "a");
164 CHECK(a->at.some && a->at.l.n == 1 && a->at.l.v[0] != 1);
165 CHECK(mt_contains(a->why, "replaced 1"));
166 mfd_doc_free(&p), mfd_doc_free(&d), mfd_doc_free(&d0);
167 free_members(ms, 4);
168}
169
170int main(void) {
171 node_shape();
172 constraints();
173 same_inputs();
174 reservations();
175 member_down_replaced();
176 return mesh_check_done();
177}