큰 그림
- Layer.emit / Model.add
- Builder 에 value 와 Op 쌓음
- 여기서 CUDA 호출에 필요한 불변 정보를 emitter 가 미리 쌓음
- compile_cuda
- Builder - lower_ir_cuda 로 LoweredOp 생ㅅ어
- make_exec_plan_cuda 로 런타임 결정을 담은 ExecPlan 생성
- CudaExecutor.run / run_compiled
- feed 로 들어온 tensor 를 value 슬롯에 bind / alloc
- plan.alias 적용
- plan.lowered 순서대로 _C.op_call 실행
- 선택적으로 CUDA Graph capture / replay 로 반복 실행 최적화
1) IR 생성 단계 Layer - Builder
Model.add 가 하는 일
- model.add
- layer.emit 호출
여기서 ctx 는 backend 별 emitter 컨텍스트 용도
Builder 에 쌓이는 데이터
Value
- 생성 위치 : Builder.input / param / state / value
- 저장 필드
- vid : 정수 id
- name : 디버그 / 출력 키에 쓰임
- spec : TensorSpec(shape, dtype, device)
- role : input | param | state | tmp | output
- producer_op, users : 그래프 연결 정보
이 Value 는 런타임 슬롯 테이블의 인덱스가 된다.
Op ( 연산 노드 )
- 생성 위치
- 저장 필드
- kind : 문자열
- inputs : in_vids
- outputs : out_vids
- attrs : 사람이 읽기쉬운 dict
- constraints / hints / saved : 플래너 / 트레이닝 정책 힌트
- emitter-first 캐시
- kind_id : C++ enum OpKind 와 일치하는 int
- attrr_schema : ABI 구분자
- attr_blob : 커널에 넘길 packed bytes
2) Emitter-first : emitters / cuda 가 채우는 불변 호출 스펙
emitter 가 실제로 채우는 것
각 emitter 의 패턴
- 입력 / 출력 vid 구성은 layer 가 결정
- emitter 는 다음을 완성
- kind_id
- attr_schema
- attr_blob
Builder.emit 을 호출하면서 Op.kind_id, attr_schema, attr_blob 를 함께 저장
3) Compile 단계 : Builder(IR) - ExecPlan
3.1 compile_cuda
b0 = m.b
b1 = optimize_ir(b0) # 현재 identity
lowered = lower_ir_cuda(b1) # emitter-first: serialize only
plan = make_exec_plan_cuda(b1, lowered)
plan = optimize_plan(plan) # 현재 identity
return CompiledProgram(plan)
3.2 lower_ir_cuda
- 입력 : Builder.ops
- 출력 : List[LowerdOp]
각 op 에서
- op.kind_id, op.attr_schema, op.attr_blob 필수
LoweredOp 구조
- kind_id, attr_schema, attr_blob
- in_vids, out_vids
- constraints 전달
lower 는 이제 커널 호출 스펙을 런타임 형태로 옮기는 단계
3.3 make_exec_plan_cuda
- 입력
- builder
- lowered ops
- 출력
- execplan
- inplace 가능 같은 constraints 기반으로
- out_vid 가 in_vid 슬롯을 그대로 쓰도록 alias 결정을 담음
4) Runtime 단계 : ExecPlan 실행 ( Eager )
bind_and_alloc_slots
입력
- Builder
- feed : Dict[str, torch.Tensor]
출력
- slots : List[torch.Tensor]
동작 개념
- externals 은 feed 에서 가져옴
- tmp / output 은 spec 기반으로 새로 alloc
- contig() 정책 처리
plan.alias 적용
for out_vid, in_vid in plan.alias.items():
slots[out_vid] = slots[in_vid]
out_vid 는 별도 텐서가 아닌 in_vid 와 동일한 storage 를 참조할수 있음
lowered 실행
for lop in plan.lowered:
ins = [slots[v] for v in lop.in_vids]
outs = [slots[v] for v in lop.out_vids]
op_call(lop.kind_id, ins, outs, lop.attr_schema, lop.attr_blob, stream)
실제로 backend 에 전달되는 최종 스펙
- kind_id
- attr_schema
- attr_blob
- ins / outs
5) CUDA Graph 경로 : capture + replay
cache key
- (mode, plan_key, static_roles, copy_roles, feed_signature)
- externals 이름 + shape, dtype, device 포함
- contig 은 제외
capture 정책
- static_roles 캡처 중 고정 슬롯으로 유지할 role
- ingerence
- train
- copy_roles : replay 마다 feed 에서 복사해 업데이트할 role
- inference 기본 : input
- train 기본 : input
replay 보안 성질
train 모드에서 replay 시
- feed 로 w/step 을 바꿔도 무시됨
- 오직 input 만 매 replay 반영
- 그래서 step 은 계속 증가하고, w 는 reset 되지 않음
'AI Compiler framework' 카테고리의 다른 글
| lower / optimize_plan 제거 파이프 라인 (0) | 2026.02.03 |
|---|---|
| AICF v2 실행 파이프라인 - 함수 단위 호출 트레이스 (0) | 2026.02.03 |
| Layer 내부에서의 emit 정의 및 사용 방식의 변경, 사전 정의 op emitter 의 생성으로 lower_ir_cuda 의 기능 축소, 전체 로직 간편화 (0) | 2026.02.02 |
| compile 파이프 라인과 lower_ir_cuda 에서의 registry 탐색 ( b.ops 와 사전 정의한 registry 와의 매칭 (0) | 2026.02.02 |
| CUDA Graph Capture / Replay 설계 정리 (0) | 2026.02.01 |