skip to content
==> tests/block.c <==
1/* mesh-ref block.rs's test, then a golden digest from the Rust: every reduction and scan (f32 sum
2 * and max, u32 and u64 sums; inclusive and exclusive) for 20 seeds at 32..1024 threads. */
3#include "mesh/ref/block.h"
4
5#include "mesh/ftz.h"
6
7#include <stdio.h>
8
9static int failures;
10#define CHECK(c)                                                                                   \
11    do {                                                                                           \
12        if (!(c)) {                                                                                \
13            fprintf(stderr, "%s:%d: CHECK(%s) failed\n", __FILE__, __LINE__, #c);                 \
14            failures++;                                                                            \
15        }                                                                                          \
16    } while (0)
17
18static uint64_t fnv(uint64_t h, uint64_t w) { return (h ^ w) * 0x100000001b3ull; }
19
20static void rust_trees_and_identities(void) {
21    /* The tree over 1024 leaves, whatever the warps: 4 warps == 32 warps with the rest -0.0. */
22    float v[128], w[1024];
23    uint32_t u[256];
24    uint64_t dummy;
25    float fd;
26    for (uint32_t t = 0; t < 128; t++) mesh_block_test_values(7, t, &v[t], &u[0], &dummy);
27    for (int t = 0; t < 1024; t++) w[t] = t < 128 ? v[t] : mesh_block_sum_f32_id();
28    CHECK(mesh_ftz_bits(mesh_block_reduce_f32(v, 128, mesh_block_sum_f32_id(), mesh_block_add_f32)) ==
29          mesh_ftz_bits(mesh_block_reduce_f32(w, 1024, mesh_block_sum_f32_id(), mesh_block_add_f32)));
30    /* u32 sums: any order; scans are prefix sums. */
31    for (uint32_t t = 0; t < 256; t++) mesh_block_test_values(9, t, &fd, &u[t], &dummy);
32    uint32_t seq = 0;
33    for (int t = 0; t < 256; t++) seq += u[t];
34    CHECK(mesh_block_reduce_u32(u, 256, 0, mesh_block_add_u32) == seq);
35    uint32_t inc[256], exc[256], acc = 0;
36    CHECK(mesh_block_scan_u32(u, 256, 0, mesh_block_add_u32, true, inc));
37    CHECK(mesh_block_scan_u32(u, 256, 0, mesh_block_add_u32, false, exc));
38    for (int t = 0; t < 256; t++) {
39        CHECK(exc[t] == acc);
40        acc += u[t];
41        CHECK(inc[t] == acc);
42    }
43    /* max: total order, one of the inputs. */
44    CHECK(mesh_ftz_bits(mesh_block_max_f32(-0.0f, 0.0f)) == 0);
45    CHECK(mesh_ftz_bits(mesh_block_max_f32(0.0f, -0.0f)) == 0);
46    float m[32];
47    const float pat[4] = {1.0f, -2.0f, 3.5f, mesh_ftz_from_bits(0xff800000u)};
48    for (int i = 0; i < 32; i++) m[i] = pat[i % 4];
49    CHECK(mesh_block_reduce_f32(m, 32, mesh_block_max_f32_id(), mesh_block_max_f32) == 3.5f);
50    /* Invalid sizes. */
51    CHECK(mesh_block_reduce_u32(u, 33, 7, mesh_block_add_u32) == 7);
52    CHECK(!mesh_block_scan_u32(u, 0, 0, mesh_block_add_u32, true, inc));
53}
54
55static void rust_golden(void) {
56    static const size_t ns[6] = {32, 64, 128, 256, 544, 1024};
57    static float f[1024], fo[1024];
58    static uint32_t u[1024], uo[1024];
59    static uint64_t w[1024], wo[1024];
60    uint64_t h = 0xcbf29ce484222325ull;
61    for (uint32_t seed = 0; seed < 20; seed++) {
62        for (int ni = 0; ni < 6; ni++) {
63            size_t n = ns[ni];
64            for (uint32_t t = 0; t < n; t++) mesh_block_test_values(seed, t, &f[t], &u[t], &w[t]);
65            h = fnv(h, mesh_ftz_bits(mesh_block_reduce_f32(f, n, mesh_block_sum_f32_id(), mesh_block_add_f32)));
66            h = fnv(h, mesh_ftz_bits(mesh_block_reduce_f32(f, n, mesh_block_max_f32_id(), mesh_block_max_f32)));
67            h = fnv(h, mesh_block_reduce_u32(u, n, 0, mesh_block_add_u32));
68            h = fnv(h, mesh_block_reduce_u64(w, n, 0, mesh_block_add_u64));
69            for (int inc = 1; inc >= 0; inc--) {
70                mesh_block_scan_f32(f, n, mesh_block_sum_f32_id(), mesh_block_add_f32, inc, fo);
71                for (size_t i = 0; i < n; i++) h = fnv(h, mesh_ftz_bits(fo[i]));
72                mesh_block_scan_f32(f, n, mesh_block_max_f32_id(), mesh_block_max_f32, inc, fo);
73                for (size_t i = 0; i < n; i++) h = fnv(h, mesh_ftz_bits(fo[i]));
74                mesh_block_scan_u32(u, n, 0, mesh_block_add_u32, inc, uo);
75                for (size_t i = 0; i < n; i++) h = fnv(h, uo[i]);
76                mesh_block_scan_u64(w, n, 0, mesh_block_add_u64, inc, wo);
77                for (size_t i = 0; i < n; i++) h = fnv(h, wo[i]);
78            }
79        }
80    }
81    if (h != 0xb142436d933cba7eull) {
82        fprintf(stderr, "block digest %#018llx, want 0xb142436d933cba7e\n", (unsigned long long)h);
83        failures++;
84    }
85}
86
87int main(void) {
88    rust_trees_and_identities();
89    rust_golden();
90    return failures != 0;
91}