1. 개요
| 루프라인 모델 Roofline Model | |
|---|---|
| 핵심 식 | |
| 가로축 | 연산 강도 [flop/byte], 로그 눈금 |
| 세로축 | 달성 가능 성능 [flop/s], 로그 눈금 |
| 능선점 | |
| 제안 | 윌리엄스·워터먼·패터슨 (2009) |
| 측정 도구 | STREAM, ERT, Intel Advisor, Nsight Compute, LIKWID |
“이 커널, 몇 %까지 빨라질 수 있어요?” — 이 질문에 그래프 한 장으로 답하는 법.
루프라인 모델(roofline model)은 어떤 계산 커널이 한 기계에서 낼 수 있는 성능의 상한을 “부동소수점 연산 피크”와 “메모리 대역폭 × 연산 강도” 중 작은 쪽으로 잡는 성능 모델이다. 2009년 버클리의 새뮤얼 윌리엄스·앤드루 워터먼·데이비드 패터슨이 멀티코어 시대의 성능 분석 도구로 제안했다. 로그-로그 축에 그리면 비스듬한 대역폭 경사와 수평 연산 천장이 만나 지붕 모양이 되므로 이 이름이 붙었다.
모델이 하는 일은 딱 하나다. 커널을 지붕 아래 한 점으로 찍고, 그 점 위 지붕이 경사면이면 메모리가, 평지면 연산 유닛이 병목이라고 알려 준다. 정확한 실행 시간을 예측하는 모델이 아니라 “어느 쪽을 최적화해야 하는가”를 알려 주는 진단 도구다. GPU 컴퓨팅 문서가 이 그림을 한 문단으로 소개했고, BLAS 문서는 레벨 1·2·3의 연산 강도를 실측했다. 이 문서는 모델 자체, 즉 식·능선점·천장·계층 루프라인과 대표 시뮬레이션 커널의 위치를 다룬다.
2. 식과 그림
커널이 번의 부동소수점 연산을 하면서 주메모리와 바이트를 주고받는다고 하자. 연산 강도(arithmetic intensity)는
이다. 기계의 연산 피크를 [flop/s], 지속 가능한 메모리 대역폭을 [byte/s] 라 하면, 실행 시간은 와 중 큰 쪽보다 짧을 수 없다. 연산과 전송이 완벽히 겹친다는 낙관적 가정 아래 성능 상한은
이다. 로그 축에서 는 기울기 1인 직선이고, 는 수평선이다. 둘이 만나는 점
을 능선점(ridge point)이라 한다. 인 커널은 메모리 한계(memory-bound), 는 연산 한계(compute-bound)다. 능선점은 그 기계에서 “피크를 볼 자격”을 얻기 위해 바이트당 해야 하는 최소 연산 수이고, 세대가 바뀔수록 오른쪽으로 밀려 왔다. 연산 유닛은 SIMD 폭과 코어 수로 늘리기 쉽지만 핀 수와 전력에 묶인 대역폭은 그만큼 못 따라가기 때문이다.1
예를 들어 NVIDIA A100(40 GB)의 공개 사양은 텐서 코어를 쓰지 않는 배정밀도 피크 9.7 TFLOP/s, HBM2 대역폭 1555 GB/s 이므로 flop/byte 다. 바이트당 6번 넘게 계산하지 않는 커널은 이 GPU 의 연산 유닛을 다 쓸 수 없다는 뜻이다.
3. 대표 커널은 어디에 찍히나
아래 표는 배정밀도(8 바이트) 기준의 이상적 연산 강도다. 캐시가 재사용을 완벽히 잡아 주고, 각 배열은 주메모리에서 한 번씩만 읽고 쓴다고 가정했다. 오른쪽 열은 가상의 기계 TFLOP/s, GB/s()에서의 상한이다.
| 커널 | 연산/항목 | 바이트/항목 | 상한 (GFLOP/s) | 피크 대비 | |
|---|---|---|---|---|---|
daxpy | 2 | 24 | 0.083 | 16.7 | 0.8% |
| 내적 | 2 | 16 | 0.125 | 25 | 1.3% |
| CSR 희소 행렬-벡터 곱 (비영 원소당) | 2 | ≥ 12 | ≤ 0.17 | ≤ 33 | ≤ 1.7% |
| 3차원 7점 스텐실 (쓰기 할당 포함) | 8 | 24 | 0.33 | 67 | 3.3% |
| 같은 스텐실 (스트리밍 저장) | 8 | 16 | 0.5 | 100 | 5% |
dgemm (, 이상적) | 2000 | 100% |
몇 가지는 숫자로 짚어 둘 만하다.
- 희소 행렬-벡터 곱은 비영 원소 하나마다 값 8 바이트와 열 인덱스 4 바이트를 읽고 곱셈·덧셈 두 번을 한다. 벡터 접근과 행 포인터를 공짜로 쳐도 이 상한이다. 켤레기울기법 같은 크리로프 솔버의 시간이 대부분 여기서 나가므로, 이 계열 솔버는 피크의 몇 % 이상을 원리적으로 낼 수 없다. 이게 “솔버를 GPU 로 옮겼더니 대역폭 비율만큼 빨라졌다”는 흔한 보고의 정체다.
- 스텐실의 24 바이트는 읽기 8 + 쓰기 8 + 쓰기 할당(write-allocate) 8 이다. 대부분의 CPU 캐시는 쓰기 전에 그 캐시 라인을 먼저 읽어 오므로, 결과 배열을 쓰는 데도 읽기 트래픽이 한 번 더 붙는다. 비시간적(non-temporal) 저장 명령으로 이걸 없애면 강도가 1.5배가 된다. 코드 한 줄 안 바꾸고 상한이 50% 오른다.
- 격자 볼츠만(격자 볼츠만 방법) D3Q19 배정밀도는 격자점당 분포 19개를 읽고 19개를 쓰므로, 쓰기 할당까지 치면 바이트를 옮긴다. 충돌 연산이 대략 200 플롭 안팎이라 대의 전형적인 메모리 한계 커널이다. 그래서 LBM 코드의 성능은 보통 flop/s 가 아니라 MLUPS(초당 백만 격자점 갱신)로 보고하고, 상한은 그냥 이다. 위 가상 기계면 , 즉 약 440 MLUPS 가 천장이다.
dgemm은 블록을 캐시에 올려 재사용하면 강도가 블록 크기에 비례해 커지므로 능선점을 쉽게 넘는다. 이 대목은 행렬 곱셈과 BLAS가 자세히 다룬다.
정리하면 CFD·구조해석 시뮬레이션의 주력 커널 대부분은 능선점 왼쪽에 있다. 이런 코드에서 “피크 대비 3%“는 부끄러운 숫자가 아니라 대역폭을 다 쓴 숫자일 수 있다. 피크 대비 %가 아니라 **해당 지붕 대비 %**로 보고해야 하는 이유다.
4. 천장을 여러 겹 — 낮은 지붕들
실제 그림에는 지붕이 하나가 아니다. 원 논문부터 천장(ceiling)을 여러 겹 그렸다. 피크는 모든 최적화가 다 들어간 이상치이고, 하나라도 빠지면 더 낮은 수평선이 실질 지붕이 된다.
- SIMD 를 안 쓰면: SIMD 폭만큼 나눈 천장. AVX-512 배정밀도면 1/8.
- FMA 를 안 쓰면: 곱셈과 덧셈을 따로 발행하므로 1/2.
- 곱셈·덧셈 균형이 안 맞으면: 덧셈만 잔뜩 있는 커널은 FMA 유닛의 절반만 쓴다.
- 대역폭 쪽 천장: NUMA 노드 하나만 쓰거나 원격 메모리를 읽으면 경사가 아래로 평행이동한다. 하드웨어 프리페처가 못 따라오는 불규칙 접근도 마찬가지다.
커널이 지붕보다 한참 아래 찍혔다면, 그 사이에 있는 천장 중 하나가 실제 원인일 가능성이 높다. 그래서 루프라인은 “더 빨라질 여지가 있는가”와 함께 “어떤 최적화부터 할 것인가”의 순서도 정해 준다. 위로 올리는 손잡이는 벡터화·FMA·스레드이고, 오른쪽으로 미는 손잡이는 재사용을 늘리는 것이다(캐시 블로킹, 시간 블로킹, 커널 융합, 정밀도 축소).
커널 융합의 효과는 표로 바로 보인다. daxpy 두 번(, )을 따로 돌리면 플롭 4번에 48 바이트지만, 한 루프로 합치면 갱신한 를 다시 읽어 올 필요가 없어 읽기 24 + 쓰기 16 = 40 바이트로 줄고, 강도가 0.083 에서 0.1 로 오른다. 융합할 연산이 많을수록(같은 배열을 여러 번 오가는 연산 사슬일수록) 이득이 커진다. 반대로 단정밀도로 내리면 바이트가 반으로 줄어 강도가 두 배가 되는데, 피크도 대개 두 배라 능선점 대비 위치는 그대로다. 메모리 한계 커널에서 정밀도 축소가 거의 정확히 2배를 주는 이유다.
5. 계층 루프라인과 측정
원래 모델은 “주메모리”라는 한 층만 봤다. 그런데 블로킹을 잘한 커널은 DRAM 트래픽이 작아 DRAM 지붕 기준으로는 연산 한계처럼 보이면서도 실제로는 L2 대역폭에서 막혀 있을 수 있다. 그래서 L1·L2·L3·DRAM 마다 대역폭 경사를 따로 그리고, 각 층에서 실제로 오간 바이트로 강도를 따로 계산해 점을 여러 개 찍는 계층 루프라인(hierarchical roofline)을 쓴다. 일리치 등(2014)의 캐시 인지 루프라인(cache-aware roofline)은 반대로 코어 관점에서 모든 층의 트래픽을 합쳐 한 강도로 보는 변형이다. 두 방식은 같은 커널을 다른 위치에 찍으므로, 그림을 볼 때 어느 정의인지 먼저 확인해야 한다.
측정은 두 부분이다.
- 지붕: 사양서 숫자 대신 실측값을 쓴다. 대역폭은 매캘핀의 STREAM 벤치마크(
triad커널)가 사실상 표준이고, NERSC 의 ERT(Empirical Roofline Toolkit)는 층별 대역폭과 피크를 한 번에 잰다. 사양서 대역폭의 70~90% 정도가 실측되는 게 보통이다. - 점: 플롭 수와 바이트 수를 하드웨어 성능 카운터로 센다. CPU 에서는 Intel Advisor 와 LIKWID, NVIDIA GPU 에서는 Nsight Compute 가 루프라인 그림을 직접 그려 준다. 손으로 셀 때는 위 표처럼 “이상적 강도”를 먼저 계산하고, 카운터로 잰 실제 바이트가 그보다 얼마나 많은지(캐시 미스로 인한 초과 트래픽)를 비교하는 것이 가장 유익하다.
6. 한계 — 지붕이 다 말해 주지는 않는다
- 겹침 가정: 연산과 전송이 완전히 겹친다고 보므로 능선점 근처에서는 실제 성능이 두 직선의 꺾인 모서리보다 꽤 아래로 둥글게 내려앉는다.
- 지연 한계: 연결 리스트 추적이나 간접 참조가 많은 커널은 대역폭이 아니라 메모리 지연과 동시 요청 수에 묶인다. 이건 루프라인에 안 보인다. 희소 행렬의 벡터 랜덤 접근이 대표적이다.
- 코어 내부 병목: 명령 발행 폭, 레지스터 압박, 분기 예측 실패, 나눗셈·제곱근 같은 긴 지연 연산은 별도 천장으로 넣지 않으면 보이지 않는다. 캐시 층 사이의 전송 시간을 더하는 방식으로 이를 정교화한 것이 하거·트라이비히 쪽의 ECM 모델(Execution-Cache-Memory)이다.
- 병렬 확장: 코어를 늘리면 연산 피크는 선형으로 늘지만 대역폭은 소켓 몇 개 코어에서 포화된다. 메모리 한계 커널이 코어 8개쯤에서 스케일링이 멈추는 현상은 루프라인으로 바로 설명된다.2
그래도 이 모델이 15년 넘게 살아남은 이유는 분명하다. 계산 하나와 측정 두 개로, 몇 주짜리 최적화에 착수할지 말지를 정해 준다. “이미 지붕에 닿았다”는 판정은 그 자체로 엄청난 시간 절약이다.3
7. 관련 문서
- GPU 컴퓨팅 · 병렬 컴퓨팅 · SIMD · MPI
- BLAS · 행렬 곱셈 · LAPACK · 희소행렬
- 격자 볼츠만 방법 · 유한차분법 · 켤레기울기법
- 스텐실 연산 · 메모리 계층 · ECM 모델
8. Footnotes
이 문서의 주요 출처
- S. Williams, A. Waterman, D. Patterson (2009), Roofline: an insightful visual performance model for multicore architectures, Communications of the ACM 52(4), 65-76
- A. Ilic, F. Pratas, L. Sousa (2014), Cache-aware Roofline model: Upgrading the loft, IEEE Computer Architecture Letters 13(1), 21-24
- J. D. McCalpin, STREAM: Sustainable Memory Bandwidth in High Performance Computers
- NERSC — Roofline Performance Model (Empirical Roofline Toolkit 안내)
의견을 반영할게요. 감사합니다.