==> src/manifest.c <==1/* The manifest's helpers: Place's parts, the node shape, load from a dir, copy, free, Debug. */
2#include "mesh/manifest.h"
3
4#include "mesh/abi/backend.h"
5#include "mesh/abi/base.h"
6
7#include <errno.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/stat.h>
12
13size_t mesh_manifest_place_state_bytes(const mesh_manifest_place *p) {
14 size_t n = 0;
15 for (size_t i = 0; i < p->nstate; i++) n += p->state[i].len;
16 return n;
17}
18
19uint32_t mesh_manifest_place_out_bytes(const mesh_manifest_place *p) {
20 uint32_t n = 0;
21 for (size_t i = 0; i < p->nout; i++) n += p->out[i].len;
22 return n;
23}
24
25void mesh_manifest_place_part(const mesh_manifest_place *p, uint32_t b, mesh_manifest_region *out) {
26 for (size_t i = 0; i < p->nout; i++) {
27 uint32_t n = p->out[i].len / p->fanout;
28 out[i] = (mesh_manifest_region){p->out[i].off + b * n, n};
29 }
30}
31
32void mesh_manifest_place_part_in_buffer(const mesh_manifest_place *p, uint32_t b, mesh_manifest_region *out) {
33 uint32_t at = 0;
34 for (size_t i = 0; i < p->nout; i++) {
35 uint32_t n = p->out[i].len / p->fanout;
36 out[i] = (mesh_manifest_region){at + b * n, n};
37 at += p->out[i].len;
38 }
39}
40
41size_t mesh_manifest_place_part_bytes(const mesh_manifest_place *p) { return mesh_manifest_place_out_bytes(p) / p->fanout; }
42
43uint32_t mesh_manifest_place_mask(uint32_t lo, uint32_t hi) {
44 uint32_t m = 0;
45 for (uint32_t b = lo; b < hi; b++) m |= 1u << b;
46 return m;
47}
48
49uint32_t mesh_manifest_threads(const mesh_manifest *m) { return MESH_NODE_THREADS * m->warps; }
50uint32_t mesh_manifest_smem(const mesh_manifest *m) { return MESH_RT_SHARED_BYTES + m->shared_bytes; }
51
52bool mesh_manifest_native(const mesh_manifest *m) {
53 for (size_t i = 0; i < m->nbackends; i++)
54 if (strcmp(m->backends[i], MESH_BACKENDS[MESH_BACKEND_NATIVE]) == 0) return true;
55 return false;
56}
57
58static void place_free(mesh_manifest_place *p) {
59 if (!p) return;
60 free(p->state);
61 free(p->out);
62 free(p);
63}
64
65void mesh_manifest_free(mesh_manifest *m) {
66 free(m->name);
67 mesh_strs_free(m->reads, m->nreads);
68 for (size_t i = 0; i < MESH_COUNTERS; i++) free(m->counters[i]);
69 for (size_t i = 0; i < m->nfields; i++) free(m->fields[i].name);
70 free(m->fields);
71 place_free(m->place);
72 mesh_strs_free(m->backends, m->nbackends);
73 if (m->inbox) free(m->inbox->ty);
74 free(m->inbox);
75 for (size_t i = 0; i < m->nfeeds; i++) {
76 free(m->feeds[i].consumer);
77 free(m->feeds[i].ty);
78 }
79 free(m->feeds);
80 mesh_needs_free(&m->needs);
81 *m = (mesh_manifest){0};
82}
83
84static void *dup_bytes(const void *p, size_t n) {
85 if (!p || n == 0) return NULL;
86 void *d = mesh_alloc(n);
87 memcpy(d, p, n);
88 return d;
89}
90
91void mesh_manifest_copy(mesh_manifest *dst, const mesh_manifest *src) {
92 *dst = *src;
93 dst->name = mesh_strdup(src->name);
94 dst->reads = mesh_strs_copy(src->reads, src->nreads);
95 for (size_t i = 0; i < MESH_COUNTERS; i++) dst->counters[i] = mesh_strdup(src->counters[i] ? src->counters[i] : "");
96 dst->fields = dup_bytes(src->fields, src->nfields * sizeof *src->fields);
97 for (size_t i = 0; i < src->nfields; i++) dst->fields[i].name = mesh_strdup(src->fields[i].name);
98 if (src->place) {
99 dst->place = dup_bytes(src->place, sizeof *src->place);
100 dst->place->state = dup_bytes(src->place->state, src->place->nstate * sizeof(mesh_manifest_region));
101 dst->place->out = dup_bytes(src->place->out, src->place->nout * sizeof(mesh_manifest_region));
102 }
103 dst->backends = mesh_strs_copy(src->backends, src->nbackends);
104 if (src->inbox) {
105 dst->inbox = dup_bytes(src->inbox, sizeof *src->inbox);
106 dst->inbox->ty = mesh_strdup(src->inbox->ty);
107 }
108 dst->feeds = dup_bytes(src->feeds, src->nfeeds * sizeof *src->feeds);
109 for (size_t i = 0; i < src->nfeeds; i++) {
110 dst->feeds[i].consumer = mesh_strdup(src->feeds[i].consumer);
111 dst->feeds[i].ty = mesh_strdup(src->feeds[i].ty);
112 }
113 mesh_needs_copy(&dst->needs, &src->needs);
114}
115
116/* Reads a whole file; NULL with errno on failure. */
117static char *slurp(const char *path, size_t *n) {
118 FILE *f = fopen(path, "rb");
119 if (!f) return NULL;
120 mesh_text t = {0};
121 char buf[8192];
122 size_t k;
123 while ((k = fread(buf, 1, sizeof buf, f)) > 0) mesh_text_putn(&t, buf, k);
124 int bad = ferror(f);
125 fclose(f);
126 if (bad) {
127 mesh_text_free(&t);
128 errno = EIO;
129 return NULL;
130 }
131 *n = t.len;
132 return mesh_text_take(&t);
133}
134
135/* Rust's io::Error Display: "No such file or directory (os error 2)". */
136static char *os_error(int e) { return mesh_fmt("%s (os error %d)", strerror(e), e); }
137
138bool mesh_manifest_load(const char *path, mesh_manifest *out, char **ptx, char **err) {
139 struct stat st;
140 bool dir = stat(path, &st) == 0 && S_ISDIR(st.st_mode);
141 char *toml = dir ? mesh_fmt("%s/program.toml", path) : mesh_strdup(path);
142 size_t n;
143 char *text = slurp(toml, &n);
144 if (!text) {
145 char *e = os_error(errno);
146 mesh_errf(err, "%s: %s", toml, e);
147 free(e);
148 free(toml);
149 return false;
150 }
151 char *why = NULL;
152 bool ok = mesh_manifest_parse(text, n, out, &why);
153 free(text);
154 if (!ok) {
155 mesh_errf(err, "%s: %s", toml, why);
156 free(why);
157 free(toml);
158 return false;
159 }
160 /* <name>.ptx beside the manifest. */
161 char *slash = strrchr(toml, '/');
162 if (ptx) *ptx = slash ? mesh_fmt("%.*s/%s.ptx", (int)(slash - toml), toml, out->name) : mesh_fmt("%s.ptx", out->name);
163 free(toml);
164 return true;
165}
166
167static void dstr(mesh_text *t, const char *s) { mesh_text_debug_str(t, s, strlen(s)); }
168static void dbool(mesh_text *t, bool b) { mesh_text_puts(t, b ? "true" : "false"); }
169
170static void regions_debug(mesh_text *t, const mesh_manifest_region *r, size_t n) {
171 mesh_text_putc(t, '[');
172 for (size_t i = 0; i < n; i++) mesh_text_printf(t, "%s(%u, %u)", i ? ", " : "", (unsigned)r[i].off, (unsigned)r[i].len);
173 mesh_text_putc(t, ']');
174}
175
176void mesh_manifest_debug(mesh_text *t, const mesh_manifest *m) {
177 mesh_text_puts(t, "Manifest { name: ");
178 dstr(t, m->name);
179 mesh_text_printf(t, ", abi: %u, view_bytes: %u, view_abi: %u, snap_bytes: %u, nodes: %u, nodes_fit: ", (unsigned)m->abi,
180 (unsigned)m->view_bytes, (unsigned)m->view_abi, (unsigned)m->snap_bytes, (unsigned)m->nodes);
181 dbool(t, m->nodes_fit);
182 mesh_text_printf(t, ", warps: %u, shared_bytes: %u, scratch_bytes: %u, sms: %u, policy: %u, hz: %u, fanout: %u, batch: ",
183 (unsigned)m->warps, (unsigned)m->shared_bytes, (unsigned)m->scratch_bytes, (unsigned)m->sms,
184 (unsigned)m->policy, (unsigned)m->hz, (unsigned)m->fanout);
185 dbool(t, m->batch);
186 mesh_text_printf(t, ", arg_mode: %u, arg_off: %u, reads: ", (unsigned)m->arg_mode, (unsigned)m->arg_off);
187 mesh_strs_debug(t, m->reads, m->nreads);
188 mesh_text_printf(t, ", input_off: %u, input_len: %u, request: ", (unsigned)m->input_off, (unsigned)m->input_len);
189 if (m->has_request)
190 mesh_text_printf(t, "Some(Window { req_off: %u, req_max: %u, resp_off: %u, resp_max: %u })", (unsigned)m->request.req_off,
191 (unsigned)m->request.req_max, (unsigned)m->request.resp_off, (unsigned)m->request.resp_max);
192 else
193 mesh_text_puts(t, "None");
194 mesh_text_printf(t, ", peer: %u, counters: ", (unsigned)m->peer);
195 mesh_strs_debug(t, m->counters, MESH_COUNTERS);
196 mesh_text_puts(t, ", fields: [");
197 for (size_t i = 0; i < m->nfields; i++) {
198 mesh_text_puts(t, i ? ", Field { name: " : "Field { name: ");
199 dstr(t, m->fields[i].name);
200 mesh_text_printf(t, ", ty: %u, off: %u }", (unsigned)m->fields[i].ty, (unsigned)m->fields[i].off);
201 }
202 mesh_text_puts(t, "], autostart: ");
203 dbool(t, m->autostart);
204 mesh_text_puts(t, ", place: ");
205 if (m->place) {
206 mesh_text_printf(t, "Some(Place { cap: %u, state: ", (unsigned)m->place->cap);
207 regions_debug(t, m->place->state, m->place->nstate);
208 mesh_text_printf(t, ", frame: %u, out: ", (unsigned)m->place->frame);
209 regions_debug(t, m->place->out, m->place->nout);
210 mesh_text_printf(t, ", show: %u, fanout: %u })", (unsigned)m->place->show, (unsigned)m->place->fanout);
211 } else {
212 mesh_text_puts(t, "None");
213 }
214 mesh_text_puts(t, ", backends: ");
215 mesh_strs_debug(t, m->backends, m->nbackends);
216 mesh_text_printf(t, ", param: %u, ftz: ", (unsigned)m->param);
217 dbool(t, m->ftz);
218 mesh_text_printf(t, ", mem_mb: %u, task_ms: %u, cpu_pct: %u, mem: %llu, nice: %u, background: ", (unsigned)m->mem_mb,
219 (unsigned)m->task_ms, (unsigned)m->cpu_pct, (unsigned long long)m->mem, (unsigned)m->nice);
220 dbool(t, m->background);
221 mesh_text_puts(t, ", device_gpu: ");
222 dbool(t, m->device_gpu);
223 mesh_text_puts(t, ", inbox: ");
224 if (m->inbox) {
225 mesh_text_printf(t, "Some(Inbox { off: %u, cap: %u, rec: %u, ty: ", (unsigned)m->inbox->off, (unsigned)m->inbox->cap,
226 (unsigned)m->inbox->rec);
227 dstr(t, m->inbox->ty);
228 mesh_text_puts(t, " })");
229 } else {
230 mesh_text_puts(t, "None");
231 }
232 mesh_text_puts(t, ", feeds: [");
233 for (size_t i = 0; i < m->nfeeds; i++) {
234 mesh_text_puts(t, i ? ", (" : "(");
235 dstr(t, m->feeds[i].consumer);
236 mesh_text_puts(t, ", ");
237 dstr(t, m->feeds[i].ty);
238 mesh_text_putc(t, ')');
239 }
240 mesh_text_puts(t, "], needs: ");
241 mesh_needs_debug(t, &m->needs);
242 mesh_text_puts(t, ", job_base: ");
243 if (m->has_job_base) mesh_text_printf(t, "Some(%u)", (unsigned)m->job_base);
244 else mesh_text_puts(t, "None");
245 mesh_text_puts(t, ", job_out: ");
246 if (m->has_job_out) mesh_text_printf(t, "Some((%u, %u))", (unsigned)m->job_out_off, (unsigned)m->job_out_rec);
247 else mesh_text_puts(t, "None");
248 mesh_text_puts(t, ", job_payload: ");
249 if (m->has_job_payload) mesh_text_printf(t, "Some((%u, %u))", (unsigned)m->job_payload_off, (unsigned)m->job_payload_len);
250 else mesh_text_puts(t, "None");
251 mesh_text_puts(t, " }");
252}