==> tests/blocks.c <==1/* kcheck's B checks on the CPU simulator: every collective of a 32-warp node
2 * (B1) and a 4-warp one (B2) bitwise against @ajax/mesh-ref-block, the f32
3 * sum of 4 warps equal to the 1024-leaf tree's, and early exits with a
4 * stop/start (B3). Ported from alpha-rust-mesh crates/mesh-kcheck/src/blocks.rs. */
5#include "mesh/check.h"
6#include "mesh/ref/block.h"
7#include "mesh/rt/sim_mailbox.h"
8
9#include "../src/blocks.c"
10
11#include <stdlib.h>
12
13static uint32_t f2u(float f) { return mesh_f32_bits(f); }
14
15/* One seed through the slot: header and every thread's words == the reference. */
16static void check_seed(uint8_t *mb, uint32_t slot, uint32_t seed, uint32_t threads, uint32_t nodes) {
17 float f[1024];
18 uint32_t u[1024];
19 uint64_t l[1024];
20 for (uint32_t t = 0; t < threads; t++) mesh_block_test_values(seed, t, &f[t], &u[t], &l[t]);
21 float sf = mesh_block_reduce_f32(f, threads, mesh_block_sum_f32_id(), mesh_block_add_f32);
22 float mf = mesh_block_reduce_f32(f, threads, mesh_block_max_f32_id(), mesh_block_max_f32);
23 uint32_t su = mesh_block_reduce_u32(u, threads, 0, mesh_block_add_u32), mu = mesh_block_reduce_u32(u, threads, 0, mesh_rt_max_u32);
24 uint64_t sl = mesh_block_reduce_u64(l, threads, 0, mesh_block_add_u64), ml = mesh_block_reduce_u64(l, threads, 0, mesh_rt_max_u64);
25 static float fi[1024], fe[1024];
26 static uint32_t ui[1024], ue[1024];
27 static uint64_t li[1024], le[1024];
28 CHECK(mesh_block_scan_f32(f, threads, mesh_block_sum_f32_id(), mesh_block_add_f32, true, fi));
29 CHECK(mesh_block_scan_f32(f, threads, mesh_block_sum_f32_id(), mesh_block_add_f32, false, fe));
30 CHECK(mesh_block_scan_u32(u, threads, 0, mesh_block_add_u32, true, ui));
31 CHECK(mesh_block_scan_u32(u, threads, 0, mesh_block_add_u32, false, ue));
32 CHECK(mesh_block_scan_u64(l, threads, 0, mesh_block_add_u64, true, li));
33 CHECK(mesh_block_scan_u64(l, threads, 0, mesh_block_add_u64, false, le));
34
35 uint32_t t = mesh_sim_publish(mb, slot, MESH_OP_TASK, seed), res = 0;
36 CHECK(mesh_sim_wait(mb, slot, t, &res, 120000));
37 uint8_t *view = mesh_sim_view(mb, slot);
38 uint32_t r = BLOCKS_R0 + BLOCKS_REGION * (t % 4);
39 uint32_t hdr[10] = {threads, f2u(sf), f2u(mf), su, mu, (uint32_t)sl, (uint32_t)(sl >> 32), (uint32_t)ml, (uint32_t)(ml >> 32), u[seed % threads]};
40 for (uint32_t i = 0; i < 10; i++) CHECK_U(mesh_sim_u32(view + r + 4 * i), hdr[i]);
41 CHECK(mesh_sim_u32(view + r + 40) < nodes);
42 CHECK_U(mesh_sim_u32(view + r + 44), threads / 32);
43 CHECK_U(res, su);
44 uint32_t wrong = 0;
45 for (uint32_t th = 0; th < threads; th++) {
46 uint32_t want[9] = {f2u(fi[th]), f2u(fe[th]), ui[th], ue[th], (uint32_t)li[th], (uint32_t)(li[th] >> 32), (uint32_t)le[th],
47 (uint32_t)(le[th] >> 32), f2u(f[threads - 1 - th])};
48 for (uint32_t i = 0; i < 9; i++)
49 if (mesh_sim_u32(view + r + BLOCKS_HDR + BLOCKS_PER * th + 4 * i) != want[i]) wrong++;
50 }
51 CHECK_U(wrong, 0);
52}
53
54static void run_shape(const char *name, uint32_t warps, uint32_t nodes, uint32_t shared, const uint32_t *seeds, size_t ns) {
55 uint8_t *mb = mesh_sim_mailbox();
56 mesh_sim_prog p = {.name = name, .view_bytes = 0x41000, .nodes = nodes, .warps = warps, .shared_bytes = shared};
57 mesh_sim_install(mb, 0, &p);
58 mesh_sim_launch *l = mesh_sim_launch_prog(mb, 0, &p, mesh_main);
59 CHECK_U(mesh_sim_call(mb, 0, MESH_OP_INIT, 0), MESH_R_NONE);
60 CHECK_U(mesh_sim_u32(mesh_sim_view(mb, 0)), BLOCKS_MAGIC);
61 for (size_t i = 0; i < ns; i++) check_seed(mb, 0, seeds[i], 32 * warps, nodes);
62 if (warps == 32) {
63 /* B3: early exits (warp 0 alone sums its lanes: 496), then stop/start and a task. */
64 uint8_t *ctl = mesh_sim_ctl(mb, 0);
65 uint32_t c0 = mesh_sim_u32(ctl + MESH_P_COUNTERS + 4);
66 for (int round = 0; round < 2; round++) {
67 uint32_t ts[32];
68 for (int k = 0; k < 32; k++) ts[k] = mesh_sim_publish(mb, 0, BLOCKS_OP_EARLY, 0);
69 for (int k = 0; k < 32; k++) {
70 uint32_t r = 0;
71 CHECK(mesh_sim_wait(mb, 0, ts[k], &r, 60000));
72 CHECK_U(r, 496);
73 }
74 }
75 CHECK_U(mesh_sim_u32(ctl + MESH_P_COUNTERS + 4), c0 + 64);
76 mesh_sim_halt(mb, 0, l);
77 l = mesh_sim_launch_prog(mb, 0, &p, mesh_main);
78 uint32_t u[1024], s = 0;
79 float f;
80 uint64_t w;
81 for (uint32_t t = 0; t < 1024; t++) { mesh_block_test_values(5, t, &f, &u[t], &w); }
82 s = mesh_block_reduce_u32(u, 1024, 0, mesh_block_add_u32);
83 CHECK_U(mesh_sim_call(mb, 0, MESH_OP_TASK, 5), s);
84 } else {
85 /* Fewer warps: the tree is the 1024-leaf one, padded with -0.0 (the same f32 sum). */
86 float f[1024];
87 uint32_t u;
88 uint64_t w;
89 for (uint32_t t = 0; t < 1024; t++) {
90 if (t < 32 * warps) mesh_block_test_values(seeds[0], t, &f[t], &u, &w);
91 else f[t] = mesh_block_sum_f32_id();
92 }
93 CHECK_U(f2u(mesh_block_reduce_f32(f, 32 * warps, mesh_block_sum_f32_id(), mesh_block_add_f32)),
94 f2u(mesh_block_reduce_f32(f, 1024, mesh_block_sum_f32_id(), mesh_block_add_f32)));
95 }
96 CHECK_U(mesh_sim_u32(mesh_sim_ctl(mb, 0) + MESH_P_FAULT), 0);
97 mesh_sim_halt(mb, 0, l);
98 mesh_sim_mailbox_free(mb);
99}
100
101int main(void) {
102 const uint32_t seeds[] = {1, 2, 3, 0xdeadbeefu, mesh_block_mix(100), mesh_block_mix(101)};
103 run_shape("blocks", 32, 1, 0x1000, seeds, sizeof seeds / sizeof *seeds);
104 run_shape("blocks-w4", 4, 2, 0x200, seeds, sizeof seeds / sizeof *seeds);
105 run_shape("blocks-w1", 1, 1, 0x200, seeds, 2);
106 return mesh_check_done();
107}