char-fork/llama.cpp

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

Daniel Beveniuscommon : fix typo in speculative.cpp comment [no ci] (#28750)1dfe94e04

char/aliceai-t5-moe
114.4 KiB2997 linesraw
1#include "speculative.h"
2
3#include "common.h"
4#include "ggml.h"
5#include "ggml-cpp.h"
6#include "llama.h"
7#include "log.h"
8#include "ngram-cache.h"
9#include "ngram-map.h"
10#include "ngram-mod.h"
11#include "sampling.h"
12
13#include "../src/llama-ext.h" // staging API: llama_set_embeddings_nextn / llama_get_embeddings_nextn_ith (used by MTP)
14
15#include <algorithm>
16#include <cassert>
17#include <cmath>
18#include <cstring>
19#include <iomanip>
20#include <map>
21#include <cinttypes>
22
23#define SPC_DBG(fmt, ...) LOG_DBG("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
24#define SPC_TRC(fmt, ...) LOG_TRC("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
25#define SPC_INF(fmt, ...) LOG_INF("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
26#define SPC_WRN(fmt, ...) LOG_WRN("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
27#define SPC_ERR(fmt, ...) LOG_ERR("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
28#define SPC_CNT(fmt, ...) LOG_CNT(""              fmt,               __VA_ARGS__)
29
30#define SPEC_VOCAB_MAX_SIZE_DIFFERENCE  128
31#define SPEC_VOCAB_CHECK_START_TOKEN_ID 5
32
33const std::map<std::string, common_speculative_type> common_speculative_type_from_name_map = {
34    {"none",          COMMON_SPECULATIVE_TYPE_NONE},
35    {"draft-simple",  COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE},
36    {"draft-eagle3",  COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3},
37    {"draft-mtp",     COMMON_SPECULATIVE_TYPE_DRAFT_MTP},
38    {"draft-dflash",  COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH},
39    {"draft-dspark",  COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK},
40    {"ngram-simple",  COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE},
41    {"ngram-map-k",   COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K},
42    {"ngram-map-k4v", COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V},
43    {"ngram-mod",     COMMON_SPECULATIVE_TYPE_NGRAM_MOD},
44    {"ngram-cache",   COMMON_SPECULATIVE_TYPE_NGRAM_CACHE}
45};
46
47static std::string common_speculative_get_devices_str(const std::vector<ggml_backend_dev_t> & devices) {
48    std::string result;
49    for (size_t i = 0; i < devices.size(); i++) {
50        if (devices[i] == nullptr) {
51            continue;
52        }
53        if (!result.empty()) result += ", ";
54        result += ggml_backend_dev_name(devices[i]);
55    }
56    return result.empty() ? "default" : result;
57}
58
59struct common_speculative_config {
60    common_speculative_type type;
61    common_params_speculative params;
62
63    common_speculative_config(common_speculative_type t,
64            const common_params_speculative & p = common_params_speculative{}) : type(t), params(p) {}
65};
66
67static bool common_speculative_are_compatible(
68    const llama_model * model_tgt,
69    const llama_model * model_dft) {
70    const llama_vocab * vocab_tgt = llama_model_get_vocab(model_tgt);
71    const llama_vocab * vocab_dft = llama_model_get_vocab(model_dft);
72
73    const auto vocab_type_tgt = llama_vocab_type(vocab_tgt);
74    SPC_DBG("vocab_type tgt: %d\n", vocab_type_tgt);
75
76    const auto vocab_type_dft = llama_vocab_type(vocab_dft);
77    SPC_DBG("vocab_type dft: %d\n", vocab_type_dft);
78
79    if (vocab_type_tgt != vocab_type_dft) {
80        SPC_WRN("draft model vocab type must match target model to use speculation but "
81                "vocab_type_dft = %d while vocab_type_tgt = %d\n", vocab_type_dft, vocab_type_tgt);
82        return false;
83    }
84
85    if (llama_vocab_get_add_bos(vocab_tgt) != llama_vocab_get_add_bos(vocab_dft) ||
86        (llama_vocab_get_add_bos(vocab_tgt) && llama_vocab_bos(vocab_tgt) != llama_vocab_bos(vocab_dft))) {
87        SPC_WRN("draft model bos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n",
88                llama_vocab_get_add_bos(vocab_tgt), llama_vocab_get_add_bos(vocab_dft),
89                llama_vocab_bos(vocab_tgt), llama_vocab_bos(vocab_dft));
90        return false;
91    }
92
93    if (llama_vocab_get_add_eos(vocab_tgt) != llama_vocab_get_add_eos(vocab_dft) ||
94        (llama_vocab_get_add_eos(vocab_tgt) && llama_vocab_eos(vocab_tgt) != llama_vocab_eos(vocab_dft))) {
95        SPC_WRN("draft model eos tokens must match target model to use speculation. add: %d - %d, id: %d - %d)\n",
96                llama_vocab_get_add_eos(vocab_tgt), llama_vocab_get_add_eos(vocab_dft),
97                llama_vocab_eos(vocab_tgt), llama_vocab_eos(vocab_dft));
98        return false;
99    }
100
101    {
102        const int n_vocab_tgt = llama_vocab_n_tokens(vocab_tgt);
103        const int n_vocab_dft = llama_vocab_n_tokens(vocab_dft);
104        const int vocab_diff  = n_vocab_tgt > n_vocab_dft
105            ? n_vocab_tgt - n_vocab_dft
106            : n_vocab_dft - n_vocab_tgt;
107
108        if (vocab_diff > SPEC_VOCAB_MAX_SIZE_DIFFERENCE) {
109            SPC_DBG("draft model vocab must closely match target model to use speculation but "
110                    "target vocab size %d does not match draft vocab size %d - difference %d, max allowed %d\n",
111                    n_vocab_tgt, llama_vocab_n_tokens(vocab_dft), vocab_diff, SPEC_VOCAB_MAX_SIZE_DIFFERENCE);
112            return false;
113        }
114
115        for (int i = SPEC_VOCAB_CHECK_START_TOKEN_ID; i < std::min(n_vocab_tgt, n_vocab_dft); ++i) {
116            const char * token_text_tgt = llama_vocab_get_text(vocab_tgt, i);
117            const char * token_text_dft = llama_vocab_get_text(vocab_dft, i);
118
119            if (std::strcmp(token_text_tgt, token_text_dft) != 0) {
120                SPC_DBG("draft model vocab must match target model to use speculation but "
121                        "token %d content differs - target '%s', draft '%s'\n", i,
122                        common_token_to_piece(vocab_tgt, i).c_str(),
123                        common_token_to_piece(vocab_dft, i).c_str());
124                return false;
125            }
126        }
127    }
128
129    return true;
130}
131
132using common_speculative_draft_params_vec = std::vector<common_speculative_draft_params>;
133
134// state of an implementation of speculative decoding
135//
136// each implementation has a unique type and a state that is implementation-specific
137// in a subclass of common_speculative_impl
138struct common_speculative_impl {
139    const common_speculative_type type;
140
141    uint32_t n_seq;
142    int32_t n_max; // maximum draft length after implementation-specific limits
143
144    size_t n_call_begin  = 0; // number of times this implementation was called for refresh.
145    size_t n_call_draft  = 0; // number of times this implementation was called for generation.
146    size_t n_call_accept = 0; // number of times this implementation was called for accumulation.
147
148    size_t n_gen_drafts = 0; // number of times a draft or part was generated by this implementation.
149    size_t n_acc_drafts = 0; // number of times a draft or part was accepted by the target model.
150    size_t n_gen_tokens = 0; // number of tokens generated by this implementation.
151    size_t n_acc_tokens = 0; // number of tokens accepted by the target model.
152
153    std::vector<size_t> n_acc_tokens_per_pos; // number of tokens accepted per draft position.
154
155    // TODO: track performance of most recent calls
156    const bool gen_perf = true; // whether to generate performance stats.
157
158    int64_t t_begin_us  = 0; // total time spent in refresh of this implementation in microseconds.
159    int64_t t_draft_us  = 0; // total time spent in generating drafts in this implementation in microseconds.
160    int64_t t_accept_us = 0; // total time spent in accumulation of this implementation in microseconds.
161
162    common_speculative_impl(common_speculative_type type, uint32_t n_seq, int32_t n_max) : type(type), n_seq(n_seq), n_max(n_max) {}
163
164    virtual ~common_speculative_impl() = default;
165
166    virtual void begin(llama_seq_id seq_id, const llama_tokens & prompt) = 0;
167
168    virtual bool process(const llama_batch & batch) = 0;
169
170    virtual void draft(common_speculative_draft_params_vec & dparams) = 0;
171
172    virtual void accept(llama_seq_id seq_id, uint16_t n_accepted, bool is_other) = 0;
173
174    // (optional) serialize/restore per-seq internal state (e.g. eagle3's deferred boundary).
175    virtual bool get_state(llama_seq_id /*seq_id*/, std::vector<uint8_t> & /*data*/) const { return false; }
176    virtual void set_state(llama_seq_id /*seq_id*/, const std::vector<uint8_t> & /*data*/) {}
177};
178
179struct common_speculative_impl_draft_simple : public common_speculative_impl {
180    common_params_speculative_draft params;
181
182    llama_batch batch;
183
184    std::vector<common_sampler_ptr> smpls;
185
186    common_speculative_impl_draft_simple(const common_params_speculative & params, uint32_t n_seq)
187        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE, n_seq, params.draft.n_max)
188        , params(params.draft)
189    {
190        auto * ctx_dft = this->params.ctx_dft;
191        auto * ctx_tgt = this->params.ctx_tgt;
192
193        if (!ctx_dft) {
194            throw std::runtime_error("draft-simple requires a draft context");
195        }
196
197        SPC_TRC("%s", "adding speculative implementation 'draft-simple'\n");
198        SPC_TRC("- n_max=%d, n_min=%d, p_min=%f\n", this->params.n_max, this->params.n_min, this->params.p_min);
199        SPC_TRC("- gpu_layers=%d, cache_k=%s, cache_v=%s, ctx_tgt=%s, ctx_dft=%s, devices=[%s]\n",
200                this->params.n_gpu_layers,
201                ggml_type_name(this->params.cache_type_k),
202                ggml_type_name(this->params.cache_type_v),
203                ctx_tgt ? "yes" : "no",
204                ctx_dft ? "yes" : "no",
205                common_speculative_get_devices_str(this->params.devices).c_str());
206
207        batch = llama_batch_init(llama_n_batch(ctx_dft), 0, 1);
208
209        // TODO: optimize or pass from outside?
210        // {
211        //     common_params_sampling params;
212        //     params.no_perf = false;
213        //
214        //     params.top_k = 40;
215        //     params.top_p = 0.9;
216        //
217        //     params.samplers = {
218        //         COMMON_SAMPLER_TYPE_TOP_K,
219        //         COMMON_SAMPLER_TYPE_TOP_P,
220        //         COMMON_SAMPLER_TYPE_INFILL,
221        //     };
222        //
223        //     result->smpl = common_sampler_init(llama_get_model(ctx_dft), params);
224        // }
225
226        smpls.resize(n_seq);
227        for (auto & smpl : smpls) {
228            common_params_sampling params;
229            params.no_perf = false;
230            params.top_k = 10;
231            params.samplers = {
232                COMMON_SAMPLER_TYPE_TOP_K,
233            };
234
235            smpl.reset(common_sampler_init(llama_get_model(ctx_dft), params));
236        }
237
238        const bool vocab_cmpt = common_speculative_are_compatible(llama_get_model(ctx_tgt), llama_get_model(ctx_dft));
239        SPC_DBG("vocab_cmpt = %d\n", vocab_cmpt);
240
241        if (!vocab_cmpt) {
242            SPC_ERR("%s", "the target and draft vocabs are not compatible\n");
243
244            throw std::runtime_error("draft model vocab type must match target model to use speculation");
245        }
246
247        if (n_seq != llama_n_seq_max(ctx_dft)) {
248            SPC_ERR("n_seq mismatch: %d != %d\n", n_seq, llama_n_seq_max(ctx_dft));
249
250            throw std::runtime_error("the draft model number of sequences is incompatible with the speculative n_seq");
251        }
252    }
253
254    ~common_speculative_impl_draft_simple() override {
255        llama_batch_free(batch);
256    }
257
258    void begin(llama_seq_id /*seq_id*/, const llama_tokens & /*prompt*/) override {
259        // noop
260    }
261
262    bool process(const llama_batch & batch) override {
263        auto * ctx_dft = params.ctx_dft;
264
265        llama_batch batch_dft = batch;
266        batch_dft.logits = nullptr;
267
268        const int ret = llama_decode(ctx_dft, batch_dft);
269
270        if (ret != 0) {
271            SPC_ERR("failed to decode draft batch, ret = %d\n", ret);
272
273            return false;
274        }
275
276        return true;
277    }
278
279    void draft(common_speculative_draft_params_vec & dparams) override {
280        auto & ctx_dft = params.ctx_dft;
281
282        common_batch_clear(batch);
283
284        // keep track of which sequences are still drafting
285        int n_drafting = 0;
286        std::vector<bool> drafting(n_seq);
287
288        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
289            auto & dp = dparams[seq_id];
290
291            if (!dp.drafting) {
292                continue;
293            }
294
295            n_drafting++;
296            drafting[seq_id] = true;
297            common_sampler_reset(smpls[seq_id].get());
298
299            common_batch_add(batch, dp.id_last, dp.pos0, { seq_id }, true);
300        }
301
302        int ret = llama_decode(ctx_dft, batch);
303        if (ret != 0) {
304            SPC_ERR("llama_decode returned %d\n", ret);
305            return;
306        }
307
308        int i = 0;
309
310        while (n_drafting > 0) {
311            int i_batch = 0;
312
313            common_batch_clear(batch);
314
315            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
316                if (!drafting[seq_id]) {
317                    continue;
318                }
319
320                auto * smpl = smpls[seq_id].get();
321
322                common_sampler_sample(smpl, ctx_dft, i_batch, true);
323                ++i_batch;
324
325                const auto * cur_p = common_sampler_get_candidates(smpl, true);
326
327                for (int k = 0; k < std::min(3, (int) cur_p->size); ++k) {
328                    SPC_DBG(" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n",
329                            seq_id, k, i, cur_p->data[k].id, cur_p->data[k].p,
330                            common_token_to_piece(ctx_dft, cur_p->data[k].id).c_str());
331                }
332
333                // add drafted token for each sequence
334                const llama_token id = cur_p->data[0].id;
335
336                // only collect very high-confidence draft tokens
337                if (cur_p->data[0].p < params.p_min) {
338                    drafting[seq_id] = false;
339                    n_drafting--;
340
341                    continue;
342                }
343
344                common_sampler_accept(smpl, id, true);
345
346                auto & dp = dparams.at(seq_id);
347                auto & result = *dp.result;
348
349                result.push_back(id);
350
351                if ((params.n_max <= (int) result.size()) ||
352                    (dp.n_max > 0 && dp.n_max <= (int) result.size())) {
353                    drafting[seq_id] = false;
354                    n_drafting--;
355                    continue;
356                }
357
358                common_batch_add(batch, id, dp.pos0 + i + 1, { seq_id }, true);
359            }
360
361            if (batch.n_tokens == 0) {
362                break;
363            }
364
365            // evaluate the drafted tokens on the draft model
366            ret = llama_decode(ctx_dft, batch);
367            if (ret != 0) {
368                SPC_ERR("llama_decode[%d] returned %d\n", i, ret);
369                break;
370            }
371
372            ++i;
373        }
374
375        for (auto & dp : dparams) {
376            if (!dp.drafting) {
377                continue;
378            }
379
380            if (dp.result->size() < (size_t) params.n_min) {
381                dp.result->clear();
382            }
383        }
384    }
385
386    void accept(llama_seq_id /*seq_id*/, uint16_t /*n_accepted*/, bool /*is_other*/) override {
387        // noop
388    }
389};
390
391
392// EAGLE3 speculative decoding state
393//
394// Input of draft decoder: (This is different compared to MTP)
395//   At "pos P", the decoder takes input pair (t_{P+1}, g_P), with RoPE at P.
396//     - t_{P+1} = token at sequence pos P+1 (the *next* token after P)
397//     - g_P     = encoder output = projection of target's extracted hidden states at P
398//
399// Deferred boundary (MTP doesn't have this issue):
400//   Within a single process() call with n_tokens, we can only write decoder KV for
401//   training pos 0..n_tokens-2. The last training pos (n_tokens-1) needs t_{n_tokens}
402//   which lies *outside* this batch — it is the token target will sample next or the first token from next ubatch.
403//   So the last training pos of each process() call is *deferred* to whichever next call has
404//   the missing token in hand:
405//     - multi-ubatch prefill: the next process()'s first token completes the pair
406//                              (handled by the per-seq "cross-ubatch bridge")
407//     - single-ubatch prefill / after verify: draft()'s seed step uses "dp.id_last"
408//                              (target's freshest sample) to complete the pair
409//
410// Per-seq carry-over state:
411//   pending_g_last    [n_embd_dec]  ┐  the deferred boundary's (g, pos). Set by
412//   pending_pos_last  llama_pos     ┘  process() at end of ubatch (= last row);
413//                                       rebased by accept() to first-non-accepted pos.
414//   verify_g          [N × n_embd_dec] snapshot of process()'s encoder output;
415//   verify_pos_first  llama_pos         consumed by accept() to recover the right
416//   verify_g_rows     int32_t           pending_g_last row for any n_accepted value.
417//
418// Performance is overall good but there is waste in verify cycle:
419//   process() runs encoder + decoder on the *full* verify batch including rows for
420//   rejected drafts. The KV at those positions is then dropped.
421//
422// TODO: Not sure if we need optimization for this waste?
423// If so we may need hybrid stash:
424//      in verify mode, have process() only stash features and let draft() seed run
425//      encoder+decoder on n_accepted+1 rows).
426struct common_speculative_impl_draft_eagle3 : public common_speculative_impl {
427    common_params_speculative_draft params;
428    llama_batch batch;
429
430    std::vector<common_sampler_ptr> smpls;
431
432    // backend sampler chain per seq, attached to ctx_dft
433    std::vector<llama_sampler *> backend_chains;
434
435    int32_t n_embd_dec = 0;       // draft hidden size
436    int32_t n_embd_enc = 0;       // target_layer_ids_n * target_hidden_size
437    int32_t n_embd_tgt = 0;       // target model hidden size
438    int32_t n_layer_tgt = 0;      // target model layer count
439
440    const int32_t * target_layer_ids   = nullptr; // model_dft's extract layer indices
441    uint32_t        target_layer_ids_n = 0;
442
443    // [per-seq] deferred boundary state
444    std::vector<std::vector<float>> pending_g_last;
445    std::vector<llama_pos>          pending_pos_last;
446
447    // [per-seq] snapshot of the most recent process()'s encoder output
448    std::vector<std::vector<float>> verify_g;         // [n_seq][n_rows * n_embd_dec]
449    std::vector<llama_pos>          verify_pos_first; // [n_seq] — pos of verify_g[seq][0]
450    std::vector<int32_t>            verify_g_rows;    // [n_seq] — number of rows
451
452    // scratch buffer for concatenated target features [n_tokens, n_embd_enc]
453    std::vector<float> features_buf;
454    std::vector<float> g_embd_buf;
455
456    common_speculative_impl_draft_eagle3(const common_params_speculative & params, uint32_t n_seq)
457        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, n_seq, params.draft.n_max)
458        , params(params.draft)
459    {
460        SPC_TRC("%s", "adding speculative implementation 'draft-eagle3'\n");
461        SPC_TRC("- n_max=%d, n_min=%d, p_min=%f, backend_sampling=%d\n", params.draft.n_max, params.draft.n_min, params.draft.p_min, (int) params.draft.backend_sampling);
462
463        auto * ctx_tgt = this->params.ctx_tgt;
464        auto * ctx_dft = this->params.ctx_dft;
465        GGML_ASSERT(ctx_tgt && ctx_dft && "EAGLE3 requires ctx_tgt and ctx_dft to be set");
466
467        const llama_model * model_dft = llama_get_model(ctx_dft);
468        const llama_model * model_tgt = llama_get_model(ctx_tgt);
469
470        target_layer_ids   = llama_model_target_layer_ids  (model_dft);
471        target_layer_ids_n = llama_model_target_layer_ids_n(model_dft);
472        if (target_layer_ids_n != 3) {
473            throw std::runtime_error("draft model is not eagle3 (expected 3 extract layers, got " +
474                                     std::to_string(target_layer_ids_n) + ")");
475        }
476
477        n_embd_tgt = llama_model_n_embd(model_tgt);
478        n_embd_dec = llama_model_n_embd(model_dft);
479        n_embd_enc = (int32_t) target_layer_ids_n * n_embd_tgt;
480        n_layer_tgt = llama_model_n_layer(model_tgt);
481
482        const int32_t n_b = (int32_t) llama_n_batch(ctx_dft);
483        batch = llama_batch_init(/*n_tokens=*/ n_b, /*embd=*/ n_embd_dec, /*n_seq_max=*/ 1);
484        // llama_batch_init allocates only one of token/embd; eagle3 decoder needs both.
485        // TODO: fix, how to call without malloc
486        batch.token = (llama_token *) malloc(sizeof(llama_token) * n_b);
487
488        smpls.resize(n_seq);
489        for (auto & s : smpls) {
490            common_params_sampling sparams;
491            sparams.no_perf  = false;
492            sparams.top_k    = 10;
493            sparams.samplers = { COMMON_SAMPLER_TYPE_TOP_K };
494            s.reset(common_sampler_init(llama_get_model(ctx_dft), sparams));
495        }
496
497        // offload draft sampling to the backend
498        backend_chains.assign(n_seq, nullptr);
499        if (this->params.backend_sampling) {
500            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
501                llama_sampler * chain = llama_sampler_chain_init(llama_sampler_chain_default_params());
502                llama_sampler_chain_add(chain, llama_sampler_init_top_k(10));
503
504                if (!llama_set_sampler(ctx_dft, seq_id, chain)) {
505                    SPC_WRN("backend offload failed for seq_id=%d; using CPU sampler\n", (int) seq_id);
506                    llama_sampler_free(chain);
507                    chain = nullptr;
508                }
509                backend_chains[seq_id] = chain;
510            }
511        }
512
513        // turn on extraction of the target layers' hidden states
514        for (uint32_t k = 0; k < target_layer_ids_n; ++k) {
515            if (target_layer_ids[k] < n_layer_tgt) {
516                llama_set_embeddings_layer_inp(ctx_tgt, (uint32_t) target_layer_ids[k], true);
517            } else if (target_layer_ids[k] == n_layer_tgt) {
518                llama_set_embeddings_nextn(ctx_tgt, true, /*masked*/ false);
519            } else {
520                GGML_ABORT("EAGLE3: target layer id %d exceeds target n_layer %d", target_layer_ids[k], n_layer_tgt);
521            }
522        }
523
524        // turn on extraction of the draft model's pre-norm hidden state
525        // (used both for the encoder output g_embd and the decoder pre-norm output).
526        llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ true);
527
528        pending_g_last.assign(n_seq, std::vector<float>(n_embd_dec, 0.0f));
529        pending_pos_last.assign(n_seq, -1);
530
531        verify_g.assign(n_seq, std::vector<float>());
532        verify_pos_first.assign(n_seq, -1);
533        verify_g_rows.assign(n_seq, 0);
534    }
535
536    ~common_speculative_impl_draft_eagle3() override {
537        auto * ctx_dft = this->params.ctx_dft;
538        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) backend_chains.size(); ++seq_id) {
539            if (backend_chains[seq_id] == nullptr) {
540                continue;
541            }
542            if (ctx_dft) {
543                llama_set_sampler(ctx_dft, seq_id, nullptr);
544            }
545            llama_sampler_free(backend_chains[seq_id]);
546        }
547        backend_chains.clear();
548
549        if (batch.token != nullptr) {
550            free(batch.token);
551            batch.token = nullptr;
552        }
553        llama_batch_free(batch);
554    }
555
556    void begin(llama_seq_id seq_id, const llama_tokens & prompt) override {
557        const int32_t N = (int32_t) prompt.size();
558        if (N <= 0) {
559            return;
560        }
561        // expected state after prefill: ctx_dft has pos 0..N-2 (last position is deferred to
562        // draft()'s seed step). Warn only if more than one position is missing.
563        auto * ctx_dft = this->params.ctx_dft;
564        const llama_pos pos_max = llama_memory_seq_pos_max(llama_get_memory(ctx_dft), seq_id);
565        if (pos_max < N - 2) {
566            SPC_WRN("ctx_dft pos_max=%d < N-2=%d — process() did not run on every prefill ubatch. "
567                    "Drafts may degrade.\n",
568                    (int) pos_max, N - 2);
569        }
570    }
571
572    bool process(const llama_batch & batch_in) override {
573        if (batch_in.n_tokens <= 0) {
574            return true;
575        }
576
577        if (batch_in.token == nullptr || batch_in.embd != nullptr) {
578            return true;
579        }
580
581        const int32_t n_tokens = batch_in.n_tokens;
582
583        // i_batch_beg[seq] / i_batch_end[seq]: inclusive batch indices of this seq's
584        // first/last token in batch_in. Assumes per-seq tokens are contiguous within
585        // the ubatch (server's default ordering).
586        std::vector<int32_t> i_batch_beg(n_seq, -1);
587        std::vector<int32_t> i_batch_end(n_seq, -1);
588        for (int k = 0; k < n_tokens; ++k) {
589            GGML_ASSERT(batch_in.n_seq_id[k] == 1);
590            const llama_seq_id seq_id = batch_in.seq_id[k][0];
591            if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
592                continue;
593            }
594            i_batch_end[seq_id] = k;
595            if (i_batch_beg[seq_id] < 0) {
596                i_batch_beg[seq_id] = k;
597            }
598        }
599
600        auto * ctx_tgt = this->params.ctx_tgt;
601        auto * ctx_dft = this->params.ctx_dft;
602
603        // Interleave each extract_layer's hidden state into a contiguous buffer of
604        // shape [n_tokens, target_layer_ids_n * n_embd_tgt]. Then run EAGLE3 encoder
605        // to get one g_embd row per token.
606        features_buf.resize((size_t) n_tokens * n_embd_enc, 0.0f);
607
608        for (uint32_t k = 0; k < target_layer_ids_n; ++k) {
609            const float * layer = target_layer_ids[k] < n_layer_tgt
610                ? llama_get_embeddings_layer_inp(ctx_tgt, (uint32_t) target_layer_ids[k])
611                : llama_get_embeddings_nextn(ctx_tgt);
612            if (!layer) {
613                GGML_ABORT("EAGLE3: target layer %d input not extracted.", target_layer_ids[k]);
614            }
615            for (int32_t i = 0; i < n_tokens; ++i) {
616                float * dst = features_buf.data() + (size_t) i * n_embd_enc + k * (size_t) n_embd_tgt;
617                const float * src = layer + (size_t) i * n_embd_tgt;
618                std::memcpy(dst, src, (size_t) n_embd_tgt * sizeof(float));
619            }
620        }
621
622        g_embd_buf.resize((size_t) n_tokens * n_embd_dec);
623
624        // llama_encode() requires the full encoder batch to fit in n_ubatch.
625        // Allow batch > ubatch: eagle3's per-token encoder can be chunked safely.
626        const int32_t n_ubatch_dft = (int32_t) llama_n_ubatch(ctx_dft);
627        for (int32_t i = 0; i < n_tokens; i += n_ubatch_dft) {
628            const int32_t n_chunk = std::min(n_ubatch_dft, n_tokens - i);
629
630            llama_batch enc_batch = {
631                /*.n_tokens =*/ n_chunk,
632                /*.token    =*/ nullptr,
633                /*.embd     =*/ features_buf.data() + (size_t) i * n_embd_enc,
634                /*.pos      =*/ nullptr,
635                /*.n_seq_id =*/ nullptr,
636                /*.seq_id   =*/ nullptr,
637                /*.logits   =*/ nullptr,
638            };
639            const int32_t rc = llama_encode(ctx_dft, enc_batch);
640            if (rc != 0) {
641                SPC_ERR("llama_encode(ctx_dft) failed rc=%d (n_tokens=%d, offset=%d)\n",
642                        rc, (int) n_chunk, (int) i);
643                return false;
644            }
645
646            // g_embd has shape [n_chunk, n_embd_dec] in ctx_dft's pre-norm embeddings buffer.
647            const float * g_embd_chunk = llama_get_embeddings_nextn(ctx_dft);
648            GGML_ASSERT(g_embd_chunk && "EAGLE3 encoder produced no output.");
649            std::memcpy(g_embd_buf.data() + (size_t) i * n_embd_dec,
650                        g_embd_chunk,
651                        (size_t) n_chunk * n_embd_dec * sizeof(float));
652        }
653
654        const float * g_embd = g_embd_buf.data();
655
656        const size_t row_bytes = (size_t) n_embd_dec * sizeof(float);
657
658        // EAGLE3 decoder input convention: at memory pos P the input pair is
659        // (token[P+1], g_embd[P]). This shifts the token index "left by one" relative to g_embd.
660        //
661        // Per seq, in order:
662        //   (a) cross-ubatch bridge — when applicable, write the previously-deferred
663        //       pos using this ubatch's first token + pending_g_last.
664        //   (b) main write loop — for k in [beg, end-1], write (token[k+1], g_embd[k])
665        //       at pos[k]. The last training pos (k=end) is left unwritten = new
666        //       deferred boundary, completed by the next process() or draft() call.
667        //   (c) refresh deferred state — stash this ubatch's full g_embd into verify_g,
668        //       update pending_g_last / pending_pos_last to the last row.
669        common_batch_clear(batch);
670
671        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
672            const int32_t beg = i_batch_beg[seq_id];
673            const int32_t end = i_batch_end[seq_id];
674            if (beg < 0 || end < 0) {
675                continue;
676            }
677
678            // cross-ubatch bridge — complete the prior ubatch's deferred boundary.
679            // Fires iff all three preconditions hold:
680            //   1) pending_pos_last >= 0
681            //   2) pending_pos_last + 1 == pos[beg]
682            //   3) pending_pos_last > dft_pos_max // TODO: is this check needed?
683            const llama_pos pending_pos = pending_pos_last[seq_id];
684            if (pending_pos >= 0 && pending_pos + 1 == batch_in.pos[beg]) {
685                const llama_pos dft_pos_max = llama_memory_seq_pos_max(llama_get_memory(ctx_dft), seq_id);
686                if (pending_pos > dft_pos_max) {
687                    common_batch_add(batch, batch_in.token[beg], pending_pos, { seq_id }, /*logits=*/ false);
688                    std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd_dec,
689                                pending_g_last[seq_id].data(), row_bytes);
690                }
691            }
692
693            for (int32_t k = beg; k < end; ++k) {
694                common_batch_add(batch, batch_in.token[k + 1], batch_in.pos[k], { seq_id }, /*logits=*/ false);
695                std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd_dec,
696                            g_embd + (size_t) k * n_embd_dec, row_bytes);
697            }
698
699            // refresh deferred state
700            const int32_t n_rows = end - beg + 1;
701            verify_pos_first[seq_id] = batch_in.pos[beg];
702            pending_pos_last[seq_id] = batch_in.pos[end];
703            verify_g_rows[seq_id]    = n_rows;
704            verify_g[seq_id].resize((size_t) n_rows * n_embd_dec, 0.0f);
705            std::memcpy(verify_g[seq_id].data(),       g_embd + (size_t) beg * n_embd_dec, row_bytes * n_rows);
706            std::memcpy(pending_g_last[seq_id].data(), g_embd + (size_t) end * n_embd_dec, row_bytes);
707        }
708
709        if (batch.n_tokens > 0) {
710            const int32_t rc = llama_decode(ctx_dft, batch);
711            if (rc != 0) {
712                SPC_ERR("llama_decode(ctx_dft) failed rc=%d (n_tokens=%d, ubatch_pos[0]=%d)\n",
713                        rc, (int) batch.n_tokens, (int) batch_in.pos[0]);
714                return false;
715            }
716        }
717
718        return true;
719    }
720
721    void draft(common_speculative_draft_params_vec & dparams) override {
722        auto & ctx_dft = params.ctx_dft;
723
724        common_batch_clear(batch);
725
726        // keep track of which sequences are still drafting
727        int n_drafting = 0;
728        std::vector<bool> drafting(n_seq);
729
730        const size_t row_bytes = (size_t) n_embd_dec * sizeof(float);
731
732        // Complete the deferred boundary pair (dp.id_last, pending_g_last) at memory
733        // pos pending_pos_last. dp.id_last is target's freshest sample (= corrected
734        // token after verify, or first generated token after prefill), matching the
735        // EAGLE3 input convention (token[P+1], g_embd[P]) at pos P.
736        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
737            auto & dp = dparams[seq_id];
738
739            if (!dp.drafting) {
740                continue;
741            }
742            if (pending_pos_last[seq_id] < 0) {
743                continue;
744            }
745
746            n_drafting++;
747            drafting[seq_id] = true;
748            common_sampler_reset(smpls[seq_id].get());
749
750            llama_memory_seq_rm(llama_get_memory(ctx_dft), seq_id, pending_pos_last[seq_id], -1);
751
752            common_batch_add(batch, dp.id_last, pending_pos_last[seq_id], { seq_id }, true);
753            std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd_dec,
754                        pending_g_last[seq_id].data(),
755                        row_bytes);
756        }
757
758        if (batch.n_tokens == 0) {
759            return;
760        }
761
762        int ret = llama_decode(ctx_dft, batch);
763        if (ret != 0) {
764            SPC_ERR("llama_decode returned %d\n", ret);
765            return;
766        }
767
768        int i = 0;
769
770        while (n_drafting > 0) {
771            int i_batch = 0;
772
773            common_batch_clear(batch);
774
775            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
776                if (!drafting[seq_id]) {
777                    continue;
778                }
779
780                auto * smpl = smpls[seq_id].get();
781
782                common_sampler_sample(smpl, ctx_dft, i_batch, true);
783                // pre-norm hidden state of this position becomes g_embd for the next step
784                const float * prenorm = llama_get_embeddings_nextn_ith(ctx_dft, i_batch);
785                ++i_batch;
786
787                const auto * cur_p = common_sampler_get_candidates(smpl, true);
788
789                for (int k = 0; k < std::min(3, (int) cur_p->size); ++k) {
790                    SPC_DBG(" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n",
791                            seq_id, k, i, cur_p->data[k].id, cur_p->data[k].p,
792                            common_token_to_piece(ctx_dft, cur_p->data[k].id).c_str());
793                }
794
795                const llama_token id = cur_p->data[0].id;
796
797                // only collect very high-confidence draft tokens
798                // (configurable via --spec-draft-p-min, set to 0.0 to disable early-stop)
799                if (cur_p->data[0].p < params.p_min) {
800                    drafting[seq_id] = false;
801                    n_drafting--;
802
803                    continue;
804                }
805
806                common_sampler_accept(smpl, id, true);
807
808                auto & dp = dparams.at(seq_id);
809                auto & result = *dp.result;
810
811                result.push_back(id);
812
813                if (params.n_max <= (int) result.size()) {
814                    drafting[seq_id] = false;
815                    n_drafting--;
816                    continue;
817                }
818
819                common_batch_add(batch, id, pending_pos_last[seq_id] + (i + 1), { seq_id }, true);
820                std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd_dec, prenorm, row_bytes);
821            }
822
823            if (batch.n_tokens == 0) {
824                break;
825            }
826
827            ret = llama_decode(ctx_dft, batch);
828            if (ret != 0) {
829                SPC_ERR("llama_decode[%d] returned %d\n", i, ret);
830                break;
831            }
832
833            ++i;
834        }
835
836        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
837            auto & dp = dparams[seq_id];
838            if (!dp.drafting) {
839                continue;
840            }
841
842            if (dp.result->size() < (size_t) params.n_min) {
843                dp.result->clear();
844            }
845        }
846    }
847
848    void accept(llama_seq_id seq_id, uint16_t n_accepted, bool /*is_other*/) override {
849        if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
850            return;
851        }
852
853        const int32_t n_rows = verify_g_rows[seq_id];
854        if (n_rows <= 0) {
855            return;
856        }
857
858        const int32_t i_g = std::min<int32_t>(n_accepted, n_rows - 1);
859        pending_pos_last[seq_id] = verify_pos_first[seq_id] + i_g;
860        std::memcpy(pending_g_last[seq_id].data(),
861                    verify_g[seq_id].data() + (size_t) i_g * n_embd_dec,
862                    (size_t) n_embd_dec * sizeof(float));
863    }
864
865    // we only need to stash the deferred boundary's g_embd row for recurrent/hybrid targets:
866    // their single-position checkpoints drop it on restore
867    bool need_boundary_stash() const {
868        const llama_model * model_tgt = llama_get_model(params.ctx_tgt);
869        return llama_model_is_recurrent(model_tgt) || llama_model_is_hybrid(model_tgt);
870    }
871
872    bool get_state(llama_seq_id seq_id, std::vector<uint8_t> & data) const override {
873        if (!need_boundary_stash()) {
874            return false;
875        }
876        if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq || pending_pos_last[seq_id] < 0) {
877            return false;
878        }
879
880        const llama_pos          pos = pending_pos_last[seq_id];
881        const std::vector<float> & g = pending_g_last[seq_id];
882
883        data.resize(sizeof(llama_pos) + g.size() * sizeof(float));
884        std::memcpy(data.data(),                     &pos,     sizeof(llama_pos));
885        std::memcpy(data.data() + sizeof(llama_pos), g.data(), g.size() * sizeof(float));
886        return true;
887    }
888
889    void set_state(llama_seq_id seq_id, const std::vector<uint8_t> & data) override {
890        if (!need_boundary_stash()) {
891            return;
892        }
893        if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
894            return;
895        }
896        if (data.size() != sizeof(llama_pos) + (size_t) n_embd_dec * sizeof(float)) {
897            return;
898        }
899
900        llama_pos pos = -1;
901        std::memcpy(&pos, data.data(), sizeof(llama_pos));
902
903        pending_pos_last[seq_id] = pos;
904        pending_g_last[seq_id].resize(n_embd_dec);
905        std::memcpy(pending_g_last[seq_id].data(), data.data() + sizeof(llama_pos), (size_t) n_embd_dec * sizeof(float));
906    }
907};
908
909// DFlash: block-diffusion drafting with a draft-side KV cache injection
910struct common_speculative_impl_draft_dflash : public common_speculative_impl {
911    common_params_speculative_draft params;
912
913    llama_batch batch;        // noise tokens
914    llama_batch batch_inject; // target features for KV cache injection
915
916    std::vector<common_sampler_ptr> smpls;
917
918    // backend sampler chain per seq, attached to ctx_dft
919    std::vector<llama_sampler *> backend_chains;
920
921    int32_t n_embd_dec = 0;  // draft hidden size
922    int32_t n_embd_enc = 0;  // target_layer_ids_n * target_hidden_size
923    int32_t n_embd_tgt = 0;  // target model hidden size
924
925    int32_t     block_size    = 0;
926    llama_token mask_token_id = 0;
927
928    bool    is_dflash2     = false;
929    bool    is_mrope       = false;
930    int32_t selector_top_k = 0;
931
932    // draft-dspark: the draft carries a Markov head and uses an anchor-first block layout
933    const bool is_dspark;
934
935    // dspark speculators
936    bool sample_from_anchor = true;
937
938    // block-internal attention
939    bool causal_attn = false;
940
941    const int32_t * target_layer_ids   = nullptr; // model_dft's extract layer indices
942    uint32_t        target_layer_ids_n = 0;
943
944    common_speculative_impl_draft_dflash(const common_params_speculative & params, uint32_t n_seq,
945            common_speculative_type type = COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH)
946        : common_speculative_impl(type, n_seq, params.draft.n_max)
947        , params(params.draft)
948        , is_dspark(type == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK)
949    {
950        auto * ctx_tgt = this->params.ctx_tgt;
951        auto * ctx_dft = this->params.ctx_dft;
952        GGML_ASSERT(ctx_tgt && ctx_dft && "DFlash requires ctx_tgt and ctx_dft to be set");
953
954        const llama_model * model_dft = llama_get_model(ctx_dft);
955        const llama_model * model_tgt = llama_get_model(ctx_tgt);
956
957        target_layer_ids   = llama_model_target_layer_ids  (model_dft);
958        target_layer_ids_n = llama_model_target_layer_ids_n(model_dft);
959        GGML_ASSERT(target_layer_ids_n > 0 && "DFlash model has no target_layer_ids");
960
961        n_embd_tgt    = llama_model_n_embd(model_tgt);
962        n_embd_dec    = llama_model_n_embd(model_dft);
963        n_embd_enc    = (int32_t) target_layer_ids_n * n_embd_tgt;
964
965        // read the trained block size from the dflash.block_size metadata key
966        block_size = 16;
967        {
968            char buf[32] = {};
969            if (llama_model_meta_val_str(model_dft, "dflash.block_size", buf, sizeof(buf)) >= 0) {
970                block_size = std::atoi(buf);
971            }
972            if (llama_model_meta_val_str(model_dft, "dflash.sample_from_anchor", buf, sizeof(buf)) >= 0) {
973                sample_from_anchor = std::strcmp(buf, "true") == 0;
974            }
975            if (llama_model_meta_val_str(model_dft, "dflash.attention.causal", buf, sizeof(buf)) >= 0) {
976                causal_attn = std::strcmp(buf, "true") == 0;
977            }
978        }
979
980        selector_top_k = llama_model_dflash_selector_top_k(model_dft);
981        is_dflash2     = selector_top_k > 0;
982        mask_token_id = llama_vocab_mask(llama_model_get_vocab(model_dft));
983
984        if (is_dspark && this->params.p_min > 0.0f) {
985            char buf[16] = {};
986            const bool has_conf =
987                llama_model_meta_val_str(model_dft, "dflash.has_confidence_head", buf, sizeof(buf)) < 0 ||
988                std::strcmp(buf, "true") == 0;
989            if (!has_conf) {
990                throw std::runtime_error("DSpark draft has no confidence head: please set --spec-draft-p-min 0");
991            }
992        }
993
994        LOG_INF("%s: adding speculative implementation '%s'\n", __func__, common_speculative_type_to_str(type).c_str());
995        LOG_INF("%s: - n_max=%d, n_min=%d, p_min=%.2f\n", __func__, this->params.n_max, this->params.n_min, this->params.p_min);
996        LOG_INF("%s: - block_size=%d, mask_token_id=%d, n_extract=%u, sample_from_anchor=%s\n", __func__,
997                block_size, mask_token_id, target_layer_ids_n, sample_from_anchor ? "true" : "false");
998
999        // DFlash input is [id_last, <mask> * (block_size-1)]: in-place denoising yields at most
1000        // block_size-1 draft tokens, anchor-first DSpark yields a full block_size draft tokens
1001        const int32_t n_draft_max = is_dspark && sample_from_anchor ? block_size : block_size - 1;
1002        if (this->params.n_max > n_draft_max || this->params.n_min > n_draft_max) {
1003            LOG_WRN("%s: requested draft size (n_max=%d, n_min=%d) exceeds the trained block size %d -- clamping to %d\n",
1004                    __func__, this->params.n_max, this->params.n_min, block_size, n_draft_max);
1005            this->params.n_max = std::min(this->params.n_max, n_draft_max);
1006            this->params.n_min = std::min(this->params.n_min, n_draft_max);
1007        }
1008        this->n_max = this->params.n_max;
1009
1010        batch        = llama_batch_init(llama_n_batch(ctx_dft), 0,          n_seq);
1011        batch_inject = llama_batch_init(llama_n_ubatch(ctx_dft), n_embd_enc, n_seq);
1012
1013        // embd batches on an M-RoPE draft need 4 position rows per token
1014        is_mrope = llama_model_rope_type(model_dft) == LLAMA_ROPE_TYPE_MROPE;
1015        if (is_mrope) {
1016            free(batch_inject.pos);
1017            batch_inject.pos = (llama_pos *) malloc(sizeof(llama_pos) * 4 * llama_n_batch(ctx_dft));
1018        }
1019
1020        smpls.resize(n_seq);
1021        for (auto & s : smpls) {
1022            common_params_sampling sparams;
1023            sparams.no_perf  = false;
1024            sparams.top_k    = 10;
1025            sparams.samplers = { COMMON_SAMPLER_TYPE_TOP_K };
1026            s.reset(common_sampler_init(model_dft, sparams));
1027        }
1028
1029        // offload draft sampling to the backend
1030        backend_chains.assign(n_seq, nullptr);
1031        if (this->params.backend_sampling && !is_dflash2) {
1032            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1033                llama_sampler * chain = llama_sampler_chain_init(llama_sampler_chain_default_params());
1034                llama_sampler_chain_add(chain, llama_sampler_init_top_k(10));
1035
1036                if (!llama_set_sampler(ctx_dft, seq_id, chain)) {
1037                    SPC_WRN("backend offload failed for seq_id=%d; using CPU sampler\n", (int) seq_id);
1038                    llama_sampler_free(chain);
1039                    chain = nullptr;
1040                }
1041                backend_chains[seq_id] = chain;
1042            }
1043        }
1044
1045        // turn on extraction of the target layers' input embeddings
1046        for (uint32_t k = 0; k < target_layer_ids_n; ++k) {
1047            llama_set_embeddings_layer_inp(ctx_tgt, (uint32_t) target_layer_ids[k], true);
1048        }
1049
1050        // DFlash2 reads its selector lattice from h_nextn and never consumes raw logits.
1051        llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ !is_dflash2);
1052        llama_set_causal_attn(ctx_dft, causal_attn); // DFlash needs non-causal attention unless the model says otherwise
1053    }
1054
1055    ~common_speculative_impl_draft_dflash() override {
1056        auto * ctx_dft = this->params.ctx_dft;
1057        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) backend_chains.size(); ++seq_id) {
1058            if (backend_chains[seq_id] == nullptr) {
1059                continue;
1060            }
1061            if (ctx_dft) {
1062                llama_set_sampler(ctx_dft, seq_id, nullptr);
1063            }
1064            llama_sampler_free(backend_chains[seq_id]);
1065        }
1066        backend_chains.clear();
1067
1068        llama_batch_free(batch);
1069        llama_batch_free(batch_inject);
1070    }
1071
1072    void begin(llama_seq_id seq_id, const llama_tokens & prompt) override {
1073        if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
1074            return;
1075        }
1076
1077        const int32_t N = (int32_t) prompt.size();
1078        if (N <= 0) {
1079            return;
1080        }
1081
1082        const llama_pos pos_max = llama_memory_seq_pos_max(llama_get_memory(params.ctx_dft), seq_id);
1083        if (pos_max < N - 1) {
1084            LOG_WRN("%s: ctx_dft pos_max=%d < N-1=%d - process() did not run on every prefill ubatch. "
1085                    "Drafts may degrade.\n",
1086                    __func__, (int) pos_max, N - 1);
1087        }
1088    }
1089
1090    bool process(const llama_batch & batch_in) override {
1091        if (batch_in.n_tokens <= 0) {
1092            return true;
1093        }
1094
1095        // Target prefill may contain token IDs or multimodal embeddings. Both
1096        // produce the target-layer features used to seed the draft KV cache, so
1097        // embeddings are injected too, except the pinned ones skipped below.
1098        // TODO: revisit after https://github.com/ggml-org/llama.cpp/pull/24669 is merged
1099        const bool has_tokens     = batch_in.token != nullptr;
1100        const bool has_embeddings = batch_in.embd  != nullptr;
1101        if (has_tokens == has_embeddings) {
1102            return true;
1103        }
1104
1105        const int32_t n_tokens = batch_in.n_tokens;
1106
1107        // per-seq inclusive batch range (assumes each seq's tokens are contiguous in the batch)
1108        std::vector<int32_t> i_batch_beg(n_seq, -1);
1109        std::vector<int32_t> i_batch_end(n_seq, -1);
1110        for (int32_t k = 0; k < n_tokens; ++k) {
1111            GGML_ASSERT(batch_in.n_seq_id[k] == 1);
1112            const llama_seq_id seq_id = batch_in.seq_id[k][0];
1113            if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
1114                continue;
1115            }
1116            i_batch_end[seq_id] = k;
1117            if (i_batch_beg[seq_id] < 0) {
1118                i_batch_beg[seq_id] = k;
1119            }
1120        }
1121
1122        auto * ctx_tgt = this->params.ctx_tgt;
1123        auto * ctx_dft = this->params.ctx_dft;
1124
1125        const int32_t n_ubatch = (int32_t) llama_n_ubatch(ctx_dft);
1126
1127        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1128            if (i_batch_beg[seq_id] < 0) {
1129                continue;
1130            }
1131            const int32_t n_rows = i_batch_end[seq_id] - i_batch_beg[seq_id] + 1;
1132
1133            // an M-RoPE image pins all its rows to one position, so a windowed draft
1134            // cache cannot free cells for it - skip it, the draft can jump over the gap
1135            const bool pos_pinned = batch_in.pos[i_batch_beg[seq_id]] == batch_in.pos[i_batch_end[seq_id]];
1136            if (has_embeddings && n_rows > 1 && pos_pinned) {
1137                continue;
1138            }
1139
1140            for (int32_t offset = 0; offset < n_rows; offset += n_ubatch) {
1141                const int32_t n_chunk = std::min(n_ubatch, n_rows - offset);
1142
1143                // gather target features per extract layer; the fused decode encodes and
1144                // injects them into the K/V cache at the target positions
1145                batch_inject.n_tokens = n_chunk;
1146                for (uint32_t k = 0; k < target_layer_ids_n; ++k) {
1147                    const float * layer = llama_get_embeddings_layer_inp(ctx_tgt, (uint32_t) target_layer_ids[k]);
1148                    if (!layer) {
1149                        GGML_ABORT("DFlash: target layer %d input not extracted.", target_layer_ids[k]);
1150                    }
1151                    for (int32_t i = 0; i < n_chunk; ++i) {
1152                        float       * dst = batch_inject.embd + (size_t) i * n_embd_enc + k * (size_t) n_embd_tgt;
1153                        const float * src = layer + (size_t) (i_batch_beg[seq_id] + offset + i) * n_embd_tgt;
1154                        std::memcpy(dst, src, (size_t) n_embd_tgt * sizeof(float));
1155                    }
1156                }
1157
1158                for (int32_t i = 0; i < n_chunk; ++i) {
1159                    const llama_pos p = batch_in.pos[i_batch_beg[seq_id] + offset + i];
1160                    batch_inject.pos[i] = p;
1161                    if (is_mrope) {
1162                        batch_inject.pos[1 * n_chunk + i] = p;
1163                        batch_inject.pos[2 * n_chunk + i] = p;
1164                        batch_inject.pos[3 * n_chunk + i] = 0;
1165                    }
1166                    batch_inject.n_seq_id[i]  = 1;
1167                    batch_inject.seq_id[i][0] = seq_id;
1168                    batch_inject.logits[i]    = false;
1169                }
1170                const int32_t rc = llama_decode(ctx_dft, batch_inject);
1171                if (rc != 0) {
1172                    LOG_ERR("%s: llama_decode(ctx_dft) failed rc=%d (n_tokens=%d, offset=%d)\n",
1173                            __func__, rc, (int) n_chunk, (int) offset);
1174                    return false;
1175                }
1176            }
1177        }
1178
1179        return true;
1180    }
1181
1182    void draft(common_speculative_draft_params_vec & dparams) override {
1183        auto & ctx_dft = params.ctx_dft;
1184
1185        common_batch_clear(batch);
1186
1187        // build one batch holding every drafting sequence's noise block into a single decode)
1188        // record where each block starts and its size
1189        std::vector<int32_t> i_block_beg(n_seq, -1);
1190        std::vector<int32_t> n_block    (n_seq,  0);
1191
1192        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1193            auto & dp = dparams[seq_id];
1194            if (!dp.drafting) {
1195                continue;
1196            }
1197
1198            common_sampler_reset(smpls[seq_id].get());
1199
1200            const int32_t n = (int32_t) dp.pos0;
1201
1202            const int32_t n_draft = params.n_max;
1203
1204            const int32_t n_block_tokens = n_draft + (is_dspark && sample_from_anchor ? 0 : 1);
1205            i_block_beg[seq_id] = batch.n_tokens;
1206            n_block    [seq_id] = n_block_tokens;
1207            for (int32_t i = 0; i < n_block_tokens; ++i) {
1208                common_batch_add(batch, i == 0 ? dp.id_last : mask_token_id, n + i, { seq_id }, !is_dflash2);
1209            }
1210        }
1211
1212        if (batch.n_tokens == 0) {
1213            return;
1214        }
1215
1216        // decode all sequence's noise block in a single batch
1217        int ret = llama_decode(ctx_dft, batch);
1218        if (ret != 0) {
1219            LOG_WRN("%s: llama_decode returned %d\n", __func__, ret);
1220            return;
1221        }
1222
1223        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1224            if (i_block_beg[seq_id] < 0) {
1225                continue;
1226            }
1227            auto & dp = dparams[seq_id];
1228
1229            const int32_t beg            = i_block_beg[seq_id];
1230            const int32_t n_block_tokens = n_block[seq_id];
1231
1232            auto * smpl = smpls[seq_id].get();
1233
1234            auto & result = *dp.result;
1235
1236            if (is_dflash2) {
1237                const float * lattice = llama_get_embeddings_nextn(ctx_dft);
1238                GGML_ASSERT(lattice && "DFlash2 selector produced no lattice");
1239
1240                int32_t predecessor = 0;
1241                for (int32_t i = 1; i < n_block_tokens; ++i) {
1242                    const float * row = lattice + (size_t) (beg + i) * n_embd_dec;
1243                    const float * scores = row + selector_top_k + (size_t) predecessor * selector_top_k;
1244
1245                    predecessor = (int32_t) std::distance(scores,
1246                            std::max_element(scores, scores + selector_top_k));
1247                    if (params.p_min > 0.0f) {
1248                        // softmax(scores) at the argmax, i.e. 1 / sum(exp(s_k - s_max))
1249                        float sum = 0.0f;
1250                        for (int32_t k = 0; k < selector_top_k; ++k) {
1251                            sum += std::exp(scores[k] - scores[predecessor]);
1252                        }
1253                        if (1.0f / sum < params.p_min) {
1254                            break;
1255                        }
1256                    }
1257                    result.push_back((llama_token) row[predecessor]);
1258                }
1259
1260                if (result.size() < (size_t) params.n_min) {
1261                    result.clear();
1262                }
1263                continue;
1264            }
1265
1266            if (is_dspark) {
1267                // DSpark: read from the first draft slot, truncate below the confidence threshold
1268                const float * conf = params.p_min > 0.0f ? llama_get_embeddings_nextn(ctx_dft) : nullptr;
1269                // bonus-anchor drafts read the mask positions only, like DFlash
1270                const int32_t i_draft_beg = sample_from_anchor ? 0 : 1;
1271                for (int32_t i = i_draft_beg; i < n_block_tokens; ++i) {
1272                    const int32_t idx = beg + i;
1273
1274                    if (conf && conf[(size_t) idx * n_embd_dec] < params.p_min) {
1275                        break;
1276                    }
1277
1278                    common_sampler_sample(smpl, ctx_dft, idx, true);
1279
1280                    const auto * cur_p = common_sampler_get_candidates(smpl, true);
1281
1282                    for (int k = 0; k < std::min(3, (int) cur_p->size); ++k) {
1283                        LOG_DBG(" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n",
1284                                seq_id, k, i, cur_p->data[k].id, cur_p->data[k].p,
1285                                common_token_to_piece(ctx_dft, cur_p->data[k].id).c_str());
1286                    }
1287
1288                    const llama_token id = cur_p->data[0].id;
1289
1290                    common_sampler_accept(smpl, id, true);
1291
1292                    result.push_back(id);
1293                }
1294            } else {
1295                // greedily read the predicted block at this sequence's noise positions 1..n_block_tokens-1
1296                for (int32_t i = 1; i < n_block_tokens; ++i) {
1297                    common_sampler_sample(smpl, ctx_dft, beg + i, true);
1298
1299                    const auto * cur_p = common_sampler_get_candidates(smpl, true);
1300
1301                    for (int k = 0; k < std::min(3, (int) cur_p->size); ++k) {
1302                        LOG_DBG(" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n",
1303                                seq_id, k, i - 1, cur_p->data[k].id, cur_p->data[k].p,
1304                                common_token_to_piece(ctx_dft, cur_p->data[k].id).c_str());
1305                    }
1306
1307                    const llama_token id = cur_p->data[0].id;
1308
1309                    if (cur_p->data[0].p < params.p_min) {
1310                        break;
1311                    }
1312
1313                    common_sampler_accept(smpl, id, true);
1314
1315                    result.push_back(id);
1316                }
1317            }
1318
1319            if (result.size() < (size_t) params.n_min) {
1320                result.clear();
1321            }
1322        }
1323    }
1324
1325    void accept(llama_seq_id /*seq_id*/, uint16_t /*n_accepted*/, bool /*is_other*/) override {
1326        // noop
1327    }
1328};
1329
1330struct common_speculative_impl_draft_mtp : public common_speculative_impl {
1331    common_params_speculative_draft params; // reuses the draft-model params slot (ctx_tgt/ctx_dft)
1332
1333    llama_batch batch;
1334
1335    std::vector<common_sampler_ptr> smpls;
1336
1337    // backend sampler chain per seq, attached to ctx_dft
1338    std::vector<llama_sampler *> backend_chains;
1339
1340    int32_t n_embd = 0;
1341
1342    // One MTP draft driver, three modes (set once in the ctor):
1343    //   is_mem_shared (gemma4): shares the target KV, runs all heads in one graph.
1344    //   chain_heads (step35): n_mtp_layers trained heads, one per draft step.
1345    //   neither (qwen35 / qwen35moe): a single trained MTP head.
1346    int32_t n_mtp_layers  = 1;
1347    bool    is_mem_shared = false;   // gemma4
1348    bool    chain_heads   = false;   // derived in the ctor: n_mtp_layers > 1 && !is_mem_shared
1349
1350    // Per-sequence cross-batch carryover: pair (h_p, x_{p+1}) at MTP pos p+1.
1351    // The last h-row of one process() call needs the first token of the NEXT
1352    // call to pair with, so it's stashed here until that next call fires.
1353    std::vector<std::vector<float>> pending_h;   // [n_seq][n_embd]
1354
1355    std::vector<int32_t> i_batch_beg;
1356    std::vector<int32_t> i_batch_end;
1357
1358    // Hidden rows from the most recent target verification batch, grouped by seq.
1359    // Row 0 corresponds to the sampled token, row N to the Nth accepted draft token.
1360    std::vector<std::vector<float>> verify_h;
1361    std::vector<int32_t> verify_h_rows;
1362
1363    std::vector<int>                i_last;
1364    std::vector<std::vector<float>> chain_h;
1365
1366    common_speculative_impl_draft_mtp(const common_params_speculative & params, uint32_t n_seq)
1367        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_DRAFT_MTP, n_seq, params.draft.n_max)
1368        , params(params.draft)
1369    {
1370        auto * ctx_tgt = this->params.ctx_tgt;
1371        auto * ctx_dft = this->params.ctx_dft;
1372        GGML_ASSERT(ctx_tgt && ctx_dft && "MTP requires ctx_tgt and ctx_dft to be set");
1373
1374        n_embd = llama_model_n_embd_out(llama_get_model(ctx_dft));
1375        GGML_ASSERT(n_embd == llama_model_n_embd_out(llama_get_model(ctx_tgt)) &&
1376                "MTP input row width must match the target h_nextn width");
1377        n_mtp_layers = std::max(1, (int) llama_model_n_layer_nextn(llama_get_model(ctx_dft)));
1378
1379        SPC_TRC("%s", "adding speculative implementation 'draft-mtp'\n");
1380        SPC_TRC("- n_max=%d, n_min=%d, p_min=%.2f, n_embd=%d, backend_sampling=%d\n", this->params.n_max, this->params.n_min, this->params.p_min, n_embd, (int) this->params.backend_sampling);
1381        SPC_TRC("- gpu_layers=%d, cache_k=%s, cache_v=%s, ctx_tgt=%s, ctx_dft=%s, devices=[%s]\n",
1382                this->params.n_gpu_layers,
1383                ggml_type_name(this->params.cache_type_k),
1384                ggml_type_name(this->params.cache_type_v),
1385                ctx_tgt ? "yes" : "no",
1386                ctx_dft ? "yes" : "no",
1387                common_speculative_get_devices_str(this->params.devices).c_str());
1388
1389        const int32_t n_b = (int32_t) llama_n_batch(ctx_dft);
1390        batch = llama_batch_init(/*n_tokens=*/ n_b, /*embd=*/ n_embd, /*n_seq_max=*/ 1);
1391        // llama_batch_init allocates only one of token/embd; MTP needs both.
1392        // TODO: fix, how to call without malloc
1393        batch.token = (llama_token *) malloc(sizeof(llama_token) * n_b);
1394
1395        smpls.resize(n_seq);
1396        for (auto & s : smpls) {
1397            common_params_sampling sparams;
1398            sparams.no_perf  = false;
1399            sparams.top_k    = 10;
1400            sparams.samplers = { COMMON_SAMPLER_TYPE_TOP_K };
1401            s.reset(common_sampler_init(llama_get_model(ctx_dft), sparams));
1402        }
1403
1404        // offload draft sampling to the backend
1405        backend_chains.assign(n_seq, nullptr);
1406        if (this->params.backend_sampling) {
1407            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1408                llama_sampler * chain = llama_sampler_chain_init(llama_sampler_chain_default_params());
1409                llama_sampler_chain_add(chain, llama_sampler_init_top_k(10));
1410
1411                if (!llama_set_sampler(ctx_dft, seq_id, chain)) {
1412                    SPC_WRN("backend offload failed for seq_id=%d; using CPU sampler\n", (int) seq_id);
1413                    llama_sampler_free(chain);
1414                    chain = nullptr;
1415                }
1416                backend_chains[seq_id] = chain;
1417            }
1418        }
1419
1420        llama_set_embeddings_nextn(ctx_tgt, true, /*masked*/ false);
1421        llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ true);
1422
1423        is_mem_shared = llama_get_ctx_other(ctx_dft) == ctx_tgt;
1424        chain_heads   = n_mtp_layers > 1 && !is_mem_shared;
1425
1426        if (chain_heads) {
1427            this->params.n_max = std::min(this->params.n_max, n_mtp_layers);
1428
1429            chain_h.assign(n_seq, {});
1430            for (auto & c : chain_h) {
1431                c.reserve((size_t) (this->params.n_max + 1) * n_embd);
1432            }
1433        }
1434        this->n_max = this->params.n_max;
1435
1436        pending_h.assign(n_seq, std::vector<float>(n_embd, 0.0f));
1437
1438        i_last.assign(n_seq, -1);
1439        i_batch_beg.assign(n_seq, -1);
1440        i_batch_end.assign(n_seq, -1);
1441
1442        verify_h.assign(n_seq, {});
1443        verify_h_rows.assign(n_seq, 0);
1444    }
1445
1446    ~common_speculative_impl_draft_mtp() override {
1447        auto * ctx_dft = this->params.ctx_dft;
1448        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) backend_chains.size(); ++seq_id) {
1449            if (backend_chains[seq_id] == nullptr) {
1450                continue;
1451            }
1452            if (ctx_dft) {
1453                llama_set_sampler(ctx_dft, seq_id, nullptr);
1454            }
1455            llama_sampler_free(backend_chains[seq_id]);
1456        }
1457        backend_chains.clear();
1458
1459        if (batch.token != nullptr) {
1460            free(batch.token);
1461            batch.token = nullptr;
1462        }
1463        llama_batch_free(batch);
1464    }
1465
1466    void begin(llama_seq_id seq_id, const llama_tokens & prompt) override {
1467        const int32_t N = (int32_t) prompt.size();
1468        if (N <= 0) {
1469            return;
1470        }
1471
1472        auto * ctx_dft = this->params.ctx_dft;
1473        const llama_pos pos_max = llama_memory_seq_pos_max(llama_get_memory(ctx_dft), seq_id);
1474
1475        if (pos_max < N - 1 && !is_mem_shared) {
1476            SPC_WRN("ctx_dft pos_max=%d < N-1=%d - "
1477                    "process() hook may not have run on every prefill ubatch "
1478                    "(need_embd / logits=1 on every prompt position?). "
1479                    "Drafts may degrade.\n",
1480                    (int) pos_max, N - 1);
1481        }
1482    }
1483
1484    bool process(const llama_batch & batch_in) override {
1485        if (batch_in.n_tokens <= 0) {
1486            return true;
1487        }
1488
1489        // TODO: how to make it work with vision tokens?
1490        if (batch_in.token == nullptr || batch_in.embd != nullptr) {
1491            return true;
1492        }
1493
1494        const int32_t n_tokens = batch_in.n_tokens;
1495
1496        // remember the first and last batch index for each sequence
1497        std::fill(i_batch_beg.begin(), i_batch_beg.end(), -1);
1498        std::fill(i_batch_end.begin(), i_batch_end.end(), -1);
1499
1500        for (int k = 0; k < n_tokens; ++k) {
1501            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1502                GGML_ASSERT(batch_in.n_seq_id[k] == 1);
1503
1504                if (batch_in.seq_id[k][0] == seq_id) {
1505                    i_batch_end[seq_id] = k;
1506                    if (i_batch_beg[seq_id] < 0) {
1507                        i_batch_beg[seq_id] = k;
1508                    }
1509                }
1510            }
1511        }
1512
1513        auto * ctx_tgt = this->params.ctx_tgt;
1514        auto * ctx_dft = this->params.ctx_dft;
1515
1516        const size_t row_bytes = (size_t) n_embd * sizeof(float);
1517
1518        // if kv is shared with target (e.g Gemma4), then we can skip this catch-up decode
1519        if (!is_mem_shared) {
1520            common_batch_clear(batch);
1521
1522            for (int k = 0; k < n_tokens; ++k) {
1523                common_batch_add(batch, batch_in.token[k], batch_in.pos[k], { batch_in.seq_id[k][0] }, 0);
1524            }
1525
1526            // shift the tgt embeddings to the right by one position
1527            // assumes that the tokens in the batch are sequential for each sequence
1528            // i.e. we cannot have seq_id like this: [0, 0, 0, 1, 1, 0, 1, 1]
1529            //                                                       ^--- this is a problem
1530            // TODO:this is generally true, but would be nice to assert it
1531            {
1532                const float * h_tgt = llama_get_embeddings_nextn(ctx_tgt);
1533                std::memcpy(batch.embd + (size_t) 1 * n_embd, h_tgt, row_bytes * (n_tokens-1));
1534            }
1535
1536            // fill the pending embeddings from a previous run
1537            auto set_h = [&](int idx, const float * h_row) {
1538                std::memcpy(batch.embd + (size_t) idx * n_embd, h_row, row_bytes);
1539            };
1540
1541            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1542                if (i_batch_beg[seq_id] < 0) {
1543                    continue;
1544                }
1545
1546                set_h(i_batch_beg[seq_id], pending_h[seq_id].data());
1547            }
1548
1549            auto * mem_dft = llama_get_memory(ctx_dft);
1550
1551            bool ok = true;
1552            for (int head = 0; head < n_mtp_layers; ++head) {
1553                if (chain_heads) {
1554                    // ref: https://github.com/ggml-org/llama.cpp/pull/24340/changes#r3413498544
1555                    for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1556                        if (i_batch_beg[seq_id] < 0) {
1557                            continue;
1558                        }
1559                        llama_memory_seq_rm(mem_dft, seq_id, batch_in.pos[i_batch_beg[seq_id]], -1);
1560                    }
1561                    llama_set_nextn_layer_offset(ctx_dft, head);
1562                }
1563
1564                const int32_t rc = llama_decode(ctx_dft, batch);
1565                if (rc != 0) {
1566                    SPC_ERR("llama_decode(ctx_dft) head=%d failed rc=%d (pos=%d)\n",
1567                            head, (int) rc, (int) batch_in.pos[0]);
1568                    ok = false;
1569                    break;
1570                }
1571            }
1572
1573            if (chain_heads) {
1574                llama_set_nextn_layer_offset(ctx_dft, 0); // restore default for non-draft decodes
1575            }
1576            if (!ok) {
1577                return false;
1578            }
1579        }
1580
1581        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1582            if (i_batch_end[seq_id] < 0) {
1583                continue;
1584            }
1585
1586            const int32_t n_rows = i_batch_end[seq_id] - i_batch_beg[seq_id] + 1;
1587            verify_h_rows[seq_id] = n_rows;
1588            verify_h[seq_id].resize((size_t) n_rows * n_embd);
1589
1590            for (int32_t i = 0; i < n_rows; ++i) {
1591                const float * h = llama_get_embeddings_nextn_ith(ctx_tgt, i_batch_beg[seq_id] + i);
1592                std::memcpy(verify_h[seq_id].data() + (size_t) i * n_embd, h, row_bytes);
1593            }
1594
1595            std::memcpy(pending_h[seq_id].data(),
1596                    verify_h[seq_id].data() + (size_t) (n_rows - 1) * n_embd, row_bytes);
1597        }
1598
1599        return true;
1600    }
1601
1602    void draft(common_speculative_draft_params_vec & dparams) override {
1603        auto & ctx_dft = params.ctx_dft;
1604
1605        common_batch_clear(batch);
1606
1607        // keep track of which sequences are still drafting
1608        int n_drafting = 0;
1609        std::vector<bool> drafting(n_seq);
1610
1611        const size_t row_bytes = (size_t) n_embd * sizeof(float);
1612
1613        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1614            auto & dp = dparams[seq_id];
1615
1616            if (!dp.drafting) {
1617                continue;
1618            }
1619
1620            n_drafting++;
1621            drafting[seq_id] = true;
1622            common_sampler_reset(smpls[seq_id].get());
1623
1624            common_batch_add(batch, dp.id_last, dp.pos0, { seq_id }, true);
1625            std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd, pending_h[seq_id].data(), row_bytes);
1626
1627            i_last[seq_id] = batch.n_tokens - 1;
1628
1629            if (chain_heads) {
1630                chain_h[seq_id].assign(pending_h[seq_id].begin(), pending_h[seq_id].end());
1631            }
1632        }
1633
1634        int i = 0;
1635
1636        while (n_drafting > 0) {
1637            // each step decodes under a different head, i.e. a different decoder layer, and
1638            // KV is per layer. process() filled this layer's KV only for positions < pos0
1639            // (prompt + accepted prefix) — nothing in the draft region yet. so reset the
1640            // draft region (the seq_rm lower bound is pos0, leaving the prompt KV intact)
1641            // and select head i so it rebuilds its own layer's KV there; decoding just the
1642            // latest token would leave its attention reading cells only another head wrote.
1643            if (chain_heads) {
1644                auto * mem_dft = llama_get_memory(ctx_dft);
1645                for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1646                    if (drafting[seq_id]) {
1647                        llama_memory_seq_rm(mem_dft, seq_id, dparams[seq_id].pos0, -1);
1648                    }
1649                }
1650                llama_set_nextn_layer_offset(ctx_dft, i);
1651            }
1652
1653            int ret = llama_decode(ctx_dft, batch);
1654            if (ret != 0) {
1655                SPC_ERR("llama_decode[%d] returned %d\n", i, ret);
1656                break;
1657            }
1658
1659            // rebuild the batch for the next step: the growing-KV paths re-add only the
1660            // new token (the KV already holds the prefix), while chained heads re-add the
1661            // whole prefix at the next head. dropped sequences are simply not re-added.
1662            common_batch_clear(batch);
1663
1664            for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1665                if (!drafting[seq_id]) {
1666                    continue;
1667                }
1668
1669                auto * smpl = smpls[seq_id].get();
1670
1671                common_sampler_sample(smpl, ctx_dft, i_last[seq_id], true);
1672                const float * h_row = llama_get_embeddings_nextn_ith(ctx_dft, i_last[seq_id]);
1673
1674                const auto * cur_p = common_sampler_get_candidates(smpl, true);
1675
1676                for (int k = 0; k < std::min(3, (int) cur_p->size); ++k) {
1677                    SPC_DBG(" - seq_id %d, draft candidate %3d, pos %3d: %6d (%8.3f) '%s'\n",
1678                            seq_id, k, i, cur_p->data[k].id, cur_p->data[k].p,
1679                            common_token_to_piece(ctx_dft, cur_p->data[k].id).c_str());
1680                }
1681
1682                // add drafted token for each sequence
1683                const llama_token id = cur_p->data[0].id;
1684
1685                // only collect very high-confidence draft tokens
1686                if (cur_p->data[0].p < params.p_min) {
1687                    drafting[seq_id] = false;
1688                    n_drafting--;
1689
1690                    continue;
1691                }
1692
1693                common_sampler_accept(smpl, id, true);
1694
1695                auto & dp = dparams.at(seq_id);
1696                auto & result = *dp.result;
1697
1698                result.push_back(id);
1699
1700                if (params.n_max <= (int) result.size()) {
1701                    drafting[seq_id] = false;
1702                    n_drafting--;
1703                    continue;
1704                }
1705
1706                if (chain_heads) {
1707                    // ref: https://github.com/ggml-org/llama.cpp/pull/24340#discussion_r3448031546
1708                    chain_h[seq_id].insert(chain_h[seq_id].end(), h_row, h_row + n_embd);
1709
1710                    const int n_rows = (int) result.size() + 1; // id_last + tokens drafted so far
1711                    for (int t = 0; t < n_rows; ++t) {
1712                        const llama_token tok = (t == 0) ? dp.id_last : result[t - 1];
1713                        common_batch_add(batch, tok, dp.pos0 + t, { seq_id }, t == n_rows - 1);
1714                        std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd,
1715                                    chain_h[seq_id].data() + (size_t) t * n_embd, row_bytes);
1716                    }
1717                } else if (is_mem_shared) {
1718                    // note: with shared memory (e.g. Gemma4 assistants) we use the same position for all draft tokens
1719                    // ref: https://github.com/huggingface/transformers/blob/effde20942e3f82a1b97449f60b3a48c5ff96145/docs/source/en/model_doc/gemma4_assistant.md?plain=1#L36-L37
1720                    common_batch_add(batch, id, dp.pos0, { seq_id }, true);
1721                    std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd, h_row, row_bytes);
1722                } else {
1723                    common_batch_add(batch, id, dp.pos0 + i + 1, { seq_id }, true);
1724                    std::memcpy(batch.embd + (size_t) (batch.n_tokens - 1) * n_embd, h_row, row_bytes);
1725                }
1726
1727                i_last[seq_id] = batch.n_tokens - 1;
1728            }
1729
1730            if (batch.n_tokens == 0) {
1731                break;
1732            }
1733
1734            ++i;
1735        }
1736
1737        if (chain_heads) {
1738            llama_set_nextn_layer_offset(ctx_dft, 0); // restore default for non-draft decodes
1739        }
1740
1741        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1742            auto & dp = dparams[seq_id];
1743            if (!dp.drafting) {
1744                continue;
1745            }
1746
1747            if (dp.result->size() < (size_t) params.n_min) {
1748                dp.result->clear();
1749            }
1750        }
1751    }
1752
1753    void accept(llama_seq_id seq_id, uint16_t n_accepted, bool /*is_other*/) override {
1754        if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
1755            return;
1756        }
1757
1758        const int32_t n_rows = verify_h_rows[seq_id];
1759        if (n_rows <= 0) {
1760            return;
1761        }
1762
1763        const int32_t i_h = std::min<int32_t>(n_accepted, n_rows - 1);
1764        const size_t row_bytes = (size_t) n_embd * sizeof(float);
1765        std::memcpy(pending_h[seq_id].data(), verify_h[seq_id].data() + (size_t) i_h * n_embd, row_bytes);
1766    }
1767};
1768
1769// state of self-speculation (simple implementation, not ngram-map)
1770struct common_speculative_impl_ngram_simple : public common_speculative_impl {
1771    common_params_speculative_ngram_map params;
1772
1773    // shared across all sequences
1774    common_ngram_simple_config config;
1775
1776    common_speculative_impl_ngram_simple(
1777            const common_params_speculative & params, uint32_t n_seq,
1778            common_ngram_simple_config config)
1779        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE, n_seq, params.ngram_simple.size_m)
1780        , params(params.ngram_simple)
1781        , config(config)
1782    {
1783        SPC_TRC("%s", "adding speculative implementation 'ngram-simple'\n");
1784        SPC_TRC("- size_n=%d, size_m=%d, min_hits=%d\n",
1785                this->params.size_n, this->params.size_m, this->params.min_hits);
1786    }
1787
1788    void begin(llama_seq_id /*seq_id*/, const llama_tokens & /*prompt*/) override {
1789        // noop
1790    }
1791
1792    bool process(const llama_batch & /*batch*/) override {
1793        // TODO: implement
1794        return true;
1795    }
1796
1797    void draft(common_speculative_draft_params_vec & dparams) override {
1798        assert(dparams.size() == n_seq);
1799
1800        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1801            auto & dp = dparams[seq_id];
1802            if (!dp.drafting) {
1803                continue;
1804            }
1805
1806            *dp.result = common_ngram_simple_draft(config, *dp.prompt, dp.id_last);
1807        }
1808    }
1809
1810    void accept(llama_seq_id /*seq_id*/, uint16_t /*n_accepted*/, bool /*is_other*/) override {
1811        // noop
1812    }
1813};
1814
1815struct common_speculative_impl_ngram_map_k : public common_speculative_impl {
1816    // n_seq configs
1817    std::vector<common_ngram_map> config;
1818
1819    common_speculative_impl_ngram_map_k(
1820            const common_ngram_map & config,
1821            uint32_t n_seq)
1822        : common_speculative_impl(config.key_only ? COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K
1823            : COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V, n_seq, config.size_value)
1824    {
1825        for (uint32_t i = 0; i < n_seq; i++) {
1826            this->config.push_back(config);
1827        }
1828
1829        SPC_TRC("adding speculative implementation '%s'\n", common_speculative_type_to_str(this->type).c_str());
1830        SPC_TRC("- size_key=%d, size_value=%d, key_only=%d, min_hits=%d\n",
1831                config.size_key, config.size_value, config.key_only, config.min_hits);
1832    }
1833
1834    void begin(llama_seq_id seq_id, const llama_tokens & prompt) override {
1835        GGML_ASSERT(seq_id < (llama_seq_id) n_seq);
1836
1837        common_ngram_map_begin(config[seq_id], prompt);
1838    }
1839
1840    bool process(const llama_batch & /*batch*/) override {
1841        // TODO: implement
1842        return true;
1843    }
1844
1845    void draft(common_speculative_draft_params_vec & dparams) override {
1846        assert(dparams.size() == n_seq);
1847
1848        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
1849            auto & dp = dparams[seq_id];
1850            if (!dp.drafting) {
1851                continue;
1852            }
1853
1854            common_ngram_map_draft(config[seq_id], *dp.prompt, dp.id_last, *dp.result);
1855        }
1856    }
1857
1858    void accept(llama_seq_id seq_id, uint16_t n_accepted, bool is_other) override {
1859        GGML_ASSERT((seq_id < (llama_seq_id) config.size()));
1860
1861        if (is_other) {
1862            return;
1863        }
1864
1865        common_ngram_map_accept(config[seq_id], n_accepted);
1866    }
1867};
1868
1869struct common_speculative_impl_ngram_mod : public common_speculative_impl {
1870    common_params_speculative_ngram_mod params;
1871
1872    // shared across all sequences
1873    common_ngram_mod mod;
1874
1875    // enable trace logging if LLAMA_TRACE is set
1876    const bool verbose;
1877
1878    struct seq_info {
1879        // the last position in the prompt that was added to the ngram container
1880        size_t i_last = 0;
1881
1882        // length of the last drafted n-gram (number of tokens returned by draft)
1883        size_t n_draft_last = 0;
1884
1885        // consecutive accept rounds with low acceptance fraction (< 0.5)
1886        int n_low = 0;
1887    };
1888
1889    std::vector<seq_info> sinfos;
1890
1891    common_speculative_impl_ngram_mod(
1892            const common_params_speculative & params,
1893            uint32_t n_seq)
1894        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_MOD, n_seq, params.ngram_mod.n_max)
1895        , params(params.ngram_mod)
1896        , mod(params.ngram_mod.n_match, 4*1024*1024)
1897        , verbose(std::getenv("LLAMA_TRACE") != nullptr) {
1898        static_assert(sizeof(llama_token) == sizeof(common_ngram_mod::entry_t));
1899
1900        SPC_TRC("%s", "adding speculative implementation 'ngram-mod'\n");
1901        SPC_TRC("- n_match=%d, n_max=%d, n_min=%d\n",
1902                this->params.n_match, this->params.n_max, this->params.n_min);
1903        SPC_TRC("- mod size=%zu (%.3f MB)\n",
1904                mod.size(), (float)(mod.size_bytes())/1024/1024);
1905
1906        if (this->params.n_match < 16) {
1907            SPC_WRN("ngram_mod n_match=%d is too small - poor quality is possible, "
1908                    "see: https://github.com/ggml-org/llama.cpp/pull/19164\n", this->params.n_match);
1909        }
1910
1911        sinfos.resize(n_seq);
1912    }
1913
1914    void begin(llama_seq_id seq_id, const llama_tokens & prompt) override {
1915        auto & sinfo = sinfos[seq_id];
1916
1917        sinfo.i_last = 0;
1918        sinfo.n_draft_last = 0;
1919
1920        const size_t n = mod.get_n();
1921        if (prompt.size() < n) {
1922            return;
1923        }
1924
1925        for (size_t i = 0; i < prompt.size() - n; ++i) {
1926            mod.add(prompt.data() + i);
1927        }
1928
1929        sinfo.i_last = prompt.size() - n;
1930
1931        const double f = (double)mod.get_used() / (double)mod.size();
1932        SPC_TRC("ngram_mod occupancy = %zu/%zu (%.2f)\n", mod.get_used(), mod.size(), f);
1933
1934        constexpr double f_thold = 0.25;
1935        if (f > f_thold) {
1936            SPC_WRN("ngram_mod occupancy %.2f exceeds threshold (%.2f) - resetting\n", f, f_thold);
1937
1938            mod.reset();
1939        }
1940    }
1941
1942    void draft_one(
1943            llama_seq_id seq_id,
1944            common_speculative_draft_params & dparams) {
1945        auto & sinfo = sinfos[seq_id];
1946        auto & result = *dparams.result;
1947
1948        const auto & prompt = *dparams.prompt;
1949
1950        sinfo.n_draft_last = 0;
1951
1952        const size_t cur_len = prompt.size();
1953        if (cur_len < mod.get_n()) {
1954            return;
1955        }
1956
1957        const size_t n = mod.get_n();
1958
1959        // add new ngrams in chunks
1960        if (sinfo.i_last + 32 < cur_len) {
1961            for (size_t i = sinfo.i_last; i < cur_len - n; ++i) {
1962                mod.add(prompt.data() + i);
1963            }
1964
1965            sinfo.i_last = cur_len - n;
1966        }
1967
1968        result.resize(n + params.n_max);
1969        for (size_t i = 0; i < n - 1; ++i) {
1970            result[i] = prompt.at(cur_len - n + 1 + i);
1971        }
1972        result[n - 1] = dparams.id_last;
1973
1974        for (int i = 0; i < params.n_max; ++i) {
1975            const llama_token token = mod.get(result.data() + i);
1976            if (token == common_ngram_mod::EMPTY) {
1977                if (i < params.n_min) {
1978                    result.clear();
1979                    return;
1980                }
1981
1982                result.resize(n + i);
1983                break;
1984            }
1985            result[n + i] = token;
1986        }
1987
1988        // only return the m tokens that were drafted
1989        for (size_t i = 0; n + i < result.size(); ++i) {
1990            result[i] = result[n + i];
1991        }
1992        result.resize(result.size() - n);
1993
1994        // store length of drafted n-gram for later acceptance analysis
1995        sinfo.n_draft_last = result.size();
1996    }
1997
1998    bool process(const llama_batch & /*batch*/) override {
1999        // TODO: implement
2000        return true;
2001    }
2002
2003    void draft(common_speculative_draft_params_vec & dparams) override {
2004        assert(dparams.size() == n_seq);
2005
2006        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
2007            auto & dp = dparams[seq_id];
2008            if (!dp.drafting) {
2009                continue;
2010            }
2011
2012            draft_one(seq_id, dp);
2013        }
2014    }
2015
2016    void accept(llama_seq_id seq_id, uint16_t n_accepted, bool is_other) override {
2017        if (is_other) {
2018            return;
2019        }
2020
2021        auto & sinfo = sinfos[seq_id];
2022
2023        // compute acceptance fraction if we have a recorded draft length
2024        if (sinfo.n_draft_last > 0) {
2025            const double f_acc = (double)n_accepted / (double)sinfo.n_draft_last;
2026            if (f_acc < 0.25) {
2027                sinfo.n_low++;
2028                if (sinfo.n_low >= 5) {
2029                    if (verbose) {
2030                        SPC_TRC("low acceptance streak (%d) - resetting ngram_mod\n", sinfo.n_low);
2031                    }
2032
2033                    mod.reset();
2034                    sinfo.n_low = 0;
2035                    sinfo.i_last = 0;
2036                }
2037            } else {
2038                sinfo.n_low = 0;
2039            }
2040        }
2041    }
2042};
2043
2044struct common_speculative_impl_ngram_cache : public common_speculative_impl {
2045    common_params_speculative_ngram_cache params;
2046
2047    uint16_t n_draft;
2048
2049    bool save_dynamic;
2050    bool save_static;
2051
2052    struct seq_info {
2053        size_t cache_size = 0; // number of tokens in n-gram cache
2054
2055        common_ngram_cache ngram_cache_context;
2056        common_ngram_cache ngram_cache_dynamic;
2057        common_ngram_cache ngram_cache_static;
2058    };
2059
2060    std::vector<seq_info> sinfos;
2061
2062    common_speculative_impl_ngram_cache(
2063            const common_params_speculative & params,
2064            uint32_t n_seq,
2065            uint16_t n_draft,
2066            const std::string & path_static,
2067            const std::string & path_dynamic,
2068            bool save_dynamic,
2069            bool save_static)
2070        : common_speculative_impl(COMMON_SPECULATIVE_TYPE_NGRAM_CACHE, n_seq, n_draft)
2071        , params(params.ngram_cache)
2072        , n_draft(n_draft)
2073        , save_dynamic(save_dynamic)
2074        , save_static(save_static)
2075    {
2076        SPC_TRC("%s", "adding speculative implementation 'ngram-cache'\n");
2077        SPC_TRC("- n_draft=%d, cache_static=%s, cache_dynamic=%s\n",
2078                n_draft,
2079                path_static.empty() ? "none" : path_static.c_str(),
2080                path_dynamic.empty() ? "none" : path_dynamic.c_str());
2081
2082        sinfos.resize(n_seq);
2083
2084        if (!path_static.empty()) {
2085            try {
2086                auto ngram_cache_static = common_ngram_cache_load(path_static);
2087
2088                for (auto & sinfo : sinfos) {
2089                    sinfo.ngram_cache_static = ngram_cache_static;
2090                }
2091            } catch (...) {
2092                SPC_ERR("failed to open static lookup cache: %s", path_static.c_str());
2093                GGML_ABORT("Couldn't read static lookup cache");
2094            }
2095        }
2096
2097        if (!path_dynamic.empty()) {
2098            try {
2099                auto ngram_cache_dynamic = common_ngram_cache_load(path_dynamic);
2100
2101                for (auto & sinfo : sinfos) {
2102                    sinfo.ngram_cache_dynamic = ngram_cache_dynamic;
2103                }
2104            } catch (...) {
2105                SPC_ERR("failed to open dynamic lookup cache: %s", path_dynamic.c_str());
2106                GGML_ABORT("Couldn't read dynamic lookup cache");
2107            }
2108        }
2109    }
2110
2111    void begin(llama_seq_id /*seq_id*/, const llama_tokens & /*prompt*/) override {
2112        // noop
2113    }
2114
2115    void draft_one(
2116            llama_seq_id seq_id,
2117            common_speculative_draft_params & dparams) {
2118        auto & sinfo = sinfos[seq_id];
2119        auto & result = *dparams.result;
2120
2121        const auto & prompt = *dparams.prompt;
2122
2123        if (sinfo.cache_size < prompt.size() + 1) {
2124            llama_tokens tokens_new;
2125            tokens_new.reserve(prompt.size() + 1 - sinfo.cache_size);
2126            for (size_t j = sinfo.cache_size; j < prompt.size(); ++j) {
2127                tokens_new.push_back(prompt[j]);
2128            }
2129            tokens_new.push_back(dparams.id_last); // add the last token
2130
2131            // Update context ngram cache with new dparams.prompt:
2132            common_ngram_cache_update(
2133                    sinfo.ngram_cache_context,
2134                    LLAMA_NGRAM_MIN, LLAMA_NGRAM_MAX,
2135                    tokens_new, tokens_new.size(), false);
2136            sinfo.cache_size = prompt.size() + 1;
2137        }
2138
2139        llama_tokens inp;
2140        inp.reserve(prompt.size() + 1);
2141        for (size_t j = 0; j < prompt.size(); ++j) {
2142            inp.push_back(prompt[j]);
2143        }
2144        inp.push_back(dparams.id_last);
2145
2146        result.push_back(dparams.id_last);
2147
2148        common_ngram_cache_draft(
2149                inp, result, n_draft, LLAMA_NGRAM_MIN, LLAMA_NGRAM_MAX,
2150                sinfo.ngram_cache_context,
2151                sinfo.ngram_cache_dynamic,
2152                sinfo.ngram_cache_static);
2153
2154        if (result.size() > 0) {
2155            // delete first token in result (which is the id_last token)
2156            result.erase(result.begin());
2157        }
2158    }
2159
2160    bool process(const llama_batch & /*batch*/) override {
2161        // TODO: implement
2162        return true;
2163    }
2164
2165    void draft(common_speculative_draft_params_vec & dparams) override {
2166        assert(dparams.size() == n_seq);
2167
2168        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) n_seq; ++seq_id) {
2169            auto & dp = dparams[seq_id];
2170            if (!dp.drafting) {
2171                continue;
2172            }
2173
2174            draft_one(seq_id, dp);
2175        }
2176    }
2177
2178    void accept(llama_seq_id /*seq_id*/, uint16_t /*n_accepted*/, bool /*is_other*/) override {
2179        // noop
2180    }
2181};
2182
2183struct common_speculative {
2184    common_speculative_draft_params_vec dparams;
2185
2186    // list of implementations to use and their states
2187    std::vector<std::unique_ptr<common_speculative_impl>> impls;
2188
2189    // which implementaion was used for a given seq_id
2190    std::vector<common_speculative_impl *> impl_last;
2191
2192    std::vector<double> synth_probs;
2193};
2194
2195static common_ngram_map get_common_ngram_map(
2196        common_speculative_type type,
2197        const common_params_speculative_ngram_map & config) {
2198    uint16_t size_key   = config.size_n;
2199    uint16_t size_value = config.size_m;
2200    bool     key_only   = type == COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K;
2201    uint16_t min_hits   = config.min_hits;
2202
2203    return common_ngram_map(size_key, size_value, key_only, min_hits);
2204}
2205
2206static common_speculative_impl_ngram_cache create_state_ngram_cache(
2207        const common_speculative_config & config,
2208        uint32_t n_seq,
2209        const std::string & path_static,
2210        const std::string & path_dynamic) {
2211    uint16_t n_draft = 8; // TODO get from config?
2212
2213    // TODO bool param in common/common.h to set save_static/save_dynamic?
2214    bool save_static = false;
2215    bool save_dynamic = false;
2216
2217    common_speculative_impl_ngram_cache state(config.params, n_seq, n_draft, path_static, path_dynamic, save_static, save_dynamic);
2218
2219    return state;
2220}
2221
2222std::string common_speculative_type_name_str(const std::vector<common_speculative_type> & types) {
2223    std::string result;
2224
2225    for (size_t i = 0; i < types.size(); i++) {
2226        if (i > 0) {
2227            result += ",";
2228        }
2229        result += common_speculative_type_to_str(types[i]);
2230    }
2231    return result;
2232}
2233
2234const char * common_speculative_all_types_str() {
2235    static std::string all_types_str = []() {
2236        std::vector<common_speculative_type> types;
2237        types.reserve(COMMON_SPECULATIVE_TYPE_COUNT);
2238        for (int i = 0; i < COMMON_SPECULATIVE_TYPE_COUNT; i++) {
2239            types.push_back((common_speculative_type) i);
2240        }
2241        return common_speculative_type_name_str(types);
2242    }();
2243    return all_types_str.c_str();
2244}
2245
2246std::string common_speculative_type_to_str(common_speculative_type type) {
2247    switch (type) {
2248        case COMMON_SPECULATIVE_TYPE_NONE:          return "none";
2249        case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE:  return "draft-simple";
2250        case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3:  return "draft-eagle3";
2251        case COMMON_SPECULATIVE_TYPE_DRAFT_MTP:     return "draft-mtp";
2252        case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH:  return "draft-dflash";
2253        case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK:  return "draft-dspark";
2254        case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE:  return "ngram-simple";
2255        case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K:   return "ngram-map-k";
2256        case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V: return "ngram-map-k4v";
2257        case COMMON_SPECULATIVE_TYPE_NGRAM_MOD:     return "ngram-mod";
2258        case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE:   return "ngram-cache";
2259        default:                                    return "unknown";
2260    }
2261}
2262
2263std::vector<common_speculative_type> common_speculative_types_from_names(const std::vector<std::string> & names) {
2264    std::vector<common_speculative_type> types;
2265    types.reserve(names.size());
2266
2267    for (const auto & name : names) {
2268        auto type = common_speculative_type_from_name_map.find(name);
2269        if (type != common_speculative_type_from_name_map.end()) {
2270            if (type->second == COMMON_SPECULATIVE_TYPE_NONE) {
2271                return std::vector<common_speculative_type> { COMMON_SPECULATIVE_TYPE_NONE };
2272            }
2273            types.push_back(type->second);
2274            continue;
2275        }
2276        throw std::invalid_argument("unknown speculative type: " + name);
2277    }
2278
2279    return types;
2280}
2281
2282common_speculative_type common_speculative_type_from_name(const std::string & name) {
2283    const auto it = common_speculative_type_from_name_map.find(name);
2284    if (it == common_speculative_type_from_name_map.end()) {
2285        return COMMON_SPECULATIVE_TYPE_COUNT;
2286    }
2287    return it->second;
2288}
2289
2290std::vector<common_speculative_type> common_speculative_types_from_gguf(const std::string & path) {
2291    struct gguf_init_params gguf_params = {
2292        /* .no_alloc = */ true,
2293        /* .ctx      = */ nullptr,
2294    };
2295
2296    gguf_context_ptr gguf_ctx(gguf_init_from_file(path.c_str(), gguf_params));
2297    if (!gguf_ctx) {
2298        return {};
2299    }
2300
2301    const int64_t arch_id = gguf_find_key(gguf_ctx.get(), "general.architecture");
2302    if (arch_id < 0 || gguf_get_kv_type(gguf_ctx.get(), arch_id) != GGUF_TYPE_STRING) {
2303        return {};
2304    }
2305
2306    const std::string arch = gguf_get_val_str(gguf_ctx.get(), arch_id);
2307    if (arch != "dflash") {
2308        const uint32_t block_count = gguf_get_val_u32(gguf_ctx.get(), gguf_find_key(gguf_ctx.get(), (arch + ".block_count").c_str()));
2309
2310        if (gguf_find_tensor(gguf_ctx.get(), ("blk." + std::to_string(block_count - 1) + ".nextn.eh_proj.weight").c_str()) >= 0) {
2311            return { COMMON_SPECULATIVE_TYPE_DRAFT_MTP };
2312        }
2313
2314        return {};
2315    }
2316
2317    // the Markov head distinguishes draft-dspark from draft-dflash
2318    const auto type = gguf_find_tensor(gguf_ctx.get(), "markov_w1.weight") >= 0
2319                    ? COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK
2320                    : COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH;
2321
2322    SPC_INF("auto-detected speculative type '%s' from the draft model metadata\n", common_speculative_type_to_str(type).c_str());
2323
2324    return { type };
2325}
2326
2327static uint32_t common_get_enabled_speculative_configs(const std::vector<common_speculative_type> & configs) {
2328    uint32_t result = 0;
2329    for (size_t i = 0; i < configs.size(); i++) {
2330        result |= (1u << configs[i]);
2331    }
2332    return result;
2333}
2334
2335int32_t common_speculative_n_max(const common_params_speculative * spec) {
2336    int32_t n_max = 0;
2337
2338    for (const auto type : spec->types) {
2339        switch (type) {
2340            case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE:
2341            case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3:
2342            case COMMON_SPECULATIVE_TYPE_DRAFT_MTP:
2343            case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH:
2344            case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK:
2345                n_max = std::max(n_max, std::max(0, spec->draft.n_max));
2346                break;
2347            case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE:
2348                n_max = std::max(n_max, (int32_t) spec->ngram_simple.size_m);
2349                break;
2350            case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K:
2351                n_max = std::max(n_max, (int32_t) spec->ngram_map_k.size_m);
2352                break;
2353            case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V:
2354                n_max = std::max(n_max, (int32_t) spec->ngram_map_k4v.size_m);
2355                break;
2356            case COMMON_SPECULATIVE_TYPE_NGRAM_MOD:
2357                n_max = std::max(n_max, std::max(0, spec->ngram_mod.n_max));
2358                break;
2359            case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE:
2360                n_max = std::max(n_max, (int32_t) 8);
2361                break;
2362            case COMMON_SPECULATIVE_TYPE_NONE:
2363            case COMMON_SPECULATIVE_TYPE_COUNT:
2364                break;
2365        }
2366    }
2367
2368    return n_max;
2369}
2370
2371int32_t common_speculative_n_max(const common_speculative * spec) {
2372    int32_t n_max = 0;
2373
2374    if (spec == nullptr) {
2375        return n_max;
2376    }
2377
2378    for (const auto & impl : spec->impls) {
2379        n_max = std::max(n_max, std::max(0, impl->n_max));
2380    }
2381
2382    return n_max;
2383}
2384
2385std::vector<double> common_speculative_synth_rates_resolve(const common_params_speculative * spec, int32_t n_max) {
2386    const bool has_length = spec->synth_len != -1.0;
2387    const bool has_rates  = !spec->synth_rates.empty();
2388
2389    if (!has_length && !has_rates) {
2390        return {};
2391    }
2392    if (has_length && has_rates) {
2393        throw std::invalid_argument("synthetic acceptance length and rates are mutually exclusive");
2394    }
2395
2396    if (n_max <= 0) {
2397        throw std::invalid_argument("synthetic acceptance requires at least one speculative token");
2398    }
2399
2400    if (has_rates) {
2401        const auto & rates = spec->synth_rates;
2402        if (rates.size() != (size_t) n_max) {
2403            throw std::invalid_argument(string_format(
2404                    "synthetic acceptance rates must contain %d values, got %zu", n_max, rates.size()));
2405        }
2406
2407        for (size_t i = 0; i < rates.size(); ++i) {
2408            if (!std::isfinite(rates[i]) || rates[i] < 0.0 || rates[i] > 1.0) {
2409                throw std::invalid_argument("synthetic acceptance rates must be finite and within [0, 1]");
2410            }
2411            if (i > 0 && rates[i] > rates[i - 1]) {
2412                throw std::invalid_argument("synthetic acceptance rates must be monotonically non-increasing");
2413            }
2414        }
2415
2416        return rates;
2417    }
2418
2419    const double length = spec->synth_len;
2420    const double length_max = (double) n_max + 1.0;
2421    if (!std::isfinite(length) || length < 1.0 || length > length_max) {
2422        throw std::invalid_argument(string_format(
2423                "synthetic acceptance length must be finite and within [1, %.0f]", length_max));
2424    }
2425
2426    double p = 0.0;
2427    if (length == length_max) {
2428        p = 1.0;
2429    } else if (length > 1.0) {
2430        double p_min = 0.0;
2431        double p_max = 1.0;
2432        for (int i = 0; i < 32; ++i) {
2433            const double p_mid = 0.5 * (p_min + p_max);
2434            double sum = 0.0;
2435            double term = p_mid;
2436            for (int32_t j = 0; j < n_max; ++j) {
2437                sum += term;
2438                term *= p_mid;
2439            }
2440
2441            if (sum < length - 1.0) {
2442                p_min = p_mid;
2443            } else {
2444                p_max = p_mid;
2445            }
2446        }
2447        p = 0.5 * (p_min + p_max);
2448    }
2449
2450    std::vector<double> rates;
2451    rates.reserve(n_max);
2452    double rate = p;
2453    for (int32_t i = 0; i < n_max; ++i) {
2454        rates.push_back(rate);
2455        rate *= p;
2456    }
2457
2458    return rates;
2459}
2460
2461const std::vector<double> & common_speculative_get_synth_probs(const common_speculative * spec) {
2462    GGML_ASSERT(spec);
2463    return spec->synth_probs;
2464}
2465
2466common_params common_base_params_to_speculative(const common_params & params) {
2467    const bool has_draft = params.speculative.has_dft();
2468
2469    const auto & params_spec = params.speculative.draft;
2470    common_params result = params;
2471
2472    result.embedding    = false;
2473    result.pooling_type = LLAMA_POOLING_TYPE_UNSPECIFIED;
2474
2475    if (has_draft) {
2476        // default to global devices value
2477        if (!params_spec.devices.empty()) {
2478            result.devices           = params_spec.devices;
2479        }
2480        result.model                 = params_spec.mparams;
2481        result.n_gpu_layers          = params_spec.n_gpu_layers;
2482        result.tensor_buft_overrides = params_spec.tensor_buft_overrides;
2483
2484        // a draft pinned to a single device doesn't need the meta wrapper an inherited -sm tensor would give it
2485        // (the device list is null-terminated, so a single device means size 2)
2486        const size_t n_devs = std::count_if(params_spec.devices.begin(), params_spec.devices.end(),
2487                [](ggml_backend_dev_t d) { return d != nullptr; });
2488        if (n_devs == 1) {
2489            result.split_mode = LLAMA_SPLIT_MODE_LAYER;
2490        }
2491
2492        if (params_spec.cpuparams.n_threads > 0) {
2493            result.cpuparams.n_threads       = params_spec.cpuparams.n_threads;
2494            result.cpuparams_batch.n_threads = params_spec.cpuparams_batch.n_threads;
2495        }
2496    }
2497
2498    result.cache_type_k  = params_spec.cache_type_k;
2499    result.cache_type_v  = params_spec.cache_type_v;
2500    result.n_outputs_max = params.n_parallel;
2501    result.n_outputs_max_per_seq = 1;
2502
2503    // dflash/dspark decode the whole noise block in a single pass and sample every block position on the backend
2504    // TODO: refactor such properties to be announced by the speculative types
2505    //       something like `struct common_speculative_type_props common_speculative_type_get_props(...);`
2506    const bool has_block_draft = std::any_of(
2507        params.speculative.types.begin(), params.speculative.types.end(),
2508        [](common_speculative_type t) {
2509            return t == COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH || t == COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK;
2510        });
2511    if (has_block_draft) {
2512        // per-seq output positions: DFlash decodes anchor + n_max masks (n_max + 1); DSpark n_max -> +1 covers both
2513        const int32_t per_seq = std::max(1, params_spec.n_max + 1);
2514        result.n_outputs_max = params.n_parallel * per_seq;
2515        if (params_spec.backend_sampling) {
2516            result.n_outputs_max_per_seq = per_seq;
2517        }
2518    }
2519
2520    return result;
2521}
2522
2523struct common_speculative_init_result::impl {
2524    impl() = default;
2525    ~impl() = default;
2526
2527    // note: the order in which model, context, etc. are declared matters because their destructors will be called bottom-to-top
2528    llama_model_ptr   model;
2529    llama_context_ptr context;
2530};
2531
2532common_speculative_init_result::common_speculative_init_result(
2533    common_params & params,
2534      llama_model * model_tgt,
2535    llama_context * ctx_tgt) :
2536    pimpl(new impl{}) {
2537    const bool has_draft = params.speculative.has_dft();
2538    const bool spec_mtp = std::find(params.speculative.types.begin(),
2539                                    params.speculative.types.end(),
2540                                    COMMON_SPECULATIVE_TYPE_DRAFT_MTP) != params.speculative.types.end();
2541
2542    auto mparams = common_model_params_to_llama(params);
2543    auto cparams = common_context_params_to_llama(params);
2544
2545    if (spec_mtp) {
2546        cparams.ctx_type = LLAMA_CONTEXT_TYPE_MTP;
2547    }
2548
2549    // the draft context holds as many tokens per sequence as the target context
2550    cparams.n_ctx = llama_n_ctx(ctx_tgt);
2551
2552    // note: for small models maybe we can set this to the maximum possible draft from all speculative types
2553    //       the extra memory for small models is likely negligible?
2554    cparams.n_rs_seq  = 0;
2555    cparams.ctx_other = ctx_tgt;
2556
2557    std::string model_path;
2558    if (has_draft) {
2559        model_path = params.speculative.draft.mparams.path;
2560        LOG_INF("%s: loading draft model '%s'\n", __func__, model_path.c_str());
2561
2562        llama_model * model_dft = llama_model_load_from_file(params.model.path.c_str(), mparams);
2563        if (model_dft == NULL) {
2564            LOG_ERR("%s: failed to load draft model, '%s'\n", __func__, model_path.c_str());
2565            return;
2566        }
2567
2568        pimpl->model.reset(model_dft);
2569
2570        llama_context * ctx_dft = llama_init_from_model(model_dft, cparams);
2571        if (ctx_dft == nullptr) {
2572            LOG_ERR("%s: failed to create MTP context\n", __func__);
2573            return;
2574        }
2575
2576        pimpl->context.reset(ctx_dft);
2577    } else if (spec_mtp) {
2578        model_path = params.model.path;
2579
2580        LOG_INF("%s: creating MTP draft context against the target model '%s'\n", __func__, model_path.c_str());
2581
2582        llama_context * ctx_dft = llama_init_from_model(model_tgt, cparams);
2583        if (ctx_dft == nullptr) {
2584            LOG_ERR("%s: failed to create MTP context\n", __func__);
2585            return;
2586        }
2587
2588        pimpl->context.reset(ctx_dft);
2589    }
2590}
2591
2592common_speculative_init_result::~common_speculative_init_result() = default;
2593
2594llama_model * common_speculative_init_result::model() {
2595    return pimpl->model.get();
2596}
2597
2598llama_context * common_speculative_init_result::context() {
2599    return pimpl->context.get();
2600}
2601
2602common_speculative_init_result_ptr common_speculative_init_from_params(common_params & params, llama_model * model_tgt, llama_context * ctx_tgt) {
2603    return std::make_unique<common_speculative_init_result>(params, model_tgt, ctx_tgt);
2604}
2605
2606common_speculative_output_limits common_speculative_get_output_limits(
2607        int32_t n_batch, int32_t n_parallel, int32_t n_draft) {
2608    const int64_t per_seq = 1 + (int64_t) std::max(0, n_draft);
2609    const int64_t total   = (int64_t) n_parallel * per_seq;
2610
2611    return {
2612        /* .total   = */ (int32_t) std::min<int64_t>(n_batch, total),
2613        /* .per_seq = */ (int32_t) std::min<int64_t>(n_batch, per_seq),
2614    };
2615}
2616
2617// initialization of the speculative decoding system
2618//
2619common_speculative * common_speculative_init(common_params_speculative & params, uint32_t n_seq) {
2620    // Compute the implementations to use based on the config and their order of preference
2621    std::vector<common_speculative_config> configs = {}; // list of speculative configs to try
2622    {
2623        uint32_t enabled_configs = common_get_enabled_speculative_configs(params.types);
2624
2625        auto add_config_if_enabled = [&](common_speculative_type type, bool available = true) {
2626            if (available && (enabled_configs & (1u << type))) {
2627                configs.emplace_back(type, params);
2628            }
2629        };
2630
2631        // when adding a new type - update here the logic above
2632        static_assert(COMMON_SPECULATIVE_TYPE_COUNT == 11);
2633
2634        // this list here defines the priority of the speculators
2635        // the one with highest priority are listed first
2636        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE);
2637        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K);
2638        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V);
2639        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_NGRAM_MOD);
2640        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_NGRAM_CACHE);
2641
2642        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE);
2643        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3, params.draft.ctx_dft != nullptr);
2644        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_DRAFT_MTP,    params.draft.ctx_dft != nullptr);
2645        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH, params.draft.ctx_dft != nullptr);
2646        add_config_if_enabled(COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK, params.draft.ctx_dft != nullptr);
2647    }
2648
2649    std::vector<std::unique_ptr<common_speculative_impl>> impls = {};
2650
2651    for (const common_speculative_config & config : configs) {
2652        switch (config.type) {
2653            case COMMON_SPECULATIVE_TYPE_NONE:
2654                break;
2655            case COMMON_SPECULATIVE_TYPE_DRAFT_SIMPLE: {
2656                impls.push_back(std::make_unique<common_speculative_impl_draft_simple>(config.params, n_seq));
2657                break;
2658            }
2659            case COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3: {
2660                impls.push_back(std::make_unique<common_speculative_impl_draft_eagle3>(config.params, n_seq));
2661                break;
2662            }
2663            case COMMON_SPECULATIVE_TYPE_DRAFT_MTP: {
2664                impls.push_back(std::make_unique<common_speculative_impl_draft_mtp>(config.params, n_seq));
2665                break;
2666            }
2667            case COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH: {
2668                impls.push_back(std::make_unique<common_speculative_impl_draft_dflash>(config.params, n_seq));
2669                break;
2670            }
2671            case COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK: {
2672                impls.push_back(std::make_unique<common_speculative_impl_draft_dflash>(
2673                        config.params, n_seq, COMMON_SPECULATIVE_TYPE_DRAFT_DSPARK));
2674                break;
2675            }
2676            case COMMON_SPECULATIVE_TYPE_NGRAM_SIMPLE: {
2677                common_ngram_map ngram_map = get_common_ngram_map(config.type, config.params.ngram_simple);
2678
2679                uint16_t ngram_size_key   = ngram_map.size_key;
2680                uint16_t mgram_size_value = ngram_map.size_value;
2681
2682                auto config_simple = common_ngram_simple_config {
2683                    /* .size_ngram = */ ngram_size_key,
2684                    /* .size_mgram = */ mgram_size_value
2685                };
2686                auto state = std::make_unique<common_speculative_impl_ngram_simple>(
2687                    /* .params = */ config.params,
2688                    /* .n_seq  = */ n_seq,
2689                    /* .state  = */ config_simple
2690                );
2691                impls.push_back(std::move(state));
2692                break;
2693            }
2694            case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K: {
2695                impls.push_back(
2696                        std::make_unique<common_speculative_impl_ngram_map_k>(
2697                            get_common_ngram_map(config.type, config.params.ngram_map_k), n_seq));
2698                break;
2699            }
2700            case COMMON_SPECULATIVE_TYPE_NGRAM_MAP_K4V: {
2701                impls.push_back(
2702                        std::make_unique<common_speculative_impl_ngram_map_k>(
2703                            get_common_ngram_map(config.type, config.params.ngram_map_k4v), n_seq));
2704                break;
2705            }
2706            case COMMON_SPECULATIVE_TYPE_NGRAM_MOD: {
2707                impls.push_back(
2708                        std::make_unique<common_speculative_impl_ngram_mod>(config.params, n_seq));
2709                break;
2710            }
2711            case COMMON_SPECULATIVE_TYPE_NGRAM_CACHE: {
2712                auto state = create_state_ngram_cache(
2713                        config, n_seq,
2714                        params.ngram_cache.lookup_cache_static,
2715                        params.ngram_cache.lookup_cache_dynamic);
2716                impls.push_back(std::make_unique<common_speculative_impl_ngram_cache>(state));
2717                break;
2718            }
2719            default:
2720                break;
2721        }
2722    }
2723
2724    if (impls.empty()) {
2725        SPC_TRC("%s", "no implementations specified for speculative decoding\n");
2726        return nullptr;
2727    }
2728
2729    common_speculative_ptr result(new common_speculative {
2730        /* .dparams     = */ common_speculative_draft_params_vec(n_seq),
2731        /* .impls       = */ std::move(impls),
2732        /* .impl_last   = */ std::vector<common_speculative_impl *>(n_seq, nullptr),
2733        /* .synth_probs = */ {},
2734    });
2735
2736    const int32_t n_max_configured = common_speculative_n_max(&params);
2737    const int32_t n_max_effective  = common_speculative_n_max(result.get());
2738    const auto rates = common_speculative_synth_rates_resolve(&params, n_max_effective);
2739
2740    std::vector<std::string> rates_str;
2741    rates_str.reserve(rates.size());
2742    result->synth_probs.reserve(rates.size());
2743    double rate_prev = 1.0;
2744    double acceptance_length = 1.0;
2745    for (const double rate : rates) {
2746        result->synth_probs.push_back(rate_prev > 0.0 ? rate / rate_prev : 0.0);
2747        rates_str.push_back(string_format("%.6g", rate));
2748        rate_prev = rate;
2749        acceptance_length += rate;
2750    }
2751    if (!result->synth_probs.empty()) {
2752        SPC_WRN("%s", "synthetic speculative acceptance is enabled for benchmarking; generated output is not valid\n");
2753        if (n_max_effective != n_max_configured) {
2754            SPC_WRN("synthetic acceptance draft limit was reduced from %d to %d by the initialized speculative implementations\n",
2755                    n_max_configured, n_max_effective);
2756        }
2757        SPC_INF("synthetic acceptance: n_max = %zu, mean length = %.6f, rates = [%s]\n",
2758                rates.size(), acceptance_length, string_join(rates_str, ", ").c_str());
2759    }
2760
2761    return result.release();
2762}
2763
2764void common_speculative_free(common_speculative * spec) {
2765    if (spec == nullptr) {
2766        return;
2767    }
2768
2769    delete spec;
2770}
2771
2772common_speculative_draft_params & common_speculative_get_draft_params(
2773        common_speculative * spec,
2774        llama_seq_id seq_id) {
2775    GGML_ASSERT(spec);
2776    GGML_ASSERT(seq_id < (llama_seq_id) spec->dparams.size());
2777
2778    return spec->dparams[seq_id];
2779}
2780
2781void common_speculative_begin(common_speculative * spec, llama_seq_id seq_id, const llama_tokens & prompt) {
2782    if (spec == nullptr) {
2783        return;
2784    }
2785
2786    for (auto & impl : spec->impls) {
2787        common_time_meas tm(impl->t_begin_us, !impl->gen_perf);
2788        impl->begin(seq_id, prompt);
2789        impl->n_call_begin++;
2790    }
2791}
2792
2793bool common_speculative_process(common_speculative * spec, const llama_batch & batch) {
2794    bool result = true;
2795
2796    if (spec == nullptr) {
2797        return result;
2798    }
2799
2800    for (auto & impl : spec->impls) {
2801        result = result && impl->process(batch);
2802    }
2803
2804    return result;
2805}
2806
2807void common_speculative_draft(common_speculative * spec) {
2808    if (spec == nullptr) {
2809        return;
2810    }
2811
2812    auto & dparams = spec->dparams;
2813
2814    {
2815        int n_drafting = 0;
2816
2817        for (auto & dp : dparams) {
2818            GGML_ASSERT(!dp.drafting || dp.result->empty());
2819
2820            if (dp.drafting) {
2821                n_drafting++;
2822            }
2823        }
2824
2825        if (n_drafting == 0) {
2826            return;
2827        }
2828    }
2829
2830    for (auto & impl : spec->impls) {
2831        {
2832            common_time_meas tm(impl->t_draft_us, !impl->gen_perf);
2833            impl->draft(dparams);
2834            impl->n_call_draft++;
2835        }
2836
2837        int n_drafting = 0;
2838
2839        for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) dparams.size(); ++seq_id) {
2840            auto & dp = dparams[seq_id];
2841
2842            if (!dp.drafting) {
2843                continue;
2844            }
2845
2846            auto & result = *dp.result;
2847
2848            // a new draft has been sampled
2849            if (dp.drafting && !result.empty()) {
2850                dp.drafting = false;
2851
2852                if (dp.n_max > 0) {
2853                    if (!result.empty() && (int) result.size() > dp.n_max) {
2854                        SPC_DBG("truncating draft to %d tokens\n", dp.n_max);
2855                        result.resize(dp.n_max);
2856                    }
2857                }
2858
2859                if (!result.empty()) {
2860                    SPC_DBG("called impl %s, hist size = %zu, call_count = %zu, gen = %zu\n",
2861                            common_speculative_type_to_str(impl.get()->type).c_str(), dp.prompt->size(),
2862                            impl.get()->n_call_draft, result.size());
2863
2864                    // remember which implementation was used
2865                    spec->impl_last[seq_id] = impl.get();
2866
2867                    impl->n_gen_drafts++;
2868                    impl->n_gen_tokens += result.size();
2869                }
2870            }
2871
2872            if (dp.drafting) {
2873                n_drafting++;
2874            }
2875        }
2876
2877        if (n_drafting == 0) {
2878            break;
2879        }
2880    }
2881
2882    // these sequences failed to generate a draft
2883    for (llama_seq_id seq_id = 0; seq_id < (llama_seq_id) dparams.size(); ++seq_id) {
2884        auto & dp = dparams[seq_id];
2885
2886        if (dp.drafting) {
2887            dp.drafting = false;
2888        }
2889    }
2890}
2891
2892void common_speculative_accept(common_speculative * spec, llama_seq_id seq_id, uint16_t n_accepted) {
2893    common_speculative_impl * impl = spec->impl_last[seq_id];
2894
2895    if (impl == nullptr) {
2896        GGML_ASSERT(n_accepted == 0);
2897        return;
2898    }
2899
2900    {
2901        common_time_meas tm(impl->t_accept_us, !impl->gen_perf);
2902
2903        if (impl->n_acc_tokens_per_pos.size() < n_accepted) {
2904            impl->n_acc_tokens_per_pos.resize(n_accepted, 0);
2905        }
2906
2907        for (size_t i = 0; i < n_accepted; ++i) {
2908            impl->n_acc_tokens_per_pos[i]++;
2909        }
2910
2911        if (n_accepted > 0) {
2912            impl->n_acc_drafts++;
2913            impl->n_acc_tokens += n_accepted;
2914        }
2915
2916        impl->accept(seq_id, n_accepted, false);
2917        impl->n_call_accept++;
2918    }
2919
2920    // accept with the rest of the implementations, using is_other == true
2921    for (auto & impl_other : spec->impls) {
2922        if (impl_other.get() != impl) {
2923            impl_other->accept(seq_id, n_accepted, true);
2924        }
2925    }
2926}
2927
2928// TODO: support the case of more than one speculative implementations having a state
2929bool common_speculative_get_state(common_speculative * spec, llama_seq_id seq_id, std::vector<uint8_t> & data) {
2930    if (spec == nullptr) {
2931        return false;
2932    }
2933
2934    for (auto & impl : spec->impls) {
2935        if (impl->get_state(seq_id, data)) {
2936            return true;
2937        }
2938    }
2939
2940    return false;
2941}
2942
2943void common_speculative_set_state(common_speculative * spec, llama_seq_id seq_id, const std::vector<uint8_t> & data) {
2944    if (spec == nullptr) {
2945        return;
2946    }
2947
2948    for (auto & impl : spec->impls) {
2949        impl->set_state(seq_id, data);
2950    }
2951}
2952
2953void common_speculative_print_stats(const common_speculative * spec) {
2954    if (spec == nullptr) {
2955        return;
2956    }
2957
2958    for (const auto & impl : spec->impls) {
2959        std::string str_perf;
2960        if (impl->gen_perf) {
2961            std::ostringstream oss;
2962            oss << std::fixed << std::setprecision(3) << impl->t_begin_us / 1000.0 << ", ";
2963            oss << std::fixed << std::setprecision(3) << impl->t_draft_us / 1000.0 << ", ";
2964            oss << std::fixed << std::setprecision(3) << impl->t_accept_us / 1000.0;
2965            str_perf = ", dur(b,g,a) = " + oss.str() + " ms";
2966        } else {
2967            str_perf = "";
2968        }
2969
2970        std::string str_stats;
2971        if (impl->n_call_accept > 0) {
2972            const double mean =
2973                1.0 + (double) impl->n_acc_tokens / (double) impl->n_call_accept;
2974            std::ostringstream tmp;
2975            tmp << std::fixed << std::setprecision(3);
2976            for (size_t i = 0; i < impl->n_acc_tokens_per_pos.size(); ++i) {
2977                if (i > 0) {
2978                    tmp << ", ";
2979                }
2980                tmp << (double) impl->n_acc_tokens_per_pos[i] / (double) impl->n_call_accept;
2981            }
2982            std::ostringstream oss;
2983            oss << std::fixed << std::setprecision(2) << mean;
2984            str_stats = ", #mean acc len = " + oss.str() + ", #acc rate/pos = (" + tmp.str() + ")";
2985        }
2986
2987        SPC_TRC("statistics %16s: #calls(b,g,a) = %4zu %6zu %6zu, #gen drafts = %6zu, #acc drafts = %5zu, #gen tokens = %6zu, #acc tokens = %5zu%s%s\n",
2988                common_speculative_type_to_str(impl->type).c_str(),
2989                impl->n_call_begin, impl->n_call_draft, impl->n_call_accept,
2990                impl->n_gen_drafts,
2991                impl->n_acc_drafts,
2992                impl->n_gen_tokens,
2993                impl->n_acc_tokens,
2994                str_stats.c_str(),
2995                str_perf.c_str());
2996    }
2997}