Contents · Memory hierarchy, prefetching, NUMA
Hierarchy overview and AMAT
Foundations | 7-minute read
- CPU accesses progress from registers → L1 → L2 → LLC (L3) → DRAM → storage.
- Average Memory Access Time (AMAT) models latency contributions across levels.
- Workloads vary: compute-bound vs memory-bound; reuse and locality dominate.
AMAT ≈ L1_hit + L1_miss_rate × (L2_hit + L2_miss_rate × (L3_hit + L3_miss_rate × DRAM))
L1/L2/L3 properties and inclusivity
Cache levels | 8-minute read
- L1: per-core, small and fast; L2: larger, per-core; L3: largest, often shared.
- Inclusive LLC simplifies snooping; exclusive reduces duplication; non-inclusive is flexible.
- Prefetchers exist at multiple levels and can affect inclusivity behavior.
TLBs, page size, huge pages
Address translation | 8-minute read
- Translation Lookaside Buffers cache page table entries; TLB misses are costly.
- Use larger pages (2MB, 1GB) for streaming/large arrays to reduce TLB pressure.
- Beware of fragmentation and reduced protection granularity.
TLB reach = (#entries) × (page size)
Hardware/software prefetching
Timeliness | 9-minute read
- Hardware: next-line, stride, stream, spatial; tune via MSRs/BIOS where available.
- Software: compiler hints and intrinsics (e.g., __builtin_prefetch, _mm_prefetch).
- Balance pollution and timeliness; prefetch distance depends on latency and ILP.
// Software prefetch hint (GCC/Clang)
for (size_t i = 0; i < n; ++i) {
__builtin_prefetch(&a[i + 64], 0, 3);
sum += a[i];
}
Bandwidth vs latency, roofline
Performance | 8-minute read
- Compute throughput vs memory bandwidth determines upper bounds.
- Arithmetic intensity (FLOPs/byte) positions kernels on the roofline.
- Vectorization and tiling raise intensity; streaming stores save bandwidth.
NUMA basics and policies
Topology | 9-minute read
- Non-Uniform Memory Access: each socket has local memory; remote access is slower.
- Policies: default (first-touch), interleave, preferred, bind; affect placement and latency.
- Tools: numactl, lscpu, lstopo (hwloc) to inspect and control locality.
# Run on NUMA node 0 with interleaved memory
numactl --cpunodebind=0 --membind=0 ./app
Placement, first-touch, affinity
Practical tuning | 8-minute read
- Initialize memory on the threads that will use it (first-touch policy).
- Pin threads to cores/sockets to preserve locality and reduce migration.
- Use partitioned data structures to reduce cross-socket sharing.
# Pin to physical cores 0-7
sudo taskset -c 0-7 ./app
Measuring and profiling
Observability | 8-minute read
- Measure misses (L1/L2/L3), bandwidth, latency, TLB stats with perf/VTune/pcm.
- Trace prefetchers; tune BIOS/MSR controls cautiously, validate with benchmarks.
- NUMA counters: local vs remote accesses, inter-socket traffic.
Exercises
Hands-on | 8-minute read
- Implement cache tiling for a stencil and compare AMAT-derived predictions to measurements.
- Enable huge pages and measure TLB miss rate changes for a streaming workload.
- Optimize an app for NUMA: add thread pinning and first-touch initialization; measure speedup.
Memory performance is a multi-level problem: design for locality, prefetch wisely, and respect NUMA topology.