From: Meshnet Subject: [PATCH] llama: expose worker-owned range report hook and fixture Concern: worker hooks. Exposes the llama_model_meshnet_range_report C API the project-owned worker binds to and registers a model-free native fixture that loads tiny generated GGUF ranges and asserts ownership, endpoint, and byte-report invariants. --- diff --git a/include/llama.h b/include/llama.h index 8a7521349..5818daf94 100644 --- a/include/llama.h +++ b/include/llama.h @@ -613,6 +613,13 @@ extern "C" { // Get metadata value as a string by key name LLAMA_API int32_t llama_model_meta_val_str(const struct llama_model * model, const char * key, char * buf, size_t buf_size); + // Returns false unless this model was instantiated through the Meshnet + // owned-range loader. Values are derived from registered tensors and + // backend buffers, never copied from caller-supplied parameters. + LLAMA_API bool llama_model_meshnet_range_report( + const struct llama_model * model, + struct llama_meshnet_range_report * out); + // Get the number of metadata key/value pairs LLAMA_API int32_t llama_model_meta_count(const struct llama_model * model); diff --git a/src/llama-model.cpp b/src/llama-model.cpp index 2ea8598ad..c9d3cf6d3 100644 --- a/src/llama-model.cpp +++ b/src/llama-model.cpp @@ -2695,6 +2695,10 @@ uint64_t llama_model_size(const llama_model * model) { return model->size(); } +bool llama_model_meshnet_range_report(const llama_model * model, llama_meshnet_range_report * out) { + return model != nullptr && model->meshnet_range_report(out); +} + const char * llama_model_chat_template(const llama_model * model, const char * name) { const auto key = name ? LLM_KV(model->arch, name)(LLM_KV_TOKENIZER_CHAT_TEMPLATE) : LLM_KV(model->arch)(LLM_KV_TOKENIZER_CHAT_TEMPLATE); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 855295c15..9a7be6eed 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -193,6 +193,7 @@ if (NOT WIN32 OR NOT BUILD_SHARED_LIBS) # llama_build_and_test(test-double-float.cpp) # SLOW llama_build_and_test(test-llama-archs.cpp) + llama_build_and_test(test-meshnet-range-ownership.cpp) endif() llama_build_and_test(test-chat-peg-parser.cpp peg-parser/simple-tokenize.cpp) diff --git a/tests/test-meshnet-range-ownership.cpp b/tests/test-meshnet-range-ownership.cpp new file mode 100644 index 000000000..6b3aa5ac5 100644 --- /dev/null +++ b/tests/test-meshnet-range-ownership.cpp @@ -0,0 +1,143 @@ +#include "ggml.h" +#include "gguf.h" +#include "llama.h" + +#include "../src/llama-model.h" + +#include +#include +#include +#include + +namespace { + +constexpr int kLayers = 4; +constexpr int kEmbd = 8; +constexpr int kFfn = 16; +constexpr int kVocab = 16; + +void check(bool condition, const char * message) { + if (!condition) { + throw std::runtime_error(message); + } +} + +void add_tensor(gguf_context * gguf, ggml_context * tensors, const char * name, int d0, int d1 = 1) { + ggml_tensor * tensor = d1 == 1 + ? ggml_new_tensor_1d(tensors, GGML_TYPE_F32, d0) + : ggml_new_tensor_2d(tensors, GGML_TYPE_F32, d0, d1); + ggml_set_name(tensor, name); + std::memset(tensor->data, 0, ggml_nbytes(tensor)); + gguf_add_tensor(gguf, tensor); +} + +std::string write_fixture() { + const std::string path = "meshnet-dense-llama-range-fixture.gguf"; + gguf_context * gguf = gguf_init_empty(); + ggml_init_params params = { 128 * 1024, nullptr, false }; + ggml_context * tensors = ggml_init(params); + check(gguf && tensors, "failed to create dense-Llama fixture contexts"); + + gguf_set_val_str(gguf, "general.architecture", "llama"); + gguf_set_val_u32(gguf, "llama.context_length", 16); + gguf_set_val_u32(gguf, "llama.embedding_length", kEmbd); + gguf_set_val_u32(gguf, "llama.block_count", kLayers); + gguf_set_val_u32(gguf, "llama.feed_forward_length", kFfn); + gguf_set_val_u32(gguf, "llama.attention.head_count", 2); + gguf_set_val_u32(gguf, "llama.attention.head_count_kv", 2); + gguf_set_val_u32(gguf, "llama.rope.dimension_count", 4); + gguf_set_val_f32(gguf, "llama.attention.layer_norm_rms_epsilon", 1.0e-5f); + gguf_set_val_str(gguf, "tokenizer.ggml.model", "no_vocab"); + gguf_set_val_u32(gguf, "llama.vocab_size", kVocab); + + add_tensor(gguf, tensors, "token_embd.weight", kEmbd, kVocab); + add_tensor(gguf, tensors, "output_norm.weight", kEmbd); + add_tensor(gguf, tensors, "output.weight", kEmbd, kVocab); + for (int layer = 0; layer < kLayers; ++layer) { + const std::string p = "blk." + std::to_string(layer) + "."; + add_tensor(gguf, tensors, (p + "attn_norm.weight").c_str(), kEmbd); + add_tensor(gguf, tensors, (p + "attn_q.weight").c_str(), kEmbd, kEmbd); + add_tensor(gguf, tensors, (p + "attn_k.weight").c_str(), kEmbd, kEmbd); + add_tensor(gguf, tensors, (p + "attn_v.weight").c_str(), kEmbd, kEmbd); + add_tensor(gguf, tensors, (p + "attn_output.weight").c_str(), kEmbd, kEmbd); + add_tensor(gguf, tensors, (p + "ffn_norm.weight").c_str(), kEmbd); + add_tensor(gguf, tensors, (p + "ffn_gate.weight").c_str(), kEmbd, kFfn); + add_tensor(gguf, tensors, (p + "ffn_down.weight").c_str(), kFfn, kEmbd); + add_tensor(gguf, tensors, (p + "ffn_up.weight").c_str(), kEmbd, kFfn); + } + check(gguf_write_to_file(gguf, path.c_str(), false), "failed to write dense-Llama fixture"); + ggml_free(tensors); + gguf_free(gguf); + return path; +} + +int block_number(const std::string & name) { + int block = -1; + return std::sscanf(name.c_str(), "blk.%d.", &block) == 1 ? block : -1; +} + +bool is_allowed_endpoint_tensor(const std::string & name, int start, int end) { + if (name == "token_embd.weight") { + return start == 0; + } + if (name == "output_norm.weight" || name == "output.weight") { + return end == kLayers; + } + return false; +} + +llama_meshnet_range_report load_and_check(const std::string & path, int start, int end) { + llama_model_params params = llama_model_default_params(); + params.meshnet_owned_layer_start = start; + params.meshnet_owned_layer_end = end; + llama_model * model = llama_model_load_from_file(path.c_str(), params); + check(model != nullptr, "failed to load dense-Llama fixture"); + + llama_meshnet_range_report report = {}; + check(llama_model_meshnet_range_report(model, &report), "range report is absent"); + check(report.start_layer == start, "reported start does not match registered range"); + check(report.end_layer == end, "reported end does not match registered range"); + check(report.mapped_bytes > 0, "mmap report is empty"); + check(report.resident_bytes >= report.mapped_bytes, "resident bytes undercount mapped bytes"); + check(report.has_token_embeddings == (start == 0), "token-embedding ownership is not the head endpoint"); + check(report.has_output_head == (end == kLayers), "output-head ownership is not the tail endpoint"); + + const auto & tensors = llama_internal_get_tensor_map(model); + check(!tensors.empty(), "no tensors registered for owned range"); + for (const auto & [name, _] : tensors) { + const int block = block_number(name); + check((block >= start && block < end) || (block == -1 && is_allowed_endpoint_tensor(name, start, end)), + "registered tensor is outside the owned range and its endpoints"); + } + llama_model_free(model); + return report; +} + +} // namespace + +int main() { + llama_backend_init(); + const std::string fixture = write_fixture(); + + const auto head = load_and_check(fixture, 0, 1); + const auto middle = load_and_check(fixture, 1, 3); + load_and_check(fixture, 3, 4); + check(middle.mapped_bytes > head.mapped_bytes, "two-layer range did not map more bytes than head"); + + // A stock load has no owned-range report and registers every tensor. + llama_model * stock = llama_model_load_from_file(fixture.c_str(), llama_model_default_params()); + check(stock != nullptr, "stock load failed"); + llama_meshnet_range_report stock_report = {}; + check(!llama_model_meshnet_range_report(stock, &stock_report), "stock load reported an owned range"); + check(llama_internal_get_tensor_map(stock).size() == 3 + 9 * kLayers, "stock load lost tensors"); + llama_model_free(stock); + + llama_model_params invalid = llama_model_default_params(); + invalid.meshnet_owned_layer_start = 3; + invalid.meshnet_owned_layer_end = 5; + check(llama_model_load_from_file(fixture.c_str(), invalid) == nullptr, "invalid range loaded"); + + std::remove(fixture.c_str()); + llama_backend_free(); + return 0; +}