char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Charlotte Somsupport aliceai_t5_moe98a01afd9

char/aliceai-t5-moe
150.9 KiB4335 linesraw
1#include "llama-context.h"
2
3#include "ggml.h"
4#include "llama-arch.h"
5#include "llama-graph.h"
6#include "llama-impl.h"
7#include "llama-batch.h"
8#include "llama-io.h"
9#include "llama-memory.h"
10#include "llama-mmap.h"
11#include "llama-model.h"
12#include "llama-ext.h"
13#include "llama-sampler.h"
14#include "llama.h"
15
16#include <cinttypes>
17#include <cmath>
18#include <cstring>
19#include <limits>
20#include <stdexcept>
21#include <string>
22
23//
24// llama_context
25//
26
27static llm_graph_type ctx_type_to_graph_type(llama_context_type ctx_type) {
28    switch (ctx_type) {
29        case LLAMA_CONTEXT_TYPE_DEFAULT: return LLM_GRAPH_TYPE_DEFAULT;
30        case LLAMA_CONTEXT_TYPE_MTP    : return LLM_GRAPH_TYPE_DECODER_MTP;
31    }
32    throw std::runtime_error("Unsupported ctx type");
33}
34
35struct llm_fused_op_probe {
36    llm_fused_op op;
37    const char * name;
38    uint32_t n_tokens_per_seq;
39};
40
41static const llm_fused_op_probe llm_fused_op_flash_attn_probe = {
42    /*.op               =*/ LLM_FUSED_OP_FLASH_ATTN,
43    /*.name             =*/ "Flash Attention",
44    /*.n_tokens_per_seq =*/ 1,
45};
46
47static const llm_fused_op_probe llm_fused_op_gdn_ar_probe = {
48    /*.op               =*/ LLM_FUSED_OP_GDN_AR,
49    /*.name             =*/ "fused Gated Delta Net (autoregressive)",
50    /*.n_tokens_per_seq =*/ 1,
51};
52
53static const llm_fused_op_probe llm_fused_op_gdn_ch_probe = {
54    /*.op               =*/ LLM_FUSED_OP_GDN_CH,
55    /*.name             =*/ "fused Gated Delta Net (chunked)",
56    /*.n_tokens_per_seq =*/ 16,
57};
58
59static const llm_fused_op_probe llm_fused_op_lid_probe = {
60    /*.op               =*/ LLM_FUSED_OP_LIGHTNING_INDEXER,
61    /*.name             =*/ "Lightning Indexer",
62    /*.n_tokens_per_seq =*/ 1,
63};
64
65static const llm_fused_op_probe llm_fused_op_dsv4_hc_pre_probe = {
66    /*.op               =*/ LLM_FUSED_OP_DSV4_HC_PRE,
67    /*.name             =*/ "fused DeepSeek V4 HC pre",
68    /*.n_tokens_per_seq =*/ 1,
69};
70
71static const llm_fused_op_probe llm_fused_op_dsv4_hc_comb_probe = {
72    /*.op               =*/ LLM_FUSED_OP_DSV4_HC_COMB,
73    /*.name             =*/ "fused DeepSeek V4 HC comb",
74    /*.n_tokens_per_seq =*/ 1,
75};
76
77static const llm_fused_op_probe llm_fused_op_dsv4_hc_post_probe = {
78    /*.op               =*/ LLM_FUSED_OP_DSV4_HC_POST,
79    /*.name             =*/ "fused DeepSeek V4 HC post",
80    /*.n_tokens_per_seq =*/ 1,
81};
82
83llama_context::llama_context(
84        const llama_model & model,
85              llama_context_params params) :
86    model(model),
87    cvec(std::make_unique<llama_adapter_cvec>()),
88    loras(std::make_unique<llama_adapter_loras>()),
89    balloc(std::make_unique<llama_batch_allocr>(model.hparams.n_pos_per_embd())) {
90    // TODO warning when creating llama_context with awkward ctx size that is not a power of 2,
91    //     may need to be backend-dependent
92    LLAMA_LOG_INFO("%s: constructing llama_context\n", __func__);
93
94    t_start_us = model.t_start_us;
95    t_load_us  = model.t_load_us;
96
97    const auto & hparams = model.hparams;
98
99    cparams.n_seq_max = std::max(1u, params.n_seq_max);
100    if (cparams.n_seq_max > LLAMA_MAX_SEQ) {
101        throw std::runtime_error("n_seq_max must be <= " + std::to_string(LLAMA_MAX_SEQ));
102    }
103
104    cparams.n_rs_seq = params.n_rs_seq;
105    if (cparams.n_rs_seq > 0 && !llm_arch_supports_rs_rollback(model.arch)) {
106        LLAMA_LOG_DEBUG("%s: n_rs_seq=%u requested but model does not support recurrent partial rollback; clamping to 0\n",
107                        __func__, cparams.n_rs_seq);
108        cparams.n_rs_seq = 0;
109    }
110
111    cparams.n_threads               = params.n_threads;
112    cparams.n_threads_batch         = params.n_threads_batch;
113    cparams.yarn_ext_factor         = params.yarn_ext_factor  >= 0.0f ? params.yarn_ext_factor  : hparams.yarn_ext_factor;
114    cparams.yarn_attn_factor        = params.yarn_attn_factor >= 0.0f ? params.yarn_attn_factor : hparams.yarn_attn_factor;
115    cparams.yarn_beta_fast          = params.yarn_beta_fast   >= 0.0f ? params.yarn_beta_fast   : hparams.yarn_beta_fast;
116    cparams.yarn_beta_slow          = params.yarn_beta_slow   >= 0.0f ? params.yarn_beta_slow   : hparams.yarn_beta_slow;
117    cparams.embeddings              = params.embeddings;
118    cparams.embeddings_nextn        = false;
119    cparams.embeddings_nextn_masked = false;
120    cparams.offload_kqv             = params.offload_kqv;
121    cparams.no_perf                 = params.no_perf;
122    cparams.warmup                  = false;
123
124    // +1: id n_layer() taps the output of the last layer ("input" of the head)
125    cparams.embeddings_layer_inp.resize(hparams.n_layer() + 1, false);
126    embd_layer_inp.resize(hparams.n_layer() + 1);
127
128    cparams.ctx_type          = params.ctx_type;
129    cparams.rope_scaling_type = params.rope_scaling_type;
130    cparams.pooling_type      = params.pooling_type;
131
132    cparams.n_ctx            = params.n_ctx           == 0    ? hparams.n_ctx_train           : params.n_ctx;
133    cparams.rope_freq_base   = params.rope_freq_base  == 0.0f ? hparams.rope_freq_base_train  : params.rope_freq_base;
134    cparams.rope_freq_scale  = params.rope_freq_scale == 0.0f ? hparams.rope_freq_scale_train : params.rope_freq_scale;
135
136    cparams.n_ctx_orig_yarn  = params.yarn_orig_ctx    != 0 ? params.yarn_orig_ctx    :
137                               hparams.n_ctx_orig_yarn != 0 ? hparams.n_ctx_orig_yarn :
138                                                              hparams.n_ctx_train;
139
140    cparams.cb_eval           = params.cb_eval;
141    cparams.cb_eval_user_data = params.cb_eval_user_data;
142
143    cparams.ctx_other = nullptr;
144
145    // TODO: more generic
146    if (model.arch == LLM_ARCH_GEMMA4_ASSISTANT) {
147        if (params.ctx_other == nullptr) {
148            // TODO: change from runtime_error to llama_exception to avoid printing error message
149            throw std::runtime_error("Gemma4Assistant requires ctx_other to be set (this warning is normal during memory fitting)");
150        }
151
152        cparams.ctx_other = params.ctx_other;
153    }
154
155    if (model.arch == LLM_ARCH_EAGLE3 || model.arch == LLM_ARCH_DFLASH) {
156        if (model.tok_embd == nullptr || model.output == nullptr) {
157            if (params.ctx_other == nullptr) {
158                throw std::runtime_error(model.arch_name() + " requires ctx_other to be set (this warning is normal during memory fitting)");
159            }
160            cparams.ctx_other = params.ctx_other;
161        }
162    }
163
164    if (cparams.rope_scaling_type == LLAMA_ROPE_SCALING_TYPE_UNSPECIFIED) {
165        cparams.rope_scaling_type = hparams.rope_scaling_type_train;
166    }
167
168    if (cparams.rope_scaling_type == LLAMA_ROPE_SCALING_TYPE_NONE) {
169        cparams.rope_freq_scale = 1.0f; // never scale if scaling type is none
170    }
171
172    if (cparams.yarn_ext_factor < 0.0f) { // negative indicates 'not set'
173        cparams.yarn_ext_factor = cparams.rope_scaling_type == LLAMA_ROPE_SCALING_TYPE_YARN ? 1.0f : 0.0f;
174    }
175
176    if (cparams.yarn_ext_factor != 0) {
177        static auto get_mscale = [](float scale, float mscale) {
178            return scale <= 1.0f ? 1.0f : (0.1f * mscale * logf(scale) + 1.0f);
179        };
180
181        const float factor = 1.0f / cparams.rope_freq_scale;
182
183        // ref: https://github.com/huggingface/transformers/blob/6d00f6b0a5679c36510f203e4226e36f517c3032/src/transformers/modeling_rope_utils.py#L336-L348
184        if (hparams.rope_yarn_log_mul != 0.0f) {
185            // note: here we assume `mscale == 1.0f`
186            // TODO: start reading the actual value of mscale and handle the case where it is not 1.0f
187                  float mscale          = 1.0f;
188            const float mscale_all_dims = hparams.rope_yarn_log_mul;
189
190            // [TAG_DEEPSEEK2_YARN_LOG_MUL_FIX]
191            // special-case DEEPSEEK v2:
192            // https://huggingface.co/deepseek-ai/DeepSeek-V2-Lite-Chat/blob/main/config.json#L42-L43
193            if (model.arch == LLM_ARCH_DEEPSEEK2 && mscale_all_dims != 1.0f) {
194                mscale = mscale_all_dims;
195            }
196
197            cparams.yarn_attn_factor = get_mscale(factor, mscale) / get_mscale(factor, mscale_all_dims);
198
199            LLAMA_LOG_WARN("%s: setting new yarn_attn_factor = %.4f (mscale == %.1f, mscale_all_dim = %.1f)\n",
200                    __func__, cparams.yarn_attn_factor, mscale, mscale_all_dims);
201        } else {
202            cparams.yarn_attn_factor = get_mscale(factor, 1.0f);
203        }
204
205        // when YARN is applied with yarn_ext_factor != 0.0f, we need to cancel this factor:
206        // https://github.com/ggml-org/llama.cpp/blob/a81a569577cc38b32558958b048228150be63eae/ggml/src/ggml-cpu/ops.cpp#L5541-L5544
207        //
208        // ref: https://github.com/ggml-org/llama.cpp/discussions/7416
209        //      https://github.com/ggml-org/llama.cpp/pull/17945
210        cparams.yarn_attn_factor *= 1.0f / (1.0f + 0.1f * logf(factor));
211    }
212
213    cparams.yarn_attn_factor *= hparams.rope_attn_factor;
214
215    if (cparams.pooling_type == LLAMA_POOLING_TYPE_UNSPECIFIED) {
216        if (hparams.pooling_type == LLAMA_POOLING_TYPE_UNSPECIFIED) {
217            cparams.pooling_type = LLAMA_POOLING_TYPE_NONE;
218        } else {
219            cparams.pooling_type = hparams.pooling_type;
220        }
221    }
222
223    if (params.attention_type == LLAMA_ATTENTION_TYPE_UNSPECIFIED) {
224        cparams.causal_attn = hparams.causal_attn;
225    } else {
226        cparams.causal_attn = params.attention_type == LLAMA_ATTENTION_TYPE_CAUSAL;
227    }
228
229    cparams.flash_attn = params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_DISABLED;
230    cparams.auto_fa    = params.flash_attn_type == LLAMA_FLASH_ATTN_TYPE_AUTO;
231
232    cparams.fused_gdn_ar = true;
233    cparams.fused_gdn_ch = true;
234    cparams.auto_fgdn    = false;
235
236    cparams.fused_lid = true;
237    cparams.auto_flid = false;
238
239    cparams.fused_dsv4_hc_pre  = true;
240    cparams.fused_dsv4_hc_comb = true;
241    cparams.fused_dsv4_hc_post = true;
242    cparams.auto_fhc           = true;
243
244    // with causal attention, the batch size is limited by the context size
245    cparams.n_batch = cparams.causal_attn ? std::min(cparams.n_ctx, params.n_batch) : params.n_batch;
246
247    cparams.n_ubatch = std::min(cparams.n_batch, params.n_ubatch == 0 ? params.n_batch : params.n_ubatch);
248
249    cparams.n_outputs_max = params.n_outputs_max == 0 || llama_model_has_encoder(&model) ? cparams.n_batch : params.n_outputs_max;
250    cparams.n_outputs_max_per_seq = params.n_outputs_max_per_seq == 0 ?
251            cparams.n_outputs_max : std::min(params.n_outputs_max_per_seq, cparams.n_outputs_max);
252
253    // Initialize backend samplers here so they are part of the sampling graph
254    // before the reserve passes run later in this function. This avoids a later
255    // re-reserve when graph nodes change.
256    if (params.samplers != nullptr && params.n_samplers > 0) {
257        for (size_t i = 0; i < params.n_samplers; ++i) {
258            const auto & config = params.samplers[i];
259
260            if (llama_sampler_chain_get(config.sampler, -1) == nullptr) {
261                throw std::runtime_error("the backend samplers must be of type llama_sampler_chain");
262            }
263
264            if (set_sampler(config.seq_id, config.sampler)) {
265                const int n_samplers = llama_sampler_chain_n(config.sampler);
266
267                LLAMA_LOG_INFO("%s: setting backend sampler for seq_id %d (n = %d)\n", __func__, config.seq_id, n_samplers);
268            }
269        }
270    }
271
272    cparams.op_offload = params.op_offload;
273    cparams.kv_unified = params.kv_unified;
274
275    // initialized later
276    cparams.pipeline_parallel = false;
277
278    {
279        const char * LLAMA_GRAPH_REUSE_DISABLE = getenv("LLAMA_GRAPH_REUSE_DISABLE");
280        graph_reuse_disable = LLAMA_GRAPH_REUSE_DISABLE ? (atoi(LLAMA_GRAPH_REUSE_DISABLE) != 0) : graph_reuse_disable;
281
282        if (graph_reuse_disable) {
283            LLAMA_LOG_WARN("%s: graph reuse disabled\n", __func__);
284        }
285    }
286
287    // ref: https://github.com/ggml-org/llama.cpp/pull/17046#discussion_r2503085732
288    cparams.n_ctx = GGML_PAD(cparams.n_ctx, 256);
289
290    if (cparams.kv_unified) {
291        cparams.n_ctx_seq = cparams.n_ctx;
292    } else {
293        cparams.n_ctx_seq = cparams.n_ctx / cparams.n_seq_max;
294        cparams.n_ctx_seq = GGML_PAD(cparams.n_ctx_seq, 256);
295
296        if (cparams.n_ctx_seq == 0) {
297            throw std::runtime_error("n_ctx_seq == 0");
298        }
299
300        if (cparams.n_ctx != cparams.n_ctx_seq * cparams.n_seq_max) {
301            cparams.n_ctx =  cparams.n_ctx_seq * cparams.n_seq_max;
302            LLAMA_LOG_WARN("%s: n_ctx is not divisible by n_seq_max - rounding down to %u\n", __func__, cparams.n_ctx);
303        }
304    }
305
306    LLAMA_LOG_INFO("%s: n_seq_max             = %u\n",   __func__, cparams.n_seq_max);
307    LLAMA_LOG_INFO("%s: n_ctx                 = %u\n",   __func__, cparams.n_ctx);
308    LLAMA_LOG_INFO("%s: n_ctx_seq             = %u\n",   __func__, cparams.n_ctx_seq);
309    LLAMA_LOG_INFO("%s: n_batch               = %u\n",   __func__, cparams.n_batch);
310    LLAMA_LOG_INFO("%s: n_ubatch              = %u\n",   __func__, cparams.n_ubatch);
311    LLAMA_LOG_INFO("%s: causal_attn           = %d\n",   __func__, cparams.causal_attn);
312    LLAMA_LOG_INFO("%s: flash_attn            = %s\n",   __func__, llama_flash_attn_type_name(params.flash_attn_type));
313    LLAMA_LOG_INFO("%s: kv_unified            = %s\n",   __func__, cparams.kv_unified ? "true" : "false");
314    LLAMA_LOG_INFO("%s: freq_base             = %.1f\n", __func__, cparams.rope_freq_base);
315    LLAMA_LOG_INFO("%s: freq_scale            = %g\n",   __func__, cparams.rope_freq_scale);
316    LLAMA_LOG_INFO("%s: n_rs_seq              = %u\n",   __func__, cparams.n_rs_seq);
317    LLAMA_LOG_INFO("%s: n_outputs_max         = %u\n",   __func__, cparams.n_outputs_max);
318    LLAMA_LOG_INFO("%s: n_outputs_max_per_seq = %u\n",   __func__, cparams.n_outputs_max_per_seq);
319
320    if (cparams.n_ctx_seq < hparams.n_ctx_train) {
321        LLAMA_LOG_INFO("%s: n_ctx_seq (%u) < n_ctx_train (%u) -- the full capacity of the model will not be utilized\n",
322                __func__, cparams.n_ctx_seq, hparams.n_ctx_train);
323    }
324
325    if (cparams.n_ctx_seq > hparams.n_ctx_train) {
326        LLAMA_LOG_WARN("%s: n_ctx_seq (%u) > n_ctx_train (%u) -- possible training context overflow\n",
327                __func__, cparams.n_ctx_seq, hparams.n_ctx_train);
328    }
329
330    if (!hparams.vocab_only) {
331        // GPU backends
332        for (const auto & dev : model.devices) {
333            ggml_backend_t backend = ggml_backend_dev_init(dev.dev, nullptr);
334            if (backend == nullptr) {
335                throw std::runtime_error(format("failed to initialize %s backend", ggml_backend_dev_name(dev.dev)));
336            }
337            backends.emplace_back(backend);
338        }
339
340        // add ACCEL backends (such as BLAS)
341        for (size_t i = 0; i < ggml_backend_dev_count(); ++i) {
342            ggml_backend_dev_t dev = ggml_backend_dev_get(i);
343            if (ggml_backend_dev_type(dev) == GGML_BACKEND_DEVICE_TYPE_ACCEL) {
344                ggml_backend_t backend = ggml_backend_dev_init(dev, nullptr);
345                if (backend == nullptr) {
346                    throw std::runtime_error(format("failed to initialize %s backend", ggml_backend_dev_name(dev)));
347                }
348                backends.emplace_back(backend);
349            }
350        }
351
352        // add CPU backend
353        backend_cpu = ggml_backend_init_by_type(GGML_BACKEND_DEVICE_TYPE_CPU, nullptr);
354        if (backend_cpu == nullptr) {
355            throw std::runtime_error("failed to initialize CPU backend");
356        }
357        backends.emplace_back(backend_cpu);
358
359        // create a list of the set_n_threads functions in the backends
360        for (auto & backend : backends) {
361            ggml_backend_dev_t dev = ggml_backend_get_device(backend.get());
362            ggml_backend_reg_t reg = dev ? ggml_backend_dev_backend_reg(dev) : nullptr;
363            if (reg) {
364                auto ggml_backend_set_n_threads_fn = (ggml_backend_set_n_threads_t) ggml_backend_reg_get_proc_address(reg, "ggml_backend_set_n_threads");
365                if (ggml_backend_set_n_threads_fn) {
366                    set_n_threads_fns.emplace_back(backend.get(), ggml_backend_set_n_threads_fn);
367                }
368            }
369        }
370
371        llama_set_abort_callback(this, params.abort_callback, params.abort_callback_data);
372
373        // graph outputs buffer
374        {
375            if (output_reserve(params.n_seq_max) < params.n_seq_max) {
376                throw std::runtime_error("failed to reserve initial output buffer");
377            }
378
379            LLAMA_LOG_INFO("%s: %10s  output buffer size = %8.2f MiB\n", __func__,
380                    ggml_backend_buffer_name    (buf_output.get()),
381                    ggml_backend_buffer_get_size(buf_output.get()) / 1024.0 / 1024.0);
382        }
383    }
384
385    // init the memory module
386    if (!hparams.vocab_only) {
387        llama_memory_params params_mem = {
388            /*.type_k    =*/ params.type_k,
389            /*.type_v    =*/ params.type_v,
390            /*.swa_full  =*/ params.swa_full,
391            /*.ctx_type  =*/ cparams.ctx_type,
392            /*.mem_other =*/ llama_get_memory(cparams.ctx_other),
393        };
394
395        memory.reset(model.create_memory(params_mem, cparams));
396    }
397
398    // init backends
399    if (!hparams.vocab_only) {
400        LLAMA_LOG_DEBUG("%s: enumerating backends\n", __func__);
401
402        backend_buft.clear();
403        backend_ptrs.clear();
404        backend_buf_exp_size.clear();
405
406        for (auto & backend : backends) {
407            auto * buft = ggml_backend_get_default_buffer_type(backend.get());
408            auto backend_type = ggml_backend_dev_type(ggml_backend_get_device(backend.get()));
409
410            if (backend_type == GGML_BACKEND_DEVICE_TYPE_CPU && !model.devices.empty()) {
411                // use the host buffer of the first device CPU for faster transfer of the intermediate state
412                const auto & dev = model.devices[0];
413                auto * host_buft = ggml_backend_dev_host_buffer_type(dev.dev);
414                if (host_buft) {
415                    buft = host_buft;
416                }
417            }
418
419            backend_buft.push_back(buft);
420            backend_ptrs.push_back(backend.get());
421            backend_buf_exp_size.push_back(0);
422        }
423
424        LLAMA_LOG_DEBUG("%s: backend_ptrs.size() = %zu\n", __func__, backend_ptrs.size());
425
426        // TODO: move these checks to ggml_backend_sched
427        // enabling pipeline parallelism in the scheduler increases memory usage, so it is only done when necessary
428        bool pipeline_parallel =
429            model.n_devices() > 1 &&
430            model.n_gpu_layers() > model.hparams.n_layer_all &&
431            model.split_mode() == LLAMA_SPLIT_MODE_LAYER &&
432            cparams.offload_kqv &&
433            !model.has_tensor_overrides();
434
435        // pipeline parallelism requires support for async compute and events in all devices
436        if (pipeline_parallel) {
437            for (auto & backend : backends) {
438                auto dev_type = ggml_backend_dev_type(ggml_backend_get_device(backend.get()));
439                if (dev_type == GGML_BACKEND_DEVICE_TYPE_CPU) {
440                    // ignore CPU backend
441                    // TODO: should we ignore ACCEL types too?
442                    continue;
443                }
444                auto * dev = ggml_backend_get_device(backend.get());
445                ggml_backend_dev_props props;
446                ggml_backend_dev_get_props(dev, &props);
447                if (!props.caps.async || !props.caps.events) {
448                    // device does not support async compute or events
449                    pipeline_parallel = false;
450                    break;
451                }
452            }
453        }
454
455        cparams.pipeline_parallel = pipeline_parallel;
456
457        if (cparams.pipeline_parallel) {
458            LLAMA_LOG_INFO("%s: pipeline parallelism enabled\n", __func__);
459        }
460
461        sched_reserve();
462
463        if (!cparams.flash_attn) {
464            if (ggml_is_quantized(params.type_v)) {
465                throw std::runtime_error("quantized V cache was requested, but this requires Flash Attention");
466            }
467        }
468    }
469
470    // Initialize the full vocabulary token ids for backend samplers.
471    {
472        const int n_vocab = model.vocab.n_tokens();
473
474        sampling.token_ids_full_vocab.resize(n_vocab);
475        for (int i = 0; i < n_vocab; ++i) {
476            sampling.token_ids_full_vocab[i] = i;
477        }
478    }
479}
480
481llama_context::~llama_context() {
482    // wait for any pending asynchronous copies into the output buffers before they are freed
483    synchronize();
484
485    // when training, ggml_opt allocates extra buffers through the scheduler, so the sizes no longer match the expectation
486    if (!model.hparams.no_alloc && !opt_ctx) {
487        for (size_t i = 0; i < backend_ptrs.size(); ++i) {
488            ggml_backend_t             backend = backend_ptrs[i];
489            ggml_backend_buffer_type_t buft    = backend_buft[i];
490
491            const size_t size_exp = backend_buf_exp_size[i];
492            const size_t size_act = ggml_backend_sched_get_buffer_size(sched.get(), backend);
493            if (size_exp == size_act) {
494                LLAMA_LOG_DEBUG("%s: %10s compute buffer size is %8.4f MiB, matches expectation of %8.4f MiB\n",
495                    __func__, ggml_backend_buft_name(buft), size_act / (1024.0*1024.0), size_exp / (1024.0*1024.0));
496            } else {
497                LLAMA_LOG_WARN("%s: %10s compute buffer size of %8.4f MiB, does not match expectation of %8.4f MiB\n",
498                    __func__, ggml_backend_buft_name(buft), size_act / (1024.0*1024.0), size_exp / (1024.0*1024.0));
499            }
500        }
501    }
502    ggml_opt_free(opt_ctx);
503}
504
505void llama_context::resolve_fused_ops(const llama_memory_context_i * mctx, uint32_t n_seqs) {
506    const char * func = __func__;
507    auto resolve = [&](const llm_fused_op_probe & probe, bool & enabled) {
508        if (!enabled) {
509            return;
510        }
511
512        const uint32_t n_tokens_probe = probe.n_tokens_per_seq*n_seqs;
513
514        auto * gf = graph_reserve(n_tokens_probe, n_seqs, n_tokens_probe, mctx, true);
515        if (!gf) {
516            throw std::runtime_error(std::string("failed to reserve graph for ") + probe.name + " check");
517        }
518
519        bool device_mismatch = false;
520        for (const auto & node : get_gf_res_reserve()->get_fused_nodes()) {
521            if (node.op != probe.op) {
522                continue;
523            }
524
525            GGML_ASSERT(node.il >= 0);
526
527            ggml_backend_t backend_fused = ggml_backend_sched_get_tensor_backend(sched.get(), node.tensor);
528            ggml_backend_dev_t device_fused = backend_fused ? ggml_backend_get_device(backend_fused) : nullptr;
529
530            // TODO: make this descriptor-specific; model.dev_layer() preserves the current behavior,
531            // but is still wrong for cases like --no-kv-offload.
532            ggml_backend_dev_t device_layer = model.dev_layer(node.il);
533
534            if (device_fused != device_layer) {
535                LLAMA_LOG_WARN("%s: layer %d is assigned to device %s but %s "
536                        "is assigned to device %s (usually due to missing support)\n",
537                        func, node.il,
538                        device_layer ? ggml_backend_dev_name(device_layer) : "none",
539                        probe.name,
540                        device_fused ? ggml_backend_dev_name(device_fused) : "none");
541                device_mismatch = true;
542                break;
543            }
544        }
545
546        if (device_mismatch) {
547            enabled = false;
548            LLAMA_LOG_WARN("%s: %s not supported, set to disabled\n", func, probe.name);
549        } else {
550            enabled = true;
551            LLAMA_LOG_INFO("%s: %s enabled\n", func, probe.name);
552        }
553    };
554
555    if (cparams.auto_fa) {
556        resolve(llm_fused_op_flash_attn_probe, cparams.flash_attn);
557        cparams.auto_fa = false;
558    }
559
560    if (cparams.auto_fgdn) {
561        LLAMA_LOG_INFO("%s: resolving fused Gated Delta Net support:\n", func);
562        resolve(llm_fused_op_gdn_ar_probe, cparams.fused_gdn_ar);
563        resolve(llm_fused_op_gdn_ch_probe, cparams.fused_gdn_ch);
564        cparams.auto_fgdn = false;
565    }
566
567    if (cparams.auto_flid) {
568        LLAMA_LOG_INFO("%s: resolving fused Lightning Indexer support:\n", func);
569        resolve(llm_fused_op_lid_probe, cparams.fused_lid);
570        cparams.auto_flid = false;
571    }
572
573    if (cparams.auto_fhc) {
574        LLAMA_LOG_INFO("%s: resolving fused DeepSeek V4 HC support:\n", func);
575        resolve(llm_fused_op_dsv4_hc_pre_probe,  cparams.fused_dsv4_hc_pre);
576        resolve(llm_fused_op_dsv4_hc_comb_probe, cparams.fused_dsv4_hc_comb);
577        resolve(llm_fused_op_dsv4_hc_post_probe, cparams.fused_dsv4_hc_post);
578        cparams.auto_fhc = false;
579    }
580}
581
582void llama_context::sched_reserve() {
583    if (!sched_need_reserve) {
584        return;
585    }
586
587    sched_need_reserve = false;
588
589    LLAMA_LOG_INFO("%s: reserving ...\n", __func__);
590
591    synchronize();
592
593    const int64_t t_start_us = ggml_time_us();
594
595    const uint32_t n_seqs = cparams.n_seq_max;
596    const uint32_t n_tokens = std::min(cparams.n_ctx, cparams.n_ubatch);
597
598    const size_t max_nodes = this->graph_max_nodes(n_tokens);
599
600    LLAMA_LOG_DEBUG("%s: max_nodes = %zu\n", __func__, max_nodes);
601
602    gf_res_prev.reset(new llm_graph_result(max_nodes));
603    gf_res_reserve.reset(new llm_graph_result(max_nodes));
604
605    sched.reset(ggml_backend_sched_new(backend_ptrs.data(), backend_buft.data(), backend_ptrs.size(), max_nodes, cparams.pipeline_parallel, cparams.op_offload));
606
607    llama_memory_context_ptr mctx;
608    if (memory) {
609        LLAMA_LOG_DEBUG("%s: reserving full memory module\n", __func__);
610        mctx = memory->init_full();
611        if (!mctx) {
612            throw std::runtime_error("failed to initialize memory module");
613        }
614    }
615
616    // avoid reserving graphs with zero outputs - assume one output per sequence
617    const int n_outputs = n_seqs;
618
619    LLAMA_LOG_DEBUG("%s: worst-case: n_tokens = %d, n_seqs = %d, n_outputs = %d\n", __func__, n_tokens, n_seqs, n_outputs);
620
621    resolve_fused_ops(mctx.get(), n_seqs);
622
623    // reserve worst-case graph
624    int n_splits_pp = -1;
625    int n_nodes_pp  = -1;
626
627    int n_splits_tg = -1;
628    int n_nodes_tg  = -1;
629
630    const uint32_t n_outputs_pp = std::min(n_tokens, cparams.n_outputs_max);
631
632    // reserve pp (prompt processing) graph first so that buffers are only allocated once
633    {
634        auto * gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(),
635                model.hparams.no_alloc, model.hparams.no_alloc ? backend_buf_exp_size.data() : nullptr);
636        if (!gf) {
637            if (cparams.pipeline_parallel) {
638                LLAMA_LOG_WARN("%s: compute buffer allocation failed, retrying without pipeline parallelism\n", __func__);
639                cparams.pipeline_parallel = false;
640                sched.reset(ggml_backend_sched_new(backend_ptrs.data(), backend_buft.data(), backend_ptrs.size(), max_nodes, false, cparams.op_offload));
641                gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get());
642            }
643            if (!gf) {
644                throw std::runtime_error("failed to allocate compute pp buffers");
645            }
646        }
647
648        n_splits_pp = ggml_backend_sched_get_n_splits(sched.get());
649        n_nodes_pp  = ggml_graph_n_nodes(gf);
650    }
651
652    // reserve with tg (token generation) graph to get the number of splits and nodes
653    {
654        auto * gf = graph_reserve(n_seqs, n_seqs, n_seqs, mctx.get(), model.hparams.no_alloc);
655        if (!gf) {
656            throw std::runtime_error("failed to allocate compute tg buffers");
657        }
658
659        n_splits_tg = ggml_backend_sched_get_n_splits(sched.get());
660        n_nodes_tg  = ggml_graph_n_nodes(gf);
661    }
662
663    // reserve again with pp graph to avoid ggml-alloc reallocations during inference
664    {
665        // TODO: the worst case graph is not always reached for `n_seqs > 1`
666        //       need to implement a more robust mechanism that tries a few different inputs and analyzes the results
667        ggml_cgraph * gf = nullptr;
668        switch (model.arch) {
669            case LLM_ARCH_KIMI_LINEAR:
670            case LLM_ARCH_MINIMAX_01:
671                // [TAG_RESERVE_DIAG_DECAY]
672                // the `inp_diag_decay` tensor size scales with `n_seq_tokens^2` which
673                // makes `n_seqs == 1` use more memory for the compute graph compared to `n_seqs > 1`
674                gf = graph_reserve(n_tokens, 1,      n_outputs_pp, mctx.get(), model.hparams.no_alloc);
675                break;
676            default:
677                gf = graph_reserve(n_tokens, n_seqs, n_outputs_pp, mctx.get(), model.hparams.no_alloc);
678        };
679
680        if (!gf) {
681            throw std::runtime_error("failed to allocate compute pp buffers");
682        }
683    }
684
685    for (size_t i = 0; i < backend_ptrs.size(); ++i) {
686        ggml_backend_t             backend = backend_ptrs[i];
687        ggml_backend_buffer_type_t buft    = backend_buft[i];
688        if (!model.hparams.no_alloc) {
689            backend_buf_exp_size[i] = ggml_backend_sched_get_buffer_size(sched.get(), backend);
690        }
691        if (backend_buf_exp_size[i] > 1) {
692            LLAMA_LOG_INFO("%s: %10s compute buffer size = %8.2f MiB\n", __func__,
693                    ggml_backend_buft_name(buft),
694                    backend_buf_exp_size[i] / 1024.0 / 1024.0);
695        }
696    }
697
698    if (n_nodes_pp == n_nodes_tg) {
699        LLAMA_LOG_INFO("%s: graph nodes  = %d\n", __func__, n_nodes_pp);
700    } else {
701        LLAMA_LOG_INFO("%s: graph nodes  = %d (with bs=%d), %d (with bs=1)\n", __func__, n_nodes_pp, n_tokens, n_nodes_tg);
702    }
703
704    if (n_splits_pp == n_splits_tg) {
705        LLAMA_LOG_INFO("%s: graph splits = %d\n", __func__, n_splits_pp);
706    } else {
707        LLAMA_LOG_INFO("%s: graph splits = %d (with bs=%d), %d (with bs=1)\n", __func__, n_splits_pp, n_tokens, n_splits_tg);
708    }
709
710    const int64_t t_end_us = ggml_time_us();
711
712    LLAMA_LOG_INFO("%s: reserve took %.2f ms, sched copies = %d\n",
713            __func__, (t_end_us - t_start_us)/1000.0, ggml_backend_sched_get_n_copies(sched.get()));
714}
715
716void llama_context::synchronize() {
717    if (!sched) {
718        return;
719    }
720
721    ggml_backend_sched_synchronize(sched.get());
722
723    // FIXME: if multiple single tokens are evaluated without a synchronization,
724    // the stats will be added to the prompt evaluation stats
725    // this should only happen when using batch size 1 to evaluate a batch
726
727    // add the evaluation to the stats
728    if (n_queued_tokens == 1) {
729        if (!cparams.no_perf) {
730            t_eval_us += ggml_time_us() - t_compute_start_us;
731        }
732        n_eval++;
733    } else if (n_queued_tokens > 1) {
734        if (!cparams.no_perf) {
735            t_p_eval_us += ggml_time_us() - t_compute_start_us;
736        }
737        n_p_eval += n_queued_tokens;
738    }
739
740    // get a more accurate load time, upon first eval
741    if (n_queued_tokens > 0 && !has_evaluated_once) {
742        t_load_us = ggml_time_us() - t_start_us;
743        has_evaluated_once = true;
744    }
745
746    n_queued_tokens = 0;
747    t_compute_start_us = 0;
748}
749
750const llama_model & llama_context::get_model() const {
751    return model;
752}
753
754const llama_cparams & llama_context::get_cparams() const {
755    return cparams;
756}
757
758ggml_backend_sched_t llama_context::get_sched() const {
759    return sched.get();
760}
761
762uint32_t llama_context::n_ctx() const {
763    return cparams.n_ctx;
764}
765
766uint32_t llama_context::n_ctx_seq() const {
767    return cparams.n_ctx_seq;
768}
769
770uint32_t llama_context::n_batch() const {
771    return cparams.n_batch;
772}
773
774uint32_t llama_context::n_ubatch() const {
775    return cparams.n_ubatch;
776}
777
778uint32_t llama_context::n_seq_max() const {
779    return cparams.n_seq_max;
780}
781
782uint32_t llama_context::n_threads() const {
783    return cparams.n_threads;
784}
785
786uint32_t llama_context::n_threads_batch() const {
787    return cparams.n_threads_batch;
788}
789
790llama_memory_t llama_context::get_memory() const {
791    return memory.get();
792}
793
794bool llama_context::memory_update(bool optimize) {
795    if (!memory) {
796        return false;
797    }
798
799    {
800        const auto mctx = memory->init_update(this, optimize);
801        switch (mctx->get_status()) {
802            case LLAMA_MEMORY_STATUS_SUCCESS:
803                {
804                    // noop
805                } break;
806            case LLAMA_MEMORY_STATUS_NO_UPDATE:
807                {
808                    // no updates need to be performed
809                    return false;
810                }
811            case LLAMA_MEMORY_STATUS_FAILED_PREPARE:
812            case LLAMA_MEMORY_STATUS_FAILED_COMPUTE:
813                {
814                    LLAMA_LOG_ERROR("%s: failed to prepare memory update\n", __func__);
815                    return false;
816                }
817        }
818
819        // reset the previous graph result to make sure that it won't be reused
820        // TODO: change the mctx->apply() to return information if a graph reserve is needed
821        //       reset the graph result only if the memory module did reset the scheduler
822        gf_res_prev->reset();
823
824        if (!mctx->apply()) {
825            LLAMA_LOG_ERROR("%s: failed to apply memory update\n", __func__);
826        }
827    }
828
829    // if the memory module did any computation, we have to reserve a new worst-case graph
830    {
831        const auto mctx = memory->init_full();
832        if (!mctx) {
833            throw std::runtime_error("failed to initialize memory context");
834        }
835
836        const uint32_t n_seqs = cparams.n_seq_max;
837        const uint32_t n_tokens = std::min(cparams.n_ctx, cparams.n_ubatch);
838
839        const uint32_t n_outputs_max = std::min(n_tokens, cparams.n_outputs_max);
840
841        auto * gf = graph_reserve(n_tokens, n_seqs, n_outputs_max, mctx.get());
842        if (!gf) {
843            LLAMA_LOG_ERROR("%s: failed to reserve graph after the memory update\n", __func__);
844        }
845    }
846
847    return true;
848}
849
850enum llama_pooling_type llama_context::pooling_type() const {
851    return cparams.pooling_type;
852}
853
854float * llama_context::get_logits() {
855    output_reorder();
856
857    return logits.data;
858}
859
860int64_t llama_context::output_resolve_row(int32_t i) const {
861    int64_t j = -1;
862
863    // support negative indices (last output row)
864    if (i < 0) {
865        j = n_outputs + i;
866        if (j < 0) {
867            throw std::runtime_error(format("negative index out of range [0, %d)", n_outputs));
868        }
869    } else if ((size_t) i >= output_ids.size()) {
870        throw std::runtime_error(format("out of range [0, %zu)", output_ids.size()));
871    } else {
872        // use output_ids to translate the batch token index into a row number
873        // that holds this token's data.
874        j = output_ids[i];
875    }
876
877    if (j < 0) {
878        // the batch token was not configured to output anything
879        throw std::runtime_error(format("batch.logits[%d] != true", i));
880    }
881
882    if (j >= n_outputs) {
883        throw std::runtime_error(format("corrupt output buffer (j=%" PRId64 ", n_outputs=%d)", j, n_outputs));
884    }
885
886    return j;
887}
888
889float * llama_context::get_logits_ith(int32_t i) {
890    output_reorder();
891
892    try {
893        if (logits.data == nullptr) {
894            throw std::runtime_error("no logits");
895        }
896
897        const int64_t j = output_resolve_row(i);
898        return logits.data + j*model.vocab.n_tokens();
899    } catch (const std::exception & err) {
900        LLAMA_LOG_ERROR("%s: invalid logits id %d, reason: %s\n", __func__, i, err.what());
901#ifndef NDEBUG
902        GGML_ABORT("fatal error");
903#else
904        return nullptr;
905#endif
906    }
907}
908
909float * llama_context::get_embeddings() {
910    output_reorder();
911
912    return embd.data;
913}
914
915llama_token * llama_context::get_sampled_tokens()  const{
916    return sampling.sampled.data;
917}
918
919float * llama_context::get_embeddings_ith(int32_t i) {
920    output_reorder();
921
922    try {
923        if (embd.data == nullptr) {
924            throw std::runtime_error("no embeddings");
925        }
926
927        const int64_t j = output_resolve_row(i);
928        const uint32_t n_embd_out = model.hparams.n_embd_out();
929        return embd.data + j*n_embd_out;
930    } catch (const std::exception & err) {
931        LLAMA_LOG_ERROR("%s: invalid embeddings id %d, reason: %s\n", __func__, i, err.what());
932#ifndef NDEBUG
933        GGML_ABORT("fatal error");
934#else
935        return nullptr;
936#endif
937    }
938}
939
940float * llama_context::get_embeddings_seq(llama_seq_id seq_id) {
941    auto it = embd_seq.find(seq_id);
942    if (it == embd_seq.end()) {
943        return nullptr;
944    }
945
946    return it->second.data();
947}
948
949float * llama_context::get_embeddings_nextn() {
950    output_reorder();
951
952    return embd_nextn.data;
953}
954
955float * llama_context::get_embeddings_nextn_ith(int32_t i) {
956    output_reorder();
957
958    try {
959        if (embd_nextn.data == nullptr) {
960            throw std::runtime_error("no nextn embeddings");
961        }
962
963        const uint32_t n_embd = model.hparams.n_embd_out();
964
965        if (!cparams.embeddings_nextn_masked) {
966            // unmasked: nextn rows are stored densely, indexed by raw token position.
967            if (i < 0 || (size_t)(i + 1) * n_embd > embd_nextn.size) {
968                throw std::runtime_error(format("out of range [0, %zu)", embd_nextn.size / n_embd));
969            }
970            return embd_nextn.data + (size_t) i * n_embd;
971        }
972
973        const int64_t j = output_resolve_row(i);
974        return embd_nextn.data + j*n_embd;
975    } catch (const std::exception & err) {
976        LLAMA_LOG_ERROR("%s: invalid nextn embeddings id %d, reason: %s\n", __func__, i, err.what());
977#ifndef NDEBUG
978        GGML_ABORT("fatal error");
979#else
980        return nullptr;
981#endif
982    }
983}
984
985float * llama_context::get_embeddings_layer_inp(uint32_t lid) {
986    output_reorder();
987
988    GGML_ASSERT(lid < embd_layer_inp.size() && embd_layer_inp[lid].has_data());
989
990    return embd_layer_inp[lid].data;
991}
992
993llama_token llama_context::get_sampled_token_ith(int32_t idx) {
994    output_reorder();
995
996    if (!sampling.sampled.has_data()) {
997        return LLAMA_TOKEN_NULL;
998    }
999
1000    try {
1001        const int64_t row = output_resolve_row(idx);
1002        GGML_ASSERT(row < (int64_t) sampling.sampled.size);
1003        return sampling.sampled.data[row];
1004    } catch (const std::exception & err) {
1005        LLAMA_LOG_ERROR("%s: invalid backend sampled token id %d, reason: %s\n", __func__, idx, err.what());
1006        return LLAMA_TOKEN_NULL;
1007    }
1008}
1009
1010float * llama_context::get_sampled_probs_ith(int32_t idx) {
1011    output_reorder();
1012
1013    if (!sampling.probs.has_data()) {
1014        return nullptr;
1015    }
1016
1017    try {
1018        const int64_t row = output_resolve_row(idx);
1019        if ((size_t) row >= sampling.probs_count.size() || sampling.probs_count[row] == 0) {
1020            return nullptr;
1021        }
1022        return sampling.probs.data + row*model.vocab.n_tokens();
1023    } catch (const std::exception & err) {
1024        LLAMA_LOG_ERROR("%s: invalid backend sampled probs id %d, reason: %s\n", __func__, idx, err.what());
1025        return nullptr;
1026    }
1027}
1028
1029float * llama_context::get_sampled_logits_ith(int32_t idx) {
1030    output_reorder();
1031
1032    if (!sampling.logits.has_data()) {
1033        return nullptr;
1034    }
1035
1036    try {
1037        const int64_t row = output_resolve_row(idx);
1038        if ((size_t) row >= sampling.logits_count.size() || sampling.logits_count[row] == 0) {
1039            return nullptr;
1040        }
1041        return sampling.logits.data + row*model.vocab.n_tokens();
1042    } catch (const std::exception & err) {
1043        LLAMA_LOG_ERROR("%s: invalid backend sampled logits id %d, reason: %s\n", __func__, idx, err.what());
1044        return nullptr;
1045    }
1046}
1047
1048const llama_token * llama_context::get_sampled_candidates_ith(int32_t idx) {
1049    output_reorder();
1050
1051    try {
1052        const int64_t row = output_resolve_row(idx);
1053        if (sampling.candidates.has_data() &&
1054            (size_t) row < sampling.candidates_count.size() &&
1055            sampling.candidates_count[row] > 0) {
1056            return sampling.candidates.data + row*model.vocab.n_tokens();
1057        }
1058    } catch (const std::exception & err) {
1059        // fallback to full vocab list
1060        GGML_UNUSED(err);
1061    }
1062
1063    return sampling.token_ids_full_vocab.data();
1064}
1065
1066size_t llama_context::get_sampled_candidates_count(int32_t idx) {
1067    output_reorder();
1068
1069    if (!sampling.candidates.has_data()) {
1070        return 0;
1071    }
1072
1073    try {
1074        const int64_t row = output_resolve_row(idx);
1075        if ((size_t) row >= sampling.candidates_count.size()) {
1076            return 0;
1077        }
1078        return sampling.candidates_count[row];
1079    } catch (const std::exception & err) {
1080        LLAMA_LOG_ERROR("%s: invalid backend sampled candidates count id %d, reason: %s\n", __func__, idx, err.what());
1081        return 0;
1082    }
1083}
1084
1085size_t llama_context::get_sampled_logits_count(int32_t idx) {
1086    output_reorder();
1087
1088    if (!sampling.logits.has_data()) {
1089        return model.vocab.n_tokens();
1090    }
1091
1092    try {
1093        const int64_t row = output_resolve_row(idx);
1094        if ((size_t) row >= sampling.logits_count.size()) {
1095            return 0;
1096        }
1097        return sampling.logits_count[row];
1098    } catch (const std::exception & err) {
1099        LLAMA_LOG_ERROR("%s: invalid backend sampled logits count id %d, reason: %s\n", __func__, idx, err.what());
1100        return 0;
1101    }
1102}
1103
1104size_t llama_context::get_sampled_probs_count(int32_t idx) {
1105    output_reorder();
1106
1107    if (!sampling.probs.has_data()) {
1108        return 0;
1109    }
1110
1111    try {
1112        const int64_t row = output_resolve_row(idx);
1113        if ((size_t) row >= sampling.probs_count.size()) {
1114            return 0;
1115        }
1116        return sampling.probs_count[row];
1117    } catch (const std::exception & err) {
1118        LLAMA_LOG_ERROR("%s: invalid backend sampled probs count id %d, reason: %s\n", __func__, idx, err.what());
1119        return 0;
1120    }
1121}
1122
1123
1124void llama_context::attach_threadpool(
1125           ggml_threadpool_t threadpool,
1126           ggml_threadpool_t threadpool_batch) {
1127    LLAMA_LOG_DEBUG("%s: call\n", __func__);
1128
1129    this->threadpool       = threadpool;
1130    this->threadpool_batch = threadpool_batch ? threadpool_batch : threadpool;
1131}
1132
1133void llama_context::detach_threadpool() {
1134    LLAMA_LOG_DEBUG("%s: call\n", __func__);
1135
1136    this->threadpool       = nullptr;
1137    this->threadpool_batch = nullptr;
1138}
1139
1140void llama_context::set_n_threads(int32_t n_threads, int32_t n_threads_batch) {
1141    LLAMA_LOG_DEBUG("%s: n_threads = %d, n_threads_batch = %d\n", __func__, n_threads, n_threads_batch);
1142
1143    cparams.n_threads       = n_threads;
1144    cparams.n_threads_batch = n_threads_batch;
1145}
1146
1147void llama_context::set_abort_callback(bool (*abort_callback)(void * data), void * abort_callback_data) {
1148    LLAMA_LOG_DEBUG("%s: call\n", __func__);
1149
1150    this->abort_callback      = abort_callback;
1151    this->abort_callback_data = abort_callback_data;
1152
1153    for (auto & backend : backends) {
1154        auto * reg = ggml_backend_dev_backend_reg(ggml_backend_get_device(backend.get()));
1155        if (reg) {
1156            auto * set_abort_callback_fn = (ggml_backend_set_abort_callback_t) ggml_backend_reg_get_proc_address(reg, "ggml_backend_set_abort_callback");
1157            if (set_abort_callback_fn) {
1158                set_abort_callback_fn(backend.get(), this->abort_callback, this->abort_callback_data);
1159            }
1160        }
1161    }
1162}
1163
1164void llama_context::set_embeddings(bool value) {
1165    LLAMA_LOG_DEBUG("%s: value = %d\n", __func__, value);
1166
1167    cparams.embeddings = value;
1168
1169    // TODO: not sure yet if we want to reserve here
1170    //sched_need_reserve = true;
1171}
1172
1173void llama_context::set_embeddings_nextn(bool value, bool masked) {
1174    LLAMA_LOG_DEBUG("%s: value = %d, masked = %d\n", __func__, value, masked);
1175
1176    cparams.embeddings_nextn        = value;
1177    cparams.embeddings_nextn_masked = masked;
1178}
1179
1180void llama_context::set_embeddings_layer_inp(uint32_t lid, bool enable) {
1181    LLAMA_LOG_DEBUG("%s: lid = %d, enable = %d\n", __func__, lid, enable);
1182
1183    GGML_ASSERT(lid <= model.hparams.n_layer());
1184
1185    cparams.embeddings_layer_inp[lid] = enable;
1186
1187    // note: without this reserve, the draft acceptance drops to zero. not sure why - this is unexpected
1188    sched_need_reserve = true;
1189}
1190
1191void llama_context::set_nextn_layer_offset(int32_t offset) {
1192    cparams.nextn_layer_offset = offset;
1193}
1194
1195void llama_context::set_causal_attn(bool value) {
1196    LLAMA_LOG_DEBUG("%s: value = %d\n", __func__, value);
1197
1198    if (cparams.causal_attn == value) {
1199        return;
1200    }
1201
1202    cparams.causal_attn = value;
1203
1204    sched_need_reserve = true;
1205}
1206
1207void llama_context::set_warmup(bool value) {
1208    LLAMA_LOG_DEBUG("%s: value = %d\n", __func__, value);
1209
1210    if (cparams.warmup == value) {
1211        return;
1212    }
1213
1214    cparams.warmup = value;
1215
1216    // warmups are usually with small batches, so no need to reserve
1217    //sched_need_reserve = true;
1218}
1219
1220bool llama_context::set_sampler(llama_seq_id seq_id, llama_sampler * sampler) {
1221    if (!sampler && sampling.samplers.count(seq_id) == 0) {
1222        return true;
1223    }
1224
1225    LLAMA_LOG_DEBUG("%s: seq_id = %d, sampler = %p\n", __func__, (int) seq_id, (void *) sampler);
1226
1227    if (sampler && model.split_mode() == LLAMA_SPLIT_MODE_TENSOR) {
1228        static bool warned = false;
1229        if (!warned) {
1230            LLAMA_LOG_WARN("%s: backend sampling not supported with SPLIT_MODE_TENSOR; using CPU\n", __func__);
1231            warned = true;
1232        }
1233        if (sampling.samplers.count(seq_id) > 0) {
1234            sched_need_reserve = true;
1235        }
1236        sampling.samplers.erase(seq_id);
1237        return false;
1238    }
1239
1240    const bool can_offload =
1241        sampler &&
1242        sampler->iface->backend_init &&
1243        sampler->iface->backend_apply &&
1244        llama_sampler_chain_n(sampler) > 0;
1245
1246    if (sampler && can_offload) {
1247        auto * buft = ggml_backend_dev_buffer_type(model.dev_output());
1248
1249        sampler->iface->backend_init(sampler, buft, cparams.n_outputs_max_per_seq);
1250
1251        sampling.samplers[seq_id] = sampler;
1252
1253        sched_need_reserve = true;
1254
1255        return true;
1256    }
1257
1258    if (sampler && !can_offload) {
1259        LLAMA_LOG_WARN("%s: sampler '%s' for seq_id = %d, cannot be offloaded to the backend\n", __func__, llama_sampler_name(sampler), seq_id);
1260
1261        if (sampling.samplers.count(seq_id) > 0) {
1262            sched_need_reserve = true;
1263        }
1264
1265        sampling.samplers.erase(seq_id);
1266
1267        return false;
1268    }
1269
1270    sampling.samplers.erase(seq_id);
1271
1272    sched_need_reserve = true;
1273
1274    return true;
1275}
1276
1277void llama_context::set_adapters_lora(llama_adapter_lora ** adapters, size_t n_adapters, float * scales) {
1278    LLAMA_LOG_DEBUG("%s: adapters = %p\n", __func__, (void *) adapters);
1279
1280    if (adapters_lora_are_same(adapters, n_adapters, scales)) {
1281        return;
1282    }
1283
1284    loras.reset(new llama_adapter_loras());
1285
1286    for (size_t i = 0; i < n_adapters; i ++) {
1287        if (scales[i] != 0.0f) {
1288            loras->insert({adapters[i], scales[i]});
1289        }
1290    }
1291
1292    sched_need_reserve = true;
1293}
1294
1295bool llama_context::adapters_lora_are_same(llama_adapter_lora ** adapters, size_t n_adapters, float * scales) {
1296    LLAMA_LOG_DEBUG("%s: adapters = %p\n", __func__, (void *) adapters);
1297
1298    // Adapters with a zero scale are never added to `loras`, so also ignore them for the comparison.
1299    size_t n_non_zero = 0;
1300
1301    for (size_t i = 0; i < n_adapters; i ++) {
1302        if (scales[i] == 0.0f) {
1303            continue;
1304        }
1305        n_non_zero++;
1306
1307        auto it = loras->find(adapters[i]);
1308
1309        if (it == loras->end() || it->second != scales[i]) {
1310            return false;
1311        }
1312    }
1313
1314    if (n_non_zero != loras->size()) {
1315        return false;
1316    }
1317
1318    return true;
1319}
1320
1321bool llama_context::set_adapter_cvec(
1322            const float * data,
1323                 size_t   len,
1324                int32_t   n_embd,
1325                int32_t   il_start,
1326                int32_t   il_end) {
1327    LLAMA_LOG_DEBUG("%s: il_start = %d, il_end = %d\n", __func__, il_start, il_end);
1328
1329    bool res = cvec->apply(model, data, len, n_embd, il_start, il_end);
1330
1331    sched_need_reserve = true;
1332
1333    return res;
1334}
1335
1336llm_graph_result * llama_context::process_ubatch(const llama_ubatch & ubatch, llm_graph_type gtype, llama_memory_context_i * mctx, ggml_status & ret) {
1337    if (mctx && !mctx->apply()) {
1338        LLAMA_LOG_ERROR("%s: failed to apply memory context\n", __func__);
1339        ret = GGML_STATUS_FAILED;
1340        return nullptr;
1341    }
1342
1343    auto * res = gf_res_prev.get();
1344    auto * gf  = res->get_gf();
1345
1346    // the new graph parameters
1347    // in order to correctly reuse a graph, it's full topology has to be uniquely determined by these parameters
1348    const auto gparams = graph_params(res, ubatch, mctx, gtype);
1349
1350    if (!graph_reuse_disable && res->can_reuse(gparams)) {
1351        //LLAMA_LOG_DEBUG("%s: reusing previous graph\n", __func__);
1352
1353        // with pipeline parallelism, the previous graph_compute_async may still be running
1354        // on the GPU. we must synchronize before set_inputs to avoid overwriting input tensors
1355        // that the previous compute is still reading.
1356        if (cparams.pipeline_parallel) {
1357            ggml_backend_sched_synchronize(sched.get());
1358        }
1359
1360        n_reused++;
1361    } else {
1362        res->reset();
1363
1364        ggml_backend_sched_reset(sched.get());
1365        ggml_backend_sched_set_eval_callback(sched.get(), cparams.cb_eval, cparams.cb_eval_user_data);
1366
1367        //const auto t_start_us = ggml_time_us();
1368
1369        gf = model.build_graph(gparams);
1370
1371        //LLAMA_LOG_INFO("graph build time: %.3f ms\n", (ggml_time_us() - t_start_us)/1000.0);
1372
1373        if (!gf) {
1374            LLAMA_LOG_ERROR("%s: failed to initialize graph\n", __func__);
1375            ret = GGML_STATUS_FAILED;
1376            return nullptr;
1377        }
1378
1379        if (!ggml_backend_sched_alloc_graph(sched.get(), gf)) {
1380            LLAMA_LOG_ERROR("%s: failed to allocate graph\n", __func__);
1381            ret = GGML_STATUS_ALLOC_FAILED;
1382            return nullptr;
1383        }
1384    }
1385
1386    // set the input data for the input tensors
1387    {
1388        //const auto t_start_us = ggml_time_us();
1389
1390        // FIXME this call causes a crash if any model inputs were not used in the graph and were therefore not allocated
1391        res->set_inputs(&ubatch);
1392
1393        //LLAMA_LOG_INFO("graph set inputs time: %.3f ms\n", (ggml_time_us() - t_start_us)/1000.0);
1394    }
1395
1396    const auto status = graph_compute(res->get_gf(), ubatch.n_tokens > 1);
1397    if (status != GGML_STATUS_SUCCESS) {
1398        LLAMA_LOG_ERROR("%s: failed to compute graph, compute status: %d\n", __func__, status);
1399        ret = status;
1400        return nullptr;
1401    }
1402
1403    ret = GGML_STATUS_SUCCESS;
1404
1405    return res;
1406}
1407
1408int llama_context::encode(const llama_batch & batch_inp) {
1409    // MTP hook batches carry both token (next-token id) and embd (h_nextn row),
1410    // so accept either present rather than requiring exactly one.
1411    GGML_ASSERT(batch_inp.token || batch_inp.embd);
1412
1413    if (batch_inp.n_tokens == 0) {
1414        LLAMA_LOG_ERROR("%s: n_tokens == 0\n", __func__);
1415        return -1;
1416    }
1417
1418    const auto & hparams = model.hparams;
1419
1420    // eagle3/DFlash: features as encoder input, and non-draft paths fall back to model's input dim
1421    const int64_t n_embd = hparams.n_embd_inp_enc();
1422    const int64_t n_vocab = model.vocab.n_tokens();
1423
1424    // note: during encode, we always pass the full sequence starting from pos = 0
1425    if (!balloc->init(batch_inp, model.vocab, nullptr, n_embd, cparams.kv_unified ? LLAMA_MAX_SEQ : cparams.n_seq_max, true)) {
1426        LLAMA_LOG_ERROR("%s: failed to initialize batch\n", __func__);
1427        return -1;
1428    }
1429
1430    const uint32_t n_tokens = balloc->get_n_tokens();
1431
1432    // [TAG_NO_CACHE_PAD]
1433    // TODO: add new split mode where we pad the input sequences so that ubatch.equal_seqs == true
1434    const llama_ubatch ubatch = balloc->split_simple(n_tokens);
1435
1436    // micro-batching is not possible for non-causal encoding, so we process the batch in a single shot
1437    GGML_ASSERT(cparams.n_ubatch >= n_tokens && "encoder requires n_ubatch >= n_tokens");
1438
1439    // TODO: this clear of the buffer can easily be forgotten - need something better
1440    // sync first so any in-flight async copies into embd_seq complete before it is freed
1441    if (!embd_seq.empty()) {
1442        synchronize();
1443    }
1444    embd_seq.clear();
1445
1446    if (t_compute_start_us == 0) {
1447        t_compute_start_us = ggml_time_us();
1448    }
1449
1450    sched_reserve();
1451
1452    n_queued_tokens += n_tokens;
1453
1454    // reserve output buffer
1455    if (output_reserve(n_tokens) < n_tokens) {
1456        LLAMA_LOG_ERROR("%s: could not reserve space for batch with %u outputs\n", __func__, n_tokens);
1457        return -2;
1458    };
1459
1460    for (uint32_t i = 0; i < n_tokens; ++i) {
1461        output_ids[i] = i;
1462    }
1463
1464    n_outputs = n_tokens;
1465
1466    const auto causal_attn_org = cparams.causal_attn;
1467
1468    // always use non-causal attention for encoder graphs
1469    // TODO: this is a tmp solution until we have a proper way to support enc-dec models
1470    //       ref: https://github.com/ggml-org/llama.cpp/pull/12181#issuecomment-2730451223
1471    cparams.causal_attn = false;
1472
1473    ggml_status status;
1474    const auto * res = process_ubatch(ubatch, LLM_GRAPH_TYPE_ENCODER, nullptr, status);
1475
1476    cparams.causal_attn = causal_attn_org;
1477
1478    if (!res) {
1479        switch (status) {
1480            case GGML_STATUS_ABORTED:      return  2;
1481            case GGML_STATUS_ALLOC_FAILED: return -2;
1482            case GGML_STATUS_FAILED:       return -3;
1483            case GGML_STATUS_SUCCESS:      GGML_ABORT("should not happen");
1484        }
1485    }
1486
1487    auto * t_logits  = res->get_logits();
1488    auto * t_embd    = res->get_embd_pooled() ? res->get_embd_pooled() : res->get_embd();
1489    auto * t_h_nextn = cparams.embeddings_nextn ? res->get_h_nextn() : nullptr;
1490
1491    // extract logits
1492    if (logits.data && t_logits) {
1493        ggml_backend_t backend_res = ggml_backend_sched_get_tensor_backend(sched.get(), t_logits);
1494        GGML_ASSERT(backend_res != nullptr);
1495        GGML_ASSERT(logits.data != nullptr);
1496
1497        ggml_backend_tensor_get_async(backend_res, t_logits, logits.data, 0, n_tokens*n_vocab*sizeof(float));
1498    }
1499
1500    // extract embeddings
1501    if (embd.data && t_embd) {
1502        ggml_backend_t backend_embd = ggml_backend_sched_get_tensor_backend(sched.get(), t_embd);
1503        GGML_ASSERT(backend_embd != nullptr);
1504
1505        switch (cparams.pooling_type) {
1506            case LLAMA_POOLING_TYPE_NONE:
1507                {
1508                    // extract token embeddings
1509                    GGML_ASSERT(embd.data != nullptr);
1510                    const uint32_t n_embd_out = hparams.n_embd_out();
1511
1512                    GGML_ASSERT(n_tokens*n_embd_out <= (int64_t) embd.size);
1513                    ggml_backend_tensor_get_async(backend_embd, t_embd, embd.data, 0, n_tokens*n_embd_out*sizeof(float));
1514                } break;
1515            case LLAMA_POOLING_TYPE_MEAN:
1516            case LLAMA_POOLING_TYPE_CLS:
1517            case LLAMA_POOLING_TYPE_LAST:
1518                {
1519                    // extract sequence embeddings
1520                    auto & embd_seq_out = embd_seq;
1521
1522                    for (uint32_t s = 0; s < ubatch.n_seqs_unq; ++s) {
1523                        const llama_seq_id seq_id  = ubatch.seq_id_unq[s];
1524                        const int32_t      seq_idx = ubatch.seq_idx[seq_id];
1525
1526                        // use n_embd_out (not n_embd_inp) - the pooled embedding has the model's
1527                        // output dimension, which differs from input dimension for deepstack models (e.g. qwen3vl)
1528                        const uint32_t n_embd_out = hparams.n_embd_out();
1529                        embd_seq_out[seq_id].resize(n_embd_out);
1530                        ggml_backend_tensor_get_async(backend_embd, t_embd, embd_seq_out[seq_id].data(), (n_embd_out*seq_idx)*sizeof(float), n_embd_out*sizeof(float));
1531                    }
1532                } break;
1533            case LLAMA_POOLING_TYPE_RANK:
1534                {
1535                    // extract the rerank score - n_cls_out floats per sequence
1536                    auto & embd_seq_out = embd_seq;
1537
1538                    const uint32_t n_cls_out = hparams.n_cls_out;
1539
1540                    for (uint32_t s = 0; s < ubatch.n_seqs_unq; ++s) {
1541                        const llama_seq_id seq_id  = ubatch.seq_id_unq[s];
1542                        const int32_t      seq_idx = ubatch.seq_idx[seq_id];
1543
1544                        embd_seq_out[seq_id].resize(n_cls_out);
1545                        ggml_backend_tensor_get_async(backend_embd, t_embd, embd_seq_out[seq_id].data(), (n_cls_out*seq_idx)*sizeof(float), n_cls_out*sizeof(float));
1546                    }
1547                } break;
1548            case LLAMA_POOLING_TYPE_UNSPECIFIED:
1549                {
1550                    GGML_ABORT("unknown pooling type");
1551                }
1552        }
1553    }
1554
1555    // extract nextn embeddings (hidden state before the final output norm)
1556    if (embd_nextn.data && t_h_nextn && cparams.pooling_type == LLAMA_POOLING_TYPE_NONE) {
1557        ggml_backend_t backend_h = ggml_backend_sched_get_tensor_backend(sched.get(), t_h_nextn);
1558        GGML_ASSERT(backend_h != nullptr);
1559
1560        const uint32_t n_embd = hparams.n_embd_out();
1561        GGML_ASSERT(n_tokens*n_embd <= (int64_t) embd_nextn.size);
1562        ggml_backend_tensor_get_async(backend_h, t_h_nextn, embd_nextn.data, 0, n_tokens*n_embd*sizeof(float));
1563    }
1564
1565    // TODO: hacky solution
1566    if ((model.arch == LLM_ARCH_T5 || model.arch == LLM_ARCH_ALICEAI_T5_MOE) && t_embd) {
1567        //cross.t_embd = t_embd;
1568
1569        synchronize();
1570
1571        cross.n_embd = t_embd->ne[0];
1572        cross.n_enc  = t_embd->ne[1];
1573        cross.v_embd.resize(cross.n_embd*cross.n_enc);
1574        memcpy(cross.v_embd.data(), embd.data, ggml_nbytes(t_embd));
1575
1576        const auto & batch = balloc->get_batch();
1577
1578        // remember the sequence ids used during the encoding - needed for cross attention later
1579        cross.seq_ids_enc.resize(n_tokens);
1580        for (uint32_t i = 0; i < n_tokens; i++) {
1581            cross.seq_ids_enc[i].clear();
1582
1583            for (int s = 0; s < batch.n_seq_id[i]; s++) {
1584                const llama_seq_id seq_id = batch.seq_id[i][s];
1585
1586                cross.seq_ids_enc[i].insert(seq_id);
1587            }
1588        }
1589    }
1590
1591    return 0;
1592}
1593
1594template<typename T>
1595static void copy_tensor_async_rows(
1596    const std::vector<ggml_tensor *> & tensors,
1597    const buffer_view<T> & dst,
1598    size_t stride,
1599    uint32_t row_offset,
1600    ggml_backend_sched_t sched,
1601    std::vector<uint32_t> * counts = nullptr) {
1602    if (!dst.has_data()) {
1603        return;
1604    }
1605
1606    for (size_t i = 0; i < tensors.size(); ++i) {
1607        auto * tensor = tensors[i];
1608        if (tensor == nullptr) {
1609            continue;
1610        }
1611
1612        const uint32_t row = row_offset + i;
1613        const size_t n_elements = ggml_nelements(tensor);
1614        GGML_ASSERT(ggml_is_contiguous(tensor) && "sampling tensor must be contiguous for async copy");
1615        GGML_ASSERT(n_elements <= stride);
1616        GGML_ASSERT((size_t) row * stride + n_elements <= dst.size);
1617
1618        ggml_backend_t backend = ggml_backend_sched_get_tensor_backend(sched, tensor);
1619        T * row_ptr = dst.data + (size_t) row * stride;
1620        ggml_backend_tensor_get_async(backend, tensor, row_ptr, 0, ggml_nbytes(tensor));
1621
1622        if (counts) {
1623            GGML_ASSERT(row < counts->size());
1624            (*counts)[row] = n_elements;
1625        }
1626    }
1627}
1628
1629static bool needs_raw_logits(const llama_ubatch & ubatch, const std::map<llama_seq_id, llama_sampler *> & samplers) {
1630    for (uint32_t i = 0; i < ubatch.n_tokens; i++) {
1631        if (!ubatch.output[i]) {
1632            continue;
1633        }
1634
1635        // Check if the output token has at least one sequence without a backend sampler.
1636        for (int32_t j = 0; j < ubatch.n_seq_id[i]; ++j) {
1637            llama_seq_id seq_id = ubatch.seq_id[i][j];
1638            if (samplers.find(seq_id) == samplers.end()) {
1639                return true;
1640            }
1641        }
1642    }
1643    return false; // all sequences use backend sampling
1644}
1645
1646int llama_context::decode(const llama_batch & batch_inp) {
1647    // MTP hook batches carry both token (next-token id) and embd (h_nextn row),
1648    // so accept either present rather than requiring exactly one.
1649    GGML_ASSERT(batch_inp.token || batch_inp.embd);
1650
1651    if (!memory) {
1652        LLAMA_LOG_DEBUG("%s: cannot decode batches with this context (calling encode() instead)\n", __func__);
1653        return encode(batch_inp);
1654    }
1655
1656    if (batch_inp.n_tokens == 0) {
1657        LLAMA_LOG_ERROR("%s: n_tokens == 0\n", __func__);
1658        return -1;
1659    }
1660
1661    const auto & vocab   = model.vocab;
1662    const auto & hparams = model.hparams;
1663
1664    const int64_t n_vocab = vocab.n_tokens();
1665    const bool    mtp_embd = cparams.ctx_type == LLAMA_CONTEXT_TYPE_MTP && batch_inp.embd;
1666    // DFlash embd batches carry the fused target features at the encoder input width
1667    const bool    dflash_embd = model.arch == LLM_ARCH_DFLASH && batch_inp.embd;
1668    const int64_t n_embd  = mtp_embd ? hparams.n_embd_out() : dflash_embd ? hparams.n_embd_inp_enc() : hparams.n_embd_inp();
1669
1670    // when computing embeddings, all tokens are output
1671    const bool output_all   = cparams.embeddings;
1672    const bool has_samplers = !sampling.samplers.empty();
1673
1674    const uint32_t n_seq_max = cparams.kv_unified ? LLAMA_MAX_SEQ : cparams.n_seq_max;
1675
1676    // embedding contexts output every token even when batch.logits is not set
1677    if (has_samplers && (output_all || batch_inp.logits)) {
1678        std::vector<int32_t> seq_output_count(n_seq_max, 0);
1679
1680        for (int32_t i = 0; i < batch_inp.n_tokens; ++i) {
1681            if (!output_all && batch_inp.logits[i] == 0) {
1682                continue;
1683            }
1684
1685            const int ns = batch_inp.n_seq_id ? batch_inp.n_seq_id[i] : 1;
1686
1687            for (int32_t s = 0; s < ns; ++s) {
1688                const llama_seq_id seq_id = batch_inp.seq_id ? batch_inp.seq_id[i][s] : 0;
1689
1690                if (seq_id < 0 || (uint32_t) seq_id >= n_seq_max) {
1691                    continue;
1692                }
1693
1694                seq_output_count[seq_id]++;
1695                auto sampler = sampling.samplers.find(seq_id);
1696                if (sampler != sampling.samplers.end() &&
1697                        seq_output_count[seq_id] > (int32_t) cparams.n_outputs_max_per_seq) {
1698                    LLAMA_LOG_ERROR("%s: backend sampling supports at most %u outputs per sequence "
1699                            "(seq_id %d had %d)\n", __func__, cparams.n_outputs_max_per_seq,
1700                            seq_id, seq_output_count[seq_id]);
1701                    return -1;
1702                }
1703            }
1704        }
1705    }
1706
1707    if (!balloc->init(batch_inp, vocab, memory.get(), n_embd, n_seq_max, output_all)) {
1708        LLAMA_LOG_ERROR("%s: failed to initialize batch\n", __func__);
1709        return -1;
1710    }
1711
1712    const uint32_t n_tokens_all  = balloc->get_n_tokens();
1713    const uint32_t n_outputs_all = balloc->get_n_outputs();
1714
1715    if (output_all) {
1716        // require that all tokens are output
1717        if (n_outputs_all != n_tokens_all) {
1718            LLAMA_LOG_ERROR("%s: pooled embedding requires that all tokens are output (n_outputs_all = %d, n_tokens_all = %d)\n",
1719                    __func__, n_outputs_all, n_tokens_all);
1720            return -1;
1721        }
1722    }
1723
1724    GGML_ASSERT(n_tokens_all <= cparams.n_batch);
1725
1726    GGML_ASSERT((cparams.causal_attn || cparams.n_ubatch >= n_tokens_all) && "non-causal attention requires n_ubatch >= n_tokens");
1727
1728    // TODO: this clear of the buffer can easily be forgotten - need something better
1729    // sync first so any in-flight async copies into embd_seq complete before it is freed
1730    if (!embd_seq.empty()) {
1731        synchronize();
1732    }
1733    embd_seq.clear();
1734
1735    if (t_compute_start_us == 0) {
1736        t_compute_start_us = ggml_time_us();
1737    }
1738    n_queued_tokens += n_tokens_all;
1739
1740    output_swaps.clear();
1741
1742    sched_reserve();
1743
1744    bool did_optimize = false;
1745
1746    // handle any pending shifts/copies
1747    memory_update(false);
1748
1749    llama_memory_context_ptr mctx;
1750
1751    while (true) {
1752        mctx = memory->init_batch(*balloc, cparams.n_ubatch, output_all);
1753        if (!mctx) {
1754            return -2;
1755        }
1756
1757        switch (mctx->get_status()) {
1758            case LLAMA_MEMORY_STATUS_SUCCESS:
1759                {
1760                } break;
1761            case LLAMA_MEMORY_STATUS_NO_UPDATE:
1762                {
1763                    LLAMA_LOG_ERROR("%s: unexpected memory context status: %d\n", __func__, mctx->get_status());
1764
1765                    return -2;
1766                }
1767            case LLAMA_MEMORY_STATUS_FAILED_PREPARE:
1768                {
1769                    if (!did_optimize) {
1770                        did_optimize = true;
1771
1772                        if (memory_update(true)) {
1773                            LLAMA_LOG_DEBUG("%s: retrying batch size %d after cache optimization\n", __func__, balloc->get_n_tokens());
1774
1775                            continue;
1776                        }
1777                    }
1778
1779                    LLAMA_LOG_WARN("%s: failed to find a memory slot for batch of size %d\n", __func__, balloc->get_n_tokens());
1780
1781                    return 1;
1782                }
1783            case LLAMA_MEMORY_STATUS_FAILED_COMPUTE:
1784                {
1785                    LLAMA_LOG_ERROR("%s: compute failed while preparing batch of size %d\n", __func__, balloc->get_n_tokens());
1786
1787                    return -2;
1788                }
1789        }
1790
1791        break;
1792    }
1793
1794    // reserve output buffer
1795    if (output_reserve(n_outputs_all) < n_outputs_all) {
1796        LLAMA_LOG_ERROR("%s: could not reserve space for batch with %d outputs\n", __func__, n_outputs_all);
1797        return -2;
1798    };
1799
1800    // start a new sampling transaction for this logical batch
1801    for (const auto & entry : sampling.samplers) {
1802        llama_sampler_backend_begin(entry.second);
1803    }
1804
1805    int64_t n_outputs_prev = 0;
1806    int64_t n_tokens_prev  = 0;
1807
1808    do {
1809        const auto & ubatch = mctx->get_ubatch();
1810
1811        // count the outputs in this ubatch
1812        {
1813            int32_t n_outputs_new = 0;
1814
1815            if (n_outputs_all == n_tokens_all) {
1816                n_outputs_new = ubatch.n_tokens;
1817            } else {
1818                for (uint32_t i = 0; i < ubatch.n_tokens; i++) {
1819                    n_outputs_new += (int32_t) (ubatch.output[i] != 0);
1820                }
1821            }
1822
1823            // needs to happen before the graph is built
1824            n_outputs = n_outputs_new;
1825        }
1826
1827        ggml_status status;
1828
1829        const auto * res = process_ubatch(ubatch, ctx_type_to_graph_type(cparams.ctx_type), mctx.get(), status);
1830
1831        if (!res) {
1832            // the last ubatch failed or was aborted -> remove all positions of that ubatch from the memory module
1833            llama_pos pos_min[LLAMA_MAX_SEQ];
1834            for (int s = 0; s < LLAMA_MAX_SEQ; ++s) {
1835                pos_min[s] = std::numeric_limits<llama_pos>::max();
1836            }
1837
1838            for (uint32_t i = 0; i < ubatch.n_tokens; ++i) {
1839                const auto & seq_id = ubatch.seq_id[i][0];
1840
1841                pos_min[seq_id] = std::min(pos_min[seq_id], ubatch.pos[i]);
1842            }
1843
1844            for (int s = 0; s < LLAMA_MAX_SEQ; ++s) {
1845                if (pos_min[s] == std::numeric_limits<llama_pos>::max()) {
1846                    continue;
1847                }
1848
1849                LLAMA_LOG_WARN("%s: removing memory module entries for seq_id = %d, pos = [%d, +inf)\n", __func__, s, pos_min[s]);
1850
1851                memory->seq_rm(s, pos_min[s], -1);
1852            }
1853
1854            switch (status) {
1855                case GGML_STATUS_ABORTED:      return  2;
1856                case GGML_STATUS_ALLOC_FAILED: return -2;
1857                case GGML_STATUS_FAILED:       return -3;
1858                case GGML_STATUS_SUCCESS:      GGML_ABORT("should not happen");
1859            }
1860        }
1861
1862        // plot the computation graph in dot format (for debugging purposes)
1863        //if (n_past%100 == 0) {
1864        //    ggml_graph_dump_dot(gf, NULL, "llama.dot");
1865        //}
1866
1867        auto * t_logits  = res->get_logits();
1868        auto * t_embd    = cparams.embeddings       ? res->get_embd()     : nullptr;
1869        auto * t_h_nextn = cparams.embeddings_nextn ? res->get_h_nextn()  : nullptr;
1870
1871        if (t_embd && res->get_embd_pooled()) {
1872            t_embd = res->get_embd_pooled();
1873        }
1874
1875        // extract logits
1876        if (logits.data && t_logits && n_outputs > 0 && needs_raw_logits(ubatch, sampling.samplers)) {
1877            ggml_backend_t backend_res = ggml_backend_sched_get_tensor_backend(sched.get(), t_logits);
1878            GGML_ASSERT(backend_res != nullptr);
1879            GGML_ASSERT(logits.data != nullptr);
1880
1881            float * logits_out = logits.data + n_outputs_prev*n_vocab;
1882
1883            if (n_outputs) {
1884                GGML_ASSERT( n_outputs_prev + n_outputs <= n_outputs_all);
1885                GGML_ASSERT((n_outputs_prev + n_outputs)*n_vocab <= (int64_t) logits.size);
1886                ggml_backend_tensor_get_async(backend_res, t_logits, logits_out, 0, n_outputs*n_vocab*sizeof(float));
1887            }
1888        }
1889
1890        // extract embeddings
1891        if (embd.data && t_embd && n_outputs > 0) {
1892            ggml_backend_t backend_embd = ggml_backend_sched_get_tensor_backend(sched.get(), t_embd);
1893            GGML_ASSERT(backend_embd != nullptr);
1894
1895            switch (cparams.pooling_type) {
1896                case LLAMA_POOLING_TYPE_NONE:
1897                    {
1898                        // extract token embeddings
1899                        GGML_ASSERT(embd.data != nullptr);
1900                        const uint32_t n_embd_out = hparams.n_embd_out();
1901                        float * embd_out = embd.data + n_outputs_prev*n_embd_out;
1902
1903                        if (n_outputs) {
1904                            GGML_ASSERT( n_outputs_prev + n_outputs <= n_outputs_all);
1905                            GGML_ASSERT((n_outputs_prev + n_outputs)*n_embd_out <= (int64_t) embd.size);
1906                            ggml_backend_tensor_get_async(backend_embd, t_embd, embd_out, 0, n_outputs*n_embd_out*sizeof(float));
1907                        }
1908                    } break;
1909                case LLAMA_POOLING_TYPE_MEAN:
1910                case LLAMA_POOLING_TYPE_CLS:
1911                case LLAMA_POOLING_TYPE_LAST:
1912                    {
1913                        // extract sequence embeddings (cleared before processing each batch)
1914                        auto & embd_seq_out = embd_seq;
1915
1916                        // use n_embd_out (not n_embd_inp) - the pooled embedding has the model's
1917                        // output dimension, which differs from input dimension for deepstack models (e.g. qwen3vl)
1918                        const uint32_t n_embd_out = hparams.n_embd_out();
1919
1920                        for (uint32_t s = 0; s < ubatch.n_seqs_unq; ++s) {
1921                            const llama_seq_id seq_id  = ubatch.seq_id_unq[s];
1922                            const int32_t      seq_idx = ubatch.seq_idx[seq_id];
1923
1924                            embd_seq_out[seq_id].resize(n_embd_out);
1925                            ggml_backend_tensor_get_async(backend_embd, t_embd, embd_seq_out[seq_id].data(), (n_embd_out*seq_idx)*sizeof(float), n_embd_out*sizeof(float));
1926                        }
1927                    } break;
1928                case LLAMA_POOLING_TYPE_RANK:
1929                    {
1930                        // extract the rerank score - n_cls_out floats per sequence
1931                        auto & embd_seq_out = embd_seq;
1932
1933                        const uint32_t n_cls_out = hparams.n_cls_out;
1934
1935                        for (uint32_t s = 0; s < ubatch.n_seqs_unq; ++s) {
1936                            const llama_seq_id seq_id  = ubatch.seq_id_unq[s];
1937                            const int32_t      seq_idx = ubatch.seq_idx[seq_id];
1938
1939                            embd_seq_out[seq_id].resize(n_cls_out);
1940                            ggml_backend_tensor_get_async(backend_embd, t_embd, embd_seq_out[seq_id].data(), (n_cls_out*seq_idx)*sizeof(float), n_cls_out*sizeof(float));
1941                        }
1942                    } break;
1943                case LLAMA_POOLING_TYPE_UNSPECIFIED:
1944                    {
1945                        GGML_ABORT("unknown pooling type");
1946                    }
1947            }
1948        }
1949
1950        extract_layer_inputs(res, n_tokens_prev, ubatch.n_tokens);
1951
1952        // extract nextn embeddings before
1953        // only meaningful in LLAMA_POOLING_TYPE_NONE (per-token); other pooling modes are ignored.
1954        {
1955            const bool masked    = cparams.embeddings_nextn_masked;
1956            const int64_t n_rows = masked ? n_outputs       : (int64_t) ubatch.n_tokens;
1957            const int64_t offset = masked ? n_outputs_prev  : n_tokens_prev;
1958
1959            if (embd_nextn.data && t_h_nextn && n_rows > 0 && cparams.pooling_type == LLAMA_POOLING_TYPE_NONE) {
1960                ggml_backend_t backend_h = ggml_backend_sched_get_tensor_backend(sched.get(), t_h_nextn);
1961                GGML_ASSERT(backend_h != nullptr);
1962
1963                const uint32_t n_embd  = hparams.n_embd_out();
1964                float * embd_nextn_out = embd_nextn.data + offset*n_embd;
1965
1966                GGML_ASSERT((offset + n_rows)*n_embd <= (int64_t) embd_nextn.size);
1967                ggml_backend_tensor_get_async(backend_h, t_h_nextn, embd_nextn_out, 0, n_rows*n_embd*sizeof(float));
1968            }
1969        }
1970
1971        if (has_samplers) {
1972            const auto stride = n_vocab;
1973
1974            // async copy the sampling data from the backend to the host
1975            copy_tensor_async_rows(res->t_sampled,        sampling.sampled,    1,      n_outputs_prev, sched.get());
1976            copy_tensor_async_rows(res->t_sampled_logits, sampling.logits,     stride, n_outputs_prev, sched.get(), &sampling.logits_count);
1977            copy_tensor_async_rows(res->t_sampled_probs,  sampling.probs,      stride, n_outputs_prev, sched.get(), &sampling.probs_count);
1978            copy_tensor_async_rows(res->t_candidates,     sampling.candidates, stride, n_outputs_prev, sched.get(), &sampling.candidates_count);
1979        }
1980
1981        n_outputs_prev += n_outputs;
1982        n_tokens_prev  += ubatch.n_tokens;
1983    } while (mctx->next());
1984
1985    // set to total number of outputs in the batch, for use in llama_get_logits_ith
1986    n_outputs = n_outputs_all;
1987
1988    // set output mappings
1989    if (n_outputs > 0) {
1990        bool sorted_output = true;
1991
1992        auto & out_ids = balloc->get_out_ids();
1993
1994        GGML_ASSERT(out_ids.size() == (size_t) n_outputs);
1995
1996        for (int64_t i = 0; i < n_outputs; ++i) {
1997            int64_t out_id = out_ids[i];
1998            output_ids[out_id] = i;
1999            if (out_id != i) {
2000                sorted_output = false;
2001            }
2002        }
2003
2004        // make the outputs have the same order they had in the user-provided batch
2005        // note: this is mostly relevant for recurrent models atm
2006        if (!sorted_output && n_outputs > 1) {
2007            GGML_ASSERT((size_t) n_outputs == out_ids.size());
2008
2009            // TODO: is there something more efficient which also minimizes swaps?
2010            // selection sort, to minimize swaps (from https://en.wikipedia.org/wiki/Selection_sort)
2011            for (uint32_t i = 0; i < n_outputs - 1; ++i) {
2012                uint32_t j_min = i;
2013                for (uint32_t j = i + 1; j < n_outputs; ++j) {
2014                    if (out_ids[j] < out_ids[j_min]) {
2015                        j_min = j;
2016                    }
2017                }
2018                if (j_min == i) {
2019                    continue;
2020                }
2021                std::swap(out_ids[i], out_ids[j_min]);
2022
2023                // remember the swaps and apply them lazily upon logits/embeddings access
2024                output_swaps.push_back({ i, j_min });
2025            }
2026
2027            std::fill(output_ids.begin(), output_ids.end(), -1);
2028
2029            for (uint32_t i = 0; i < n_outputs; ++i) {
2030                output_ids[out_ids[i]] = i;
2031            }
2032        }
2033    }
2034
2035    // wait for the computation to finish (automatically done when obtaining the model output)
2036    //synchronize();
2037
2038    return 0;
2039}
2040
2041//
2042// output
2043//
2044
2045uint32_t llama_context::output_reserve(int32_t n_outputs) {
2046    const auto & hparams = model.hparams;
2047    const auto & vocab   = model.vocab;
2048
2049    const int64_t n_outputs_max = std::max<int64_t>(n_outputs, n_seq_max());
2050
2051    const auto n_batch    = cparams.n_batch;
2052    const auto n_vocab    = vocab.n_tokens();
2053    const auto n_embd     = hparams.n_embd;
2054    const auto n_embd_out = hparams.n_embd_out();
2055
2056    bool has_logits     = true;
2057    bool has_embd       = cparams.embeddings;
2058    bool has_embd_nextn = cparams.embeddings_nextn;
2059
2060    // TODO: hacky enc-dec support
2061    if (model.arch == LLM_ARCH_T5 || model.arch == LLM_ARCH_ALICEAI_T5_MOE) {
2062        has_logits = true;
2063        has_embd   = true;
2064    }
2065
2066    size_t backend_float_count = 0;
2067    size_t backend_token_count = 0;
2068    size_t embd_layer_inp_float_count = 0;
2069
2070    logits.size     = has_logits     ? n_vocab*n_outputs_max     : 0;
2071    embd.size       = has_embd       ? n_embd_out*n_outputs_max  : 0;
2072    embd_nextn.size = has_embd_nextn ? n_embd_out*n_outputs_max  : 0;
2073
2074    if (has_embd_nextn && !cparams.embeddings_nextn_masked) {
2075        // unmasked: nextn row exists for every token in the batch, not just
2076        // those flagged via batch.logits[i] -> size by token count instead.
2077        embd_nextn.size = (size_t) n_embd_out * n_batch;
2078    }
2079
2080    for (bool enabled : cparams.embeddings_layer_inp) {
2081        if (enabled) {
2082            embd_layer_inp_float_count += (size_t) n_embd * n_batch;
2083        }
2084    }
2085
2086    // Allocate backend sampling output buffers if there are backend samplers configured.
2087    const bool has_sampling = !sampling.samplers.empty();
2088    if (has_sampling) {
2089        backend_float_count = 2 * n_vocab * n_outputs_max;      // logits + probs
2090        backend_token_count = (1 + n_vocab) * n_outputs_max;    // sampled + candidates
2091    }
2092
2093    if (output_ids.empty()) {
2094        // init, never resized afterwards
2095        output_ids.resize(n_batch);
2096    }
2097
2098    const size_t prev_size = buf_output ? ggml_backend_buffer_get_size(buf_output.get()) : 0;
2099    const size_t new_size  =
2100        (logits.size + embd.size + embd_nextn.size + embd_layer_inp_float_count + backend_float_count) * sizeof(float) +
2101        (                                                                         backend_token_count) * sizeof(llama_token);
2102
2103    // alloc only when more than the current capacity is required
2104    // TODO: also consider shrinking the buffer
2105    if (!buf_output || prev_size < new_size) {
2106        if (buf_output) {
2107#ifndef NDEBUG
2108            // This doesn't happen often, but may be annoying in some cases (like the HellaSwag benchmark)
2109            LLAMA_LOG_DEBUG("%s: reallocating output buffer from size %.02f MiB to %.02f MiB\n", __func__, prev_size / 1024.0 / 1024.0, new_size / 1024.0 / 1024.0);
2110#endif
2111            synchronize();
2112
2113            // TODO: not needed?
2114            buf_output = nullptr;
2115            logits.data = nullptr;
2116            embd.data = nullptr;
2117            embd_nextn.data = nullptr;
2118            for (auto & layer_inp : embd_layer_inp) {
2119                layer_inp = {nullptr, 0};
2120            }
2121        }
2122
2123        auto * buft = ggml_backend_cpu_buffer_type();
2124        // try to use the host buffer of the device where the output tensor is allocated for faster transfer to system memory
2125        auto * output_dev = model.dev_output();
2126        auto * output_dev_host_buft = output_dev ? ggml_backend_dev_host_buffer_type(output_dev) : nullptr;
2127        if (output_dev_host_buft) {
2128            buft = output_dev_host_buft;
2129        }
2130        buf_output.reset(ggml_backend_buft_alloc_buffer(buft, new_size));
2131        if (buf_output == nullptr) {
2132            LLAMA_LOG_ERROR("%s: failed to allocate output buffer of size %.2f MiB\n", __func__, new_size / (1024.0 * 1024.0));
2133            return 0;
2134        }
2135        ggml_backend_buffer_clear(buf_output.get(), 0);
2136    }
2137
2138    float * output_base = (float *) ggml_backend_buffer_get_base(buf_output.get());
2139
2140    size_t offset = 0;
2141    uint8_t * base = (uint8_t *) output_base;
2142
2143    logits = has_logits ? buffer_view<float>{output_base, logits.size} : buffer_view<float>{nullptr, 0};
2144    offset += logits.size * sizeof(float);
2145
2146    embd = has_embd ? buffer_view<float>{(float *) (base + offset), embd.size} : buffer_view<float>{nullptr, 0};
2147    offset += embd.size * sizeof(float);
2148
2149    embd_nextn = has_embd_nextn ? buffer_view<float>{(float *) (base + offset), embd_nextn.size} : buffer_view<float>{nullptr, 0};
2150    offset += embd_nextn.size * sizeof(float);
2151
2152    for (uint32_t il = 0; il < embd_layer_inp.size(); ++il) {
2153        if (cparams.embeddings_layer_inp[il]) {
2154            embd_layer_inp[il] = buffer_view<float>{(float *) (base + offset), (size_t) n_embd * n_batch};
2155            offset += embd_layer_inp[il].size * sizeof(float);
2156        } else {
2157            embd_layer_inp[il] = buffer_view<float>{nullptr, 0};
2158        }
2159    }
2160
2161    if (has_sampling) {
2162        sampling.logits = {(float *) (base + offset), (size_t)(n_vocab*n_outputs_max)};
2163        offset += sampling.logits.size * sizeof(float);
2164
2165        sampling.probs = {(float *) (base + offset), (size_t)(n_vocab*n_outputs_max)};
2166        offset += sampling.probs.size * sizeof(float);
2167
2168        sampling.sampled = {(llama_token *) (base + offset), (size_t)n_outputs_max};
2169        offset += sampling.sampled.size * sizeof(llama_token);
2170
2171        sampling.candidates = {(llama_token *) (base + offset), (size_t)(n_vocab*n_outputs_max)};
2172        offset += sampling.candidates.size * sizeof(llama_token);
2173
2174        // The count vectors keep track of the actual number of logits/probs/candidates
2175        // copied from the backend for each output row.
2176
2177        sampling.logits_count.resize(n_outputs_max);
2178        sampling.probs_count.resize(n_outputs_max);
2179        sampling.candidates_count.resize(n_outputs_max);
2180
2181        std::fill(sampling.logits_count.begin(),     sampling.logits_count.end(),     0);
2182        std::fill(sampling.probs_count.begin(),      sampling.probs_count.end(),      0);
2183        std::fill(sampling.candidates_count.begin(), sampling.candidates_count.end(), 0);
2184
2185        std::fill_n(sampling.sampled.data, sampling.sampled.size, LLAMA_TOKEN_NULL);
2186    } else {
2187        sampling.logits     = {nullptr, 0};
2188        sampling.probs      = {nullptr, 0};
2189        sampling.sampled    = {nullptr, 0};
2190        sampling.candidates = {nullptr, 0};
2191
2192        sampling.logits_count.clear();
2193        sampling.probs_count.clear();
2194        sampling.candidates_count.clear();
2195    }
2196
2197    // set all ids as invalid (negative)
2198    std::fill(output_ids.begin(), output_ids.end(), -1);
2199
2200    this->n_outputs = 0;
2201
2202    GGML_ASSERT(n_outputs_max <= cparams.n_outputs_max);
2203
2204    return n_outputs_max;
2205}
2206
2207void llama_context::extract_layer_inputs(const llm_graph_result * res, size_t token_offset, size_t n_tokens) {
2208    for (uint32_t il = 0; il < cparams.embeddings_layer_inp.size(); ++il) {
2209        if (!cparams.embeddings_layer_inp[il]) {
2210            continue;
2211        }
2212        if (!embd_layer_inp[il].has_data()) {
2213            GGML_ABORT("output layer input buffer not allocated");
2214        }
2215        ggml_tensor * t = res->get_layer_inp((int) il);
2216        if (!t) {
2217            GGML_ABORT("layer input tensor not found");
2218        }
2219
2220        const size_t nbytes = ggml_nbytes(t);
2221        const size_t nfloats = nbytes / sizeof(float);
2222        GGML_ASSERT(n_tokens > 0);
2223        GGML_ASSERT(nfloats % n_tokens == 0);
2224
2225        const size_t row_floats = nfloats / n_tokens;
2226        const size_t dst_offset = token_offset * row_floats;
2227        GGML_ASSERT(dst_offset + nfloats <= embd_layer_inp[il].size);
2228
2229        ggml_backend_t backend = ggml_backend_sched_get_tensor_backend(sched.get(), t);
2230        GGML_ASSERT(backend != nullptr);
2231        ggml_backend_tensor_get_async(backend, t, embd_layer_inp[il].data + dst_offset, 0, nbytes);
2232    }
2233}
2234
2235void llama_context::output_reorder() {
2236    const uint64_t n_vocab     = model.vocab.n_tokens();
2237    const uint64_t n_embd      = model.hparams.n_embd;
2238    const uint64_t n_embd_out  = model.hparams.n_embd_out();
2239
2240    for (size_t s = 0; s < output_swaps.size(); ++s) {
2241        const uint64_t i0 = output_swaps[s].i0;
2242        const uint64_t i1 = output_swaps[s].i1;
2243
2244        if (logits.size > 0) {
2245            for (uint64_t k = 0; k < n_vocab; k++) {
2246                std::swap(logits.data[i0*n_vocab + k], logits.data[i1*n_vocab + k]);
2247            }
2248        }
2249
2250        if (embd.size > 0) {
2251            for (uint64_t k = 0; k < n_embd_out; k++) {
2252                std::swap(embd.data[i0*n_embd_out + k], embd.data[i1*n_embd_out + k]);
2253            }
2254        }
2255
2256        if (embd_nextn.size > 0) {
2257            for (uint64_t k = 0; k < n_embd_out; k++) {
2258                std::swap(embd_nextn.data[i0*n_embd_out + k], embd_nextn.data[i1*n_embd_out + k]);
2259            }
2260        }
2261
2262        if (embd_layer_inp.size() > 0) {
2263            for (int lid = 0; lid < (int) embd_layer_inp.size(); ++lid) {
2264                if (embd_layer_inp[lid].size > 0) {
2265                    for (uint64_t k = 0; k < n_embd; ++k) {
2266                        std::swap(embd_layer_inp[lid].data[i0*n_embd + k], embd_layer_inp[lid].data[i1*n_embd + k]);
2267                    }
2268                }
2269            }
2270        }
2271
2272        if (!sampling.samplers.empty()) {
2273            assert(sampling.logits.size > 0);
2274            assert(sampling.probs.size > 0);
2275            assert(sampling.candidates.size > 0);
2276            assert(sampling.sampled.size > 0);
2277            assert(sampling.logits_count.size() > 0);
2278            assert(sampling.probs_count.size() > 0);
2279            assert(sampling.candidates_count.size() > 0);
2280
2281            for (uint64_t k = 0; k < n_vocab; ++k) {
2282                std::swap(sampling.logits.data[i0*n_vocab + k], sampling.logits.data[i1*n_vocab + k]);
2283            }
2284
2285            for (uint64_t k = 0; k < n_vocab; ++k) {
2286                std::swap(sampling.probs.data[i0*n_vocab + k], sampling.probs.data[i1*n_vocab + k]);
2287            }
2288
2289            for (uint64_t k = 0; k < n_vocab; ++k) {
2290                std::swap(sampling.candidates.data[i0*n_vocab + k], sampling.candidates.data[i1*n_vocab + k]);
2291            }
2292
2293            std::swap(sampling.sampled.data[i0],     sampling.sampled.data[i1]);
2294            std::swap(sampling.logits_count[i0],     sampling.logits_count[i1]);
2295            std::swap(sampling.probs_count[i0],      sampling.probs_count[i1]);
2296            std::swap(sampling.candidates_count[i0], sampling.candidates_count[i1]);
2297        }
2298    }
2299
2300    output_swaps.clear();
2301}
2302
2303//
2304// graph
2305//
2306
2307uint32_t llama_context::graph_max_nodes(uint32_t n_tokens) const {
2308    uint32_t res;
2309    if (model.arch == LLM_ARCH_KIMI_K3) {
2310        // the n_tokens*40 budget below is exhausted at ubatch 3840
2311        res = std::max<uint32_t>(n_tokens * 160, 64u * model.n_tensors());
2312    } else if (model.arch == LLM_ARCH_QWEN3NEXT ||
2313        model.arch == LLM_ARCH_KIMI_LINEAR ||
2314        model.arch == LLM_ARCH_BAILINGMOE3 ||
2315        model.arch == LLM_ARCH_QWEN35 ||
2316        model.arch == LLM_ARCH_QWEN35MOE ||
2317        model.arch == LLM_ARCH_QWEN4EXP ||
2318        model.arch == LLM_ARCH_DEEPSEEK4 ||
2319        (model.arch == LLM_ARCH_DFLASH && model.hparams.dsv4_hc_mult > 0) ||
2320        model.arch == LLM_ARCH_NANBEIGE ||
2321        model.arch == LLM_ARCH_MINIMAX_01 ||
2322        model.arch == LLM_ARCH_MINIMAX_M3 ||
2323        model.arch == LLM_ARCH_HY_V4) {
2324        res = std::max<uint32_t>(n_tokens * 40, 32u * model.n_tensors());
2325    } else if (model.arch == LLM_ARCH_DFLASH && model.hparams.dflash_selector_rank > 0) {
2326        // DFlash2's convolutions and selector are shape work rather than matmuls,
2327        // so they cost ~8.6 nodes per tensor against ~5.9 for a plain DFlash draft
2328        res = std::max<uint32_t>(1024u, 12u*model.n_tensors());
2329    } else {
2330        res = std::max<uint32_t>(1024u, 8u*model.n_tensors());
2331        for (const auto & lora : model.loras) {
2332            res += lora->get_n_nodes();
2333        }
2334    }
2335
2336    uint32_t n_sampling_nodes = 0;
2337    uint32_t n_sampling_nodes_max = 0;
2338    for (const auto & [seq_id, sampler] : sampling.samplers) {
2339        const uint32_t n_nodes = llama_sampler_backend_n_nodes(sampler);
2340        n_sampling_nodes += n_nodes;
2341        if (cparams.n_outputs_max_per_seq > 1) {
2342            n_sampling_nodes_max = std::max(n_sampling_nodes_max, n_nodes);
2343        }
2344    }
2345
2346    const uint32_t n_sampling_outputs_max = std::min<uint64_t>(
2347            std::min(n_tokens, cparams.n_outputs_max),
2348            (uint64_t) cparams.n_seq_max * cparams.n_outputs_max_per_seq);
2349
2350    res += n_sampling_nodes;
2351    if (n_sampling_outputs_max > 1) {
2352        res += (n_sampling_outputs_max - 1) * n_sampling_nodes_max;
2353    }
2354    return res;
2355}
2356
2357llm_graph_result * llama_context::get_gf_res_reserve() const {
2358    return static_cast<llm_graph_result *>(gf_res_reserve.get());
2359}
2360
2361// pack sampler outputs into as few sequences as possible before using sequences without samplers
2362static void ubatch_prepare_reserve(
2363              llama_ubatch                            & ubatch,
2364              uint32_t                                  n_outputs,
2365        const std::map<llama_seq_id, llama_sampler *> & samplers,
2366              uint32_t                                  n_outputs_max_per_seq) {
2367    const uint32_t n_seqs       = ubatch.n_seqs;
2368    const uint32_t n_seq_tokens = ubatch.n_seq_tokens;
2369
2370    for (uint32_t s = 0; s < n_seqs; ++s) {
2371        for (uint32_t t = 0; t < n_seq_tokens; ++t) {
2372            const uint32_t i = s * n_seq_tokens + t;
2373            ubatch.n_seq_id[i] = 1;
2374            ubatch.seq_id[i] = &ubatch.seq_id_unq[s];
2375        }
2376    }
2377
2378    // sequences with a sampler that fit in this ubatch
2379    std::vector<uint32_t> sampler_seqs;
2380    std::vector<bool> has_sampler(n_seqs, false);
2381    for (const auto & entry : samplers) {
2382        const llama_seq_id seq_id = entry.first;
2383        if (seq_id < 0 || (uint32_t) seq_id >= n_seqs) {
2384            continue;
2385        }
2386
2387        sampler_seqs.push_back(seq_id);
2388        has_sampler[seq_id] = true;
2389    }
2390
2391    uint32_t n_outputs_set = 0;
2392
2393    const uint32_t n_outputs_per_seq = std::min(n_seq_tokens, n_outputs_max_per_seq);
2394    for (uint32_t s : sampler_seqs) {
2395        if (n_outputs_set >= n_outputs) {
2396            break;
2397        }
2398
2399        for (uint32_t t = 0; t < n_outputs_per_seq && n_outputs_set < n_outputs; ++t) {
2400            ubatch.output[s * n_seq_tokens + t] = true;
2401            ++n_outputs_set;
2402        }
2403    }
2404
2405    // use sequences without samplers for any remaining outputs
2406    for (uint32_t t = 0; t < n_seq_tokens && n_outputs_set < n_outputs; ++t) {
2407        for (uint32_t s = 0; s < n_seqs && n_outputs_set < n_outputs; ++s) {
2408            if (has_sampler[s]) {
2409                continue;
2410            }
2411
2412            ubatch.output[s * n_seq_tokens + t] = true;
2413            ++n_outputs_set;
2414        }
2415    }
2416}
2417
2418ggml_cgraph * llama_context::graph_reserve(
2419        uint32_t n_tokens, uint32_t n_seqs, uint32_t n_outputs, const llama_memory_context_i * mctx, bool split_only, size_t * sizes) {
2420    LLAMA_LOG_DEBUG("%s: reserving a graph for ubatch with n_tokens = %4u, n_seqs = %2u, n_outputs = %4u\n", __func__, n_tokens, n_seqs, n_outputs);
2421    GGML_ASSERT(n_outputs >= 1);
2422
2423    if (n_tokens % n_seqs != 0) {
2424        n_tokens = ((n_tokens + (n_seqs - 1)) / n_seqs) * n_seqs; // round to next multiple of n_seqs
2425        LLAMA_LOG_DEBUG("%s: making n_tokens a multiple of n_seqs - n_tokens = %u, n_seqs = %u, n_outputs = %u\n", __func__, n_tokens, n_seqs, n_outputs);
2426    }
2427
2428    ggml_backend_sched_reset(sched.get());
2429
2430    // when the scheduler is reset, we cannot reuse the old graph, so we reset the previous graph result to prevent that
2431    gf_res_prev->reset();
2432
2433    // store the n_outputs as it is, and restore it afterwards
2434    // TODO: not sure if needed, might simplify in the future by removing this
2435    const auto save_n_outputs = this->n_outputs;
2436
2437    this->n_outputs = n_outputs;
2438
2439    llama_batch_allocr balloc(model.hparams.n_pos_per_embd());
2440    llama_ubatch ubatch = balloc.ubatch_reserve(n_tokens/n_seqs, n_seqs);
2441
2442    ubatch_prepare_reserve(ubatch, n_outputs, sampling.samplers, cparams.n_outputs_max_per_seq);
2443
2444    auto * res = gf_res_reserve.get();
2445
2446    const auto gparams = graph_params(res, ubatch, mctx, ctx_type_to_graph_type(cparams.ctx_type));
2447
2448    res->reset();
2449
2450    auto * gf = model.build_graph(gparams);
2451
2452    this->n_outputs = save_n_outputs;
2453
2454    // initialize scheduler with the specified graph
2455    if (split_only) {
2456        if (sizes) {
2457            ggml_backend_sched_reserve_size(sched.get(), gf, sizes);
2458        } else {
2459            ggml_backend_sched_split_graph(sched.get(), gf);
2460        }
2461    } else if (!ggml_backend_sched_reserve(sched.get(), gf)) {
2462        GGML_ASSERT(!sizes);
2463        LLAMA_LOG_ERROR("%s: failed to allocate compute buffers\n", __func__);
2464        return nullptr;
2465    }
2466
2467    return gf;
2468}
2469
2470llm_graph_params llama_context::graph_params(
2471                        llm_graph_result * res,
2472                      const llama_ubatch & ubatch,
2473            const llama_memory_context_i * mctx,
2474                          llm_graph_type   gtype) const {
2475    return {
2476        /*.arch        =*/ model.arch,
2477        /*.hparams     =*/ model.hparams,
2478        /*.cparams     =*/ cparams,
2479        /*.ubatch      =*/ ubatch,
2480        /*.gtype       =*/ gtype,
2481        /*.sched       =*/ sched.get(),
2482        /*.backend_cpu =*/ backend_cpu,
2483        /*.cvec        =*/ cvec.get(),
2484        /*.loras       =*/ loras.get(),
2485        /*.mctx        =*/ mctx,
2486        /*.cross       =*/ &cross,
2487        /*.samplers    =*/ sampling.samplers,
2488        /*.n_outputs   =*/ n_outputs,
2489        /*.cb          =*/ graph_get_cb(),
2490        /*.res         =*/ res,
2491    };
2492}
2493
2494ggml_status llama_context::graph_compute(
2495            ggml_cgraph * gf,
2496                   bool   batched) {
2497    int n_threads        = batched ? cparams.n_threads_batch : cparams.n_threads;
2498    ggml_threadpool_t tp = batched ? threadpool_batch        : threadpool;
2499
2500    if (backend_cpu != nullptr) {
2501        auto * reg = ggml_backend_dev_backend_reg(ggml_backend_get_device(backend_cpu));
2502        auto * set_threadpool_fn = (decltype(ggml_backend_cpu_set_threadpool) *) ggml_backend_reg_get_proc_address(reg, "ggml_backend_cpu_set_threadpool");
2503        if (set_threadpool_fn) {
2504            set_threadpool_fn(backend_cpu, tp);
2505        }
2506    }
2507
2508    // set the number of threads for all the backends
2509    for (const auto & set_n_threads_fn : set_n_threads_fns) {
2510        set_n_threads_fn.second(set_n_threads_fn.first, n_threads);
2511    }
2512
2513    auto status = ggml_backend_sched_graph_compute_async(sched.get(), gf);
2514    if (status != GGML_STATUS_SUCCESS) {
2515        LLAMA_LOG_ERROR("%s: ggml_backend_sched_graph_compute_async failed with error %d\n", __func__, status);
2516    }
2517
2518    // fprintf(stderr, "splits: %d\n", ggml_backend_sched_get_n_splits(sched));
2519
2520    return status;
2521}
2522
2523llm_graph_cb llama_context::graph_get_cb() const {
2524    return [&](const llama_ubatch & ubatch, ggml_tensor * cur, const char * name, int il) {
2525        if (il >= 0) {
2526            ggml_format_name(cur, "%s-%d", name, il);
2527        } else {
2528            ggml_set_name(cur, name);
2529        }
2530
2531        // - norm may be automatically assigned to the backend of the previous layer, increasing data transfer between backends
2532        // - force the last op of the layer on the specified backend to avoid running it on the backend of the next layer due to scheduling
2533        // FIXME: fix in ggml_backend_sched
2534        const bool full_offload = model.n_gpu_layers() > model.hparams.n_layer_all;
2535        if (ubatch.n_tokens < 32 || full_offload) {
2536            if (il != -1 && (strcmp(name, "norm") == 0 || strcmp(name, "l_last") == 0)) {
2537                const auto & dev_layer = model.dev_layer(il);
2538                for (const auto & backend : backends) {
2539                    if (ggml_backend_get_device(backend.get()) == dev_layer) {
2540                        if (ggml_backend_supports_op(backend.get(), cur)) {
2541                            ggml_backend_sched_set_tensor_backend(sched.get(), cur, backend.get());
2542                        }
2543                    }
2544                }
2545            }
2546        }
2547    };
2548}
2549
2550//
2551// state save/load
2552//
2553
2554class llama_io_write_dummy : public llama_io_write_i {
2555public:
2556    llama_io_write_dummy(bool skip_tensors) : skip_tensors(skip_tensors) {}
2557
2558    void write(const void * /* src */, size_t size) override {
2559        size_written += size;
2560    }
2561
2562    void write_tensor(ggml_tensor * /* tensor */, size_t /* offset */, size_t size) override {
2563        if (skip_tensors) {
2564            return;
2565        }
2566
2567        size_written += size;
2568    }
2569
2570    size_t n_bytes() override {
2571        return size_written;
2572    }
2573
2574private:
2575    const bool skip_tensors;
2576
2577    size_t size_written = 0;
2578};
2579
2580class llama_io_write_host : public llama_io_write_i {
2581public:
2582    llama_io_write_host(
2583            uint8_t * p, size_t len) : ptr(p), buf_size(len) {}
2584
2585    ~llama_io_write_host() {
2586        // TODO: add backend support to batch tensor_get? or some other way to speed this up
2587        for (const auto & winfo : winfos) {
2588            ggml_backend_tensor_get(winfo.tensor, winfo.ptr, winfo.offset, winfo.size);
2589        }
2590    }
2591
2592    void write(const void * src, size_t size) override {
2593        if (size > buf_size) {
2594            throw std::runtime_error("unexpectedly reached end of buffer");
2595        }
2596        memcpy(ptr, src, size);
2597        ptr += size;
2598        size_written += size;
2599        buf_size -= size;
2600    }
2601
2602    void write_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
2603        if (size > buf_size) {
2604            throw std::runtime_error("unexpectedly reached end of buffer");
2605        }
2606
2607        // save the write for later during destruction
2608        winfos.push_back({tensor, ptr, size, offset});
2609
2610        ptr += size;
2611        size_written += size;
2612        buf_size -= size;
2613    }
2614
2615    size_t n_bytes() override {
2616        return size_written;
2617    }
2618
2619private:
2620    uint8_t * ptr;
2621    size_t buf_size = 0;
2622    size_t size_written = 0;
2623
2624    struct write_info {
2625        ggml_tensor * tensor;
2626        uint8_t * ptr;
2627        size_t size;
2628        size_t offset;
2629    };
2630    std::vector<write_info> winfos;
2631};
2632
2633class llama_io_read_host : public llama_io_read_i {
2634public:
2635    llama_io_read_host(const uint8_t * p, size_t len) : ptr(p), buf_size(len) {}
2636
2637    ~llama_io_read_host() {
2638        // flush the reads
2639        for (const auto & rinfo : rinfos) {
2640            ggml_backend_tensor_set(rinfo.tensor, rinfo.ptr, rinfo.offset, rinfo.size);
2641        }
2642    }
2643
2644    void read(void * dst, size_t size) override {
2645        if (size > buf_size) {
2646            throw std::runtime_error("unexpectedly reached end of buffer");
2647        }
2648        memcpy(dst, ptr, size);
2649        ptr += size;
2650        size_read += size;
2651        buf_size -= size;
2652    }
2653
2654    void read_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
2655        if (size > buf_size) {
2656            throw std::runtime_error("unexpectedly reached end of buffer");
2657        }
2658
2659        // save for later during destruction
2660        rinfos.push_back({tensor, ptr, size, offset});
2661
2662        ptr += size;
2663        size_read += size;
2664        buf_size -= size;
2665    }
2666
2667    size_t n_bytes() override {
2668        return size_read;
2669    }
2670
2671private:
2672    const uint8_t * ptr;
2673    size_t buf_size = 0;
2674    size_t size_read = 0;
2675
2676    struct read_info {
2677        ggml_tensor * tensor;
2678        const uint8_t * ptr;
2679        size_t size;
2680        size_t offset;
2681    };
2682    std::vector<read_info> rinfos;
2683};
2684
2685class llama_io_write_file : public llama_io_write_i {
2686public:
2687    llama_io_write_file(llama_file * f) : file(f) {}
2688
2689    void write(const void * src, size_t size) override {
2690        file->write_raw(src, size);
2691        size_written += size;
2692    }
2693
2694    void write_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
2695        temp_buffer.resize(size);
2696        ggml_backend_tensor_get(tensor, temp_buffer.data(), offset, size);
2697        write(temp_buffer.data(), temp_buffer.size());
2698    }
2699
2700    size_t n_bytes() override {
2701        return size_written;
2702    }
2703
2704private:
2705    llama_file * file;
2706    size_t size_written = 0;
2707    std::vector<uint8_t> temp_buffer;
2708};
2709
2710class llama_io_read_file : public llama_io_read_i {
2711public:
2712    llama_io_read_file(llama_file * f) : file(f) {}
2713
2714    void read(void * dst, size_t size) override {
2715        file->read_raw(dst, size);
2716        size_read += size;
2717    }
2718
2719    void read_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
2720        temp_buffer.resize(size);
2721        read(temp_buffer.data(), size);
2722        ggml_backend_tensor_set(tensor, temp_buffer.data(), offset, size);
2723    }
2724
2725    size_t n_bytes() override {
2726        return size_read;
2727    }
2728
2729private:
2730    llama_file * file;
2731    size_t size_read = 0;
2732    std::vector<uint8_t> temp_buffer;
2733};
2734
2735class llama_io_write_device : public llama_io_write_i {
2736public:
2737    llama_io_write_device(uint8_t * p, size_t len, llama_memory_buffers & mbufs) : ptr(p), buf_size(len), mbufs(mbufs)  {
2738    }
2739
2740    ~llama_io_write_device() {
2741        llama_memory_buffers mbufs_new;
2742
2743        for (const auto & winfo : winfos) {
2744            auto * buft = ggml_backend_buffer_get_type(winfo.tensor->buffer);
2745
2746            mbufs_new[buft].n_tensors++;
2747            mbufs_new[buft].total_size += winfo.size;
2748        }
2749
2750        for (auto & [buft, mbuf] : mbufs_new) {
2751            ggml_init_params params = {
2752                /*.mem_size   =*/ 2*mbuf.n_tensors*ggml_tensor_overhead(),
2753                /*.mem_buffer =*/ NULL,
2754                /*.no_alloc   =*/ true,
2755            };
2756
2757            mbuf.ctx.reset(ggml_init(params));
2758
2759            mbuf.org.reserve(mbuf.n_tensors);
2760            mbuf.cpy.reserve(mbuf.n_tensors);
2761        }
2762
2763        for (const auto & winfo : winfos) {
2764            auto * buft = ggml_backend_buffer_get_type(winfo.tensor->buffer);
2765
2766            const int64_t n = winfo.size/ggml_element_size(winfo.tensor);
2767
2768            auto & mbuf = mbufs_new[buft];
2769
2770            mbuf.org.push_back(ggml_view_1d      (mbuf.ctx.get(), winfo.tensor, n, winfo.offset));
2771            mbuf.cpy.push_back(ggml_new_tensor_1d(mbuf.ctx.get(), winfo.tensor->type, n));
2772        }
2773
2774        for (auto & [buft, mbuf] : mbufs_new) {
2775            auto & mbuf_cur = mbufs[buft];
2776
2777            bool need_alloc = false;
2778
2779            need_alloc = need_alloc || (!mbuf_cur.buf);
2780            need_alloc = need_alloc || (mbuf_cur.org.size() != mbuf.org.size());
2781            need_alloc = need_alloc || (mbuf_cur.total_size != mbuf.total_size);
2782
2783            if (!need_alloc) {
2784                for (size_t i = 0; i < mbuf_cur.org.size(); ++i) {
2785                    auto * org0 = mbuf_cur.org[i];
2786                    auto * org1 = mbuf.org[i];
2787
2788                    if (!ggml_are_same_shape(org0, org1)) {
2789                        need_alloc = true;
2790                        break;
2791                    }
2792
2793                    if (org0->view_src != org1->view_src || org0->view_offs != org1->view_offs) {
2794                        need_alloc = true;
2795                        break;
2796                    }
2797                }
2798            }
2799
2800            if (need_alloc) {
2801                if (!mbuf_cur.buf || mbuf_cur.total_size != mbuf.total_size) {
2802                    mbuf_cur = std::move(mbuf);
2803
2804                    mbuf_cur.buf.reset(ggml_backend_alloc_ctx_tensors_from_buft(mbuf_cur.ctx.get(), buft));
2805
2806                    LLAMA_LOG_INFO("%s: allocated '%s' buffer %.3f MiB\n", __func__, ggml_backend_buft_name(buft), mbuf.total_size/1024.0/1024.0);
2807                } else {
2808                    //LLAMA_LOG_INFO("%s: reallocating tensors in '%s' buffer %.3f MiB\n", __func__, ggml_backend_buft_name(buft), mbuf.total_size/1024.0/1024.0);
2809
2810                    // save the old buffer and allocate the new tensors in it
2811                    auto buf = std::move(mbuf_cur.buf);
2812
2813                    mbuf_cur = std::move(mbuf);
2814
2815                    ggml_tallocr talloc = ggml_tallocr_new(buf.get());
2816
2817                    for (size_t i = 0; i < mbuf_cur.org.size(); ++i) {
2818                        ggml_backend_view_init(mbuf_cur.org[i]);
2819                        ggml_tallocr_alloc(&talloc, mbuf_cur.cpy[i]);
2820                    }
2821
2822                    mbuf_cur.buf = std::move(buf);
2823                }
2824            }
2825
2826            for (size_t i = 0; i < mbuf_cur.org.size(); ++i) {
2827                ggml_backend_tensor_copy(mbuf_cur.org[i], mbuf_cur.cpy[i]);
2828            }
2829        }
2830    }
2831
2832    void write(const void * src, size_t size) override {
2833        if (size > buf_size) {
2834            throw std::runtime_error("unexpectedly reached end of buffer");
2835        }
2836        memcpy(ptr, src, size);
2837        ptr += size;
2838        size_written += size;
2839        buf_size -= size;
2840    }
2841
2842    void write_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
2843        // save the write for later during destruction
2844        winfos.push_back({tensor, ptr, size, offset});
2845    }
2846
2847    size_t n_bytes() override {
2848        return size_written;
2849    }
2850
2851private:
2852    uint8_t * ptr;
2853    size_t buf_size = 0;
2854    size_t size_written = 0;
2855
2856    struct write_info {
2857        ggml_tensor * tensor;
2858        uint8_t * ptr;
2859        size_t size;
2860        size_t offset;
2861    };
2862    std::vector<write_info> winfos;
2863
2864    llama_memory_buffers & mbufs;
2865};
2866
2867class llama_io_read_device : public llama_io_read_i {
2868public:
2869    llama_io_read_device(const uint8_t * p, size_t len, const llama_memory_buffers & mbufs) : ptr(p), buf_size(len), mbufs(mbufs) {
2870    }
2871
2872    ~llama_io_read_device() {
2873        llama_memory_buffers mbufs_new;
2874
2875        for (const auto & rinfo : rinfos) {
2876            auto * buft = ggml_backend_buffer_get_type(rinfo.tensor->buffer);
2877
2878            mbufs_new[buft].n_tensors++;
2879            mbufs_new[buft].total_size += rinfo.size;
2880        }
2881
2882        for (auto & [buft, mbuf] : mbufs_new) {
2883            ggml_init_params params = {
2884                /*.mem_size   =*/ mbuf.n_tensors*ggml_tensor_overhead(),
2885                /*.mem_buffer =*/ NULL,
2886                /*.no_alloc   =*/ true,
2887            };
2888
2889            mbuf.ctx.reset(ggml_init(params));
2890
2891            mbuf.org.reserve(mbuf.n_tensors);
2892        }
2893
2894        for (const auto & rinfo : rinfos) {
2895            auto * buft = ggml_backend_buffer_get_type(rinfo.tensor->buffer);
2896
2897            const int64_t n = rinfo.size/ggml_element_size(rinfo.tensor);
2898
2899            auto & mbuf = mbufs_new[buft];
2900
2901            mbuf.org.push_back(ggml_view_1d(mbuf.ctx.get(), rinfo.tensor, n, rinfo.offset));
2902
2903            ggml_backend_view_init(mbuf.org.back());
2904        }
2905
2906        for (auto & [buft, mbuf] : mbufs_new) {
2907            const auto & mbuf_cur = mbufs.at(buft);
2908
2909            if (!mbuf_cur.buf || mbuf_cur.total_size != mbuf.total_size) {
2910                GGML_ABORT("%s: memory buffer mismatch\n", __func__);
2911            }
2912
2913            if (mbuf_cur.n_tensors == mbuf.n_tensors) {
2914                // an equal tensor count does not imply the same chunking, e.g. save ranges [2,1] vs restore runs [1,2]
2915                bool same_chunking = true;
2916                for (size_t i = 0; i < mbuf_cur.org.size(); ++i) {
2917                    if (ggml_nbytes(mbuf_cur.cpy[i]) != ggml_nbytes(mbuf.org[i])) {
2918                        same_chunking = false;
2919                        break;
2920                    }
2921                }
2922
2923                if (same_chunking) {
2924                    // same chunking: copy 1:1 by index
2925                    for (size_t i = 0; i < mbuf_cur.org.size(); ++i) {
2926                        ggml_backend_tensor_copy(mbuf_cur.cpy[i], mbuf.org[i]);
2927                    }
2928                    continue;
2929                }
2930            }
2931
2932            // different chunking: copy the write-side data (mbuf_cur.cpy) into the read-side targets (mbuf.org)
2933            // with a byte cursor. Write and read enumerate the same logical data in the same order but may chunk
2934            // it differently (even with an equal number of tensors), so copy across tensor boundaries rather than
2935            // 1:1 by index.
2936            const size_t total = mbuf_cur.total_size;
2937
2938            ggml_init_params params_scratch = {
2939                /*.mem_size   =*/ 2*(mbuf_cur.cpy.size() + mbuf.org.size())*ggml_tensor_overhead(),
2940                /*.mem_buffer =*/ NULL,
2941                /*.no_alloc   =*/ true,
2942            };
2943            ggml_context * ctx_scratch = ggml_init(params_scratch);
2944
2945            size_t src_pos  = 0;
2946            size_t dst_pos  = 0;
2947            size_t src_j    = 0;
2948            size_t dst_i    = 0;
2949            size_t src_base = 0;
2950            size_t dst_base = 0;
2951
2952            while (src_pos < total) {
2953                const auto & src_t = mbuf_cur.cpy[src_j];
2954                const auto & dst_t = mbuf.org[dst_i];
2955
2956                const size_t src_size = ggml_nbytes(src_t);
2957                const size_t dst_size = ggml_nbytes(dst_t);
2958
2959                const size_t src_off  = src_pos - src_base;
2960                const size_t dst_off  = dst_pos - dst_base;
2961
2962                const size_t n_copy = std::min(src_size - src_off, dst_size - dst_off);
2963
2964                const size_t   el   = ggml_element_size(src_t);
2965                const int64_t n_el = (int64_t) (n_copy / el);
2966
2967                auto * src_v = ggml_view_1d(ctx_scratch, src_t, n_el, src_off);
2968                ggml_backend_view_init(src_v);
2969                auto * dst_v = ggml_view_1d(ctx_scratch, dst_t, n_el, dst_off);
2970                ggml_backend_view_init(dst_v);
2971
2972                ggml_backend_tensor_copy(src_v, dst_v);
2973
2974                src_pos += n_copy;
2975                dst_pos += n_copy;
2976
2977                if (src_pos - src_base == src_size) {
2978                    src_base = src_pos;
2979                    ++src_j;
2980                }
2981                if (dst_pos - dst_base == dst_size) {
2982                    dst_base = dst_pos;
2983                    ++dst_i;
2984                }
2985            }
2986
2987            GGML_ASSERT(src_pos == total && dst_pos == total);
2988            // any tensors left unvisited hold no data
2989            for (size_t i = src_j; i < mbuf_cur.cpy.size(); ++i) {
2990                GGML_ASSERT(ggml_nbytes(mbuf_cur.cpy[i]) == 0);
2991            }
2992            for (size_t i = dst_i; i < mbuf.org.size(); ++i) {
2993                GGML_ASSERT(ggml_nbytes(mbuf.org[i]) == 0);
2994            }
2995
2996            ggml_free(ctx_scratch);
2997        }
2998
2999        GGML_ASSERT(buf_size == 0);
3000    }
3001
3002    void read(void * dst, size_t size) override {
3003        if (size > buf_size) {
3004            throw std::runtime_error("unexpectedly reached end of buffer");
3005        }
3006        memcpy(dst, ptr, size);
3007        ptr += size;
3008        size_read += size;
3009        buf_size -= size;
3010    }
3011
3012    void read_tensor(ggml_tensor * tensor, size_t offset, size_t size) override {
3013        // save for later during destruction
3014        rinfos.push_back({tensor, ptr, size, offset});
3015    }
3016
3017    size_t n_bytes() override {
3018        return size_read;
3019    }
3020
3021private:
3022    const uint8_t * ptr;
3023    size_t buf_size = 0;
3024    size_t size_read = 0;
3025
3026    struct read_info {
3027        ggml_tensor * tensor;
3028        const uint8_t * ptr;
3029        size_t size;
3030        size_t offset;
3031    };
3032    std::vector<read_info> rinfos;
3033
3034    const llama_memory_buffers & mbufs;
3035};
3036
3037size_t llama_context::state_get_size() {
3038    llama_io_write_dummy io(false);
3039    try {
3040        return state_write_data(io);
3041    } catch (const std::exception & err) {
3042        LLAMA_LOG_ERROR("%s: error getting state size: %s\n", __func__, err.what());
3043        return 0;
3044    }
3045}
3046
3047size_t llama_context::state_get_data(uint8_t * dst, size_t size) {
3048    llama_io_write_host io(dst, size);
3049    try {
3050        return state_write_data(io);
3051    } catch (const std::exception & err) {
3052        LLAMA_LOG_ERROR("%s: error saving state: %s\n", __func__, err.what());
3053        return 0;
3054    }
3055}
3056
3057size_t llama_context::state_set_data(const uint8_t * src, size_t size) {
3058    llama_io_read_host io(src, size);
3059    try {
3060        return state_read_data(io);
3061    } catch (const std::exception & err) {
3062        LLAMA_LOG_ERROR("%s: error loading state: %s\n", __func__, err.what());
3063        return 0;
3064    }
3065}
3066
3067static constexpr uint32_t io_magic = 0xaf143cd8;
3068
3069size_t llama_context::state_seq_get_size(llama_seq_id seq_id, llama_state_seq_flags flags) {
3070    llama_io_write_dummy io(flags & LLAMA_STATE_SEQ_FLAGS_ON_DEVICE);
3071    try {
3072        io.write(&io_magic, sizeof(io_magic));
3073        io.write(&seq_id, sizeof(seq_id));
3074
3075        return state_seq_write_data(io, seq_id, flags);
3076    } catch (const std::exception & err) {
3077        LLAMA_LOG_ERROR("%s: error getting state size: %s\n", __func__, err.what());
3078        return 0;
3079    }
3080}
3081
3082size_t llama_context::state_seq_get_data(llama_seq_id seq_id, uint8_t * dst, size_t size, llama_state_seq_flags flags) {
3083    std::unique_ptr<llama_io_write_i> io;
3084    if (flags & LLAMA_STATE_SEQ_FLAGS_ON_DEVICE) {
3085        io = std::make_unique<llama_io_write_device>(dst, size, mem_storage[seq_id]);
3086    } else {
3087        io = std::make_unique<llama_io_write_host>(dst, size);
3088    }
3089
3090    try {
3091        io->write(&io_magic, sizeof(io_magic));
3092        io->write(&seq_id, sizeof(seq_id));
3093
3094        return state_seq_write_data(*io, seq_id, flags);
3095    } catch (const std::exception & err) {
3096        LLAMA_LOG_ERROR("%s: error saving state: %s\n", __func__, err.what());
3097        return 0;
3098    }
3099}
3100
3101size_t llama_context::state_seq_set_data(llama_seq_id seq_id, const uint8_t * src, size_t size, llama_state_seq_flags flags) {
3102    std::unique_ptr<llama_io_read_i> io;
3103    if (flags & LLAMA_STATE_SEQ_FLAGS_ON_DEVICE) {
3104        // create a temporary io to read the magic and the src seq_id
3105        io = std::make_unique<llama_io_read_host>(src, size);
3106
3107        uint32_t magic_read;
3108        io->read(&magic_read, sizeof(magic_read));
3109        if (io_magic != magic_read) {
3110            throw std::runtime_error("wrong sequence state magic");
3111        }
3112
3113        llama_seq_id seq_id_read;
3114        io->read(&seq_id_read, sizeof(seq_id_read));
3115
3116        GGML_ASSERT(mem_storage.find(seq_id_read) != mem_storage.end());
3117
3118        io = std::make_unique<llama_io_read_device>(src, size, mem_storage[seq_id_read]);
3119    } else {
3120        io = std::make_unique<llama_io_read_host>(src, size);
3121    }
3122
3123    try {
3124        uint32_t magic_read;
3125        io->read(&magic_read, sizeof(magic_read));
3126        if (io_magic != magic_read) {
3127            throw std::runtime_error("wrong sequence state magic");
3128        }
3129
3130        llama_seq_id seq_id_read;
3131        io->read(&seq_id_read, sizeof(seq_id_read));
3132
3133        return state_seq_read_data(*io, seq_id, flags);
3134    } catch (const std::exception & err) {
3135        LLAMA_LOG_ERROR("%s: error loading state: %s\n", __func__, err.what());
3136        return 0;
3137    }
3138}
3139
3140bool llama_context::state_load_file(const char * filepath, llama_token * tokens_out, size_t n_token_capacity, size_t * n_token_count_out) {
3141    llama_file file(filepath, "rb");
3142
3143    // sanity checks
3144    {
3145        const uint32_t magic   = file.read_u32();
3146        const uint32_t version = file.read_u32();
3147
3148        if (magic != LLAMA_SESSION_MAGIC || version != LLAMA_SESSION_VERSION) {
3149            LLAMA_LOG_ERROR("%s: unknown (magic, version) for session file: %08x, %08x\n", __func__, magic, version);
3150            return false;
3151        }
3152    }
3153
3154    // load the prompt
3155    {
3156        const uint32_t n_token_count = file.read_u32();
3157
3158        if (n_token_count > n_token_capacity) {
3159            LLAMA_LOG_ERROR("%s: token count in session file exceeded capacity! %u > %zu\n", __func__, n_token_count, n_token_capacity);
3160            return false;
3161        }
3162
3163        file.read_raw(tokens_out, sizeof(llama_token) * n_token_count);
3164        *n_token_count_out = n_token_count;
3165    }
3166
3167    // restore the context state
3168    {
3169        const size_t n_state_size_cur = file.size() - file.tell();
3170
3171        llama_io_read_file io( &file);
3172        const size_t n_read = state_read_data(io);
3173
3174        if (n_read != n_state_size_cur) {
3175            LLAMA_LOG_ERROR("%s: did not read all of the session file data! size %zu, got %zu\n", __func__, n_state_size_cur, n_read);
3176            return false;
3177        }
3178    }
3179
3180    return true;
3181}
3182
3183bool llama_context::state_save_file(const char * filepath, const llama_token * tokens, size_t n_token_count) {
3184    llama_file file(filepath, "wb");
3185
3186    file.write_u32(LLAMA_SESSION_MAGIC);
3187    file.write_u32(LLAMA_SESSION_VERSION);
3188
3189    // save the prompt
3190    file.write_u32((uint32_t) n_token_count);
3191    file.write_raw(tokens, sizeof(llama_token) * n_token_count);
3192
3193    // save the context state using stream saving
3194    llama_io_write_file io(&file);
3195    state_write_data(io);
3196
3197    return true;
3198}
3199
3200size_t llama_context::state_seq_load_file(llama_seq_id seq_id, const char * filepath, llama_token * tokens_out, size_t n_token_capacity, size_t * n_token_count_out) {
3201    llama_file file(filepath, "rb");
3202
3203    // version checks
3204    {
3205        const uint32_t magic   = file.read_u32();
3206        const uint32_t version = file.read_u32();
3207
3208        if (magic != LLAMA_STATE_SEQ_MAGIC || version != LLAMA_STATE_SEQ_VERSION) {
3209            LLAMA_LOG_ERROR("%s: unknown (magic, version) for sequence state file: %08x, %08x\n", __func__, magic, version);
3210            return 0;
3211        }
3212    }
3213
3214    // load the prompt
3215    {
3216        const uint32_t n_token_count = file.read_u32();
3217
3218        if (tokens_out == nullptr) {
3219            const size_t n_token_max = (file.size() - file.tell()) / sizeof(llama_token);
3220            if (n_token_count > n_token_max) {
3221                LLAMA_LOG_ERROR("%s: token count in sequence state file exceeds the file size! %u > %zu\n", __func__, n_token_count, n_token_max);
3222                return 0;
3223            }
3224
3225            *n_token_count_out = n_token_count;
3226            return file.tell();
3227        }
3228
3229        if (n_token_count > n_token_capacity) {
3230            LLAMA_LOG_ERROR("%s: token count in sequence state file exceeded capacity! %u > %zu\n", __func__, n_token_count, n_token_capacity);
3231            return 0;
3232        }
3233
3234        file.read_raw(tokens_out, sizeof(llama_token) * n_token_count);
3235        *n_token_count_out = n_token_count;
3236    }
3237
3238    // restore the context state
3239    {
3240        const size_t state_size = file.size() - file.tell();
3241        llama_io_read_file io(&file);
3242        const size_t nread = state_seq_read_data(io, seq_id, 0);
3243        if (!nread) {
3244            LLAMA_LOG_ERROR("%s: failed to restore sequence state\n", __func__);
3245            return 0;
3246        }
3247        GGML_ASSERT(nread <= state_size);
3248        GGML_ASSERT(nread + sizeof(uint32_t) * 3 + sizeof(llama_token) * *n_token_count_out == file.tell());
3249    }
3250
3251    return file.tell();
3252}
3253
3254size_t llama_context::state_seq_save_file(llama_seq_id seq_id, const char * filepath, const llama_token * tokens, size_t n_token_count) {
3255    llama_file file(filepath, "wb");
3256
3257    file.write_u32(LLAMA_STATE_SEQ_MAGIC);
3258    file.write_u32(LLAMA_STATE_SEQ_VERSION);
3259
3260    // save the prompt
3261    file.write_u32((uint32_t) n_token_count);
3262    file.write_raw(tokens, sizeof(llama_token) * n_token_count);
3263
3264    // save the context state using stream saving
3265    llama_io_write_file io(&file);
3266    state_seq_write_data(io, seq_id, 0);
3267
3268    const size_t res = file.tell();
3269    GGML_ASSERT(res == sizeof(uint32_t) * 3 + sizeof(llama_token) * n_token_count + io.n_bytes());
3270
3271    return res;
3272}
3273
3274size_t llama_context::state_write_data(llama_io_write_i & io) {
3275    LLAMA_LOG_DEBUG("%s: writing state\n", __func__);
3276
3277    // write model info
3278    {
3279        LLAMA_LOG_DEBUG("%s: - writing model info\n", __func__);
3280
3281        const std::string arch_str = llm_arch_name(model.arch);
3282        io.write_string(arch_str);
3283        // TODO: add more model-specific info which should prevent loading the session file if not identical
3284    }
3285
3286    if (memory != nullptr) {
3287        LLAMA_LOG_DEBUG("%s: - writing memory module\n", __func__);
3288        memory->state_write(io);
3289    }
3290
3291    return io.n_bytes();
3292}
3293
3294size_t llama_context::state_read_data(llama_io_read_i & io) {
3295    LLAMA_LOG_DEBUG("%s: reading state\n", __func__);
3296
3297    // read model info
3298    {
3299        LLAMA_LOG_DEBUG("%s: - reading model info\n", __func__);
3300
3301        const std::string cur_arch_str = llm_arch_name(model.arch);
3302
3303        std::string arch_str;
3304        io.read_string(arch_str);
3305        if (cur_arch_str != arch_str) {
3306            throw std::runtime_error(format("wrong model arch: '%s' instead of '%s'", arch_str.c_str(), cur_arch_str.c_str()));
3307        }
3308        // TODO: add more info which needs to be identical but which is not verified otherwise
3309    }
3310
3311    if (memory) {
3312        LLAMA_LOG_DEBUG("%s: - reading memory module\n", __func__);
3313
3314        memory->state_read(io);
3315    }
3316
3317    return io.n_bytes();
3318}
3319
3320size_t llama_context::state_seq_write_data(llama_io_write_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) {
3321    if (memory) {
3322        memory->state_write(io, seq_id, flags);
3323    }
3324
3325    return io.n_bytes();
3326}
3327
3328size_t llama_context::state_seq_read_data(llama_io_read_i & io, llama_seq_id seq_id, llama_state_seq_flags flags) {
3329    if (memory) {
3330        memory->state_read(io, seq_id, flags);
3331    }
3332
3333    return io.n_bytes();
3334}
3335
3336//
3337// perf
3338//
3339
3340llama_perf_context_data llama_context::perf_get_data() const {
3341    llama_perf_context_data data = {};
3342
3343    data.t_start_ms  = 1e-3 * t_start_us;
3344    data.t_load_ms   = 1e-3 * t_load_us;
3345    data.t_p_eval_ms = 1e-3 * t_p_eval_us;
3346    data.t_eval_ms   = 1e-3 * t_eval_us;
3347    data.n_p_eval    = std::max(1, n_p_eval);
3348    data.n_eval      = std::max(1, n_eval);
3349    data.n_reused    = std::max(0, n_reused);
3350
3351    return data;
3352}
3353
3354void llama_context::perf_reset() {
3355    t_start_us  = ggml_time_us();
3356    t_eval_us   = n_eval = 0;
3357    t_p_eval_us = n_p_eval = 0;
3358    n_reused    = 0;
3359}
3360
3361llama_memory_breakdown llama_context::memory_breakdown() const {
3362    std::map<ggml_backend_buffer_type_t, llama_memory_breakdown_data> ret;
3363    for (const auto & [buft, size] : model.memory_breakdown()) {
3364        ret[buft].model += size;
3365    }
3366    if (memory) {
3367        for (const auto & [buft, size] : memory->memory_breakdown()) {
3368            ret[buft].context += size;
3369        }
3370    }
3371    if (model.hparams.no_alloc) {
3372        for (size_t i = 0; i < backends.size(); ++i) {
3373            ggml_backend_t             backend = backends[i].get();
3374            ggml_backend_buffer_type_t buft    = ggml_backend_sched_get_buffer_type(sched.get(), backend);
3375            ret[buft].compute += backend_buf_exp_size[i];
3376        }
3377    } else {
3378        for (const auto & backend_ptr : backends) {
3379            ggml_backend_t             backend = backend_ptr.get();
3380            ggml_backend_buffer_type_t buft    = ggml_backend_sched_get_buffer_type(sched.get(), backend);
3381            ret[buft].compute += ggml_backend_sched_get_buffer_size(sched.get(), backend);
3382        }
3383    }
3384    return ret;
3385}
3386
3387//
3388// training
3389//
3390
3391static void llama_set_param(struct ggml_tensor * tensor, llama_opt_param_filter param_filter, void * userdata) {
3392    if (!tensor || tensor->type != GGML_TYPE_F32) {
3393        return;
3394    }
3395    if (!param_filter(tensor, userdata)) {
3396        return;
3397    }
3398    if (strcmp(tensor->name, "token_embd.weight") == 0) {
3399        return; // FIXME
3400    }
3401    if (strcmp(tensor->name, "rope_freqs.weight") == 0) {
3402        return; // FIXME
3403    }
3404    ggml_set_param(tensor);
3405}
3406
3407void llama_context::opt_init(struct llama_model * model, struct llama_opt_params lopt_params) {
3408    GGML_ASSERT(!opt_ctx);
3409    model->hparams.n_ctx_train = lopt_params.n_ctx_train > 0 ? lopt_params.n_ctx_train : n_ctx();
3410    const uint32_t n_batch     = std::min(this->n_batch(),  model->hparams.n_ctx_train);
3411    const uint32_t n_ubatch    = std::min(this->n_ubatch(), n_batch);
3412    GGML_ASSERT(model->hparams.n_ctx_train % n_batch  == 0);
3413    GGML_ASSERT(n_batch                    % n_ubatch == 0);
3414
3415    if (cparams.flash_attn) {
3416        LLAMA_LOG_INFO("%s: disabling flash attention, FLASH_ATTN_EXT has no backward pass\n", __func__);
3417        cparams.flash_attn = false;
3418
3419        // the graph changes without flash attention, need to reserve again
3420        sched_need_reserve = true;
3421        sched_reserve();
3422    }
3423
3424    ggml_opt_params opt_params = ggml_opt_default_params(sched.get(), GGML_OPT_LOSS_TYPE_CROSS_ENTROPY);
3425    opt_params.opt_period      = n_batch / n_ubatch;
3426    opt_params.get_opt_pars    = lopt_params.get_opt_pars;
3427    opt_params.get_opt_pars_ud = lopt_params.get_opt_pars_ud;
3428    opt_params.optimizer       = lopt_params.optimizer_type;
3429    opt_ctx = ggml_opt_init(opt_params);
3430
3431    llama_opt_param_filter param_filter = lopt_params.param_filter;
3432    void * param_filter_ud              = lopt_params.param_filter_ud;
3433
3434  //llama_set_param(model->tok_embd,        param_filter, param_filter_ud); // FIXME
3435    llama_set_param(model->type_embd,       param_filter, param_filter_ud);
3436    llama_set_param(model->pos_embd,        param_filter, param_filter_ud);
3437    llama_set_param(model->tok_norm,        param_filter, param_filter_ud);
3438    llama_set_param(model->tok_norm_b,      param_filter, param_filter_ud);
3439    llama_set_param(model->output_norm,     param_filter, param_filter_ud);
3440    llama_set_param(model->output_norm_b,   param_filter, param_filter_ud);
3441    llama_set_param(model->output,          param_filter, param_filter_ud);
3442    llama_set_param(model->output_b,        param_filter, param_filter_ud);
3443    llama_set_param(model->output_norm_enc, param_filter, param_filter_ud);
3444    llama_set_param(model->cls,             param_filter, param_filter_ud);
3445    llama_set_param(model->cls_b,           param_filter, param_filter_ud);
3446    llama_set_param(model->cls_out,         param_filter, param_filter_ud);
3447    llama_set_param(model->cls_out_b,       param_filter, param_filter_ud);
3448    llama_set_param(model->cls_norm,        param_filter, param_filter_ud);
3449
3450    for (struct llama_layer & layer : model->layers) {
3451        for (size_t i = 0; i < sizeof(layer)/sizeof(struct ggml_tensor *); ++i) {
3452            llama_set_param(reinterpret_cast<struct ggml_tensor **>(&layer)[i], param_filter, param_filter_ud);
3453        }
3454    }
3455}
3456
3457void llama_context::opt_epoch_iter(
3458        ggml_opt_dataset_t               dataset,
3459        ggml_opt_result_t                result,
3460        const std::vector<llama_token> & tokens,
3461        const std::vector<llama_token> & labels_sparse,
3462        llama_batch                    & batch,
3463        ggml_opt_epoch_callback          callback,
3464        bool                             train,
3465        int64_t                          idata_in_loop,
3466        int64_t                          ndata_in_loop,
3467        int64_t                          t_loop_start) {
3468    GGML_ASSERT(opt_ctx);
3469    const uint32_t n_ctx    = llama_model_n_ctx_train(&model);
3470    const uint32_t n_batch  = std::min(this->n_batch(),  n_ctx);
3471    const uint32_t n_ubatch = std::min(this->n_ubatch(), n_batch);
3472
3473    memory->clear(true);
3474
3475    for (uint32_t pos_ctx = 0; pos_ctx < n_ctx; pos_ctx += n_batch) {
3476        batch.n_tokens = n_batch;
3477        for (uint32_t pos_batch = 0; pos_batch < n_batch; ++pos_batch) {
3478            batch.token   [pos_batch]    = tokens[pos_ctx + pos_batch];
3479            batch.pos     [pos_batch]    = pos_ctx + pos_batch;
3480            batch.n_seq_id[pos_batch]    = 1;
3481            batch.seq_id  [pos_batch][0] = 0;
3482            batch.logits  [pos_batch]    = true;
3483        }
3484
3485        if (!balloc->init(batch, model.vocab, nullptr, model.hparams.n_embd_inp(), cparams.kv_unified ? LLAMA_MAX_SEQ : cparams.n_seq_max, true)) {
3486            LLAMA_LOG_ERROR("%s: failed to initialize batch\n", __func__);
3487            return;
3488        }
3489
3490        const uint32_t n_tokens_all = balloc->get_n_tokens();
3491
3492        n_queued_tokens += n_tokens_all;
3493
3494        embd_seq.clear();
3495
3496        uint32_t n_outputs_all = n_tokens_all;
3497
3498        auto mctx = memory->init_batch(*balloc, cparams.n_ubatch, true);
3499        if (!mctx || mctx->get_status() != LLAMA_MEMORY_STATUS_SUCCESS) {
3500            LLAMA_LOG_ERROR("%s: could not initialize batch\n", __func__);
3501            break;
3502        }
3503
3504        // reserve output buffer
3505        if (output_reserve(n_outputs_all) < n_outputs_all) {
3506            LLAMA_LOG_ERROR("%s: could not reserve space for batch with %d outputs\n", __func__, n_outputs_all);
3507            GGML_ABORT("TODO: handle this error");
3508        };
3509
3510        uint32_t pos_batch = 0;
3511        do {
3512            const auto & ubatch = mctx->get_ubatch();
3513
3514            n_outputs = ubatch.n_tokens;
3515
3516            if (!mctx->apply()) {
3517                LLAMA_LOG_ERROR("%s: failed to update the memory context\n", __func__);
3518                break;
3519            }
3520
3521            auto * res = gf_res_prev.get();
3522
3523            const auto gparams = graph_params(res, ubatch, mctx.get(), ctx_type_to_graph_type(cparams.ctx_type));
3524
3525            res->reset();
3526
3527            auto * gf = model.build_graph(gparams);
3528
3529            struct ggml_context * ctx_compute_opt;
3530            {
3531                const size_t size_gf = ggml_graph_size(gf);
3532                const size_t size_meta = 4*size_gf*ggml_tensor_overhead() + 2*ggml_graph_overhead_custom(size_gf, /*grads = */ true);
3533                struct ggml_init_params params = {
3534                    /*.mem_size   =*/ size_meta,
3535                    /*.mem_buffer =*/ nullptr,
3536                    /*.no_alloc   =*/ true,
3537                };
3538                ctx_compute_opt = ggml_init(params);
3539            }
3540            ggml_opt_prepare_alloc(opt_ctx, ctx_compute_opt, gf, res->get_inp_tokens(), res->get_logits());
3541            ggml_opt_alloc(opt_ctx, train);
3542
3543            res->set_inputs(&ubatch);
3544            {
3545                struct ggml_tensor * labels = ggml_opt_labels(opt_ctx);
3546                GGML_ASSERT(labels->ne[1] == n_ubatch);
3547                ggml_set_zero(labels);
3548                const float onef = 1.0f;
3549                for (uint32_t pos_ubatch = 0; pos_ubatch < n_ubatch; ++pos_ubatch) {
3550                    const uint32_t ilabel = pos_ctx + pos_batch + pos_ubatch;
3551                    GGML_ASSERT(labels_sparse[ilabel] < labels->ne[0]);
3552                    ggml_backend_tensor_set(labels, &onef, (pos_ubatch*labels->ne[0] + labels_sparse[ilabel])*sizeof(float), sizeof(float));
3553                }
3554            }
3555            ggml_opt_eval(opt_ctx, result);
3556            if (callback) {
3557                callback(train, opt_ctx, dataset, result, idata_in_loop + (pos_ctx + pos_batch)/n_ubatch + 1, ndata_in_loop, t_loop_start);
3558            }
3559            ggml_free(ctx_compute_opt);
3560
3561            pos_batch += ubatch.n_tokens;
3562        } while (mctx->next());
3563    }
3564}
3565
3566void llama_context::opt_epoch(
3567        ggml_opt_dataset_t        dataset,
3568        ggml_opt_result_t         result_train,
3569        ggml_opt_result_t         result_eval,
3570        int64_t                   idata_split,
3571        ggml_opt_epoch_callback   callback_train,
3572        ggml_opt_epoch_callback   callback_eval) {
3573    const uint32_t n_ctx    = this->n_ctx();
3574    const uint32_t n_batch  = std::min(cparams.n_batch,  n_ctx);
3575    const uint32_t n_ubatch = std::min(cparams.n_ubatch, n_batch);
3576    const  int64_t ndata    = ggml_opt_dataset_ndata(dataset);
3577
3578    GGML_ASSERT(idata_split >= 0);
3579    GGML_ASSERT(idata_split <= ndata);
3580
3581    const uint32_t ubatch_per_ctx = n_ctx / n_ubatch;
3582
3583    struct llama_batch batch = llama_batch_init(n_batch, 0, 1);
3584    std::vector<llama_token>        tokens(n_ctx);
3585    std::vector<llama_token> labels_sparse(n_ctx);
3586
3587    int64_t idata = 0;
3588
3589    int64_t t_loop_start = ggml_time_us();
3590    int64_t ndata_in_loop = idata_split*ubatch_per_ctx;
3591    for (; idata < idata_split; ++idata) {
3592        constexpr bool train = true;
3593        const int64_t idata_in_loop = idata*ubatch_per_ctx;
3594
3595        ggml_opt_dataset_get_batch_host(dataset, tokens.data(), n_ctx*sizeof(llama_token), labels_sparse.data(), idata);
3596        opt_epoch_iter(dataset, result_train, tokens, labels_sparse, batch,
3597            callback_train, train, idata_in_loop, ndata_in_loop, t_loop_start);
3598    }
3599
3600    t_loop_start = ggml_time_us();
3601    ndata_in_loop = (ndata - idata_split)*ubatch_per_ctx;
3602    for (; idata < ndata; ++idata) {
3603        constexpr bool train = false;
3604        const int64_t idata_in_loop = (idata - idata_split)*ubatch_per_ctx;
3605
3606        ggml_opt_dataset_get_batch_host(dataset, tokens.data(), n_ctx*sizeof(llama_token), labels_sparse.data(), idata);
3607        opt_epoch_iter(dataset, result_eval, tokens, labels_sparse, batch,
3608            callback_eval, train, idata_in_loop, ndata_in_loop, t_loop_start);
3609    }
3610
3611    llama_batch_free(batch);
3612}
3613
3614//
3615// interface implementation
3616//
3617
3618llama_context_params llama_context_default_params() {
3619    llama_context_params result = {
3620        /*.n_ctx                       =*/ 512,
3621        /*.n_batch                     =*/ 2048,
3622        /*.n_ubatch                    =*/ 512,
3623        /*.n_seq_max                   =*/ 1,
3624        /*.n_rs_seq                    =*/ 0,
3625        /*.n_outputs_max               =*/ 0,
3626        /*.n_outputs_max_per_seq       =*/ 1,
3627        /*.n_threads                   =*/ GGML_DEFAULT_N_THREADS, // TODO: better default
3628        /*.n_threads_batch             =*/ GGML_DEFAULT_N_THREADS,
3629        /*.ctx_type                    =*/ LLAMA_CONTEXT_TYPE_DEFAULT,
3630        /*.rope_scaling_type           =*/ LLAMA_ROPE_SCALING_TYPE_UNSPECIFIED,
3631        /*.pooling_type                =*/ LLAMA_POOLING_TYPE_UNSPECIFIED,
3632        /*.attention_type              =*/ LLAMA_ATTENTION_TYPE_UNSPECIFIED,
3633        /*.flash_attn_type             =*/ LLAMA_FLASH_ATTN_TYPE_AUTO,
3634        /*.rope_freq_base              =*/ 0.0f,
3635        /*.rope_freq_scale             =*/ 0.0f,
3636        /*.yarn_ext_factor             =*/ -1.0f,
3637        /*.yarn_attn_factor            =*/ -1.0f,
3638        /*.yarn_beta_fast              =*/ -1.0f,
3639        /*.yarn_beta_slow              =*/ -1.0f,
3640        /*.yarn_orig_ctx               =*/ 0,
3641        /*.defrag_thold                =*/ -1.0f,
3642        /*.cb_eval                     =*/ nullptr,
3643        /*.cb_eval_user_data           =*/ nullptr,
3644        /*.type_k                      =*/ GGML_TYPE_F16,
3645        /*.type_v                      =*/ GGML_TYPE_F16,
3646        /*.abort_callback              =*/ nullptr,
3647        /*.abort_callback_data         =*/ nullptr,
3648        /*.embeddings                  =*/ false,
3649        /*.offload_kqv                 =*/ true,
3650        /*.no_perf                     =*/ true,
3651        /*.op_offload                  =*/ true,
3652        /*.swa_full                    =*/ true,
3653        /*.kv_unified                  =*/ false,
3654        /*.sampler                     =*/ nullptr,
3655        /*.n_sampler                   =*/ 0,
3656        /*.ctx_other                   =*/ nullptr,
3657    };
3658
3659    return result;
3660}
3661
3662llama_context * llama_init_from_model(
3663                 llama_model * model,
3664        llama_context_params   params) {
3665    if (!model) {
3666        LLAMA_LOG_ERROR("%s: model cannot be NULL\n", __func__);
3667        return nullptr;
3668    }
3669
3670    if (params.n_batch == 0 && params.n_ubatch == 0) {
3671        LLAMA_LOG_ERROR("%s: n_batch and n_ubatch cannot both be zero\n", __func__);
3672        return nullptr;
3673    }
3674
3675    if (params.n_ctx == 0 && model->hparams.n_ctx_train == 0) {
3676        LLAMA_LOG_ERROR("%s: n_ctx and model->hparams.n_ctx_train cannot both be zero\n", __func__);
3677        return nullptr;
3678    }
3679
3680    if (params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_DISABLED && model->arch == LLM_ARCH_GROK) {
3681        LLAMA_LOG_WARN("%s: flash_attn is not compatible with Grok - forcing off\n", __func__);
3682        params.flash_attn_type = LLAMA_FLASH_ATTN_TYPE_DISABLED;
3683    }
3684
3685    if (model->split_mode() == LLAMA_SPLIT_MODE_TENSOR) {
3686        if (params.flash_attn_type == LLAMA_FLASH_ATTN_TYPE_AUTO) {
3687            LLAMA_LOG_INFO("%s: enabling flash_attn since it is required for SPLIT_MODE_TENSOR\n", __func__);
3688            params.flash_attn_type = LLAMA_FLASH_ATTN_TYPE_ENABLED;
3689        }
3690        if (params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_ENABLED) {
3691            LLAMA_LOG_ERROR("%s: SPLIT_MODE_TENSOR requires flash_attn to be enabled\n", __func__);
3692            return nullptr;
3693        }
3694        if (model->get_split_state_ud.n_devices == 1) {
3695            LLAMA_LOG_WARN("%s: SPLIT_MODE_TENSOR being used for a single device is not recommended\n", __func__);
3696        }
3697    }
3698
3699    if ((model->hparams.is_mla() || model->arch == LLM_ARCH_DEEPSEEK4) && params.type_k != params.type_v) {
3700        LLAMA_LOG_ERROR("%s: model does not support different K (%s) and V (%s) cache types\n", __func__, ggml_type_name(params.type_k), ggml_type_name(params.type_v));
3701        return nullptr;
3702    }
3703
3704    if (ggml_is_quantized(params.type_v) && params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_ENABLED) {
3705        if (params.flash_attn_type == LLAMA_FLASH_ATTN_TYPE_AUTO) {
3706            LLAMA_LOG_INFO("%s: enabling flash_attn since it is required for quantized V cache\n", __func__);
3707            params.flash_attn_type = LLAMA_FLASH_ATTN_TYPE_ENABLED;
3708        }
3709        if (params.flash_attn_type == LLAMA_FLASH_ATTN_TYPE_DISABLED) {
3710            LLAMA_LOG_ERROR("%s: quantized V cache requires flash_attn to be enabled\n", __func__);
3711            return nullptr;
3712        }
3713    }
3714
3715    if (params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_DISABLED && ggml_is_quantized(params.type_k)) {
3716        const uint32_t blck_size = ggml_blck_size(params.type_k);
3717        for (uint32_t il = 0; il < model->hparams.n_layer(); ++il) {
3718            if (model->hparams.n_embd_head_k(il) % blck_size != 0) {
3719                LLAMA_LOG_ERROR("%s: K cache type %s with block size %u does not divide n_embd_head_k=%u\n",
3720                    __func__, ggml_type_name(params.type_k), blck_size, model->hparams.n_embd_head_k(il));
3721                return nullptr;
3722            }
3723        }
3724    }
3725
3726    if (params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_DISABLED && ggml_is_quantized(params.type_v)) {
3727        const uint32_t blck_size = ggml_blck_size(params.type_v);
3728        for (uint32_t il = 0; il < model->hparams.n_layer(); ++il) {
3729            if (model->hparams.n_embd_head_v(il) % blck_size != 0) {
3730                LLAMA_LOG_ERROR("%s: V cache type %s with block size %u does not divide n_embd_head_v=%u\n",
3731                    __func__, ggml_type_name(params.type_v), blck_size, model->hparams.n_embd_head_v(il));
3732                return nullptr;
3733            }
3734        }
3735    }
3736
3737    if (params.pooling_type != LLAMA_POOLING_TYPE_UNSPECIFIED &&
3738        params.pooling_type != model->hparams.pooling_type) {
3739        //user-specified pooling-type is different from the model default
3740        LLAMA_LOG_WARN("%s: model default pooling_type is [%d], but [%d] was specified\n", __func__,
3741                       model->hparams.pooling_type, params.pooling_type);
3742    }
3743
3744    // router_layer >= 0 means n_layer_nextn is repurposed for a router layer, not real MTP
3745    if (params.ctx_type == LLAMA_CONTEXT_TYPE_MTP &&
3746        (model->hparams.n_layer_nextn == 0 || model->hparams.router_layer >= 0)) {
3747        LLAMA_LOG_WARN("%s: context type MTP requested but model doesn't contain MTP layers\n", __func__);
3748        return nullptr;
3749    }
3750
3751    try {
3752        auto * ctx = new llama_context(*model, params);
3753        const auto & cparams = ctx->get_cparams();
3754
3755        if (cparams.rope_scaling_type == LLAMA_ROPE_SCALING_TYPE_YARN && cparams.rope_freq_scale != model->hparams.rope_freq_scale_train) {
3756            LLAMA_LOG_INFO("%s: custom YaRN scaling detected, re-adjusting n_ctx_train(%u)...\n", __func__, model->hparams.n_ctx_train);
3757            model->hparams.n_ctx_train = cparams.n_ctx_orig_yarn / cparams.rope_freq_scale;
3758            LLAMA_LOG_INFO("%s: n_ctx_train adjusted to %u\n", __func__, model->hparams.n_ctx_train);
3759        }
3760
3761        return ctx;
3762    } catch (const std::exception & err) {
3763        LLAMA_LOG_ERROR("%s: failed to initialize the context: %s\n", __func__, err.what());
3764    }
3765
3766    return nullptr;
3767}
3768
3769// deprecated
3770llama_context * llama_new_context_with_model(
3771                 llama_model * model,
3772        llama_context_params   params) {
3773    return llama_init_from_model(model, params);
3774}
3775
3776void llama_free(llama_context * ctx) {
3777    delete ctx;
3778}
3779
3780uint32_t llama_n_ctx(const llama_context * ctx) {
3781    return ctx->n_ctx();
3782}
3783
3784uint32_t llama_n_ctx_seq(const llama_context * ctx) {
3785    return ctx->n_ctx_seq();
3786}
3787
3788uint32_t llama_n_batch(const llama_context * ctx) {
3789    return ctx->n_batch();
3790}
3791
3792uint32_t llama_n_ubatch(const llama_context * ctx) {
3793    return ctx->n_ubatch();
3794}
3795
3796uint32_t llama_n_seq_max(const llama_context * ctx) {
3797    return ctx->n_seq_max();
3798}
3799
3800uint32_t llama_n_rs_seq(const llama_context * ctx) {
3801    return ctx->get_cparams().n_rs_seq;
3802}
3803
3804const llama_model * llama_get_model(const llama_context * ctx) {
3805    return &ctx->get_model();
3806}
3807
3808enum llama_pooling_type llama_pooling_type(const llama_context * ctx) {
3809    return ctx->pooling_type();
3810}
3811
3812void llama_attach_threadpool(
3813            llama_context * ctx,
3814        ggml_threadpool_t   threadpool,
3815        ggml_threadpool_t   threadpool_batch) {
3816    ctx->attach_threadpool(threadpool, threadpool_batch);
3817}
3818
3819void llama_detach_threadpool(llama_context * ctx) {
3820    ctx->detach_threadpool();
3821}
3822
3823void llama_set_n_threads(llama_context * ctx, int32_t n_threads, int32_t n_threads_batch) {
3824    ctx->set_n_threads(n_threads, n_threads_batch);
3825}
3826
3827int32_t llama_n_threads(llama_context * ctx) {
3828    return ctx->n_threads();
3829}
3830
3831int32_t llama_n_threads_batch(llama_context * ctx) {
3832    return ctx->n_threads_batch();
3833}
3834
3835void llama_set_abort_callback(llama_context * ctx, bool (*abort_callback)(void * data), void * abort_callback_data) {
3836    ctx->set_abort_callback(abort_callback, abort_callback_data);
3837}
3838
3839void llama_set_embeddings(llama_context * ctx, bool embeddings) {
3840    ctx->set_embeddings(embeddings);
3841}
3842
3843void llama_set_causal_attn(llama_context * ctx, bool causal_attn) {
3844    ctx->set_causal_attn(causal_attn);
3845}
3846
3847void llama_set_warmup(llama_context * ctx, bool warmup) {
3848    ctx->set_warmup(warmup);
3849}
3850
3851void llama_synchronize(llama_context * ctx) {
3852    ctx->synchronize();
3853}
3854
3855float * llama_get_logits(llama_context * ctx) {
3856    ctx->synchronize();
3857
3858    return ctx->get_logits();
3859}
3860
3861float * llama_get_logits_ith(llama_context * ctx, int32_t i) {
3862    ctx->synchronize();
3863
3864    float * res = nullptr;
3865
3866    res = ctx->get_sampled_logits_ith(i);
3867
3868    if (!res) {
3869        res = ctx->get_logits_ith(i);
3870    }
3871
3872    return res;
3873}
3874
3875float * llama_get_embeddings(llama_context * ctx) {
3876    ctx->synchronize();
3877
3878    return ctx->get_embeddings();
3879}
3880
3881float * llama_get_embeddings_ith(llama_context * ctx, int32_t i) {
3882    ctx->synchronize();
3883
3884    return ctx->get_embeddings_ith(i);
3885}
3886
3887float * llama_get_embeddings_seq(llama_context * ctx, llama_seq_id seq_id) {
3888    ctx->synchronize();
3889
3890    return ctx->get_embeddings_seq(seq_id);
3891}
3892
3893void llama_set_embeddings_nextn(llama_context * ctx, bool value, bool masked) {
3894    ctx->set_embeddings_nextn(value, masked);
3895}
3896
3897void llama_set_embeddings_layer_inp(llama_context * ctx, uint32_t lid, bool value) {
3898    ctx->set_embeddings_layer_inp(lid, value);
3899}
3900
3901void llama_set_nextn_layer_offset(llama_context * ctx, int32_t offset) {
3902    ctx->set_nextn_layer_offset(offset);
3903}
3904
3905llama_memory_t llama_get_memory(const struct llama_context * ctx) {
3906    if (!ctx) {
3907        return nullptr;
3908    }
3909
3910    return ctx->get_memory();
3911}
3912
3913float * llama_get_embeddings_nextn(llama_context * ctx) {
3914    ctx->synchronize();
3915
3916    return ctx->get_embeddings_nextn();
3917}
3918
3919float * llama_get_embeddings_nextn_ith(llama_context * ctx, int32_t i) {
3920    ctx->synchronize();
3921
3922    return ctx->get_embeddings_nextn_ith(i);
3923}
3924
3925float * llama_get_embeddings_layer_inp(llama_context * ctx, uint32_t lid) {
3926    ctx->synchronize();
3927
3928    return ctx->get_embeddings_layer_inp(lid);
3929}
3930
3931bool llama_set_sampler(llama_context * ctx, llama_seq_id seq_id, llama_sampler * smpl) {
3932    return ctx->set_sampler(seq_id, smpl);
3933}
3934
3935llama_token llama_get_sampled_token_ith(llama_context * ctx, int32_t i) {
3936    ctx->synchronize();
3937
3938    return ctx->get_sampled_token_ith(i);
3939}
3940
3941float * llama_get_sampled_probs_ith(llama_context * ctx, int32_t i) {
3942    ctx->synchronize();
3943
3944    return ctx->get_sampled_probs_ith(i);
3945}
3946
3947float * llama_get_sampled_logits_ith(llama_context * ctx, int32_t i) {
3948    ctx->synchronize();
3949
3950    return ctx->get_sampled_logits_ith(i);
3951}
3952
3953llama_token * llama_get_sampled_candidates_ith(llama_context * ctx, int32_t i) {
3954    ctx->synchronize();
3955
3956    return const_cast<llama_token *>(ctx->get_sampled_candidates_ith(i));
3957}
3958
3959uint32_t llama_get_sampled_candidates_count_ith(llama_context * ctx, int32_t i) {
3960    ctx->synchronize();
3961
3962    return static_cast<uint32_t>(ctx->get_sampled_candidates_count(i));
3963}
3964
3965uint32_t llama_get_sampled_logits_count_ith(llama_context * ctx, int32_t i) {
3966    ctx->synchronize();
3967
3968    return static_cast<uint32_t>(ctx->get_sampled_logits_count(i));
3969}
3970
3971uint32_t llama_get_sampled_probs_count_ith(llama_context * ctx, int32_t i) {
3972    ctx->synchronize();
3973
3974    return static_cast<uint32_t>(ctx->get_sampled_probs_count(i));
3975}
3976
3977struct ggml_cgraph * llama_graph_reserve(
3978        struct llama_context * ctx,
3979        uint32_t n_tokens,
3980        uint32_t n_seqs,
3981        uint32_t n_outputs) {
3982    auto memory = ctx->get_memory();
3983    llama_memory_context_ptr mctx;
3984    if (memory) {
3985        mctx = memory->init_full();
3986    }
3987    return ctx->graph_reserve(n_tokens, n_seqs, n_outputs, mctx.get());
3988}
3989
3990// llama adapter API
3991
3992int32_t llama_set_adapters_lora(
3993            llama_context * ctx,
3994            llama_adapter_lora ** adapters,
3995            size_t n_adapters,
3996            float * scales) {
3997    if (adapters == nullptr || scales == nullptr) {
3998        GGML_ASSERT(n_adapters == 0 && "invalid llama_set_adapters_lora call");
3999    }
4000
4001    ctx->set_adapters_lora(adapters, n_adapters, scales);
4002
4003    return 0;
4004}
4005
4006int32_t llama_set_adapter_cvec(
4007        llama_context * ctx,
4008          const float * data,
4009               size_t   len,
4010              int32_t   n_embd,
4011              int32_t   il_start,
4012              int32_t   il_end) {
4013    bool res = ctx->set_adapter_cvec(data, len, n_embd, il_start, il_end);
4014
4015    return res ? 0 : -1;
4016}
4017
4018//
4019// memory
4020//
4021
4022void llama_memory_clear(llama_memory_t mem, bool data) {
4023    if (!mem) {
4024        return;
4025    }
4026
4027    mem->clear(data);
4028}
4029
4030bool llama_memory_seq_rm(
4031        llama_memory_t mem,
4032          llama_seq_id seq_id,
4033             llama_pos p0,
4034             llama_pos p1) {
4035    if (!mem) {
4036        return true;
4037    }
4038
4039    return mem->seq_rm(seq_id, p0, p1);
4040}
4041
4042void llama_memory_seq_cp(
4043        llama_memory_t mem,
4044          llama_seq_id seq_id_src,
4045          llama_seq_id seq_id_dst,
4046             llama_pos p0,
4047             llama_pos p1) {
4048    if (!mem) {
4049        return;
4050    }
4051
4052    mem->seq_cp(seq_id_src, seq_id_dst, p0, p1);
4053}
4054
4055void llama_memory_seq_keep(
4056        llama_memory_t mem,
4057          llama_seq_id seq_id) {
4058    if (!mem) {
4059        return;
4060    }
4061
4062    mem->seq_keep(seq_id);
4063}
4064
4065void llama_memory_seq_add(
4066        llama_memory_t mem,
4067          llama_seq_id seq_id,
4068             llama_pos p0,
4069             llama_pos p1,
4070             llama_pos delta) {
4071    if (!mem) {
4072        return;
4073    }
4074
4075    mem->seq_add(seq_id, p0, p1, delta);
4076}
4077
4078void llama_memory_seq_div(
4079        llama_memory_t mem,
4080          llama_seq_id seq_id,
4081             llama_pos p0,
4082             llama_pos p1,
4083                   int d) {
4084    if (!mem) {
4085        return;
4086    }
4087
4088    mem->seq_div(seq_id, p0, p1, d);
4089}
4090
4091llama_pos llama_memory_seq_pos_min(
4092        llama_memory_t mem,
4093          llama_seq_id seq_id) {
4094    if (!mem) {
4095        return -1;
4096    }
4097
4098    return mem->seq_pos_min(seq_id);
4099}
4100
4101llama_pos llama_memory_seq_pos_max(
4102        llama_memory_t mem,
4103          llama_seq_id seq_id) {
4104    if (!mem) {
4105        return -1;
4106    }
4107
4108    return mem->seq_pos_max(seq_id);
4109}
4110
4111bool llama_memory_can_shift(llama_memory_t mem) {
4112    if (!mem) {
4113        return false;
4114    }
4115
4116    return mem->get_can_shift();
4117}
4118
4119// llama state API
4120
4121// deprecated
4122size_t llama_get_state_size(llama_context * ctx) {
4123    return llama_state_get_size(ctx);
4124}
4125
4126// deprecated
4127size_t llama_copy_state_data(llama_context * ctx, uint8_t * dst) {
4128    return llama_state_get_data(ctx, dst, -1);
4129}
4130
4131// deprecated
4132size_t llama_set_state_data(llama_context * ctx, const uint8_t * src) {
4133    return llama_state_set_data(ctx, src, -1);
4134}
4135
4136// deprecated
4137bool llama_load_session_file(llama_context * ctx, const char * path_session, llama_token * tokens_out, size_t n_token_capacity, size_t * n_token_count_out) {
4138    return llama_state_load_file(ctx, path_session, tokens_out, n_token_capacity, n_token_count_out);
4139}
4140
4141// deprecated
4142bool llama_save_session_file(llama_context * ctx, const char * path_session, const llama_token * tokens, size_t n_token_count) {
4143    return llama_state_save_file(ctx, path_session, tokens, n_token_count);
4144}
4145
4146// Returns the *actual* size of the state.
4147// Intended to be used when saving to state to a buffer.
4148size_t llama_state_get_size(llama_context * ctx) {
4149    return ctx->state_get_size();
4150}
4151
4152size_t llama_state_get_data(llama_context * ctx, uint8_t * dst, size_t size) {
4153    ctx->synchronize();
4154
4155    return ctx->state_get_data(dst, size);
4156}
4157
4158// Sets the state reading from the specified source address
4159size_t llama_state_set_data(llama_context * ctx, const uint8_t * src, size_t size) {
4160    ctx->synchronize();
4161
4162    return ctx->state_set_data(src, size);
4163}
4164
4165bool llama_state_load_file(llama_context * ctx, const char * path_session, llama_token * tokens_out, size_t n_token_capacity, size_t * n_token_count_out) {
4166    ctx->synchronize();
4167
4168    try {
4169        return ctx->state_load_file(path_session, tokens_out, n_token_capacity, n_token_count_out);
4170    } catch (const std::exception & err) {
4171        LLAMA_LOG_ERROR("%s: error loading session file: %s\n", __func__, err.what());
4172        return false;
4173    }
4174}
4175
4176bool llama_state_save_file(llama_context * ctx, const char * path_session, const llama_token * tokens, size_t n_token_count) {
4177    ctx->synchronize();
4178
4179    try {
4180        return ctx->state_save_file(path_session, tokens, n_token_count);
4181    } catch (const std::exception & err) {
4182        LLAMA_LOG_ERROR("%s: error saving session file: %s\n", __func__, err.what());
4183        return false;
4184    }
4185}
4186
4187size_t llama_state_seq_get_size(llama_context * ctx, llama_seq_id seq_id) {
4188    return llama_state_seq_get_size_ext(ctx, seq_id, 0);
4189}
4190
4191size_t llama_state_seq_get_data(llama_context * ctx, uint8_t * dst, size_t size, llama_seq_id seq_id) {
4192    return llama_state_seq_get_data_ext(ctx, dst, size, seq_id, 0);
4193}
4194
4195size_t llama_state_seq_set_data(llama_context * ctx, const uint8_t * src, size_t size, llama_seq_id seq_id) {
4196    return llama_state_seq_set_data_ext(ctx, src, size, seq_id, 0);
4197}
4198
4199size_t llama_state_seq_get_size_ext(llama_context * ctx, llama_seq_id seq_id, llama_state_seq_flags flags) {
4200    return ctx->state_seq_get_size(seq_id, flags);
4201}
4202
4203size_t llama_state_seq_get_data_ext(llama_context * ctx, uint8_t * dst, size_t size, llama_seq_id seq_id, llama_state_seq_flags flags) {
4204    ctx->synchronize();
4205
4206    return ctx->state_seq_get_data(seq_id, dst, size, flags);
4207}
4208size_t llama_state_seq_set_data_ext(llama_context * ctx, const uint8_t * src, size_t size, llama_seq_id seq_id, llama_state_seq_flags flags) {
4209    ctx->synchronize();
4210
4211    return ctx->state_seq_set_data(seq_id, src, size, flags);
4212}
4213
4214size_t llama_state_seq_save_file(llama_context * ctx, const char * filepath, llama_seq_id seq_id, const llama_token * tokens, size_t n_token_count) {
4215    ctx->synchronize();
4216
4217    try {
4218        return ctx->state_seq_save_file(seq_id, filepath, tokens, n_token_count);
4219    } catch (const std::exception & err) {
4220        LLAMA_LOG_ERROR("%s: error saving sequence state file: %s\n", __func__, err.what());
4221        return 0;
4222    }
4223}
4224
4225size_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) {
4226    ctx->synchronize();
4227
4228    try {
4229        return ctx->state_seq_load_file(dest_seq_id, filepath, tokens_out, n_token_capacity, n_token_count_out);
4230    } catch (const std::exception & err) {
4231        LLAMA_LOG_ERROR("%s: error loading sequence state file: %s\n", __func__, err.what());
4232        return 0;
4233    }
4234}
4235
4236///
4237
4238int32_t llama_encode(
4239        llama_context * ctx,
4240          llama_batch   batch) {
4241    const int ret = ctx->encode(batch);
4242    if (ret != 0) {
4243        LLAMA_LOG_ERROR("%s: failed to encode, ret = %d\n", __func__, ret);
4244    }
4245
4246    return ret;
4247}
4248
4249int32_t llama_decode(
4250        llama_context * ctx,
4251          llama_batch   batch) {
4252    const int ret = ctx->decode(batch);
4253    if (ret != 0 && ret != 1) {
4254        LLAMA_LOG_ERROR("%s: failed to decode, ret = %d\n", __func__, ret);
4255    }
4256
4257    return ret;
4258}
4259
4260//
4261// perf
4262//
4263
4264llama_perf_context_data llama_perf_context(const llama_context * ctx) {
4265    llama_perf_context_data data = {};
4266
4267    if (ctx == nullptr) {
4268        return data;
4269    }
4270
4271    data = ctx->perf_get_data();
4272
4273    return data;
4274}
4275
4276void llama_perf_context_print(const llama_context * ctx) {
4277    const auto data = llama_perf_context(ctx);
4278
4279    const double t_end_ms = 1e-3 * ggml_time_us();
4280
4281    LLAMA_LOG_INFO("%s:        load time = %10.2f ms\n", __func__, data.t_load_ms);
4282    LLAMA_LOG_INFO("%s: prompt eval time = %10.2f ms / %5d tokens (%8.2f ms per token, %8.2f tokens per second)\n",
4283            __func__, data.t_p_eval_ms, data.n_p_eval, data.t_p_eval_ms / data.n_p_eval, 1e3 / data.t_p_eval_ms * data.n_p_eval);
4284    LLAMA_LOG_INFO("%s:        eval time = %10.2f ms / %5d runs   (%8.2f ms per token, %8.2f tokens per second)\n",
4285            __func__, data.t_eval_ms, data.n_eval, data.t_eval_ms / data.n_eval, 1e3 / data.t_eval_ms * data.n_eval);
4286    LLAMA_LOG_INFO("%s:       total time = %10.2f ms / %5d tokens\n", __func__, (t_end_ms - data.t_start_ms), (data.n_p_eval + data.n_eval));
4287    LLAMA_LOG_INFO("%s:    graphs reused = %10d\n", __func__, data.n_reused);
4288}
4289
4290void llama_perf_context_reset(llama_context * ctx) {
4291    ctx->perf_reset();
4292}
4293
4294//
4295// training
4296//
4297
4298bool llama_opt_param_filter_all(const struct ggml_tensor * tensor, void * userdata) {
4299    GGML_UNUSED(tensor);
4300    GGML_UNUSED(userdata);
4301    return true;
4302}
4303
4304void llama_opt_init(struct llama_context * ctx, struct llama_model * model, struct llama_opt_params lopt_params) {
4305    ctx->opt_init(model, lopt_params);
4306}
4307
4308void llama_opt_epoch(
4309        struct llama_context    * ctx,
4310        ggml_opt_dataset_t        dataset,
4311        ggml_opt_result_t         result_train,
4312        ggml_opt_result_t         result_eval,
4313        int64_t                   idata_split,
4314        ggml_opt_epoch_callback   callback_train,
4315        ggml_opt_epoch_callback   callback_eval) {
4316    ctx->opt_epoch(
4317        dataset,
4318        result_train,
4319        result_eval,
4320        idata_split,
4321        callback_train,
4322        callback_eval);
4323}
4324
4325//
4326// ext
4327//
4328
4329llama_memory_breakdown llama_get_memory_breakdown(const struct llama_context * ctx) {
4330    return ctx->memory_breakdown();
4331}
4332
4333llama_context * llama_get_ctx_other(struct llama_context * ctx) {
4334    return ctx->get_cparams().ctx_other;
4335}