code wiki / (root) / locality.nx

locality.nx source

↩ module page · 105 lines · 3553 B

1// locality.nx -- data-locality markers + cost estimates. 2// 3// EFFICIENCY_ROADMAP ยง1.1. Speed of light = 30 cm/ns. Modern 4// memory / network hierarchy looks like: 5// L1 cache ~1 ns reg-adjacent 6// L2 cache ~5 ns 7// L3 cache ~20 ns 8// DRAM (NUMA-local) ~100 ns 9// DRAM (remote) ~150 ns 10// NVMe SSD ~10,000 ns (10 us) 11// CXL tier-3 mem ~500 ns (emerging) 12// Network LAN ~100,000 ns (100 us) 13// Network WAN ~10,000,000 ns (10 ms) 14// Interplanetary ~minutes+ (light-delay bound) 15// 16// NishiLang today can't reason about ANY of this -- every deref 17// looks equal to the type system. Phase B lifts these constants 18// + markers into the type system so hot loops can be flagged 19// when they cross locality boundaries ('remote deref in hot 20// loop' warning, cost-aware codegen). 21// 22// Phase A: runtime descriptors so library code can attach 23// locality tags to its pointers + query / branch on them. 24// 25// Invariants: 26// LC1 Every LocalityTier constant carries a pessimistic- 27// upper-bound latency in nanoseconds. 28// LC2 Ordering is monotonic: tier N implies latency <= tier N+1. 29// LC3 `locality_worse(a, b)` returns the slower of two tiers 30// -- useful when composing operations. 31 32import "syscalls.nx" 33 34// Locality tiers (ns-upper-bound latency for a single read). 35const LOC_REGISTER: i64 = 1 36const LOC_L1: i64 = 2 37const LOC_L2: i64 = 10 38const LOC_L3: i64 = 30 39const LOC_DRAM_LOCAL: i64 = 100 40const LOC_DRAM_REMOTE: i64 = 200 41const LOC_CXL: i64 = 600 42const LOC_NVME: i64 = 15000 43const LOC_NET_LAN: i64 = 200000 44const LOC_NET_WAN: i64 = 50000000 45const LOC_DISTANT: i64 = 1000000000 // moon/mars/satellite 46 47// Latency ns for a tier. Returns the same constant values as 48// above; exposed as a function so cost calculations stay 49// abstract. 50func locality_latency_ns(tier: i64) -> i64 { 51 return tier 52} 53 54// Pick the slower (pessimistic-bound) of two tiers. 55func locality_worse(a: i64, b: i64) -> i64 { 56 if a > b { return a } 57 return b 58} 59 60// Is a given tier considered "hot-loop safe" (= L3 or faster)? 61func locality_hot_safe(tier: i64) -> i64 { 62 if tier <= LOC_L3 { return 1 } 63 return 0 64} 65 66// === locality-tagged pointer descriptor ============================= 67// 68// Attach to any *u8 to track where it lives. Runtime check 69// only; compile-time enforcement is the Phase B upgrade. 70 71struct LocPtr { 72 ptr: *u8, 73 tier: i64, 74 bytes: i64, // accessible region length 75} 76 77func locptr_new(p: *u8, tier: i64, bytes: i64) -> *LocPtr { 78 let raw: *u8 = sys_mmap(32) 79 let lp: *LocPtr = raw as *LocPtr 80 lp.ptr = p 81 lp.tier = tier 82 lp.bytes = bytes 83 return lp 84} 85 86// Compute the cost of accessing `n_reads` through a LocPtr. 87func locptr_access_cost_ns(lp: *LocPtr, n_reads: i64) -> i64 { 88 return locality_latency_ns(lp.tier) * n_reads 89} 90 91// Compile-only smoke. 92func main() -> i64 { 93 // Sanity: DRAM remote is slower than L1. 94 if locality_worse(LOC_L1, LOC_DRAM_REMOTE) != LOC_DRAM_REMOTE { 95 return 1 96 } 97 if locality_hot_safe(LOC_L2) != 1 { return 2 } 98 if locality_hot_safe(LOC_DRAM_REMOTE) != 0 { return 3 } 99 100 let scratch: *u8 = sys_mmap(4096) 101 let lp: *LocPtr = locptr_new(scratch, LOC_L2, 4096) 102 if lp.tier != LOC_L2 { return 4 } 103 if locptr_access_cost_ns(lp, 1000) != 10000 { return 5 } 104 return 0 105}