skip to content
==> 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}