개요:
- False Sharing: 서로 다른 스레드가 독립적으로 접근하는 데이터가 같은 CPU 캐시 라인(cache line)을 공유할 때 발생하는 성능 저하 현상. 실제로는 공유되지 않는 데이터인데 캐시 일관성(coherence) 메커니즘 때문에 불필요한 캐시 무효화(invalidation)와 캐시 라인 이동이 발생한다.
원인(요지):
- CPU는 메모리를 캐시 라인 단위(일반적으로 64바이트)로 읽고 쓴다.
- 서로 다른 스레드가 동일한 캐시 라인 내 서로 다른 변수(예: 서로 다른 인덱스의 카운터)를 빈번히 쓰면, 캐시 일관성 프로토콜이 라인을 다른 코어로 이동시키며 쓰기 성능을 크게 떨어뜨린다.
증상 및 영향:
- 병렬 속도 확장(스케일링) 미달성.
- 컨텍스트에서 높은 캐시 전송량, 높은 LLC 또는 L1 캐시 미스가 관찰됨.
- 원인 코드는 보통 짧은(작은) 데이터 구조의 배열에서 자주 발생함(예: 여러 스레드가 인접한 카운터를 업데이트).
탐지 방법:
- 성능 프로파일러 사용:
perf (Linux), Intel VTune, Linux perf stat의 cache-misses/L1-dcache-loads/mem_load_uops_retired 등.
- 증거: 스레드 수 증가에 따라 CPU 사용률은 높지만 처리량은 증가하지 않거나 떨어짐; 캐시-코herence 관련 이벤트(심한 ICACHE/라인 전송) 증가.
완화 기법(요약):
- 캐시 라인 분리: 변수 사이에 패딩을 넣어 같은 캐시 라인을 쓰지 않게 함. 예:
alignas(64) 또는 char pad[64].
- 구조 재배열: 자주 쓰는 필드를 서로 떨어뜨리거나, 읽기 전용과 쓰기 전용 필드를 분리.
- 스레드 로컬 데이터: 가능한 경우
thread_local 또는 각 스레드 전용 버퍼 사용.
- 배치 업데이트: 빈번한 업데이트를 로컬에서 배치한 뒤 드물게 합침(aggregation).
- 적절한 동기화 원자성 사용: 필요하다면
std::atomic을 사용하지만, 원자 변수도 같은 캐시 라인을 공유하면 False Sharing 발생.
- 캐시라인 친화적 할당: 캐시라인 경계를 고려한 메모리 정렬/할당기 사용.
- 알고리즘 변경: 경쟁을 줄이는 알고리즘(예: sharding, work-stealing with local queues).