From: Meshnet Subject: [PATCH] llama: add dense-Llama owned-range report tool Concern: range reporting. Adds the project-owned meshnet-range-report tool: it loads one GGUF artifact through the Meshnet owned-range loader and prints a JSON document derived from the loaded model state — the owned-range report, the registered tensor set audited against the requested ownership, and backend-buffer byte counts (optionally split from repack buffers, plus process resident readings). It never builds or runs a compute graph and never trusts caller-asserted range or endpoint claims. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index a9afcff..868793b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -281,3 +281,6 @@ configure_file(cmake/llama.pc.in install(FILES "${CMAKE_CURRENT_BINARY_DIR}/llama.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +# Meshnet-owned owned-range report tool (patch stack, range-report concern). +add_subdirectory(tools/meshnet-range-report) diff --git a/tools/meshnet-range-report/CMakeLists.txt b/tools/meshnet-range-report/CMakeLists.txt new file mode 100644 index 000000000..24401007e --- /dev/null +++ b/tools/meshnet-range-report/CMakeLists.txt @@ -0,0 +1,7 @@ +# Meshnet-owned dense-Llama owned-range load/report tool. +# +# Built unconditionally with the patched tree: it exercises the Meshnet +# owned-range loader against real GGUF artifacts and reports only state +# derived from the loaded model (registered tensors, backend buffers). +add_executable(meshnet-range-report meshnet-range-report.cpp) +target_link_libraries(meshnet-range-report PRIVATE llama) diff --git a/tools/meshnet-range-report/meshnet-range-report.cpp b/tools/meshnet-range-report/meshnet-range-report.cpp new file mode 100644 index 000000000..49a5eb2a0 --- /dev/null +++ b/tools/meshnet-range-report/meshnet-range-report.cpp @@ -0,0 +1,373 @@ +// Meshnet-owned dense-Llama owned-range load/report tool. +// +// Loads one GGUF artifact through the Meshnet owned-range loader +// (llama_model_params::meshnet_owned_layer_start/end) and prints a single +// JSON report derived from the loaded model state — registered tensors and +// backend buffers, never caller-asserted values. The audit fails closed when +// the registered tensor set disagrees with the requested ownership: every +// registered per-layer tensor must lie inside [start, end), the token +// embedding may be registered only by the head shard (start == 0) or by a +// tail shard whose model ties the output head to the embedding, and the +// final norm plus output head may be registered only by the tail shard +// (end == n_layer). + +#include "ggml.h" +#include "llama.h" + +#include "../../src/llama-model.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +constexpr int kExitUsage = 2; +constexpr int kExitLoad = 3; +constexpr int kExitAudit = 4; + +std::string g_log_tail; + +void capture_log(enum ggml_log_level level, const char * text, void *) { + if (level >= GGML_LOG_LEVEL_ERROR) { + g_log_tail += text; + if (g_log_tail.size() > 512) { + g_log_tail.erase(0, g_log_tail.size() - 512); + } + } +} + +std::string json_escape(const std::string & value) { + std::string out; + for (const char c : value) { + if (c == '"' || c == '\\') { + out += '\\'; + out += c; + } else if (c == '\n') { + out += "\\n"; + } else if (c == '\r') { + // drop carriage returns from embedded log text + } else { + out += c; + } + } + return out; +} + +std::string json_string_array(const std::vector & items) { + std::string out = "["; + for (size_t i = 0; i < items.size(); ++i) { + if (i) { + out += ", "; + } + out += "\"" + json_escape(items[i]) + "\""; + } + return out + "]"; +} + +std::string json_int_array(const std::vector & items) { + std::string out = "["; + for (size_t i = 0; i < items.size(); ++i) { + if (i) { + out += ", "; + } + out += std::to_string(items[i]); + } + return out + "]"; +} + +int fail(int code, const std::string & error) { + std::string detail = error; + if (!g_log_tail.empty()) { + detail += ": " + g_log_tail; + } + std::printf("{\"ok\": false, \"error\": \"%s\"}\n", json_escape(detail).c_str()); + return code; +} + +bool parse_nonnegative(const char * text, int & out) { + if (text == nullptr || *text == '\0' || *text == '-') { + return false; + } + char * end = nullptr; + const long value = std::strtol(text, &end, 10); + if (end == text || *end != '\0' || value > INT32_MAX) { + return false; + } + out = static_cast(value); + return true; +} + +uint64_t file_size(const std::string & path) { + struct stat st; + return ::stat(path.c_str(), &st) == 0 ? static_cast(st.st_size) : 0; +} + +struct proc_status { + uint64_t vm_size = 0; + uint64_t vm_rss = 0; + uint64_t vm_hwm = 0; + bool valid = false; +}; + +proc_status read_proc_status() { + proc_status out; +#ifdef __linux__ + FILE * f = std::fopen("/proc/self/status", "r"); + if (!f) { + return out; + } + char line[256]; + while (std::fgets(line, sizeof(line), f)) { + uint64_t kb = 0; + if (std::sscanf(line, "VmSize: %lu kB", &kb) == 1) { + out.vm_size = kb * 1024; + } else if (std::sscanf(line, "VmRSS: %lu kB", &kb) == 1) { + out.vm_rss = kb * 1024; + } else if (std::sscanf(line, "VmHWM: %lu kB", &kb) == 1) { + out.vm_hwm = kb * 1024; + } + } + std::fclose(f); + out.valid = true; +#endif + return out; +} + +void usage(const char * argv0) { + std::fprintf(stderr, + "usage: %s --model PATH --start N --end M [--no-mmap] [--no-extra-bufts] [--touch]\n" + "loads one dense-Llama GGUF through the Meshnet owned-range loader and\n" + "prints a JSON report derived from the loaded model state\n", + argv0); +} + +} // namespace + +int main(int argc, char ** argv) { + std::string model_path; + int start = -1; + int end = -1; + bool use_mmap = true; + bool use_extra_bufts = true; + bool touch = false; + + for (int i = 1; i < argc; ++i) { + const std::string arg = argv[i]; + if (arg == "--model" && i + 1 < argc) { + model_path = argv[++i]; + } else if (arg == "--start" && i + 1 < argc) { + if (!parse_nonnegative(argv[++i], start)) { + usage(argv[0]); + return kExitUsage; + } + } else if (arg == "--end" && i + 1 < argc) { + if (!parse_nonnegative(argv[++i], end)) { + usage(argv[0]); + return kExitUsage; + } + } else if (arg == "--no-mmap") { + use_mmap = false; + } else if (arg == "--no-extra-bufts") { + use_extra_bufts = false; + } else if (arg == "--touch") { + touch = true; + } else { + usage(argv[0]); + return kExitUsage; + } + } + if (model_path.empty() || start < 0 || end < 0) { + usage(argv[0]); + return kExitUsage; + } + + llama_log_set(capture_log, nullptr); + llama_backend_init(); + + llama_model_params params = llama_model_default_params(); + params.meshnet_owned_layer_start = start; + params.meshnet_owned_layer_end = end; + params.use_mmap = use_mmap; + params.use_extra_bufts = use_extra_bufts; + params.progress_callback = nullptr; + + llama_model * model = llama_model_load_from_file(model_path.c_str(), params); + if (model == nullptr) { + return fail(kExitLoad, "owned-range load rejected the artifact or range"); + } + + llama_meshnet_range_report report = {}; + if (!llama_model_meshnet_range_report(model, &report)) { + llama_model_free(model); + return fail(kExitLoad, "loaded model carries no owned-range report"); + } + + char arch_buf[128] = {}; + std::string arch; + if (llama_model_meta_val_str(model, "general.architecture", arch_buf, sizeof(arch_buf)) >= 0) { + arch = arch_buf; + } + const int n_layer = llama_model_n_layer(model); + const uint64_t bytes_on_disk = file_size(model_path); + + // Audit the registered tensor set against the requested ownership. + const auto & tensors = llama_internal_get_tensor_map(model); + bool has_embd = false; + bool has_out_norm = false; + bool has_out = false; + std::set owned_layers; + std::vector unexpected; + uint64_t registered_bytes = 0; + for (const auto & entry : tensors) { + const std::string & name = entry.first; + registered_bytes += ggml_nbytes(entry.second); + if (name == "token_embd.weight") { + has_embd = true; + continue; + } + if (name == "output_norm.weight") { + has_out_norm = true; + continue; + } + if (name == "output.weight") { + has_out = true; + continue; + } + int block = -1; + if (std::sscanf(name.c_str(), "blk.%d.", &block) == 1 && block >= 0) { + owned_layers.insert(block); + continue; + } + unexpected.push_back(name); + } + + // A tail shard whose model ties the output head to the token embedding + // registers token_embd.weight as its output head instead of output.weight. + const bool tied_tail = end == n_layer && has_embd && !has_out; + const bool expect_embd = start == 0 || tied_tail; + + std::vector missing_layers; + for (int i = start; i < end; ++i) { + if (!owned_layers.count(i)) { + missing_layers.push_back(i); + } + } + std::vector outside_layers; + for (const int block : owned_layers) { + if (block < start || block >= end) { + outside_layers.push_back(block); + } + } + + std::vector mismatches; + if (report.start_layer != start || report.end_layer != end) { + mismatches.push_back("reported range differs from the requested range"); + } + if (has_embd != expect_embd) { + mismatches.push_back("token-embedding registration disagrees with endpoint ownership"); + } + if ((end == n_layer) && !has_out_norm) { + mismatches.push_back("tail range is missing the final norm"); + } + if ((end == n_layer) && !has_out && !has_embd) { + mismatches.push_back("tail range is missing the output head"); + } + if ((end != n_layer) && (has_out_norm || has_out)) { + mismatches.push_back("non-tail range registered tail-only tensors"); + } + if (report.has_token_embeddings != has_embd) { + mismatches.push_back("reported embedding ownership disagrees with registered tensors"); + } + if (report.has_output_head != (end == n_layer)) { + mismatches.push_back("reported output-head ownership disagrees with endpoint ownership"); + } + if (!missing_layers.empty()) { + mismatches.push_back("owned range has missing per-layer tensors"); + } + if (!outside_layers.empty()) { + mismatches.push_back("registered per-layer tensors lie outside the owned range"); + } + if (!unexpected.empty()) { + mismatches.push_back("registered tensors outside the dense-Llama ownership vocabulary"); + } + if (use_mmap && report.mapped_bytes < registered_bytes) { + mismatches.push_back("mapped span undercounts the registered tensors"); + } + if (!use_mmap && report.resident_bytes < registered_bytes) { + mismatches.push_back("resident allocation undercounts the registered tensors"); + } + + if (touch) { + volatile uint64_t sink = 0; + for (const auto & entry : tensors) { + const auto * data = static_cast(entry.second->data); + const size_t nbytes = ggml_nbytes(entry.second); + for (size_t i = 0; i < nbytes; i += 4096) { + sink += data[i]; + } + } + (void) sink; + } + + const proc_status proc = read_proc_status(); + + if (!mismatches.empty()) { + llama_model_free(model); + return fail(kExitAudit, "ownership audit failed: " + json_string_array(mismatches)); + } + + std::printf( + "{\n" + " \"ok\": true,\n" + " \"model\": \"%s\",\n" + " \"architecture\": \"%s\",\n" + " \"n_layer\": %d,\n" + " \"file_bytes\": %llu,\n" + " \"requested_range\": [%d, %d],\n" + " \"reported_range\": [%d, %d],\n" + " \"mmap\": %s,\n" + " \"touched\": %s,\n" + " \"use_extra_bufts\": %s,\n" + " \"has_token_embeddings\": %s,\n" + " \"has_output_head\": %s,\n" + " \"tied_output_head\": %s,\n" + " \"mapped_bytes\": %llu,\n" + " \"resident_bytes\": %llu,\n" + " \"registered_tensors\": %d,\n" + " \"registered_bytes\": %llu,\n" + " \"unexpected_registered_tensors\": [],\n" + " \"missing_owned_layers\": [],\n" + " \"vm_size_bytes\": %llu,\n" + " \"vm_rss_bytes\": %llu,\n" + " \"vm_hwm_bytes\": %llu\n" + "}\n", + json_escape(model_path).c_str(), + json_escape(arch).c_str(), + n_layer, + (unsigned long long) bytes_on_disk, + start, end, + report.start_layer, report.end_layer, + use_mmap ? "true" : "false", + touch ? "true" : "false", + use_extra_bufts ? "true" : "false", + report.has_token_embeddings ? "true" : "false", + report.has_output_head ? "true" : "false", + tied_tail ? "true" : "false", + (unsigned long long) report.mapped_bytes, + (unsigned long long) report.resident_bytes, + (int) tensors.size(), + (unsigned long long) registered_bytes, + (unsigned long long) proc.vm_size, + (unsigned long long) proc.vm_rss, + (unsigned long long) proc.vm_hwm); + + llama_model_free(model); + llama_backend_free(); + return 0; +}