feat(qwen35): add opt-in SM120 FlashInfer GDN prefill - #862
Conversation
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8c88c6c9c4
ℹ️ 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".
| git rev-parse HEAD | ||
| git status --short -- pegainfer-qwen35 |
There was a problem hiding this comment.
Validate the benchmark's actual source tree
When Stage 9 is run from a working checkout, this records the current commit but neither compares it with PEGAINFER_STAGE9_COMMIT nor checks changes outside pegainfer-qwen35. In particular, edits under pegainfer-kernels—which contains the candidate CUDA kernel and FFI—are compiled while remaining invisible in the provenance log, so results can be attributed to a clean commit that did not produce them. Validate the supplied commit against git rev-parse HEAD and reject or capture the complete dirty tree before benchmarking.
Useful? React with 👍 / 👎.
| _require_equal(artifact.get("size_bytes"), len(data), "artifact size") | ||
| _require_equal(artifact.get("sha256"), sha256_bytes(data), "artifact hash") |
There was a problem hiding this comment.
Pin the standalone validator to the candidate PTX
When a generated, downloaded, or copied bundle is checked without --flashinfer-dir as documented, this only verifies that the manifest's hash matches its accompanying bytes. A modified PTX can therefore be accepted after recomputing the artifact and bundle hashes; even source-assisted validation does not bind those instructions to the pinned source. The Rust loader later rejects such a bundle using its hard-coded candidate hash, making the advertised validation produce a false success. Check the pinned release PTX hash here as well.
Useful? React with 👍 / 👎.
| Run source and host-side contract checks without CuTe: | ||
|
|
||
| ```bash | ||
| python3 pegainfer-kernels/tools/flashinfer_gdn/artifact_contract.py verify-source |
There was a problem hiding this comment.
Initialize the pinned submodule before verification
On a fresh checkout whose FlashInfer submodule has not been initialized, this documented first command fails: git -C pegainfer-kernels/third_party/flashinfer rev-parse HEAD walks up to the parent repository and reports its unrelated commit as a FlashInfer SHA mismatch. Initialize/update the pinned submodule before this command or make verify-source detect and initialize the missing gitlink; the documented command was reproduced failing in that context.
AGENTS.md reference: AGENTS.md:L136-L137
Useful? React with 👍 / 👎.
| @@ -0,0 +1,100 @@ | |||
| # FlashInfer GDN SM120 artifact generation | |||
There was a problem hiding this comment.
Add the required model-line decision record
This commit introduces a large Qwen3.5 backend candidate, artifact contract, accuracy gates, and benchmark workflow, but records it only in a tool-local README; no relevant docs/models/qwen35/ document or docs/index.md route is created or updated. Add the model-line task/decision record so the rationale, validation status, blockers, and next action remain discoverable under the repository's required documentation workflow.
AGENTS.md reference: AGENTS.md:L160-L164
Useful? React with 👍 / 👎.
|
Thanks for exploring this direction. I think keeping the FlashInfer CuTe DSL kernel is reasonable: if we AOT-compile it, the serving runtime can avoid Python, Triton, JIT compilation, and JIT cache management. The main change I would suggest is to simplify the integration boundary before expanding the candidate further. Today, Could we reshape the PR around this smaller end-to-end boundary?
This keeps the useful CuTe kernel and the goal of removing Triton from serving, while giving the runtime a boundary we can maintain. |
|
Thanks, this makes sense. I’ll reshape the PR around the smaller integration boundary you suggested |
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
|
Thanks — the new C ABI boundary is a substantial improvement. One remaining request is scope reduction. The PR is still +6,711 lines across 43 files, and much of that is staged diagnostics and benchmark infrastructure rather than the production integration itself. Please keep this PR focused on the production wrapper/dispatch, one reproducible generation path, and the essential end-to-end correctness/performance checks. The stage7/stage13 diagnostics, ABBA harnesses, and additional research scaffolding can move to follow-up PRs or external artifacts. That would make the runtime change much easier to review and maintain without losing the useful validation work. |
|
Following the review feedback, I have completed the integration-boundary refactor and production-path validation for the SM120 FlashInfer GDN prefill candidate. The review requested that the FlashInfer CuTe kernel remain AOT-compiled while moving all generated CuTe/PTX/TMA details out of
The supported single-GPU SM120 Qwen3.5-4B Hv32 case is now connected to production dispatch, while unsupported capabilities explicitly retain the Triton fallback. Invalid artifact/ABI/hash/geometry combinations fail validation rather than silently executing an incompatible kernel. Serving-path validationThe serving path was also tested with an empty environment and with PTX JIT disabled. Real inference completed successfully using the embedded native CUBIN and statically linked runtime, without requiring Python, Triton JIT, FlashInfer Python, or the CuTe compiler at serving time. Cross-machine validationI validated the refactored code on two RTX 5090 machines:
Both machines used CUDA Toolkit 12.8 and the same source commit, FlashInfer submodule, generator, patch, and pinned package versions. Each machine generated its object reproducibly within that machine, but the object hashes differed across machines. Both objects were exactly 291,336 bytes and passed the complete correctness suite. This validates the runtime ABI and numerical behavior, while bitwise cross-machine artifact reproducibility remains an open build-boundary issue. CorrectnessOn both machines, the Hv32 production candidate passed:
Production dispatch selected FlashInfer, and the successful-launch counters increased as expected, confirming that the tests did not silently fall back to Triton. The production HF short replay also remained stable across machines:
The broader HF comparison against the same oracle remains:
FlashInfer therefore has a slightly better overall error distribution, although it is not uniformly better on every tail metric. The non-production Hv48/T128 result is unchanged: FlashInfer has five localized state-tail violations versus two for Triton. The A/B attribution continues to show that these originate from the upstream FlashInfer kernel rather than the PegaInfer HKV layout patch. PerformanceMachine 1 completed a 15-case same-production-path ABBA matrix covering:
FlashInfer won TTFT p50 in 14/15 cases and throughput in 12/15 cases. The case-level geometric-mean improvements were:
One case, T2048/c8, regressed by 1.95% in TTFT p50 and 2.59% in throughput. In that profile, the FlashInfer GDN operator was 7.94% slower despite reducing the GDN launch count by 3×. Machine 2 repeated representative cases:
On Machine 2, the earlier c8 regression did not reproduce: T2048/c8 was effectively at parity. Nsight Systems measured FlashInfer GDN GPU time as:
Scratch allocation remains approximately 48.52 MiB for FlashInfer versus 184.50 MiB for Triton, a 73.70% reduction. The c8 traces show that per-launch FlashInfer time remains stable, while the current single-sequence operation is repeated once per sequence. Based on this analysis, the next optimization directions are multi-sequence batching and native-prepare optimization. The existing Triton capability fallback and Hv48 diagnostic scope remain unchanged while the maintainers decide the final release and distribution policy. After the optimization work is complete, I will also clean up the PR itself by removing the staged diagnostic tooling, benchmark infrastructure, and other temporary research scaffolding that is not required for the production integration. The goal is to keep the final PR focused and minimal, preserving only the production integration, reproducible generation path, and essential correctness/performance validation needed for long-term maintainability. |
…fer-gdn-sm120-pr Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
…fer-gdn-sm120-pr # Conflicts: # pegainfer-qwen35/tests/serving_tp2.rs Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
|
Following the review feedback, I have completed the integration-boundary refactor, scope reduction, native-prepare optimization, and production-path validation for the SM120 FlashInfer GDN prefill candidate. Current integration boundaryThe integration now follows this path:
The supported single-GPU SM120 Qwen3.5-4B Hv32 case is connected to production dispatch. Unsupported capabilities explicitly retain the Triton fallback. If an eligible FlashInfer configuration selects an invalid, incomplete, or ABI-incompatible artifact, validation fails instead of silently executing another kernel. The README now documents the complete reproducible local path:
PR scope reductionThe PR has been reduced from 43 files and approximately 6,711 added lines to 34 files and approximately 3.7k added lines. The stage7/stage13 harnesses, ABBA infrastructure, profiling scripts, generated artifacts, logs, benchmark JSON, and other temporary research scaffolding have been removed. The remaining scope is limited to:
Serving validationThe serving path was tested with an empty environment and again with PTX JIT disabled. Real inference completed using the embedded native CUBIN and statically linked runtime, without requiring Python, Triton JIT, FlashInfer Python, or the CuTe compiler at serving time. Cross-machine validationThe refactored implementation was validated on two RTX 5090 machines:
Both used CUDA Toolkit 12.8 and the same source commit, FlashInfer submodule, generator, patch, and pinned package versions. Generation was bitwise reproducible when repeated on the same machine. The objects differed across machines, although both were exactly 291,336 bytes and passed the complete correctness suite. The runtime ABI and numerical behavior are therefore validated, while cross-machine bitwise artifact reproducibility remains an open build/distribution question. CorrectnessThe Hv32 production candidate passed:
Production tests reported: and successful-launch counters increased as expected, confirming that the tests did not silently fall back to Triton. The latest final gate on commit
The broader comparison against the same HF oracle remains:
FlashInfer has a lower mean error in four of five replay surfaces and a lower maximum error in four of five, but a lower p99 in only two of five. It is slightly better overall, but not uniformly better on every tail metric. The non-production Hv48/T128 investigation remains unchanged: FlashInfer has five localized final-state tail violations versus two for Triton. Patched-HKV versus upstream-HVK A/B testing produced identical results after layout conversion, attributing these violations to the upstream kernel rather than the PegaInfer HKV patch. PerformanceMachine 1 completed a 15-case same-production-path ABBA matrix covering FlashInfer won:
The case-level geometric-mean results were:
The T2048/c8 case regressed by 1.95% in TTFT p50 and 2.59% in throughput. In that trace, the FlashInfer GDN operator was 7.94% slower despite reducing the GDN launch count by approximately 3×. Machine 2 repeated representative cases:
The earlier c8 regression did not reproduce on Machine 2; T2048/c8 was effectively at parity. Nsight Systems measured FlashInfer GDN GPU time as:
FlashInfer scratch allocation is approximately 48.52 MiB versus 184.50 MiB for Triton, a 73.70% reduction. The native Hv32 prepare optimization was also validated independently. Relative to the previous production implementation, the ABBA means were:
The optimization therefore provides a small, consistent improvement without changing the selected artifact or production numerical gates. Multi-sequence batching remains a follow-up and is not part of the current PR. Maintainer decisions still neededThe remaining policy and scope decisions are:
The current implementation keeps the conservative Triton capability fallback and retains the Hv48 diagnostic path until these decisions are made. |
|
The test suite is still broader than the production confidence it buys. I suggest reducing it around five meaningful gates:
Several micro-tests can be deleted or collapsed without reducing confidence: Most importantly, the high-value GPU tests are all ignored, while the Python contract tests are not wired into GitHub CI. Current CI therefore does not prove that the SM120 production path can build, link, and launch. Replacing the mocked artifact micro-tests with one real production-boundary integration gate would reduce the diff and increase confidence. |
|
Thanks, I learned a lot from this review. I’ll simplify the test coverage further and add a real integration gate that exercises the production path end to end, so the tests actually demonstrate that the SM120 path can build, link, launch, and produce correct results. Thanks again for the thoughtful review and guidance! |
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
|
This pass reduces the boundary-cleanup diff by 409 net lines (
ValidationAll five required gates passed on SM120 for this exact commit and the newly generated candidate:
|
|
I approved and ran the full CI workflow for the current head. It is not merge-ready yet:
Both CUDA compile jobs and the CPU/format/metadata/sim-E2E jobs pass. Please fix the four Clippy findings, sign the commits, and rerun the complete workflow; once it is fully green, we can merge. |
…fer-gdn-sm120-pr Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
…fer-gdn-sm120-pr Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
40f038d to
9f6073d
Compare
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
FeathBow
left a comment
There was a problem hiding this comment.
Thanks for the thorough work on the AOT boundary. I am requesting changes because the current head changes production behaviour in ways the submitted gates do not cover.
On SM120/Hv32/TP1, a normal Qwen3.5 build links no GDN bundle but model loading still requires one, so the documented clean build cannot start. The FlashInfer prefill path also performs a stream-wide host synchronization after each request chunk, which removes most of the existing Shared-SM overlap. The five-gate runner uses overlap-off and does not retain the reported upstream-HVK versus patched-HKV differential.
Please make the candidate explicitly selectable unless a trusted bundle is distributed, remove the host barrier from normal serving, and validate those two boundaries on the exact production path. The backend also needs to be selected before KV budgeting, and the build must enforce the complete artifact contract.
The patch can be smaller: keep the project-owned ABI, native-prepare oracle, continuation check, and existing HF/scheduler E2E; remove the validation-only counters and public API, duplicate backend-specific gates, upstream alias/separate test path, dead helper, and process-history comments. Please also restore the scheduler-level chunked-prefill E2E, which the new private model test does not replace.
| unsafe { ffi::pegainfer_qwen35_gdn_abi_version() } == QWEN35_GDN_ABI_VERSION, | ||
| "Qwen3.5 GDN stable C ABI version mismatch" | ||
| ); | ||
| ensure!( |
There was a problem hiding this comment.
This makes the bundle a startup requirement. A normal Qwen3.5 build links only the unavailable stub, but every SM120/Hv32/TP1 model load reaches this check and fails. Neither the repository nor the v0.1.1 release provides the bundle, while the README describes it as optional.
Please either ship a trusted bundle through the release build or select FlashInfer only when it is explicitly enabled. Without that selection, the existing Triton path should remain unchanged.
| )?; | ||
| } | ||
|
|
||
| if let GdnPrefillChunkScratch::FlashInfer(resources) = &gdn_scratch { |
There was a problem hiding this comment.
This check performs a status D2H followed by ctx.sync() after all linear layers. launch_async_prefill() cannot record its event or continue decode until this returns, so most Shared-SM overlap is lost. A batch also repeats the barrier for each request chunk.
Please remove the finite-status path from normal serving and remeasure FlashInfer with Shared-SM enabled.
| prefill::tests::flashinfer_gdn_chunk_continuation_and_model_outputs_match \ | ||
| -p pegainfer-qwen35 --features qwen35,gdn-validation --lib | ||
|
|
||
| run_exact_gate \ |
There was a problem hiding this comment.
Gate 5 starts the default overlap-off scheduler, so these five gates cannot catch the stream barrier above. The separate Shared-SM E2E checks correctness and lifecycle, not GPU overlap, and this runner does not execute it.
The state checks also compare only the same patched artifact. The reported upstream-HVK versus patched-HKV parity is not reproducible from this runner. Please retain exact-head evidence for FlashInfer + Shared-SM overlap and for the upstream-to-patched layout conversion.
|
|
||
| // The first production specialization is deliberately single-GPU. | ||
| // TP remains an explicit capability fallback to the existing Triton path. | ||
| let flashinfer_gdn = if geometry.world_size() == 1 { |
There was a problem hiding this comment.
The KV pool has already been sized here using GdrChunkwiseScratch35::estimate_bytes(). FlashInfer therefore still loses KV pages to the larger Triton reserve and can fail the earlier memory check even when its actual scratch would fit.
Please reserve the peak memory of the selected backend.
| }); | ||
| let manifest: serde_json::Value = serde_json::from_slice(&manifest_bytes) | ||
| .unwrap_or_else(|error| panic!("parse GDN AOT manifest: {error}")); | ||
| assert_eq!(json_u64(&manifest, &["schema_version"]), 3); |
There was a problem hiding this comment.
This block does not bind the source lock, toolchain, dtypes, or Q/K/V/output views. The file hashes are also read from the same supplied manifest. Normal cargo build does not run the fuller Python validator, and that validator does not check the view fields either.
A self-consistent but incompatible bundle can therefore link with the wrong tensor contract. Please validate the complete frozen production contract before linking it.
| name = "sampling_behavior" | ||
| required-features = ["qwen35"] | ||
|
|
||
| [[test]] |
There was a problem hiding this comment.
This test forces resumed prefill through EngineHandle and a small scheduler budget. The new test calls private prefill_chunk_forward() directly, so it does not cover scheduler admission, request events, or the real scheduler chunk boundary and is not a replacement.
|
|
||
| [features] | ||
| default = [] | ||
| gdn-validation = ["qwen35"] |
There was a problem hiding this comment.
This feature adds counters and hooks across the model, graph, executor, and scheduler, plus a public test-only constructor and duplicate FlashInfer-only HF/E2E tests. The existing HF and scheduler gates already use the normal model loader and exercise the selected backend.
Please remove this feature and keep backend identity at the production startup boundary.
| assert_stable_c_struct_layout(); | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
Production always launches in place, while this test adds a separate-state wrapper only to compare two modes of the same upstream artifact. That tests upstream aliasing and expands the project ABI without a production caller. please remove upstream tests.
| #[cfg(feature = "gdn-validation")] | ||
| use crate::weights::Qwen35Model; | ||
|
|
||
| // Stage 18 measured the real-model FP32 recurrent-state partition floor at |
There was a problem hiding this comment.
The Stage 18/19 chronology is tuning history rather than a code invariant. This file also adds three tests for an unchanged private position helper; the public scheduler E2E already covers context rejection, and the usize::MAX case is unreachable from the request boundary.
Please remove the history and those unrelated helper tests. Keep the recurrent-state and logits continuation checks.
|
I really appreciate the careful review and the detailed code-level analysis. The issues you identified are clear, and I agree that the current gates do not fully cover the production behavior changed by this PR. I’ll address them as follows:
Thank you again for taking the time to review this so thoroughly! |
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Restore the original three-argument executor API and move the existing HF gate into a private test module. Keep shared fixtures loaded once and fix test-only Clippy findings without changing production behavior or golden tolerances. Integrate main scheduler and documentation changes, update HF entry points, and document the explicit FlashInfer GDN boundary and workload-dependent tradeoffs. Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
|
This PR integrates an opt-in FlashInfer GDN prefill backend into the actual Qwen3.5 serving path. Triton remains the default, including when a candidate bundle is linked. The candidate supports SM120, TP1 and Hq/Hk/Hv/D = 16/16/32/128, validated with Qwen3.5-4B. Changes following review
ValidationThe final runtime/test source was validated on RTX 5090 with Qwen3.5-4B: release build, affected-package all-targets Clippy, short/long HF, Shared-SM lifecycle, and real default/explicit-candidate HTTP requests. The candidate HTTP check consumed 20,000 input tokens and generated eight output tokens. Existing real-bundle, native-prepare oracle, upstream/patched layout, continuation and positive-overlap evidence retains its original source identities. Earlier same-binary, unprofiled ABBA on |
xiaguan
left a comment
There was a problem hiding this comment.
Thank you for the substantial cleanup and for retaining the measured evidence. The direct-parent Shared-SM A/B completed 12,288/12,288 requests and reports +0.64% to +2.39% paired throughput on the retained workloads, while also documenting the tail-latency regression. My remaining concerns are about making the candidate identity and acceptance gates fail closed.
-
Qwen35GdnAot::artifact_sha256()currently converts a null C pointer to"unavailable"and invalid UTF-8 to"invalid-utf8".load_for_production()does not validate the queried identity, so an explicitly selected candidate can finish loading and serve with only a sentinel in the startup log. Please make this query fallible, validate the 64-character hexadecimal SHA during construction, and store the validated identity inQwen35GdnAot. A broken artifact-identity ABI should reject model loading. -
The candidate acceptance tests do not encode candidate selection themselves.
tests/common::gdn_backend()silently defaults to Triton whenPEGAINFER_TEST_QWEN35_GDN_BACKENDis absent, so the HF, scheduler, and Shared-SM exact tests can pass without loading the candidate. The canonical shell runner sets the variable and checks the startup hash, which is helpful, but direct execution of the named tests is still a false positive for candidate coverage. Please give the candidate acceptance path an explicit candidate requirement and assert the validated artifact identity from the loaded model/engine. -
The HF provenance check has another silent-success path: when
model_revision()cannot resolve a revision,check_fixture_metadata()returnsfalseand four tests return normally, which Cargo reports as passed. The runner's log scan catches this in the canonical script, but the tests themselves remain green without validating the pinned model artifact. Please make an unresolved revision an error for these acceptance tests.
The real-layout gate's exact SHA comparison does reject the two sentinel strings, so this is not a claim that that specific gate is bypassed. The issue is that the runtime constructor and the other directly runnable acceptance tests do not preserve the same invariant.
Reject malformed runtime artifact identities before loading the candidate and retain the validated SHA in the existing GDN wrapper. Require explicit candidate selection, the loaded model's artifact identity and a resolved HF model revision in the existing acceptance scenarios. Keep candidate setup in private test modules and linker fault injection in its dedicated test executable. Reuse the existing numerical scenarios and tolerances, and update their gate and documentation entry points. Validation: returned RTX 5090 evidence covers five runtime identity rejections, seven admission rejections, candidate/default production HTTP, six model acceptance scenarios and release all-targets Clippy. Local fmt, Bash syntax, ShellCheck and diff checks pass; the committed source matches the returned source manifest. Two short-HF regret failures preceded a pass with identical inputs; retain them as unresolved numerical instability. This local checkpoint precedes numerical diagnostics and adds no such diagnostic helpers or generated evidence to the source tree. Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
Preserve main's TP geometry, decode graph and scheduler policy behavior while retaining explicit GDN selection and the fail-closed candidate acceptance. Keep the original executor API and all acceptance setup in private test modules. Validation: tree c923500 completed 19 RTX 5090 acceptance stages with one attempt each: real build/link/load/HTTP, strict Clippy, artifact and identity rejection, layout/native prepare, short/long HF, continuation and scheduler/Shared-SM lifecycle with measured graph overlap. Source and returned evidence hashes match; formatting and locked metadata pass. The earlier configuration-dependent short-HF regression remains unresolved. No diagnostic helpers, numerical workaround, threshold changes or generated evidence are included. Historical performance retains its original source identity; the complete hosted workflow must run on the submitted head. Signed-off-by: qwzx-qwas <zzzt8047@gmail.com>
66e1365 to
1bceb20
Compare
|
Thank you for the careful review, particularly for identifying the silent-success paths in artifact identity and candidate acceptance. Following your latest review, I have added three changes:
The negative cases exercise the existing constructor and acceptance entries before the positive scenarios. Test setup remains private, and identity fault injection is confined to a single test executable. No production injection hook or additional public testing API was introduced. During validation, two candidate short-HF runs failed at the same padded-decode position: seq 3 / pos 2 selected token 67, whose HF regret is 0.25 nat against the unchanged 0.20 limit. The third run and subsequent direct reruns passed. The latest main-integrated tree also passed all 19 acceptance stages, including short/long HF, real build/load/HTTP, layout and prepare checks, continuation, scheduler lifecycle, and actual Shared-SM overlap. These passes do not resolve the earlier failure. The isolated investigations narrowed the issue. Fixed GEMM configurations reproduced the candidate failure with the two sensitive projection split-K settings at 9/9, while Triton at 9/9 and the candidate at 16/16 passed. Real-input GDN replay found prefill-state differences. With identical decode-entry state, changing the controlled GEMM configuration still changed the outcome; the first captured differences appeared in the shared decode b/a projections. Both backends use the same decode operators. My strongest suspicion is an interaction between prefill-state differences, shared split-K rounding, and final BF16 logit materialization. For the failing hidden vector, FP64 projection gives logits of 11.14099662 and 11.11763134 for tokens 692 and 67, respectively. Both round to BF16 11.125, matching the GPU result, and the sampler selects 67. The observed GEMM recipes also store split-K partial results in BF16 despite requesting FP32 computation. This is a concrete precision lead, but its individual contribution has not been isolated, and a unique FlashInfer kernel defect has not been established. No production fix has been implemented for this numerical issue. I have not hardcoded the passing split-K configuration, changed tie-breaking, relaxed the HF threshold, or promoted diagnostic helpers into this PR. Triton remains the default backend. |
xiaguan
left a comment
There was a problem hiding this comment.
Thank you for addressing the previous review. At 1bceb209, constructor identity validation, explicit candidate selection on the actual tested model, and rejection of unknown model revisions are all fixed.
The reported historical A/B at aa9ce155 measured +0.64–2.39% throughput, with a +35% median TPOT regression in one c8 pair and SSE-gap p99 increasing from 44.8 to 292.2 ms. These are synthetic-prompt results from an earlier tree, not current-head performance evidence; SSE gaps are not token ITL. The PR appropriately limits those claims.
I am requesting changes for the unresolved numerical failure and the remaining implementation/test-harness complexity.
-
Resolve the known HF acceptance failure before production integration. The report still records two short-HF failures at seq3/pos2: token 67, regret 0.25 nat against the unchanged 0.20 limit. Later passing runs, including the reported 19 successful stages, do not resolve a failure that configuration experiments can reproduce. Please retain the failing workload/configuration, compare default and candidate outputs under matched conditions, and establish the cause and resolution under the existing correctness threshold. The evidence does not yet isolate a defect in the FlashInfer kernel: candidate prefill-state differences and shared decode rounding remain possible contributors. After the correction and scope reduction, please provide fresh matched A/B evidence for the resulting tree before making a production performance claim.
-
Make artifact identity valid by construction and remove the resulting machinery.
pegainfer-kernels/build.rsalready validates the bundle bytes and generates the hash literal returned by the C shim. Consider emitting a private typed Rust identity from those same validated bytes, retaining independent build-time hash/ABI validation and the actual-model-versus-expected identity check. This would eliminate the C-string identity interface, repeated pointer/UTF-8/hex handling,tests/gdn_identity.rs, and its special GNU--wrapbuild/runner path. The current validation correctly fixes my earlier concern; this is a request to simplify the representation, not to remove validation while leaving the unsafe string boundary intact. -
Reduce the gate runner and intermediate artifact protocol. In
run_gdn_production_gates.sh, the seven negative HF invocations and Rust-panic/abort-text parsing add substantial maintenance cost for prerequisite checks. Please have the same fixture/revision/identity prerequisite functions return errors that Rust tests can assert directly. Retain subprocess checks where the process/link boundary or CUDA isolation actually matters, real HTTP smoke, provenance, and protection against accidentally running zero tests. Likewise, consider having the selected pinned compiler/generator produce the final bundle directly, removing thecompile-metadata.jsonhandoff and its parser. Keep the final manifest, hashes of the bytes actually linked, and independent Rust pre-link validation. -
Trim redundant comments, pass-through code, and duplicate tests. Please remove comments that merely narrate visible control flow or repeat implementation history, and simplify the launch-options unpack/repack chain. Keep explanations of ABI layout, ownership/lifetime, and numerical constraints. Please also remove tests whose only contribution is checking upstream/library behavior or repeating an invariant already exercised by the retained E2E tests; avoid replacing the removed harness with a new framework. The project's actual ABI/in-place-state oracle, native-prepare numerical reference, unchanged HF gates, model continuation, scheduler/SharedSm coverage, startup selection, and corrupt-bundle rejection provide useful protection and should remain.
Public checks are currently green, including DCO. My local format/diff checks, runner syntax check, and strict build-crate Clippy check passed. I have not independently rerun the GPU gates or A/B benchmarks.
|
Oh, thanks for testing all these options—let’s go with down, get the accuracy checks passing, and wrap this up. |
Description
Add an explicitly selected FlashInfer GDN prefill candidate to Qwen3.5 serving. Triton remains the default even when a candidate is linked. The candidate supports SM120, TP1 and Hq/Hk/Hv/D = 16/16/32/128, validated with Qwen3.5-4B.
Backend selection, capability checks and module loading precede KV budgeting. Scratch reservation and dispatch use the selected backend. Unsupported or unavailable candidates fail at load; incompatible bundles fail before linking. Normal prefill has no diagnostic status copy or per-chunk host barrier.
pegainfer-kernelsowns pinned generation, complete artifact-contract validation and the stable in-place C ABI. Generated symbols and TMA layouts remain outside the model; generation uses an independent checkout without changing the shared FlashInfer headers.The latest review changes make the boundaries fail closed:
Existing HF, continuation and scheduler bodies are reused in private test modules. The public three-argument executor API matches main. Identity fault injection is linked only into its dedicated test executable. Validation features/counters, diagnostic controllers, duplicate scenario bodies, profiling/ABBA scaffolding and generated artifacts are excluded. See the model decision record, routed from the docs index.
Fixes #691
Type of Change
Validation
Submitted head:
1bceb2098e462a141c95a32b0acc7ab4abf47f4f, including main4043d50a. Its complete tree is exactly the GPU-testedc923500e21e7223a08c9845d36c2e3e5fa15626c; subsequent Gmail/sign-off normalization changed commit metadata, not source trees.On 2026-09-09, all 19 planned acceptance stages passed with one attempt each:
851bf6e806efd8d0a36b00ddf55e13ccb7b8cd0a.Candidate object SHA-256:
35c0ee54e427b4a13661225ab7804ea93a051f54221414d5a36d7c5f254b8450.Returned GPU archive SHA-256:
9f348623c5494c5216123a7c23ad4e7017c4646825da95611e27fdd43cadac18; all 254 evidence-file hashes were verified locally.This is SM120/TP1 acceptance; actual two-GPU inference was not rerun. Local artifact hashes establish consistency, not trusted release provenance.
Known numerical limitation
Two earlier candidate short-HF runs failed at the same padded-decode coordinate: seq 3 / pos 2 selected token 67, whose HF regret was 0.25 nat against the unchanged 0.20 limit. The third run and subsequent direct reruns passed; manual interruption is excluded from the numerical-failure count. Isolated controlled experiments reproduced configuration-dependent failure. The latest passing batch does not resolve it.
No validated production fix is claimed. Algorithm pinning, shared tuner/sampler changes, precision workarounds, tolerance relaxation and diagnostic helpers were not added to obtain passing results. Triton remains the default.
Performance
Historical matched HTTP A/B uses source
aa9ce155, RTX 5090 with driver 580.126.09, one linked binary for both backends, Shared-SM and synthetic token-ID prompts. Twelve unprofiled rounds completed 12,288 measured requests with zero failures.Tail latency did not improve uniformly: one concurrency-8 pair increased TPOT median by 35% and SSE-chunk-gap p99 from 44.8 to 292.2 ms. SSE gaps are not per-token ITL. Short profiler captures support diagnosis, not the unprofiled throughput claim. Performance A/B was not repeated after main integration; these results do not establish natural-language performance or justify changing the default.
Checklist
action_required, awaiting maintainer approval; no jobs have run. The successful old-head run is not evidence for this head.