Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ jobs:
-DLLAMA_BUILD_BORINGSSL=ON ^
-DGGML_SCHED_NO_REALLOC=ON
set /A NINJA_JOBS=%NUMBER_OF_PROCESSORS%-1
cmake --build build --config Release -j %NINJA_JOBS% --target llama-server
cmake --build build --config Release -j %NINJA_JOBS% --target llama-server test-server-pages

- name: Page publication tests
id: server_page_tests
shell: cmd
run: |
ctest --test-dir build -C Release -R test-server-pages --output-on-failure

- name: Python setup
id: setup_python
Expand Down
29 changes: 29 additions & 0 deletions common/arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,18 @@ static std::string get_all_kv_cache_types() {
return msg.str();
}

// an exact byte count: the caller passes a measured number, so no unit suffixes are guessed
static uint64_t parse_byte_count(const std::string & value, const char * flag) {
if (value.empty() || value.size() > 20 || value.find_first_not_of("0123456789") != std::string::npos) {
throw std::invalid_argument(std::string(flag) + " takes an unsigned byte count, got: " + value);
}
try {
return std::stoull(value);
} catch (const std::exception &) {
throw std::invalid_argument(std::string(flag) + " is out of range: " + value);
}
}

static bool parse_bool_value(const std::string & value) {
if (is_truthy(value)) {
return true;
Expand Down Expand Up @@ -1691,6 +1703,23 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
params.n_ctx_checkpoints = value;
}
).set_env("LLAMA_ARG_CTX_CHECKPOINTS").set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}));
add_opt(common_arg(
{"--ctx-checkpoints-bytes"}, "BYTES",
"byte budget for the context checkpoints of all slots together, in place of the per-slot count "
"(default: 0 = use --ctx-checkpoints); when a new checkpoint would exceed it, the slot holding the "
"most checkpoint bytes drops its oldest checkpoint after its first, so each slot keeps its head and its newest",
[](common_params & params, const std::string & value) {
params.ctx_checkpoints_bytes = parse_byte_count(value, "--ctx-checkpoints-bytes");
}
).set_env("LLAMA_ARG_CTX_CHECKPOINTS_BYTES").set_examples({LLAMA_EXAMPLE_SERVER}));
add_opt(common_arg(
{"--page-ram-bytes"}, "BYTES",
"ceiling of the host-RAM page store that /slots page_out fills (default: 0 = no ceiling); "
"a page_out that would exceed it is refused, so the caller spills a page to disk first",
[](common_params & params, const std::string & value) {
params.page_ram_bytes = parse_byte_count(value, "--page-ram-bytes");
}
).set_env("LLAMA_ARG_PAGE_RAM_BYTES").set_examples({LLAMA_EXAMPLE_SERVER}));
add_opt(common_arg(
{"-cms", "--checkpoint-min-step"}, "N",
string_format("minimum spacing between context checkpoints in tokens (default: %d, 0 = no minimum)", params.checkpoint_min_step),
Expand Down
2 changes: 2 additions & 0 deletions common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,8 @@ struct common_params {
bool cache_idle_slots = true; // save and clear idle slots upon starting a new task
int32_t n_ctx_checkpoints = 32; // max number of context checkpoints per slot
int32_t checkpoint_min_step = 8192; // minimum spacing between context checkpoints
uint64_t ctx_checkpoints_bytes = 0; // checkpoint byte budget across all slots; 0 = the count above governs
uint64_t page_ram_bytes = 0; // ceiling of the named host-RAM page store; 0 = no ceiling
int32_t cache_ram_mib = 8192; // -1 = no limit, 0 - disable, 1 = 1 MiB, etc.

std::string hostname = "127.0.0.1";
Expand Down
30 changes: 30 additions & 0 deletions src/llama-context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3995,6 +3995,36 @@ size_t llama_state_seq_save_file(llama_context * ctx, const char * filepath, lla
}
}

size_t llama_state_seq_save_file_from_data(const char * filepath, const uint8_t * data, size_t size, const llama_token * tokens, size_t n_token_count) {
// get_data writes [io_magic][seq_id][state]; the file is [magic][version][count][tokens][state]
const size_t prefix = sizeof(io_magic) + sizeof(llama_seq_id);
if (data == nullptr || size <= prefix) {
LLAMA_LOG_ERROR("%s: no sequence state to write\n", __func__);
return 0;
}
uint32_t magic_read = 0;
std::memcpy(&magic_read, data, sizeof(magic_read));
if (magic_read != io_magic) {
LLAMA_LOG_ERROR("%s: the bytes are not a sequence state (magic %08x)\n", __func__, magic_read);
return 0;
}
try {
llama_file file(filepath, "wb");
const uint32_t magic = LLAMA_STATE_SEQ_MAGIC;
const uint32_t version = LLAMA_STATE_SEQ_VERSION;
const uint32_t count = (uint32_t) n_token_count;
file.write_raw(&magic, sizeof(magic));
file.write_raw(&version, sizeof(version));
file.write_raw(&count, sizeof(count));
file.write_raw(tokens, sizeof(llama_token) * n_token_count);
file.write_raw(data + prefix, size - prefix);
return file.tell();
} catch (const std::exception & err) {
LLAMA_LOG_ERROR("%s: error writing sequence state file: %s\n", __func__, err.what());
return 0;
}
}

size_t llama_state_seq_load_file(llama_context * ctx, const char * filepath, llama_seq_id dest_seq_id, llama_token * tokens_out, size_t n_token_capacity, size_t * n_token_count_out) {
return llama_state_seq_load_file_with_progress(ctx, filepath, dest_seq_id, tokens_out, n_token_capacity, n_token_count_out, nullptr, nullptr);
}
Expand Down
16 changes: 16 additions & 0 deletions src/llama-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,19 @@ LLAMA_API uint32_t llama_model_target_layer_ids_n(const struct llama_mode
// if out is nullptr, returns the number of tokens without writing to out
// caller must allocate enough memory for out before calling
LLAMA_API uint32_t llama_model_get_tok_embd(const struct llama_model * model, float * out);

//
// sequence state pages (Continuum fork)
//

// Writes a sequence-state file (the llama_state_seq_save_file format) from bytes that
// llama_state_seq_get_data_ext returned with LLAMA_STATE_SEQ_FLAGS_NONE, without a context:
// a page held in host RAM spills to disk off the engine thread, and llama_state_seq_load_file
// reads it back. Returns the bytes written, or 0 when the bytes are not a sequence state or
// the write fails.
LLAMA_API size_t llama_state_seq_save_file_from_data(
const char * filepath,
const uint8_t * data,
size_t size,
const llama_token * tokens,
size_t n_token_count);
7 changes: 7 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ llama_build_and_test(test-grad-leaf.cpp)
# ggml-opt with per-step graphs (the llama training path) starts each optimizer period from zero accumulators
llama_build_and_test(test-opt-dynamic-accum.cpp)

# Continuum fork: the RAM page store's ceiling and the page files' whole-generation publication.
# Built on every platform: it links only server-context, as llama-server does, and Windows is
# where its durable-move adapter differs most.
llama_build_and_test(test-server-pages.cpp)
target_include_directories(test-server-pages PRIVATE ${PROJECT_SOURCE_DIR}/tools/server)
target_link_libraries(test-server-pages PRIVATE server-context)

if (NOT WIN32 OR NOT BUILD_SHARED_LIBS)
# these tests are disabled on Windows because they use internal functions not exported with LLAMA_API (when building with shared libraries)
llama_build_and_test(test-unicode.cpp)
Expand Down
Loading
Loading