Course contentsShow
← Rust
Lesson 458 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Data Layout for Cache Locality

Structure types to ensure fields accessed together stay within the same cache line.

In this lesson, you will learn how to arrange your struct fields to ensure that data accessed together stays within the same CPU cache line.

Understanding the Cache Line

Modern CPUs don't fetch single bytes from memory; they fetch "cache lines," which are typically 64 bytes wide. If your code accesses field_a and field_b in the same loop, but they are physically far apart in your struct, the CPU might have to fetch two separate cache lines from main memory. This leads to "cache misses," which are significantly slower than reading data already in the L1 cache.

Arranging for Locality

To optimize for cache locality, you should group your "hot" data—the fields you access together—at the top of your struct.

Consider a particle simulation where you frequently update x, y, and z coordinates, but rarely touch the last_updated timestamp:

// Inefficient: 'last_updated' sits between our hot coordinate data.
struct Particle {
    x: f32,
    last_updated: u64, // Hot data is split across cache lines!
    y: f32,
    z: f32,
}

// Efficient: Hot data is packed together.
struct Particle {
    x: f32,
    y: f32,
    z: f32,
    last_updated: u64, // Cold data moved to the end.
}

In the efficient version, x, y, and z are guaranteed to be contiguous in memory. When the CPU loads the struct into its cache, these three fields will almost certainly reside in the same 64-byte window. By placing the "cold" last_updated field at the end, you ensure that your tight iteration loop doesn't pull unnecessary bytes into your cache, maximizing the "density" of your memory fetches.

Alignment Considerations

Remember that Rust's compiler may reorder fields to satisfy alignment requirements. However, within those constraints, you retain control. By grouping your primary access targets together, you minimize the risk of "false sharing" or cache line splitting, allowing the CPU’s prefetcher to do its job more effectively.

Key Takeaway: Group your hot, frequently accessed fields at the beginning of your structs to ensure they occupy the same cache line and reduce memory latency.