mirror of https://github.com/maderix/ANE.git
5.5 KiB
5.5 KiB
Local Apple M2 ANE Benchmark Results
Date: 2026-06-05
Host:
- Mac mini (Mac14,3), Apple M2, 8-core CPU (4 performance + 4 efficiency), 8 GB memory
- macOS 26.5, build 25F71
- Apple clang 21.0.0 (clang-2100.1.1.101)
- ANE subtype reported by the private benchmark API: h14
- Repository commit tested:
d91c9845c0(origin/main)
Runtime notes:
- Results were measured from a clean worktree at
/private/tmp/ANE-m2-cleanto avoid local code changes affecting benchmark numbers. - Benchmarks were run sequentially on the same machine because parallel ANE workloads contend for the accelerator and produce outliers.
- Tables below use the median of three runs where repeated. Raw logs were kept locally under
/private/tmp/ane_m2_2026-06-05_clean/. - Qwen3-0.6B dynamic training was not run on this 8 GB M2 machine; resident fp32 weights, gradients, Adam state, activations, transposed buffers, and IOSurfaces are expected to be memory-heavy.
- Two upstream output quirks were observed but not fixed in this results-only report:
inmem_peakprints an invalid%peakvalue, andane_int8_benchlabels the h14 run asM4. The tables below use the raw TFLOPS/TOPS and host metadata instead.
In-Memory Baseline
Command:
xcrun clang -O2 -fobjc-arc -framework Foundation -framework IOSurface -ldl \
-o inmem_bench inmem_bench.m
./inmem_bench
Median of three runs:
| Config | Weight MB | ms/eval | TFLOPS |
|---|---|---|---|
| 256ch x 64sp | 0.1 | 0.136 | 0.06 |
| 512ch x 64sp | 0.5 | 0.140 | 0.24 |
| 1024ch x 64sp | 2.0 | 0.204 | 0.66 |
| 2048ch x 64sp | 8.0 | 0.358 | 1.50 |
| 3072ch x 64sp | 18.0 | 0.552 | 2.19 |
| 4096ch x 64sp | 32.0 | 0.909 | 2.36 |
Peak-Style Conv Chain
Command:
xcrun clang -O2 -fobjc-arc -framework Foundation -framework CoreML \
-framework IOSurface -ldl -o inmem_peak inmem_peak.m
./inmem_peak
Median of three runs. % peak below is computed against the M2 15.8 TFLOPS FP16 reference; the current program output prints an invalid %peak column.
| Config | Weight MB | GFLOP | ms/eval | TFLOPS | % peak |
|---|---|---|---|---|---|
| 32x conv 512ch sp64 | 16.0 | 1.07 | 0.239 | 4.50 | 28.5 |
| 48x conv 512ch sp64 | 24.0 | 1.61 | 0.280 | 5.74 | 36.3 |
| 64x conv 512ch sp64 | 32.0 | 2.15 | 0.301 | 7.13 | 45.1 |
| 96x conv 512ch sp64 | 48.0 | 3.22 | 0.404 | 7.98 | 50.5 |
| 128x conv 512ch sp64 | 64.0 | 4.29 | 0.537 | 7.99 | 50.6 |
| 64x conv 256ch sp64 | 8.0 | 0.54 | 0.160 | 3.35 | 21.2 |
| 128x conv 256ch sp64 | 16.0 | 1.07 | 0.222 | 4.84 | 30.6 |
| 256x conv 256ch sp64 | 32.0 | 2.15 | 0.340 | 6.32 | 40.0 |
| 64x conv 384ch sp64 | 18.0 | 1.21 | 0.245 | 4.94 | 31.3 |
| 128x conv 384ch sp64 | 36.0 | 2.42 | 0.345 | 7.00 | 44.3 |
INT8 W8A8
Command:
xcrun clang -O2 -fobjc-arc -framework Foundation -framework IOSurface -ldl \
-o ane_int8_bench ane_int8_bench.m
./ane_int8_bench
Median of three runs:
| Config | Precision | Weight MB | GOP | ms/eval | TOPS | Ratio |
|---|---|---|---|---|---|---|
| 128x conv 512ch 64x64 | FP16 | 64.0 | 274.88 | 22.847 | 12.03 | - |
| 128x conv 512ch 64x64 | W8A8 | 32.0 | 274.88 | 23.046 | 11.93 | 1.01x |
| 64x conv 512ch 64x64 | FP16 | 32.0 | 137.44 | 12.442 | 11.05 | - |
| 64x conv 512ch 64x64 | W8A8 | 16.0 | 137.44 | 11.861 | 11.59 | 1.06x |
| 256x conv 256ch 64x64 | FP16 | 32.0 | 137.44 | 12.984 | 10.59 | - |
| 256x conv 256ch 64x64 | W8A8 | 16.0 | 137.44 | 13.272 | 10.36 | 1.05x |
| 128x conv 256ch 64x64 | FP16 | 16.0 | 68.72 | 6.801 | 10.10 | - |
| 128x conv 256ch 64x64 | W8A8 | 8.0 | 68.72 | 6.348 | 10.83 | 1.11x |
| 128x conv 384ch 64x64 | FP16 | 36.0 | 154.62 | 14.220 | 10.87 | - |
| 128x conv 384ch 64x64 | W8A8 | 18.0 | 154.62 | 13.770 | 11.23 | 1.08x |
On this M2, W8A8 is approximately parity to a modest improvement for these kernels, not the larger M4 speedup reported upstream.
Dynamic Matmul
Command:
cd training
xcrun clang -O2 -Wall -DACCELERATE_NEW_LAPACK -fobjc-arc \
-o test_dynamic_matmul test_dynamic_matmul.m \
-framework Foundation -framework CoreML -framework IOSurface -ldl -framework Accelerate
./test_dynamic_matmul
Result:
- 64x64 identity correctness: PASS, max error 0.001938
- 64x64 scale-by-2 correctness: PASS, ratio 2.000
- 768x768x256 single dynamic matmul: 1.012 ms/eval, 298.4 GFLOP/s
- With weight IO: 0.871 ms/eval, 346.8 GFLOP/s
- vs
cblas_sgemm: PASS, max error 0.014646
Tiled 768x768 matmul:
| tile_oc | tiles | compile ms | eval ms | GFLOP/s |
|---|---|---|---|---|
| 64 | 12 | 543 | 4.318 | 69.9 |
| 128 | 6 | 260 | 1.752 | 172.4 |
| 256 | 3 | 110 | 1.041 | 290.1 |
| 384 | 2 | 69 | 0.871 | 346.8 |
| 768 | 1 | 47 | 0.652 | 463.0 |
Dynamic Training
Data:
cd training
bash download_data.sh
The local run used tinystories_data00.bin: 20,658,981 tokens, 41.3 MB.
Build and run:
cd training/training_dynamic
make MODEL=stories110m
./train --scratch --steps 20 --accum 10 --warmup 2 --data ../tinystories_data00.bin
Result:
- Model: Stories110M, 109.5M parameters
- Active compact vocab: 9,205 tokens from 32,000
- One-time compile: 1,196 ms for 10 kernels
- Train time: 31,081 ms total
- Average train: 1,554.0 ms/step
- Wall time: 68.0 s
- Step 0 loss: 9.1105
- Step 10 loss: 8.6389
Notes:
- This is the dynamic weight pipeline, not the static pipeline used by the main cross-generation training table.
- The measured dynamic training run was IO-dominated on this 8 GB M2 machine.