==> 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}