Add portable CPU longhaul support
This commit is contained in:
+1
-1
@@ -2631,7 +2631,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
||||
).set_env("LLAMA_ARG_LOAD_MODE"));
|
||||
add_opt(common_arg(
|
||||
{"--longhaul"},
|
||||
"stream routed Qwen3.5 MoE experts through a bounded Metal cache",
|
||||
"stream routed Qwen3.5 MoE or Laguna experts through a bounded CPU or Metal cache",
|
||||
[](common_params & params) {
|
||||
params.load_mode = LLAMA_LOAD_MODE_LONGHAUL;
|
||||
}
|
||||
|
||||
+30
-9
@@ -11,11 +11,17 @@ llama-cli \
|
||||
--model /path/to/model.gguf \
|
||||
--longhaul \
|
||||
--longhaul-cache 2 \
|
||||
--n-gpu-layers 99
|
||||
--n-gpu-layers 0
|
||||
```
|
||||
|
||||
`--longhaul-cache` is the expert cache budget in GiB. It is required when `--longhaul` is used. The same options are accepted by `llama-server`.
|
||||
|
||||
The command above runs every repeating layer on CPU and is supported on macOS,
|
||||
Linux, and Windows. On macOS, the existing all-Metal mode remains available by
|
||||
using `--n-gpu-layers 99` instead. Longhaul does not silently change device
|
||||
placement: an unsupported GPU or mixed CPU/GPU repeating-layer placement fails
|
||||
with guidance to use `--n-gpu-layers 0`.
|
||||
|
||||
Longhaul may reduce `--ubatch-size` so that every expert selected by one graph segment can be present in the cache at the same time. The effective value is logged during context creation. If one token selects more experts than the cache has slots, the routed MoE computation is split into multiple stages and the partial results are summed. This permits smaller caches at the cost of additional graph work.
|
||||
|
||||
The normal startup warmup is skipped automatically in longhaul mode. Routed expert weights are not read until the first real decode.
|
||||
@@ -24,23 +30,38 @@ The normal startup warmup is skipped automatically in longhaul mode. Routed expe
|
||||
|
||||
Longhaul currently requires:
|
||||
|
||||
- macOS with the Metal backend
|
||||
- all repeating layers on CPU, or all repeating layers on Metal
|
||||
- Qwen3.5 MoE or Laguna architecture
|
||||
- all repeating model layers assigned to Metal
|
||||
- text generation without embeddings or LoRA adapters
|
||||
|
||||
Longhaul does not restrict the GGUF quantization type. Individual tensor types must still be supported by Metal.
|
||||
CPU mode is available wherever the CPU backend is supported. Metal mode requires
|
||||
macOS. Longhaul does not restrict the GGUF quantization type; individual tensor
|
||||
types must still be supported by the selected compute backend.
|
||||
|
||||
MTP/speculative decoding, tensor validation during loading, vocabulary-only loading, and CPU or mixed CPU/Metal layer placement are not supported. Both single-file and split GGUF models are supported; routed expert tensors are read from the shard that owns each tensor.
|
||||
MTP/speculative decoding, tensor validation during loading, vocabulary-only
|
||||
loading, and mixed CPU/GPU repeating-layer placement are not supported. Both
|
||||
single-file and split GGUF models are supported; routed expert tensors are read
|
||||
from the shard that owns each tensor.
|
||||
|
||||
The cache budget covers the compact routed-expert tensors. It does not include dense weights, attention weights, the KV cache, graph allocations, or the temporary buffer used for one expert read. Disk reads bypass the macOS unified file cache where supported, avoiding a second long-lived copy of streamed weights in system RAM.
|
||||
The cache budget covers the compact routed-expert tensors. It does not include
|
||||
dense weights, attention weights, the KV cache, graph allocations, or temporary
|
||||
staging buffers. CPU expert caches use the standard directly writable tensor
|
||||
layout so individual slots can be replaced; optimized CPU buffer selection
|
||||
continues to apply to all non-streamed weights.
|
||||
|
||||
File-cache control is best effort and is outside the explicit cache budget.
|
||||
macOS disables caching for streamed files where supported, and Linux advises the
|
||||
kernel to discard completed reads. Windows may retain file data in its system
|
||||
cache. Windows reads from one GGUF shard are serialized to preserve positional
|
||||
read correctness, while POSIX systems retain concurrent `pread` operations.
|
||||
|
||||
This implementation synchronizes at each routed MoE layer to discover the selected experts, populate missing cache slots, and continue execution with cache-local expert IDs. Storage speed and expert reuse therefore have a large effect on generation speed.
|
||||
|
||||
Expert IDs are planned as a batch at each synchronization point. Experts already
|
||||
needed by that batch are protected from eviction, duplicate IDs are loaded only
|
||||
once, and independent expert slices are read concurrently on shared-memory Metal
|
||||
devices. Private Metal buffers use a staged fallback.
|
||||
once, and independent expert slices are read concurrently where the platform
|
||||
supports positional reads. CPU and shared Metal buffers are populated directly;
|
||||
private Metal buffers use a staged fallback.
|
||||
|
||||
## Benchmarking prompt processing
|
||||
|
||||
@@ -51,7 +72,7 @@ llama-bench \
|
||||
--model /path/to/model.gguf \
|
||||
--load-mode longhaul \
|
||||
--longhaul-cache 2 \
|
||||
--n-gpu-layers 99 \
|
||||
--n-gpu-layers 0 \
|
||||
--n-prompt 2048 \
|
||||
--n-gen 0
|
||||
```
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdexcept>
|
||||
#include <cerrno>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<unistd.h>)
|
||||
@@ -66,8 +67,12 @@ static std::string llama_format_win_err(DWORD err) {
|
||||
// llama_file
|
||||
|
||||
struct llama_file::impl {
|
||||
bool no_cache = false;
|
||||
|
||||
#if defined(_WIN32)
|
||||
HANDLE fp_win32;
|
||||
std::mutex read_at_mutex;
|
||||
|
||||
std::string GetErrorMessageWin32(DWORD error_code) const {
|
||||
std::string ret;
|
||||
LPSTR lpMsgBuf = NULL;
|
||||
@@ -433,6 +438,10 @@ void llama_file::read_raw_unsafe(void * ptr, size_t len) { pimpl->read_raw_unsaf
|
||||
|
||||
void llama_file::read_at(void * ptr, size_t len, size_t offset) {
|
||||
#ifdef _WIN32
|
||||
// The Windows FILE pointer is shared by all longhaul I/O workers. Keep the
|
||||
// seek and read together so concurrent jobs cannot change each other's
|
||||
// offsets. POSIX uses pread below and does not need this serialization.
|
||||
std::lock_guard<std::mutex> lock(pimpl->read_at_mutex);
|
||||
seek(offset, SEEK_SET);
|
||||
read_raw(ptr, len);
|
||||
#else
|
||||
@@ -448,6 +457,13 @@ void llama_file::read_at(void * ptr, size_t len, size_t offset) {
|
||||
}
|
||||
n_read += result;
|
||||
}
|
||||
#if defined(__linux__) && defined(POSIX_FADV_DONTNEED)
|
||||
if (pimpl->no_cache) {
|
||||
// Longhaul owns a bounded expert cache, so avoid retaining a second
|
||||
// long-lived copy of completed reads in the kernel page cache.
|
||||
(void) posix_fadvise(file_id(), (off_t) offset, (off_t) len, POSIX_FADV_DONTNEED);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -456,6 +472,12 @@ void llama_file::set_no_cache() const {
|
||||
if (fcntl(file_id(), F_NOCACHE, 1) != 0) {
|
||||
throw std::runtime_error(format("failed to disable file cache: %s", strerror(errno)));
|
||||
}
|
||||
#elif defined(__linux__) && defined(POSIX_FADV_RANDOM)
|
||||
pimpl->no_cache = true;
|
||||
const int err = posix_fadvise(file_id(), 0, 0, POSIX_FADV_RANDOM);
|
||||
if (err != 0) {
|
||||
LLAMA_LOG_WARN("%s: failed to set random-access file advice: %s\n", __func__, strerror(err));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1220,6 +1220,7 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
}
|
||||
|
||||
ggml_backend_buffer_type_t buft = nullptr;
|
||||
ggml_backend_buffer_type_t requested_override = nullptr;
|
||||
|
||||
// check overrides
|
||||
if (tensor_buft_overrides) {
|
||||
@@ -1227,6 +1228,7 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
for (const auto * overrides = tensor_buft_overrides; overrides->pattern != nullptr; ++overrides) {
|
||||
std::regex pattern(overrides->pattern);
|
||||
if (std::regex_search(tensor_name, pattern)) {
|
||||
requested_override = overrides->buft;
|
||||
if (overrides->buft == ggml_backend_cpu_buffer_type()) {
|
||||
// when overriding to a CPU buffer, consider the extra buffer types
|
||||
buft = select_weight_buft(hparams, t_meta, op, buft_list_cpu);
|
||||
@@ -1256,6 +1258,25 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
}
|
||||
}
|
||||
|
||||
// Streamed CPU experts are updated one expert slice at a time. CPU
|
||||
// repack and accelerator buffers only accept whole-tensor updates, so
|
||||
// keep these cache tensors in the standard, directly writable layout.
|
||||
if ((flags & TENSOR_LONGHAUL) && buft_list == buft_list_cpu) {
|
||||
auto * cpu_dev = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU);
|
||||
if (!cpu_dev) {
|
||||
throw std::runtime_error("no CPU backend found");
|
||||
}
|
||||
ggml_backend_buffer_type_t cpu_buft = ggml_backend_dev_buffer_type(cpu_dev);
|
||||
if (requested_override != nullptr &&
|
||||
requested_override != ggml_backend_cpu_buffer_type() &&
|
||||
requested_override != cpu_buft) {
|
||||
throw std::runtime_error(format(
|
||||
"longhaul CPU expert tensor '%s' has an incompatible buffer override",
|
||||
tn.str().c_str()));
|
||||
}
|
||||
buft = cpu_buft;
|
||||
}
|
||||
|
||||
// avoid using a host buffer when using mmap
|
||||
auto * buft_dev = ggml_backend_buft_get_device(buft);
|
||||
if (use_mmap && buft_dev && buft == ggml_backend_dev_host_buffer_type(buft_dev)) {
|
||||
|
||||
+17
-6
@@ -1356,9 +1356,6 @@ bool llama_model_base::load_tensors(llama_model_loader & ml) {
|
||||
}
|
||||
|
||||
if (params.load_mode == LLAMA_LOAD_MODE_LONGHAUL) {
|
||||
#if !defined(__APPLE__)
|
||||
throw std::runtime_error("longhaul is only supported on macOS");
|
||||
#endif
|
||||
if (arch != LLM_ARCH_QWEN35MOE && arch != LLM_ARCH_LAGUNA) {
|
||||
throw std::runtime_error("longhaul currently requires a qwen35moe or laguna model");
|
||||
}
|
||||
@@ -1368,13 +1365,27 @@ bool llama_model_base::load_tensors(llama_model_loader & ml) {
|
||||
if (params.check_tensors || params.no_alloc || params.vocab_only) {
|
||||
throw std::runtime_error("longhaul does not support check-tensors, no-alloc, or vocab-only loading");
|
||||
}
|
||||
bool all_cpu = true;
|
||||
bool all_metal = true;
|
||||
for (int il = 0; il < n_layer_all; ++il) {
|
||||
ggml_backend_dev_t dev = pimpl->dev_layer[il].dev;
|
||||
if (ggml_backend_dev_type(dev) != GGML_BACKEND_DEVICE_TYPE_GPU ||
|
||||
strcmp(ggml_backend_reg_name(ggml_backend_dev_backend_reg(dev)), "MTL") != 0) {
|
||||
throw std::runtime_error("longhaul requires every model layer on Metal");
|
||||
const char * backend = ggml_backend_reg_name(ggml_backend_dev_backend_reg(dev));
|
||||
all_cpu = all_cpu && ggml_backend_dev_type(dev) == GGML_BACKEND_DEVICE_TYPE_CPU;
|
||||
all_metal = all_metal &&
|
||||
ggml_backend_dev_type(dev) == GGML_BACKEND_DEVICE_TYPE_GPU &&
|
||||
strcmp(backend, "MTL") == 0;
|
||||
}
|
||||
if (!all_cpu && !all_metal) {
|
||||
throw std::runtime_error(
|
||||
"longhaul requires every repeating model layer on CPU or Metal; "
|
||||
"use --n-gpu-layers 0 for CPU mode");
|
||||
}
|
||||
#if !defined(__APPLE__)
|
||||
if (all_metal) {
|
||||
throw std::runtime_error("longhaul Metal mode is only supported on macOS");
|
||||
}
|
||||
#endif
|
||||
LLAMA_LOG_INFO("%s: longhaul using %s expert cache\n", __func__, all_cpu ? "CPU" : "Metal");
|
||||
ml.configure_longhaul(params.longhaul_cache_bytes, n_expert, n_layer_all);
|
||||
if (ml.longhaul_slots < (size_t) n_expert_used) {
|
||||
LLAMA_LOG_WARN("%s: longhaul cache has %zu slots for %lld selected experts; "
|
||||
|
||||
@@ -259,6 +259,22 @@ set_tests_properties(test-thread-safety PROPERTIES FIXTURES_REQUIRED test-downlo
|
||||
|
||||
llama_build_and_test(test-arg-parser.cpp)
|
||||
llama_build_and_test(test-longhaul.cpp)
|
||||
llama_test(
|
||||
test-longhaul
|
||||
NAME test-longhaul-cpu-qwen35moe
|
||||
ARGS --cpu-model "${MODEL_DIR}/qwen35moe-moe.gguf" 3145728
|
||||
)
|
||||
set_tests_properties(test-longhaul-cpu-qwen35moe PROPERTIES
|
||||
FIXTURES_REQUIRED generate-models
|
||||
)
|
||||
llama_test(
|
||||
test-longhaul
|
||||
NAME test-longhaul-cpu-laguna
|
||||
ARGS --cpu-model "${MODEL_DIR}/laguna-moe.gguf" 2097152
|
||||
)
|
||||
set_tests_properties(test-longhaul-cpu-laguna PROPERTIES
|
||||
FIXTURES_REQUIRED generate-models
|
||||
)
|
||||
llama_build_and_test(test-token-cache.cpp)
|
||||
target_include_directories(test-token-cache PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
// TODO: replace with #include "llama-ext.h" in the future
|
||||
#include "../src/llama-arch.h"
|
||||
#include "../src/llama-model.h"
|
||||
#include "../src/llama-model-saver.h"
|
||||
|
||||
#include <cinttypes>
|
||||
@@ -476,7 +477,9 @@ static int save_models(const llm_arch target_arch, const size_t seed, const ggml
|
||||
if (!moe && moe_mandatory(arch)) {
|
||||
continue;
|
||||
}
|
||||
if (!llama_model_saver_supports_arch(arch) || !arch_supported(arch)) {
|
||||
const bool can_save_fixture =
|
||||
llama_model_saver_supports_arch(arch) || arch == LLM_ARCH_LAGUNA;
|
||||
if (!can_save_fixture || !arch_supported(arch)) {
|
||||
LOG_INF("%s: %s model (%s) is unsupported, skipping\n", __func__, llm_arch_name(arch), moe ? "MoE" : "dense");
|
||||
continue;
|
||||
}
|
||||
@@ -484,7 +487,20 @@ static int save_models(const llm_arch target_arch, const size_t seed, const ggml
|
||||
auto model_and_ctx = get_model_and_ctx(gguf_ctx.get(), nullptr, seed, {});
|
||||
const std::string path = dir + "/" + llm_arch_name(arch) + (moe ? "-moe.gguf" : "-dense.gguf");
|
||||
LOG_INF("%s: Saving %s model (%s) to %s...\n", __func__, llm_arch_name(arch), moe ? "MoE" : "dense", path.c_str());
|
||||
if (llama_model_saver_supports_arch(arch)) {
|
||||
llama_model_save_to_file(model_and_ctx.first.get(), path.c_str());
|
||||
} else {
|
||||
// Laguna is not supported by the production model saver yet.
|
||||
// Preserve the exact synthetic fixture metadata and attach the
|
||||
// initialized model tensors so longhaul can be tested from a
|
||||
// real file without broadening the saver API.
|
||||
gguf_context_ptr fixture(gguf_init_empty());
|
||||
gguf_set_kv(fixture.get(), gguf_ctx.get());
|
||||
for (const auto & item : llama_internal_get_tensor_map(model_and_ctx.first.get())) {
|
||||
gguf_add_tensor(fixture.get(), item.second);
|
||||
}
|
||||
gguf_write_to_file(fixture.get(), path.c_str(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
llama_log_set(ud.original_logger.callback, ud.original_logger.user_data);
|
||||
|
||||
+148
-1
@@ -1,11 +1,16 @@
|
||||
#include "testing.h"
|
||||
|
||||
#include "../src/llama-longhaul.h"
|
||||
#include "../src/llama-model.h"
|
||||
|
||||
#include "ggml-backend.h"
|
||||
#include "llama-cpp.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct longhaul_fixture {
|
||||
@@ -128,6 +133,32 @@ static void test_multiple_sources(testing & t) {
|
||||
t.assert_equal(uint8_t(34), fixture.slot_value(fixture.weights_b, remapped[1]));
|
||||
}
|
||||
|
||||
static void test_concurrent_source_reads(testing & t) {
|
||||
longhaul_fixture fixture(2, 4, true);
|
||||
|
||||
for (int iteration = 0; iteration < 64; ++iteration) {
|
||||
const int32_t first = iteration % 2 == 0 ? 0 : 2;
|
||||
const int32_t second = first + 1;
|
||||
const auto remapped = fixture.remap({first, second});
|
||||
|
||||
if (!t.assert_equal(2u, remapped.size())) {
|
||||
return;
|
||||
}
|
||||
t.assert_equal(
|
||||
uint8_t(1 + first),
|
||||
fixture.slot_value(fixture.weights_a, remapped[0]));
|
||||
t.assert_equal(
|
||||
uint8_t(33 + first),
|
||||
fixture.slot_value(fixture.weights_b, remapped[0]));
|
||||
t.assert_equal(
|
||||
uint8_t(1 + second),
|
||||
fixture.slot_value(fixture.weights_a, remapped[1]));
|
||||
t.assert_equal(
|
||||
uint8_t(33 + second),
|
||||
fixture.slot_value(fixture.weights_b, remapped[1]));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_invalid_ids(testing & t) {
|
||||
longhaul_fixture fixture(2, 4);
|
||||
|
||||
@@ -152,8 +183,110 @@ static void test_read_failure_recovery(testing & t) {
|
||||
t.assert_equal(uint8_t(1), fixture.slot_value(fixture.weights_a, remapped[0]));
|
||||
}
|
||||
|
||||
struct cpu_decode_result {
|
||||
std::vector<float> logits;
|
||||
uint32_t capacity = 0;
|
||||
uint64_t misses = 0;
|
||||
uint64_t bytes_read = 0;
|
||||
bool expert_buffer_is_host = false;
|
||||
};
|
||||
|
||||
static cpu_decode_result decode_cpu_model(
|
||||
const std::string & path,
|
||||
llama_load_mode load_mode,
|
||||
uint64_t cache_bytes) {
|
||||
llama_model_params model_params = llama_model_default_params();
|
||||
model_params.n_gpu_layers = 0;
|
||||
model_params.load_mode = load_mode;
|
||||
model_params.longhaul_cache_bytes = cache_bytes;
|
||||
model_params.use_extra_bufts = true;
|
||||
|
||||
llama_model_ptr model(llama_model_load_from_file(path.c_str(), model_params));
|
||||
if (!model) {
|
||||
throw std::runtime_error("failed to load CPU model: " + path);
|
||||
}
|
||||
|
||||
llama_context_params context_params = llama_context_default_params();
|
||||
context_params.n_ctx = 32;
|
||||
context_params.n_batch = 8;
|
||||
context_params.n_ubatch = 8;
|
||||
context_params.n_threads = 2;
|
||||
context_params.n_threads_batch = 2;
|
||||
|
||||
llama_context_ptr context(llama_init_from_model(model.get(), context_params));
|
||||
if (!context) {
|
||||
throw std::runtime_error("failed to create CPU context: " + path);
|
||||
}
|
||||
|
||||
std::vector<llama_token> tokens = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
llama_batch batch = llama_batch_get_one(tokens.data(), tokens.size());
|
||||
if (llama_decode(context.get(), batch) != 0) {
|
||||
throw std::runtime_error("failed to decode CPU model: " + path);
|
||||
}
|
||||
|
||||
const int32_t n_vocab = llama_vocab_n_tokens(llama_model_get_vocab(model.get()));
|
||||
const float * logits = llama_get_logits_ith(context.get(), -1);
|
||||
if (!logits) {
|
||||
throw std::runtime_error("CPU model produced no logits: " + path);
|
||||
}
|
||||
|
||||
cpu_decode_result result;
|
||||
result.logits.assign(logits, logits + n_vocab);
|
||||
|
||||
if (load_mode == LLAMA_LOAD_MODE_LONGHAUL) {
|
||||
llama_longhaul_cache * cache = model->longhaul_cache();
|
||||
if (!cache) {
|
||||
throw std::runtime_error("longhaul cache was not created: " + path);
|
||||
}
|
||||
result.capacity = cache->capacity();
|
||||
result.misses = cache->misses();
|
||||
result.bytes_read = cache->bytes_read_count();
|
||||
|
||||
for (const auto & item : llama_internal_get_tensor_map(model.get())) {
|
||||
const std::string & name = item.first;
|
||||
if (name.find("ffn_") != std::string::npos &&
|
||||
name.find("_exps.weight") != std::string::npos &&
|
||||
item.second->ne[2] == result.capacity) {
|
||||
result.expert_buffer_is_host = ggml_backend_buffer_is_host(item.second->buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void test_cpu_model(
|
||||
testing & t,
|
||||
const std::string & path,
|
||||
uint64_t cache_bytes) {
|
||||
const cpu_decode_result regular =
|
||||
decode_cpu_model(path, LLAMA_LOAD_MODE_NONE, 0);
|
||||
const cpu_decode_result longhaul =
|
||||
decode_cpu_model(path, LLAMA_LOAD_MODE_LONGHAUL, cache_bytes);
|
||||
|
||||
t.assert_equal(1u, longhaul.capacity);
|
||||
t.assert_true("longhaul loaded at least one expert", longhaul.misses > 0);
|
||||
t.assert_true("longhaul read expert bytes", longhaul.bytes_read > 0);
|
||||
t.assert_true("streamed experts use a directly writable host buffer", longhaul.expert_buffer_is_host);
|
||||
t.assert_equal(regular.logits.size(), longhaul.logits.size());
|
||||
|
||||
double squared_error = 0.0;
|
||||
double squared_reference = 0.0;
|
||||
for (size_t i = 0; i < regular.logits.size(); ++i) {
|
||||
const double delta = double(regular.logits[i]) - double(longhaul.logits[i]);
|
||||
squared_error += delta * delta;
|
||||
squared_reference += double(regular.logits[i]) * double(regular.logits[i]);
|
||||
}
|
||||
const double nmse = squared_reference > 0.0 ? squared_error / squared_reference : squared_error;
|
||||
t.assert_true(
|
||||
"longhaul CPU logits NMSE = " + std::to_string(nmse),
|
||||
std::isfinite(nmse) && nmse <= 1e-6);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
testing t;
|
||||
llama_backend_init();
|
||||
|
||||
const char * verbose = getenv("LLAMA_TEST_VERBOSE");
|
||||
if (verbose) {
|
||||
@@ -163,14 +296,28 @@ int main(int argc, char ** argv) {
|
||||
llama_log_set([](ggml_log_level, const char *, void *) {}, nullptr);
|
||||
}
|
||||
|
||||
if (argc == 4 && std::string(argv[1]) == "--cpu-model") {
|
||||
const std::string path = argv[2];
|
||||
const uint64_t cache_bytes = std::stoull(argv[3]);
|
||||
t.test("cpu_model", [&](testing & current) {
|
||||
test_cpu_model(current, path, cache_bytes);
|
||||
});
|
||||
const int result = t.summary();
|
||||
llama_backend_free();
|
||||
return result;
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
t.set_filter(argv[1]);
|
||||
}
|
||||
|
||||
t.test("batch_planning", test_batch_planning);
|
||||
t.test("multiple_sources", test_multiple_sources);
|
||||
t.test("concurrent_reads", test_concurrent_source_reads);
|
||||
t.test("invalid_ids", test_invalid_ids);
|
||||
t.test("read_failure", test_read_failure_recovery);
|
||||
|
||||
return t.summary();
|
||||
const int result = t.summary();
|
||||
llama_backend_free();
|
||||
return result;
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@
|
||||
| `--mmap, --no-mmap` | DEPRECATED in favor of `--load-mode`: whether to memory-map model. (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>(env: LLAMA_ARG_MMAP) |
|
||||
| `-dio, --direct-io, -ndio, --no-direct-io` | DEPRECATED in favor of `--load-mode`: use DirectIO if available<br/>(env: LLAMA_ARG_DIO) |
|
||||
| `-lm, --load-mode MODE` | model loading mode (default: mmap)<br/>- none: no special loading mode<br/>- mmap: memory-map model (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>- mlock: force system to keep model in RAM rather than swapping or compressing<br/>- mmap+mlock: mmap + force system to keep model in RAM rather than swapping or compressing<br/>- dio: use DirectIO if available<br/>- longhaul: stream routed MoE experts through a bounded cache<br/><br/>(env: LLAMA_ARG_LOAD_MODE) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE experts through a bounded Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE or Laguna experts through a bounded CPU or Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul-cache N` | longhaul expert cache size in GiB<br/>(env: LLAMA_ARG_LONGHAUL_CACHE) |
|
||||
| `--numa TYPE` | attempt optimizations that help on some NUMA systems<br/>- distribute: spread execution evenly over all nodes<br/>- isolate: only spawn threads on CPUs on the node that execution started on<br/>- numactl: use the CPU map provided by numactl<br/>if run without this previously, it is recommended to drop the system page cache before using this<br/>see https://github.com/ggml-org/llama.cpp/issues/1437<br/>(env: LLAMA_ARG_NUMA) |
|
||||
| `-dev, --device <dev1,dev2,..>` | comma-separated list of devices to use for offloading (none = don't offload)<br/>use --list-devices to see a list of available devices<br/>(env: LLAMA_ARG_DEVICE) |
|
||||
|
||||
@@ -144,7 +144,7 @@ llama-completion.exe -m models\gemma-1.1-7b-it.Q4_K_M.gguf --ignore-eos -n -1
|
||||
| `--mmap, --no-mmap` | DEPRECATED in favor of `--load-mode`: whether to memory-map model. (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>(env: LLAMA_ARG_MMAP) |
|
||||
| `-dio, --direct-io, -ndio, --no-direct-io` | DEPRECATED in favor of `--load-mode`: use DirectIO if available<br/>(env: LLAMA_ARG_DIO) |
|
||||
| `-lm, --load-mode MODE` | model loading mode (default: mmap)<br/>- none: no special loading mode<br/>- mmap: memory-map model (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>- mlock: force system to keep model in RAM rather than swapping or compressing<br/>- mmap+mlock: mmap + force system to keep model in RAM rather than swapping or compressing<br/>- dio: use DirectIO if available<br/>- longhaul: stream routed MoE experts through a bounded cache<br/><br/>(env: LLAMA_ARG_LOAD_MODE) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE experts through a bounded Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE or Laguna experts through a bounded CPU or Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul-cache N` | longhaul expert cache size in GiB<br/>(env: LLAMA_ARG_LONGHAUL_CACHE) |
|
||||
| `--numa TYPE` | attempt optimizations that help on some NUMA systems<br/>- distribute: spread execution evenly over all nodes<br/>- isolate: only spawn threads on CPUs on the node that execution started on<br/>- numactl: use the CPU map provided by numactl<br/>if run without this previously, it is recommended to drop the system page cache before using this<br/>see https://github.com/ggml-org/llama.cpp/issues/1437<br/>(env: LLAMA_ARG_NUMA) |
|
||||
| `-dev, --device <dev1,dev2,..>` | comma-separated list of devices to use for offloading (none = don't offload)<br/>use --list-devices to see a list of available devices<br/>(env: LLAMA_ARG_DEVICE) |
|
||||
|
||||
@@ -78,7 +78,7 @@ For the full list of features, please refer to [server's changelog](https://gith
|
||||
| `--mmap, --no-mmap` | DEPRECATED in favor of `--load-mode`: whether to memory-map model. (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>(env: LLAMA_ARG_MMAP) |
|
||||
| `-dio, --direct-io, -ndio, --no-direct-io` | DEPRECATED in favor of `--load-mode`: use DirectIO if available<br/>(env: LLAMA_ARG_DIO) |
|
||||
| `-lm, --load-mode MODE` | model loading mode (default: mmap)<br/>- none: no special loading mode<br/>- mmap: memory-map model (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>- mlock: force system to keep model in RAM rather than swapping or compressing<br/>- mmap+mlock: mmap + force system to keep model in RAM rather than swapping or compressing<br/>- dio: use DirectIO if available<br/>- longhaul: stream routed MoE experts through a bounded cache<br/><br/>(env: LLAMA_ARG_LOAD_MODE) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE experts through a bounded Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul` | stream routed Qwen3.5 MoE or Laguna experts through a bounded CPU or Metal cache<br/>(env: LLAMA_ARG_LONGHAUL) |
|
||||
| `--longhaul-cache N` | longhaul expert cache size in GiB<br/>(env: LLAMA_ARG_LONGHAUL_CACHE) |
|
||||
| `--numa TYPE` | attempt optimizations that help on some NUMA systems<br/>- distribute: spread execution evenly over all nodes<br/>- isolate: only spawn threads on CPUs on the node that execution started on<br/>- numactl: use the CPU map provided by numactl<br/>if run without this previously, it is recommended to drop the system page cache before using this<br/>see https://github.com/ggml-org/llama.cpp/issues/1437<br/>(env: LLAMA_ARG_NUMA) |
|
||||
| `-dev, --device <dev1,dev2,..>` | comma-separated list of devices to use for offloading (none = don't offload)<br/>use --list-devices to see a list of available devices<br/>(env: LLAMA_ARG_DEVICE) |
|
||||
|
||||
Reference in New Issue
Block a user