Files
llama.cpp-xrip/tests/llama-context/test-case.cpp
T
Georgi Gerganov a17e94d229 tests : consolidate context state tests into test-llama-context (#30023)
* tests : consolidate the context state tests into test-llama-context

test-save-load-state, test-recurrent-state-rollback and
test-state-restore-fragmented check the same object from three places:
the KV cache and the recurrent state of a llama_context, saved, loaded,
copied, rolled back. Each had its own main, its own loop over the
models, its own copy of the token and the comparison helpers, and a run
of all three loaded the same models several times.

They are one binary now, and the case is the unit of the test:

  tests/llama-context/test-case.h   the interface a case implements
  tests/llama-context/cases-kv.cpp  the cases of the KV cache
  tests/llama-context/cases-rs.cpp  the cases of the recurrent state
  tests/llama-context/test-util.cpp tokens, generation, comparison
  tests/llama-context/test-runner.cpp the models of a case, on threads
  tests/llama-context/test-log.cpp  the log file of a model

A run is a table: a row per model, a column per case, a cell holds the
verdict of that pair. The models load on several threads (-j, --threads,
min(cores, 4) by default), the table is printed when it is complete and
the log of a model that failed is printed after it, in the order of the
rows. A case returns a verdict and the reason for it, and the runner is
the only one who reports - the test does not use tests/testing.h, a run
over 130 models is a matrix of verdicts and not a tree of subtests.

Staging no longer travels through the environment: llama_model_set_attn_rot
replaces the LLAMA_ATTN_ROT_DISABLE variable, which a model loaded in one
thread used to change for the models the other threads were loading, and
llama_memory_get_buffers is added for the cases that copy the buffers of
a memory. common_log_set_stdo keeps the console quiet while the table is
being built.

ggml_aligned_malloc allocates with posix_memalign when the thread
sanitizer is on. On macOS it allocates with the Mach VM, which the
sanitizer does not intercept, so it never sees a page range change hands
and reports the first write into recycled memory as a race - 30 of them
in this test, and every one of them false.

Assisted-by: pi:llama.cpp/Qwen3.8-Flash-Next

* cont : run single-threaded by default

* cont : try to build the tests on all platforms

* cont : trim down some body fat

* cont : fix

* cont : fix the fix
2026-10-13 16:21:55 +03:00

70 lines
1.9 KiB
C++

#include "test-case.h"
#include <iterator>
const char * test_status_str(test_status status) {
switch (status) {
case test_status::PASS: return "\033[1;32mOK\033[0m";
case test_status::FAIL: return "\033[1;31mFAIL\033[0m";
case test_status::SKIP: return "\033[1;33mSKIP\033[0m";
}
return "";
}
// the printable width of a verdict, the color escapes of test_status_str are not part of it
size_t test_status_width(test_status status) {
switch (status) {
case test_status::PASS: return 2; // "OK"
case test_status::FAIL: return 4; // "FAIL"
case test_status::SKIP: return 4; // "SKIP"
}
return 0;
}
test_status merge_status(test_status a, test_status b) {
if (a == test_status::FAIL || b == test_status::FAIL) {
return test_status::FAIL;
}
if (a == test_status::PASS || b == test_status::PASS) {
return test_status::PASS;
}
return test_status::SKIP;
}
case_result case_result::pass() {
return { test_status::PASS, {} };
}
case_result case_result::fail(const std::string & why) {
return { test_status::FAIL, why };
}
case_result case_result::skip(const std::string & why) {
return { test_status::SKIP, why };
}
std::string ctx_test::skip_reason(model_run & mr) const {
// the recurrent cases need a recurrent cache, the KV cases work with any model
if (group() == TEST_GROUP_RS && !mr.is_recurrent()) {
return "not a recurrent model";
}
return {};
}
const std::vector<ctx_test_ptr> & test_cases() {
static const std::vector<ctx_test_ptr> cases = [] {
std::vector<ctx_test_ptr> res;
for (const auto & maker : { make_kv_cases, make_rs_cases }) {
auto part = maker();
res.insert(res.end(), std::make_move_iterator(part.begin()), std::make_move_iterator(part.end()));
}
return res;
}();
return cases;
}