Benchmarks
這一頁把 Story 的 pack-once 設計放回完整 measurements,界定 它在哪些 workload 勝出、持平或仍然落後。
Result Map
PR #1256 量測一個 targeted Cartesian family:
2 dtypes
x 3 broadcast positions: LHS, RHS, cross
x 2 BLAS-incompatible inner layouts: reverse, step 2
x 6 affected sizes: 16, 24, 32, 64, 128, 256
= 72 cases
這 72 點都會走 PR 新增的 pack-once route。下圖逐格顯示公開 JSONL 重算出的
NumPy median / solvcon median;1.00x 是同速,大於 1.00x 才是 solvcon
較快。
圖裡也能看出結果不是「矩陣越大,優勢越大」。float32 的高點集中在 S=64,
float64 多數在 S=32;到了 S=256,float64 的優勢只剩 1.15x–1.22x。
最低的 1.11x 出現在 float64、cross broadcast、step-two、S=16。該點的
90 筆 estimates 中,NumPy median 是 0.008119 ms,IQR 為
0.008051–0.008239 ms;solvcon median 是 0.007331 ms,IQR 為
0.007116–0.007600 ms。IQR 描述 raw samples 的分布,不是 confidence
interval。最靠近 crossover 與最大尺寸的 margin 並不寬。
同一次實驗另有 S=8、S=12 的 24 個 controls。它們沒有改變 route,不在
上圖的 72 格中;24 點仍全部由 NumPy 領先,solvcon runtime 是 NumPy 的
1.37x–2.33x。這正好保留了 policy boundary 兩側的結果。
Other Routes
其他 PR 補上「持平」與「仍然輸」的區域:
- #1256 reused incompatible matrix, pack once:72/72 勝出,範圍
1.11x–2.97x。這就是本頁 heatmap 的 targeted family。 - #1209 C-contiguous
S=256batched GEMM:ratio 為0.951–1.031。 兩邊使用同一 Accelerate backend,大致持平。 - #1259 reused negative-stride vector, pack once:32/32 勝出,median
6.24x。vector reuse 也能攤提 packing。 - #1259 positive-stride vector, direct BLAS:16/80 勝出,median runtime
是
1.06x NumPy。direct BLAS 消除舊 generic 成本,但不保證贏 NumPy。
這張表的分界比「用了 BLAS」更具解釋力。兩邊直接進入同一個 backend 時,首先 應期待 parity;能跨 contractions 少付重複 layout 成本時,才出現穩定勝出的 targeted family。
Measurement
1256 的正式資料來自 native macOS 26.5.1 arm64、Python 3.14.6、NumPy 2.5.1
與單執行緒 Apple Accelerate。每個 workload 比較 NumPy、PR parent、PR head,
並量完整的 np.matmul() 或 matmul_planned() call,不只抽出 BLAS kernel。
每個 method 先執行一次 discarded preconditioning。接著六個 rounds 走遍三種
methods 的六種 execution orders。每個 method 在每輪先跑兩個 untimed warm-up
batches,再收集 15 個 calibrated timed batches;每個 timed batch 約 30 ms,
elapsed time 除以 inner-loop count 得到 per-call estimate。每個 method 因此有
6 x 15 = 90 筆 estimates,圖中每格使用 untrimmed median。
完整 artifact 有 96 workloads x 3 methods x 6 rounds = 1,728 筆 JSONL
records。inputs、conversion、warm-up 與 correctness checks 不計時;dispatch、
output allocation、kernel execution 與 return 都在 timer 內。96 個 workloads
全部通過 numerical check,最大 relative Frobenius error 是 1.32e-16。
Calibration
Result map 是 merged selector 在 targeted family 上的 measurements;threshold
calibration 是另一件事。
PR #1209 以相同 inputs 強制執行
generic 與 CBLAS,量出不同 role 的 crossover。這些 measurements 形成當時
merged policy,例如 DOT K >= 128 與 GEMM min(M,N,K) >= 8。
完整 boundaries 與 selector 條件放在 Dispatch。 它們是該機器與 backend 的實測 policy,不是 Matmul semantics,也不是 portable performance constants。
Audit
公開 artifact 保留了重算上圖所需的資料。下載 raw data 後,以下腳本會 檢查 record 數量、每格的 90 筆 samples、72 格的 Cartesian coverage,並輸出 heatmap 使用的全部 ratios 與 summary。
顯示 artifact audit 指令
curl -L \
https://github.com/user-attachments/files/30812808/pr1256-exact-head-profiling.jsonl.txt \
-o pr1256.jsonl
python3 - pr1256.jsonl <<'PY'
import collections
import json
import statistics
import sys
samples = collections.defaultdict(list)
records = 0
with open(sys.argv[1], encoding="utf-8") as stream:
for line in stream:
row = json.loads(line)
key = (row["dtype"], row["case"], row["size"], row["method"])
samples[key].extend(row["samples_ms"])
records += 1
assert records == 1728
assert all(len(values) == 90 for values in samples.values())
medians = {
key: statistics.median(values)
for key, values in samples.items()
}
dtypes = ("float32", "float64")
cases = (
"cross_broadcast_negative",
"cross_broadcast_step2",
"lhs_broadcast_negative",
"lhs_broadcast_step2",
"rhs_broadcast_negative",
"rhs_broadcast_step2",
)
sizes = (16, 24, 32, 64, 128, 256)
ratios = {}
for dtype in dtypes:
for case in cases:
row = []
for size in sizes:
key = (dtype, case, size)
ratio = (
medians[key + ("numpy",)] /
medians[key + ("after",)]
)
ratios[key] = ratio
row.append(ratio)
print(dtype, case, *(f"{value:.2f}" for value in row))
assert len(ratios) == 72
values = list(ratios.values())
print("all above 1:", all(value > 1 for value in values))
print("minimum:", f"{min(values):.2f}x")
print("median:", f"{statistics.median(values):.2f}x")
print("maximum:", f"{max(values):.2f}x")
PY
預期 summary 是:
artifact 也記錄 benchmarked revisions:parent d3464749、PR head d4c1c98e、
NumPy 2.5.1。這是重算既有 measurements,不是重新執行 benchmark。
Re-run
1256 公開了完整 raw JSONL,但產生這 1,728 records 的 exact harness 沒有納入
版本控制。目前能精確重算 artifact,尚不能用 repository checkout clean re-run 同一組 cases、process ordering 與 timing protocol。完整 rerun 需要補上當時的 harness source、環境建置與 thread-control command。
Sources
- PR #1256: pack reused matrices once
- PR #1256 raw JSONL
- PR #1209: direct BLAS calibration and controls
- PR #1209 raw profile
- PR #1259: batched vector routing
- PR #1259 formal JSONL
- PR #1259 targeted confirmation JSONL
#1209 與 #1259 的 measurement protocols
1209 使用五個 rounds,每 round 兩次 warm-up 與 15 次 individually timed
calls,再取 75 筆的 untrimmed median。
1259 使用 persistent processes、約 15 ms 的 calibrated timed batches
與 12 個 rounds;六種 method orders 各出現兩次。不同 PR 的 samples 沒有 混成跨實驗 aggregate。