Skip to content
Draft
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
11 changes: 11 additions & 0 deletions include/llama.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,17 @@ extern "C" {
// Get the model file type (quantization), e.g. LLAMA_FTYPE_MOSTLY_Q8_0
LLAMA_API enum llama_ftype llama_model_ftype(const struct llama_model * model);

// Context-owned allocations only. Host buffers (including pinned host memory) are
// reported separately from device buffers. Buffer names are borrowed for the callback.
typedef void (*llama_context_memory_callback)(const char * buffer, bool host, uint64_t bytes, void * data);
// Build the same context layout and graph without allocating tensor payloads.
// Uses the loaded model's placement; never reloads or mutates its weights.
LLAMA_API bool llama_context_measure_memory(
struct llama_model * model, struct llama_context_params params,
llama_context_memory_callback callback, void * data);
LLAMA_API void llama_context_visit_memory(
const struct llama_context * ctx, llama_context_memory_callback callback, void * data);

// Returns the total size of all the tensors in the model in bytes
LLAMA_API uint64_t llama_model_size(const struct llama_model * model);

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_library(llama
llama-batch.cpp
llama-chat.cpp
llama-context.cpp
llama-context-memory.cpp
llama-context-opt.cpp
llama-context-opt-measure.cpp
llama-context-learn.cpp
Expand Down
33 changes: 33 additions & 0 deletions src/llama-context-memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "llama-context.h"
#include "llama-model.h"
#include <exception>

void llama_context::visit_context_memory(llama_context_memory_callback callback, void * data) const {
for (const auto & [buft, size] : memory_breakdown()) {
callback(ggml_backend_buft_name(buft), ggml_backend_buft_is_host(buft),
size.context + size.compute, data);
}
if (output_buft) {
callback(ggml_backend_buft_name(output_buft), ggml_backend_buft_is_host(output_buft), output_bytes, data);
}
}

bool llama_context_measure_memory(llama_model * model, llama_context_params params,
llama_context_memory_callback callback, void * data) {
if (!model || !callback || params.n_ctx == 0 || params.n_batch == 0 || params.n_ubatch == 0) {
return false;
}
try {
std::unique_ptr<llama_context> measured(llama_context_create(model, params, true));
if (!measured) { return false; }
measured->visit_context_memory(callback, data);
return true;
} catch (const std::exception & error) {
LLAMA_LOG_ERROR("%s: %s\n", __func__, error.what());
return false;
}
}

void llama_context_visit_memory(const llama_context * ctx, llama_context_memory_callback callback, void * data) {
if (ctx && callback) { ctx->visit_context_memory(callback, data); }
}
45 changes: 30 additions & 15 deletions src/llama-context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ static const llm_fused_op_probe llm_fused_op_dsv4_hc_post_probe = {

llama_context::llama_context(
const llama_model & model,
llama_context_params params) :
model(model),
llama_context_params params, bool measure_only) :
no_alloc(measure_only || model.hparams.no_alloc), model(model),
cvec(std::make_unique<llama_adapter_cvec>()),
loras(std::make_unique<llama_adapter_loras>()),
balloc(std::make_unique<llama_batch_allocr>(model.hparams.n_pos_per_embd())) {
Expand Down Expand Up @@ -368,7 +368,8 @@ llama_context::llama_context(

// graph outputs buffer
{
if (output_reserve(params.n_seq_max) < params.n_seq_max) {
const uint32_t output_count = no_alloc ? cparams.n_batch : params.n_seq_max;
if (output_reserve(output_count) < output_count) {
throw std::runtime_error("failed to reserve initial output buffer");
}

Expand All @@ -381,6 +382,7 @@ llama_context::llama_context(
// init the memory module
if (!hparams.vocab_only) {
llama_memory_params params_mem = {
/*.no_alloc =*/ no_alloc,
/*.type_k =*/ params.type_k,
/*.type_v =*/ params.type_v,
/*.swa_full =*/ params.swa_full,
Expand Down Expand Up @@ -478,7 +480,7 @@ llama_context::~llama_context() {
// wait for any pending asynchronous copies into the output buffers before they are freed
synchronize();

if (!model.hparams.no_alloc) {
if (!no_alloc) {
for (size_t i = 0; i < backend_ptrs.size(); ++i) {
ggml_backend_t backend = backend_ptrs[i];
ggml_backend_buffer_type_t buft = backend_buft[i];
Expand Down Expand Up @@ -639,13 +641,13 @@ void llama_context::sched_reserve() {
// reserve pp (prompt processing) graph first so that buffers are only allocated once
{
auto * gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(),
model.hparams.no_alloc, model.hparams.no_alloc ? backend_buf_exp_size.data() : nullptr);
no_alloc, no_alloc ? backend_buf_exp_size.data() : nullptr);
if (!gf) {
if (cparams.pipeline_parallel) {
LLAMA_LOG_WARN("%s: compute buffer allocation failed, retrying without pipeline parallelism\n", __func__);
cparams.pipeline_parallel = false;
sched.reset(ggml_backend_sched_new(backend_ptrs.data(), backend_buft.data(), backend_ptrs.size(), max_nodes, false, cparams.op_offload));
gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get());
gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(), no_alloc, no_alloc ? backend_buf_exp_size.data() : nullptr);
}
if (!gf) {
throw std::runtime_error("failed to allocate compute pp buffers");
Expand All @@ -658,7 +660,7 @@ void llama_context::sched_reserve() {

// reserve with tg (token generation) graph to get the number of splits and nodes
{
auto * gf = graph_reserve(n_seqs, n_seqs, n_seqs, mctx.get(), model.hparams.no_alloc);
auto * gf = graph_reserve(n_seqs, n_seqs, n_seqs, mctx.get(), no_alloc, no_alloc ? backend_buf_exp_size.data() : nullptr);
if (!gf) {
throw std::runtime_error("failed to allocate compute tg buffers");
}
Expand All @@ -673,7 +675,7 @@ void llama_context::sched_reserve() {
//
// auto * gf = graph_reserve(n_tokens, 1, n_tokens, mctx.get());
//
auto * gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(), model.hparams.no_alloc);
auto * gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(), no_alloc, no_alloc ? backend_buf_exp_size.data() : nullptr);
if (!gf) {
throw std::runtime_error("failed to allocate compute pp buffers");
}
Expand All @@ -682,7 +684,7 @@ void llama_context::sched_reserve() {
for (size_t i = 0; i < backend_ptrs.size(); ++i) {
ggml_backend_t backend = backend_ptrs[i];
ggml_backend_buffer_type_t buft = backend_buft[i];
if (!model.hparams.no_alloc) {
if (!no_alloc) {
backend_buf_exp_size[i] = ggml_backend_sched_get_buffer_size(sched.get(), backend);
}
if (backend_buf_exp_size[i] > 1) {
Expand Down Expand Up @@ -2211,6 +2213,13 @@ uint32_t llama_context::output_reserve(int32_t n_outputs) {
if (output_dev_host_buft) {
buft = output_dev_host_buft;
}
output_buft = buft;
output_bytes = new_size;
if (no_alloc) {
buf_output.reset(ggml_backend_buft_alloc_buffer(buft, 0));
if (!buf_output) { return 0; }
return n_outputs_max;
}
buf_output.reset(ggml_backend_buft_alloc_buffer(buft, new_size));
if (buf_output == nullptr) {
LLAMA_LOG_ERROR("%s: failed to allocate output buffer of size %.2f MiB\n", __func__, new_size / (1024.0 * 1024.0));
Expand Down Expand Up @@ -2546,7 +2555,9 @@ ggml_cgraph * llama_context::graph_reserve(
// initialize scheduler with the specified graph
if (split_only) {
if (sizes) {
ggml_backend_sched_reserve_size(sched.get(), gf, sizes);
std::vector<size_t> measured(backend_ptrs.size(), 0);
ggml_backend_sched_reserve_size(sched.get(), gf, measured.data());
for (size_t i = 0; i < measured.size(); ++i) { sizes[i] = std::max(sizes[i], measured[i]); }
} else {
ggml_backend_sched_split_graph(sched.get(), gf);
}
Expand Down Expand Up @@ -3401,11 +3412,11 @@ llama_memory_breakdown llama_context::memory_breakdown() const {
ret[buft].context += size;
}
}
if (model.hparams.no_alloc) {
if (no_alloc) {
for (size_t i = 0; i < backends.size(); ++i) {
ggml_backend_t backend = backends[i].get();
ggml_backend_buffer_type_t buft = ggml_backend_sched_get_buffer_type(sched.get(), backend);
ret[buft].compute += backend_buf_exp_size[i];
ret[buft].compute = std::max(ret[buft].compute, backend_buf_exp_size[i]);
}
} else {
std::vector<ggml_backend_buffer_type_t> reported;
Expand Down Expand Up @@ -3475,9 +3486,9 @@ llama_context_params llama_context_default_params() {
return result;
}

llama_context * llama_init_from_model(
llama_context * llama_context_create(
llama_model * model,
llama_context_params params) {
llama_context_params params, bool measure_only) {
if (!model) {
LLAMA_LOG_ERROR("%s: model cannot be NULL\n", __func__);
return nullptr;
Expand Down Expand Up @@ -3562,7 +3573,7 @@ llama_context * llama_init_from_model(
}

try {
auto * ctx = new llama_context(*model, params);
auto * ctx = new llama_context(*model, params, measure_only);
return ctx;
} catch (const std::exception & err) {
LLAMA_LOG_ERROR("%s: failed to initialize the context: %s\n", __func__, err.what());
Expand All @@ -3571,6 +3582,10 @@ llama_context * llama_init_from_model(
return nullptr;
}

llama_context * llama_init_from_model(llama_model * model, llama_context_params params) {
return llama_context_create(model, params, false);
}

// deprecated
llama_context * llama_new_context_with_model(
llama_model * model,
Expand Down
8 changes: 7 additions & 1 deletion src/llama-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct llama_context {
// init scheduler and compute buffers, reserve worst-case graphs
llama_context(
const llama_model & model,
llama_context_params params);
llama_context_params params, bool measure_only = false);

~llama_context();

Expand Down Expand Up @@ -198,6 +198,7 @@ struct llama_context {
void perf_reset();

llama_memory_breakdown memory_breakdown() const;
void visit_context_memory(llama_context_memory_callback callback, void * data) const;

//
// training
Expand Down Expand Up @@ -380,6 +381,7 @@ struct llama_context {
// members
//

const bool no_alloc;
const llama_model & model;

llama_cparams cparams;
Expand Down Expand Up @@ -506,6 +508,8 @@ struct llama_context {

// host buffer for the model output (logits and embeddings)
ggml_backend_buffer_ptr buf_output;
size_t output_bytes = 0;
ggml_backend_buffer_type_t output_buft = nullptr;

// keep copies of the per-sequence memory on the device
std::map<llama_seq_id, llama_memory_buffers> mem_storage;
Expand All @@ -529,3 +533,5 @@ struct llama_context {

mutable int32_t n_reused = 0; // number of times the previous graph was reused
};

llama_context * llama_context_create(llama_model * model, llama_context_params params, bool measure_only);
6 changes: 3 additions & 3 deletions src/llama-kv-cache-dsa-iswa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//

llama_kv_cache_dsa_iswa::llama_kv_cache_dsa_iswa(
const llama_model & model,
bool no_alloc, const llama_model & model,
ggml_type type_k,
ggml_type type_v,
bool v_trans,
Expand Down Expand Up @@ -63,14 +63,14 @@ llama_kv_cache_dsa_iswa::llama_kv_cache_dsa_iswa(
LLAMA_LOG_INFO("%s: creating DSA KV cache, size = %u cells\n", __func__, size_dsa);

kv_dsa = std::make_unique<llama_kv_cache_dsa>(
model, type_k, type_v,
no_alloc, model, type_k, type_v,
v_trans, offload, unified, size_dsa, n_seq_max, n_pad,
0, LLAMA_SWA_TYPE_NONE, filter_dsa, filter_lid, reuse);

LLAMA_LOG_INFO("%s: creating SWA KV cache, size = %u cells\n", __func__, size_swa);

kv_swa = std::make_unique<llama_kv_cache>(
model, hparams, type_k, type_v,
no_alloc, model, hparams, type_k, type_v,
v_trans, offload, unified, size_swa, n_seq_max, n_pad,
hparams.n_swa, hparams.swa_type, nullptr, filter_swa, reuse, nullptr);
}
Expand Down
2 changes: 1 addition & 1 deletion src/llama-kv-cache-dsa-iswa.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class llama_kv_cache_dsa_iswa : public llama_memory_i {
public:
llama_kv_cache_dsa_iswa(
const llama_model & model,
bool no_alloc, const llama_model & model,
ggml_type type_k,
ggml_type type_v,
bool v_trans,
Expand Down
6 changes: 3 additions & 3 deletions src/llama-kv-cache-dsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//

llama_kv_cache_dsa::llama_kv_cache_dsa(
const llama_model & model,
bool no_alloc, const llama_model & model,
ggml_type type_k,
ggml_type type_v,
bool v_trans,
Expand All @@ -31,7 +31,7 @@ llama_kv_cache_dsa::llama_kv_cache_dsa(
LLAMA_LOG_INFO("%s: creating main KV cache, size = %u cells\n", __func__, kv_size);

kv_mla = std::make_unique<llama_kv_cache>(
model, model.hparams, type_k, type_v,
no_alloc, model, model.hparams, type_k, type_v,
v_trans, offload, unified, kv_size, n_seq_max, n_pad,
n_swa, swa_type, nullptr, filter_mla, reuse, nullptr);

Expand All @@ -48,7 +48,7 @@ llama_kv_cache_dsa::llama_kv_cache_dsa(
LLAMA_LOG_INFO("%s: creating indexer KV cache, size = %u cells\n", __func__, kv_size);

kv_lid = std::make_unique<llama_kv_cache>(
model, hparams_lid, type_k, type_v,
no_alloc, model, hparams_lid, type_k, type_v,
v_trans, offload, unified, kv_size, n_seq_max, n_pad,
n_swa, swa_type, nullptr, filter_lid, reuse, nullptr);
}
Expand Down
2 changes: 1 addition & 1 deletion src/llama-kv-cache-dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
class llama_kv_cache_dsa : public llama_memory_i {
public:
llama_kv_cache_dsa(
const llama_model & model,
bool no_alloc, const llama_model & model,
ggml_type type_k,
ggml_type type_v,
bool v_trans,
Expand Down
Loading
Loading