fruit-fly-simulation / src /gpu-check.js
Xenova's picture
Xenova HF Staff
Upload 227 files
cc38b25 verified
Raw History Blame Contribute Delete
2.63 kB
import { BrainCPU } from './brain.js';
// 257-neuron fixture covers three workgroups, including a partial group.
export function parityGraph() {
const n = 257,
rows = Array.from({ length: n }, () => []),
sign = new Int32Array(n).fill(1);
for (let i = 0; i < 64; i++) {
rows[64 + i].push([i, 80], [128 + i, 60]);
rows[192 + i].push([64 + i, 100]);
sign[128 + i] = -1;
}
rows[256].push([0, 80], [128, 60]);
const offsets = [0],
sources = [],
counts = [];
for (const row of rows) {
for (const [i, c] of row) {
sources.push(i);
counts.push(c);
}
offsets.push(sources.length);
}
return {
n,
offsets: Uint32Array.from(offsets),
sources: Uint32Array.from(sources),
counts: Uint32Array.from(counts),
sign,
};
}
export async function checkGPU(create) {
const graph = parityGraph(),
cpu = new BrainCPU(graph),
gpu = await create(graph);
const rates = Float32Array.from({ length: graph.n }, (_, i) =>
i < 64 || (i >= 128 && i < 192) ? 1000 : 0,
);
let maxVoltageError = 0,
maxSynapticError = 0,
totalSpikes = 0;
try {
// Irregular batch boundaries exercise delay-ring wrap and count clearing.
for (const silent of [false, true]) {
cpu.reset();
await gpu.reset();
for (const steps of [1, 17, 19, 63, 100, 100, 100, 100, 100, 100, 100]) {
const expected = cpu.batch(steps, rates, silent),
actual = await gpu.batch(steps, rates, silent);
if (actual.tick !== expected.tick || actual.counts.length !== graph.n)
throw Error('GPU self-check: invalid clock or output size');
for (let i = 0; i < graph.n; i++)
if (actual.counts[i] !== expected.counts[i])
throw Error(`GPU self-check: spike mismatch at neuron ${i}, tick ${expected.tick}`);
totalSpikes += expected.total;
const state = await gpu.snapshot();
for (let i = 0; i < graph.n; i++) {
const dv = Math.abs(state.v[i] - cpu.v[i]),
dg = Math.abs(state.g[i] - cpu.g[i]);
if (
!Number.isFinite(dv) ||
!Number.isFinite(dg) ||
dv > 0.002 ||
dg > 0.002 ||
state.until[i] !== cpu.until[i]
)
throw Error(`GPU self-check: state mismatch at neuron ${i}, tick ${expected.tick}`);
maxVoltageError = Math.max(maxVoltageError, dv);
maxSynapticError = Math.max(maxSynapticError, dg);
}
}
}
return { neurons: graph.n, steps: 1600, totalSpikes, maxVoltageError, maxSynapticError };
} finally {
gpu.destroy();
}
}