Repository navigation
Retain CUDA graph executables and resource owners during export - #262
voipmonitor wants to merge 2 commits into
Conversation
The graph export change in b455be5 replaced an instantiated executable with reset template metadata. A serving package produced by that path fails on its second full-model request: `cuGraphLaunch` reports CUDA_ERROR_ILLEGAL_ADDRESS after the first request completes. Exporting the same model, layouts, and weights through the executable-retaining path preserves valid replay. Restore `instantiate_graph` in `record_export_graph` and return the executable graph while retaining the existing graph-pool ownership validation. This keeps the graph and its external storage alive for repeated launches instead of resetting them into template-only metadata. Update the metadata tests to assert that the returned object is the original instantiated graph, that no `record_template` call is made, and that collective consumers keep their associations. The CUDA export fixture validates executable graph metadata and requires that graph-pool storage remains valid after `empty_cache`. Validation: all 9 graph metadata tests and all 23 runtime-core/capture-readiness tests pass with CUDA disabled. The real CUDA export fixture passes. As an end-to-end comparison, a C4 export through the reset-template path fails on the second long request, while the same model through this fix completes four sequential long requests (frames 831, 1777, 2896, and 4110) with HTTP 200 on TP16. No claim is made about model quality or performance. Design-Signed-Off-By: Kimi (Kimi); design-review=cfcf Co-Authored-By: Kimi <noreply@anthropic.com>
Returning an instantiated CUDA graph discarded the explicit kernel and pool owners supplied to record_export_graph. Device pointer capture does not retain those Python objects. Bind their lifetime to the graph with Torch's retained-object API before instantiation, and preserve pool checks. Retained resources survive instantiation failure and are released on reset or collection after tracked Python replay streams drain. Native callers still provide their existing explicit drain. Document the prohibition on owner-to-graph reference cycles and the preparation memory cost of retaining executables. Correct export documentation and misleading test names. This repairs the helper's lifetime contract, without changing serialized core format, model arithmetic or runtime policy. Three ownership regressions fail on the submitted implementation and pass with this change. The focused CPU capture suite passes 73 tests. No CUDA or end-to-end test was run. The reported second-request failure remains causally unqualified because the available comparison also changes the Kimi gather configuration. Design-Signed-Off-By: Codex GPT-6; design-review=cfcf Signed-off-by: Martin Vit <martin@voipmonitor.org>
|
Correction: a subsequent command/hash review found that this control was not an exact reconstruction of the original failing Controlled native replay A/B, 2026-11-11I tested the serving-causality question with two C4 packages built with the same FlashInfer sources, export arguments and native runtime. The no-retention control completed long sequential requests with 831, 1,777, 2,896 and 4,110 prompt tokens, followed by four concurrent 1,024-token requests. It did not reproduce During the concurrent phase, the control completed 722 scheduler rounds and 4,092 emitted tokens (5.668 tokens/round, 30.868 ms/round). The retention package completed 745 rounds and 4,092 emitted tokens (5.493 tokens/round, 30.319 ms/round). Different adaptive acceptance makes these timings unsuitable for a performance claim. Outcome: the original serving failure was not reproduced in this controlled comparison. Retention must not be presented as the proven fix for that illegal-address failure. The independently tested resource-ownership correction remains, but the original crash's cause is still unproven. |
|
Update: the original illegal-address failure has now been reproduced on Frank1. A no-retention C4 package built with the reconstructed paired-gather configuration and cold tuning failed on the original request-831 input after 0.38 seconds with cuEventQuery failed (700, CUDA_ERROR_ILLEGAL_ADDRESS), followed by HTTP 503. The native binary matches the original SHA-256 (8b7be5de6b7fd28f23e01abf21d0540990cf958e3372a6d3abb2ef348be239c6). A retention export using the same tuning cache and original development signer is in progress; its replay result will determine whether ec6190c prevents this exact failure. |
|
Final A/B update: a warm no-retention package (gb202-tp16-202611111441, 3,940 functions/3,900 modules) also completed the original request-831 input on the original native binary in 112.39 seconds with stop_reason=tool_use and a healthy server. By contrast, the cold no-retention package (gb202-tp16-202611111614, 4,030/3,990) reproduced CUDA_ERROR_ILLEGAL_ADDRESS in 0.38 seconds and HTTP 503. The retention package (gb202-tp16-202611111711, 3,945/3,905) completed request 831, the remaining long sequential requests and four concurrent 1024-token requests without an illegal address; its concurrent phase completed 639 scheduler rounds and 4,092 emitted tokens (6.404 tokens/round, 33.814 ms/round), with zero host-cache errors and zero disk records. No-retention is therefore not sufficient to cause the failure, and retention is not necessary for the same request to succeed. The decisive variable demonstrated here is the graph/tuning variant, not graph retention. This serving-causality claim should be withdrawn from the PR. The independently tested resource-ownership correction may still have value, but the original illegal-address failure requires separate graph/tuning bisection rather than attribution to this PR. |
Captured node pointers do not retain the Python owners of pools and kernel resources. Releasing graph handles before serialization can therefore leave export without the complete resource lifetimes used during capture. Retain each captured template and instantiated executable through export. Attach external pool and kernel owners to the graph's synchronized release path. Extend ownership tests for reset, collection, and instantiation failure, and document the executable memory retained during preparation. This keeps export resources alive until graph release without changing the serialized core format or native loading contract. The CPU capture metadata suite passes all 12 tests. The CUDA export test is skipped, and a full Kimi export has not been run with this change. Applies NVIDIA/hyperflare-inference PR #262 commits bb3ce1e and ec6190c. Design-Signed-Off-By: Codex GPT-6; design-review=ed22
|
merged differently through another commit. |
Why
A reported Kimi K3.1 TP16 failure on a second long request motivated comparing export with retained CUDA executables against export that records template metadata and immediately resets the capture graph. Retention changes preparation-time resource lifetime. It does not transfer the Python executable into serving: Helios reconstructs and instantiates its own graphs when loading the core.
The supplied comparison does not yet isolate executable retention as the cause of recovery. That causal attribution remains unverified.
Changes
record_export_graphinstantiates and returns the original graph instead of copying template-only metadata and resetting it.Result and compatibility
The external-owner lifetime fix is implemented and qualified by focused CPU tests. The global executable-retention path remains research-only as a remedy for the reported serving failure. It retains one executable per captured graph during preparation, increasing memory requirements relative to template-only recording; the total cost has not been measured here.
Serialized core format, model arithmetic and native serving policy are unchanged. This change does not repair an already exported core. No performance or model-quality improvement is claimed.
Validation
Review validation, without CUDA or end-to-end execution:
bb3ce1eaand pass with the fix. The original helper allowed both supplied pool owners and the kernel owner to be collected while the graph remained alive. The corrected helper retains them through release, drains registered replay streams first, and does not retain the graph itself.git diff --checkpassed.Run the ownership and metadata regressions from the repository root:
Earlier report and attribution limit:
The original report described an illegal-address failure with template-reset export, four successful sequential long requests with retained executables, and successful C4 replay with a 128G host prefix cache. These serving results were not rerun during review.
The available preparation checkouts also differ in the eight-row paired gather:
load_batch=2 if rows == 8 else 1is present in the failing checkout and absent from the successful checkout. Their export logs report 3,980 kernels in 3,940 modules versus 3,940 kernels in 3,900 modules per rank. The corresponding cores aregb202-tp16-202611110058andgb202-tp16-202611110504. These artifacts do not establish a single-change A/B comparison or prove that template reset caused the serving failure.Before treating this as a serving correctness fix, isolate retention with otherwise identical preparation inputs and test repeated native replay. The caller-owner regression repaired here is independently demonstrated; it is not evidence of the cause of the original serving failure.
🤖 Generated with Claude Code