Skip to content

Commit f64ccfd

Browse files
committed
feat(wp): routing-boundary pre-pass (mark_routing_boundaries/is_routing_break)
Assisted-by: Codex
1 parent c7a2c9f commit f64ccfd

3 files changed

Lines changed: 59 additions & 0 deletions

File tree

src/weight-pager/wp-pager.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "wp-pager.h"
22

33
#include "ggml-backend.h"
4+
#include "ggml.h"
5+
#include "../../ggml/src/ggml-impl.h"
46
#include "llama-impl.h" // LLAMA_LOG_*
57
#include "wp-eval-cb.h"
68

@@ -512,6 +514,25 @@ bool WeightPager::batch_safe() const {
512514
return stats_.evictions == 0 && pool_.size_class_slots_enabled() && !catalog_.has_experts();
513515
}
514516

517+
void WeightPager::mark_routing_boundaries(const struct ggml_cgraph * gf) {
518+
if (gf == nullptr || gf->n_nodes <= 0) { return; }
519+
const void * first = gf->nodes[0];
520+
const void * last = gf->nodes[gf->n_nodes - 1];
521+
if (routing_sig_.n_nodes == gf->n_nodes && routing_sig_.first == first && routing_sig_.last == last) { return; }
522+
routing_break_tensors_.clear();
523+
for (int i = 0; i < gf->n_nodes; ++i) {
524+
struct ggml_tensor * node = gf->nodes[i];
525+
if (node->op != GGML_OP_MUL_MAT_ID) { continue; }
526+
routing_break_tensors_.insert(node);
527+
struct ggml_tensor * ids = node->src[2];
528+
while (ids != nullptr && ids->view_src != nullptr) { ids = ids->view_src; }
529+
if (ids != nullptr) { routing_break_tensors_.insert(ids); }
530+
}
531+
routing_sig_.n_nodes = gf->n_nodes;
532+
routing_sig_.first = first;
533+
routing_sig_.last = last;
534+
}
535+
515536
int WeightPager::loaded_pages() const {
516537
int n = 0;
517538
for (bool loaded : page_loaded_) {

src/weight-pager/wp-pager.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <memory>
3232
#include <string>
3333
#include <unordered_map>
34+
#include <unordered_set>
3435
#include <vector>
3536

3637
struct ggml_backend_buffer;
@@ -39,6 +40,9 @@ typedef struct ggml_backend_buffer * ggml_backend_buffer_t;
3940
struct ggml_backend_buffer_type;
4041
typedef struct ggml_backend_buffer_type * ggml_backend_buffer_type_t;
4142

43+
struct ggml_cgraph;
44+
struct ggml_tensor;
45+
4246
namespace wp {
4347

4448
class WeightPager {
@@ -147,6 +151,10 @@ class WeightPager {
147151
bool async_ensure_enabled() const { return async_ensure_enabled_; }
148152
const Stats & stats() const;
149153
bool batch_safe() const;
154+
void mark_routing_boundaries(const struct ggml_cgraph * gf);
155+
bool is_routing_break(const struct ggml_tensor * t) const {
156+
return routing_break_tensors_.count(t) != 0;
157+
}
150158
uint64_t sync_fallback_count() const { return stats_.sync_fallbacks; }
151159
int loaded_pages() const;
152160
int pending_prefetches() const { return prefetch_.pending(); }
@@ -298,6 +306,12 @@ class WeightPager {
298306
// Stored as slots, not pages, so unpin releases the same refcounts even
299307
// if a page later moves to another slot.
300308
std::unordered_map<const void *, std::vector<int>> graph_pin_slots_;
309+
std::unordered_set<const struct ggml_tensor *> routing_break_tensors_;
310+
struct {
311+
int n_nodes = -1;
312+
const void * first = nullptr;
313+
const void * last = nullptr;
314+
} routing_sig_;
301315

302316
// Shared pinned staging buffer for page_in_sync_. Allocated once at
303317
// init, sized to max_page_size, reused across every sync page-in.

tests/test-weight-pager.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "weight-pager/wp-pool.h"
1313

1414
#include "ggml-backend.h"
15+
#include "ggml.h"
1516

1617
#include <cerrno>
1718
#include <cstdint>
@@ -1511,6 +1512,28 @@ static int test_is_uma_device_smoke() {
15111512
return fails;
15121513
}
15131514

1515+
static int test_routing_boundary_prepass() {
1516+
int fails = 0;
1517+
struct ggml_init_params ip = { /*.mem_size=*/ 16*1024*1024, /*.mem_buffer=*/ nullptr, /*.no_alloc=*/ true };
1518+
struct ggml_context * ctx = ggml_init(ip);
1519+
struct ggml_tensor * ids_producer = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, 8);
1520+
ggml_set_name(ids_producer, "ids_producer");
1521+
struct ggml_tensor * ids_view = ggml_view_1d(ctx, ids_producer, 8, 0);
1522+
struct ggml_tensor * as = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, 4, 4, 2);
1523+
struct ggml_tensor * b = ggml_new_tensor_2d(ctx, GGML_TYPE_F32, 4, 8);
1524+
struct ggml_tensor * mmid = ggml_mul_mat_id(ctx, as, b, ids_view);
1525+
ggml_set_name(mmid, "mmid");
1526+
struct ggml_cgraph * gf = ggml_new_graph(ctx);
1527+
ggml_build_forward_expand(gf, mmid);
1528+
wp::WeightPager pager;
1529+
pager.mark_routing_boundaries(gf);
1530+
if (!pager.is_routing_break(mmid)) { fprintf(stderr, "FAIL: mmid not marked\n"); fails++; }
1531+
if (!pager.is_routing_break(ids_producer)) { fprintf(stderr, "FAIL: ids producer (view root) not marked\n"); fails++; }
1532+
if (pager.is_routing_break(b)) { fprintf(stderr, "FAIL: unrelated tensor marked\n"); fails++; }
1533+
ggml_free(ctx);
1534+
return fails;
1535+
}
1536+
15141537
// ---------------------------------------------------------------------------
15151538
// main
15161539
// ---------------------------------------------------------------------------
@@ -1556,6 +1579,7 @@ int main() {
15561579
{ "pool_hot_threshold_protects", test_pool_hot_threshold_protects_in_eviction },
15571580
{ "pool_hot_fallback_when_all_hot", test_pool_hot_fallback_when_all_hot },
15581581
{ "pool_default_threshold_zero_lru", test_pool_default_threshold_zero_is_pure_lru },
1582+
{ "routing_boundary_prepass", test_routing_boundary_prepass },
15591583
};
15601584

15611585
for (const auto & t : tests) {

0 commit comments

Comments
 (0)