skip to content
==> tests/inproc.c <==
1/* inproc.rs as kcheck uses it, on the fake CUDA device (blink mode) with a
2 * fake nvJitLink: a catalog dir loaded and checked, installed in a slot,
3 * launched, tickets one by one and in a batch, the input queue, a request
4 * through the window, a stop and a relaunch, the heap and reads masks. */
5#include "mesh/check.h"
6#include "mesh/cuda_fake.h"
7#include "mesh/inproc.h"
8#include "mesh/mps.h"
9#include "mesh/worker_node.h"
10
11#include "mesh/abi/ops.h"
12#include "mesh/abi/view_heap.h"
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/stat.h>
18#include <unistd.h>
19
20static void p_init(const mesh_worker_ctx *c, void *u) {
21    (void)u;
22    mesh_ctx_set_u32(c, 0, 0x4f4c4548);
23}
24static uint32_t p_task(const mesh_worker_ctx *c, uint32_t op, uint32_t arg, void *u) {
25    (void)u;
26    if (op == MESH_OP_TASK) return arg * 3 + 7;
27    if (op == MESH_OP_REQ) {
28        mesh_view rq = mesh_ctx_request(c), rs = mesh_ctx_response(c);
29        uint32_t n = mesh_view_len(rq);
30        for (uint32_t i = 0; i < n; i++) mesh_view_set_u8(rs, i, mesh_view_u8(rq, n - 1 - i));
31        mesh_ctx_respond(c, n);
32        return n;
33    }
34    if (op == 7) {
35        uint32_t sum = 0;
36        uint8_t b;
37        while (mesh_ctx_input_pop(c, &b)) sum += b;
38        return sum;
39    }
40    return MESH_R_BAD_OP;
41}
42static const mesh_worker_program prog = {p_init, p_task, NULL};
43static void kernel(const char *e, uint64_t mb, uint32_t slot, uint32_t nodes, uint32_t threads, void *u) {
44    (void)e, (void)nodes, (void)threads, (void)u;
45    mesh_worker_run_nodes(mesh_mailbox_new((uint8_t *)(uintptr_t)mb, 0), slot, &prog, NULL);
46}
47
48static int j_create(void **h, uint32_t n, const char *const *o) {
49    (void)n, (void)o;
50    *h = (void *)1;
51    return 0;
52}
53static int j_destroy(void **h) {
54    *h = NULL;
55    return 0;
56}
57static int j_add(void *h, int k, const void *d, size_t n, const char *name) {
58    (void)h, (void)k, (void)d, (void)n, (void)name;
59    return 0;
60}
61static int j_complete(void *h) {
62    (void)h;
63    return 0;
64}
65static const char cubin[] = "FAKECUBIN entry=mesh_main regs=32 rt_abi=6";
66static int j_size(void *h, size_t *n) {
67    (void)h;
68    *n = sizeof cubin;
69    return 0;
70}
71static int j_cubin(void *h, void *out) {
72    (void)h;
73    memcpy(out, cubin, sizeof cubin);
74    return 0;
75}
76static int j_none(void *h, size_t *n) {
77    (void)h;
78    *n = 0;
79    return 0;
80}
81static int j_log(void *h, void *o) {
82    (void)h, (void)o;
83    return 0;
84}
85static const mesh_nvjitlink_fns jit_fns = {j_create, j_destroy, j_add, j_complete, j_size, j_cubin, j_none, j_log};
86
87static void write_file(const char *p, const char *s) {
88    FILE *f = fopen(p, "w");
89    fputs(s, f);
90    fclose(f);
91}
92
93int main(void) {
94    setenv("CUDA_MODULE_LOADING", "EAGER", 1);
95    mesh_fake_cuda_install(&(mesh_fake_cuda_cfg){.run = kernel});
96    char *err = NULL;
97    mesh_shm shm;
98    CHECK(mesh_shm_new(&shm, &err));
99    mesh_nvjitlink jit;
100    mesh_nvjitlink_from(&jit_fns, &jit);
101    mesh_backend *b;
102    if (!CHECK(mesh_cuda_backend_open(MESH_ISOLATION_MODE_BLINK, 0, NULL, 0, &shm, &jit, &b, &err))) {
103        fprintf(stderr, "%s\n", err);
104        return mesh_check_done();
105    }
106    mesh_dev d;
107    mesh_dev_from(b, &shm, &d);
108    CHECK(mesh_dev_cuda(&d) && !mesh_dev_wasm(&d));
109    CHECK_S(mesh_dev_code(&d), "cubin");
110    CHECK_U(mesh_dev_sms_total(&d), 48);
111    mesh_mb2 mb;
112    CHECK(mesh_mb2_alloc(&d, &mb, &err));
113    CHECK_U(mesh_mb2_r32(mb, 0), 0x4853454d);
114
115    char root[] = "/tmp/mesh-inproc-XXXXXX";
116    CHECK(mkdtemp(root) != NULL);
117    char *dir = mesh_fmt("%s/echo", root), *toml = mesh_fmt("%s/program.toml", dir), *ptx = mesh_fmt("%s/echo.ptx", dir);
118    mkdir(dir, 0755);
119    write_file(toml, "name = \"echo\"\nabi = 6\nview_bytes = 0x1000\nnodes = \"fit\"\ninput = 64\nrequest = \"0x100:0x40,0x200:0x40\"\nreads = [\"other\"]\n");
120    write_file(ptx, ".visible .entry mesh_main() { ret; }\n");
121    mesh_image2 im;
122    if (!CHECK(mesh_inproc_load(&d, dir, &im, &err))) {
123        fprintf(stderr, "%s\n", err);
124        return mesh_check_done();
125    }
126    CHECK(im.rt_abi == 6 && im.regs == 32 && im.cubin_bytes == sizeof cubin);
127    /* nodes = "fit": 3/4 of 16 per SM x 48 SMs, at most PROG_MAX_NODES. */
128    CHECK_U(im.manifest.nodes, 32);
129    uint32_t mask;
130    mesh_slot_name slots[] = {{"other", 9}, {"echo", 2}};
131    CHECK(mesh_reads_mask(&im.manifest, slots, 2, &mask, &err) && mask == 1u << 9);
132    CHECK(!mesh_reads_mask(&im.manifest, slots + 1, 1, &mask, &err));
133    CHECK_S(err, "echo: reads \"other\", which is not loaded");
134    mesh_heap h = mesh_heap_new();
135    uint32_t v1, v2;
136    CHECK(mesh_heap_alloc(&h, 0x1000, &v1, &err) && v1 == MESH_VIEW_HEAP);
137    CHECK(mesh_heap_alloc(&h, 0x1001, &v2, &err) && v2 == MESH_VIEW_HEAP + 0x1000);
138    CHECK_U(h.next, MESH_VIEW_HEAP + 0x3000);
139    mesh_prog p;
140    CHECK(mesh_prog_install(&d, mb, 2, &im, v1, mask, &p, &err));
141    double ms;
142    if (!CHECK(mesh_prog_launch(&d, &p, &ms, &err))) fprintf(stderr, "%s\n", err);
143    uint32_t r;
144    CHECK(mesh_prog_run(&p, MESH_OP_INIT, 0, &r, &err) && r == MESH_R_NONE);
145    CHECK_U(mesh_mb2_r32(mb, v1), 0x4f4c4548);
146    /* A batch is at most a ring of results (64): the Rust's batch too. */
147    uint32_t res[60];
148    if (!CHECK(mesh_prog_batch(&p, MESH_OP_TASK, 60, res, &err))) fprintf(stderr, "batch: %s\n", err);
149    bool all = true;
150    for (uint32_t a = 0; a < 60; a++) all = all && res[a] == a * 3 + 7;
151    CHECK(all);
152    CHECK(mesh_prog_input_push(&p, (const uint8_t *)"\x01\x02\x03", 3, &err));
153    CHECK(mesh_prog_run(&p, 7, 0, &r, &err) && r == 6);
154    uint8_t *resp;
155    size_t rn;
156    CHECK(mesh_prog_request(&p, (const uint8_t *)"hello", 5, &resp, &rn, &err));
157    CHECK(rn == 5 && memcmp(resp, "olleh", 5) == 0);
158    free(resp);
159    /* Stop and relaunch: tickets continue from the tail. */
160    CHECK(mesh_prog_stop(&d, &p, &ms, &err));
161    CHECK(mesh_prog_launch(&d, &p, &ms, &err));
162    CHECK(mesh_prog_run(&p, MESH_OP_TASK, 1000, &r, &err) && r == 3007);
163    CHECK(mesh_prog_stop(&d, &p, &ms, &err));
164    mesh_prog_free(&d, &p);
165    CHECK_I(mesh_fake_cuda_stats_now().modules_live, 0);
166    mesh_dev_close(&d);
167    unlink(toml);
168    unlink(ptx);
169    rmdir(dir);
170    rmdir(root);
171    free(dir);
172    free(toml);
173    free(ptx);
174    free(err);
175    return mesh_check_done();
176}