CUDA 18-VOLUME SERIES · CONTENT-FIRST · A4 LANDSCAPE · 18p

Hopper PTX & SASS 단권화

TMA · WGMMA · Cluster · mbarrier · SASS Fundamentals (sm_90 / sm_90a)
Volume V04/18
Tier T1 HW & ISA
선행 V01·V02·V03
용도 Hopper 비동기 ISA 지도

목차

1. Hopper PTX 추가분 개요p.2
2. Thread Block Clusterp.3
3. Distributed Shared Memoryp.4
4. TMA 개념 (descriptor/box dim)p.5
5. TMA PTX (cp.async.bulk.tensor)p.6
6. mbarrier (init/arrive/wait)p.7
7. WGMMA 개요p.8
8. WGMMA shape×dtype 완전표p.9
9. Warp Specializationp.10
10. Async Proxy · Setmaxnregp.11
11. DPX (vimax3/vimin3)p.12
12. SASS란?p.13
13. SASS 핵심 opcodep.14
14. SASS Control Codesp.15
15. Dual Issue · Scoreboardp.16
16. SASS 읽기 실전 가이드p.17
17. Hopper Cheat Sheetp.18

범례

핵심 용어 (노란 배경)
표 헤더 / 매우 중요
정의·공식 박스
예시·워크드 박스
빨강주의·실수·비동기 함정
시험·실무 핵심
(!)니모닉 (첫글자 암기)
다른 권 cross-ref
PTX ↔ SASS 대응
인쇄 설정 · A4 가로 / 여백 없음 / 배경 그래픽 포함 · Ctrl(⌘)+P
PTX ISA 7.x (sm_90a) · GH100 whitepaper · nvdisasm · cuobjdump

1 왜 Hopper가 ISA를 늘렸나 비동기의 정식화

배경 Ampere까지 cp.asyncglobal→shmem 비동기가 도입되었으나, 발행 단위가 warp(32T)였고 Tensor Core 자체는 여전히 동기. Hopper는 TMA(1T issue) + WGMMA(async TC) + mbarrier(hw signal) 3종 셋으로 producer–consumer 분리를 ISA 수준에서 지원한다.
  • sm_90: Hopper 공통 feature
  • sm_90a: architecture-specific (TMA/WGMMA). forward-compat 포기 대신 full 기능
-arch=sm_90만으로는 TMA/WGMMA PTX 생성 불가. -arch=sm_90a 필수. PTX ISA 8.0+ / CUDA 12.0+

2 신기능 5종 TWC·mD

  1. TMA — Tensor Memory Accelerator. 1-thread가 tile copy 발행
  2. WGMMA — warp-group async MMA (128T = 4 warp)
  3. Cluster — block들의 집합, 같은 GPC에 co-schedule
  4. DSM — Distributed Shared Memory (cluster 내 remote smem)
  5. mbarrier — smem 64-bit HW barrier (phase bit)
5종 암기: TWCmD (TMA·Wgmma·Cluster·mbar·Dsm)

3 비동기 ISA 지도 ★

        Ampere              Hopper
 copy    cp.async (warp)     cp.async.bulk.tensor (1T)
 MMA     mma.sync (sync)     wgmma.mma_async (async)
 sync    bar.sync            mbarrier.{arrive|wait}
 scope   block               cluster (block ×N)
 shmem   local only          + remote (DSM)

공통: cp.async·mma.sync는 Hopper에서도 유효 ↗ V03 §6·§7

4 Producer–Consumer 계층

패턴 Hopper의 WS(warp specialization) 커널은 세 역할로 분할된다: producer warp(TMA 발행) · consumer warpgroup(WGMMA) · epilogue warp(store·activation). 세 역할이 mbarrier로 phase를 맞춘다.
producer WG0  →  [sA,sB] smem  →  consumer WG1
   TMA issue     mbarrier full       WGMMA async
      ↑______ mbarrier empty ________|

5 도입 이유 3가지

이유해결 수단
TC throughput 증가WGMMA async → 동기 오버헤드 제거
register 부족setmaxnreg 재분배 + shmem operand
L2 BW 재분배Cluster multicast + DSM

출처: GH100 Whitepaper §3, PTX ISA 8.x §9.7

6 Async Proxy의 등장

  • generic proxy: 일반 ld/st
  • async proxy: TMA/WGMMA가 쓰는 경로
  • 두 proxy 사이에 reorder 가능 fence.proxy.async 필요
함정: TMA로 shmem에 쓰고 같은 thread가 바로 st.shared로 overwrite하면 race. async proxy fence로 order 보장.

7 Out-of-Scope

  • SASS 전수 opcode — 핵심 7개만
  • 실전 decompile 감각 — 코드 훈련 영역
  • CUTLASS 내부 레이아웃 ↗ V06
  • FA3 스케줄 디테일 ↗ V07 §9·§10

1 Cluster 정의 ★ block의 block

Cluster 1개 이상 thread block의 집합. 같은 GPC(Graphics Processing Cluster) 내 SM들에 공동 스케줄된다. Hopper 고유 계층: grid > cluster > block > warpgroup > warp > thread.
  • 최대 크기: portable 8 / non-portable up to 16 blocks
  • CTA 간 cluster.sync로 집합적 동기화
  • DSM으로 remote smem 접근 가능 ↗ §3 p.4

2 선언 문법

// C++ attribute
__global__ __cluster_dims__(2,1,1)
void kernel(...){ ... }

// PTX directive
.reqnctapercluster 2, 1, 1
// launch API (dynamic)
cudaLaunchKernelEx(&cfg, kernel, args);

cluster shape는 kernel-time 또는 launch-time 결정. cudaFuncSetAttribute(..., NonPortableClusterSize, 1)로 16 unlock.

3 Built-in 좌표

변수의미
clusterDimcluster 내 block 수 (x,y,z)
clusterIdxgrid 내 cluster 좌표
blockRank
InCluster()
cluster 내 block의 linear id ∈ [0, |cluster|)
cluster.sync()cluster 내 모든 thread 집합 동기

Cooperative Groups: cluster_group cg = this_cluster()

4 PTX instruction

// cluster-wide barrier
barrier.cluster.arrive;
barrier.cluster.wait;
// or fused
barrier.cluster.sync;

// rank query
mov.u32 %r0, %cluster_ctarank;
mov.u32 %r1, %cluster_nctaid.x;
제약: cluster 내 모든 block은 동시에 resident. SM 자원 부족하면 launch 실패 (cudaErrorLaunch
OutOfResources
).

5 Cluster 활용 이유

  1. TMA multicast: 1 load → N block shmem 동시 broadcast
  2. DSM reuse: 인접 block이 서로의 smem 읽음 → L2 BW 절약
  3. Cluster launch control: co-location 보장 → latency 예측

6 전형 cluster shape

용도shape비고
Hopper GEMM(2,1,1)multicast A tile
Hopper GEMM big(2,2,1)4 block × N-way
Conv / Attn(1,1,1)cluster 미사용, WS만
Max portable(8,1,1)spec 보장 최대

출처: CUTLASS 3.x SM90 collective.

7 Launch 조건 배수

gridx mod clusterDimx = 0
gridy mod clusterDimy = 0 배수 조건 위반 시 launch 실패. 마지막 tile padding 필요.

1 DSM 정의 ★ remote smem

DSM 같은 cluster에 속한 다른 block의 shared memory일반 load/store처럼 접근하는 기능. cluster 내 SM-to-SM 고속 interconnect를 사용.
  • address space: .shared::cluster (확장된 smem window)
  • block의 smem은 cluster rank 별로 mapped region에 나타남
  • HBM 거치지 않음 — L2보다 훨씬 낮은 latency

2 Latency 대략값

accesscycles (approx)
local smem~20
DSM (cluster)~30–40
L2 hit~200
HBM~400–600

정확 수치는 V02 §14 ↗ V02. 여기는 비율만 기억.

3 Address mapping PTX

// local smem ptr → remote smem ptr
// target rank = r
mapa.shared::cluster.u32
  %r_remote, %r_local, %r_rank;
// 이후 일반 ld/st.shared::cluster 사용
ld.shared::cluster.f32 %f0,[%r_remote];
st.shared::cluster.f32 [%r_remote],%f1;

mapa = map address. 단일 instruction, smem offset 보존.

4 Cooperative Groups API

auto cg = cg::this_cluster();
int  myr = cg.block_rank();
int  N   = cg.num_blocks();
float* remote =
  cg.map_shared_rank(local_ptr, peer_rank);
// remote는 유효한 .shared::cluster ptr
cg.sync();   // cluster barrier

5 Atomic도 가능

  • atom.shared::cluster.add
  • cluster scope atomic의 가시성: 같은 cluster 내 thread에 대해 순서 보장

6 DSM 활용 패턴

패턴용도
A-multicast GEMM1 block이 A tile load → N block이 읽음
Reduction across blockscluster 내 partial sum 병합
Conv halo share인접 block의 edge row 참조
Attention KV shareKV tile을 cluster 내 분산 저장

7 동기화 규칙 ★

writer block: store → barrier.cluster.arrive
reader block: barrier.cluster.wait → load
또는 mbarrier를 .shared::cluster로 초기화 후 arrive/wait.
함정: 일반 __syncthreads()는 block-scope. DSM 대상은 절대 보장 못함.

8 제한 사항

  • cluster 내부만 — cross-cluster는 L2 경유
  • cluster resident 동안만 유효 (block eviction 없음)
  • smem 사용량 = |cluster| × per-block smem 고려

1 TMA란 ★★ 1T·N-D

TMA SM 외부의 copy engine. 1 thread가 다차원 tile copy를 발행하면 HW가 boundary check·swizzle·multicast를 수행. 완료는 mbarrier로 signal.
  • 발행 단위: 1 thread (vs cp.async = 32T)
  • 방향: G→S (load) · S→G (store) · S→S (cluster multicast)
  • 차원: 1D–5D tensor, box(tile) 단위 copy

2 Tensor Descriptor 구조

필드의미
tensor ptrglobal base address
rank1–5
global dims각 축 크기
global strides바이트 stride (축별)
box dimstile 크기 (smem 복사 단위)
element stridedilation (≥1)
dtypeFP16/BF16/FP8/TF32/…
swizzleNONE / 32B / 64B / 128B
OOB fillNONE / zero / NaN

3 Descriptor 생성 (host)

CUtensorMap desc;
cuTensorMapEncodeTiled(
  &desc,
  CU_TENSOR_MAP_DATA_TYPE_FLOAT16,
  /*rank=*/2,
  g_ptr, /*dims=*/{M,N},
  /*strides=*/{N*2, 2},
  /*box=*/{BM, BN},
  /*elemStride=*/{1,1},
  CU_TENSOR_MAP_INTERLEAVE_NONE,
  CU_TENSOR_MAP_SWIZZLE_128B,
  CU_TENSOR_MAP_L2_PROMOTION_L2_128B,
  CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE);

128-byte 정렬 · const로 kernel에 넘김 (__grid_constant__ CUtensorMap).

4 Tile mode vs Im2col mode

mode의미용도
tilebox 단위 rectangular copyGEMM, Transformer
im2colconv sliding window → columnCNN, 2D conv

im2col: descriptor의 interleave·lower/upper offset·kernel strides로 conv 변환.

5 Swizzle 선택 bank conflict 회피

swizzle ∈ {NONE, 32B, 64B, 128B}
swizzle size = WGMMA K-dim · sizeof(dtype) FP16·k16 → 32B = 16·2, m64n*k16 → 128B 권장.
  • 32-bank smem과 WGMMA fragment layout 일치
  • 잘못 설정 시 silent 성능 저하 (정답은 맞으나 BW 반감)

6 발행 → 완료 흐름도 ★

[thread 0]          [TMA engine]         [mbarrier]
  init desc               ─                init(1)
  expect_tx(bytes)────────────────────────▶ set TX count
  cp.async.bulk.tensor ──▶ fetch tile
                          │
                          ▼
                        write smem
                        arrive.complete_tx──▶ TX count↓
  try_wait.parity ◀──────────────────────── phase flip
  consume smem

7 OOB 처리

  • NONE: 호출자가 bounds 보장
  • ZERO: OOB 영역 0으로 채움 (attention padding에 유용)
  • NaN: float만 해당

1 명령 형식 ★

cp.async.bulk.tensor.{rank}D
.shared::cluster.global.mbarrier::
complete_tx::bytes
[smem], [desc, {coords}], [mbar]; rank ∈ {1..5}. 1 thread가 issue. async proxy 경로로 복사.

2 G→S 2D load ★★

// thread 0만 발행
if (threadIdx.x == 0) {
  asm volatile(
    "cp.async.bulk.tensor.2d"
    ".shared::cluster.global"
    ".mbarrier::complete_tx::bytes"
    " [%0], [%1, {%2,%3}], [%4];"
    ::
    "r"(smem_ptr),   // dst
    "l"(tma_desc),   // CUtensorMap*
    "r"(coord_x),
    "r"(coord_y),
    "r"(bar_ptr));   // mbarrier
}
  • completion 방식: complete_tx::bytes (mbarrier TX counter에 bytes 추가)
  • 다른 옵션: bulk_group (commit_group/wait_group 기반)

3 전체 lifecycle pseudo-code ★★

// === setup (thread 0) ===
if (tid == 0) {
  mbarrier_init(bar, 1);
  fence_mbarrier_init();
}
__syncthreads();

// === phase 0: issue ===
if (tid == 0) {
  mbarrier_expect_tx(bar, BM*BN*2);
  cp_async_bulk_tensor_2d(
      sA, &tma_desc, {cx, cy}, bar);
}

// === wait (all threads) ===
uint32_t phase = 0;
while (!mbarrier_try_wait_parity(
              bar, phase)) { }

// === consume ===
wgmma_fence();
wgmma(acc, sA, sB);
wgmma_commit_group();
wgmma_wait_group(0);

// === next iter: toggle phase ===
phase ^= 1;

4 변종 table

명령용도
cp.async.bulk
.tensor.{N}d
.shared::cluster.global
G→S tile load
cp.async.bulk
.tensor.{N}d
.global.shared::cta
S→G store
cp.async.bulk
.tensor.{N}d
.shared::cluster
.shared::cta.multicast
cluster multicast
cp.async.bulk
.prefetch.tensor
L2 prefetch
cp.async.bulk
.commit_group
commit 그룹 닫기
cp.async.bulk
.wait_group N
N개 미만 남을 때까지 대기

5 Multicast mask

// N-bit mask: cluster rank별 수신 여부
asm("cp.async.bulk.tensor.2d"
    ".shared::cluster.global"
    ".multicast::cluster"
    ".mbarrier::complete_tx::bytes"
    " [%0],[%1,{%2,%3}],[%4],%5;"
    :: ... , "h"(mask));

mask = 0b0011 → rank 0·1 수신.

6 주의점

함정 3선: ① TMA 후 같은 smem 영역을 st.shared로 바로 overwrite → async proxy race. ② mbarrier init은 1 thread + fence. ③ descriptor는 128B aligned, const 선호.

1 mbarrier 구조 ★

mbarrier smem 64-bit object. 4 필드로 구성: expected arrive count, current arrive count, TX count(byte 예약), phase bit(0/1 토글).
[63]    phase bit
[62:44] expected arrive count
[43:25] current arrive count
[24: 0] pending TX bytes  (TMA용)

정확한 bit layout은 구현 dependent. 의미만 사용.

2 Lifecycle

  1. init — expected count 설정 + phase=0
  2. expect_tx — TMA가 들어올 byte 수 예약 (optional)
  3. arrive — count++ (thread 단위)
  4. arrive.expect_tx — count++ & TX 예약
  5. try_wait.parity — phase 반전 때까지 spin
  6. phase flip: count==expected && TX==0 충족 시 자동

3 PTX 명령 표

명령주체효과
mbarrier
.init.shared.b64
1 threadcount 설정
mbarrier
.inval.shared.b64
1 thread소멸
mbarrier
.arrive.shared.b64
각 thread도착 signal
mbarrier.arrive
.expect_tx.b64
1 thread도착+TX 예약
mbarrier
.expect_tx.b64
1 threadTX 예약만
mbarrier
.try_wait.parity
각 threadphase 체크
mbarrier
.test_wait.parity
각 threadnon-blocking 체크

4 기본 사용 패턴

// init (1 thread)
asm("mbarrier.init.shared.b64"
    " [%0], %1;"
  :: "r"(bar), "r"(N_ARRIVE));
fence_mbarrier_init_release();

// arrive (각 thread)
asm("mbarrier.arrive.shared.b64"
    " _, [%0];"
  :: "r"(bar));

// wait
uint32_t p = 0;
while(!try_wait_parity(bar, p)){}
p ^= 1;

5 Phase bit 개념 ★

phase barrier는 단일 counter를 매번 reset하는 대신 parity로 세대(generation)를 표현한다. 같은 barrier를 N iter 재사용 가능.
iter 0:  init→arrives→flip(0→1)  wait p=0
iter 1:      arrives→flip(1→0)  wait p=1
iter 2:      arrives→flip(0→1)  wait p=0
...  phase ^= 1 매 iter

6 짝짓기 규칙

signal 주체waiter
TMA (HW)consumer warpcomplete_tx
producer warpconsumer WGfull barrier
consumer WGproducer warpempty barrier
cluster peersthis blockcluster barrier

7 함정

init fence 필수: fence.mbarrier_init.release.cluster 없이 다른 warp가 arrive 시도하면 UB.
count 정확: TMA = 1 arrive (HW가 대표). warp arrive는 warp 수.

1 warpgroup 정의 ★

warpgroup 연속된 4 warp = 128 thread. warp index = [4k, 4k+1, 4k+2, 4k+3]로 정렬. WGMMA는 warpgroup 전체가 집합적으로 수행.
  • Block당 warpgroup 수 ≤ 4 (typical 2: producer + consumer)
  • 모든 128T가 같은 wgmma.mma_async 호출 — lane divergence 금지

2 Async 의미론

wgmma.fence         ; 이전 reg writes flush
wgmma.mma_async     ; 발행 후 즉시 다음 명령 가능
wgmma.commit_group  ; 지금까지 발행된 mma 그룹 닫기
wgmma.wait_group N  ; N개 group 이하만 in-flight 유지

commit/wait 쌍으로 pipeline 제어. N=0이면 모든 in-flight 완료 대기.

3 Operand 배치

피연산자위치형태
ARF or smemregister tile / matrix desc
Bsmem onlymatrix desc (64-bit)
D (accum)RFper-thread fragment

4 명령 형식 ★★

wgmma.mma_async.sync.aligned
.m64n{N}k{K}.dtypeD.dtypeA.dtypeB m=64 고정. N ∈ {8,16,..,256}. K = 16(FP16/BF16), 32(FP8), 8(TF32), 16(INT8).

5 사용 template ★★★

// === setup ===
uint64_t descA = make_desc(sA, stride, swizzle);
uint64_t descB = make_desc(sB, stride, swizzle);
float d[64];   // accumulator fragment

// === mainloop ===
asm("wgmma.fence.sync.aligned;");
asm volatile(
 "wgmma.mma_async.sync.aligned"
 ".m64n256k16"
 ".f32.f16.f16"
 " {%0,%1,...,%127},"   // D: 128 regs
 " %128, %129,"            // descA, descB
 " %130, 1, 1, 1, 1;"      // scaleD,A,B,tnsA,tnsB
 : "+f"(d[0]), "+f"(d[1]), ...
 : "l"(descA), "l"(descB),
   "r"(scaleD));
asm("wgmma.commit_group.sync.aligned;");
asm("wgmma.wait_group.sync.aligned 0;");
// d[] 이제 consumption 가능

6 Matrix descriptor bit layout ★

[63:62] base offset       (smem alignment)
[61:49] leading dim BO    (byte offset between 8·k tiles)
[48:46] swizzle           (0=none,1=32B,2=64B,3=128B)
[45:32] stride dim BO     (byte offset between groups of 8 rows)
[31:14] reserved
[13: 0] start address     (smem offset / 16)

CuTe의 make_gmma_desc가 자동 생성. 수동 생성은 silent 오답 유발.

7 scale·tns 파라미터

imm의미
scaleD1 = D += A·B, 0 = D = A·B
scaleA/B±1 (부호)
tnsA/B0=NN, 1=transposed

8 기존 mma와 차이

mma.sync(Ampere): warp(32T), sync, reg만. wgmma.mma_async(Hopper): WG(128T), async, B는 smem. ↗ V03 §7

1 Shape 축 의미

D[m64, nN] = A[m64, kK] · B[kK, nN]
     ↑             ↑              ↑
  accumulator   SM-input-A   SM-input-B (smem)
  • m = 64 고정 (warpgroup 단일 축)
  • N = 8, 16, 24, ..., 256 (8 단위)
  • K는 dtype별로 결정

2 N 값 허용 셋

N ∈ {8, 16, 24, 32, 40, 48, 56, 64,
72, 80, 88, 96, 104, 112, 120, 128,
136, ..., 248, 256} 전체 32개 값. 8의 배수. GEMM epilogue tile에 맞춤.

출처: PTX ISA 8.x §9.7.14.

3 권장 N (H100 SXM5)

N_C tile권장 WGMMA N
6464
128128
192192 (=8·24)
256256 (peak)

N 클수록 발행 횟수 ↓ → issue overhead ↓.

4 dtype × K 완전표 ★★★

입력 A/Baccum DK명령 접미
FP16 / FP16FP3216.f32.f16.f16
FP16 / FP16FP1616.f16.f16.f16
BF16 / BF16FP3216.f32.bf16.bf16
TF32 / TF32FP328.f32.tf32.tf32
E4M3 / E4M3FP3232.f32.e4m3.e4m3
E4M3 / E5M2FP3232.f32.e4m3.e5m2
E5M2 / E4M3FP3232.f32.e5m2.e4m3
E5M2 / E5M2FP3232.f32.e5m2.e5m2
S8 / S8S3232.s32.s8.s8
U8 / U8S3232.s32.u8.u8
S8 / U8S3232.s32.s8.u8
B1 / B1 (XOR.POP)S32256.s32.b1.b1

FP8: E4M3=더 정밀·낮은 range, E5M2=높은 range·낮은 정밀 ↗ V09 §5.

5 Accum register 수

regs_per_thread = m·N / (128·reg_width)
= 64·N / (128·1) · (acc_bits/32) FP32 accum: m64·n{N}·FP32 → N/2 regs/thread.
shapeaccum dtyperegs/T
m64n64k16FP3232
m64n128k16FP3264
m64n256k16FP32128
m64n128k16FP1632

128T × 128 reg = 16K reg/WG → consumer에 몰아주기 필요.

6 Register budget 제약

H100: 65536 regs / SM. 2 WG 사용 시 WG당 32K. consumer WG가 m64n256k16 accum FP32 = 128 reg/T 유지에는 setmaxnreg 240+ 필요. ↗ §10 p.11

7 Sparsity variant

  • wgmma.mma_async.sp.sync.aligned
  • A가 2:4 sparse → 실효 K 2배
  • metadata: 2-bit per 4 elem, smem에 동반 load

1 WS 정의 ★ 역할 분담

WS block 내 warp를 역할별로 분할. 대표적으로 producer(TMA 발행) vs consumer(WGMMA). mbarrier로 phase를 동기.
  • Cooperative Groups 모델에서 벗어나 imperative async 설계
  • 목적: WGMMA를 TMA·softmax와 시간적으로 overlap

2 WG 분할 전형

configproducerconsumer
1P+1CWG0 (warp 0–3)WG1 (warp 4–7)
1P+2C (pingpong)WG0WG1, WG2
1P+1C+1EWG0WG1

E=epilogue. FA3 커널은 1P+2C. CUTLASS GEMM은 config 선택.

3 Producer / Consumer pseudo-code ★★★

// === shared mbarriers ===
__shared__ uint64_t bar_full[S];
__shared__ uint64_t bar_empty[S];

// === init (1 thread) ===
if (tid == 0) {
  for (i=0; i<S; i++){
    mbarrier_init(&bar_full[i],  1);
    mbarrier_init(&bar_empty[i], 2);  // 2 cons WG
  }
  fence_mbarrier_init_cluster();
}
__syncthreads();

// === PRODUCER warp-group (WG0) ===
if (wg_idx == 0) {
  setmaxnreg_dec(40);   // 240 → 40
  uint32_t p = 0;
  for (k=0; k<K_TILES; k++){
    int slot = k % S;
    mbarrier_wait_parity(
        &bar_empty[slot], p);
    if (lane==0) {
      mbarrier_expect_tx(
          &bar_full[slot],
          BM*BK*2 + BK*BN*2);
      cp_async_bulk_tensor(
          &sA[slot], &desc_A,
          {k*BK, m0}, &bar_full[slot]);
      cp_async_bulk_tensor(
          &sB[slot], &desc_B,
          {n0, k*BK}, &bar_full[slot]);
    }
    if ((k%S) == S-1) p ^= 1;
  }
}

4 Consumer pseudo-code ★★★

// === CONSUMER warp-groups (WG1, WG2) ===
else {
  setmaxnreg_inc(232);  // 40 → 232
  float acc[128] = {0};
  uint32_t p = 0;
  for (k=0; k<K_TILES; k++){
    int slot = k % S;
    mbarrier_wait_parity(
        &bar_full[slot], p);
    wgmma_fence();
    wgmma_mma_async(
        acc,
        make_desc(&sA[slot]),
        make_desc(&sB[slot]));
    wgmma_commit_group();
    wgmma_wait_group(1);  // 1 in-flight
    mbarrier_arrive(
        &bar_empty[slot]);
    if ((k%S) == S-1) p ^= 1;
  }
  wgmma_wait_group(0);
  store_epilogue(acc);
}

5 패턴 비교

패턴consumer 분배
Cooperative같은 M tile의 N축 절반씩
Pingpong다른 M tile 교대

상세 trade-off ↗ V06 §15, ↗ V07 §10.

1 Proxy 개념 ★

proxy memory access path. 일반 thread-issued ld/st는 generic proxy, TMA·WGMMA 등 HW engine은 async proxy. 두 proxy 간 ordering은 별도 fence로만 보장.
thread  ──generic──▶ smem/L2/HBM
TMA     ──async ────▶ smem/L2/HBM
WGMMA   ──async ────▶ RF/smem(read)

2 Proxy fence PTX

명령효과
fence.proxy
.async.shared::cta
async→generic(smem)
fence.proxy
.async.global
async→generic(gmem)
fence.mbarrier_
init.release.cluster
init 가시성
wgmma.fence
.sync.aligned
WGMMA 전 RF commit

3 언제 쓰는가

  • TMA write → WGMMA read: TMA complete_tx가 함께 proxy fence 역할
  • TMA write → thread read(ld.shared): 명시 fence 필요
  • WGMMA write RF → epilogue: wgmma.wait_group이 release 역할

4 setmaxnreg 정의 ★

setmaxnreg warp별 register budget을 warp-group 수준에서 재조정하는 PTX 명령. 총합 유지 필요. WG 단위 호출.
setmaxnreg.dec.sync.aligned.u32 %R;  // reduce to R
setmaxnreg.inc.sync.aligned.u32 %R;  // raise to R

5 허용 값 / 규칙

항목
허용 R24, 32, 40, ... , 240 (8의 배수)
dec 대상 기본initial max nregs
inc 상한240 (일반) / 224 (setup 제한 시)
동기WG 전원이 같은 call

PTX ISA 8.x. __nv_cvta_set_maxnreg_dec_sync_aligned_u32 builtin.

6 재분배 전형 값 ★

producer WG: 40 reg/T
consumer WG: 232 reg/T
WG 2개일 때 총합 ≈ (40+232)·128 = 34816 reg (regs/WG 예산 내).

FA3 (Hopper) 기본값: prod 40, cons 232 (H100 SM).

7 호출 위치 규칙

  • kernel 초반, role-분기 직후 즉시 호출
  • mainloop 진입 전 완료
  • 중간 변경 금지 (deadlock risk)
if (wg_idx == 0) {
  setmaxnreg_dec(40);
  producer_loop();
} else {
  setmaxnreg_inc(232);
  consumer_loop();
}

8 launch_bounds 와의 관계

__launch_bounds__(N, M)initial max reg/T 결정. setmaxnreg는 그 범위에서만 유효. initial이 너무 작으면 inc(232) 실패.

9 제한

  • setmaxnreg는 WG 전원이 aligned — divergent call 불가
  • cluster launch 시 각 block별 독립 적용
  • debug: cuobjdump --dump-resource-usage로 per-kernel reg 확인

1 DPX 동기 DP 가속

DPX 반복적인 min/max + add 패턴(Smith-Waterman, Needleman-Wunsch, Floyd-Warshall, Viterbi 등)을 단일 instruction으로 압축한 확장 ISA.
  • Hopper 신설. 대상: bioinformatics / graph / RL path
  • 스루풋: Ampere 대비 약 7× (vendor 공식 자료)

출처: GH100 Whitepaper §3.3, CUDA Math API.

2 3-operand min/max

PTX동작
vimin3.s32min(a,b,c)
vimax3.s32max(a,b,c)
vimin3.s16x22×min, 16-bit packed
vimax3.s16x22×max, packed
vibmax3.s32max + index

3 복합 relu+add+max

// y = max(x+bias, 0) + c, 단일 inst
asm("viaddmax.s32.relu"
    " %0, %1, %2, %3;"
  : "=r"(y)
  : "r"(x), "r"(bias), "r"(c));

// 3-arg max with saturate
asm("vimax3.s32"
    " %0, %1, %2, %3;"
  : "=r"(m)
  : "r"(a), "r"(b), "r"(c));

4 SW 업데이트 예

H[i,j] = max(0,
  H[i-1,j-1] + s(a,b),
  H[i-1,j] − gap,
  H[i,j-1] − gap) vimax3 + viaddmax로 2 inst로 compact.

5 CUDA C intrinsic

C builtinPTX
__vimax3_s32vimax3.s32
__vimin3_s32vimin3.s32
__vibmax_s32vibmax3 (idx)
__viaddmax_
s32_relu
viaddmax.relu
__viaddmin_
s16x2
packed

unsigned, signed, packed 버전 합쳐 약 20개.

6 활용 영역

  • Bioinformatics: Smith-Waterman, DP 정렬
  • Robotics: path planning, dynamic programming
  • RL: value iteration
  • Graph: Floyd-Warshall all-pairs shortest

7 한계

packed 16x2는 bit 정렬 제약 있음. 데이터가 int16 범위 초과하면 wraparound. float DP는 일반 fma로 처리.

1 SASS 정의 ★ 실제 opcode

SASS Streaming ASsembler. GPU HW가 실제로 실행하는 architecture-specific ISA. PTX가 virtual이라면 SASS는 real. NVIDIA는 공식 스펙 미공개(간접 참조만).
  • 각 세대마다 encoding 상이 (sm_80 ≠ sm_90)
  • JIT: PTX → ptxas → SASS
  • Reverse: nvdisasm, cuobjdump

2 변환 파이프라인

.cu    ─[nvcc front]─▶ .ptx
.ptx   ─[ptxas]──────▶ .cubin (SASS + metadata)
.cubin ─[driver JIT]─▶ (native) → launch

embedded PTX는 driver가 최종 SM에 대해 runtime compile (fat binary).

3 세대별 encoding

archword특징
Fermi64-bit구조적 단순
Maxwell/Pascal64-bit + 3-inst ctrlcontrol word 분리
Volta/Turing128-bitinst당 ctrl 내장
Ampere/Hopper128-bit+ async ops, mbar, WGMMA

출처: Jia et al. 2018 / Dissecting Volta · Ampere reverse-engineering 논문.

4 왜 SASS를 읽나

  1. register spill 확인 (LDL/STL 존재)
  2. stall 이유 추적 (control code)
  3. instruction mix 분석 (FFMA vs HMMA 비율)
  4. compiler 스케줄링 의도 역추론

5 nvdisasm 기본

# cubin에서 SASS 덤프
nvdisasm --print-code kernel.cubin

# control code 함께
nvdisasm --print-instruction-encoding \
         --print-line-info kernel.cubin

# cuobjdump from fatbin
cuobjdump --dump-sass a.out

6 PTX ↔ SASS 관계 ★

1 PTX inst → 1..N SASS inst
(대체로 1:1, 복합 op는 1:N) 예: PTX mad.rn.f32 → SASS FFMA. PTX mma.sync → SASS HMMA.

7 SASS 기본 형식

  [label]   OPCODE.MOD  [P?] dst, src1, src2 [, src3] ;
  예:
  /*0010*/  FFMA R3, R2, R5, R3 ;
  /*0020*/  @P0 BRA  0x50 ;
  /*0030*/  STG.E [R6], R4 ;
  • @P0: predicate (0~6)
  • .E: effective addr (64-bit pointer)
  • 레지스터: R0..R255 + RZ(=0), URx(uniform)

8 Hopper 특유 SASS

SASS (Hopper)PTX 대응
UBLKCPcp.async.bulk
UTMALDG/UTMASTGcp.async.bulk.tensor
MBARRIER_*mbarrier.*
GMMAwgmma.mma_async
SETMAXREGsetmaxnreg.{inc,dec}

opcode 이름은 nvdisasm 버전에 따라 약간 다를 수 있음.

9 범위 밖 의도적 제외

  • 전수 opcode 리스트 — 공식 미공개
  • 실제 cubin 디컴파일 훈련 — 코드 영역
  • 세대별 encoding bit 분석

1 산술 ★

opcode의미
IMADint multiply-add (포인터 계산 주력)
IADD33-op integer add (주소+offset+base)
IMULint mul
FFMAfloat fused multiply-add (FP32 core 주력)
FMUL/FADDfloat mul/add
HFMA2FP16×2 packed FMA
DFMAdouble fused MA
핵심 7: IMAD·IADD3·FFMA·HFMA2·LDG·STG·LDS

2 Memory

opcode의미
LDG.Eload global (effective addr)
STG.Estore global
LDSload smem
STSstore smem
LDL/STLlocal mem (spill 신호)
LDGSTSAmpere cp.async
LDSMldmatrix

3 Tensor Core ★

opcode의미
HMMAHalf-precision MMA (FP16/BF16)
IMMAInteger MMA (INT8)
BMMABinary MMA (1-bit)
QMMAFP8 quarter-precision (Hopper)
GMMAgroup MMA = WGMMA (Hopper)

HMMA는 warp-level, GMMA는 warpgroup-level async.

4 Control flow

opcode의미
BRAbranch
BRXindexed branch
JMPjump (long)
BSSY/BSYNCconvergence barrier (Volta+)
EXITthread 종료
CALL/RETfunction

5 Sync / Atomic

opcode의미
BAR.SYNC__syncthreads
MEMBARfence
ATOMSatomic smem
ATOMGatomic global
RED.Ereduction global

6 대표 modifier

mod의미
.Eeffective 64-bit addr
.128128-bit vectorized
.CA/.CGcache L1+L2 / L2 only
.CSstreaming (non-coherent)
.SYSsystem-scope atomic
.STRONGstrong ordering

7 실행 예 (Hopper GEMM 발췌)

/*0100*/ IMAD.WIDE R4, R3, 0x4, R0 ;   // addr calc
/*0108*/ ULDC.64 UR4, c[0x0][0x160] ; // desc
/*0110*/ LDS.128 R8, [R4+0x0] ;        // smem load
/*0118*/ GMMA.64x256x16.F32.F16 R16, desc_A, desc_B, R16 ;
/*0120*/ GMMA.FENCE ;
/*0128*/ GMMA.COMMIT_GROUP ;
/*0130*/ GMMA.WAIT_GROUP 0x0 ;
/*0138*/ STG.E.128 [R20], R16 ;

주소·opcode는 예시용. 실제 nvdisasm 출력과 다를 수 있음.

8 Spill 진단

LDL/STL이 보이면 register spill → local mem. ptxas -v로 확인. 해결: __launch_bounds__ 조정·loop 분할.

1 Control code 개요 ★

control code Maxwell+에서 각 instruction에 inline 부착된 16-bit field. read/write barrier, yield hint, reuse, stall count 정보를 담음. SASS latency 해석의 열쇠.
128-bit SASS inst = [64b opcode] [64b operand/ctrl]
       control field ≈ 16-bit subset

2 구성 요소

fieldbit역할
stall4다음 inst 전 대기 cycle (0~15)
yield1다른 warp 양보 hint
write barrier3SB# 설정 (이 inst 결과 ready 신호)
read barrier3SB# 대기
wait mask6대기할 SB 비트맵
reuse4operand cache reuse flag

SB = ScoreBoard. 6개 slot. fixed-latency는 stall만, variable(LDG/HMMA)는 SB 사용.

3 의미 해석 ★

  • stall = k: 이 inst issue 후 k cycle 뒤 다음 inst (fixed latency 의존성)
  • write SB#n: 이 inst 완료 시 SB#n 해제. 해제 전까지 SB#n 보유자는 대기.
  • wait 000100: SB#2 기다림. 그 이전 LDG가 완료되어야 진행
  • yield: eligible warp 재평가 trigger (occupancy 도움)
  • reuse: 직전 inst의 operand register를 operand collector에서 재사용

4 nvdisasm 출력 예

/*0200*/    LDG.E.SB0 R4, [R2] ;       // write SB0
/*0208*/    IADD3 R5, R5, R0, RZ ;     // stall=1
/*0210*/  @SB0 FFMA R6, R4, R7, R6 ;   // wait SB0
/*0218*/    FFMA.REUSE R8, R4, R9, R8; // reuse R4

@SB0 표기는 툴에 따라 WAIT(0) 등으로 나타남.

5 Hopper 추가

  • GMMA completion: 별도 GMMA scoreboard
  • TMA completion: mbarrier로 signal (SB 미사용)
  • GMMA.WAIT_GROUP이 GMMA SB drain

6 Latency 분류 표

카테고리처리
fixed 고정 (FFMA, IADD)stall 필드
variable 메모리 (LDG, LDS)write/wait SB
async (cp.async, TMA)mbarrier/그룹
TC (HMMA, GMMA)dedicated SB (Hopper)

7 Stall 값 의미

next_issue_cycle = current_cycle + stall stall=0: back-to-back. 일반 FFMA는 2–4. load는 variable이라 stall 무의미, SB만 사용.

8 읽기 팁

  1. WAIT 표기가 많다 → 메모리 의존성
  2. REUSE 표기가 적다 → operand collector 압박
  3. YIELD 없음 → occupancy low 의심
  4. stall≥8 연속 → fixed-lat 직렬화 (dep chain 길이)

9 프로파일러와 관계

Nsight Compute의 stall reason 분류는 이 control code를 집계한 것. ↗ V18 §4.

1 Dual Issue 정의 ★

Dual issue SM 내 warp scheduler가 한 cycle에 같은 warp의 연속 2 inst를 다른 function unit에 발행. 조건: 독립(RAW 없음), unit 중복 없음.
  • Ampere: 1 inst/cycle/scheduler × 4 scheduler
  • Hopper: 2 inst/cycle/scheduler 가능 (dual issue) × 4 scheduler GH100 wp §3.2

2 쌍 조건 표

A / Bdual 가능?
FFMA + LDG○ (다른 unit)
FFMA + IMAD△ (unit 중복)
FFMA + FFMA×
LDS + FFMA
HMMA + anything× (TC 전용)

실제 규칙은 compiler 전담. 사용자는 관찰만.

2 Scoreboard 개념 ★

scoreboard variable-latency inst의 완료를 추적하는 per-warp bit register. Maxwell+ 6 slot. 각 slot: "이 load/MMA가 아직 in-flight인가"를 1비트로 표시.
warp scoreboard:  [SB0 SB1 SB2 SB3 SB4 SB5]
                    ▲                   ▲
                    |                   |
                 LDG.E → set SB0     HMMA → set SB4
                 @SB0 FFMA waits for SB0 == 0

3 할당 규칙

  • compiler가 inst 발행 시 SB# 선택 (write barrier)
  • 같은 SB# 재사용 전에 반드시 해제
  • 과도 할당 → stall 누적, 과소 할당 → false-dep

4 Hopper SB 분리

SB group추적 대상
일반 SBLDG/LDS/STG 등
GMMA SBWGMMA (group 단위)
mbarrierTMA (SB 미사용)

5 Read-after-Write 분석

LDG.E R4 [write SB0]
…other work…
@SB0 FFMA R6, R4, … [wait SB0] load latency가 길수록 between 구간에 다른 independent work 배치 → latency hiding.

6 Compiler scheduling 영향

  • ptxas의 instruction scheduling pass가 write/wait 배치 결정
  • -Xptxas -O3: aggressive reorder
  • #pragma unroll / loop hoist가 체인 길이 결정
  • inline asm 직후 : 인접 SASS 순서 제약 가능

7 Pipeline hazard 유형

hazard해결
RAW fixedstall cycles
RAW variablescoreboard wait
WAWrename (HW)
WARoperand latch
struct (unit busy)issue slot block

8 Issue slot 최적화 요점

dual-issue와 async는 상호 보완: 동기 inst의 dual-issue로 instruction 밀도 ↑, async inst(TMA/GMMA)로 메모리·TC overlap.

1 툴 표 ★

용도
cuobjdumpfatbin/ELF → SASS 덤프
nvdisasmcubin → SASS (text)
nvcc -ptxptx 단독 출력
ptxas -vreg/smem/lmem 사용량
Nsight Computesource↔SASS 매핑 UI

2 기본 워크플로

# 1. arch 지정 컴파일 + lineinfo
nvcc -arch=sm_90a -lineinfo \
     -Xptxas -v -o k.cubin k.cu

# 2. PTX
nvcc -arch=sm_90a -ptx k.cu -o k.ptx

# 3. SASS + line
nvdisasm --print-line-info \
         --print-instruction-encoding \
         k.cubin > k.sass

# 4. PTX ↔ SASS side-by-side
diff -y k.ptx k.sass | less

3 PTX ↔ SASS 대응 패턴

PTXSASS (Hopper)
mad.rn.f32FFMA
ld.global.f32LDG.E
ld.shared.f32LDS
st.global.v4STG.E.128
cp.async.ca.b128LDGSTS
cp.async.bulk
.tensor.2d
UTMALDG
mbarrier.arriveMBARRIER.ARRIVE
wgmma.mma_asyncGMMA
setmaxnreg.decSETMAXREG
bar.syncBAR.SYNC

4 주석 달기 규칙

  1. 범위 표시: mainloop 시작/끝 라벨
  2. 역할 표기: producer/consumer 섹션 분리
  3. SB 지도: 각 SB#가 어느 load를 커버하는지
  4. spill flag: LDL/STL에 ! 표시

5 진단 체크리스트

증상SASS 단서
reg spillLDL/STL 등장
bank conflictLDS 다수 + 긴 stall
동기 GEMMHMMA (GMMA 아님)
TMA 미사용UBLKCP 없음, LDGSTS만
uncoalesced G loadLDG.E 반복, 32B 이하
divergent branchBSSY/BSYNC 빈번

6 Loop identify

.L_LOOP_START:
  @SB0 LDS ... ;
       GMMA ... ;
       GMMA.COMMIT_GROUP ;
       GMMA.WAIT_GROUP 1 ;
       MBARRIER.ARRIVE ... ;
       BRA .L_LOOP_START ;

mainloop는 보통 BSSY/BRA 쌍 + stage pipeline. MBARRIER가 경계.

7 Source↔SASS mapping

  • -lineinfo 필수 (-G는 debug, 성능 왜곡)
  • Nsight Compute의 Source View가 같은 정보
  • 한 source line ↔ 다수 SASS (N:M)

8 종료 체크

SASS에서 EXIT가 중간에 있다 → divergent early-exit. warp vote로 대체하면 성능 개선 가능한 경우 많음.

1 PTX 추가분 5종 1-liner ★

기능핵심 명령
TMA loadcp.async.bulk.tensor.{N}d.shared::cluster.global.mbarrier::complete_tx::bytes
WGMMAwgmma.mma_async.sync.aligned.m64n{N}k{K}.dD.dA.dB
mbarriermbarrier.{init,arrive,expect_tx,try_wait.parity}.shared.b64
Clusterbarrier.cluster.sync, mapa.shared::cluster
Reg redistsetmaxnreg.{inc,dec}.sync.aligned.u32

2 TMA 템플릿

init(bar, 1); fence_init();
expect_tx(bar, BYTES);
cp.async.bulk.tensor(dst, desc, {x,y}, bar);
while(!try_wait_parity(bar, p)){}
p ^= 1;

3 WGMMA 템플릿

wgmma.fence;
wgmma.mma_async.m64n256k16.f32.f16.f16
      {D[0..127]}, descA, descB,
      scaleD, 1, 1, 1, 1;
wgmma.commit_group;
wgmma.wait_group 0;

4 WS skeleton

if (wg == 0) {      // producer
  setmaxnreg_dec(40);
  for(k : K_TILES) {
    wait_empty(k);
    tma_load_A(k);
    tma_load_B(k);   // → bar_full arrive
  }
} else {               // consumer
  setmaxnreg_inc(232);
  for(k : K_TILES) {
    wait_full(k);
    wgmma(acc, sA[k], sB[k]);
    wgmma_wait(1);
    arrive_empty(k);
  }
  epilogue(acc);
}

5 WGMMA shape 요약

m64n{N}k{K}
N ∈ 8·{1..32}, N ≤ 256
K = 16 (F16/BF16) · 32 (FP8/INT8) · 8 (TF32) · 256 (B1)

6 전형 reg 분배

rolereg/T
producer WG40
consumer WG232
cooperative 양쪽160·160

7 SASS 핵심 10선 ★

opcode의미
IMADint MA (addr)
FFMAfloat FMA
HFMA2FP16×2 FMA
LDG.E / STG.Eglobal ld/st
LDS / STSsmem ld/st
LDSMldmatrix
HMMA / GMMATC MMA (sync/async)
UTMALDGTMA load
MBARRIER.*barrier ops
BAR.SYNC__syncthreads

8 함정 7선 ★

  1. -arch=sm_90 ≠ sm_90a (TMA/WGMMA 미생성)
  2. mbarrier init 후 fence 미호출 → UB
  3. TMA descriptor 128B 미정렬 → crash
  4. cluster shape 배수 조건 위반 → launch 실패
  5. WGMMA B operand RF에 두면 컴파일 에러
  6. setmaxnreg 총합 초과 → launch 실패
  7. async proxy fence 누락 → silent 잘못된 결과

9 한 장 요약

TMA가 옮기고 mbar가 알리고 WGMMA가 곱하고 setmaxnreg가 나눈다.

관련 권: V02 HW 정량, V03 Ampere PTX, V06 CUTLASS, V07 FA3. ↗ V02·V03·V06·V07