graph-op ──────────────────── loop-nest
XLA HLO Inductor FX TVM TE/TIR Triton
(coarse) (mid) (fine) (tile)
│ │ │ │
fusion Triton schedule 직접
passes codegen primitive 작성
추상 수준 ↑ → 자동화 ↑, 제어 ↓ / 추상 수준 ↓ → 제어 ↑, 자동화 ↓
| 컴파일러 | 입력 | IR | 타겟 |
|---|---|---|---|
| Triton | Py DSL | TTIR/TTGIR | NV/AMD GPU |
| XLA | JAX/TF | HLO/StableHLO | GPU/TPU/CPU |
| TVM | Relay/ONNX | Relay→TE→TIR | GPU/CPU/FPGA/μC |
| Inductor | FX graph | Aten IR+Loop IR | GPU(Triton)/CPU(C++) |
StableHLO = HLO의 portable subset (2023+)
| 컴파일러 | 주된 사용자 | 조직 |
|---|---|---|
| Triton | kernel 작성자 | OpenAI → LF |
| XLA | JAX/TF 프레임워크 | Google · OpenXLA |
| TVM | 배포·edge·연구 | Apache |
| Inductor | PyTorch 사용자 | Meta |
JAX / TF graph │ (tracing, jaxpr → StableHLO) ▼ StableHLO (portable) │ (legalize) ▼ HLO (XLA internal) │ (HLO passes: §3) ▼ GPU backend (LLVM + Triton emitters) │ ▼ cubin / PTX
dot, convolution, reduce, broadcast, dynamic-slice).
shape는 정적이 원칙 (dynamic op은 제한적).
send/recv 제외)f32[128,256] 등)| 카테고리 | 대표 op |
|---|---|
| Elementwise | add·mul·exp·tanh |
| Reduce | reduce·reduce-window |
| Contraction | dot·convolution |
| Shape | reshape·broadcast·transpose |
| Data movement | gather·scatter·slice |
| Control | while·conditional·call |
| Collective | all-reduce·all-gather·reduce-scatter |
collective는 SPMD partitioner가 삽입 ↗ V15 §1
jax.jit(f)
└─ tracing (abstract vals)
└─ jaxpr (JAX IR)
└─ jaxpr → StableHLO
└─ XLA compile
└─ PjRt executable
// f(x) = softmax(x) along dim 1
HloModule softmax
ENTRY main (x: f32[B,N]) -> f32[B,N] {
x = f32[B,N] parameter(0)
mx = f32[B] reduce(x, max, dim=1)
bx = f32[B,N] broadcast(mx, {0})
sh = f32[B,N] subtract(x, bx)
e = f32[B,N] exponential(sh)
s = f32[B] reduce(e, add, dim=1)
bs = f32[B,N] broadcast(s, {0})
ROOT y = f32[B,N] divide(e, bs)
}
@jax.jit + PartitionSpec → sharding 주석 HLO실제 collective·topology는 V15에서 상세
| 규칙 | 예시 |
|---|---|
| identity | x·1 → x, x+0 → x |
| fold const | reshape(const) → const' |
| slice(concat) | slice가 가리키는 one operand 선택 |
| reshape chain | 연속 reshape 병합 |
| broadcast sink | elementwise 앞으로 이동 |
| transpose fold | dot dimension 숫자 재지정 |
수십 개 규칙을 fixed-point로 반복 적용
lhs_contracting minor인 layout 선호| 종류 | 설명 |
|---|---|
| kLoop | elementwise chain fusion |
| kInput | reduce + elementwise 앞 |
| kOutput | elementwise epilogue |
| kCustom | Triton / cuDNN 등 external emitter |
Fusion decision은 cost model 기반: reuse, register pressure 추정
StableHLO→HLO → SimplifyReshape → AlgSimplifier (fixpoint) → LayoutAssignment → HloCSE / DCE → FusionPipeline → HloScheduler → BufferAssignment → GPU emitter (LLVM+Triton)
fused HLO ──► GPU emitter 선택 │ ├─ LLVM emitter (loop) │ ├─ Triton emitter (softmax/attn) │ ├─ cuBLAS call (dot) │ └─ cuDNN call (conv/attn) ▼ cubin + host 코드
| HLO op | 선호 라이브러리 |
|---|---|
| dot (GEMM) | cuBLASLt · cuBLAS |
| convolution | cuDNN |
| fused attention | cuDNN FA / Triton |
| batched dot | cuBLASLt batched |
XLA_FLAGS=--xla_gpu_autotune_level=N으로 조절while·cond 지원cf. PyTorch CUDA Graph ↗ V13 §10
donate_argnums → in-place 재사용Client → Device → Buffer → Executable| 상황 | 경로 |
|---|---|
| 대규모 dot | cuBLASLt |
| conv | cuDNN |
| softmax·LN | Triton emitter |
| elementwise chain | LLVM loop emitter |
| decode graph | Command Buffer |
Relay / Relax ◄── graph IR
│ (op split, partition, quant)
▼
TE (Tensor Expression)
│ compute + schedule
▼
TIR (Tensor IR)
│ block-based low IR
▼
LLVM / CUDA / ROCm / Metal / C
codegen
nn.conv2d·nn.dense·add. shape polymorphism.
C = compute(def_of_matmul) ← WHAT s = schedule(C) ← HOW s[C].split(i, 32) s[C].bind(io, "blockIdx.x") ... codegen(s, "cuda") → CUDA C
Halide 2012에서 유래 · §11
| 타겟 | codegen |
|---|---|
| NV GPU | CUDA C / NVRTC |
| AMD GPU | ROCm / HIP |
| CPU | LLVM IR |
| Apple | Metal |
| Edge/μC | microTVM / C |
| WebGPU | WGSL |
본 권은 NV GPU만 다룸 (spec §Out-of-scope)
| 축 | XLA | TVM |
|---|---|---|
| IR 계층 | HLO 1층 | 3층 (Relay/TE/TIR) |
| 스케줄 | 암시적 (pass) | 명시적 (primitive) |
| 프론트엔드 | JAX/TF | ONNX/PyTorch |
| 타겟 | GPU/TPU/CPU | GPU/CPU/Edge 등 |
import tvm from tvm import te n = te.var("n") A = te.placeholder((n,), name="A") B = te.placeholder((n,), name="B") C = te.compute( (n,), lambda i: A[i] + B[i], name="C")
M, N, K = te.var("M"), te.var("N"), te.var("K") A = te.placeholder((M, K), "A") B = te.placeholder((K, N), "B") k = te.reduce_axis((0, K), name="k") C = te.compute( (M, N), lambda i, j: te.sum(A[i, k] * B[k, j], axis=k), name="C")
| 종류 | 의미 |
|---|---|
| Spatial | output 위치 loop (i, j) |
| Reduce | 축약되는 loop (k) |
| Ordered | 순서 있는 외부 loop |
| Thread | bind된 thread/block index |
dy = te.reduce_axis((0, Kh)) dx = te.reduce_axis((0, Kw)) dc = te.reduce_axis((0, IC)) O = te.compute( (B, OC, Oh, Ow), lambda b, oc, h, w: te.sum( X[b, dc, h*sh+dy, w*sw+dx] * W[oc, dc, dy, dx], axis=[dc, dy, dx]))
s = te.create_schedule(C.op)로 시작.
| 계층 | 표현 |
|---|---|
| TE | Tensor (abstract, shape만) |
| TIR | Buffer (address, stride, scope) |
TE → TIR lowering 시 buffer 생성 + load/store 구체화
| primitive | 효과 | 용도 |
|---|---|---|
| split | 1 loop → 2 loop (factor) | tile, vectorize 준비 |
| fuse | 2 loop → 1 loop | bind 단순화 |
| reorder | loop 순서 교체 | locality, reuse |
| bind | loop → thread/block idx | GPU 실행축 지정 |
| cache_read | producer 전에 shared buffer 삽입 | smem tile load |
| cache_write | consumer 이후 register/shared buffer | register blocking |
| compute_at | stage를 다른 stage 안으로 이동 | fusion, locality |
| compute_inline | stage를 사라지게 inline | elementwise 축약 |
| tensorize | inner loop → HW intrinsic | mma, wmma, tensor core |
| vectorize | loop → SIMD / vector ld | float4 load 등 |
| unroll | loop 풀어쓰기 | ILP, 상수 addr |
| parallel | CPU multi-thread (참고) | CPU target |
s = te.create_schedule(C.op) i, j = C.op.axis k, = C.op.reduce_axis # tile outer io, ii = s[C].split(i, factor=64) jo, ji = s[C].split(j, factor=64) ko, ki = s[C].split(k, factor=8) s[C].reorder(io, jo, ko, ii, ji, ki)
# GPU mapping s[C].bind(io, te.thread_axis("blockIdx.y")) s[C].bind(jo, te.thread_axis("blockIdx.x")) s[C].bind(ii, te.thread_axis("threadIdx.y")) s[C].bind(ji, te.thread_axis("threadIdx.x"))
threadIdx.x는 연속 mem dim에 bind.
AA = s.cache_read(A, "shared", [C]) BB = s.cache_read(B, "shared", [C]) s[AA].compute_at(s[C], ko) s[BB].compute_at(s[C], ko)
# 16x16x16 mma 대응 intrinsic 등록 후
s[C].tensorize(ii, wmma_sync_intrin)
cf. CUTLASS의 mma 직접 호출 ↗ V06 §3
before after compute_at(s[B], s[C], ko)
for i, j: for i, j:
for ko: for ko:
B[i,j,ko] = ... B[i,j,ko] = ... ← 여기서 생성
C[i,j] = f(B, ...) ...
C[i,j] = f(B, ...)
B의 live-range가 ko 안으로 축소 → buffer 작아짐
TE (compute + schedule) │ lower (ScheduleOps, StorageFlatten, ...) ▼ TIR (PrimFunc) │ pass: VectorizeLoop, InjectDoubleBuffer, ... ▼ codegen (LLVM / CUDA)
@T.prim_func def matmul(A: T.Buffer((M,K), "float32"), B: T.Buffer((K,N), "float32"), C: T.Buffer((M,N), "float32")): for i, j, k in T.grid(M, N, K): with T.block("C"): vi, vj, vk = T.axis.remap("SSR", [i,j,k]) with T.init(): C[vi, vj] = 0.0 C[vi, vj] += A[vi, vk] * B[vk, vj]
T.init(): reduction 초기화 블록| 속성 | 의미 |
|---|---|
| shape·strides | 다차원 view |
| dtype | float32/f16/int8 |
| scope | global · shared · local · wmma.* |
| elem_offset | base offset (align) |
| kind | 표기 |
|---|---|
| Spatial | S |
| Reduce | R |
| Opaque | O |
| Scan / Ordered | — (드물게) |
analyzer가 dependency·parallelizability 판단에 사용
T.call_intrin(...): HW 전용 호출tvm_mma_sync, tvm_load_matrix_sync (wmma)@autotvm.template("matmul") def matmul(M, N, K, dtype): cfg = autotvm.get_config() # knob 선언 cfg.define_split("tile_i", M, num_outputs=2) cfg.define_split("tile_j", N, num_outputs=2) cfg.define_knob("unroll", [0, 1, 2]) # schedule 적용 io, ii = cfg["tile_i"].apply(s, C, i) ...
matmul 기준 보통 103~106 포인트. grid search 비현실적.
┌──────────────┐
│ Cost model │◄── feature ← schedule
│ (XGBoost) │
└───┬──────┬───┘
│ │ predict best K configs
│ ▼
│ ┌───────────┐
│ │ Measurer │ real run on GPU
│ └────┬──────┘
│ │ (time)
│ record
└──── update model
| feature | 의미 |
|---|---|
| loop extent | outer/inner trip count |
| ann type | unroll/vectorize/thread |
| stride | mem access 규칙 |
| touched bytes | 총 load/store 양 |
| 알고리즘 | 특징 |
|---|---|
| GridSearchTuner | 작은 공간 |
| RandomTuner | baseline |
| XGBTuner | model 기반 UCB |
| GATuner | evolutionary |
compute def (TE) │ rule-based sketch gen ▼ Sketch 집합 ← 추상 skeleton │ annotation ▼ 구체 schedule │ evolutionary search + cost model ▼ best schedule
| 방식 | 공간 | 사람 노력 |
|---|---|---|
| Halide auto | 좁음 | 낮음 |
| AutoTVM | 중간 | template 작성 |
| Ansor | 넓음 | compute만 |
| Meta Schedule | Ansor+block기반 | compute만 |
population P (candidate schedule들) ┌───────────────────────────┐ │ mutate + crossover │ │ cost_model.predict │ │ select top-K │ │ measure top-K on GPU │ │ update cost_model │ └───────────────────────────┘
generation 수십~수백, 측정 수만 trial 가능
// algorithm Func blur; Var x, y; blur(x, y) = (in(x-1,y) + in(x,y) + in(x+1,y)) / 3; // schedule blur.split(x, xo, xi, 8) .vectorize(xi) .parallel(y);
| Halide | TVM |
|---|---|
| Func | compute/stage |
| Var | iter_var (spatial) |
| RDom | reduce_axis |
| split/reorder | split/reorder |
| compute_at / store_at | compute_at |
| vectorize / parallel | vectorize / parallel |
Halide (2012)
├─► TVM (2018) — compute/sched DSL
├─► Polymage / Tiramisu
├─► Exo
└─► Triton (tile-level, 2021)
↑ 개념적 차이: 사용자는
이미 "tile"이 schedule임
| 세대 | 방법 |
|---|---|
| Mullapudi'16 | heuristic cost |
| Adams'19 | ML cost model (tree) |
| Anderson'21 | + feature fusion |
TVM Ansor의 직접 선조 아이디어
for i = 0..N-1:
for j = 0..i:
A[i,j] = f(i,j)
Ω = 삼각형 영역
j
│ ●
│ ● ●
│ ● ● ●
└────── i
| 변환 | S 변화 |
|---|---|
| interchange | (i,j) → (j,i) |
| skewing | (i,j) → (i+j, j) |
| tiling | (i,j) → (i/B,j/B,i%B,j%B) |
| reversal | (i,j) → (-i, j) |
| fusion | 두 schedule의 lex 결합 |
2i + 3j + 5는 affine. i*j는 아님.
affine dialect ★affine.for, affine.if, affine.load/store, affine.apply(d0,d1) -> (d0+d1, d0)scf/llvm/GPUaffine.for %i = 0 to %N { affine.for %j = 0 to (%i + 1) { %v = affine.load %A[%i, %j] : memref<?x?xf32> affine.store %v, %B[%j, %i] : memref<?x?xf32> } }
for t in 0..T:
for i in 1..N-1:
A[t+1,i] = A[t,i-1]+A[t,i]+A[t,i+1]
d1=(1,-1), d2=(1,0), d3=(1,1)
t축 tiling 불가 (d1 t+ but i-)
skew (t, i) → (t, i+t):
새 dep = (1,0),(1,1),(1,2) → fully permut
→ time-tile 가능 (locality ↑)
| 툴 | 타겟 | 설명 |
|---|---|---|
| PPCG | CUDA | polyhedral → CUDA C |
| Polly | LLVM IR | loop opt |
| MLIR affine | GPU·CPU | 모듈식 polyhedral |
| Tiramisu | 다양 | scheduling + polyhedral 혼합 |
| 기준 | Triton | XLA |
|---|---|---|
| 추상 수준 | tile DSL | graph (HLO) |
| 사용자 제어 | 높음 | 낮음 |
| 최적화 자동성 | 중 (autotune) | 높음 (passes) |
| GPU 성숙도 | NV高 · AMD中 | NV高 · TPU高 |
| 프론트엔드 | Py DSL | JAX / TF |
| IR 계층 | TTIR→TTGIR | HLO 1층 |
| Fusion | tile 내부 | graph pass |
| Auto-tune | config sweep | algo picker |
| 생태계 | OpenAI · LF | OpenXLA · JAX |
| Hopper 지원 | sm_90 · TMA | Triton emitter |
| 기준 | TVM | Inductor |
|---|---|---|
| 추상 수준 | Relay/TE/TIR 3층 | FX graph + Loop IR |
| 사용자 제어 | 중~높음 (수동 sched) | 낮음 |
| 최적화 자동성 | 높음 (MetaSched) | 높음 |
| GPU 성숙도 | 중 | NV高 |
| 프론트엔드 | ONNX / Relay | PyTorch / Dynamo |
| IR 계층 | 3층 | Aten + Loop IR |
| Fusion | op + schedule | scheduler + codegen |
| Auto-tune | AutoTVM·Ansor | heuristic + Triton tune |
| 생태계 | Apache · edge | Meta · PyTorch |
| Hopper 지원 | 제한적 | Triton 경유 |
| 툴 | 결정자 |
|---|---|
| XLA | cost model + rule |
| TVM | Relay pattern + schedule |
| Inductor | scheduler (group ops) |
| Triton | 사용자가 tile 내부에서 결합 |
| 방법 | 샘플 효율 | 전제 |
|---|---|---|
| Grid | 낮음 | 공간 작음 |
| Random | 낮음~중 | baseline |
| Bayesian | 중~높음 | 부드러운 함수 |
| Evolutionary | 중 | 조합/이산 |
| RL | 가변 | 많은 data |
| Cost model | 높음 | feature 가능 |
Ansor·Meta Schedule은 이 경로 기본
실제로는 build 병렬화·cache가 절대 필요
넓이 ┐ ┌ 좋은 해 포함
│ optimal │
│ coverage ↑ │
│ │
└─────────────────┘
탐색 ↑ 비용·시간 ↑
| 성질 | 의미 |
|---|---|
| 직교성 | primitive가 독립 차원 |
| 합성성 | 순서·조합 가능 |
| 안전성 | correctness 불변 |
| 관찰성 | feature 추출 가능 |
TVM schedule primitive는 대체로 이 성질 만족
START: 어떤 모델/커널인가?
│
├─ 프레임워크가 PyTorch?
│ ├─ Yes → Inductor (기본) ──► 부족하면 Triton
│ │ (↗ V13 §2)
│ └─ No
│ │
├─ 프레임워크가 JAX / TF?
│ ├─ Yes → XLA (기본) ──► 특수 pattern은 Triton emitter
│ └─ No
│ │
├─ multi-backend 배포 (CPU/GPU/Edge)?
│ ├─ Yes → TVM (Relax + Meta Schedule)
│ └─ No
│ │
├─ custom kernel 최고 성능이 목표?
│ └─ Triton (또는 CUTLASS/CuTe ↗ V06)
│
└─ 연구: 자동 tiling·polyhedral 탐구
└─ MLIR affine + Pluto/PPCG
| 상황 | 답 |
|---|---|
| JAX 학습 | XLA |
| PyTorch 학습·추론 | Inductor → Triton |
| vLLM/TRT 외 직접 kernel | Triton/CUTLASS |
| ONNX 서빙 multi-target | TVM |
| edge/μC | microTVM |
| 새 HW 타겟 연구 | MLIR + TVM |
| 기호 | 의미 |
|---|---|
| Ω | iteration domain |
| A | access relation |
| S | schedule (affine) |
| D | dependence |