《GPU Mode》L024Scan at the Speed of LightHigh prioritytranscript · available
Scan at the Speed of Light
L020/L021 의 multi-block scan 을 한 단계 더 — memcpy 와 같은 시간으로 scan 을 끝낸다. NVIDIA CCCL 의 Jake Hemstad 와 Georgii Evtushenko 가 보여주는 “speed-of-light analysis” 의 frame, 그리고 그 분석이 어떻게 reduce-then-scan, hierarchical, decoupled lookback 세 알고리즘을 비교하게 만드는지의 학습 노트.
Jake 와 Georgii 의 강의는 L021 가 끝난 자리에서 출발한다. multi-block scan 이 동작하긴 하는데 — peak 의 절반도 안 나온다. 왜? 어떻게 더 짜낼 수 있는가? 이론적 한계는 어디인가?
강의가 깐 큰 질문 세 개.
“빠르다” 의 절대 기준 — speed-of-light. Nvidia 가 내부적으로 쓰는 분석 frame. 이건 § 02 의 본론.
scan 의 SoL 이 정확히 무엇인가 — input 한 번 read, output 한 번 write 의 memcpy. 그것보다 빠를 수는 없다(§ 03).
3 알고리즘의 상한이 SoL 의 몇 % 인가 — reduce-then-scan ~50%, hierarchical ~50%, stream ~2%, decoupled lookback ~95%. 이 분석이 알고리즘 선택의 frame(§ 04–07).
강의의 인지적 frame
“speed-of-light” 는 hardware 의 절대 한계 (HBM bandwidth, memcpy 시간) 에 의해 결정되는 산수. 이 frame 의 큰 장점 — “우리 알고리즘이 90% 도달” 이라고 말하는 게 “2× 빨라졌다” 보다 훨씬 의미 있다. 절대 척도이기 때문.
“at NVIDIA we rarely use speed-up. We identify the theoretical peak for the algorithm — speed of light — and evaluate against it.”Georgii Evtushenko (요약)
§ 02speed-of-light 분석· peak 의 기준
“이 알고리즘의 이론적 최단 시간은?” 의 산수
SoL 의 정의 — 알고리즘이 반드시 해야 하는 minimum work / hardware 의 peak throughput. 두 종류가 있다.
compute-bound SoL — 알고리즘의 산술 양 (FLOPs) ÷ peak FLOPS. matmul 같은 algorithm.
memory-bound SoL — 알고리즘의 minimum 메모리 트래픽 (byte) ÷ HBM bandwidth. scan, copy, reduction 같은 algorithm.
알고리즘이 inherently memory-bound 이면 (예: scan), “반드시 read 해야 하는 byte 수 + 반드시 write 해야 하는 byte 수” ÷ HBM 가 SoL 시간의 하한.
왜 “speedup” 이 위험한 단어인가
알고리즘 A 가 B 보다 2× 빠르다 — 그게 좋은가? 둘 다 SoL 의 1% 면 의미가 작다. SoL 의 50% 와 95% 의 차이는 “두 배” 지만, 그건 절대값이 의미 있는 자리. “우리는 SoL 의 X% 다” 가 더 정확한 표현.
§ 03scan 의 SoL = memcpy· 왜 그게 한계인가
scan 은 한 번 read + 한 번 write 만으로 끝낼 수 있는 알고리즘
scan 의 minimum memory 트래픽 — input N 을 한 번 읽고, output N 을 한 번 쓴다. 총 2N memory operation. 산술은 byte 수보다 훨씬 작아 무시 가능. scan 의 SoL = 2N / HBM bandwidth.
그리고 이건 정확히 memcpy 의 시간. memcpy 도 N byte read + N byte write. 같은 시간.
결정적 통찰
“scan 을 memcpy 와 같은 시간으로 끝낼 수 있는가?” — Yes. 알고리즘이 input 을 한 번만 통과하면서 output 을 한 번만 쓰면. 그게 single-pass scan + decoupled lookback 의 약속(§ 07).
“speed of light for prefix sum should essentially match the performance of memcpy.”Georgii Evtushenko (요약)
§ 04reduce-then-scan· N memory access × 4
알고리즘 ①: 한 번 reduce, 한 번 scan — input 을 두 번 통과
가장 단순한 multi-block scan 의 한 형태. “각 block 의 sum 을 먼저 다 구한다 — 그 sum 들의 prefix 를 구한다 — block 을 다시 통과하면서 prefix 를 더한다”.
pass 1: 각 block 이 자기 segment 의 sum 만 계산 (intermediate 저장 안 함). N read.
pass 2: 작은 array 의 sum 들의 scan (작아서 무시).
pass 3: 각 block 이 자기 segment 다시 통과 — prefix 받아서 scan + write. N read + N write.
총 메모리 트래픽 — 2N read + N write = 3N. SoL 의 2N 대비 67%. 최선 ~67% SoL.
trade-off
장점 — block 간 동기화가 단순 (kernel launch 가 barrier). 단점 — input 을 한 번 더 read. memory bandwidth 의 한 배가 그냥 낭비.
§ 05hierarchical (3 launch)· N × 4 — 50% SoL 한계
알고리즘 ②: L021 의 표준 패턴 — input 두 번 read, output 두 번 write
L021 의 multi-block scan. block 별 scan 결과를 일단 메모리에 적었다, partial sum 을 또 scan, 다시 읽어서 더한다.
launch 1: 각 block scan. N read + N write (intermediate scan 결과 저장).
launch 2: partial sum array 의 scan (작아서 무시).
launch 3: 각 block 의 prefix add. N read + N write.
총 — 2N read + 2N write = 4N. SoL 2N 대비 50%. 강의의 figure 가 이걸 정확히 보여줌 — “이 알고리즘은 이론적으로 50% 가 한계”.
강의의 큰 메시지
아무리 잘 짜도 50% 를 못 넘는다. 알고리즘 선택이 hardware-tier 성능의 상한을 결정. 같은 알고리즘 안에서 코드 최적화는 그 상한 안에서만 의미가 있다. 진짜 더 빠르려면 — 알고리즘을 바꿔야 한다.
§ 06stream/chained scan· 왜 직렬화로 떨어지는가
알고리즘 ③: input 한 번만 — 그런데 block 들이 직렬화
Naive 한 single-pass 시도. 한 kernel 안에서 block 0 이 자기 prefix 를 다 만들고, block 1 이 그 prefix 를 받아서 자기 것 만들고, … 직렬로. 메모리는 2N (read + write 각 한 번).
이론상 SoL 100%. 그런데 실제 측정 — SoL 의 2% 미만. 왜?
stream serialization
block N 이 block N-1 의 결과를 기다리는 동안 — 모든 다른 block 도 idle. 한 번에 한 block 만 진행. GPU 의 수천 개 thread 가 1 thread 만큼만 활성. parallelism 이 0 으로 무너진다.
이게 강의의 가장 큰 통찰 중 하나 — “단순히 메모리 트래픽이 적은 알고리즘이 빠르지 않다”. parallelism 도 같이 봐야 한다. SoL 분석이 만능은 아니라는 자리.
§ 07decoupled lookback· 한 launch · X·A·P
알고리즘 ④: input 한 번 통과, block 들 동시 진행, prefix 만 직렬
stream scan 의 trick — “block 들이 자기 sum 을 빨리 publish 한 뒤, 다른 일을 하면서 prefix 를 기다린다”. NVIDIA 가 발표한 single-pass scan 의 핵심.
각 block 의 한 “status flag” — 세 상태.
X · invalid아직 자기 segment 처리 시작 안 함. 다른 block 이 보면 — 무시 (계속 더 앞 block 을 본다).초기 상태
A · aggregate자기 segment 의 sum 계산 완료. publish. 자기 prefix sum 은 아직 모름. 다른 block 이 보면 — 그 block 이 “이 sum 을 받아서 더 앞으로 가자” 라고 결정.중간 상태
P · prefix자기 prefix sum 도 결정됨. publish. 다른 block 이 보면 — “여기까지가 답이다, 이제 lookback 멈추고 자기 일 시작”.완료 상태
한 block 의 한 round
local sum — 자기 segment 합 계산. flag = A, sum publish.
lookback — 자기 앞 block 들을 거꾸로 본다. 각 block 의 flag 가:
X → spin (아직 안 끝났다)
A → 그 sum 을 받아서 누적, 더 앞으로 lookback
P → 그 prefix 를 받아서 멈춤
publish prefix — 자기 prefix sum 결정. flag = P, prefix publish.
local scan + write — 자기 segment 에 prefix 를 더해 출력 write.
왜 “decoupled” 인가
모든 block 이 step 1 (local sum) 을 동시에 시작. step 2 (lookback) 만 제한적으로 직렬화 — 그것도 평균적으로 한두 block 만 거꾸로 본다 (대부분 곧 P 를 만나니까). parallelism 이 거의 안 깎임. 메모리 트래픽은 정확히 2N (input read + output write). SoL 의 ~95% 도달.
“decoupled lookback 은 parallelism 을 잃지 않으면서 single-pass 를 한다 — scan 의 SoL 한계를 처음으로 90% 이상 도달한 알고리즘이다.”Jake Hemstad (요약)
§ 08CCCL · CUB · Thrust 안의 구현· DeviceScan 의 내부
“그래서 이걸 직접 짤 필요는 없다” — production 라이브러리
강의의 실용적 메시지. “decoupled lookback 을 직접 짜면 두 달 걸린다 — 이미 CUB 안에 있다.” Thrust 의 thrust::inclusive_scan / thrust::exclusive_scan, CUB 의 cub::DeviceScan::ExclusiveSum 같은 라이브러리가 그걸 호출.
Cuda Core Compute Libraries — CUB, Thrust, libcudacxx 의 통합 우산. 한 repo. C++ standard 호환 algorithm 들의 GPU 버전.
CUB
low-level building block. BlockScan, WarpScan, DeviceScan 의 layered abstraction. 라이브러리 작성자용.
Thrust
STL-like API. thrust::inclusive_scan 같은 high-level interface. 사용자용. 내부적으로 CUB 호출.
libcudacxx
cuda::std::* 의 GPU-host 양쪽 호환 C++ standard 라이브러리. atomic, memory_resource 등.
§ 09production benchmark· ~95% SoL 의 검증
네 알고리즘의 SoL 비율 — 한 그래프로
FIG · scan 알고리즘들의 SoL 비율이론 한계 + 실측
알고리즘peak SoL (memcpy 대비)비고
stream / chained scan~2%
hierarchical (3 launch)~50%
reduce-then-scan~67%
decoupled lookback (CUB)~95%
memcpy (이론 SoL)100%
% 는 강의의 narrative 와 표준 NVIDIA benchmark 를 재구성한 개념적 값(확인 필요). 핵심 — 알고리즘 선택이 상한선을 결정. CUB 의 95% 는 같은 hardware 에서 hierarchical 의 90% 가 아니라 “scan 자체의 한계인 memcpy 의 95%”.
강의의 마지막 메시지 — 자기 알고리즘을 평가할 때 “이게 SoL 의 몇 % 인가” 의 frame 을 항상 머리에 두기. 그리고 그 % 가 알고리즘 자체의 한계인지, 구현의 한계인지 분리해 보기.
“if your benchmark says ‘our kernel is 90% SoL’, that's a real claim — speedup numbers without context can mislead.”Jake Hemstad (요약)