code wiki / _hdl_build / nx_dod_cache.nx

nx_dod_cache.nx source

↩ module page · 26 lines · 1517 B

1// nx_dod_cache.nx -- P3: measured cache-traffic model for DATA-ORIENTED (SoA/ECS) vs ARRAY-OF-STRUCTS 2// (AoS / classic OOP layout). When a system uses A of F fields per entity: AoS drags the WHOLE struct 3// array through cache (you pay for all F fields even though you use A); SoA stores each field contiguously 4// so you stream only the A arrays you touch. Memory traffic (cache lines) is the binding cost on weak 5// cores (deep-research: DOD = "efficient usage of the CPU cache ... SoA vs AoS"). Pure integer. license_tier: ORIGINAL 6 7const DC_BELOW: i64 = 0 8const DC_PARITY: i64 = 1 9const DC_EXCEEDS: i64 = 2 10 11func dc_ceil_div(a: i64, b: i64) -> i64 { return (a + b - 1) / b } 12 13// AoS: iterating the system streams the entire struct array (all F fields) -> cache lines for N*F*bpf. 14func dc_aos_lines(n: i64, fields: i64, bpf: i64, line: i64) -> i64 { return dc_ceil_div(n * fields * bpf, line) } 15// SoA: stream ONLY the A accessed component arrays -> cache lines for N*A*bpf. 16func dc_soa_lines(n: i64, accessed: i64, bpf: i64, line: i64) -> i64 { return dc_ceil_div(n * accessed * bpf, line) } 17 18// fewer cache lines = less memory traffic = better on weak cores. SoA < AoS -> EXCEEDS. 19func dc_verdict(aos: i64, soa: i64) -> i64 { 20 if soa < aos { return DC_EXCEEDS } 21 if soa == aos { return DC_PARITY } 22 return DC_BELOW 23} 24 25// useful-byte utilization in per-mil for AoS (SoA is always 1000): accessed/fields. 26func dc_aos_util_permil(accessed: i64, fields: i64) -> i64 { return accessed * 1000 / fields }