skip to content
==> src/needs.c <==
1/* sched.rs's Replicas, Migrate, Term and Needs: the data, parsing, equality and Debug. */
2#include "mesh/needs.h"
3
4#include "mesh/abi/backend.h"
5#include "mesh/abi/base.h"
6
7#include <stdlib.h>
8#include <string.h>
9
10const char *mesh_migrate_word(mesh_migrate m) {
11    switch (m) {
12    case MESH_MIGRATE_STATE: return "state";
13    case MESH_MIGRATE_RESTART: return "restart";
14    case MESH_MIGRATE_NEVER: return "never";
15    }
16    return "state";
17}
18
19bool mesh_term_parse(const char *s, mesh_term *out, char **err) {
20    *out = (mesh_term){0};
21    const char *colon = strchr(s, ':');
22    if (colon) {
23        size_t kn = (size_t)(colon - s);
24        const char *v = colon + 1;
25        if (kn == 4 && memcmp(s, "host", 4) == 0 && *v) {
26            out->kind = MESH_TERM_HOST;
27            out->s = mesh_strdup(v);
28            return true;
29        }
30        if (kn == 6 && memcmp(s, "system", 6) == 0) {
31            uint32_t k;
32            if (mesh_parse_u32(v, strlen(v), 10, &k) && k < MESH_MAX_SYSTEMS) {
33                out->kind = MESH_TERM_SYSTEM;
34                out->system = k;
35                return true;
36            }
37        }
38        if (kn == 4 && memcmp(s, "arch", 4) == 0 && *v) {
39            out->kind = MESH_TERM_ARCH;
40            out->s = mesh_strdup(v);
41            return true;
42        }
43    } else {
44        for (size_t i = 0; i < MESH_BACKENDS_LEN; i++)
45            if (strcmp(s, MESH_BACKENDS[i]) == 0) {
46                out->kind = MESH_TERM_BACKEND;
47                out->s = mesh_strdup(s);
48                return true;
49            }
50    }
51    mesh_text t = {0};
52    mesh_text_debug_str(&t, s, strlen(s));
53    mesh_text_puts(&t, ": a backend (");
54    for (size_t i = 0; i < MESH_BACKENDS_LEN; i++) {
55        if (i) mesh_text_puts(&t, ", ");
56        mesh_text_puts(&t, MESH_BACKENDS[i]);
57    }
58    mesh_text_puts(&t, "), \"host:NAME\", \"system:K\" or \"arch:A\"");
59    if (err) {
60        free(*err);
61        *err = mesh_text_take(&t);
62    } else {
63        mesh_text_free(&t);
64    }
65    return false;
66}
67
68char *mesh_term_word(const mesh_term *t) {
69    switch (t->kind) {
70    case MESH_TERM_BACKEND: return mesh_strdup(t->s);
71    case MESH_TERM_HOST: return mesh_fmt("host:%s", t->s);
72    case MESH_TERM_SYSTEM: return mesh_fmt("system:%u", (unsigned)t->system);
73    case MESH_TERM_ARCH: return mesh_fmt("arch:%s", t->s);
74    }
75    return mesh_strdup("");
76}
77
78bool mesh_term_eq(const mesh_term *a, const mesh_term *b) {
79    if (a->kind != b->kind) return false;
80    if (a->kind == MESH_TERM_SYSTEM) return a->system == b->system;
81    return strcmp(a->s, b->s) == 0;
82}
83
84void mesh_term_copy(mesh_term *dst, const mesh_term *src) {
85    *dst = *src;
86    dst->s = src->s ? mesh_strdup(src->s) : NULL;
87}
88
89void mesh_term_free(mesh_term *t) {
90    free(t->s);
91    *t = (mesh_term){0};
92}
93
94void mesh_needs_default(mesh_needs *n) {
95    *n = (mesh_needs){0};
96    n->backends = mesh_alloc(sizeof *n->backends);
97    n->backends[0] = mesh_strdup("cuda");
98    n->nbackends = 1;
99    n->replicas.all = true;
100    n->migrate = MESH_MIGRATE_STATE;
101    n->warps = 1;
102}
103
104char **mesh_strs_copy(char *const *v, size_t n) {
105    if (n == 0) return NULL;
106    char **c = mesh_alloc(n * sizeof *c);
107    for (size_t i = 0; i < n; i++) c[i] = mesh_strdup(v[i]);
108    return c;
109}
110
111void mesh_strs_free(char **v, size_t n) {
112    for (size_t i = 0; i < n; i++) free(v[i]);
113    free(v);
114}
115
116bool mesh_strs_eq(char *const *a, size_t an, char *const *b, size_t bn) {
117    if (an != bn) return false;
118    for (size_t i = 0; i < an; i++)
119        if (strcmp(a[i], b[i]) != 0) return false;
120    return true;
121}
122
123static mesh_term *terms_copy(const mesh_term *v, size_t n) {
124    if (n == 0) return NULL;
125    mesh_term *c = mesh_alloc(n * sizeof *c);
126    for (size_t i = 0; i < n; i++) mesh_term_copy(&c[i], &v[i]);
127    return c;
128}
129
130static void terms_free(mesh_term *v, size_t n) {
131    for (size_t i = 0; i < n; i++) mesh_term_free(&v[i]);
132    free(v);
133}
134
135static bool terms_eq(const mesh_term *a, size_t an, const mesh_term *b, size_t bn) {
136    if (an != bn) return false;
137    for (size_t i = 0; i < an; i++)
138        if (!mesh_term_eq(&a[i], &b[i])) return false;
139    return true;
140}
141
142static bool opt_eq(const char *a, const char *b) { return (!a && !b) || (a && b && strcmp(a, b) == 0); }
143static char *opt_copy(const char *s) { return s ? mesh_strdup(s) : NULL; }
144
145void mesh_needs_copy(mesh_needs *dst, const mesh_needs *src) {
146    *dst = *src;
147    dst->backends = mesh_strs_copy(src->backends, src->nbackends);
148    dst->arch = opt_copy(src->arch);
149    dst->prefer = terms_copy(src->prefer, src->nprefer);
150    dst->avoid = terms_copy(src->avoid, src->navoid);
151    dst->colocate_with = opt_copy(src->colocate_with);
152    dst->feeds = mesh_strs_copy(src->feeds, src->nfeeds);
153    dst->group = opt_copy(src->group);
154    dst->group_members = terms_copy(src->group_members, src->ngroup_members);
155}
156
157bool mesh_needs_eq(const mesh_needs *a, const mesh_needs *b) {
158    return mesh_strs_eq(a->backends, a->nbackends, b->backends, b->nbackends) && opt_eq(a->arch, b->arch) &&
159           a->min_mem_mb == b->min_mem_mb && terms_eq(a->prefer, a->nprefer, b->prefer, b->nprefer) &&
160           terms_eq(a->avoid, a->navoid, b->avoid, b->navoid) && a->replicas.all == b->replicas.all &&
161           (a->replicas.all || a->replicas.n == b->replicas.n) && a->pack == b->pack &&
162           opt_eq(a->colocate_with, b->colocate_with) && mesh_strs_eq(a->feeds, a->nfeeds, b->feeds, b->nfeeds) &&
163           opt_eq(a->group, b->group) && a->group_size == b->group_size &&
164           terms_eq(a->group_members, a->ngroup_members, b->group_members, b->ngroup_members) &&
165           a->priority == b->priority && a->cpu == b->cpu && a->mem_mb == b->mem_mb && a->migrate == b->migrate &&
166           a->lockstep == b->lockstep && a->view_bytes == b->view_bytes && a->warps == b->warps &&
167           a->shared == b->shared;
168}
169
170void mesh_needs_free(mesh_needs *n) {
171    mesh_strs_free(n->backends, n->nbackends);
172    free(n->arch);
173    terms_free(n->prefer, n->nprefer);
174    terms_free(n->avoid, n->navoid);
175    free(n->colocate_with);
176    mesh_strs_free(n->feeds, n->nfeeds);
177    free(n->group);
178    terms_free(n->group_members, n->ngroup_members);
179    *n = (mesh_needs){0};
180}
181
182void mesh_strs_debug(mesh_text *t, char *const *v, size_t n) {
183    mesh_text_putc(t, '[');
184    for (size_t i = 0; i < n; i++) {
185        if (i) mesh_text_puts(t, ", ");
186        mesh_text_debug_str(t, v[i], strlen(v[i]));
187    }
188    mesh_text_putc(t, ']');
189}
190
191static void opt_debug(mesh_text *t, const char *s) {
192    if (!s) {
193        mesh_text_puts(t, "None");
194        return;
195    }
196    mesh_text_puts(t, "Some(");
197    mesh_text_debug_str(t, s, strlen(s));
198    mesh_text_putc(t, ')');
199}
200
201void mesh_term_debug(mesh_text *t, const mesh_term *x) {
202    static const char *const names[] = {"Backend", "Host", "System", "Arch"};
203    mesh_text_printf(t, "%s(", names[x->kind]);
204    if (x->kind == MESH_TERM_SYSTEM) mesh_text_printf(t, "%u", (unsigned)x->system);
205    else mesh_text_debug_str(t, x->s, strlen(x->s));
206    mesh_text_putc(t, ')');
207}
208
209static void terms_debug(mesh_text *t, const mesh_term *v, size_t n) {
210    mesh_text_putc(t, '[');
211    for (size_t i = 0; i < n; i++) {
212        if (i) mesh_text_puts(t, ", ");
213        mesh_term_debug(t, &v[i]);
214    }
215    mesh_text_putc(t, ']');
216}
217
218void mesh_needs_debug(mesh_text *t, const mesh_needs *n) {
219    static const char *const migrates[] = {"State", "Restart", "Never"};
220    mesh_text_puts(t, "Needs { backends: ");
221    mesh_strs_debug(t, n->backends, n->nbackends);
222    mesh_text_puts(t, ", arch: ");
223    opt_debug(t, n->arch);
224    mesh_text_printf(t, ", min_mem_mb: %u, prefer: ", (unsigned)n->min_mem_mb);
225    terms_debug(t, n->prefer, n->nprefer);
226    mesh_text_puts(t, ", avoid: ");
227    terms_debug(t, n->avoid, n->navoid);
228    if (n->replicas.all) mesh_text_puts(t, ", replicas: All");
229    else mesh_text_printf(t, ", replicas: N(%u)", (unsigned)n->replicas.n);
230    mesh_text_printf(t, ", pack: %s, colocate_with: ", n->pack ? "true" : "false");
231    opt_debug(t, n->colocate_with);
232    mesh_text_puts(t, ", feeds: ");
233    mesh_strs_debug(t, n->feeds, n->nfeeds);
234    mesh_text_puts(t, ", group: ");
235    opt_debug(t, n->group);
236    mesh_text_printf(t, ", group_size: %u, group_members: ", (unsigned)n->group_size);
237    terms_debug(t, n->group_members, n->ngroup_members);
238    mesh_text_printf(t, ", priority: %d, cpu: ", (int)n->priority);
239    mesh_text_debug_f32(t, n->cpu);
240    mesh_text_printf(t, ", mem_mb: %u, migrate: %s, lockstep: %s, view_bytes: %u, warps: %u, shared: %u }",
241                     (unsigned)n->mem_mb, migrates[n->migrate], n->lockstep ? "true" : "false",
242                     (unsigned)n->view_bytes, (unsigned)n->warps, (unsigned)n->shared);
243}