Ayush · Yadav the record room · case file 2 of 7

¶ case file 2 of 7 · glyph — filed 2025-10 · last verified 2026-08

status: shipped — v1.0.0 tagged, benchmarks committed

consigned at glyph — ¶ 06 · 15:23 · waybill: a blank 28×28 — the run wants your hand

Glyph

A course C++ MLP for MNIST, hand-optimized until there was nothing under it but SIMD. Four hand-written instruction sets in the dot kernels over a scalar fallback, OpenMP parallelism, a committed benchmark suite, and a React workbench where you draw a digit and watch the network read it.

role
c++ performance engineer — two-person project, my slice below
with
Shree Chaturvedi — the SIMD kernels, written together
timeframe
2025-10 to 2026-01
stack
C++ · AVX-512 / AVX2 · NEON · wasm128 · OpenMP · React
system card
/system-card ↗

[ problem ] · § as found

MNIST is small enough to hold in your head. That’s the point — at this size, low-level matrix optimization and benchmark discipline have nowhere to hide.

constraints —

  • Keep the implementation in C++ with explicit SIMD and OpenMP paths.
  • Quote no speedup that a committed benchmark run does not produce.
  • Expose the model through an interactive React and TypeScript frontend.
  • Keep benchmark and accuracy claims traceable to source data.
input 28×28hidden ×1000123456789softmax ×10the committed record97.01% — 9,701/10,000macro-f1 0.9698mnist_eval.txt @ 97de736one thread, -O3 · 1×openmp, all cores · 3.5×dot-256 · committed 2025-12-26

fig. 1 — the network at rest, over its committed record. the input square stays blank — the live read belongs to the line, at ¶ 06.

a drawn plate, at rest — not a screenshot. structure from the repository (784 ⟶ 100 ⟶ 10); both numbers are committed artifacts: mnist_eval.txt @ 97de736 and the 2025-12-26 benchmark run.

[ architecture ] · § fig. 2, inked

Input preprocessing feeds C++ matrix kernels and OpenMP parallel paths, then the React demo displays inference behavior and benchmark proof.

MNIST input

Digit preprocessing

matrix ops

SIMD kernels

AVX2, AVX-512, NEON — wasm128 in the dot kernels

threaded paths

OpenMP

Parallel hot paths

performance proof

Benchmarks

Performance suite

normalized digits

Neural network

C++ inference

prediction — server, wasm, or js fallback

React demo

Interactive visualization

fig. 2 — the system, inked. clay marks the gate: where a check can stop the run.

[ decisions ] · § as filed

d1 — use hand-tuned simd paths · accepted

The point is performance engineering you can read — kernels on the page, not framework calls.1

1 tradeoff — Hardware-specific paths need careful fallbacks and benchmarking.

d2 — expose a react demo · accepted

A reader can watch the network work without reading C++.2

2 tradeoff — The frontend is secondary to the C++ benchmark proof.

[ validation ] · § the receipts

at a glance — 5 of 5 terminate in pinned artifacts

validation

walks the receipts below, top to bottom, and marks each row this page can verify: a check where a pinned artifact resolves, a ring where the trail ends in an on-page capture, a dash where a claim is described only. walked once, the result settles here and stays.
  1. 01claim: The network scores 97.01% on the 10,000-image MNIST test set — 9,701 correct, 299 wrong, macro-F1 0.9698 — measured by a committed eval run, not README prose.

    method: committed eval report: generator apps/eval_model.cpp, model.weights pinned by sha256, 784→100→10 sigmoid MLP; the public MNIST test set is not vendored in the repodate: 2026-07-27

  2. 02claim: The dot-256 kernel runs 3.5× faster under OpenMP than the -O3 baseline — and the parallelism carries all of it: all three configurations were built, and on arm64 the baseline and native binaries are byte-identical, so the hand-written NEON path sits in both sides of the comparison. Committed benchmark data, not a live run.

    method: committed 2026-08-02 benchmark run, 20 repetitions — protocol in the method slipdate: 2026-08-02

  3. 03claim: A benchmark suite is committed — matrix kernels measured across the repo’s three configurations (baseline, native, openmp+native), with dated run files in the repo.

    method: benchmark source + committed run JSONdate: 2026-08-02

outcomes

  1. 04claim: SIMD acceleration is implemented across AVX2, AVX-512, NEON and — in the dot kernels, since glyph@68f1362 — a hand-written wasm128 path; the verified 3.5× belongs to OpenMP parallelism, not to SIMD — the vectorised path is compiled into both sides of that comparison, so it earns none of the number.

    method: source paths + the committed benchmark rowsdate: 2026-08-08

  2. 05claim: The interactive React workbench is deployed — draw a digit and watch the network read it.

    method: the live demo itselfdate: 2026-07

    [public]

ci rows link the public run · repo pins are the exact commits verified 2026-08.

what i’m NOT claiming —

  • No AVX-512 inference-speedup claim survives here — see the corrections register below. The verified number is OpenMP’s 3.5× over the -O3 baseline at dot 256; the SIMD is in both builds and earns none of it.
  • The workbench screenshot was captured with the native inference server offline, so benchmark claims come from committed benchmark data, not the live page.
  • The two-layer MLP itself is not claimed here — it is a course network that already existed, and this file is about what was done to it. The SIMD kernels were written with Shree Chaturvedi on a two-person project; the product, the landing page and the benchmark discipline are mine.

[ corrections ] · § the register

  • erratum · 2026-07-30

    Credited the collaborator and stopped claiming the network. This file described a two-person project as though one person had built it, and its summary opened by claiming a neural network that already existed — a course MLP this work optimized rather than authored. Both were omissions on the site’s side: the résumé has consistently said 2-person team and named the kernels as written with a teammate. The meta ledger now scopes the role the way the capstone’s already does, and the not-claiming list states what is not mine. Under-crediting a collaborator is the one error on this site that costs more than a wrong number, because a number can be re-measured and a person cannot be un-omitted. The collaborator is Shree Chaturvedi, named here and in the meta ledger above, and he is the same teammate as on the capstone.

  • erratum · 2026-05-28

    Retracted the earlier AVX-512 inference-speedup claim: the committed classify-throughput rows do not support it. The number this file stands behind is the 3.5× dot-kernel speedup, and the receipt above links the committed data.

  • erratum · 2026-07-26

    The live-demo outcome row linked fast-mnist.vercel.app. That alias still answers, so nothing 404’d — but it is not the brand URL, and the file was printing one host in its meta ledger and another in the row. The row now links getglyph.vercel.app, the same host as the rest of the file.

  • note · 2026-07

    Attribution tightened, number unchanged: the committed 3.5× (dot 256) is the openmp+native configuration measured against the -O3 baseline, and the earlier site copy that credited the speedup to SIMD alone is retired. BENCHMARKS.md’s own analysis records that -march=native alone barely moves the needle. This note then named the winning side “openmp+simd”, which reads as though the vectorisation earns part of the number — a second wrong attribution, corrected by the 2026-08-06 erratum at the end of this register.

  • note · 2026-07-30

    The accuracy claim is no longer held. From the first filing this file stamped ~97% HELD, because the number lived in README prose and no committed run reproduced it — the stamp named its own release condition: held until a committed eval run earns it. That run was committed on 2026-07-27 (glyph @ 97de736), and it brings its own generator, apps/eval_model.cpp, the model it scored pinned by sha256, and a 299-row list of every image it got wrong. So the stamp comes off and the number is stated as measured rather than rounded: 9,701 of 10,000, 97.01%, macro-F1 0.9698. Holding a claim that has been earned is not caution, it is under-claiming, and it would empty the stamp of meaning for the claims that are still genuinely unearned. Honest boundary kept: the 10,000-image MNIST test set is not vendored in the repository, so the run reproduces with the standard public dataset rather than from the repo alone.

  • note · 2026-07-30

    Receipts and the repo pin now read yadava5/glyph rather than yadava5/fast-mnist-nn. No commit or number moved — c6e5c0b is the same benchmark commit it always was, and the v1.0.0 release is the same tag. The repository was renamed with the product, and the old paths now answer only through a GitHub redirect, which stops resolving if any repo named fast-mnist-nn appears under this account again. Every canonical path in this file was fetched and returned 200 before the labels were changed.

  • note · 2026-07

    The ~97% accuracy receipt now carries the HELD stamp: the number is documented in the repo’s README training notes, but no committed eval artifact reproduces it yet. The claim is unchanged and stays on file; the stamp lifts when an eval run is checked in.

  • note · 2026-07-27

    The HELD stamp described in the note above is lifted. glyph@97de736 commits benchmarks/mnist_eval.json, its generator apps/eval_model.cpp, and the 299-row miss list, which is the condition that note set. The rounded “~97%” is retired with it: once a number has an artifact, stating it approximately is a second, smaller inaccuracy. The receipt reads 97.01% — 9,701 of 10,000, macro-F1 0.9698.

  • erratum · 2026-08-02

    Three receipt labels still read “fast-mnist-nn @ c6e5c0b” even though the 2026-07-30 note above told the reader every label had been changed to glyph. The hrefs had been converted; the visible text had not, so the label and the link it sat on named different repositories. The labels now read glyph. Recorded as an erratum rather than a silent fix because the defect was not the stale name — it was a register entry describing a repair that never shipped, on a page whose argument is that this register can be trusted.

  • note · 2026-08-02

    Provenance audit: the MNIST evaluation was re-run from source on an Apple M1 Pro against the standard 10,000-image test set. The regenerated mnist_eval.json and mnist_misclassified.csv are byte-identical to the committed artifacts — 9,701 correct, 299 wrong, macro-F1 0.969822, the same model sha256. The dot-256 kernel benchmark was rebuilt and re-measured at 3.536× — the median of 20 repetitions, committed as docs/benchmarks/runs/bench-20260802-dot20x-{baseline,openmp-native}.json — against the 3.504× December record, which was taken on a different machine (a 4-performance-core M2 Air) and is history rather than the reference. The 3.520× this line used to cite had no committed JSON, and Glyph's own two records disagreed about how it was taken: ENVIRONMENT.md called it a single-repetition re-run, the audit log called it three repetitions. One caveat surfaced and is recorded at the receipt: apps/eval_model.cpp has no add_executable in CMakeLists.txt, so the generator has to be compiled by hand rather than through the project’s own build.

  • erratum · 2026-08-06

    This file credited the 3.5× to an “openmp+simd” kernel in five places — the method slip, the benchmark receipt, the SIMD outcome row, the not-claiming list, and the 2026-07 note above that was itself the correction. The fig. 1 plate said it too, in its drawn label and in the sentence a screen reader is given. The number never moved; the attribution did, and it was wrong: the speed-up is OpenMP’s alone. Settled by building rather than by reading BENCHMARKS.md — all three configurations were compiled, and on arm64 the baseline and native binaries come out byte-identical, because -march=native is an x86 flag clang does not act on here. So the hand-written NEON path is in both sides of the comparison and earns none of the ratio; it is also why a SIMD-alone measurement sits at about 1.0, comparing a binary with itself. The run’s ¶ 06 and the proof manifest have carried this attribution since 2026-08-03 while this file carried the other one, on the same site, about the same measurement. Recorded as an erratum rather than a silent edit because a corrections register that carries a stale correction is worse than one that carries none: it is this page’s own promise that somebody checked.

  • note · 2026-08-08

    The instruction-set count moves from three back to four — in the dot kernels, which is where the fourth one lives. The 2026-08-02 provenance audit cut this file’s “four” to three, and it was right: at that point the source guarded exactly __AVX512F__, __AVX2__ and __ARM_NEON over a scalar fallback, and the wasm build was -msimd128 auto-vectorisation — a compiler flag, not a kernel. Four days later, glyph@68f1362 (2026-08-06) retired the condition that finding rested on: src/NeuralNet.cpp now carries a hand-written __wasm_simd128__ branch — dot_wasm128_rowvec, wasm_f64x2 intrinsics with two independent accumulators, a shape the kernel’s own comment notes LLVM’s autovectorizer declines to produce for this loop — and the build’s -msimd128 flag means that branch is genuinely compiled into the wasm target. The qualifier travels with the number: four in the NeuralNet dot kernels, while Matrix.cpp still guards three; and the résumé, which said four throughout, is right again — though not vindicated: for the four days between the audit and the commit its four was the wrong number, and it is the source that moved, not the page that failed to keep up. This file’s repo pin (001e9b4) predates the commit and stays where it is — every use of it here is benchmark provenance — so the fourth kernel is cited at its own commit in the outcome row above. Recorded as a note rather than an erratum because the 2026-08-02 entry was correct when written; a register that rewrites a right call to look prescient is worse than one that shows the fact moving.

[ appendix ] · § plates & artifacts

artifact index —

real-screenshot

Local React workbench screenshot

open original ↗

source: local web workbench capture · date: 2026-06 · boundary: native inference server offline during capture

Local React workbench screenshot artifact