code wiki / (root) / nx_flash_attention.nx

nx_flash_attention.nx

buildroot/runtime/nx_flash_attention.nx

10355 B273 linesdepth 5pulls 5 transitivereach 1 importersview sourcekind librarytopic flash
docsdependenciesstructsconstsfunctions

about

nx_flash_attention.nx -- tiled IO-aware attention (Dao 2022). Realises the F-001 row in VRAM_OPTIMIZATION_REALISTIC_TRACKING.md: 2-3 GB working-memory savings at ZERO quality loss. HONEST about what transfers vs what doesn't on the i64 substrate: CUDA FlashAttention wins on: * Memory savings: NEVER materialise full n*n score matrix * Latency: kernel fusion + async memory hides DRAM latency * Numerical stability: online softmax via running max On i64 substrate without SIMD/GPU: * Memory savings: SAME -- algorithmic, transfers fully. For n=1024 / head_dim=64: saves ~8 MB per head per layer. Across 16 heads * 40 layers = ~5 GB of working memory. * Latency: substrate has no kernel fusion (every op is a NishiLang function call); per-block compute is *slower* than naive per-row compute on small inputs. Win flips back POSITIVE for n > ~1024 because cache locality dominates. * Numerical stability: SAME -- online softmax is algorithm, not hardware. Bottom line: ship for the memory win, not the latency win (yet). When SIMD lands the latency story flips to "FlashAttention native always wins." Algorithm (one query row at a time): m = -INF running row-max l = 0 running normaliser sum O = zero vector (head_dim) running output for each KV block [j_start, j_end): S_block[j] = Q[i, :] @ K[j, :] (per j in block) m_block = max(S_block) m_new = max(m, m_block) rescale = exp(m - m_new) <= 1 P_block[j] = exp(S_block[j] - m_new) l = l * rescale + sum(P_block)

dependencies 4 imports · 1 importers

nx_syscalls.nx nx_tier.nx nx_tensor.nx nx_attention.nx nx_flash_attention.nx nx_flash_attention_test.nx

imports: nx_syscalls.nxnx_tier.nxnx_tensor.nxnx_attention.nx

imported by: nx_flash_attention_test.nx

structs

none

consts

66const NX_MAGIC_10000: i64 = 10000
68const NX_FA_Q10: nx_int = 1024
72const NX_FA_OK: nx_int = 0
73const NX_FA_ERR_BAD_DTYPE: nx_int = 1
74const NX_FA_ERR_BAD_NDIM: nx_int = 2
75const NX_FA_ERR_SHAPE_MISMATCH: nx_int = 3
76const NX_FA_ERR_NOT_CONTIGUOUS: nx_int = 4
77const NX_FA_ERR_BAD_BLOCK_SIZE: nx_int = 5
78const NX_FA_N_VERDICTS: nx_int = 6

functions

80func nx_fa_verdict_is_valid(v: nx_int) -> nx_int
called by 1: main
94func _fa_row(q: *NxTensor, k: *NxTensor, v: *NxTensor,
213func nx_fa_forward(q: *NxTensor, k: *NxTensor, v: *NxTensor,
called by 1: main calls 2: nx_t_is_contiguous_fa_row
258func nx_fa_working_memory_bytes(n_q: nx_int, n_kv: nx_int, d: nx_int,
267func nx_fa_savings_ratio_q10(n_q: nx_int, n_kv: nx_int, d: nx_int,