strata but optimized for m5 (and maybe more later)
README.md

Phase 0 Hardware Microbench — 13" MacBook Air M5 (Mac17,3) #

experiment: measure real uncached NVMe SSD throughput across MoE expert read patterns
            (3x512 KiB std GGUF vs 1x1.5 MiB contiguous .experts copy, queue depth 1..8,
            and 4 KiB PLE n-gram row lookups) plus M5 10-core GPU FP16 GEMM ceiling and
            60-second fanless thermal sag, to replace the 3 vs 6 GB/s and ~360 tok/s
            estimates in PLAN.md §5.2.
runs:
  - run_01: bench/m5_air_microbench.m -> bench/run_01_m5_air_microbench.log
  - run_02: bench/m5_air_microbench_v2.m -> bench/run_02_m5_air_microbench_v2.log
            (strictly disjoint offsets, F_NOCACHE=0 RAM control, 60s GPU thermal sag)
  - run_03: bench/m5_air_microbench_v3.m -> bench/run_03_m5_air_microbench_v3.log
            (12 GiB virgin slices, every test verified 100.0% physical NVMe via `iostat -Id` disk0)
execution: /usr/bin/clang -O3 -fobjc-arc -framework Foundation -framework Metal
           -framework MetalPerformanceShaders -lpthread; macOS 27.0 arm64, Apple M5
           (4S+6E CPU, 10-core GPU, 24 GB unified memory, 1 TB SSD).
decision: answered. PLAN.md §2.5, §4.3, and §5.2 updated with measured constants and
          two new runtime squeezes (2-4 thread pread fan-out for experts; 8-thread
          batched pread for layer-2 PLE 4 KiB row lookups).

Key Measurements #

1. SSD Read Throughput (run_03, 100.0% disk0 hardware counter verified on virgin 1 GiB slices) #

Pattern Read size th=1 (QD1) th=2 th=4 th=8
Sequential ceiling 4 MiB 5.49 GB/s — 7.09 GB/s —
Standard GGUF (3 reads/expert, random) 512 KiB 2.41 GB/s 5.52 GB/s 7.03 GB/s 7.04 GB/s
Contiguous .experts copy (1 read/expert, random) 1.5 MiB 3.93 GB/s 6.84 GB/s 6.89 GB/s 6.66 GB/s
Prefill strided ascending (.experts copy) 1.5 MiB 3.85 GB/s — 6.60 GB/s —
PLE n-gram table random 4 KiB (run_01) 4 KiB 0.04 GB/s (~10k IOPS, ~1.6 ms/tok for 16 heads) — — 0.33 GB/s (~82k IOPS, ~0.2 ms/tok)
Control: cached RAM (F_NOCACHE=0, run_02) 512 KiB 25.59 GB/s — 45.70 GB/s —

Methodological catch during run_02 → run_03: On macOS APFS, repeating pread over the exact same file offsets across loop iterations can partially hit APFS cache on iteration 2+ even when the descriptor has F_NOCACHE=1. run_03 eliminated this by allocating a 12 GiB file of unique incompressible blocks, giving every single test its own virgin 1 GiB slice, and verifying iostat -Id (disk0 physical MiB delta == 100.0% of requested MiB) around each test.

2. M5 10-Core GPU FP16 GEMM & 60-Second Thermal Sag (run_01, run_02) #

  • MTLDevice: Apple M5, hasUnifiedMemory = 1, recommendedMaxWorkingSetSize = 17.76 GiB
  • Peak burst FP16 GEMM (K = 2560):
    • M = 512, N = 2560: 12.60 TFLOP/s
    • M = 1024, N = 2560: 13.66 TFLOP/s
    • M = 4096, N = 2560: 14.07 TFLOP/s (exactly 1/4 of the 40-core M5 Max's ~56 TFLOP/s, confirming the ~356–360 tok/s resident prefill compute ceiling at ~30.4% MFU)
  • 60-second continuous 100% GPU load (M = 4096, K = 2560, N = 2560 FP16 GEMM):
    • t = 0..15s: 14.00–14.03 TFLOP/s
    • t = 30..35s: 13.98 TFLOP/s
    • t = 55..60s: 13.88 TFLOP/s (−0.86% sag over 60 seconds; the 10-core M5 GPU does not thermally cliff inside a 1-minute window).