Skip to content

Commit 07874db

Browse files
kmbandyclaude
andcommitted
feat(wp): WP_RESIDENT_DENSE — page only routed experts, keep dense resident
Phase 1 Task 2. Widens the existing manual resident-allocation path (which already keeps token_embd/output/norms/tiny tensors VRAM-resident) to ALL dense tensors when WP_RESIDENT_DENSE=1, paging only routed-expert (_exps) tensors. Two filters must agree or a tensor is never-allocated-never-loaded (the historical bug the stale comment at :1822 refers to): is_paged_weight() drives buffer allocation (the load-bearing filter) and the catalog population drives paging. Both now use the shared wp_is_routed_expert() predicate. Gate off => unchanged. init_weight_pager runs after load_tensors, so the pager pool auto-sizes to the VRAM left after dense is resident. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014ZRfPpL8XFzk1hep9MMg9P
1 parent d4344df commit 07874db

1 file changed

Lines changed: 38 additions & 4 deletions

File tree

src/llama-model.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <cassert>
3131
#include <cfloat>
3232
#include <cstdint>
33+
#include <cstdlib>
3334
#include <cstring>
3435
#include <cmath>
3536
#include <functional>
@@ -1251,6 +1252,27 @@ void llama_model_base::load_vocab(llama_model_loader & ml) {
12511252
vocab.load(ml, kv);
12521253
}
12531254

1255+
// WP_RESIDENT_DENSE: when "1", the weight pager keeps DENSE weights VRAM-
1256+
// resident and pages ONLY routed-expert tensors. Default off. Both the
1257+
// buffer-allocation filter (is_paged_weight) and the pager-catalog population
1258+
// MUST use the same routed-expert predicate below, or a tensor left out of
1259+
// one but not the other ends up never-allocated-never-loaded (garbage).
1260+
static bool wp_resident_dense_enabled() {
1261+
const char * v = std::getenv("WP_RESIDENT_DENSE");
1262+
return v != nullptr && v[0] == '1';
1263+
}
1264+
1265+
// True iff `name` is a consolidated routed-expert tensor
1266+
// (ffn_{up,gate,down}_exps). Same detection that sets
1267+
// llama_weight_page_info::is_expert at load.
1268+
static bool wp_is_routed_expert(const char * name) {
1269+
const char * p = name ? std::strstr(name, "ffn_") : nullptr;
1270+
if (p == nullptr) return false;
1271+
return std::strstr(p, "ffn_up_exps.") != nullptr ||
1272+
std::strstr(p, "ffn_gate_exps.") != nullptr ||
1273+
std::strstr(p, "ffn_down_exps.") != nullptr;
1274+
}
1275+
12541276
bool llama_model_base::load_tensors(llama_model_loader & ml) {
12551277
const auto & split_mode = params.split_mode;
12561278
const auto & use_mlock = params.use_mlock;
@@ -1612,6 +1634,10 @@ bool llama_model_base::load_tensors(llama_model_loader & ml) {
16121634
if (std::strncmp(n, "output_norm", 11) == 0) return false;
16131635
if (std::strcmp (n, "output.weight") == 0) return false;
16141636
if (ggml_nbytes(t) < WP_MIN_PAGED_BYTES) return false; // tiny -> resident
1637+
// WP_RESIDENT_DENSE: page ONLY routed experts; every dense
1638+
// weight becomes resident (allocated by the manual loop below,
1639+
// loaded by load_all_data). Must match the catalog filter.
1640+
if (wp_resident_dense_enabled() && !wp_is_routed_expert(n)) return false;
16151641
return true; // it's a paged per-layer weight
16161642
};
16171643
const bool paging_on_device_buft =
@@ -1797,10 +1823,18 @@ bool llama_model_base::load_tensors(llama_model_loader & ml) {
17971823
}
17981824
info.is_expert = is_consolidated;
17991825
}
1800-
ml.weight_page_infos.push_back(info);
1801-
// Collect the actual model tensor pointer for the weight pager
1802-
if (weight_pager) {
1803-
weight_pager->weight_tensor_ptrs.push_back(t);
1826+
// WP_RESIDENT_DENSE: register ONLY routed-expert tensors with
1827+
// the pager; dense tensors are resident (allocated above by the
1828+
// manual loop) and must NOT get a pool placeholder. This filter
1829+
// MUST agree with is_paged_weight() — both use the routed-expert
1830+
// predicate — or a tensor is never-allocated-never-loaded.
1831+
const bool page_this = !wp_resident_dense_enabled() || info.is_expert;
1832+
if (page_this) {
1833+
ml.weight_page_infos.push_back(info);
1834+
// Collect the actual model tensor pointer for the weight pager
1835+
if (weight_pager) {
1836+
weight_pager->weight_tensor_ptrs.push_back(t);
1837+
}
18041838
}
18051839
ctx_has_weights = true;
18061840
}

0 commit comments

Comments
 (0)