feat(prep-fused): 디코드 입력 준비를 Triton 발사 하나로 (EXP-7, 기본 off) - #221
Conversation
…P-7) 9월 1일 트레이스(rank 3, 229 스텝)를 스트림 합집합으로 다시 읽으면 스텝의 12%(8.9 ms/72 ms, 프로파일러 없이 4~5 ms)가 GPU 유휴이고, 그 자리가 드래프터 그래프와 타깃 그래프 사이의 eager 입력 준비다: prepare_inputs + prepare_attn + KV 그룹 7개의 메타데이터 빌더가 스텝마다 aten ~1,000 호출, memcpy 45, 1~3 us 커널 ~100개를 내고 dflash 는 스케줄러가 동기라 그 시간 내내 GPU 가 빈다. 새 모듈 glm53_prep_fused 는 균일 spec-verify 스텝(전 요청 드래프트 7개, FULL 그래프, 요청 패딩 없음)에서 그 구간 전체를 pinned H2D 1회 + Triton 발사 1회 + deep_gemm 스케줄 1회로 접는다. 러너 파일은 덮지 않고 메서드를 패치하며, 설치 시 러너/빌더 파일 17개의 preimage 를 고정하고(드리프트 -> DISARM), plan 은 캡처 직후 live 러너에서 만들어 커널을 미리 컴파일한다. 메타데이터 dict 는 형상별 캐시(FULL 리플레이는 버퍼만 읽고, dict 는 드래프터에 넘어가 무시된다). 계약은 stock 버퍼와 bit-exact: shadow 모드는 fused 뒤에 stock 을 같은 버퍼에 돌려 전부 diff 하고 stock 이 진실이다. 오프라인 게이트(srv4 새 컨테이너, probes/run_prep_fused_check.sh): 프로덕션 기하의 무작위 배치 60/60 이 46개 텐서 bit-exact, C=1 스텝당 빌딩블록 2,556 us -> 201 us(커널 88 + deep_gemm 스케줄 64). 서빙 수치는 없다 -- 섀도 부팅 drift=0 뒤 EXP-7 브래킷. 기본값 0. 부수 발견은 원장에: kpool tail 원형 매핑이 positions 미전달로 잠들어 있음(C>=2 수치 축), 인덱서 fp32 head-gate gemmSN 86 us x 11층, 드래프터 커널 합 ~3 ms 와 D≈0 의 긴장. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
🟡 Changes recommended
A couple of verified issues (brittle regex in the new logic test and unsafe argument handling in the new probe wrapper script) should be addressed before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an EXP-7 “prep fused” overlay module for GLM-5.3 that collapses the decode-step host-side input/attention/KV-metadata preparation into a single pinned H2D copy + single Triton kernel launch (+ deep_gemm schedule), guarded by strict eligibility checks and a kill-switch (VLLM_GLM53_PREP_FUSED, default off) with shadow diffing and preimage drift DISARM.
Changes:
- Introduces
overlay/modules/glm53_prep_fused(kernel + runner patching + preimage drift guard) and wires installer intoglm53_model_wiring. - Adds offline numerics/launch-count probe (
probes/prep_fused_check.py+ wrapper script) and a logic-level contract test intests/test_logic.py. - Updates runbook/measurement/kernel-map documentation and enables mounting the module in
profiles/glm53.envwhile keeping it disabled by default.
File summaries
| File | Description |
|---|---|
| tests/test_logic.py | Adds a contract test validating wiring, env knobs, preimage pins, and key kernel invariants. |
| STEP_KERNEL_MAP.md | Documents updated trace decomposition and where prep-fused fits. |
| RUNBOOK_KERNEL_CAMPAIGN2.md | Adds EXP-7 operational ladder (logic → probe → shadow boot → bracket). |
| profiles/glm53.env | Mounts glm53_prep_fused and ships VLLM_GLM53_PREP_FUSED=0 default. |
| probes/run_prep_fused_check.sh | Wrapper to run the offline probe in a fresh container with full overlay mounts. |
| probes/prep_fused_check.py | Offline bit-exact verification + timing comparison between stock blocks and fused kernel. |
| overlay/modules/glm53_prep_fused/requires | Declares dependent overlays the module was read/tested against. |
| overlay/modules/glm53_prep_fused/README.md | Explains trace findings, behavior, guards, and arming procedure. |
| overlay/modules/glm53_prep_fused/manifest.tsv | Binds the new module file into the container at the vLLM model path. |
| overlay/modules/glm53_prep_fused/glm53_prep_fused.py | Implements Triton kernel, plan building, eligibility gating, shadow diffing, and runtime patching. |
| overlay/modules/glm53_model_wiring/glm5next_model.py | Imports and conditionally runs installer (stock-safe when absent / off). |
| MEASUREMENTS.md | Records the trace-driven rationale and offline probe results for EXP-7. |
| build/glm53/manifest.tsv | Adds built artifact entry for glm53_prep_fused.py. |
| build/glm53/glm5next_model.py | Mirrors wiring change in the composed build output. |
| build/glm53/glm53_prep_fused.py | Mirrors the module source in the composed build output. |
Review details
- Files reviewed: 15/15 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| --mount "type=bind,src=$REPO,dst=/repo,readonly" \ | ||
| "${envs[@]}" \ | ||
| "${mounts[@]}" \ | ||
| "$IMAGE" -lc "python3 /repo/probes/prep_fused_check.py $*" _ "$@" |
| profile = open(os.path.join(REPO, "profiles", "glm53.env"), encoding="utf-8").read() | ||
| modules = re.search(r'^MODULES="([^"]+)"', profile, re.M).group(1).split() |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 454efe4a7b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try: | ||
| from .glm53_prep_fused import install_glm53_prep_fused | ||
| except ImportError: | ||
| install_glm53_prep_fused = None |
There was a problem hiding this comment.
Distinguish missing module from failed module imports
When the mounted module exists but one of its transitive imports raises ImportError—for example after a vLLM/Triton API change—this handler treats it exactly like an absent optional file, emits no log, and leaves an explicitly enabled VLLM_GLM53_PREP_FUSED boot on the stock path. That can invalidate shadow or armed experiment results despite the stated fail-loud contract; only suppress the error when the missing name is the sibling module itself, and log or propagate other import failures.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 454efe4. Configure here.
| except Exception: | ||
| st.plan_failed = True | ||
| logger.exception("[prep-fused] plan build failed -> stock path for this boot") | ||
| return False |
There was a problem hiding this comment.
Recoverable plan failure permanently disarms
Medium Severity
build_plan raises when indexer_decode_block_table_buffer is still None, and _eligible latches that into plan_failed for the whole boot. That buffer is allocated only later, inside the indexer's first decode build(), which runs after prepare_inputs. Any eligible capture or live step that hits this ordering then skips the post-capture rebuild, so VLLM_GLM53_PREP_FUSED=1 stays on the stock path even after the buffer exists.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 454efe4. Configure here.
PR #221 은 09:46Z 머지됐으나 PR #224(e76452f) 가 언급 없이 18개 파일 변경을 전부 되돌려 main 에서 사라졌다. 이 브랜치는 #221·#223 을 main 위에 다시 올리고 (cherry-pick), 10 관점 리뷰 + 검증 14건에서 확인된 결함을 고친다. CONFIRMED 결함과 수정: - plan 이 prefill_len.gpu / num_blocks.gpu 를 캐시: 둘은 UvaBackedTensor 라 copy_to_uva() 마다 라운드로빈 풀의 다른 버퍼로 재바인딩된다(num_blocks 는 매 스텝 apply_staged_writes 로 회전). 격 스텝마다 한 스텝 stale -> 새 블록으로 넘어가는 스텝에 gather 가 한 블록 짧아 어텐션이 잘못된 블록을 읽음. 이미지 코드로 재현. 수정: 소유 객체(BlockTables, UvaBackedTensor)를 plan 에 두고 발사 시점에 .gpu / 포인터 텐서를 읽는다(wake-up 재생성도 자동 반영). - 드래프터 KV 그룹(7번째)에 타깃 쪽 FlashInfer 빌더가 붙어 있어 build_plan 이 모든 실제 부팅에서 실패 -> 모듈 inert. 수정: 드래프터 그룹을 레이어 소속 (draft_attn_layer_names / draft_kv_cache_group_ids)으로 식별해 gather+slot 만. - pinned 스테이징 버퍼 1개 재사용이 async scheduling 아래에서 이전 스텝 DMA 와 경합(GB10 재현). 수정: 이미지의 UvaBufferPool(동시 배치 수 라운드로빈). - Q 가 2의 거듭제곱이 아니면 tl.arange 컴파일 실패가 첫 적격 스텝에서 엔진을 죽임. 수정: plan 가드, warmup 실패 DISARM, 발사 예외 시 stock 폴백. - shadow 가 stock 배치를 반환해 armed 분기를 한 번도 실행 안 함. 수정: fused 뒤 stock 사슬 전체(prepare_inputs·gather/slot·빌더)를 돌려 diff 하고 깨끗하면 fused 배치를 흘린다; armed 도 64 fused 스텝마다 self-check, drift 면 DISARM. - kpool tail 원형 버퍼 휴면을 가정만 함. 수정: plan 생성·검증마다 assert. - 메타데이터 캐시는 dflash 가 dict 를 무시할 때만 안전. 수정: speculator 타입 게이트. - 노브 오타가 arm 으로. 수정: 0/off/false/no, shadow, 1 만 인정, 나머지 DISARM. - 런북·README 의 EXTRA_ENV="VLLM_GLM53_..." 는 프로필 선언 키라 런처가 ABORT (EXP-6 도 동일). 수정: caller env 형식 + 문서 lint 테스트. - 프로브 래퍼가 preimage 검증 없이 전 행을 마운트(fi618 위에 v13 오버레이 5개). 수정: 런처와 같은 base contract 검증, 프로필 이미지 기본. - "88/64 us GPU" 는 호스트 발사 시간(실제 커널 ~23 us). 원장·README 정정, 하네스는 CUDA 그래프 리플레이로 GPU 시간을 잰다. - warmup 이 돌려주는 컴파일 커널로 직접 발사(Triton 디스패처 ~12 us/스텝 절감, 검증에서 bit-exact); _load_ptr·PAD_SLOT_ID 재사용; 행 복사 2D 브로드캐스트; 와이어링 훅은 "미마운트" 와 "모듈 내부 ImportError" 를 구분해 후자를 로그. 오프라인 게이트(srv2, glm53:v13-b12x, 31개 행 preimage 검증): 무작위 배치 60/60 bit-exact(UVA 핸들 회전 포함), C=1 스텝당 stock 2,469 us vs fused 184 us (호스트+GPU), 실제 GPU 24.4 us(그래프 리플레이). tests/test_logic.py 통과. 서빙 미측정: EXP-7 섀도 부팅 -> 브래킷. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PR #221 은 09:46Z 머지됐으나 PR #224(e76452f) 가 언급 없이 18개 파일 변경을 전부 되돌려 main 에서 사라졌다. 이 브랜치는 #221·#223 을 main 위에 다시 올리고 (cherry-pick), 10 관점 리뷰 + 검증 14건에서 확인된 결함을 고친다. CONFIRMED 결함과 수정: - plan 이 prefill_len.gpu / num_blocks.gpu 를 캐시: 둘은 UvaBackedTensor 라 copy_to_uva() 마다 라운드로빈 풀의 다른 버퍼로 재바인딩된다(num_blocks 는 매 스텝 apply_staged_writes 로 회전). 격 스텝마다 한 스텝 stale -> 새 블록으로 넘어가는 스텝에 gather 가 한 블록 짧아 어텐션이 잘못된 블록을 읽음. 이미지 코드로 재현. 수정: 소유 객체(BlockTables, UvaBackedTensor)를 plan 에 두고 발사 시점에 .gpu / 포인터 텐서를 읽는다(wake-up 재생성도 자동 반영). - 드래프터 KV 그룹(7번째)에 타깃 쪽 FlashInfer 빌더가 붙어 있어 build_plan 이 모든 실제 부팅에서 실패 -> 모듈 inert. 수정: 드래프터 그룹을 레이어 소속 (draft_attn_layer_names / draft_kv_cache_group_ids)으로 식별해 gather+slot 만. - pinned 스테이징 버퍼 1개 재사용이 async scheduling 아래에서 이전 스텝 DMA 와 경합(GB10 재현). 수정: 이미지의 UvaBufferPool(동시 배치 수 라운드로빈). - Q 가 2의 거듭제곱이 아니면 tl.arange 컴파일 실패가 첫 적격 스텝에서 엔진을 죽임. 수정: plan 가드, warmup 실패 DISARM, 발사 예외 시 stock 폴백. - shadow 가 stock 배치를 반환해 armed 분기를 한 번도 실행 안 함. 수정: fused 뒤 stock 사슬 전체(prepare_inputs·gather/slot·빌더)를 돌려 diff 하고 깨끗하면 fused 배치를 흘린다; armed 도 64 fused 스텝마다 self-check, drift 면 DISARM. - kpool tail 원형 버퍼 휴면을 가정만 함. 수정: plan 생성·검증마다 assert. - 메타데이터 캐시는 dflash 가 dict 를 무시할 때만 안전. 수정: speculator 타입 게이트. - 노브 오타가 arm 으로. 수정: 0/off/false/no, shadow, 1 만 인정, 나머지 DISARM. - 런북·README 의 EXTRA_ENV="VLLM_GLM53_..." 는 프로필 선언 키라 런처가 ABORT (EXP-6 도 동일). 수정: caller env 형식 + 문서 lint 테스트. - 프로브 래퍼가 preimage 검증 없이 전 행을 마운트(fi618 위에 v13 오버레이 5개). 수정: 런처와 같은 base contract 검증, 프로필 이미지 기본. - "88/64 us GPU" 는 호스트 발사 시간(실제 커널 ~23 us). 원장·README 정정, 하네스는 CUDA 그래프 리플레이로 GPU 시간을 잰다. - warmup 이 돌려주는 컴파일 커널로 직접 발사(Triton 디스패처 ~12 us/스텝 절감, 검증에서 bit-exact); _load_ptr·PAD_SLOT_ID 재사용; 행 복사 2D 브로드캐스트; 와이어링 훅은 "미마운트" 와 "모듈 내부 ImportError" 를 구분해 후자를 로그. 오프라인 게이트(srv2, glm53:v13-b12x, 31개 행 preimage 검증): 무작위 배치 60/60 bit-exact(UVA 핸들 회전 포함), C=1 스텝당 stock 2,469 us vs fused 184 us (호스트+GPU), 실제 GPU 24.4 us(그래프 리플레이). tests/test_logic.py 통과. 서빙 미측정: EXP-7 섀도 부팅 -> 브래킷. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>




무엇
overlay/modules/glm53_prep_fused: GLM-5.3 디코드 스텝의 호스트 쪽 입력 준비 구간(prepare_inputs+prepare_attn+ KV 그룹 7개 빌더, 스텝당 aten ~1,000 호출 · memcpy 45 · 커널 ~100)을 pinned H2D 1회 + Triton 발사 1회 + deep_gemm 스케줄 1회로 접는다. 균일 spec-verify + FULL 그래프 + 요청 패딩 없음일 때만 적용, 나머지는 stock.왜
9월 1일 트레이스 재분석: 스텝의 12%(8.9 ms/72 ms, 프로파일러 없이 4
5 ms)가 GPU 유휴이고 그 대부분이 이 구간이다(dflash 가 async scheduling 을 끄므로 호스트 준비가 임계경로). 그래프 안 elementwise 글루 605개 전체(2.7 ms, CUPTI)보다 크다. 천장 = 준비 구간 자체, 스텝의 46%. STEP_KERNEL_MAP 보충 분해 2 참조.안전장치
VLLM_GLM53_PREP_FUSED=0;shadow= fused 뒤 stock 을 같은 버퍼에 돌려 전부 diff(stock 이 진실);1= arm.glm53:v13-b12x+ 마운트된 tail 인덱서), 드리프트 → DISARM 로그.게이트
python3 tests/test_logic.py41,009 checks OK (test_glm53_prep_fused_contracts포함).glm53:sm121-fi618,IMAGE=... bash probes/run_prep_fused_check.sh --trials 60): stock 빌딩블록 vs fused, 프로덕션 기하 무작위 배치 60/60 bit-exact(46 텐서); C=1 스텝당 빌딩블록 2,556 us → 201 us(커널 88 + deep_gemm 스케줄 64).EXTRA_ENV="VLLM_GLM53_PREP_FUSED=shadow",[prep-fused] shadow ... drift=0) → RUNBOOK EXP-7 브래킷(C=1 step/s). 플릿 부팅은 운영자 결정.부수 발견(미조치, 원장 기록)
kpool tail 원형 슬롯 매핑이
positions미전달로 잠들어 있음(C>=2 수치 축); 인덱서 fp32 head-gatetorch.mmgemmSN 2블록 86 us × 11층(glm53_prefill_fastpath.py:402소유); 드래프터 커널 합 ~3 ms(CUPTI) 와 원장 D≈0 의 긴장.🤖 Generated with Claude Code
Note
Medium Risk
Patches the decode-step input and KV metadata path that CUDA graphs consume; wrong buffers would break inference, though eligibility gates, shadow bit-exact checks, and preimage DISARM keep it off by default until validated.
Overview
Adds
glm53_prep_fused(EXP-7) to collapse the host-heavy gap between drafter and target CUDA graphs—prepare_inputs,prepare_attn, and seven KV metadata builders—into one pinned H2D copy, one_glm53_prep_fused_kernelTriton launch, and the existing deep_gemm schedule metadata, for uniform spec-verify steps on FULL cudagraph with no request padding.Integration patches
GPUModelRunner/MambaHybridModelState(no runner file overwrites), builds aPrepPlanfrom live buffers after capture, caches attention metadata per shape, and arms only whenVLLM_GLM53_PREP_FUSEDis set (shadowruns fused then stock and diffs buffers; default 0 inprofiles/glm53.env). 17 runner/builder preimages must match or install DISARMs to stock.Also ships offline proof (
probes/prep_fused_check.py/run_prep_fused_check.sh),test_glm53_prep_fused_contracts, module overlay manifest, and runbook/measurement/kernel-map notes for the ~4–6% step ceiling; serving bracket still pending after clean shadow boot.Reviewed by Cursor Bugbot for commit 454efe4. Bugbot is set up for automated code reviews on this repo. Configure here.