==> tests/score.c <==1/* sched_tests.rs: filter_keeps_the_first_reason, node_shape_filters_members (the filter part),
2 * scores_follow_share_speed_load_and_prefer. */
3#include "fixture.h"
4#include "mesh/check.h"
5#include "mesh/sched_score.h"
6
7#include <math.h>
8#include <stdlib.h>
9
10static char *why(const msm_member *m, const mesh_needs *n) {
11 char exec[16], *err = NULL;
12 if (msc_filter(m, n, exec, &err)) return mt_fmt("ok %s", exec);
13 return err;
14}
15
16#define CHECK_WHY(m, n, want) \
17 do { \
18 char *w_ = why((m), (n)); \
19 CHECK_S(w_, want); \
20 free(w_); \
21 } while (0)
22
23#define CHECK_WHY_PREFIX(m, n, prefix) \
24 do { \
25 char *w_ = why((m), (n)); \
26 CHECK(mt_starts(w_, prefix)); \
27 free(w_); \
28 } while (0)
29
30int main(void) {
31 msm_member ms[4];
32 fleet4(ms);
33 /* filter_keeps_the_first_reason */
34 mesh_needs n = needs("metal", NULL, NULL);
35 CHECK_WHY(&ms[3], &n, "ok metal");
36 CHECK_WHY(&ms[0], &n, "backends metal: it runs cuda,wasm,native");
37 mesh_needs cw = needs("cuda", "wasm", NULL);
38 CHECK_WHY(&ms[3], &cw, "ok wasm");
39 ms[1].up = false;
40 ms[1].down_ms = 4200;
41 CHECK_WHY(&ms[1], &n, "down for 4.2 s");
42 ms[0].cordoned = true;
43 CHECK_WHY(&ms[0], &n, "cordoned");
44 mesh_needs a = needs("wasm", NULL, NULL);
45 a.arch = mt_strdup("x86_64");
46 CHECK(msc_eligible(&ms[2], &a));
47 CHECK_WHY_PREFIX(&ms[3], &a, "arch x86_64");
48 mesh_needs mm = needs("wasm", NULL, NULL);
49 mm.min_mem_mb = 200000;
50 char *w = why(&ms[2], &mm);
51 CHECK(mt_contains(w, "120000 MiB"));
52 free(w);
53 mesh_needs v = needs("wasm", NULL, NULL);
54 msn_terms_push(&v.avoid, &v.navoid, term(MESH_TERM_HOST, "being", 0));
55 CHECK_WHY(&ms[2], &v, "avoid host:being");
56 CHECK(msc_eligible(&ms[3], &v) && !msc_eligible(&ms[2], &v));
57 mesh_needs_free(&n), mesh_needs_free(&cw), mesh_needs_free(&a), mesh_needs_free(&mm), mesh_needs_free(&v);
58 for (int i = 0; i < 4; i++) msm_member_free(&ms[i]);
59
60 /* node_shape_filters_members */
61 fleet4(ms);
62 mesh_needs big = needs("cuda", "metal", NULL);
63 big.warps = 16;
64 big.shared = 48 << 10;
65 CHECK(msc_eligible(&ms[0], &big) && msc_eligible(&ms[2], &big));
66 w = why(&ms[3], &big);
67 CHECK(mt_starts(w, "shared_bytes 49152: ") && mt_contains(w, "allows 32768"));
68 free(w);
69 mesh_needs fits = msn_clone(&big);
70 fits.shared = 16 << 10;
71 CHECK_WHY(&ms[3], &fits, "ok metal");
72 mesh_needs wide = msn_clone(&fits);
73 wide.warps = 32;
74 CHECK(msc_eligible(&ms[3], &wide));
75 msm_member tiny = msm_member_clone(&ms[0]);
76 tiny.max_threads = 512;
77 CHECK_WHY_PREFIX(&tiny, &wide, "warps 32: 1024 threads per node");
78 msm_member_free(&tiny);
79 mesh_needs cpu = msn_clone(&big);
80 mesh_strs_free(cpu.backends, cpu.nbackends), cpu.backends = NULL, cpu.nbackends = 0;
81 msn_strs_push(&cpu.backends, &cpu.nbackends, "wasm");
82 msn_strs_push(&cpu.backends, &cpu.nbackends, "metal");
83 CHECK_WHY(&ms[3], &cpu, "ok wasm");
84 msm_member unknown = msm_member_clone(&ms[3]);
85 unknown.max_threads = 0;
86 CHECK(msc_eligible(&unknown, &big));
87 msm_member_free(&unknown);
88 mesh_needs_free(&big), mesh_needs_free(&fits), mesh_needs_free(&wide), mesh_needs_free(&cpu);
89
90 /* scores_follow_share_speed_load_and_prefer */
91 msw_weights wt = msw_default();
92 mesh_needs g = needs("cuda", "metal", NULL);
93 msm_member hi = msm_member_clone(&ms[0]);
94 hi.gpu_share = mof32_some(0.95f);
95 CHECK(msc_score(&hi, &g, NULL, &wt) > msc_score(&ms[0], &g, NULL, &wt));
96 msm_member_free(&hi);
97 msm_perf fast = {.hash = 1, .exec = "cuda", .task_us = {true, 100.0f}};
98 msm_perf slow = fast;
99 slow.task_us = mof32_some(400.0f);
100 msc_cx cf = {.w = &wt, .here = &fast, .best_task_us = mof32_some(100.0f)};
101 msc_cx cs = cf;
102 cs.here = &slow;
103 msc_score_t sf = msc_score_terms(&ms[0], &g, &cf);
104 msc_score_t ss = msc_score_terms(&ms[0], &g, &cs);
105 CHECK(sf.perf > ss.perf && !sf.explore);
106 CHECK(fabs(ss.perf - 0.25 * 0.5) < 1e-6);
107 msc_cx none = msc_cx_simple(&wt, NULL);
108 CHECK(msc_score_terms(&ms[0], &g, &none).explore);
109 mesh_needs c = needs("wasm", NULL, NULL);
110 msn_terms_push(&c.prefer, &c.nprefer, term(MESH_TERM_HOST, "dgx-00", 0));
111 msm_member hot = msm_member_clone(&ms[1]);
112 hot.cpu_util = 1.0f;
113 hot.psi_cpu = mof32_some(0.4f);
114 msc_score_t sh = msc_score_terms(&hot, &c, &none);
115 CHECK(sh.load < 1e-9 && fabs(sh.perf - 0.6) < 1e-6);
116 CHECK(fabs(msc_score_terms(&ms[0], &c, &none).prefer - wt.prefer) < 1e-9);
117 msm_member busy = msm_member_clone(&ms[1]);
118 busy.busy = mt_strdup("x");
119 CHECK(fabs(msc_score_terms(&busy, &c, &none).owner + wt.owner) < 1e-9);
120 char *e = msc_explain(&sh);
121 CHECK(mt_contains(e, "cpu share 0.60"));
122 free(e);
123 e = msc_explain(&sf);
124 CHECK_S(e, "1.418 = perf 0.50 load 0.52 mem 0.20 spread 0.20 (cuda, gpu share 0.50, 100 us/task, cpu after 0.10)");
125 free(e);
126 msm_member_free(&hot), msm_member_free(&busy);
127 mesh_needs_free(&g), mesh_needs_free(&c);
128 for (int i = 0; i < 4; i++) msm_member_free(&ms[i]);
129 return mesh_check_done();
130}