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