Master the fundamental concepts of cache optimization through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it works__builtin_prefetch (GCC/Clang) and _mm_prefetch (Intel intrinsics) hint that the CPU should load a cache line before the load instruction executes. Compilers use this in hand-tuned memcpy and graph traversals when access patterns are predictable but not contiguous enough for hardware stride prefetchers.
Prefetch roughly 64/128 iterations ahead for memory-bound loops. Too early evicts useful lines; too late misses RAM latency hiding.
cLoading…
Keep the relevant documentation open while you implement. When your output disagrees with the reference, trace one failing case by hand before changing random lines.
You will add __builtin_prefetch to a memory-bound loop and compare timings with and without hints. This exercise asks you to find the prefetch distance that helps without polluting cache.
__builtin_prefetch(&a[i + d]) asks for data d iterations ahead, so the memory latency overlaps useful work. If d is too small, the loop still waits. If d is too large, the prefetch is wasted or arrives long before it is needed. Build a cycle-level timing model of a loop over an array, with and without software prefetch, and find the best distance. Use sequential, strided and gather (random index) access patterns; gather is the case hardware prefetchers cannot predict.
cLoading…
idx[i], which lives in line idx[i] * ELEM / LINE. For seq, idx[i] = i. For stride, idx[i] = (i * S) mod N.idx[i] = i and applies a Fisher. Yates shuffle, for i = N-1 down to 1, with x = x * 1103515245 + 12345 (unsigned 32-bit, starting from SEED, default 1, where 0 means 1) and j = (x >> 8) mod (i + 1).L cycles after it is first requested, and then stays available for the rest of the run. There is no hardware prefetcher.i + D < N, prefetch element idx[i + D]'s line: request it if it was never requested (otherwise count a redundant prefetch). Either way this costs 1 cycle.idx[i]: request its line if needed. If the data is not there yet, stall until it arrives.ceil(L / (W + 1)).cLoading…
The pattern name is sequential, strided or gather. Errors: elements: invalid (N must be 1..100000, the sizes positive), pattern: unknown X, pattern: stride must be positive, and distance D: must be >= 0.
Input:
cLoading…
Output:
cLoading…
Hidden tests cover gather access with one element per line (where prefetching matters most), a strided pattern, distances far too large, a machine with little work per element, a lower-latency memory, and invalid input.