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