skip to content
==> src/sched.c <==
1/* jobs.rs select's scheduler half: the verdict and score of an alive member that runs the program. */
2#include "mesh/jobs/sched.h"
3#include "mesh/sched_score.h"
4#include "mesh/strbuf.h"
5#include "mesh/strmap.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10void mjs_cx_free(mjs_cx *cx) {
11    for (size_t i = 0; i < cx->nmembers; i++) msm_member_free(&cx->members[i]);
12    free(cx->members);
13    for (size_t i = 0; i < cx->nneeds; i++) {
14        free(cx->need_names[i]);
15        mesh_needs_free(&cx->needs[i]);
16    }
17    free(cx->need_names);
18    free(cx->needs);
19    for (size_t i = 0; i < cx->perf.n; i++) free(cx->perf.name[i]);
20    free(cx->perf.name);
21    free(cx->perf.member);
22    free(cx->perf.perf);
23    memset(cx, 0, sizeof *cx);
24}
25
26const mesh_needs *mjs_needs(const mjs_cx *cx, const char *name) {
27    for (size_t i = 0; i < cx->nneeds; i++)
28        if (strcmp(cx->need_names[i], name) == 0) return &cx->needs[i];
29    return NULL;
30}
31
32/* The best measured time per task of prog on any member that runs it. */
33static mof32 best_task(const mjs_cx *cx, const char *prog) {
34    mof32 best = mof32_none();
35    for (size_t i = 0; i < cx->perf.n; i++) {
36        const msm_perf *p = &cx->perf.perf[i];
37        if (strcmp(cx->perf.name[i], prog) != 0 || !p->run || !p->task_us.some || !(p->task_us.v > 0.0f)) continue;
38        if (!best.some || p->task_us.v < best.v) best = mof32_some(p->task_us.v);
39    }
40    return best;
41}
42
43static int judge(void *ctx, uint32_t k, const char *prog, mj_score *score, bool *busy, char **why) {
44    const mjs_cx *cx = ctx;
45    const msm_member *m = &cx->members[k];
46    const mesh_needs *nd = mjs_needs(cx, prog);
47    if (!nd) return -1;
48    char exec[16], *err = NULL;
49    if (!msc_filter(m, nd, exec, &err)) {
50        *why = err;
51        return 0;
52    }
53    const char *failed = ms_get(&m->fails, prog);
54    if (failed) {
55        *why = mfmt("%s failed there: %s", prog, failed);
56        return 0;
57    }
58    const msm_perf *here = msm_perfs_get(&cx->perf, prog, k);
59    *busy = m->busy != NULL;
60    msc_cx scx = {.w = &cx->w, .current = true, .here = here, .best_task_us = best_task(cx, prog), .own_cpu = here ? here->cpu : 0.0f,
61                  .placed = 0, .max_placed = 0, .rtt_ms = mof32_none()};
62    msc_score_t s = msc_score_terms(m, nd, &scx);
63    score->total = s.total;
64    score->explain = msc_explain(&s);
65    return 1;
66}
67
68static char *busy_why(void *ctx, uint32_t k) {
69    const mjs_cx *cx = ctx;
70    if (k >= cx->nmembers || !cx->members[k].busy) return NULL;
71    return mstrdup(cx->members[k].busy);
72}
73
74static void release(void *ctx) {
75    mjs_cx_free(ctx);
76    free(ctx);
77}
78
79mj_sched *mjs_sched(mjs_cx cx) {
80    mjs_cx *c = mxalloc(sizeof *c);
81    *c = cx;
82    mj_sched *s = mxalloc(sizeof *s);
83    *s = (mj_sched){c, (uint32_t)cx.nmembers, judge, busy_why, release};
84    return s;
85}