Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
240767d
scripts : add Strix host-memory watchdog
Sep 12, 2026
41dbf04
scripts : clean up watchdog process group on signals
Sep 12, 2026
da5ce95
scripts : preserve child signals and monitor descendants
Sep 12, 2026
93aff41
scripts : classify soft descendant escalation as timeout
Sep 12, 2026
2e27f6e
merge : sync repaired DeepSeek V4.1 schema base
Sep 13, 2026
1193241
deepseek41 : admit unified host memory before allocation
Sep 13, 2026
0ca941a
merge : sync DeepSeek V4.1 RoPE classification
Sep 13, 2026
31d5958
scripts : add Strix host-memory watchdog
Sep 12, 2026
1639716
scripts : clean up watchdog process group on signals
Sep 12, 2026
a55e6a3
scripts : preserve child signals and monitor descendants
Sep 12, 2026
ae910f8
scripts : classify soft descendant escalation as timeout
Sep 12, 2026
af2b27f
docs : compose admission with Strix watchdog
Sep 13, 2026
c2a7661
deepseek41 : tighten admission failure guards
Sep 13, 2026
856de69
deepseek41 : remove unused admission helper
Sep 13, 2026
aa62205
merge : sync final DeepSeek V4.1 expert execution
Sep 13, 2026
7a3f93e
deepseek41 : enforce fixed memory ceilings
Sep 13, 2026
1da527c
scripts : cap Strix watchdog thresholds
Sep 13, 2026
e18f4e6
deepseek41 : compare complete cache slot caps
Sep 13, 2026
952ff22
deepseek41 : account Engram selection staging
Sep 13, 2026
ea8f88d
deepseek41 : close admission envelope gaps
Sep 13, 2026
e8bcaf1
deepseek41 : keep output admission immutable
Sep 13, 2026
8b1ee95
deepseek41 : report ignored device memory
Sep 13, 2026
0419952
deepseek41 : reject unadmitted embedding outputs
Sep 13, 2026
8d9947d
Merge DeepSeek V4.1 full graph into memory admission
Sep 13, 2026
b26c0e6
Merge commit '8cbc9e66e3331b5962e56e6b7effaba14ef7943f' into jeromeco…
Sep 13, 2026
c5d1c45
deepseek41 : close final admission review gaps
Sep 13, 2026
d0a1616
Merge commit '081c549451b92c01fe832ffb0bdd9ad90370e21a' into jeromeco…
Sep 13, 2026
8acdb46
scripts : forward SIGHUP through memory watchdog
Sep 13, 2026
04dd21c
Merge canonical Strix memory watchdog
Sep 13, 2026
a127c19
deepseek41 : close admission envelope blockers
Sep 13, 2026
5983301
scripts : publish watchdog-owned validation lease
Sep 13, 2026
09349ff
Merge canonical Strix watchdog lease
Sep 13, 2026
265f3df
deepseek41 : bind final validation envelope
Sep 13, 2026
c4598ee
scripts : harden watchdog fail-closed lease
Sep 13, 2026
0071e8f
scripts : harden watchdog cleanup lease
Sep 13, 2026
cd97b50
scripts : enforce cleanup on guardian errors
Sep 13, 2026
f6b4da4
scripts : preserve watchdog failure cause
Sep 13, 2026
778db6f
scripts : retain watchdog artifact evidence
Sep 13, 2026
8badaf9
Merge approved Strix watchdog hardening
Sep 13, 2026
c2c98de
scripts : restore approved watchdog artifacts
Sep 13, 2026
4f4a47f
common : make DeepSeek defaults admission-safe
Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Everything else is upstream `llama.cpp`. The additions currently carried here:
| Speculative checkpoints on device | | `llama-server` keeps speculative-decoding checkpoints in device memory instead of copying them to the host |
| ROCmFPx quant types | `llama-quantize` types `Q4_0_ROCMFP4`, `Q4_0_ROCMFP4_FAST`, `Q2/Q3/Q6/Q8_0_ROCMFPX` and the `_LEAN`/`_COHERENT`/`_STRIX` recipes | Loads the ROCmFP4 GGUFs published for Strix Halo. CPU codecs plus Vulkan dequant, mat-vec, matmul and integer-dot kernels. Weight formats only: not accepted as KV-cache types |
| Repeatable output at depth | | Freed KV cells are zeroed so masked-out rows never carry stale K/V, and the Vulkan radix top-k assigns output slots deterministically |
| DeepSeek V4.1 memory guard | [`scripts/strix_memory_watchdog.py`](docs/strix-memory-watchdog.md) | In-process admission auto-fits expert slots under 116 GiB before allocation; the external process-group watchdog requires zero swap and stops before the 120 GiB validation ceiling |

Every ROCm/HIP change above is guarded on architecture, shape and layout, so other devices see upstream behaviour.
Run `--help`, or see [tools/server/README.md](tools/server/README.md), for the full options.
Expand Down
61 changes: 57 additions & 4 deletions common/arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
string_format("physical maximum batch size (default: %d)", params.n_ubatch),
[](common_params & params, int value) {
params.n_ubatch = value;
params.n_ubatch_explicit = true;
}
).set_env("LLAMA_ARG_UBATCH"));
add_opt(common_arg(
Expand Down Expand Up @@ -2568,6 +2569,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
throw std::invalid_argument("error: invalid value for n_parallel\n");
}
params.n_parallel = value;
params.n_parallel_explicit = value != -1;
}
).set_env("LLAMA_ARG_N_PARALLEL").set_examples({LLAMA_EXAMPLE_SERVER}));
} else {
Expand All @@ -2576,6 +2578,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
string_format("number of parallel sequences to decode (default: %d)", params.n_parallel),
[](common_params & params, int value) {
params.n_parallel = value;
params.n_parallel_explicit = true;
}
).set_env("LLAMA_ARG_N_PARALLEL"));
}
Expand Down Expand Up @@ -2808,24 +2811,74 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
).set_env("LLAMA_ARG_NGRAM_DIRECT_IO"));
add_opt(common_arg(
{"--expert-cache-slots"}, "N",
"DeepSeek V4.1 routed experts resident per layer; requires --expert-cache-mib",
"maximum DeepSeek V4.1 routed experts resident per layer; 0 auto-fits",
[](common_params & params, int value) {
if (value <= 0) {
if (value < 0) {
throw std::invalid_argument("invalid value");
}
params.expert_cache_slots = value;
}
).set_env("LLAMA_ARG_EXPERT_CACHE_SLOTS"));
add_opt(common_arg(
{"--expert-cache-mib"}, "MiB",
"aggregate DeepSeek V4.1 fixed expert slot-tensor capacity; requires --expert-cache-slots",
"exact aggregate DeepSeek V4.1 expert cache capacity; 0 auto-fits",
[](common_params & params, int value) {
if (value <= 0) {
if (value < 0) {
throw std::invalid_argument("invalid value");
}
params.expert_cache_mib = value;
}
).set_env("LLAMA_ARG_EXPERT_CACHE_MIB"));
add_opt(common_arg(
{"--dsv41-memory-soft-mib"}, "MiB",
string_format("DeepSeek V4.1 total host-use startup target (default: %d)", params.dsv41_memory_soft_mib),
[](common_params & params, int value) {
if (value <= 0) {
throw std::invalid_argument("invalid value");
}
params.dsv41_memory_soft_mib = value;
}
).set_env("LLAMA_ARG_DSV41_MEMORY_SOFT_MIB"));
add_opt(common_arg(
{"--dsv41-memory-watchdog-mib"}, "MiB",
string_format("DeepSeek V4.1 external watchdog emergency threshold (default: %d)", params.dsv41_memory_watchdog_mib),
[](common_params & params, int value) {
if (value <= 0) {
throw std::invalid_argument("invalid value");
}
params.dsv41_memory_watchdog_mib = value;
}
).set_env("LLAMA_ARG_DSV41_MEMORY_WATCHDOG_MIB"));
add_opt(common_arg(
{"--dsv41-memory-hard-mib"}, "MiB",
string_format("DeepSeek V4.1 strict host-use ceiling (default: %d)", params.dsv41_memory_hard_mib),
[](common_params & params, int value) {
if (value <= 0) {
throw std::invalid_argument("invalid value");
}
params.dsv41_memory_hard_mib = value;
}
).set_env("LLAMA_ARG_DSV41_MEMORY_HARD_MIB"));
add_opt(common_arg(
{"--dsv41-memory-safety-margin-mib"}, "MiB",
string_format("DeepSeek V4.1 explicit startup safety margin (default: %d)", params.dsv41_memory_safety_margin_mib),
[](common_params & params, int value) {
if (value <= 0) {
throw std::invalid_argument("invalid value");
}
params.dsv41_memory_safety_margin_mib = value;
}
).set_env("LLAMA_ARG_DSV41_MEMORY_SAFETY_MARGIN_MIB"));
add_opt(common_arg(
{"--dsv41-procfs-root"}, "PATH",
"procfs root used by DeepSeek V4.1 host-memory admission (default: /proc)",
[](common_params & params, const std::string & value) {
if (value.empty()) {
throw std::invalid_argument("invalid value");
}
params.dsv41_procfs_root = value;
}
).set_env("LLAMA_ARG_DSV41_PROCFS_ROOT"));
add_opt(common_arg(
{"-cmoe", "--cpu-moe"},
"keep all Mixture of Experts (MoE) weights in the CPU",
Expand Down
51 changes: 51 additions & 0 deletions common/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,11 @@ common_init_result::common_init_result(common_params & params, bool model_only)
return;
}

char architecture[128] = {};
if (llama_model_meta_val_str(model, "general.architecture", architecture, sizeof(architecture)) >= 0) {
common_context_params_apply_arch_defaults(architecture, params, cparams);
}

const llama_vocab * vocab = llama_model_get_vocab(model);

// load and optionally apply lora adapters
Expand Down Expand Up @@ -1699,6 +1704,32 @@ struct llama_model_params common_model_params_to_llama(common_params & params) {
mparams.ple_cache_mb = params.ple_cache_mb;
mparams.expert_cache_slots = params.expert_cache_slots;
mparams.expert_cache_bytes = params.expert_cache_mib > 0 ? (size_t) params.expert_cache_mib << 20 : 0;
mparams.dsv41_memory_soft_bytes = (uint64_t) params.dsv41_memory_soft_mib << 20;
mparams.dsv41_memory_watchdog_bytes = (uint64_t) params.dsv41_memory_watchdog_mib << 20;
mparams.dsv41_memory_hard_bytes = (uint64_t) params.dsv41_memory_hard_mib << 20;
mparams.dsv41_memory_safety_margin_bytes = (uint64_t) params.dsv41_memory_safety_margin_mib << 20;
const uint32_t dsv41_admission_sequences = params.n_parallel_explicit ?
std::max(params.n_parallel, 1) : 1;
mparams.dsv41_admission_context =
params.n_ctx_auto_sized && !params.n_parallel_explicit ?
std::max(params.kv_unified_per_slot, 1) :
(params.n_ctx == 0 ? 32768 : params.n_ctx);
mparams.dsv41_admission_batch = std::max(params.n_batch, 1);
mparams.dsv41_admission_sequences = dsv41_admission_sequences;
mparams.dsv41_admission_ubatch = std::min(
mparams.dsv41_admission_batch,
static_cast<uint32_t>(params.n_ubatch_explicit ? std::max(params.n_ubatch, 1) : 32));
mparams.dsv41_admission_outputs = params.n_outputs_max <= 0 ?
mparams.dsv41_admission_batch :
std::min<uint32_t>(params.n_outputs_max, mparams.dsv41_admission_batch);
mparams.dsv41_admission_outputs = std::max<uint32_t>(
mparams.dsv41_admission_outputs, dsv41_admission_sequences);
mparams.dsv41_admission_outputs_per_seq = params.n_outputs_max_per_seq == 0 ?
mparams.dsv41_admission_outputs :
std::min<uint32_t>(std::max(params.n_outputs_max_per_seq, 1), mparams.dsv41_admission_outputs);
mparams.dsv41_admission_type_k = params.cache_type_k;
mparams.dsv41_procfs_root = params.dsv41_procfs_root.c_str();
mparams.dsv41_admission_offload_kqv = !params.no_kv_offload;

if (params.kv_overrides.empty()) {
mparams.kv_overrides = NULL;
Expand All @@ -1722,6 +1753,26 @@ struct llama_model_params common_model_params_to_llama(common_params & params) {
return mparams;
}

void common_context_params_apply_arch_defaults(
const char * architecture,
common_params & params,
llama_context_params & cparams) {
if (architecture == nullptr || strcmp(architecture, "deepseek41") != 0) {
return;
}
if (!params.n_parallel_explicit) {
params.n_parallel = 1;
cparams.n_seq_max = 1;
if (params.n_ctx_auto_sized) {
params.n_ctx = params.kv_unified_per_slot;
cparams.n_ctx = params.n_ctx;
}
}
if (!params.n_ubatch_explicit) {
cparams.n_ubatch = std::min<uint32_t>(cparams.n_batch, 32);
}
}

struct llama_context_params common_context_params_to_llama(const common_params & params) {
auto cparams = llama_context_default_params();

Expand Down
16 changes: 14 additions & 2 deletions common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -489,11 +489,14 @@ struct ggml_opt_optimizer_params common_opt_lr_pars(void * userdata);
struct common_params {
int32_t n_predict = -1; // max. number of new tokens to predict, -1 == no limit
int32_t n_ctx = 0; // context size, 0 == context the model was trained with
bool n_ctx_auto_sized = false;
int32_t n_batch = 2048; // logical batch size for prompt processing (must be >=32 to use BLAS)
int32_t n_ubatch = 512; // physical batch size for prompt processing (must be >=32 to use BLAS)
bool n_ubatch_explicit = false;
int32_t n_keep = 0; // number of tokens to keep from initial prompt
int32_t n_chunks = -1; // max number of chunks to process (-1 = unlimited)
int32_t n_parallel = 1; // number of parallel sequences to decode
bool n_parallel_explicit = false;
int32_t n_sequences = 1; // number of sequences to decode
int32_t n_outputs_max = 0; // max outputs in a batch (0 = n_batch)
int32_t n_outputs_max_per_seq = 1; // max outputs per sequence
Expand Down Expand Up @@ -626,8 +629,13 @@ struct common_params {
bool ple_direct_io = true; // ... read with O_DIRECT
int32_t ple_io_threads = 64; // ... parallel readers (random 4 KiB reads: this NVMe gives 62k IOPS at 16, 130k at 64, ~160k at 128+)
int32_t ple_cache_mb = 256; // ... row cache, 0 disables
int32_t expert_cache_slots = 0; // DeepSeek V4.1 routed experts resident per layer
int32_t expert_cache_mib = 0; // aggregate fixed slot-tensor capacity
int32_t expert_cache_slots = 0; // DeepSeek V4.1 routed experts resident per layer, 0 auto-fits
int32_t expert_cache_mib = 0; // exact aggregate cache bytes, 0 auto-fits
int32_t dsv41_memory_soft_mib = 116*1024;
int32_t dsv41_memory_watchdog_mib = 118*1024;
int32_t dsv41_memory_hard_mib = 120*1024;
int32_t dsv41_memory_safety_margin_mib = 2*1024;
std::string dsv41_procfs_root = "/proc";

bool single_turn = false; // single turn chat conversation

Expand Down Expand Up @@ -996,6 +1004,10 @@ common_init_result_ptr common_init_from_params(common_params & params, bool mode

struct llama_model_params common_model_params_to_llama ( common_params & params);
struct llama_context_params common_context_params_to_llama(const common_params & params);
void common_context_params_apply_arch_defaults(
const char * architecture,
common_params & params,
struct llama_context_params & cparams);

// clear LoRA adapters from context, then apply new list of adapters
void common_set_adapter_lora(struct llama_context * ctx, std::vector<common_adapter_lora_info> & lora);
Expand Down
34 changes: 32 additions & 2 deletions common/fit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

#include <array>
#include <cassert>
#include <stdexcept>
#include <cinttypes>
#include <cstring>
#include <set>
#include <stdexcept>
#include <string>
#include <vector>

Expand All @@ -26,6 +27,30 @@ class common_params_fit_exception : public std::runtime_error {
using std::runtime_error::runtime_error;
};

void common_fit_context_params_apply_arch_defaults(
const char * architecture,
const llama_model_params & mparams,
llama_context_params & cparams) {
if (architecture == nullptr || strcmp(architecture, "deepseek41") != 0) {
return;
}

cparams.n_ctx = cparams.n_ctx == 0 ?
mparams.dsv41_admission_context :
std::min(cparams.n_ctx, mparams.dsv41_admission_context);
cparams.n_batch = std::min(cparams.n_batch, mparams.dsv41_admission_batch);
cparams.n_seq_max = std::min(cparams.n_seq_max, mparams.dsv41_admission_sequences);
cparams.n_ubatch = cparams.n_ubatch == 0 || cparams.n_ubatch == UINT32_MAX ?
mparams.dsv41_admission_ubatch :
std::min(cparams.n_ubatch, mparams.dsv41_admission_ubatch);
cparams.n_outputs_max = cparams.n_outputs_max == 0 ?
mparams.dsv41_admission_outputs :
std::min(cparams.n_outputs_max, mparams.dsv41_admission_outputs);
cparams.n_outputs_max_per_seq = cparams.n_outputs_max_per_seq == 0 ?
mparams.dsv41_admission_outputs_per_seq :
std::min(cparams.n_outputs_max_per_seq, mparams.dsv41_admission_outputs_per_seq);
}

static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
const char * path_model,
const llama_model_params * mparams,
Expand Down Expand Up @@ -62,7 +87,12 @@ static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
throw std::runtime_error("failed to load model");
}

llama_context * ctx = llama_init_from_model(model, *cparams);
llama_context_params cparams_copy = *cparams;
char architecture[128] = {};
if (llama_model_meta_val_str(model, "general.architecture", architecture, sizeof(architecture)) >= 0) {
common_fit_context_params_apply_arch_defaults(architecture, mparams_copy, cparams_copy);
}
llama_context * ctx = llama_init_from_model(model, cparams_copy);
if (ctx == nullptr) {
llama_model_free(model);
llama_log_set(ud.original_logger.callback, ud.original_logger.user_data);
Expand Down
5 changes: 5 additions & 0 deletions common/fit.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ struct common_fit_extra_model {
bool shares_model;
};

void common_fit_context_params_apply_arch_defaults(
const char * architecture,
const llama_model_params & mparams,
llama_context_params & cparams);

// fits mparams and cparams to free device memory (assumes system memory is unlimited)
// - returns true if the parameters could be successfully modified to fit device memory
// - this function is NOT thread safe because it modifies the global llama logger state
Expand Down
Loading
Loading