false sharing cache

**False Sharing** is the **insidious parallel performance pathology where two or more threads on different cores modify independent variables that happen to reside on the same cache line — causing the hardware cache coherence protocol to repeatedly invalidate and reload the entire cache line across cores, creating catastrophic cache line "ping-pong" that can slow down parallel code by 10-100x despite the threads sharing no logical data**. **How False Sharing Occurs** CPU caches operate on cache lines (typically 64 bytes). When Thread 0 on Core 0 writes variable A and Thread 1 on Core 1 writes variable B, and A and B are within the same 64-byte cache line, the coherence protocol (MESI/MOESI) invalidates Core 1's copy when Core 0 writes, and vice versa. Each write forces the other core to fetch the updated cache line from the L3 cache or the writing core's L1 — a round trip of 40-100 cycles per access instead of 3-4 cycles for a local L1 hit. **Classic Example** ```c int counters[NUM_THREADS]; // Adjacent in memory! void work(int tid) { for (int i = 0; i < 1000000; i++) counters[tid]++; // Each thread increments its own counter } ``` `counters[0]` through `counters[15]` all live in a single 64-byte cache line. Despite each thread modifying only its own counter, every increment invalidates the line for all other cores. Performance: 10-50x slower than the single-threaded case. **Detection** - **Performance Counters**: High L1/L2 coherence miss rate (HITM events on Intel) despite non-shared data. Linux `perf c2c` specifically detects false sharing. - **Profiling Tools**: Intel VTune's memory access analysis highlights cache lines experiencing excessive coherence traffic. **Solutions** 1. **Padding**: Insert unused bytes between variables to place them on separate cache lines: ```c struct PaddedCounter { int value; char padding[60]; // Ensure each counter occupies its own 64-byte line }; PaddedCounter counters[NUM_THREADS]; ``` 2. **Alignment**: Use compiler attributes (`alignas(64)` in C++11, `__attribute__((aligned(64)))` in GCC) to force cache line alignment. 3. **Thread-Local Accumulation**: Each thread accumulates into a local variable (register), writing to the shared array only once at the end. 4. **Data Structure Redesign**: Replace arrays of per-thread values with per-thread structures spaced at cache line boundaries. Many parallel libraries (Intel TBB, Java `@Contended`) provide padded per-thread containers. False Sharing is **the performance trap that punishes the illusion of independence** — threads that believe they are working on private data are secretly fighting over cache lines, and the hardware coherence protocol silently converts what should be embarrassingly parallel code into a serialized disaster.

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account