[TIL] 프리페처(prefetcher) — 지연을 대역폭으로 바꾸는 기술
1️⃣ 왜 중요한가
CPU는 연산보다 메모리 접근이 훨씬 느리다. 결국 병목은 연산이 아니라 데이터를 언제 가져오느냐에서 생긴다.
프리페처(prefetcher)는 바로 그 타이밍을 다룬다. 곧 사용할 데이터를 미리 캐시로 가져와, 실제 접근 시 지연을 겹쳐 숨긴다.
핵심은 언제 가져오느냐이다. 너무 이르면 낭비고, 너무 늦으면 아무 의미 없다.
2️⃣ 어떻게 동작하나
프리페처는 접근 패턴을 관찰해서 다음을 예측한다. 대표적인 세 가지 방식이 있다.
- Next-line : 바로 다음 라인을 가져온다.
- Stride : 일정 간격(ΔL)으로 접근하는 패턴을 학습한다.
- Streamer : 긴 연속 접근을 여러 라인 선행(prefetch degree)으로 당긴다.
CPU는 상황에 따라 거리(distance)와 차수(degree)를 조절하고, 효율이 떨어진다고 판단되면 자동으로 세기를 줄이거나 멈춘다. 즉, 프리페처도 일종의 피드백 제어 시스템이다.
3️⃣ 잘 먹히는 패턴 vs 깨지는 패턴
잘 먹히는 패턴은 단순하다. 연속 접근, 작은 stride, 캐시 안에서 순차적으로 훑는 루프. 이 세 가지면 웬만해선 잘 맞는다.
반대로 깨지는 패턴은 명확하다. stride가 크거나 불규칙하고, 페이지 경계를 자주 넘거나, 캐시 충돌이 잦은 경우다. 이런 패턴은 프리페처가 학습하기 어렵고, 가져와도 금방 쫓겨난다.
4️⃣ HW와 SW 프리페처
하드웨어(HW) 프리페처는 자동으로 패턴을 감지하고,
소프트웨어(SW) 프리페처는 _mm_prefetch() 같은 명령으로 직접 힌트를 준다.
HW는 대부분의 일반 패턴에 잘 작동하고, SW는 하드웨어가 잡지 못하는 특이한 패턴을 다룰 때 쓴다.
최근 CPU들은 두 방식을 함께 사용한다. SW 힌트가 HW 프리페처의 학습을 돕거나, 중복 요청을 줄이기도 한다. 서로 경쟁이 아니라 협력 관계에 가깝다.
5️⃣ 튜닝 포인트
- 루프 순서 조정 – 메모리 연속 축(행)을 안쪽 루프로 둔다.
- stride 줄이기 – ΔL을 작게 유지한다.
- 데이터 구조 재배치 – SoA로 바꾸거나 타일링을 적용한다.
- 필요하면 SW 프리페치 추가 – 적당한 거리 앞에서 호출.
- 측정으로 검증 –
perf, VTune으로 미스율·IPC·프리페치 히트율 확인.
튜닝의 핵심은 복잡한 알고리즘이 아니라 데이터 접근의 연속성이다. 루프 순서 한 줄만 바꿔도 성능이 두 배 가까이 오르는 경우가 많다.
🧩 회고
프리페처는 단순히 미리 가져오는 기능이 아니다. 하드웨어가 데이터를 기다리지 않도록 만드는 타이밍 엔진이다.
결국 성능 최적화는 코드를 하드웨어가 예측하기 쉽게 만드는 일이다. 데이터 구조, 루프 순서, stride. 이 세 가지가 깨끗하게 정리돼야 프리페처가 제 역할을 한다.
이번 정리를 하면서, 성능은 ‘더 복잡하게 짜는 기술’이 아니라 ‘하드웨어가 이해하기 쉬운 코드’를 만드는 감각에서 온다는 걸 다시 느꼈다.