skip to content
==> tests/gemm.c <==
1/* gemm on exec's node loop: OP_CHECK's C against mesh-ref's f64 reference
2 * (fused multiply-adds round differently, so within a relative error), the
3 * blocked kernel against the plain loop on sizes off the tile grid, timed
4 * runs, the job record, sizes and threads. */
5#include "harness.h"
6#include "../src/gemm.h"
7#include "mesh/ref/gemm.h"
8
9
10int main(void) {
11    /* The kernel against the plain loop (tiles, edges, several threads). */
12    const size_t ns[] = {1, 5, 17, 64, 100, 257};
13    for (size_t i = 0; i < sizeof ns / sizeof *ns; i++) {
14        size_t n = ns[i];
15        float *a = malloc(sizeof(float) * n * n), *b = malloc(sizeof(float) * n * n), *c = malloc(sizeof(float) * n * n), *p = malloc(sizeof(float) * n * n);
16        mesh_gemm_inputs(n, a, b);
17        gemm_fast(n, a, b, c, false);
18        gemm_plain(n, a, b, p);
19        /* Both against the f64 reference (mesh-ref's metric: relative to the sum of |terms|). */
20        CHECK(mesh_gemm_max_rel_err(n, c) < 1e-5);
21        CHECK(mesh_gemm_max_rel_err(n, p) < 1e-5);
22        free(a), free(b), free(c), free(p);
23    }
24    mesh_mailbox mb = mesh_mailbox_test();
25    h_install(mb, 0, "gemm", 1, 0x100000, 0x8000);
26    h_slot h = {.mb = mb, .slot = 0, .prog = {gemm_init, gemm_task, NULL}};
27    h_start(&h);
28    CHECK_U(h_call(&h, MESH_OP_INIT, 0), MESH_R_NONE);
29    size_t v = 0x100000;
30    CHECK_U(mesh_mailbox_get(mb, v), GEMM_MAGIC);
31    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_SIZE), 1024);
32    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_IMPL), 2);
33    /* OP_CHECK 48: C in the view, against the reference. */
34    CHECK_U(h_call(&h, GEMM_OP_CHECK, 48), 48);
35    float c[48 * 48];
36    mesh_mailbox_read(mb, v + GEMM_V_C, (uint8_t *)c, sizeof c);
37    CHECK(mesh_gemm_max_rel_err(48, c) < 1e-4);
38    CHECK_U(h_call(&h, GEMM_OP_CHECK, 65), MESH_R_BAD_OP);
39    /* Sizes, a timed run, a job item and its record. */
40    CHECK_U(h_call(&h, GEMM_OP_SIZE, 96), 96);
41    CHECK_U(h_call(&h, GEMM_OP_SIZE, 9000), MESH_R_BAD_OP);
42    (void)h_call(&h, MESH_OP_TASK, 0);
43    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_N), 96);
44    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_RUNS), 1);
45    uint32_t t = h.next;
46    uint32_t us = h_call(&h, MESH_OP_JOB, 0);
47    CHECK(us < MESH_R_JOB_FAIL);
48    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_JOB_OUT + 8 * (t % MESH_PROG_RESULTS)), 96);
49    CHECK(mesh_mailbox_get(mb, v + GEMM_V_BEST) != 0);
50    (void)h_call(&h, GEMM_OP_PLAIN, 32);
51    (void)h_call(&h, GEMM_OP_SINGLE, 32);
52    CHECK(mesh_mailbox_get(mb, v + GEMM_V_PLAIN) != 0 && mesh_mailbox_get(mb, v + GEMM_V_SINGLE) != 0);
53    CHECK_U(h_call(&h, GEMM_OP_THREADS, 3), 3);
54    CHECK_U(mesh_mailbox_get(mb, v + GEMM_V_THREADS), 3);
55    CHECK_U(h_call(&h, 99, 0), MESH_R_BAD_OP);
56    CHECK_U(mesh_mailbox_get(mb, mesh_prog_ctl(0) + MESH_P_FAULT), 0);
57    h_stop(&h);
58    free(mb.base);
59    return mesh_check_done();
60}