A Hash That Collided on Every Name and a 25 MB Allocator Trap: What 4 Tracks of Speed Demon 2026 Taught Us About OS, Cache Hierarchy, and AI A team competing as cONFIG in the Speed Demon 2026 hackathon rewrote four slow Python reference implementations in zero-dependency Rust and C++23, achieving speedups of 159× to 942× and memory reductions of 6.5× to 29.3× across ingest, index, join and graph-traversal tracks. The team reported that a custom hash function passed SHA-256 correctness checks while colliding every customer name into a single L1 cache slot, and that an munmap-based memory reduction attempt regressed wall time from 0.052 s to 0.066 s. They also cautioned that using AI to golf line count traps developers in a local optimum until they do the hardware and scoring-function math themselves. TL;DR: For Speed Demon 2026 by Hackathon Raptors, our team cONFIG rewrote four deliberately slow Python reference implementations in zero-dependency Rust and C++23: This is the story of the mistakes that cost us the most time: a hash function that passed every SHA-256 gate while routing 100% of customer names into a single L1 slot, an munmap call that made memory no smaller and wall time worse, Golden Cove L1/L2/L3 cache sizing across 12 hyperthreads, and why golfing line count with AI traps you in a local optimum until you do the hardware and scoring-function math yourself. Repository: https://github.com/Yash-vs9/cOnfig-tracks https://github.com/Yash-vs9/cOnfig-tracks We entered all four tracks with zero external dependencies D = 1.00 , targeting the Falkenstein scoring box fsn1 : Intel Core i5-13500, 6 Golden Cove P-cores / 12 threads pinned via --cpuset-cpus="0-11" , turbo disabled at a fixed 2.50 GHz, 48 KiB L1d and 1.25 MiB L2 per P-core, 24 MiB shared L3. | Track | Task & Dataset | Language | Reference T ref / M ref | Our Best T / M / S | Speedup | Memory Reduction | K / Speed Score | |---|---|---|---|---|---|---|---| | Track A | Ingest 3.1M logs, 239 MB | Rust 2024 | 32.05 s / 228 MB | 0.034 s / 35 MB / 334 lines 282a0d6 | 942× | 6.5× | 34.19 76.70 | | Track B | Index 256 MB corpus, 50k queries | Rust 2024 | 56.35 s / 2,199 MB | 0.252 s / 75 MB / 1782 lines 282a0d6 | 223× | 29.3× | 18.84 63.75 | | Track C | Join 3.32M hostile CSV rows, 204 MB | C++23 | 14.44 s / 367 MB | 0.052 s / 15 MB / 332 lines 1e59383 | 277× | 24.5× | 26.72 71.34 | | Track D | Traverse 1.74M nodes, 5M edges, 2k queries | Rust 2024 | 72.69 s / 893 MB | 0.456 s / 83 MB / 704 lines 282a0d6 | 159× | 10.8× | 13.34 56.26 | The final numbers look clean in a table. Getting there was a sequence of wrong assumptions that the Falkenstein box corrected one by one. Track C asks you to join records.csv 3.32M rows against regions.csv and emit per-region aggregates, including the exact count of distinct customer name s per region dn . To avoid cross-core atomic contention on every row, we put a thread-local 2-way L1 filter tl cache 2048 2 32 KB per thread in front of a lock-free global hash table name keys 1 << 18 + a 256-bit region bitset name bits 1 << 18 4 . If name hash, region id was already in the thread's tl cache , we skipped the global table entirely. Here is the exact hash bytes function we shipped in commit 1e59383 0.052 s, 15 MB, 71.344 pts : js static inline uint64 t hash bytes const char s, uint32 t len { uint64 t h1 = len ^ 0x811c9dc5ULL, h2 = uint64 t len 0x9e3779b97f4a7c15ULL, w = 0, w1 = 0; if builtin expect len - 8U <= 8U, 1 { memcpy &w, s, 8 , memcpy &w1, s + len - 8, 8 ; h1 = mm crc32 u64 mm crc32 u64 h1, w , w1 ; h2 = h2 ^ w 0x9e3779b97f4a7c15ULL ^ w1 0x9e3779b97f4a7c15ULL; return h1 << 32 ^ h2 | 0x100ULL; } // ... } And inside the hot loop, we indexed the thread-local L1 filter using the low 11 bits of nh : uint32 t tl idx = uint32 t nh & 2047; It compiled cleanly. It passed every correctness check with an exact SHA-256 match. And when we shrunk the global table in commit 282a0d6 10 MB , our time actually regressed from 0.052 s to 0.066 s. Why? We finally dumped the raw hex output of hash bytes across customer names from the generator "Person 1001" , "Person 1002" , "Person 2500" , "Person 9999" : | Customer Name | 64-Bit Hash nh | Low 32 Bits uint32 t nh | tl idx = nh & 2047 | |---|---|---|---| | "Person 1001" | 0x369c194012cced30 | 0x12cced30 | 1328 | | "Person 1002" | 0x10cceab412cced30 | 0x12cced30 | 1328 | | "Person 2500" | 0xa08aee2a12cced30 | 0x12cced30 | 1328 | | "Person 5555" | 0xfba9c18c12cced30 | 0x12cced30 | 1328 | | "Person 9999" | 0xde6fb35212cced30 | 0x12cced30 | 1328 | Every 11-byte "Person XXXX" string had the exact same lower 32 bits 0x12cced30 and hashed to tl idx = 1328 . Look at what happened in the registers: "Person 1001" len = 11 , w first 8 bytes is "Person 1" and w1 last 8 bytes at s + 3 is "son 1001" . "son " 0x5f6e6f73 occupies bits 0..31 of "1001" occupy bits 32..63. 2^64 shifts bits strictly upward. Bits 32..63 of h2 h1 << 32 put the hardware CRC32 entirely into the upper 32 bits. Because the upper 32 bits h1 differed, the global hash table slot = nh ^ nh 32 & HT MASK still produced the right answer, so every correctness test passed. But tl idx = uint32 t nh & 2047 looked only at the bottom 11 bits, where "Person " and "son " were constant. Out of 2,048 slots in our L1 cache, 2,047 slots were permanently empty, and all 9,000+ names fought over the 2 ways of slot 1328, giving us a 99.98% L1 cache miss rate . Replacing the h2 multiply chain with a second mm crc32 u64 + a right-shift avalanche h ^ h 29 and an 8-miss software-pipelined mm prefetch ring buffer to hide the ~120-cycle L3 latency across 8 misses instead of probing 35 cycles after prefetching on the same row cut our sandbox join time from 74.1 ms to 50.9 ms . We originally wrote Track A in C++ and switched to zero-dependency Rust after seeing Rust dominate the top of the Track A board. Our first Rust push 1862874 , run-2f56a6016af5 ran in 0.0534 s with 42.0 MB of memory 69.88 pts . Adding an 8-byte SWAR latency parser and compacting lines for rustfmt 72.30 pts and vectorizing the endpoint space scan with AVX2 61516e3 , 75.06 pts brought our time down to 0.038 s, but our memory stayed stubbornly stuck at 42 to 44 MB, while the leaders were at 18 to 20 MB. Our static .bss struct SharedData was only ~20.8 MB. Where was the extra 23 MB coming from? Our wrong guess: We assumed the kernel was charging part of the 239 MB mmap of /data/requests.log against our container's memory counter. So we added hr buf and ep buf to copy the interned hour and endpoint strings out of the file mapping and called munmap bp, sz right after the scan phase finished. What the box said: Memory did not drop at all, and wall time got worse. The harness pre-warms /data/requests.log into the host page cache with vmtouch -t before the container starts. Under cgroups v2, mapping already-resident host page-cache pages with PROT READ + MAP SHARED charges 0 bytes of anonymous RSS to the container. Worse, cgroups v2 records memory.peak , the lifetime high-water mark of the container. Calling munmap after the scan phase cannot lower a peak that already happened; all it did was force Thread 0 to grab down write &mm- mmap lock in the kernel and tear down 61,184 page table entries while the clock was running. The actual culprit /proc/self/smaps : When we inspected /proc/self/smaps in our sandbox, two OS behaviors jumped out: l: u32; 49152 ; 12 when an hour had <= 49,152 requests, with a fallback v lats.resize tot, 0 Vec