fix(prep-fused): 리뷰 결함 12건 수정 + PR #224 가 되돌린 EXP-7 복원 (v2, 기본 off) - #226
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> (cherry picked from commit 454efe4)
…% (EXP-8, 기본 off) 이미지 config/vllm.py 의 async_scheduling 자동 판정은 speculative method 이름 허용 목록(eagle 계열, ngram GPU, draft_model, dspark)이라 dflash 부팅은 전부 "Async scheduling not supported with dflash-based speculative decoding and will be disabled" 로 동기 스케줄러를 쓴다. 업스트림 main 도 같다. 기전으로는 이름 문제다: DSparkSpeculator 는 DFlashSpeculator 의 서브클래스로 propose() 를 상속하고(async 가 건드리는 유일한 드래프터 흐름), dspark 는 dsv4 에서 --async-scheduling 으로 서빙 중이며, V2 러너에는 method 별 async 분기가 없다(스케줄러의 [-1] placeholder 를 워커가 combine_sampled_and_draft_tokens 커널로 덮어쓴다). 마운트된 glm53 오버레이 중 스케줄러 쪽 드래프트 id 를 읽는 것은 없다. 새 모듈 glm53_async_dflash 는 플릿 이미지의 config/vllm.py(preimage 2469…)에 hunk 셋: 헬퍼 _deneb_dflash_async_ok(method) 와 두 허용 조건 각각의 `and not _deneb_dflash_async_ok(...)`. 헬퍼는 VLLM_GLM53_ASYNC_DFLASH=1 이고 method 가 dflash 일 때만 True 이며 부팅 로그에 자기 선언. 기본 0 = stock 판정. 파일 전체를 마운트하는 이유는 판정이 프런트엔드·엔진코어 프로세스에서 모델 모듈 import 전에 돌아 우리 훅이 닿지 않기 때문이다. 기대값: 9월 1일 트레이스의 GPU 유휴(입력 준비 ~5.7 + 그래프 제출 1.43 + 스텝 전환 = 스텝의 12%, 프로파일러 없이 ~7%)가 동기 스케줄러가 임계경로에 올린 호스트 시간 전부다 -- 천장 7~12%. glm53_prep_fused 와 독립. 게이트: srv2 의 glm53:v13-b12x 에서 패치 파일 import + 노브 반응 스모크 통과, tests/test_logic.py 41,037 checks. 서빙 미측정 -- EXP-8: 품질 9/9, 한국어 0/16, pos-1 수용률 ±2pct(움직이면 안 됨), C=1 step/s 브래킷, KV in-flight 예약 2배 확인. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 6949cb2)
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>
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
_patched_ms_prepare_attn calls st.plan.tail_ok() without handling its RuntimeError, which can crash the engine instead of DISARMing back to stock.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Restores GLM-5.3 EXP-7 (glm53_prep_fused) and EXP-8 (glm53_async_dflash) overlays after an unintended revert, and applies the confirmed post-review fixes to make the optimizations safer (default-off, preimage-pinned, shadow/self-check + DISARM fallbacks).
Changes:
- Add/restore
glm53_prep_fusedfused decode-step input-prep (Triton) with preimage pinning, eligibility guards, shadow/self-check verification, and offline numerics probe. - Add/restore
glm53_async_dflashopt-in allowlisting sodflashcan use async scheduling when explicitly enabled. - Update profile defaults, manifests, and docs/runbooks/measurements; add logic-contract tests to prevent regressions (incl. EXTRA_ENV lint).
File summaries
| File | Description |
|---|---|
| tests/test_logic.py | Adds contract tests for prep-fused + async-dflash, and lints docs to avoid EXTRA_ENV for profile-declared keys. |
| STEP_KERNEL_MAP.md | Adds supplemental trace breakdown clarifying host-side idle regions and motivation for EXP-7/8. |
| RUNBOOK_KERNEL_CAMPAIGN2.md | Updates arming instructions (caller env, not EXTRA_ENV) and documents EXP-7/EXP-8 ladders. |
| profiles/glm53.env | Mounts new modules and introduces default-off knobs VLLM_GLM53_PREP_FUSED=0, VLLM_GLM53_ASYNC_DFLASH=0. |
| probes/run_prep_fused_check.sh | Adds wrapper to validate overlay base preimages and run the prep-fused probe in a fresh container. |
| probes/prep_fused_check.py | Adds randomized bit-exact numerics + launch/timing probe for prep-fused vs stock building blocks. |
| overlay/modules/glm53_prep_fused/requires | Declares module dependencies for prep-fused overlay. |
| overlay/modules/glm53_prep_fused/README.md | Documents motivation, behavior, guards, and arming ladder for prep-fused. |
| overlay/modules/glm53_prep_fused/manifest.tsv | Declares prep-fused file mount (new file) for overlay composition. |
| overlay/modules/glm53_prep_fused/glm53_prep_fused.py | Implements the fused prep kernel + runner/model-state patching and verification/disarm logic. |
| overlay/modules/glm53_model_wiring/glm5next_model.py | Imports and conditionally installs prep-fused when module is mounted and knob is set. |
| overlay/modules/glm53_async_dflash/requires | Empty dependency declaration file for async-dflash module. |
| overlay/modules/glm53_async_dflash/README.md | Documents async-dflash rationale, changes, gates, and arming instructions. |
| overlay/modules/glm53_async_dflash/manifest.tsv | Declares full-file mount of vllm/config/vllm.py with pinned preimage. |
| overlay/modules/glm53_async_dflash/glm53_config_vllm.py | Adds _deneb_dflash_async_ok() helper and threads it into both async-scheduling allowlist checks. |
| MEASUREMENTS.md | Records EXP-7/8 findings, corrected host-vs-GPU timing, and v2 gate results. |
| build/glm53/manifest.tsv | Adds composed build rows for prep-fused and async-dflash overlays. |
| build/glm53/glm5next_model.py | Built artifact reflecting the wiring hook for prep-fused install. |
| build/glm53/glm53_prep_fused.py | Built artifact copy of prep-fused implementation. |
| build/glm53/glm53_config_vllm.py | Built artifact copy of async-dflash vllm.py overlay. |
Review details
- Files reviewed: 17/20 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.
| md = orig(self, input_batch, cudagraph_mode, block_tables, slot_mappings, | ||
| attn_groups, kv_cache_config, for_capture) | ||
| st.plan.tail_ok() | ||
| st.metadata_cache[key] = md |
| md = orig(self, input_batch, cudagraph_mode, block_tables, slot_mappings, | ||
| attn_groups, kv_cache_config, for_capture) | ||
| st.plan.tail_ok() | ||
| st.metadata_cache[key] = md |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a75da2af9
ℹ️ 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".
| if st.mode != "shadow": | ||
| st.disarm("self-check drift") |
There was a problem hiding this comment.
Disarm shadow mode after detecting drift
When shadow mode detects a mismatch, it returns the stock batch only for the current step but deliberately avoids st.disarm(). If VLLM_GLM53_PREP_FUSED_SHADOW_EVERY is greater than 1, the intervening unchecked steps then resume serving the already-known-bad fused path via the if not check: return fused branch, which can corrupt shadow experiment results. A detected drift should disable the fused path for shadow mode as well.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default 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 4a75da2. Configure here.
리뷰 스윕 지적: tail 그룹 폭 8/행당 블록 1개인데 position 이 ~5000 까지 가서 stock·fused 양쪽이 표 밖 메모리를 읽고 같은 쓰레기를 비교하고 있었다. 프로덕션처럼 그룹마다 cdiv(max_seq, block) 이상을 할당한다. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e7a1d5d6c
ℹ️ 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".
| # them live, but the cached metadata dicts hold views -> rebuild | ||
| st.plan = None | ||
| st.metadata_cache.clear() | ||
| st.plan_failed = False |
There was a problem hiding this comment.
Preserve DISARM across KV-cache wake-up
When an armed self-check drift or fused-launch failure has called st.disarm(), a later sleep-mode KV-cache wake reaches this hook and unconditionally clears plan_failed. The next eligible decode step therefore rebuilds the plan and resumes the known-bad fused path, despite disarm() promising stock behavior for the rest of the boot. Keep the failure state sticky and only invalidate/rebuild plans that were still armed before the wake.
Useful? React with 👍 / 👎.
…라운드는 유지 #230 의 커밋(7a287e0)은 0bd06b7 에서 갈라졌으면서 glm53_prep_fused·glm53_async_dflash· glm53_indexer_gate_splitk 모듈, probes/tools 5개, glm5next_model.py 의 prep-fused 훅, 프로필 MODULES/노브, 테스트 419줄, 원장·RUNBOOK·커널맵 항목을 삭제했다(#224 와 같은 패턴: 오래된 작업 트리로 add -A). 유지한 것 = #230 이 실제로 작성한 것: 메가커널 .cu/README(KDA 2라운드), 테스트의 KDA 계약 2 hunk, 원장 10차 항목. 나머지는 이 브랜치 (0bd06b7 + 리뷰 처리분) 그대로. 41,247 checks OK. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>



왜 이 PR 인가
e76452f, MHC 재구성) 가 커밋 메시지에 언급 없이 18개 파일 변경을 전부 되돌려 main 에서 사라졌습니다. 이 브랜치는 feat(prep-fused): 디코드 입력 준비를 Triton 발사 하나로 (EXP-7, 기본 off) #221 과 feat(async-dflash): dflash 에 async scheduling 허용 (EXP-8, 기본 off) #223 (async-dflash) 을 main 위에 다시 올린 뒤 (cherry-pick), 두 PR 에 대한 10 관점 코드 리뷰 + 검증 14건에서 확인된 결함을 고칩니다. feat(async-dflash): dflash 에 async scheduling 허용 (EXP-8, 기본 off) #223 은 사라진 베이스 위에 스택돼 있어 이 PR 이 대체합니다.확인된 결함과 수정 (전부 검증 CONFIRMED, 상세는 MEASUREMENTS.md EXP-7 리뷰 항목)
prefill_len.gpu/num_blocks.gpu를 캐시했는데 둘은copy_to_uva()마다 다른 풀 버퍼로 재바인딩됩니다 (num_blocks는 매 스텝 회전). 격 스텝마다 stale → 새 블록으로 넘어가는 스텝의 gather 가 한 블록 짧아 어텐션이 잘못된 블록을 읽음 (이미지 코드로 재현). → 발사 시점에 소유 객체에서 읽음.build_plan이 모든 실제 부팅에서 실패, 모듈 inert. → 레이어 소속으로 식별.UvaBufferPool.EXTRA_ENV=명령이 런처에서 ABORT (프로필 선언 키; EXP-6 도 동일) → caller env 형식 + 문서 lint 테스트._load_ptr·PAD_SLOT_ID재사용, 행 복사 2D 브로드캐스트, 와이어링 훅의 ImportError 구분.게이트
tests/test_logic.py41,074 checks OK (신규: 문서 EXTRA_ENV lint, v2 계약).glm53:v13-b12x, 31개 행 preimage 검증): 무작위 배치 60/60 bit-exact (팔 사이에 UVA 핸들 회전 포함), C=1 스텝당 stock 2,469~2,535 us vs fused 152 us (호스트+GPU), 실제 GPU 24.5 us.VLLM_GLM53_PREP_FUSED=shadow bash launchers/start-glm53-nvfp4-tp4.sh(caller env) 로 섀도 부팅 → drift=0 → EXP-7 브래킷. async-dflash 는 EXP-8 그대로.🤖 Generated with Claude Code
Note
High Risk
Changes decode-step input/KV metadata on the hot path with bit-exact contracts; async-dflash doubles in-flight KV batches. Both default off and DISARM on drift, but armed mistakes could corrupt attention block tables or serving behavior.
Overview
Restores EXP-7 (
glm53_prep_fused) and EXP-8 (glm53_async_dflash) after PR #224 reverted them, and hardens the fused prep path from the post–#221 review.EXP-7 adds a Triton
_glm53_prep_fused_kernelplus runner patches (no file overwrites) that fold uniform spec-verify decode prep into one H2D copy, one kernel launch, and deep_gemm schedule metadata. It is gated byVLLM_GLM53_PREP_FUSED(off/shadow/on), pins 17 runner/builder preimages (drift → DISARM), and enforces bit-exact shadow and periodic self-check with stock fallback. Review fixes include reading liveUvaBackedTensorhandles at launch (not cached.gpu), correct drafter KV-group detection,UvaBufferPoolfor idx_mapping under async, power-of-twoQguards, speculator-type gating for metadata cache, invalid env → DISARM, and direct launch of warmup-compiled Triton to cut host dispatch.EXP-8 ships a pinned
glm53_config_vllm.pyoverlay that whitelistsdflashfor async scheduling whenVLLM_GLM53_ASYNC_DFLASH=1, so dflash boots are no longer forced synchronous by method name alone.Docs/runbook: new EXP-7/EXP-8 ladders, trace-driven idle analysis in
STEP_KERNEL_MAP.md/MEASUREMENTS.md, corrected timing notes (host vs ~24µs GPU), and megakernel/prep env examples switched fromEXTRA_ENV=to caller env (launcher aborts profile keys).manifest.tsvadds the new build artifacts;glm5next_model.pyimports and installs prep-fused at model init.Reviewed by Cursor Bugbot for commit 3e7a1d5. Bugbot is set up for automated code reviews on this repo. Configure here.