Skip to content

Commit 4736992

Browse files
authored
feat(laguna): use KVFlash pool for MoE placement (#448)
1 parent 673168d commit 4736992

4 files changed

Lines changed: 71 additions & 17 deletions

File tree

server/src/common/kvflash_placement.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Any MoE / weight-offload backend that places experts against a VRAM budget
44
// must decide how much KV to reserve. Reserving for `max_ctx` forces experts
55
// cold at high max_ctx even when KVFlash bounds the *resident* KV to a fixed
6-
// pool. This helper centralises the rule so every backend (qwen35moe today,
6+
// pool. This helper centralises the rule so every backend (qwen35moe, laguna,
77
// DeepSeek-V4 / future MoE next) inherits the "pool bounds the expert-placement
88
// cliff" win without re-deriving the byte math.
99
#pragma once

server/src/laguna/laguna_backend.cpp

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../common/moe_hybrid_types.h"
2020
#include "../common/moe_hybrid_types_impl.h"
2121
#include "../common/moe_hybrid_placement.h"
22+
#include "../common/kvflash_placement.h"
2223
#include "../common/moe_hybrid_ffn_eval.h"
2324
#include "../common/moe_hybrid_storage.h"
2425
#include "../common/moe_hybrid_routing_stats.h"
@@ -121,27 +122,42 @@ KvFlashConfig LagunaBackend::kvflash_config() const {
121122
return pc;
122123
}
123124

124-
void LagunaBackend::kvflash_read_config() {
125+
void LagunaBackend::kvflash_resolve_drafter() {
125126
if (std::getenv("DFLASH_KVFLASH")) {
126127
kvflash_drafter_path_ = kvflash_find_drafter(args_.target_path.c_str());
127128
}
129+
}
130+
131+
KvFlashAutoBudget LagunaBackend::make_kvflash_budget(int64_t gpu_free) const {
132+
KvFlashAutoBudget b;
133+
b.free_bytes = gpu_free;
134+
b.bytes_per_token = (int64_t)w_.n_layer * w_.n_head_kv * 2 *
135+
(int64_t)ggml_row_size(args_.kv_type, w_.head_dim);
136+
b.reserve_bytes = (int64_t)(1.5 * 1073741824.0) +
137+
(kvflash_drafter_path_.empty() ? 0 : (int64_t)(1.7 * 1073741824.0));
138+
return b;
139+
}
140+
141+
void LagunaBackend::kvflash_read_config() {
142+
kvflash_resolve_drafter();
128143
// "auto" sizes from the GPU (weights resident, cache not yet allocated):
129144
// laguna pools ALL n_layer layers at the configured KV quant.
130-
KvFlashAutoBudget kvf_budget;
131-
{
132-
size_t gpu_free = 0, gpu_total = 0;
133-
if (ggml_backend_dev_t dev = ggml_backend_get_device(backend_)) {
134-
ggml_backend_dev_memory(dev, &gpu_free, &gpu_total);
135-
}
136-
kvf_budget.free_bytes = (int64_t)gpu_free;
137-
kvf_budget.bytes_per_token = (int64_t)w_.n_layer * w_.n_head_kv * 2 *
138-
(int64_t)ggml_row_size(args_.kv_type, w_.head_dim);
139-
kvf_budget.reserve_bytes = (int64_t)(1.5 * 1073741824.0) +
140-
(kvflash_drafter_path_.empty() ? 0 : (int64_t)(1.7 * 1073741824.0));
145+
size_t gpu_free = 0, gpu_total = 0;
146+
if (ggml_backend_dev_t dev = ggml_backend_get_device(backend_)) {
147+
ggml_backend_dev_memory(dev, &gpu_free, &gpu_total);
141148
}
149+
KvFlashAutoBudget kvf_budget = make_kvflash_budget((int64_t)gpu_free);
142150
kvflash_tokens_ = kvflash_pool_from_env(args_.max_ctx, kvflash_config(),
143-
!kvflash_drafter_path_.empty(),
151+
kvflash_scorer_expected(),
144152
kvf_budget);
153+
if (kvflash_tokens_ > 0 && placement_all_hot_full_kv_) {
154+
std::printf("[laguna][kvflash] disabled: placement all-hot at max_ctx %d, "
155+
"pool not needed\n", args_.max_ctx);
156+
std::fflush(stdout);
157+
kvflash_tokens_ = 0;
158+
kvflash_tau_ = 64;
159+
kvflash_drafter_path_.clear();
160+
}
145161
if (kvflash_tokens_ > 0) {
146162
const char * tau = std::getenv("DFLASH_KVFLASH_TAU");
147163
kvflash_tau_ = std::max(1, tau ? std::atoi(tau) : 64);
@@ -266,6 +282,7 @@ bool LagunaBackend::unpark(const std::string & what) {
266282
}
267283
cache_.kv_k_type = args_.kv_type;
268284
cache_.kv_v_type = args_.kv_type;
285+
kvflash_read_config();
269286
if (!create_laguna_target_cache(w_, args_.max_ctx, backend_, cache_,
270287
kvflash_tokens_)) {
271288
std::fprintf(stderr, "[unpark] cache: %s\n", dflash27b_last_error());
@@ -1382,6 +1399,7 @@ static inline uint64_t elapsed_us(HybridClock::time_point t0, HybridClock::time_
13821399

13831400
bool LagunaBackend::init_hybrid_mode() {
13841401
const char * hotness_path = std::getenv("DFLASH_LAGUNA_HOTNESS");
1402+
placement_all_hot_full_kv_ = false;
13851403

13861404
// Step 1: Load model WITHOUT expert data to GPU (partial load)
13871405
TargetLoadPlan _hybrid_plan;
@@ -1454,13 +1472,29 @@ bool LagunaBackend::init_hybrid_mode() {
14541472

14551473
const uint64_t kv_bytes_per_tok = (uint64_t)w_.n_layer * 2 *
14561474
(uint64_t)w_.n_head_kv * (uint64_t)w_.head_dim * 2;
1457-
const uint64_t kv_total = kv_bytes_per_tok * (uint64_t)max_context;
14581475

14591476
const uint64_t warm_cache_bytes = 200ULL * 1024 * 1024;
14601477
const uint64_t safety_bytes = 512ULL * 1024 * 1024;
14611478
const uint64_t core_bytes =
14621479
moe_hybrid_core_bytes_from_memory("laguna", gpu_free, gpu_total);
14631480

1481+
kvflash_resolve_drafter();
1482+
const int kvf_pool = kvflash_pool_from_env(
1483+
max_context, kvflash_config(), kvflash_scorer_expected(),
1484+
make_kvflash_budget((int64_t)gpu_free));
1485+
const auto kvf_dec = dflash::common::kvflash_placement_decision(
1486+
kv_bytes_per_tok, max_context, kvf_pool,
1487+
gpu_total, core_bytes, total_expert_bytes,
1488+
warm_cache_bytes, safety_bytes, /*draft_bytes=*/0);
1489+
const uint64_t kv_total = kvf_dec.kv_total;
1490+
const int kv_ctx_log = kvf_dec.kv_ctx;
1491+
placement_all_hot_full_kv_ = kvf_dec.all_hot_full_kv;
1492+
if (kvf_dec.pool_reduced) {
1493+
std::printf("[laguna][kvflash] placement reserves pool KV (%d tokens, "
1494+
"not max_ctx %d) -> experts stay hot\n", kvf_pool, max_context);
1495+
std::fflush(stdout);
1496+
}
1497+
14641498
uint64_t expert_budget = 0;
14651499
if (gpu_total > core_bytes + kv_total + warm_cache_bytes + safety_bytes) {
14661500
expert_budget = gpu_total - core_bytes - kv_total - warm_cache_bytes - safety_bytes;
@@ -1511,7 +1545,7 @@ bool LagunaBackend::init_hybrid_mode() {
15111545
gpu_total / 1024.0 / 1024.0 / 1024.0,
15121546
core_bytes / 1024.0 / 1024.0 / 1024.0,
15131547
kv_total / 1024.0 / 1024.0 / 1024.0,
1514-
max_context,
1548+
kv_ctx_log,
15151549
warm_cache_bytes / 1024.0 / 1024.0,
15161550
safety_bytes / 1024.0 / 1024.0,
15171551
expert_budget / 1024.0 / 1024.0 / 1024.0,

server/src/laguna/laguna_backend.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,19 @@ class LagunaBackend : public ModelBackend {
142142
int kvflash_tau_ = 64;
143143
bool kvflash_drafter_failed_ = false;
144144
bool kvflash_active() const { return kvflash_tokens_ > 0; }
145+
// True iff hybrid placement showed all experts fit hot with the FULL
146+
// max_ctx KV reservation. In that case KVFlash is redundant and can be
147+
// disabled before cache creation.
148+
bool placement_all_hot_full_kv_ = false;
145149
// Drafter rescore + repage every effective-tau generated tokens
146150
// (lazy-loads the drafter + cross-tokenizer scorer on first need).
147151
void kvflash_maybe_reselect(const std::vector<int32_t> & history, int generated);
148152
// Pager protections (SWA tail) shared by the floor and attach.
149153
KvFlashConfig kvflash_config() const;
154+
// Shared pool sizing inputs for placement and runtime allocation.
155+
void kvflash_resolve_drafter();
156+
bool kvflash_scorer_expected() const { return !kvflash_drafter_path_.empty(); }
157+
KvFlashAutoBudget make_kvflash_budget(int64_t gpu_free) const;
150158
// Read DFLASH_KVFLASH and round/clamp; call before cache creation.
151159
void kvflash_read_config();
152160
// Attach the pager to the freshly created cache (init / unpark).

server/test/test_kvflash_placement.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ int main() {
8080
expect(d.kv_ctx == 32768, "C5: keeps full ctx");
8181
}
8282

83-
std::printf("PASS: kvflash placement decision (5 cases)\n");
83+
// Case 6 — laguna/poolside-style no-draft placement: same pool rule, no
84+
// drafter reserve. This keeps the shared helper covered for both current
85+
// backends that use it.
86+
{
87+
auto d = kvflash_placement_decision(kv_per_tok, 131072, /*pool=*/16384,
88+
gpu, core, experts, warm, safety,
89+
/*draft_bytes=*/0);
90+
expect(!d.all_hot_full_kv, "C6: full KV still forces experts cold");
91+
expect(d.kv_ctx == 16384, "C6: laguna reserves POOL ctx");
92+
expect(d.pool_reduced, "C6: laguna pool reduction engaged");
93+
}
94+
95+
std::printf("PASS: kvflash placement decision (6 cases)\n");
8496
return 0;
8597
}

0 commit comments

Comments
 (0)