skip to content
==> src/backend.c <==
1/* backend.rs's free functions and the trait defaults, over the C tables. */
2#include "mesh/backend.h"
3
4#include "mesh/abi/base.h"
5
6#include <stdlib.h>
7#include <string.h>
8#include <sys/stat.h>
9
10uint32_t mesh_caps_word(const mesh_caps *c) { return mesh_backend_word(c->kind, c->family); }
11const char *mesh_caps_backend_name(const mesh_caps *c) { return MESH_BACKENDS[c->kind]; }
12
13void mesh_caps_copy(mesh_caps *dst, const mesh_caps *src) {
14    *dst = *src;
15    dst->name = mesh_strdup(src->name ? src->name : "");
16    dst->arch = mesh_strdup(src->arch ? src->arch : "");
17}
18
19void mesh_caps_free(mesh_caps *c) {
20    free(c->name);
21    free(c->arch);
22    *c = (mesh_caps){0};
23}
24
25char *mesh_backend_label(uint32_t word) {
26    uint32_t k = mesh_backend_kind(word), f = mesh_backend_family(word);
27    if (k == MESH_BACKEND_CUDA) return mesh_strdup("cuda");
28    if (k == MESH_BACKEND_WASM) return mesh_strdup("wasm");
29    if (k == MESH_BACKEND_METAL) return f > 0 ? mesh_fmt("metal-apple%u", (unsigned)f) : mesh_strdup("metal");
30    return mesh_fmt("backend%u", (unsigned)k);
31}
32
33bool mesh_kernel_regs(const mesh_kernel *k, uint32_t *out, char **err) { return k->ops->regs(k, out, err); }
34bool mesh_kernel_local_bytes(const mesh_kernel *k, uint32_t *out, char **err) { return k->ops->local_bytes(k, out, err); }
35bool mesh_kernel_max_blocks_per_sm(const mesh_kernel *k, uint32_t *out, char **err) {
36    return k->ops->max_blocks_per_sm(k, out, err);
37}
38uint64_t mesh_kernel_scratch(const mesh_kernel *k) { return k->ops->scratch(k); }
39bool mesh_kernel_global_u32(const mesh_kernel *k, const char *name, uint32_t *out, char **err) {
40    return k->ops->global_u32(k, name, out, err);
41}
42
43void mesh_kernel_drop(mesh_kernel *k) {
44    if (!k) return;
45    if (k->ops->drop) k->ops->drop(k);
46    free(k);
47}
48
49void mesh_stream_drop(mesh_stream *s) {
50    if (!s) return;
51    if (s->drop) s->drop(s);
52    free(s);
53}
54
55void mesh_prepared_free(mesh_prepared *p) {
56    mesh_manifest_free(&p->manifest);
57    free(p->code);
58    mesh_payload_free(&p->src);
59    mesh_kernel_drop(p->kernel);
60    *p = (mesh_prepared){0};
61}
62
63char *mesh_backend_crashed(const mesh_backend *b, const mesh_stream *st, const mesh_kernel *k) {
64    return b->ops->crashed ? b->ops->crashed(b, st, k) : NULL;
65}
66bool mesh_backend_owns_halt(const mesh_backend *b) { return b->ops->owns_halt && b->ops->owns_halt(b); }
67bool mesh_backend_reads_live(const mesh_backend *b) { return b->ops->reads_live && b->ops->reads_live(b); }
68void mesh_backend_sample(const mesh_backend *b) {
69    if (b->ops->sample) b->ops->sample(b);
70}
71uint32_t mesh_backend_online_timeout_ms(const mesh_backend *b) {
72    return b->ops->online_timeout_ms ? b->ops->online_timeout_ms(b) : 2000;
73}
74void mesh_backend_destroy(mesh_backend *b) {
75    if (b && b->ops->destroy) b->ops->destroy(b);
76}
77
78static void join_backends(mesh_text *t, char *const *v, size_t n) {
79    for (size_t i = 0; i < n; i++) mesh_text_printf(t, "%s%s", i ? ", " : "", v[i]);
80}
81
82bool mesh_pick_exec(const mesh_manifest *m, const uint32_t *have, size_t nhave, uint32_t *exec, char **err) {
83    for (size_t i = 0; i < m->nbackends; i++)
84        for (size_t j = 0; j < nhave; j++)
85            if (strcmp(MESH_BACKENDS[have[j]], m->backends[i]) == 0) {
86                *exec = have[j];
87                return true;
88            }
89    mesh_text t = {0};
90    mesh_text_printf(&t, "unsupported: %s runs on ", m->name);
91    join_backends(&t, m->backends, m->nbackends);
92    mesh_text_puts(&t, " (manifest `backends`); this meshd runs ");
93    for (size_t j = 0; j < nhave; j++) mesh_text_printf(&t, "%s%s", j ? ", " : "", MESH_BACKENDS[have[j]]);
94    if (err) {
95        free(*err);
96        *err = mesh_text_take(&t);
97    } else {
98        mesh_text_free(&t);
99    }
100    return false;
101}
102
103const char *mesh_native_target(void) {
104#if defined(__APPLE__) && defined(__aarch64__)
105    return "aarch64-apple-darwin";
106#elif defined(__APPLE__)
107    return "x86_64-apple-darwin";
108#elif defined(__aarch64__)
109    return "aarch64-unknown-linux-gnu";
110#elif defined(__x86_64__)
111    return "x86_64-unknown-linux-gnu";
112#else
113    return "unknown";
114#endif
115}
116
117char *mesh_native_binary(const char *dir, const char *name) { return mesh_fmt("%s/%s/%s", dir, mesh_native_target(), name); }
118
119bool mesh_runs_here(const char *dir, const mesh_manifest *m, const uint32_t *have, size_t nhave) {
120    uint32_t exec;
121    if (!mesh_pick_exec(m, have, nhave, &exec, NULL)) return false;
122    if (exec != MESH_BACKEND_NATIVE) return true;
123    char *bin = mesh_native_binary(dir, m->name);
124    struct stat st;
125    bool file = stat(bin, &st) == 0 && S_ISREG(st.st_mode);
126    free(bin);
127    return file;
128}
129
130bool mesh_check_manifest(const mesh_payload *src, uint32_t kind, mesh_manifest *out, char **err) {
131    char *why = NULL;
132    if (!mesh_manifest_parse(src->manifest, strlen(src->manifest), out, &why)) {
133        mesh_errf(err, "manifest: %s: %s", src->dir, why);
134        free(why);
135        return false;
136    }
137    if (out->abi != MESH_RT_ABI) {
138        mesh_errf(err, "abi: %s declares abi %u, meshd runs %u", out->name, (unsigned)out->abi, (unsigned)MESH_RT_ABI);
139        goto fail;
140    }
141    const char *me = MESH_BACKENDS[kind];
142    bool listed = false;
143    for (size_t i = 0; i < out->nbackends; i++) listed = listed || strcmp(out->backends[i], me) == 0;
144    if (!listed) {
145        mesh_text t = {0};
146        mesh_text_printf(&t, "unsupported: %s runs on ", out->name);
147        join_backends(&t, out->backends, out->nbackends);
148        mesh_text_printf(&t, " (manifest `backends`); this meshd runs %s", me);
149        mesh_errf(err, "%s", mesh_text_str(&t));
150        mesh_text_free(&t);
151        goto fail;
152    }
153    if (out->sms != 0) {
154        mesh_errf(err, "manifest: %s: sms = %u: per-program green partitions are not implemented", out->name, (unsigned)out->sms);
155        goto fail;
156    }
157    return true;
158fail:
159    mesh_manifest_free(out);
160    return false;
161}
162
163bool mesh_prepare_any(const mesh_compiler_entry *comps, size_t n, mesh_payload *src, const uint64_t *expect, const char *root,
164                      mesh_prepared *out, char **err) {
165    mesh_manifest m;
166    char *why = NULL;
167    if (!mesh_manifest_parse(src->manifest, strlen(src->manifest), &m, &why)) {
168        mesh_errf(err, "manifest: %s: %s", src->dir, why);
169        free(why);
170        mesh_payload_free(src);
171        return false;
172    }
173    uint32_t *kinds = mesh_alloc((n ? n : 1) * sizeof *kinds);
174    for (size_t i = 0; i < n; i++) kinds[i] = comps[i].kind;
175    uint32_t exec;
176    bool ok = mesh_pick_exec(&m, kinds, n, &exec, err);
177    free(kinds);
178    if (!ok) {
179        mesh_manifest_free(&m);
180        mesh_payload_free(src);
181        return false;
182    }
183    const mesh_compiler *comp = NULL;
184    for (size_t i = 0; i < n && !comp; i++)
185        if (comps[i].kind == exec) comp = comps[i].comp;
186    if (comp->ops->needs_ptx(comp) && src->ptx_len == 0) {
187        mesh_errf(err, "manifest: %s/%s.ptx (%s): no PTX in the catalog (the %s image)", src->dir, m.name, m.name, MESH_BACKENDS[exec]);
188        mesh_manifest_free(&m);
189        mesh_payload_free(src);
190        return false;
191    }
192    mesh_manifest_free(&m);
193    return comp->ops->prepare(comp, src, expect, root, out, err);
194}
195
196/* The registered exit cleanups, by order. */
197static struct {
198    int order;
199    void (*fn)(void);
200} cleanups[16];
201static size_t ncleanups;
202
203void mesh_backend_on_cleanup(int order, void (*fn)(void)) {
204    for (size_t i = 0; i < ncleanups; i++)
205        if (cleanups[i].fn == fn) return;
206    if (ncleanups == sizeof cleanups / sizeof cleanups[0]) return;
207    size_t at = ncleanups++;
208    while (at > 0 && cleanups[at - 1].order > order) {
209        cleanups[at] = cleanups[at - 1];
210        at--;
211    }
212    cleanups[at].order = order;
213    cleanups[at].fn = fn;
214}
215
216void mesh_backend_cleanup(void) {
217    for (size_t i = 0; i < ncleanups; i++) cleanups[i].fn();
218}