==> 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}