mirror of
https://github.com/ggml-org/whisper.cpp.git
synced 2026-10-12 17:25:39 +02:00
tests : refactor test-recurrent-state-rollback (llama/29426)
* tests : use llama_context_ptr in test-recurrent-state-rollback Replace raw llama_context pointers with llama_context_ptr and drop the manual llama_free calls and cleanup lambda. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL * tests : run test-recurrent-state-rollback over all dummy models Add a --models DIR mode that mirrors test-save-load-state: iterate every dummy model, report PASS/FAIL/SKIP in a table and fail only when a model fails. Register a single ctest entry with ARGS --models instead of the four per-model registrations. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL * cont : fix typo * metal : allow fusing 0-element nodes to keep graph packing shape-independent The fusion packing in ggml_metal_fusion_max excluded 0-element tensors and the topk_moe/moe_reduce checks rejected n_tokens == 0, so graphs decoding batches with no outputs packed differently from the worst-case reserved graph. The Metal optimizer then reordered the nodes differently and ggml_gallocr_needs_realloc failed on the layout mismatch, forcing an unexpected graph re-reserve (caught by GGML_SCHED_DEBUG_REALLOC). Treat empty tensors like their non-empty counterparts: match them in the pattern sequence and only reject genuinely malformed shapes. Fused kernels dispatch zero threadgroups for empty graphs, which is a legal no-op. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL * tests : run test_multi_seq_split_replay as a separate test test_multi_seq_split_replay was invoked at the end of test_rollback, so its result was folded into the rollback status and it only ran when the rollback part passed. Give it its own test_status return, run both tests independently over both cache fills via a shared run_tests helper, and report them as separate rollback / split replay columns in the --models table with per-test summaries. The exit code fails when either test fails. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL * tests : loosen the split replay nmse bound to 1e-4 test-generate-models seeds its weights from std::random_device, and some generated lfm2 models drift up to ~1.7e-5 nmse on the split replay due to rounding noise, tripping the previous 1e-5 bound. Raise the bound to 1e-4 so the random generations stop flaking. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL * tests : reuse run_tests_for_model in single-model mode The single-model path duplicated the model init and the non-recurrent check from run_tests_for_model; route it through the shared helper instead. Model load failures now return FAIL rather than SKIP so that --model with a broken file still exits non-zero, and the helper loads with model_only like the --models loop does since the tests create their own contexts. Assisted-by: pi:llama.cpp/MiMo-V2.6-Flash-RL
This commit is contained in:
@@ -418,7 +418,8 @@ static bool ggml_metal_fusion_check_topk_moe(
|
||||
const int64_t n_tokens = logits->ne[1];
|
||||
const int64_t n_expert_used = ids->ne[0];
|
||||
|
||||
if (n_expert <= 0 || n_tokens <= 0 || n_expert_used <= 0 || n_expert_used > n_expert ||
|
||||
// note: n_tokens == 0 (no-output batch) must match so that the packing stays shape-independent
|
||||
if (n_expert <= 0 || n_expert_used <= 0 || n_expert_used > n_expert ||
|
||||
n_expert > GGML_METAL_TOPK_MOE_MAX_EXPERTS || n_expert_used > GGML_METAL_TOPK_MOE_MAX_EXPERTS) {
|
||||
return false;
|
||||
}
|
||||
@@ -545,7 +546,8 @@ static bool ggml_metal_fusion_match_moe_reduce(
|
||||
const int64_t n_embd = experts->ne[0];
|
||||
const int64_t n_tokens = experts->ne[2];
|
||||
|
||||
if (n_embd <= 0 || n_tokens <= 0 || experts->ne[1] != n_expert_used || experts->ne[3] != 1 ||
|
||||
// note: n_tokens == 0 (no-output batch) must match so that the packing stays shape-independent
|
||||
if (n_embd <= 0 || experts->ne[1] != n_expert_used || experts->ne[3] != 1 ||
|
||||
weights->ne[0] != 1 || weights->ne[1] != n_expert_used || weights->ne[2] != n_tokens || weights->ne[3] != 1 ||
|
||||
dst->ne[0] != n_embd || dst->ne[1] != n_tokens || dst->ne[2] != 1 || dst->ne[3] != 1) {
|
||||
return false;
|
||||
@@ -1079,16 +1081,17 @@ const ggml_metal_fusion * ggml_metal_fusion_next(
|
||||
// transparent) node sequence that the compute phase uses, so the returned count is the raw index
|
||||
// span from idx to the last matched node (intermediate views are packed along).
|
||||
int ggml_metal_fusion_max(const ggml_cgraph * gf, int idx) {
|
||||
// an empty/view node cannot start a pattern - pack it alone
|
||||
if (ggml_op_is_empty(gf->nodes[idx]->op) || ggml_is_empty(gf->nodes[idx])) {
|
||||
// a view node cannot start a pattern - pack it alone
|
||||
if (ggml_op_is_empty(gf->nodes[idx]->op)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// collect the non-empty node indices starting at idx
|
||||
// collect the non-view node indices starting at idx; 0-element tensors are included so
|
||||
// that empty graphs pack like their non-empty counterparts (see ggml_metal_fusion_filter_ops)
|
||||
int idxs[GGML_METAL_FUSION_MAX];
|
||||
int n_idxs = 0;
|
||||
for (int i = idx; i < gf->n_nodes && n_idxs < GGML_METAL_FUSION_MAX; i++) {
|
||||
if (!ggml_op_is_empty(gf->nodes[i]->op) && !ggml_is_empty(gf->nodes[i])) {
|
||||
if (!ggml_op_is_empty(gf->nodes[i]->op)) {
|
||||
idxs[n_idxs++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user