skip to content
==> 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}