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 }