Compare commits

...
4 Commits
5 changed files with 758 additions and 48 deletions
+1 -1
View File
@@ -6,7 +6,7 @@
extern "C" {
#endif
#define RPC_PROTO_MAJOR_VERSION 6
#define RPC_PROTO_MAJOR_VERSION 7
#define RPC_PROTO_MINOR_VERSION 0
#define RPC_PROTO_PATCH_VERSION 0
+14 -1
View File
@@ -865,7 +865,12 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
ggml_backend_meta_split_state split_state;
switch (tensor->op) {
case GGML_OP_NONE: {
split_state = {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
if (tensor->view_src != nullptr) {
// full-tensor view created with ggml_view_tensor, transparent for the split state
split_state = ggml_backend_meta_get_split_state(stc, tensor->view_src, assume_sync);
} else {
split_state = {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
}
} break;
case GGML_OP_DUP: {
split_state = handle_generic(src_ss, /*scalar_only =*/ true);
@@ -2283,6 +2288,14 @@ static enum ggml_status ggml_backend_meta_graph_compute(ggml_backend_t backend,
cgraph_ij->uid = ggml_graph_next_uid();
}
}
// Aux graph contents are rewritten on every compute but are identical across calls while the subgraphs are reused,
// so they can get stable uids on rebuild. Only safe without a comm backend, where the fallback usage is deterministic.
if (backend_ctx->comm_ctx == nullptr) {
for (ggml_cgraph * cgraph_aux : backend_ctx->cgraphs_aux) {
cgraph_aux->uid = ggml_graph_next_uid();
}
}
}
size_t iga = 0; // i graph aux
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -1129,7 +1129,8 @@ void server_models::load(const std::string & name, const load_options & opts) {
// exceeding models_max. Without this, the window between unload_lru()
// releasing its lock and this lock_guard acquiring allows multiple
// threads to each observe capacity and all proceed to load.
if (base_params.models_max > 0) {
// Download workers do not use models_max slots.
if (opts.mode == SERVER_CHILD_MODE_NORMAL && base_params.models_max > 0) {
size_t count_active = 0;
for (const auto & m : mapping) {
if (m.second.meta.is_running()) {
+6 -1
View File
@@ -540,13 +540,17 @@ def _wait_for_sse_event(collected: list, event_type: str, model: str, timeout: i
def test_router_download_model():
"""Case 1: download a model, verify SSE events and GET /models."""
"""Case 1: download a model at the model limit, verify SSE events and GET /models."""
global server
server.models_max = 1
server.start()
# Ensure the model is not present before we start
server.make_request("DELETE", f"/models?model={MODEL_DOWNLOAD_ID}")
# A download worker must not consume or evict a model slot
_load_model_and_wait(MODEL_B, timeout=120)
sse_events: list = []
stop = threading.Event()
sse_ready = threading.Event()
@@ -580,6 +584,7 @@ def test_router_download_model():
# Model should now appear in GET /models
ids = _get_model_ids(is_reload=False)
assert MODEL_DOWNLOAD_ID in ids, f"{MODEL_DOWNLOAD_ID} not found in /models after download"
assert _get_model_status(MODEL_B) == "loaded"
def test_router_delete_model():