feat(async-dflash): dflash 에 async scheduling 허용 (EXP-8, 기본 off) - #223
Conversation
…% (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>
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.
🔵 Needs a closer look
It introduces a pinned full-file overlay of a core vLLM config and enables a non-trivial scheduling-mode change (even if opt-in), with serving validation explicitly still pending.
Pull request overview
Adds an opt-in overlay to allow vLLM async scheduling for the dflash speculative method in the GLM-5.3 fleet image, while keeping default behavior unchanged (VLLM_GLM53_ASYNC_DFLASH=0). This is implemented by extending the existing method-name allowlist logic in vllm/config/vllm.py via a pinned full-file overlay, with documentation and contract tests to guard the intended behavior.
Changes:
- Add
glm53_async_dflashoverlay module that conditionally allowlistsmethod="dflash"for async scheduling whenVLLM_GLM53_ASYNC_DFLASH=1, with a one-time boot log marker. - Wire the new module and default knob into
profiles/glm53.env, plus update runbook/measurements documentation for EXP-8. - Add a contract test (
test_glm53_async_dflash_contracts) validating default-off behavior, allowlisting behavior, and manifest pinning.
File summaries
| File | Description |
|---|---|
| tests/test_logic.py | Adds contract checks for the new async-dflash allowlisting behavior and overlay pinning. |
| RUNBOOK_KERNEL_CAMPAIGN2.md | Documents EXP-8 procedure, expected effects, and gating checks for enabling async scheduling on dflash. |
| profiles/glm53.env | Adds glm53_async_dflash to MODULES and introduces default-off VLLM_GLM53_ASYNC_DFLASH=0 knob with guidance. |
| overlay/modules/glm53_async_dflash/requires | Adds module requirements file (empty = no dependencies). |
| overlay/modules/glm53_async_dflash/README.md | Documents rationale, implementation details, arming/rollback, and operational watchouts. |
| overlay/modules/glm53_async_dflash/manifest.tsv | Pins the base preimage for vllm/config/vllm.py and declares the overlay mapping. |
| overlay/modules/glm53_async_dflash/glm53_config_vllm.py | Full pinned copy of vllm/config/vllm.py with _deneb_dflash_async_ok() and allowlist gating in VllmConfig.__post_init__. |
| MEASUREMENTS.md | Records the motivation and expected ceiling for EXP-8 and how the overlay implements it. |
| build/glm53/manifest.tsv | Adds the built overlay entry for vllm/config/vllm.py to the composed manifest set. |
| build/glm53/glm53_config_vllm.py | Built copy of the overlaid vllm/config/vllm.py used by the build artifact. |
Review details
- Files reviewed: 7/10 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6949cb2880
ℹ️ 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".
| ```bash | ||
| # 부팅 로그에서 "[async-dflash] ... whitelisted" 가 있고 "Async scheduling not | ||
| # supported" 가 없어야 켜진 것이다 (engine-confirmed 원칙). | ||
| EXTRA_ENV="VLLM_GLM53_ASYNC_DFLASH=1" bash launchers/start-glm53-nvfp4-tp4.sh # cand |
There was a problem hiding this comment.
Pass the profile knob directly when arming
This documented candidate command always aborts before starting a container because VLLM_GLM53_ASYNC_DFLASH is declared in profiles/glm53.env, while the launcher's EXTRA_ENV validation explicitly rejects profile-declared keys at launchers/start-glm53-nvfp4-tp4.sh:340-351. Consequently, operators following EXP-8 can never enable or test this otherwise-default-off feature; use VLLM_GLM53_ASYNC_DFLASH=1 bash ... instead and update the identical command in the module README.
Useful? React with 👍 / 👎.
| logger.warning_once( | ||
| "[async-dflash] VLLM_GLM53_ASYNC_DFLASH=1: dflash whitelisted for async " | ||
| "scheduling (DSparkSpeculator is a DFlashSpeculator and shares propose())" | ||
| ) |
There was a problem hiding this comment.
Log whitelisting only after async scheduling is enabled
When the knob is set for dflash, this warning is emitted as soon as the method allowlist is passed, but VllmConfig.__post_init__ can still disable async scheduling afterward for disable_padded_drafter_batch, an unsupported executor, or ROCm DeepEP at lines 1236-1258. The new runbook treats this message and the absence of the method-specific warning as confirmation that the candidate is active, so one of those configurations can be measured as an async candidate while actually running synchronously; emit the confirmation only after the final async_scheduling = True decision or explicitly report the resolved state.
Useful? React with 👍 / 👎.
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_async_dflash: 플릿 이미지config/vllm.py의 async scheduling 허용 목록에dflash를 opt-in 으로 추가한다 (VLLM_GLM53_ASYNC_DFLASH=1). 기본 0 이면 stock 판정 그대로.스택된 PR: base 는 #221 (
feat/glm53-prep-fused). 두 변경은 독립이고 각각 노브가 있다.왜
draft_model·dspark.dflash가 없어 모든 dflash 부팅이 동기 스케줄러를 쓴다.DSparkSpeculator는DFlashSpeculator의 서브클래스로propose()를 상속하고, dspark 는 dsv4 에서 async 로 서빙 중이다. V2 러너에 method 별 async 분기는 없다. 마운트된 glm53 오버레이 중 스케줄러 쪽 드래프트 id 를 읽는 것은 없다.7%) 가 GPU 유휴이고 전부 호스트 시간 (입력 준비, 그래프 제출 1.43 ms, 스텝 전환) 이다. async 는 그것을 이전 스텝의 GPU 실행 뒤로 숨긴다. **천장 712%**, 이 캠페인 최대 단일 레버.변경 (hunk 3개)
헬퍼
_deneb_dflash_async_ok(method)와 두 허용 조건 각각의and not _deneb_dflash_async_ok(...). 켜지면 부팅 로그에[async-dflash] ... whitelisted가 찍히고 "Async scheduling not supported" 가 사라진다. preimage 는 manifest 에 고정.게이트
glm53:v13-b12x안에서 패치 파일 import + 노브 1/unset 반응 확인.python3 tests/test_logic.py41,037 checks OK (test_glm53_async_dflash_contracts).EXTRA_ENV="VLLM_GLM53_ASYNC_DFLASH=1"부팅, 품질 9/9, 한국어 0/16, pos-1 수용률 ±2pct (움직이면 안 됨), C=1 step/s 브래킷. V2+async 는max_concurrent_batches=2 라 KV in-flight 예약이 두 배 → KV 라인 먼저 확인.🤖 Generated with Claude Code
Note
Medium Risk
Opt-in scheduling change can alter timing and double KV in-flight under V2+async; default-off limits blast radius, but serving validation is still pending per EXP-8.
Overview
Adds EXP-8 documentation and the
glm53_async_dflashoverlay so dflash speculative decoding can use vLLM async scheduling whenVLLM_GLM53_ASYNC_DFLASH=1(default off).Stock
config/vllm.pyonly auto-enables async for eagle/ngram GPU/draft_model/dspark by method name, so dflash boots stay synchronous despite sharing the same drafter flow as dspark. The overlay mounts a pinned fullvllm.pywith_deneb_dflash_async_ok()andand not _deneb_dflash_async_ok(...)on both async-scheduling compatibility checks inVllmConfig.__post_init__, plus a one-time boot log when whitelisted.build/glm53/manifest.tsvrecords the preimage for drift detection.MEASUREMENTS.md and RUNBOOK_KERNEL_CAMPAIGN2.md describe the hypothesis (~7–12% step time from overlapping host prep/graph submit with GPU), launch via
EXTRA_ENV, and gates (quality, acceptance ±2%, C=1 bracket, KV withmax_concurrent_batches=2).Reviewed by Cursor Bugbot for commit 6949cb2. Bugbot is set up for automated code reviews on this repo. Configure here.