Foundry/metal/tests/fm_golden_vectors.h

114 lines
3.8 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/**
* @file fm_golden_vectors.h
* @brief Reader for the PNGOLDEN1 CPU-reference vectors the Metal kernel
* tests check against. Header-only so a test file just includes it.
*
* PROVENANCE: the .bin files in metal/tests/golden are byte copies of the
* qwen35moe golden set generated by Pantheon's gen_golden_qwen35.c from a
* fixed xorshift32 seed (0x9E3779B9), regenerated there with
* `make USE_BLAS=1 golden`. They are checked in here so foundry's tests
* need no sibling checkout. Point FM_GOLDEN_DIR at a freshly regenerated
* Pantheon set to check for drift.
*
* FILE FORMAT (self-describing):
* line 1, ASCII: PNGOLDEN1 <name> <dtype> <count> seed=0x9E3779B9\n
* remainder: <count> little-endian <dtype> values
*
* @status Reads the f32 files, which is every vector these tests use.
* @issues None
* @todo None
*/
#ifndef FOUNDRY_METAL_TEST_GOLDEN_VECTORS_H
#define FOUNDRY_METAL_TEST_GOLDEN_VECTORS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Directory the vectors are read from. Set once at startup. */
static char fm_golden_dir[1024] = "metal/tests/golden";
/**
* Points the reader at the golden directory: $FM_GOLDEN_DIR if set,
* otherwise the `golden` directory beside the test binary, which makes the
* tests runnable from any working directory.
*
* @param argv0 argv[0] of the test binary
*/
static void fm_golden_locate(const char *argv0)
{
const char *env = getenv("FM_GOLDEN_DIR");
if (env && env[0]) {
snprintf(fm_golden_dir, sizeof(fm_golden_dir), "%s", env);
return;
}
const char *slash = argv0 ? strrchr(argv0, '/') : NULL;
if (slash)
snprintf(fm_golden_dir, sizeof(fm_golden_dir), "%.*s/golden",
(int)(slash - argv0), argv0);
}
/**
* Reads a PNGOLDEN1 f32 vector.
*
* Never returns a short or silently defaulted buffer: a missing file, a bad
* magic, a non-f32 dtype, a count that disagrees with `expect_count`, or a
* truncated payload all print the reason and return NULL, so a test can
* only ever run against the real oracle.
*
* @param name File name inside the golden directory
* @param expect_count Element count the caller requires
* @return malloc'd array of expect_count floats (caller frees),
* or NULL
*/
static float *fm_golden_load_f32(const char *name, size_t expect_count)
{
char path[1152];
char header[256];
char magic[16] = {0}, vec_name[64] = {0}, dtype[8] = {0};
unsigned long count = 0;
float *values = NULL;
FILE *f = NULL;
snprintf(path, sizeof(path), "%s/%s", fm_golden_dir, name);
f = fopen(path, "rb");
if (!f) {
fprintf(stderr, " golden: cannot open %s\n", path);
return NULL;
}
if (!fgets(header, sizeof(header), f)) {
fprintf(stderr, " golden: %s has no header line\n", path);
goto cleanup;
}
if (sscanf(header, "%15s %63s %7s %lu", magic, vec_name, dtype, &count) != 4 ||
strcmp(magic, "PNGOLDEN1") != 0 || strcmp(dtype, "f32") != 0) {
fprintf(stderr, " golden: %s has a bad header: %s", path, header);
goto cleanup;
}
if (count != expect_count) {
fprintf(stderr, " golden: %s holds %lu values, expected %zu\n",
path, count, expect_count);
goto cleanup;
}
values = (float *)malloc(expect_count * sizeof(float));
if (!values) {
fprintf(stderr, " golden: out of memory for %s\n", path);
goto cleanup;
}
if (fread(values, sizeof(float), expect_count, f) != expect_count) {
fprintf(stderr, " golden: %s payload is truncated\n", path);
free(values);
values = NULL;
}
cleanup:
fclose(f);
return values;
}
#endif /* FOUNDRY_METAL_TEST_GOLDEN_VECTORS_H */