* 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
70 lines
1.9 KiB
C++
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;
|
|
}
|