code wiki / (root) / nx_softfloat_cost_kat.nx

nx_softfloat_cost_kat.nx

buildroot/runtime/nx_softfloat_cost_kat.nx

4956 B106 linesdepth 4pulls 6 transitivereach 0 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_softfloat_cost_kat.nx -- WHAT DOES SOFTWARE FLOAT ACTUALLY COST US? The most basic number in a no-float ecosystem, and nobody had measured it. WHY (2026-07-31): the perf lane converged on 'the inner loop is compute-bound on emulated float', but that was INFERRED, not measured. The chain: nx_batchscale_kat showed the matmul FLAT across m (1.12x); nx_matmul_tile_kat then read the weights 8x fewer times and gained 1.02x -- proving memory traffic was NOT the constraint; and the implied MAC rate was ~164 MFLOP/s, absurd for a modern core. Meanwhile nx_lw_cache_gate measured the Q4_K packed path at 4431 mflops on the SAME host -- ~27x faster, computing on INTEGER MANTISSAS. All of that POINTS at software float as the tax. None of it MEASURES it. THIS DOES: identical loop shape, identical trip count, identical accumulate-and-consume discipline -- one arm in emulated f32 (__f32_mul/__f32_add), one in native i64. The ratio IS the no-float tax per MAC. WHY BOTH ACCUMULATORS ARE PRINTED: a dead-code eliminator that dropped an unused result would make the integer arm look infinitely fast and produce a beautiful, meaningless number. Both accumulators are consumed by the output, and T3/T4 assert them -- a zero or wrong accumulator means the loop did not run and the timing is a lie. A benchmark that cannot prove its own loop executed is not a benchmark. WHAT THE ANSWER CHANGES: if the tax is large then quantisation is not primarily a BYTES decision, it is an ARITHMETIC decision -- integer/mantissa MACs skip the emulation entirely. Same action, different reason, and the reason decides what gets built next. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 3 imports · 0 importers

nx_f32.nx nx_f32_cvt.nx nx_fmt.nx nx_softfloat_cost_kat.nx

imports: nx_f32.nxnx_f32_cvt.nxnx_fmt.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main fmt_puts fmt_puts_fd sys_write sf_nl fmt_puts ↻ fmt_putn fmt_putn_fd sys_write ↻ nx_i32_to_f32 sys_now_us sys_mmap sys_clock_gettime_mono sf_t fmt_puts ↻ sf_nl ↻

structs

none

consts

27const SF_N: i64 = 2000000

functions

29func sf_nl() -> i64 { fmt_puts("\n" as *u8); return 0 }
called by 2: sf_tmain calls 1: fmt_puts
31func sf_t(name: *u8, cond: i64, ctr: *i64)
called by 1: main calls 2: fmt_putssf_nl
39func main() -> i64