[2026] C++ Cache Optimization: Locality, False Sharing, SoA vs AoS

[2026] C++ Cache Optimization: Locality, False Sharing, SoA vs AoS

이 글의 핵심

Improve CPU cache efficiency in C++: spatial locality, matrix layout, struct packing, prefetching, blocking, false sharing, and alignment for SIMD.

What is cache optimization?

Improving how well your code uses the CPU cache hierarchy. 아래 코드는 cpp를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Many cache misses (column-major stride in row storage)
for (int j = 0; j < cols; ++j) {
    for (int i = 0; i < rows; ++i) {
        sum += matrix[i][j];
    }
}
// ✅ Better spatial locality (row-major scan)
for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < cols; ++j) {
        sum += matrix[i][j];
    }
}

Spatial locality

아래 코드는 cpp를 사용한 구현 예제입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

std::vector<int> v(1000);
// ✅ Sequential access
for (int i = 0; i < v.size(); ++i) {
    process(v[i]);
}
// ❌ Random access pattern
for (int i = 0; i < v.size(); ++i) {
    process(v[rand() % v.size()]);
}

Examples

Example 1: Matrix multiply

다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Cache-unfriendly (strided access into B)
void matmul_slow(int** A, int** B, int** C, int n) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}
// ✅ Better with transposed B for sequential reads
void matmul_fast(int** A, int** B, int** C, int n) {
    int** BT = transpose(B, n);
    
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                C[i][j] += A[i][k] * BT[j][k];
            }
        }
    }
}

Example 2: Struct layout

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Padding / cache-line waste
struct Bad {
    char a;
    int b;
    char c;
    long d;
};
// ✅ Tighter packing (example; align to your ABI needs)
struct Good {
    long d;
    int b;
    char a;
    char c;
};

Example 3: Prefetching

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <xmmintrin.h>
void processWithPrefetch(int* data, int n) {
    constexpr int prefetchDistance = 64;
    
    for (int i = 0; i < n; ++i) {
        if (i + prefetchDistance < n) {
            _mm_prefetch(&data[i + prefetchDistance], _MM_HINT_T0);
        }
        process(data[i]);
    }
}

Example 4: Blocked (tiled) multiply

다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

void matmul_blocked(int** A, int** B, int** C, int n, int blockSize) {
    for (int i = 0; i < n; i += blockSize) {
        for (int j = 0; j < n; j += blockSize) {
            for (int k = 0; k < n; k += blockSize) {
                for (int ii = i; ii < std::min(i + blockSize, n); ++ii) {
                    for (int jj = j; jj < std::min(j + blockSize, n); ++jj) {
                        for (int kk = k; kk < std::min(k + blockSize, n); ++kk) {
                            C[ii][jj] += A[ii][kk] * B[kk][jj];
                        }
                    }
                }
            }
        }
    }
}

Cache lines

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

constexpr size_t CACHE_LINE_SIZE = 64;
alignas(CACHE_LINE_SIZE) int data[16];
struct alignas(CACHE_LINE_SIZE) Counter {
    std::atomic<int> value{0};
};

Common pitfalls

Pitfall 1: False sharing

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ❌ false sharing
std::atomic<int> counters[4];
// ✅ pad to separate cache lines
struct alignas(64) PaddedCounter {
    std::atomic<int> value{0};
};
PaddedCounter counters[4];

Pitfall 2: Large stride

for (int i = 0; i < n; i += 1000) {
    process(data[i]);
}

Pitfall 3: AoS vs SoA

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ AoS: may scatter hot fields
struct Particle {
    float x, y, z;
    float vx, vy, vz;
};
std::vector<Particle> particles;
// ✅ SoA: sequential access per field
struct Particles {
    std::vector<float> x, y, z;
    std::vector<float> vx, vy, vz;
};

Pitfall 4: Alignment for SIMD

float* alignedData = (float*)aligned_alloc(32, 100 * sizeof(float));
__m256 v = _mm256_load_ps(alignedData);

FAQ

Q1: Cache optimization?

A: Making memory access patterns friendlier to CPU caches.

Q2: Spatial locality?

A: Accessing nearby addresses in sequence.

Q3: False sharing?

A: Independent variables on the same cache line; use padding or per-line layout.

Q4: AoS vs SoA?

A: AoS is array of structs; SoA is struct of arrays—often better for SIMD and sequential field access.

Q5: Prefetching?

A: Hint loads ahead of use to hide latency.

Q6: Resources?

A: Computer Architecture, Optimized C++, What Every Programmer Should Know About Memory.

See also

Practical tips

Debugging

  • Fix warnings first
  • Reproduce with small tests

Performance

  • Profile before optimizing
  • Set measurable goals

Code review

  • Follow conventions

Checklist

Before coding

  • Right technique?
  • Maintainable?
  • Meets performance goals?

While coding

  • Warnings cleared?
  • Edge cases?
  • Errors handled?

At review

  • Intent clear?
  • Tests enough?
  • Docs OK?

Keywords

C++, cache, optimization, performance, memory, false sharing, locality.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3