-
Notifications
You must be signed in to change notification settings - Fork 249
perf(qwen35): add opt-in F32 rollback checkpoints for single-GPU inference #515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| #pragma once | ||
|
|
||
| #include <cstdlib> | ||
| #include <cstring> | ||
|
|
||
| namespace dflash::common { | ||
|
|
||
| struct ChainRollbackPolicy { | ||
| bool checkpoint_f32 = false; | ||
| int fast_rollback_threshold = 5; | ||
| bool diagnostics = false; | ||
| }; | ||
|
|
||
| inline bool env_flag_enabled(const char * name) { | ||
| const char * value = std::getenv(name); | ||
| return value != nullptr && value[0] != '\0' && std::strcmp(value, "0") != 0; | ||
| } | ||
|
|
||
| inline ChainRollbackPolicy resolve_chain_rollback_policy() { | ||
| ChainRollbackPolicy policy; | ||
| policy.checkpoint_f32 = env_flag_enabled("DFLASH_SINGLE_CHAIN_CHECKPOINT_F32"); | ||
| policy.diagnostics = env_flag_enabled("DFLASH_SINGLE_CHAIN_ROLLBACK_DIAG"); | ||
|
|
||
| // Lower thresholds are valid only with exact F32 checkpoints. This keeps | ||
| // the established F16 behavior unchanged when no opt-in flags are set. | ||
| if (policy.checkpoint_f32) { | ||
| const char * value = std::getenv("DFLASH_FAST_ROLLBACK_THRESHOLD"); | ||
| if (value != nullptr) { | ||
| const int requested = std::atoi(value); | ||
| if (requested >= 1 && requested <= 5) { | ||
| policy.fast_rollback_threshold = requested; | ||
| } | ||
| } | ||
| } | ||
| return policy; | ||
| } | ||
|
|
||
| } // namespace dflash::common | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #include "qwen35_backend.h" | ||
| #include "common/chain_rollback_policy.h" | ||
| #include "placement/skip_park_guard.h" | ||
| #include "qwen35_dflash_target.h" | ||
| #include "graph_builders.h" | ||
|
|
@@ -1927,12 +1928,33 @@ bool Qwen35Backend::do_spec_decode(int committed, int n_gen, | |
| int n_hint_proposed = 0; | ||
| int n_hint_accepted = 0; | ||
| int target_forwards = 0; | ||
| const ChainRollbackPolicy rollback_policy = resolve_chain_rollback_policy(); | ||
| int rollback_accept_hist[17] = {}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The rollback diagnostic counters and print logic are duplicated across both decode loops ( Prompt for AI agents |
||
| int rollback_fast_low = 0; | ||
| int rollback_fast_high = 0; | ||
| int rollback_legacy_replay = 0; | ||
| int rollback_failed_fallback = 0; | ||
|
|
||
|
|
||
| auto log_target_forward_stats = [&]() { | ||
| std::fprintf(stderr, "[spec-decode] target_forwards=%d forwards_per_token=%.6f forwards_per_step=%.3f\n", | ||
| target_forwards, | ||
| n_generated > 0 ? (double)target_forwards / n_generated : 0.0, | ||
| n_draft_steps > 0 ? (double)target_forwards / n_draft_steps : 0.0); | ||
| if (rollback_policy.diagnostics) { | ||
| std::fprintf(stderr, | ||
| "[chain-rollback-policy] checkpoint=%s threshold=%d fast_low=%d fast_high=%d legacy_replay=%d failed_fallback=%d accept_hist=1:%d,2:%d,3:%d,4:%d,5:%d,6:%d,7:%d,8:%d,9:%d,10:%d,11:%d,12:%d,13:%d,14:%d,15:%d,16+:%d\n", | ||
| rollback_policy.checkpoint_f32 ? "F32" : "default", | ||
| rollback_policy.fast_rollback_threshold, | ||
| rollback_fast_low, rollback_fast_high, rollback_legacy_replay, | ||
| rollback_failed_fallback, | ||
| rollback_accept_hist[1], rollback_accept_hist[2], rollback_accept_hist[3], | ||
| rollback_accept_hist[4], rollback_accept_hist[5], rollback_accept_hist[6], | ||
| rollback_accept_hist[7], rollback_accept_hist[8], rollback_accept_hist[9], | ||
| rollback_accept_hist[10], rollback_accept_hist[11], rollback_accept_hist[12], | ||
| rollback_accept_hist[13], rollback_accept_hist[14], rollback_accept_hist[15], | ||
| rollback_accept_hist[16]); | ||
| } | ||
| }; | ||
|
|
||
| // kvflash: an in-pool prompt prefills contiguously without registering | ||
|
|
@@ -2488,11 +2510,12 @@ bool Qwen35Backend::do_spec_decode(int committed, int n_gen, | |
| // 6. Fix state: adaptive fast-rollback vs legacy replay. | ||
| // Fast-rollback (implicit bonus, skip replay) is profitable when | ||
| // accept_n is large enough that skipping the replay saves more compute | ||
| // than the cost of deferring the bonus to the next step. Breakeven | ||
| // is around accept_n ≈ 5. Below that, legacy replay is cheaper. | ||
| constexpr int kFastRollbackThreshold = 5; | ||
| // than the cost of deferring the bonus to the next step. The default | ||
| // threshold is 5; exact F32 checkpoints may opt in to a lower value. | ||
| rollback_accept_hist[std::min(accept_n, 16)]++; | ||
| const bool use_fast_rollback = | ||
| target->supports_fast_rollback() && (accept_n >= kFastRollbackThreshold); | ||
| target->supports_fast_rollback() && | ||
| (accept_n >= rollback_policy.fast_rollback_threshold); | ||
|
|
||
| int replay_last_tok = -1; | ||
| bool fast_rolled_back = false; | ||
|
|
@@ -2508,15 +2531,19 @@ bool Qwen35Backend::do_spec_decode(int committed, int n_gen, | |
| if (target->rollback_to(committed, commit_n)) { | ||
| replay_last_tok = target_tok[commit_n - 1]; | ||
| fast_rolled_back = true; | ||
| if (accept_n < 5) rollback_fast_low++; | ||
| else rollback_fast_high++; | ||
| } else { | ||
| // Rollback failed (CUDA error / unsupported state type). The | ||
| // pre-verify snapshot is still valid, so degrade to the legacy | ||
| // restore+replay path below instead of aborting the request. | ||
| std::fprintf(stderr, "spec-decode: rollback_to failed; " | ||
| "falling back to restore+replay\n"); | ||
| rollback_failed_fallback++; | ||
| } | ||
| } | ||
| if (!fast_rolled_back) { | ||
| rollback_legacy_replay++; | ||
| // Legacy replay: restore SSM snapshot, replay accepted + bonus tokens. | ||
| // (When falling back from fast-rollback, bonus_tok is -1 and commit_n | ||
| // is the budget-clamped accepted count.) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.