Packages
llama_cpp_ex
0.8.12
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.0
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
0.3.0
0.2.0
Elixir bindings for llama.cpp — run LLMs locally with Metal, CUDA, Vulkan, or CPU acceleration.
Current section
Files
Jump to
Current section
Files
c_src/llama_cpp_ex/llama_nif.h
#pragma once
#include <fine.hpp>
#include <llama.h>
#include "chat.h"
#include "speculative.h"
#include <atomic>
namespace llama_cpp_ex {
// RAII wrapper for llama_model*
class LlamaModel {
public:
llama_model* model;
common_chat_templates_ptr chat_templates;
explicit LlamaModel(llama_model* m)
: model(m)
, chat_templates(common_chat_templates_init(m, ""))
{}
~LlamaModel() {
// Release chat_templates before freeing the model
chat_templates.reset();
if (model) llama_model_free(model);
}
LlamaModel(const LlamaModel&) = delete;
LlamaModel& operator=(const LlamaModel&) = delete;
const llama_vocab* vocab() const {
return llama_model_get_vocab(model);
}
};
// RAII wrapper for llama_context*
// Holds a ResourcePtr to the model to prevent premature GC.
class LlamaContext {
public:
llama_context* ctx;
fine::ResourcePtr<LlamaModel> model;
LlamaContext(llama_context* c, fine::ResourcePtr<LlamaModel> m)
: ctx(c), model(std::move(m)) {}
~LlamaContext() {
if (ctx) llama_free(ctx);
}
LlamaContext(const LlamaContext&) = delete;
LlamaContext& operator=(const LlamaContext&) = delete;
};
// RAII wrapper for llama_sampler*
class LlamaSampler {
public:
llama_sampler* sampler;
explicit LlamaSampler(llama_sampler* s) : sampler(s) {}
~LlamaSampler() {
if (sampler) llama_sampler_free(sampler);
}
LlamaSampler(const LlamaSampler&) = delete;
LlamaSampler& operator=(const LlamaSampler&) = delete;
};
// RAII wrapper for common_speculative* (MTP draft state).
// Holds ResourcePtrs to both the target (main) and draft (MTP) contexts so
// they stay alive while a speculative session is in flight. Counters are
// updated by the streaming generate_mtp_tokens NIF and read lock-free by
// speculative_stats; relaxed ordering is sufficient because readers tolerate
// a slightly stale snapshot and there is no cross-counter invariant to
// preserve.
class LlamaSpeculative {
public:
common_speculative* spec;
fine::ResourcePtr<LlamaContext> ctx_tgt;
fine::ResourcePtr<LlamaContext> ctx_dft;
uint32_t n_draft;
// True when ctx_tgt requires checkpointing for partial draft rollback
// (e.g. hybrid models like Qwen 3.6 MoE with GDN layers). Captured once
// at speculative_init time. Dense attention-only models report
// COMMON_CONTEXT_SEQ_RM_TYPE_PART and skip the checkpoint path entirely.
bool needs_ckpt;
std::atomic<uint64_t> n_iters{0};
std::atomic<uint64_t> n_drafts_generated{0};
std::atomic<uint64_t> n_drafts_accepted{0};
std::atomic<uint64_t> n_tokens_emitted{0};
std::atomic<uint64_t> us_draft{0};
std::atomic<uint64_t> us_verify{0};
std::atomic<uint64_t> us_sample{0};
// Everything in the speculative iter NOT inside the three hot-path
// timers above. On Metal this is dominated by implicit GPU-sync waits
// from the previous iter's async verify decode (llama_decode returns
// before the command buffer completes; the wait lands on the next
// unrelated allocation in the next iter). Sum of draft+verify+sample
// +other ≈ us_total.
std::atomic<uint64_t> us_other{0};
std::atomic<uint64_t> us_total{0};
LlamaSpeculative(common_speculative* s,
fine::ResourcePtr<LlamaContext> tgt,
fine::ResourcePtr<LlamaContext> dft,
uint32_t n,
bool ckpt)
: spec(s)
, ctx_tgt(std::move(tgt))
, ctx_dft(std::move(dft))
, n_draft(n)
, needs_ckpt(ckpt)
{}
~LlamaSpeculative() {
if (spec) common_speculative_free(spec);
}
LlamaSpeculative(const LlamaSpeculative&) = delete;
LlamaSpeculative& operator=(const LlamaSpeculative&) = delete;
};
} // namespace llama_cpp_ex