gpumode · 강의 아카이브
《GPU Mode》 L024 Scan at the Speed of Light High priority transcript · 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 세 알고리즘을 비교하게 만드는지의 학습 노트.

speed-of-light decoupled lookback single-pass scan CUB · cccl memcpy bound reduce-then-scan hierarchical stream serialization
J
Speakers
Jake Hemstad & Georgii Evtushenko
NVIDIA · CCCL (CUB / Thrust / libcudacxx) maintainers
강의 번호
L024
스피커
Hemstad · Evtushenko
학습 우선순위
High · 정독
다시 볼 때
CUB scan source 까기
§ 01강의가 풀려는 문제· absolute speed

“같은 알고리즘을 더 빠르게” 가 아니라 — “이론적 한계까지”

Jake 와 Georgii 의 강의는 L021 가 끝난 자리에서 출발한다. multi-block scan 이 동작하긴 하는데 — peak 의 절반도 안 나온다. 왜? 어떻게 더 짜낼 수 있는가? 이론적 한계는 어디인가?

강의가 깐 큰 질문 세 개.

  1. “빠르다” 의 절대 기준 — speed-of-light. Nvidia 가 내부적으로 쓰는 분석 frame. 이건 § 02 의 본론.
  2. scan 의 SoL 이 정확히 무엇인가 — input 한 번 read, output 한 번 write 의 memcpy. 그것보다 빠를 수는 없다(§ 03).
  3. 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. 두 종류가 있다.

알고리즘이 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 를 더한다”.

  1. pass 1: 각 block 이 자기 segment 의 sum 만 계산 (intermediate 저장 안 함). N read.
  2. pass 2: 작은 array 의 sum 들의 scan (작아서 무시).
  3. 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, 다시 읽어서 더한다.

  1. launch 1: 각 block scan. N read + N write (intermediate scan 결과 저장).
  2. launch 2: partial sum array 의 scan (작아서 무시).
  3. 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

  1. local sum — 자기 segment 합 계산. flag = A, sum publish.
  2. lookback — 자기 앞 block 들을 거꾸로 본다. 각 block 의 flag 가:
    • X → spin (아직 안 끝났다)
    • A → 그 sum 을 받아서 누적, 더 앞으로 lookback
    • P → 그 prefix 를 받아서 멈춤
  3. publish prefix — 자기 prefix sum 결정. flag = P, prefix publish.
  4. 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 같은 라이브러리가 그걸 호출.

// CUB DeviceScan — 한 줄
size_t temp_bytes = 0;
cub::DeviceScan::ExclusiveSum(
    nullptr, temp_bytes, d_in, d_out, n);

void* d_temp;
cudaMalloc(&d_temp, temp_bytes);

cub::DeviceScan::ExclusiveSum(
    d_temp, temp_bytes, d_in, d_out, n);
// 내부적으로 decoupled lookback — ~95% SoL
CCCL
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 (요약)
§ 10기억할 메모와 코드 자료· key takeaways
SoL = peak / minimum work
알고리즘의 절대 척도. memory-bound 면 minimum 트래픽 / HBM, compute-bound 면 minimum FLOPs / peak FLOPS.
scan 의 SoL = memcpy
2N read+write. 더 빠를 수는 없다. 그게 알고리즘 평가의 기준선.
알고리즘 선택이 상한 결정
hierarchical 50%, reduce-then-scan 67%, decoupled lookback 95%. 코드 최적화는 그 상한 안에서만.
stream scan 의 함정
메모리는 적게 쓰지만 직렬화로 parallelism 0. 단순 메모리 트래픽 분석이 만능 아님.
decoupled lookback 의 X·A·P
3 상태 flag 로 block 간 통신. local sum publish → lookback → prefix publish. 한 launch 안에 전부.
CUB DeviceScan
production 구현. cub::DeviceScan::ExclusiveSum 한 줄. 직접 짤 필요 없음. ~95% SoL.
CCCL 의 layer
Thrust (high-level) → CUB (block/warp/device) → libcudacxx (atomic/std). 한 repo, layered API.
SoL 의 %
발표/문서에서 “2× speedup” 보다 “SoL 의 X%” 가 더 정확. 절대 척도이기 때문.

손에 새기기 — 실습 시퀀스

  1. memcpy 시간 측정 — 1 GB array 의 cudaMemcpy 시간을 측정해 자기 GPU 의 “SoL ground truth” 를 얻는다. theoretical (size/HBM) 와 비교.
  2. hierarchical scan 직접 짜고 SoL 비교L021 의 3 launch scan 을 짜고 1GB 에서 측정. 결과가 SoL 의 50% 근처인지.
  3. CUB DeviceScan 측정 — 같은 1GB 에서 cub::DeviceScan::ExclusiveSum 시간 측정. memcpy 의 몇 % 인지.
  4. decoupled lookback 직접 짜기 — atomic 으로 X/A/P 상태 publish, 다른 block 이 spin. 작동하는 데까지만이라도 — 미묘함을 손에 박기.
  5. NCU 의 “speed of light” section — NCU 의 첫 번째 표가 정확히 이 강의의 frame. 자기 kernel 의 “SOL Memory %, SOL Compute %” 를 직접 본다.
  6. 다른 algorithm 도 SoL 분석 — reduction, sort, transpose 의 SoL 을 같은 방식으로 계산해본다. CUB 의 해당 알고리즘이 몇 % 인지 확인.
  7. multi-pass vs single-pass — 같은 reduce-by-key 같은 알고리즘을 multi-pass 와 single-pass 로 짜고 SoL 차이 확인.
§ 12열린 질문· open questions
  • SoL % 의 정확한 측정값 — § 09 의 50/67/95% 는 강의 narrative 의 개념적 값. CUB README 와 official benchmark 의 정확한 수치 확인 필요(확인 필요).
  • decoupled lookback 의 atomic 비용 — X/A/P flag publish 가 정확히 얼마의 latency 를 추가하는지. 강의에서 명시 안 됨.
  • large element-size scan — element 가 큰 struct 일 때 (예: 64 byte) memory 트래픽 모델이 같이 변하는지.
  • variable-length / segmented scan — segment 가 dynamic 한 경우의 SoL. 강의에서 다루지 않음.
  • multi-GPU scan — NVLink 위 SoL 분석은 별도 강의 영역.
  • floating-point associativity — decoupled lookback 의 누적 순서가 reduce-then-scan 과 다르므로 round-off 차이가 다를 수 있음.
검증 메모

이 노트의 SoL % 그래프는 강의의 메시지를 재구성한 개념도. 정확한 수치는 CUB benchmark suite 와 NCU 의 SoL section 으로 직접 측정해야 한다.

← Lecture 023 Tensor Cores · CUTLASS · CuTe Lecture 025 → Speaking Composable Kernel (CK) — AMD 의 CUTLASS-equivalent