From 306d5012aaeb0b65a4de02a3009ac207a4b62094 Mon Sep 17 00:00:00 2001 From: lenny76 Date: Wed, 23 Sep 2026 13:59:26 +0200 Subject: [PATCH] ggml-cpu : move repacked weight rows to the node of the thread that reads them With a NUMA strategy (--numa distribute / isolate) the repack mul_mat uses a static row split and threads are bound to nodes, but the repacked weights were written by the loading thread, so all of them sit on one node. Each thread now moves the pages of its row slice of a weight to its own node the first time it computes that weight (move_pages, once per weight and thread count, Linux only). Co-Authored-By: Claude Opus 5.5 --- ggml/src/ggml-cpu/repack.cpp | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/ggml/src/ggml-cpu/repack.cpp b/ggml/src/ggml-cpu/repack.cpp index 4471c9ab1daf..6135504bf5d3 100644 --- a/ggml/src/ggml-cpu/repack.cpp +++ b/ggml/src/ggml-cpu/repack.cpp @@ -18,6 +18,35 @@ #include "repack.h" +#if defined(__linux__) +#include +#include +#include + +// move the pages of [start, end) to the NUMA node of the calling thread (best effort) +static void ggml_repack_move_pages_to_local_node(const void * start, const void * end) { + unsigned cpu = 0; + unsigned node = 0; + if (syscall(SYS_getcpu, &cpu, &node, NULL) != 0) { + return; + } + const uintptr_t page = (uintptr_t) sysconf(_SC_PAGESIZE); + uintptr_t addr = (uintptr_t) start & ~(page - 1); + const uintptr_t stop = (uintptr_t) end; + void * pages[256]; + int nodes[256]; + int status[256]; + while (addr < stop) { + int n = 0; + for (; n < 256 && addr < stop; n++, addr += page) { + pages[n] = (void *) addr; + nodes[n] = (int) node; + } + syscall(SYS_move_pages, 0, (unsigned long) n, pages, nodes, status, 2 /* MPOL_MF_MOVE */); + } +} +#endif + #if defined(__GNUC__) #pragma GCC diagnostic ignored "-Woverlength-strings" #endif @@ -5054,6 +5083,24 @@ template placed; + if (placed.insert((uintptr_t) src0->data ^ ((uintptr_t) nth << 48)).second) { + int64_t r0 = dr0 * ith; + int64_t r1 = MIN(r0 + dr0, nr0); + r0 = (r0 % NB_COLS) ? r0 + NB_COLS - (r0 % NB_COLS) : r0; + r1 = (r1 % NB_COLS) ? r1 + NB_COLS - (r1 % NB_COLS) : r1; + r1 = MIN(r1, ne01); + if (r0 < r1) { + ggml_repack_move_pages_to_local_node((const char *) src0->data + r0 * nb01, (const char *) src0->data + r1 * nb01); + } + } + } +#endif + while (current_chunk < nchunk0 * nchunk1) { const int64_t ith0 = current_chunk % nchunk0; const int64_t ith1 = current_chunk / nchunk0;