skip to content
==> tests/pipehash.c <==
1/* pipehash on the simulator between a host source and a host sink: every msg
2 * pushed into its inbox comes out of the sink as its digest (sha256d on the
3 * GPU path), exactly once; with no sink it does nothing; a full sink stalls the
4 * warp before it pops (backpressure), and the msgs wait in its inbox. */
5#include "mesh/abi/pipe.h"
6#include "mesh/check.h"
7#include "mesh/rt/sim_mailbox.h"
8#include "mesh/words_host.h"
9
10#include "../src/pipehash.c"
11
12#include <stdlib.h>
13
14#define SRC 2
15#define HASH 0
16#define SINK 1
17#define N 200
18
19static void le(const uint32_t *w, size_t n, uint8_t *out) {
20    for (size_t i = 0; i < n; i++)
21        for (int k = 0; k < 4; k++) out[4 * i + k] = (uint8_t)(w[i] >> (8 * k));
22}
23
24int main(void) {
25    uint8_t *mb = mesh_sim_mailbox();
26    mesh_words w = mesh_words_host(mb);
27    mesh_sim_prog hp = {.name = "pipehash", .view_off = MESH_VIEW_HEAP, .view_bytes = 0x16000, .nodes = 2};
28    mesh_sim_install(mb, HASH, &hp);
29    mesh_sim_inbox(mb, HASH, MESH_PIPEDEMO_H_INBOX, MESH_PIPEDEMO_H_CAP, MESH_PIPEDEMO_MSG_BYTES, MESH_PIPEDEMO_MSG_TYPE);
30    mesh_sim_prog src = {.name = "pipesrc", .view_off = MESH_VIEW_HEAP + 0x20000, .view_bytes = 0x1000};
31    mesh_sim_install(mb, SRC, &src);
32    mesh_sim_feed(mb, SRC, HASH);
33    mesh_sim_launch *l = mesh_sim_launch_prog(mb, HASH, &hp, mesh_main);
34    /* No sink yet: a task finds none and does nothing. */
35    CHECK_U(mesh_sim_call(mb, HASH, MESH_OP_TASK, 0), 0);
36    CHECK_U(mesh_sim_u32(mesh_sim_view(mb, HASH) + MESH_PIPEDEMO_H_DST), 0);
37    /* The sink: 64 cells (two sides of 32): room for one warp's digests at a time. */
38    mesh_sim_prog sk = {.name = "pipesink", .view_off = MESH_VIEW_HEAP + 0x30000, .view_bytes = 0x8000};
39    mesh_sim_install(mb, SINK, &sk);
40    mesh_sim_inbox(mb, SINK, 0x80, 64, MESH_PIPEDEMO_DIGEST_BYTES, MESH_PIPEDEMO_DIGEST_TYPE);
41    mesh_sim_feed(mb, HASH, SINK);
42    /* The source's msgs. */
43    static uint32_t msgs[N][16];
44    for (uint32_t s = 0; s < N; s++) {
45        mesh_pipedemo_msg(s, 1000 + s, SRC, msgs[s]);
46        uint8_t b[64];
47        le(msgs[s], 16, b);
48        CHECK_I(mesh_pipe_push(&w, SRC, HASH, b, 64), 1);
49    }
50    /* Run tasks and drain the sink until every digest arrived. */
51    static bool seen[N];
52    uint32_t got = 0, rounds = 0;
53    while (got < N && rounds++ < 2000) {
54        uint32_t t = mesh_sim_publish(mb, HASH, MESH_OP_TASK, 0), r;
55        CHECK(mesh_sim_wait(mb, HASH, t, &r, 60000));
56        uint8_t out[48];
57        while (mesh_pipe_pop(&w, SINK, out, 48) == 1) {
58            uint32_t dg[12];
59            for (int k = 0; k < 12; k++) dg[k] = (uint32_t)out[4 * k] | (uint32_t)out[4 * k + 1] << 8 | (uint32_t)out[4 * k + 2] << 16 | (uint32_t)out[4 * k + 3] << 24;
60            bool found = false;
61            for (uint32_t s = 0; s < N && !found; s++) {
62                uint32_t want[12];
63                mesh_pipedemo_digest(msgs[s], MESH_PIPEDEMO_PATH_GPU, want);
64                if (memcmp(want, dg, sizeof want) == 0) {
65                    CHECK(!seen[s]);
66                    seen[s] = true;
67                    found = true;
68                    got++;
69                }
70            }
71            CHECK(found);
72        }
73    }
74    CHECK_U(got, N);
75    uint8_t *ctl = mesh_sim_ctl(mb, HASH);
76    CHECK_U(mesh_sim_u32(ctl + MESH_P_COUNTERS), N);
77    CHECK_U(mesh_sim_u32(mesh_sim_view(mb, HASH) + MESH_PIPEDEMO_H_DST), SINK + 1);
78    /* Backpressure: 32 msgs hashed and not drained fill the sink's GPU side
79     * (32 cells); then the warp pops nothing and the next msgs wait. */
80    for (uint32_t s = 0; s < 32; s++) {
81        uint8_t b[64];
82        le(msgs[s], 16, b);
83        CHECK_I(mesh_pipe_push(&w, SRC, HASH, b, 64), 1);
84    }
85    CHECK_U(mesh_sim_call(mb, HASH, MESH_OP_TASK, 0), 32);
86    for (uint32_t s = 0; s < 5; s++) {
87        uint8_t b[64];
88        le(msgs[s], 16, b);
89        CHECK_I(mesh_pipe_push(&w, SRC, HASH, b, 64), 1);
90    }
91    uint32_t stalls = mesh_sim_u32(ctl + MESH_P_COUNTERS + 4);
92    CHECK_U(mesh_sim_call(mb, HASH, MESH_OP_TASK, 0), 0);
93    CHECK(mesh_sim_u32(ctl + MESH_P_COUNTERS + 4) > stalls);
94    mesh_pipe_inbox in;
95    CHECK_I(mesh_pipe_target(&w, HASH, HASH, &in), 0);
96    CHECK_U(mesh_pipe_inbox_len(&in, &w), 5);
97    CHECK_U(mesh_sim_u32(ctl + MESH_P_FAULT), 0);
98    mesh_sim_halt(mb, HASH, l);
99    mesh_sim_mailbox_free(mb);
100    return mesh_check_done();
101}