char-fork/llama.cpp

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

Max Krasnyanskyggml-meta: propagate buffer usage and call init on the new tensors (#27586)5d5cb4c3a

char/aliceai-t5-moe
115.9 KiB2511 linesraw
1#include "ggml.h"
2#include "ggml-impl.h"
3#include "ggml-backend.h"
4#include "ggml-backend-impl.h"
5#include "ggml-alloc.h"
6#include "ggml-cpp.h"
7
8#include <algorithm>
9#include <cassert>
10#include <cmath>
11#include <cstddef>
12#include <cstdint>
13#include <cstring>
14#include <map>
15#include <memory>
16#include <set>
17#include <string>
18#include <tuple>
19#include <utility>
20#include <vector>
21
22struct ggml_backend_meta_device;
23struct ggml_backend_meta_buffer_type;
24struct ggml_backend_meta_buffer;
25struct ggml_backend_meta;
26
27const char * ggml_backend_meta_split_axis_name(enum ggml_backend_meta_split_axis split_axis) {
28    switch (split_axis) {
29        case GGML_BACKEND_SPLIT_AXIS_0:
30            return "0";
31        case GGML_BACKEND_SPLIT_AXIS_1:
32            return "1";
33        case GGML_BACKEND_SPLIT_AXIS_2:
34            return "2";
35        case GGML_BACKEND_SPLIT_AXIS_3:
36            return "3";
37        case GGML_BACKEND_SPLIT_AXIS_MIRRORED:
38            return "MIRRORED";
39        case GGML_BACKEND_SPLIT_AXIS_PARTIAL:
40            return "PARTIAL";
41        case GGML_BACKEND_SPLIT_AXIS_NONE:
42            return "NONE";
43        case GGML_BACKEND_SPLIT_AXIS_UNKNOWN:
44            return "UNKNOWN";
45        default:
46            GGML_ABORT("fatal error");
47    }
48}
49
50//
51// meta backend device
52//
53
54struct ggml_backend_meta_device_context {
55    std::vector<ggml_backend_dev_t>     simple_devs;
56    ggml_backend_meta_get_split_state_t get_split_state;
57    void *                              get_split_state_ud;
58
59    std::string name;
60    std::string description;
61
62    ggml_backend_meta_device_context(
63            std::vector<ggml_backend_dev_t> simple_devs, ggml_backend_meta_get_split_state_t get_split_state, void * get_split_state_ud) :
64            simple_devs(std::move(simple_devs)), get_split_state(get_split_state), get_split_state_ud(get_split_state_ud) {
65        name        = std::string("Meta(");
66        description = std::string("Meta(");
67        for (size_t i = 0; i < simple_devs.size(); i++) {
68            if (i > 0) {
69                name        += ",";
70                description += ",";
71            }
72            name        += ggml_backend_dev_name       (simple_devs[i]);
73            description += ggml_backend_dev_description(simple_devs[i]);
74        }
75        name        += ")";
76        description += ")";
77    }
78
79    bool operator<(const ggml_backend_meta_device_context & other) const {
80        return std::tie(simple_devs, get_split_state, get_split_state_ud)
81            < std::tie(other.simple_devs, other.get_split_state, other.get_split_state_ud);
82    }
83};
84
85static bool ggml_backend_dev_is_meta(ggml_backend_dev_t dev);
86
87static const char * ggml_backend_meta_device_get_name(ggml_backend_dev_t dev) {
88    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
89    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
90    return meta_dev_ctx->name.c_str();
91}
92
93static const char * ggml_backend_meta_device_get_description(ggml_backend_dev_t dev) {
94    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
95    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
96    return meta_dev_ctx->description.c_str();
97}
98
99static void ggml_backend_meta_device_get_memory(ggml_backend_dev_t dev, size_t * free, size_t * total) {
100    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
101    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
102    *free  = 0;
103    *total = 0;
104    for (ggml_backend_dev_t dev : meta_dev_ctx->simple_devs) {
105        size_t tmp_free, tmp_total;
106        ggml_backend_dev_memory(dev, &tmp_free, &tmp_total);
107        *free  += tmp_free;
108        *total += tmp_total;
109    }
110}
111
112static enum ggml_backend_dev_type ggml_backend_meta_device_get_type(ggml_backend_dev_t dev) {
113    return GGML_BACKEND_DEVICE_TYPE_META;
114
115    GGML_UNUSED(dev);
116}
117
118static void ggml_backend_meta_device_get_props(ggml_backend_dev_t dev, ggml_backend_dev_props * props) {
119    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
120    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
121
122    // TODO replace placeholders
123    props->name        = ggml_backend_meta_device_get_name(dev);
124    props->description = ggml_backend_meta_device_get_description(dev);
125    props->type        = ggml_backend_meta_device_get_type(dev);
126    props->device_id   = 0;
127
128    ggml_backend_meta_device_get_memory(dev, &props->memory_free, &props->memory_total);
129
130    props->caps = {
131        /* .async                 = */ true,
132        /* .host_buffer           = */ false, // Not implemented.
133        /* .buffer_from_host_ptr  = */ false, // Not implemented.
134        /* .events                = */ false, // Not implemented.
135        /* .mmap_support          = */ true,
136    };
137    for (ggml_backend_dev_t simple_dev : meta_dev_ctx->simple_devs) {
138        ggml_backend_dev_props tmp_props;
139        ggml_backend_dev_get_props(simple_dev, &tmp_props);
140        props->caps.async                = props->caps.async                && tmp_props.caps.async;
141        props->caps.host_buffer          = props->caps.host_buffer          && tmp_props.caps.host_buffer;
142        props->caps.buffer_from_host_ptr = props->caps.buffer_from_host_ptr && tmp_props.caps.buffer_from_host_ptr;
143        props->caps.events               = props->caps.events               && tmp_props.caps.events;
144        props->caps.mmap_support         = props->caps.mmap_support         && tmp_props.caps.mmap_support;
145    }
146}
147
148static ggml_backend_t ggml_backend_meta_device_init_backend(ggml_backend_dev_t dev, const char * params);
149
150static ggml_backend_buffer_type_t ggml_backend_meta_device_get_buffer_type(ggml_backend_dev_t dev);
151
152static ggml_backend_buffer_type_t ggml_backend_meta_device_get_host_buffer_type(ggml_backend_dev_t dev);
153
154static bool ggml_backend_meta_device_supports_op(ggml_backend_dev_t dev, const ggml_tensor * op) {
155    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
156    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
157    return std::all_of(meta_dev_ctx->simple_devs.begin(), meta_dev_ctx->simple_devs.end(),
158        [op](ggml_backend_dev_t simple_dev) { return ggml_backend_dev_supports_op(simple_dev, op); });
159}
160
161static bool ggml_backend_meta_device_supports_buft(ggml_backend_dev_t dev, ggml_backend_buffer_type_t buft) {
162    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
163    ggml_backend_dev_t dev_buft = ggml_backend_buft_get_device(buft);
164    if (!ggml_backend_dev_is_meta(dev_buft)) {
165        return false;
166    }
167    const ggml_backend_meta_device_context * meta_dev_ctx      = (const ggml_backend_meta_device_context *) dev->context;
168    const ggml_backend_meta_device_context * meta_buft_dev_ctx = (const ggml_backend_meta_device_context *) dev_buft->context;
169    if (meta_dev_ctx->simple_devs.size() != meta_buft_dev_ctx->simple_devs.size()) {
170        return false;
171    }
172    for (size_t i = 0; i < meta_dev_ctx->simple_devs.size(); i++) {
173        if (meta_dev_ctx->simple_devs[i] != meta_buft_dev_ctx->simple_devs[i]) {
174            return false;
175        }
176    }
177    return true;
178}
179
180static const ggml_backend_device_i ggml_backend_meta_device_iface = {
181    /* .get_name             = */ ggml_backend_meta_device_get_name,
182    /* .get_description      = */ ggml_backend_meta_device_get_description,
183    /* .get_memory           = */ ggml_backend_meta_device_get_memory,
184    /* .get_type             = */ ggml_backend_meta_device_get_type,
185    /* .get_props            = */ ggml_backend_meta_device_get_props,
186    /* .init_backend         = */ ggml_backend_meta_device_init_backend,
187    /* .get_buffer_type      = */ ggml_backend_meta_device_get_buffer_type,
188    /* .get_host_buffer_type = */ ggml_backend_meta_device_get_host_buffer_type,
189    /* .buffer_from_host_ptr = */ nullptr,
190    /* .supports_op          = */ ggml_backend_meta_device_supports_op,
191    /* .supports_buft        = */ ggml_backend_meta_device_supports_buft,
192    /* .offload_op           = */ nullptr,
193    /* .event_new            = */ nullptr,
194    /* .event_free           = */ nullptr,
195    /* .event_synchronize    = */ nullptr,
196};
197
198static bool ggml_backend_dev_is_meta(ggml_backend_dev_t dev) {
199    return dev != nullptr && dev->iface.get_name == ggml_backend_meta_device_iface.get_name;
200}
201
202static size_t ggml_backend_meta_dev_n_devs(ggml_backend_dev_t meta_dev) {
203    GGML_ASSERT(ggml_backend_dev_is_meta(meta_dev));
204    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) meta_dev->context;
205    return meta_dev_ctx->simple_devs.size();
206}
207
208static ggml_backend_dev_t ggml_backend_meta_dev_simple_dev(ggml_backend_dev_t meta_dev, size_t index) {
209    GGML_ASSERT(ggml_backend_dev_is_meta(meta_dev));
210    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) meta_dev->context;
211    GGML_ASSERT(index < meta_dev_ctx->simple_devs.size());
212    return meta_dev_ctx->simple_devs[index];
213}
214
215ggml_backend_dev_t ggml_backend_meta_device(
216        ggml_backend_dev_t * devs, size_t n_devs, ggml_backend_meta_get_split_state_t get_split_state, void * get_split_state_ud) {
217    GGML_ASSERT(n_devs <= GGML_BACKEND_META_MAX_DEVICES);
218    // TODO: this is not thread-safe - needs to be fixed
219    static std::vector<std::unique_ptr<ggml_backend_meta_device_context>>         ctxs;
220    static std::map<ggml_backend_meta_device_context, struct ggml_backend_device> meta_devs;
221
222    std::vector<ggml_backend_dev_t> simple_devs;
223    simple_devs.reserve(n_devs);
224    for (size_t i = 0; i < n_devs; i++) {
225        simple_devs.push_back(devs[i]);
226    }
227    ggml_backend_meta_device_context ctx(simple_devs, get_split_state, get_split_state_ud);
228
229    {
230        auto it = meta_devs.find(ctx);
231        if (it != meta_devs.end()) {
232            return &it->second;
233        }
234    }
235    ctxs.push_back(std::make_unique<ggml_backend_meta_device_context>(ctx));
236
237    struct ggml_backend_device meta_dev = {
238        /*iface  =*/ ggml_backend_meta_device_iface,
239        /*reg    =*/ nullptr,
240        /*ctx    =*/ ctxs.back().get(),
241    };
242
243    auto result = meta_devs.emplace(*ctxs.back(), meta_dev);
244    return &result.first->second;
245}
246
247//
248// meta backend buffer type
249//
250
251struct ggml_backend_meta_buffer_type_context {
252    std::vector<ggml_backend_buffer_type_t> simple_bufts;
253
254    std::string name;
255
256    ggml_backend_meta_buffer_type_context(std::vector<ggml_backend_buffer_type_t> simple_bufts) : simple_bufts(std::move(simple_bufts)) {
257        name = "Meta(";
258        for (size_t i = 0; i < simple_bufts.size(); i++) {
259            if (i > 0) {
260                name += ",";
261            }
262            name += ggml_backend_buft_name(simple_bufts[i]);
263        }
264        name += ")";
265    }
266
267    bool operator<(const ggml_backend_meta_buffer_type_context & other) const {
268        return simple_bufts < other.simple_bufts;
269    }
270};
271
272static size_t ggml_backend_meta_buft_n_bufts(ggml_backend_buffer_type_t meta_buft) {
273    GGML_ASSERT(ggml_backend_buft_is_meta(meta_buft));
274    const ggml_backend_meta_buffer_type_context * meta_buft_ctx = (const ggml_backend_meta_buffer_type_context *) meta_buft->context;
275    return meta_buft_ctx->simple_bufts.size();
276}
277
278static const char * ggml_backend_meta_buffer_type_get_name(ggml_backend_buffer_type_t buft) {
279    GGML_ASSERT(ggml_backend_buft_is_meta(buft));
280    const ggml_backend_meta_buffer_type_context * meta_buft_ctx = (const ggml_backend_meta_buffer_type_context *) buft->context;
281    return meta_buft_ctx->name.c_str();
282}
283
284static ggml_backend_buffer_type_t ggml_backend_meta_buft_simple_buft(ggml_backend_buffer_type_t meta_buft, size_t index) {
285    GGML_ASSERT(ggml_backend_buft_is_meta(meta_buft));
286    const ggml_backend_meta_buffer_type_context * meta_buft_ctx = (const ggml_backend_meta_buffer_type_context *) meta_buft->context;
287    GGML_ASSERT(index < meta_buft_ctx->simple_bufts.size());
288    return meta_buft_ctx->simple_bufts[index];
289}
290
291static ggml_backend_buffer_t ggml_backend_meta_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size);
292
293static size_t ggml_backend_meta_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) {
294    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
295    size_t max_alignment = 1;
296    for (size_t i = 0; i < n_simple_bufts; i++) {
297        const size_t alignment = ggml_backend_buft_get_alignment(ggml_backend_meta_buft_simple_buft(buft, i));
298        max_alignment = std::max(max_alignment, alignment);
299        GGML_ASSERT(max_alignment % alignment == 0);
300    }
301    return max_alignment;
302}
303
304static size_t ggml_backend_meta_buffer_type_get_max_size(ggml_backend_buffer_type_t buft) {
305    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
306    size_t max_size = SIZE_MAX;
307    for (size_t i = 0; i < n_simple_bufts; i++) {
308        max_size = std::min(max_size, ggml_backend_buft_get_max_size(ggml_backend_meta_buft_simple_buft(buft, i)));
309    }
310    return max_size;
311}
312
313static size_t ggml_backend_meta_buffer_type_get_alloc_size(ggml_backend_buffer_type_t buft, const ggml_tensor * tensor) {
314    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
315    size_t max_alloc_size = 0;
316    for (size_t i = 0; i < n_simple_bufts; i++) {
317        const size_t alloc_size = ggml_backend_buft_get_alloc_size(ggml_backend_meta_buft_simple_buft(buft, i), tensor);
318        max_alloc_size = std::max(max_alloc_size, alloc_size);
319    }
320    return max_alloc_size;
321}
322
323static bool ggml_backend_meta_buffer_type_is_host(ggml_backend_buffer_type_t buft) {
324    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
325    for (size_t i = 0; i < n_simple_bufts; i++) {
326        if (!ggml_backend_buft_is_host(ggml_backend_meta_buft_simple_buft(buft, i))) {
327            return false;
328        }
329    }
330    return true;
331}
332
333static const struct ggml_backend_buffer_type_i ggml_backend_meta_buffer_type_iface = {
334    /* .get_name         = */ ggml_backend_meta_buffer_type_get_name,
335    /* .alloc_buffer     = */ ggml_backend_meta_buffer_type_alloc_buffer,
336    /* .get_alignment    = */ ggml_backend_meta_buffer_type_get_alignment,
337    /* .get_max_size     = */ ggml_backend_meta_buffer_type_get_max_size,
338    /* .get_alloc_size   = */ ggml_backend_meta_buffer_type_get_alloc_size,
339    /* .is_host          = */ ggml_backend_meta_buffer_type_is_host,
340};
341
342bool ggml_backend_buft_is_meta(ggml_backend_buffer_type_t buft) {
343    return buft != nullptr && buft->iface.get_name == ggml_backend_meta_buffer_type_iface.get_name;
344}
345
346static ggml_backend_buffer_type_t ggml_backend_meta_device_get_buffer_type(ggml_backend_dev_t dev) {
347    static std::map<ggml_backend_dev_t, struct ggml_backend_buffer_type> meta_bufts;
348    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
349    {
350        auto it = meta_bufts.find(dev);
351        if (it != meta_bufts.end()) {
352            return &it->second;
353        }
354    }
355
356    const size_t n_devs = ggml_backend_meta_dev_n_devs(dev);
357    std::vector<ggml_backend_buffer_type_t> simple_bufts;
358    simple_bufts.reserve(n_devs);
359    for (size_t i = 0; i < n_devs; i++) {
360        simple_bufts.push_back(ggml_backend_dev_buffer_type(ggml_backend_meta_dev_simple_dev(dev, i)));
361    }
362    ggml_backend_meta_buffer_type_context * buft_ctx = new ggml_backend_meta_buffer_type_context(simple_bufts);
363
364    struct ggml_backend_buffer_type meta_buft = {
365        /*iface  =*/ ggml_backend_meta_buffer_type_iface,
366        /*device =*/ dev,
367        /*ctx    =*/ buft_ctx,
368    };
369    auto result = meta_bufts.emplace(dev, meta_buft);
370    return &result.first->second;
371}
372
373static ggml_backend_buffer_type_t ggml_backend_meta_device_get_host_buffer_type(ggml_backend_dev_t dev) {
374    GGML_ASSERT(ggml_backend_dev_is_meta(dev));
375    const ggml_backend_meta_device_context * meta_dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
376
377    ggml_backend_buffer_type_t host_buft = nullptr;
378    for (ggml_backend_dev_t simple_dev : meta_dev_ctx->simple_devs) {
379        ggml_backend_buffer_type_t simple_host_buft = ggml_backend_dev_host_buffer_type(simple_dev);
380        if (simple_host_buft == nullptr) {
381            return nullptr;
382        }
383        if (host_buft == nullptr) {
384            host_buft = simple_host_buft;
385        } else if (host_buft != simple_host_buft) {
386            // if different simple devices have different host buffer types,
387            // we cannot provide a single host buffer type for the meta device
388            return nullptr;
389        }
390    }
391    return host_buft;
392}
393
394//
395// meta backend buffer
396//
397
398// Container to hold the tensor slices per simple ggml backend buffer.
399struct ggml_backend_meta_simple_tensor_container {
400    std::vector<ggml_context_ptr> ctxs;
401    std::map<const ggml_tensor *, std::vector<ggml_tensor *>> simple_tensors;
402
403    ggml_backend_meta_simple_tensor_container(const ggml_init_params & params, const int n_simple) {
404        ctxs.reserve(n_simple);
405        for (int i = 0; i < n_simple; i++) {
406            ctxs.emplace_back(ggml_init(params));
407        }
408    }
409    ggml_backend_meta_simple_tensor_container() {}
410};
411
412struct ggml_backend_meta_buffer_context {
413    // FIXME
414    // Most tensors can simply be stored statically in their own buffer.
415    // Externally created views however also need a mapping to simple tensors but they use the buffer of the view source.
416    // If external views are simply using that buffer they will slowly deplete its memory.
417    // Current solution: rotating set of 2 "compute" containers to hold external views, works correctly for llama.cpp.
418    // Long-term: tie the lifetime of external views to the meta backend executing the graph instead,
419    //     currently not possible due to graph-external operations in the backend scheduler.
420    ggml_backend_meta_simple_tensor_container stc_static;
421    ggml_backend_meta_simple_tensor_container stc_compute[2];
422    int stc_compute_index      = 0;
423    int stc_compute_index_next = 0;
424    std::vector<ggml_backend_buffer_ptr> bufs;
425
426    // FIXME
427    // The size of the split state cache is unbounded and can theoretically grow infinitely large.
428    // However, it is also expensive to build and clearing it on every rebuild in ggml_backend_meta_graph_compute is too expensive.
429    static constexpr size_t nbtc = GGML_TENSOR_SIZE - sizeof(ggml_tensor::padding);
430    std::map<std::pair<const ggml_tensor *, bool>, std::pair<ggml_backend_meta_split_state, char[nbtc]>> split_state_cache;
431
432    int debug;
433
434    ggml_backend_meta_buffer_context(
435            ggml_backend_meta_simple_tensor_container & stc_static,
436            ggml_backend_meta_simple_tensor_container & stc_compute_0,
437            ggml_backend_meta_simple_tensor_container & stc_compute_1,
438            const std::vector<ggml_backend_buffer_t> & bufs)
439            : stc_static(std::move(stc_static)), stc_compute{std::move(stc_compute_0), std::move(stc_compute_1)} {
440        this->bufs.reserve(bufs.size());
441        for (ggml_backend_buffer_t buf : bufs) {
442            this->bufs.emplace_back(buf);
443        }
444        const char * GGML_META_DEBUG = getenv("GGML_META_DEBUG");
445        debug = GGML_META_DEBUG ? atoi(GGML_META_DEBUG) : 0;
446    }
447
448    ggml_backend_meta_simple_tensor_container & get_simple_tensor_container(const ggml_tensor * tensor) {
449        if (stc_static.simple_tensors.find(tensor) != stc_static.simple_tensors.end()) {
450            return stc_static;
451        }
452        return stc_compute[stc_compute_index];
453    }
454};
455
456static void ggml_backend_meta_buffer_free_buffer(ggml_backend_buffer_t buffer) {
457    GGML_ASSERT(ggml_backend_buffer_is_meta(buffer));
458    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) buffer->context;
459    delete buf_ctx;
460}
461
462static size_t ggml_backend_meta_buffer_n_bufs(ggml_backend_buffer_t meta_buf) {
463    GGML_ASSERT(ggml_backend_buffer_is_meta(meta_buf));
464    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) meta_buf->context;
465    return buf_ctx->bufs.size();
466}
467
468static ggml_backend_buffer_t ggml_backend_meta_buffer_simple_buffer(ggml_backend_buffer_t meta_buf, size_t index) {
469    GGML_ASSERT(ggml_backend_buffer_is_meta(meta_buf));
470    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) meta_buf->context;
471    GGML_ASSERT(index < buf_ctx->bufs.size());
472    return buf_ctx->bufs[index].get();
473}
474
475static struct ggml_tensor * ggml_backend_meta_buffer_simple_tensor(const struct ggml_tensor * tensor, size_t index) {
476    GGML_ASSERT(ggml_backend_buffer_is_meta(tensor->buffer));
477    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) tensor->buffer->context;
478    GGML_ASSERT(index < buf_ctx->bufs.size());
479
480    ggml_backend_meta_simple_tensor_container & stc = buf_ctx->get_simple_tensor_container(tensor);
481    auto it = stc.simple_tensors.find(tensor);
482    if (it == stc.simple_tensors.end()) {
483        return nullptr;
484    }
485    return it->second[index];
486}
487
488static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(const struct ggml_tensor * tensor, bool assume_sync);
489
490static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
491        ggml_backend_meta_simple_tensor_container & stc, const struct ggml_tensor * tensor, bool assume_sync) {
492    // FIXME Currently this function preserves/erases the information in n_segments and nr in an inconsistent way.
493    // Since the operations in question are developed specifically for llama.cpp this currently does not manifest as a bug there.
494    // However, in a broader ggml context with arbitrary ggml graphs this can lead to unexpected results.
495    const size_t n_bufs = ggml_backend_meta_buffer_n_bufs(tensor->buffer);
496    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) tensor->buffer->context;
497
498    auto split_states_equal = [&](const ggml_backend_meta_split_state & a, const ggml_backend_meta_split_state & b) -> bool {
499        if (a.axis != b.axis) {
500            return false;
501        }
502        for (size_t j = 0; j < n_bufs; j++) {
503            int64_t sum_a = 0;
504            for (size_t s = 0; s < a.n_segments; s++) {
505                sum_a += a.ne[s*n_bufs + j] * a.nr[s];
506            }
507            int64_t sum_b = 0;
508            for (size_t s = 0; s < b.n_segments; s++) {
509                sum_b += b.ne[s*n_bufs + j] * b.nr[s];
510            }
511            if (sum_a != sum_b) {
512                return false;
513            }
514        }
515        return true;
516    };
517
518    auto handle_generic = [&](const std::vector<ggml_backend_meta_split_state> & src_ss, bool scalar_only) -> ggml_backend_meta_split_state {
519        ggml_backend_meta_split_state ret = {GGML_BACKEND_SPLIT_AXIS_NONE, {0}, {1}, 1};
520        for (size_t i = 0; i < GGML_MAX_SRC; i++) {
521            if (tensor->src[i] == nullptr || tensor->src[i] == tensor) {
522                continue;
523            }
524            if (ret.axis == GGML_BACKEND_SPLIT_AXIS_NONE) {
525                ret = src_ss[i];
526            } else if (!split_states_equal(src_ss[i], ret)) {
527                ret = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
528                break;
529            }
530        }
531        if (ret.axis == GGML_BACKEND_SPLIT_AXIS_NONE) {
532            ret = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
533        }
534        if (scalar_only && ret.axis >= 0 && ret.axis < GGML_MAX_DIMS) {
535            ret = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
536        }
537        GGML_ASSERT(ret.axis != GGML_BACKEND_SPLIT_AXIS_UNKNOWN);
538        return ret;
539    };
540
541    // Some ops process data on a per-row bases:
542    auto handle_per_row = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
543        GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_0);
544        return src_ss[0];
545    };
546
547    // Some ops broadcast the src1 data across src0:
548    auto handle_bin_bcast = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
549        if (src_ss[0].axis >= 0 && src_ss[0].axis < GGML_MAX_DIMS &&
550                tensor->src[1]->ne[src_ss[0].axis] == 1 && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
551            return src_ss[0];
552        }
553        if (src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && (src_ss[0].axis == src_ss[1].axis ||
554           (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && (src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL)))) {
555            return src_ss[0]; // GGML_OP_ADD_ID
556        }
557        GGML_ASSERT(tensor->src[2] == nullptr || src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
558        return handle_generic(src_ss, /*scalar_only =*/ false);
559    };
560
561    auto handle_concat = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
562        const ggml_backend_meta_split_axis concat_axis = ggml_backend_meta_split_axis(ggml_get_op_params_i32(tensor, 0));
563        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[1].axis >= 0 && src_ss[1].axis < GGML_MAX_DIMS) {
564            GGML_ASSERT(concat_axis != src_ss[1].axis);
565            return src_ss[1];
566        }
567        if (src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[0].axis >= 0 && src_ss[0].axis < GGML_MAX_DIMS) {
568            GGML_ASSERT(concat_axis != src_ss[0].axis);
569            return src_ss[0];
570        }
571        if (src_ss[0].axis == src_ss[1].axis && src_ss[0].axis != concat_axis) {
572            return src_ss[0];
573        }
574        return handle_generic(src_ss, /*scalar_only =*/ true);
575    };
576
577    auto handle_mul_mat = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
578        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
579            return {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
580        }
581        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_1 && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
582            ggml_backend_meta_split_state ret = src_ss[0];
583            ret.axis = GGML_BACKEND_SPLIT_AXIS_0;
584            ret.nr[0] = 1;
585            ret.n_segments = 1;
586            return ret;
587        }
588        if (src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_1 && src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
589            return src_ss[1];
590        }
591        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_0 && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_0) {
592            GGML_ASSERT(split_states_equal(src_ss[0], src_ss[1]));
593            return {assume_sync ? GGML_BACKEND_SPLIT_AXIS_MIRRORED : GGML_BACKEND_SPLIT_AXIS_PARTIAL, {0}, {1}, 1};
594        }
595        if (src_ss[0].axis == src_ss[1].axis && src_ss[0].axis >= GGML_BACKEND_SPLIT_AXIS_2 &&
596                src_ss[0].axis < GGML_MAX_DIMS) {
597            GGML_ASSERT(split_states_equal(src_ss[0], src_ss[1]));
598            return src_ss[0];
599        }
600        // batched matmul with the batches split across devices and a replicated activation
601        if (src_ss[0].axis >= GGML_BACKEND_SPLIT_AXIS_2 && src_ss[0].axis < GGML_MAX_DIMS &&
602                src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
603            return src_ss[0];
604        }
605        GGML_ABORT("unsupported mul_mat split states: node=%s src0=%s axis=%d src1=%s axis=%d",
606            tensor->name, tensor->src[0]->name, (int) src_ss[0].axis, tensor->src[1]->name, (int) src_ss[1].axis);
607        //return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
608    };
609
610    auto handle_reshape = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
611        switch (src_ss[0].axis) {
612            case GGML_BACKEND_SPLIT_AXIS_0:
613            case GGML_BACKEND_SPLIT_AXIS_1:
614            case GGML_BACKEND_SPLIT_AXIS_2:
615            case GGML_BACKEND_SPLIT_AXIS_3: {
616                int64_t base_ne_in = 1;
617                for (int dim = 0; dim <= src_ss[0].axis; dim++) {
618                    base_ne_in *= tensor->src[0]->ne[dim];
619                }
620                if (src_ss[0].n_segments == 1) {
621                    base_ne_in /= src_ss[0].nr[0];
622                    if (src_ss[0].axis == ggml_n_dims(tensor->src[0]) - 1 && src_ss[0].nr[0] == 1) {
623                        return {ggml_backend_meta_split_axis(ggml_n_dims(tensor) - 1), {0}, {1}, 1};
624                    }
625                    if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_0 && tensor->ne[0] == tensor->src[0]->ne[0] &&
626                            tensor->ne[1] == 1 && src_ss[0].nr[0] == 1) {
627                        bool complete_rows = true;
628                        for (size_t j = 0; j < n_bufs; j++) {
629                            const int64_t ne = src_ss[0].ne[j];
630                            complete_rows = complete_rows && (ne == 0 || ne == tensor->src[0]->ne[0]);
631                        }
632                        if (complete_rows) {
633                            // Move a complete dim-0 split to the following singleton dimension.
634                            return {GGML_BACKEND_SPLIT_AXIS_1, {0}, {1}, 1};
635                        }
636                    }
637                }
638                // Reshape outputs use one segment; split-state propagation merges source segments.
639                int64_t base_ne_out = 1;
640                for (int dim = 0; dim < GGML_MAX_DIMS; dim++) {
641                    base_ne_out *= tensor->ne[dim];
642                    if (base_ne_out % base_ne_in == 0) {
643                        return {ggml_backend_meta_split_axis(dim), {0}, {uint32_t(base_ne_out/base_ne_in)}, 1};
644                    }
645                    if (base_ne_out > base_ne_in) {
646                        GGML_ASSERT(src_ss[0].n_segments == 1);
647                        GGML_ASSERT(src_ss[0].nr[0]      == 1);
648                        return {ggml_backend_meta_split_axis(dim), {0}, {1}, 1};
649                    }
650                }
651                GGML_ABORT("shape mismatch for %s", ggml_op_name(tensor->op));
652            }
653            case GGML_BACKEND_SPLIT_AXIS_MIRRORED:
654            case GGML_BACKEND_SPLIT_AXIS_PARTIAL: {
655                return src_ss[0];
656            }
657            default: {
658                GGML_ABORT("fatal error");
659                //return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
660            }
661        }
662    };
663
664    auto handle_cpy = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
665        if (src_ss[0].axis >= 0 && src_ss[0].axis < GGML_MAX_DIMS) {
666            return handle_reshape(src_ss);
667        }
668        return handle_generic(src_ss, /*scalar_only =*/ false);
669    };
670
671    auto handle_view = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
672        if (ggml_is_contiguous(tensor) && ggml_is_contiguous(tensor->src[0])) {
673            return handle_reshape(src_ss);
674        }
675        const int axis = src_ss[0].axis;
676        {
677            bool all_strides_the_same = true;
678            for (int dim = 0; dim < GGML_MAX_DIMS; dim++) {
679                if (tensor->ne[dim] == 1 && tensor->src[0]->ne[dim] == 1) {
680                    continue;
681                }
682                if (tensor->nb[dim] != tensor->src[0]->nb[dim]) {
683                    all_strides_the_same = false;
684                    break;
685                }
686            }
687            if (all_strides_the_same) {
688                return src_ss[0];
689            }
690        }
691        if (!ggml_is_permuted(tensor) && !ggml_is_permuted(tensor->src[0]) && axis >= 0 && axis < GGML_MAX_DIMS-1) {
692            for (int dim = 0; dim < GGML_MAX_DIMS-1; dim++) {
693                if (tensor->nb[dim+1] == tensor->src[0]->nb[axis+1]) {
694                    return {ggml_backend_meta_split_axis(dim), {0}, {1}, 1};
695                }
696            }
697            GGML_ABORT("fatal error");
698        }
699        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED || src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL) {
700            return src_ss[0];
701        }
702        GGML_ABORT("view of permuted tensor not implemented");
703        //return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
704    };
705
706    auto handle_permute = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
707        switch (src_ss[0].axis) {
708            case GGML_BACKEND_SPLIT_AXIS_0:
709            case GGML_BACKEND_SPLIT_AXIS_1:
710            case GGML_BACKEND_SPLIT_AXIS_2:
711            case GGML_BACKEND_SPLIT_AXIS_3: {
712                GGML_ASSERT(src_ss[0].n_segments == 1 || src_ss[0].nr[0] == 1);
713                return {ggml_backend_meta_split_axis(tensor->op_params[src_ss[0].axis]), {0}, {src_ss[0].nr[0]}, 1};
714            }
715            case GGML_BACKEND_SPLIT_AXIS_MIRRORED:
716            case GGML_BACKEND_SPLIT_AXIS_PARTIAL: {
717                return src_ss[0];
718            }
719            default: {
720                GGML_ABORT("fatal error");
721                //return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
722            }
723        }
724    };
725
726    auto handle_transpose = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
727        switch (src_ss[0].axis) {
728            case GGML_BACKEND_SPLIT_AXIS_0:
729            case GGML_BACKEND_SPLIT_AXIS_1: {
730                GGML_ASSERT(src_ss[0].n_segments == 1 || src_ss[0].nr[0] == 1);
731                return {ggml_backend_meta_split_axis(int(src_ss[0].axis) ^ 1), {0}, {src_ss[0].nr[0]}, 1};
732            }
733            case GGML_BACKEND_SPLIT_AXIS_2:
734            case GGML_BACKEND_SPLIT_AXIS_3:
735            case GGML_BACKEND_SPLIT_AXIS_MIRRORED:
736            case GGML_BACKEND_SPLIT_AXIS_PARTIAL: {
737                return src_ss[0];
738            }
739            default: {
740                GGML_ABORT("fatal error");
741                //return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
742            }
743        }
744    };
745
746    auto handle_get_rows = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
747        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_0 && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
748            return src_ss[0];
749        }
750        return handle_generic(src_ss, /*scalar_only =*/ true);
751    };
752
753    auto handle_set_rows = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
754        GGML_ASSERT(src_ss[0].axis != GGML_BACKEND_SPLIT_AXIS_1);
755        GGML_ASSERT(src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
756        GGML_ASSERT(split_states_equal(src_ss[0], src_ss[2]));
757        return src_ss[0];
758    };
759
760    auto handle_rope = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
761        GGML_ASSERT(src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
762        return src_ss[0];
763    };
764
765    auto handle_pad = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
766        if (src_ss[0].axis >= 0 && src_ss[0].axis < GGML_MAX_DIMS) {
767            GGML_ASSERT(tensor->op_params[2*src_ss[0].axis + 0] == 0);
768            GGML_ASSERT(tensor->op_params[2*src_ss[0].axis + 1] == 0);
769        }
770        return src_ss[0];
771    };
772
773    auto handle_flash_attn_ext = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
774        GGML_ASSERT(tensor->src[3] == nullptr || src_ss[3].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
775
776        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
777            GGML_ASSERT(src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
778            GGML_ASSERT(src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
779            GGML_ASSERT(tensor->src[4] == nullptr || src_ss[4].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
780            return {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
781        }
782
783        GGML_ASSERT(src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_2);
784        const bool kv_split = src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_2 &&
785                src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_2;
786        const bool kv_mirrored = src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED &&
787                src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED;
788        GGML_ASSERT(kv_split || kv_mirrored);
789        GGML_ASSERT(tensor->src[4] == nullptr || src_ss[4].axis == GGML_BACKEND_SPLIT_AXIS_0);
790        return {GGML_BACKEND_SPLIT_AXIS_1, {0}, {1}, 1};
791    };
792
793    auto handle_lightning_indexer = [&](
794            const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
795        for (size_t i = 0; i < 4; i++) {
796            GGML_ASSERT(src_ss[i].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
797        }
798        return {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
799    };
800
801    auto handle_ssm_conv = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
802        if (src_ss[0].axis == src_ss[1].axis) {
803            if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_0) {
804                return {GGML_BACKEND_SPLIT_AXIS_1, {0}, {1}, 1};
805            }
806            if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_1) {
807                return {GGML_BACKEND_SPLIT_AXIS_0, {0}, {1}, 1};
808            }
809        }
810        return handle_generic(src_ss, /*scalar_only =*/ false);
811    };
812
813    auto handle_gated_delta_net = [&](const std::vector<ggml_backend_meta_split_state> & src_ss) -> ggml_backend_meta_split_state {
814        if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED &&
815                src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[3].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED &&
816                src_ss[4].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED && src_ss[5].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
817            return src_ss[0];
818        }
819        GGML_ASSERT(src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_1);
820        GGML_ASSERT(src_ss[1].axis == GGML_BACKEND_SPLIT_AXIS_1);
821        GGML_ASSERT(src_ss[2].axis == GGML_BACKEND_SPLIT_AXIS_1);
822        GGML_ASSERT(src_ss[3].axis == GGML_BACKEND_SPLIT_AXIS_1);
823        GGML_ASSERT(src_ss[4].axis == GGML_BACKEND_SPLIT_AXIS_1);
824        // state shape is [S_v, S_v, H_v, n_seqs] (s0 only); the heads dim is its own axis 2,
825        // so a head-aligned split on the input cache lands on axis 2 here.
826        GGML_ASSERT(src_ss[5].axis == GGML_BACKEND_SPLIT_AXIS_2 || src_ss[5].axis == GGML_BACKEND_SPLIT_AXIS_1 || src_ss[5].axis == GGML_BACKEND_SPLIT_AXIS_0);
827        return {GGML_BACKEND_SPLIT_AXIS_0, {0}, {1}, 1};
828    };
829
830    auto calculate_split_state = [&]() -> ggml_backend_meta_split_state {
831        if (ggml_nelements(tensor) == 0) {
832            return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
833        }
834        if (ggml_backend_buffer_get_usage(tensor->buffer) != GGML_BACKEND_BUFFER_USAGE_COMPUTE && tensor->view_src == nullptr) {
835            ggml_backend_dev_t dev = ggml_backend_buft_get_device(ggml_backend_buffer_get_type(tensor->buffer));
836            const ggml_backend_meta_device_context * dev_ctx = (const ggml_backend_meta_device_context *) dev->context;
837            ggml_backend_meta_split_state ret = dev_ctx->get_split_state(tensor, dev_ctx->get_split_state_ud);
838            if (ret.axis >= 0 && ret.axis < GGML_MAX_DIMS) {
839                const int64_t granularity = ret.axis == GGML_BACKEND_SPLIT_AXIS_0 ? ggml_blck_size(tensor->type) : 1;
840                int64_t ne_sum = 0;
841                for (size_t s = 0; s < ret.n_segments; s++) {
842                    for (size_t j = 0; j < n_bufs; j++) {
843                        GGML_ASSERT(ret.ne[s*n_bufs + j] % granularity == 0);
844                        ne_sum += ret.ne[s*n_bufs + j] * ret.nr[s];
845                    }
846                }
847                GGML_ASSERT(ne_sum == tensor->ne[ret.axis]);
848            } else if (ret.axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL) {
849                GGML_ASSERT(ret.n_segments == 1);
850                GGML_ASSERT(ret.nr[0] == 1);
851            }
852            return ret;
853        }
854
855        std::vector<ggml_backend_meta_split_state> src_ss(GGML_MAX_SRC, {GGML_BACKEND_SPLIT_AXIS_NONE, {0}, {1}, 1});
856        for (size_t i = 0; i < GGML_MAX_SRC; i++) {
857            if (tensor->src[i] == nullptr || tensor->src[i] == tensor) {
858                src_ss[i] = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
859                continue;
860            }
861            src_ss[i] = ggml_backend_meta_get_split_state(stc, tensor->src[i], /*assume_sync =*/ true);
862            GGML_ASSERT(src_ss[i].axis != GGML_BACKEND_SPLIT_AXIS_UNKNOWN);
863        }
864
865        ggml_backend_meta_split_state split_state;
866        switch (tensor->op) {
867            case GGML_OP_NONE: {
868                split_state = {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
869            } break;
870            case GGML_OP_DUP: {
871                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
872            } break;
873            case GGML_OP_ADD:
874            case GGML_OP_ADD_ID: {
875                split_state = handle_bin_bcast(src_ss);
876            } break;
877            case GGML_OP_ADD1:
878            case GGML_OP_ACC: {
879                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
880            } break;
881            case GGML_OP_SUB:
882            case GGML_OP_MUL:
883            case GGML_OP_DIV: {
884                split_state = handle_bin_bcast(src_ss);
885            } break;
886            case GGML_OP_SQR:
887            case GGML_OP_SQRT:
888            case GGML_OP_LOG:
889            case GGML_OP_SIN:
890            case GGML_OP_COS: {
891                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
892            } break;
893            case GGML_OP_SUM: {
894                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
895            } break;
896            case GGML_OP_SUM_ROWS:
897            case GGML_OP_CUMSUM:
898            case GGML_OP_MEAN:
899            case GGML_OP_ARGMAX:
900            case GGML_OP_COUNT_EQUAL: {
901                split_state = handle_per_row(src_ss);
902            } break;
903            case GGML_OP_REPEAT:
904            case GGML_OP_REPEAT_BACK: {
905                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
906            } break;
907            case GGML_OP_CONCAT: {
908                split_state = handle_concat(src_ss);
909            } break;
910            case GGML_OP_SILU_BACK: {
911                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
912            } break;
913            case GGML_OP_NORM:
914            case GGML_OP_RMS_NORM:
915            case GGML_OP_RMS_NORM_BACK:
916            case GGML_OP_GROUP_NORM:
917            case GGML_OP_L2_NORM: {
918                split_state = handle_per_row(src_ss);
919            } break;
920            case GGML_OP_MUL_MAT:
921            case GGML_OP_MUL_MAT_ID: {
922                split_state = handle_mul_mat(src_ss);
923            } break;
924            case GGML_OP_OUT_PROD: {
925                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
926            } break;
927            case GGML_OP_SCALE: {
928                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
929            } break;
930            case GGML_OP_SET: {
931                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
932            } break;
933            case GGML_OP_CPY: {
934                split_state = handle_cpy(src_ss);
935            } break;
936            case GGML_OP_CONT:
937            case GGML_OP_RESHAPE: {
938                split_state = handle_reshape(src_ss);
939            } break;
940            case GGML_OP_VIEW: {
941                split_state = handle_view(src_ss);
942            } break;
943            case GGML_OP_PERMUTE: {
944                split_state = handle_permute(src_ss);
945            } break;
946            case GGML_OP_TRANSPOSE: {
947                split_state = handle_transpose(src_ss);
948            } break;
949            case GGML_OP_GET_ROWS: {
950                split_state = handle_get_rows(src_ss);
951            } break;
952            case GGML_OP_GET_ROWS_BACK: {
953                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
954            } break;
955            case GGML_OP_SET_ROWS: {
956                split_state = handle_set_rows(src_ss);
957            } break;
958            case GGML_OP_DIAG:
959            case GGML_OP_DIAG_MASK_INF:
960            case GGML_OP_DIAG_MASK_ZERO: {
961                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
962            } break;
963            case GGML_OP_SOFT_MAX:
964            case GGML_OP_SOFT_MAX_BACK: {
965                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
966            } break;
967            case GGML_OP_ROPE: {
968                split_state = handle_rope(src_ss);
969            } break;
970            case GGML_OP_ROPE_BACK: {
971                split_state = handle_rope(src_ss);
972            } break;
973            case GGML_OP_CLAMP: {
974                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
975            } break;
976            case GGML_OP_CONV_TRANSPOSE_1D:
977            case GGML_OP_IM2COL:
978            case GGML_OP_IM2COL_BACK:
979            case GGML_OP_IM2COL_3D:
980            case GGML_OP_CONV_2D:
981            case GGML_OP_CONV_3D:
982            case GGML_OP_CONV_2D_DW:
983            case GGML_OP_CONV_TRANSPOSE_2D:
984            case GGML_OP_POOL_1D:
985            case GGML_OP_POOL_2D:
986            case GGML_OP_POOL_2D_BACK:
987            case GGML_OP_UPSCALE: {
988                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
989            } break;
990            case GGML_OP_PAD: {
991                split_state = handle_pad(src_ss);
992            } break;
993            case GGML_OP_PAD_REFLECT_1D:
994            case GGML_OP_ROLL:
995            case GGML_OP_ARANGE:
996            case GGML_OP_TIMESTEP_EMBEDDING: {
997                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
998            } break;
999            case GGML_OP_ARGSORT:
1000            case GGML_OP_TOP_K: {
1001                split_state = handle_per_row(src_ss);
1002            } break;
1003            case GGML_OP_LEAKY_RELU: {
1004                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
1005            } break;
1006            case GGML_OP_TRI: {
1007                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
1008            } break;
1009            case GGML_OP_FILL: {
1010                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
1011            } break;
1012            case GGML_OP_FLASH_ATTN_EXT: {
1013                split_state = handle_flash_attn_ext(src_ss);
1014            } break;
1015            case GGML_OP_FLASH_ATTN_BACK: {
1016                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
1017            } break;
1018            case GGML_OP_SSM_CONV: {
1019                split_state = handle_ssm_conv(src_ss);
1020            } break;
1021            case GGML_OP_SSM_SCAN:
1022            case GGML_OP_WIN_PART:
1023            case GGML_OP_WIN_UNPART:
1024            case GGML_OP_GET_REL_POS:
1025            case GGML_OP_ADD_REL_POS:
1026            case GGML_OP_RWKV_WKV6:
1027            case GGML_OP_GATED_LINEAR_ATTN:
1028            case GGML_OP_RWKV_WKV7:
1029            case GGML_OP_SOLVE_TRI: {
1030                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
1031            } break;
1032            case GGML_OP_GATED_DELTA_NET: {
1033                split_state = handle_gated_delta_net(src_ss);
1034            } break;
1035            case GGML_OP_LIGHTNING_INDEXER: {
1036                split_state = handle_lightning_indexer(src_ss);
1037            } break;
1038            case GGML_OP_DSV4_HC_COMB:
1039            case GGML_OP_DSV4_HC_PRE:
1040            case GGML_OP_DSV4_HC_POST: {
1041                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
1042            } break;
1043            case GGML_OP_UNARY: {
1044                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
1045            } break;
1046            case GGML_OP_MAP_CUSTOM1:
1047            case GGML_OP_MAP_CUSTOM2:
1048            case GGML_OP_MAP_CUSTOM3:
1049            case GGML_OP_CUSTOM: {
1050                split_state = handle_generic(src_ss, /*scalar_only =*/ true);
1051            } break;
1052            case GGML_OP_CROSS_ENTROPY_LOSS:
1053            case GGML_OP_CROSS_ENTROPY_LOSS_BACK: {
1054                split_state = handle_per_row(src_ss);
1055            } break;
1056            case GGML_OP_OPT_STEP_ADAMW:
1057            case GGML_OP_OPT_STEP_SGD:
1058            case GGML_OP_GLU: {
1059                split_state = handle_generic(src_ss, /*scalar_only =*/ false);
1060            } break;
1061            default: {
1062                GGML_ABORT("ggml op not implemented: %s", ggml_op_name(tensor->op));
1063                split_state = {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
1064            } break;
1065        }
1066        if (split_state.axis >= 0 && split_state.axis < GGML_MAX_DIMS) {
1067            bool first_src_split_by_axis = true;
1068            const size_t n_bufs = ggml_backend_meta_buffer_n_bufs(tensor->buffer);
1069
1070            for (size_t i = 0; i < GGML_MAX_SRC; i++) {
1071                if (tensor->src[i] == nullptr || src_ss[i].axis < 0 || src_ss[i].axis >= GGML_MAX_DIMS) {
1072                    continue;
1073                }
1074                if (first_src_split_by_axis) {
1075                    for (size_t j = 0; j < n_bufs; j++) {
1076                        // Take over ratio from src:
1077                        for (size_t s = 0; s < src_ss[i].n_segments; s++) {
1078                            split_state.ne[s*n_bufs + j] = 0;
1079                        }
1080                        for (size_t s = 0; s < src_ss[i].n_segments; s++) {
1081                            split_state.ne[j] += src_ss[i].ne[s*n_bufs + j] * src_ss[i].nr[s];
1082                        }
1083                        split_state.ne[j] *= tensor->ne[split_state.axis];
1084                        if (split_state.ne[j] != 0 || tensor->src[i]->ne[src_ss[i].axis] != 0) {
1085                            const int64_t div = tensor->src[i]->ne[src_ss[i].axis] * split_state.nr[0];
1086                            GGML_ASSERT(split_state.ne[j] % div == 0);
1087                            split_state.ne[j] /= div;
1088                        }
1089                    }
1090                } else {
1091                    GGML_ASSERT(split_state.n_segments == 1);
1092                    for (size_t j = 0; j < n_bufs; j++) {
1093                        // Assert that ratio is consistent:
1094                        int64_t sum = 0;
1095                        for (size_t s = 0; s < src_ss[i].n_segments; s++) {
1096                            sum += src_ss[i].ne[s*n_bufs + j] * src_ss[i].nr[s];
1097                        }
1098                        GGML_ASSERT(split_state.ne[j]*split_state.nr[0] * tensor->src[i]->ne[src_ss[i].axis]
1099                                                                 == sum * tensor->ne[split_state.axis]);
1100                    }
1101                }
1102                first_src_split_by_axis = false;
1103            }
1104            GGML_ASSERT(!first_src_split_by_axis);
1105        }
1106        return split_state;
1107    };
1108
1109    const std::pair key = std::make_pair(tensor, assume_sync);
1110    auto it = buf_ctx->split_state_cache.find(key);
1111    if (it != buf_ctx->split_state_cache.end() && memcmp(it->second.second, (const char *) tensor, sizeof(it->second.second)) != 0) {
1112        buf_ctx->split_state_cache.clear();
1113        it = buf_ctx->split_state_cache.end();
1114    }
1115
1116    if (it == buf_ctx->split_state_cache.end()) {
1117        buf_ctx->split_state_cache[key].first = calculate_split_state();
1118        memcpy(buf_ctx->split_state_cache[key].second, tensor, sizeof(buf_ctx->split_state_cache[key].second));
1119        if (buf_ctx->debug > 0) {
1120            std::string srcs_info;
1121            for (size_t i = 0; i < GGML_MAX_SRC; i++) {
1122                if (tensor->src[i] == nullptr || tensor->src[i] == tensor) {
1123                    continue;
1124                }
1125                if (!srcs_info.empty()) {
1126                    srcs_info += ", ";
1127                }
1128                const ggml_backend_meta_split_state split_state =
1129                        ggml_backend_meta_get_split_state(tensor->src[i], true);
1130                GGML_ASSERT(split_state.n_segments == 1);
1131                const char * axis_name = ggml_backend_meta_split_axis_name(split_state.axis);
1132                std::string ne_info;
1133                for (size_t j = 0; j < n_bufs; j++) {
1134                    if (!ne_info.empty()) {
1135                        ne_info += ", ";
1136                    }
1137                    ne_info += std::to_string(split_state.ne[j]) + "x" + std::to_string(split_state.nr[0]);
1138                }
1139                srcs_info += std::string(tensor->src[i]->name) + "[" + ggml_op_name(tensor->src[i]->op) + ", " + axis_name + ", {" + ne_info + "}]";
1140            }
1141            std::string ne_info;
1142            for (size_t j = 0; j < n_bufs; j++) {
1143                if (!ne_info.empty()) {
1144                    ne_info += ", ";
1145                }
1146                const ggml_backend_meta_split_state & ss = buf_ctx->split_state_cache[key].first;
1147                ne_info += std::to_string(ss.ne[j]) + "x" + std::to_string(ss.nr[0]);
1148            }
1149            GGML_LOG_DEBUG("SPLIT_STATE: {%s} -> %s[%s, %s, {%s}]\n", srcs_info.c_str(), tensor->name, ggml_op_name(tensor->op),
1150                ggml_backend_meta_split_axis_name(buf_ctx->split_state_cache[key].first.axis), ne_info.c_str());
1151        }
1152    }
1153
1154    ggml_backend_meta_split_state ret = buf_ctx->split_state_cache[key].first;
1155    GGML_ASSERT(ret.axis != GGML_BACKEND_SPLIT_AXIS_NONE);
1156#ifndef NDEBUG
1157    if (ret.axis >= 0 && ret.axis < GGML_MAX_DIMS) {
1158        int64_t ne_ret = 0;
1159        for (size_t s = 0; s < ret.n_segments; s++) {
1160            for (size_t j = 0; j < n_bufs; j++) {
1161                ne_ret += ret.ne[s*n_bufs + j] * ret.nr[s];
1162            }
1163        }
1164        assert(ne_ret == tensor->ne[int(ret.axis)]);
1165    }
1166#endif // NDEBUG
1167    return ret;
1168}
1169
1170static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(const struct ggml_tensor * tensor, bool assume_sync) {
1171    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) tensor->buffer->context;
1172    return ggml_backend_meta_get_split_state(buf_ctx->get_simple_tensor_container(tensor), tensor, assume_sync);
1173}
1174
1175static void * ggml_backend_meta_buffer_get_base(ggml_backend_buffer_t buffer) {
1176    GGML_UNUSED(buffer);
1177    return (void *) 0x1000000000000000; // FIXME
1178}
1179
1180static enum ggml_status ggml_backend_meta_buffer_init_tensor_impl(ggml_backend_meta_simple_tensor_container & stc, ggml_tensor * tensor) {
1181    GGML_ASSERT(ggml_backend_buffer_is_meta(tensor->buffer));
1182    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) tensor->buffer->context;
1183    const size_t n_simple_bufs = ggml_backend_meta_buffer_n_bufs(tensor->buffer);
1184
1185    const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(stc, tensor, /*assume_sync =*/ true);
1186    GGML_ASSERT(ggml_nelements(tensor) == 0 || split_state.axis != GGML_BACKEND_SPLIT_AXIS_UNKNOWN);
1187    GGML_ASSERT(split_state.n_segments <= 16);
1188
1189    int split_dim = split_state.axis;
1190    int64_t ne[GGML_MAX_DIMS];
1191    size_t  nb[GGML_MAX_DIMS];
1192    for (size_t k = 0; k < GGML_MAX_DIMS; k++) {
1193        ne[k] = tensor->ne[k];
1194        nb[k] = tensor->nb[k];
1195    }
1196
1197    std::vector<ggml_tensor *> simple_tensors;
1198    simple_tensors.reserve(n_simple_bufs);
1199    for (size_t j = 0; j < n_simple_bufs; j++) {
1200        ggml_context          * simple_ctx = stc.ctxs[j].get();
1201        ggml_backend_buffer_t   simple_buf = buf_ctx->bufs[j].get();
1202
1203        if ((simple_buf != nullptr) && ggml_backend_buffer_is_multi_buffer(simple_buf)) {
1204            // see https://github.com/ggml-org/llama.cpp/issues/22197
1205            GGML_ABORT("multi buffers are not supported by the meta backend");
1206        }
1207
1208        if (split_dim >= 0 && split_dim < GGML_MAX_DIMS) {
1209            // TODO: the following assert fails for llama-parallel even though the results are correct:
1210            // GGML_ASSERT(ggml_is_contiguously_allocated(tensor));
1211            ne[split_dim] = 0;
1212            for (size_t s = 0; s < split_state.n_segments; s++) {
1213                ne[split_dim] += split_state.ne[s*n_simple_bufs + j] * split_state.nr[s];
1214            }
1215            for (int i = 0; i < GGML_MAX_DIMS; i++) {
1216                if (tensor->nb[i] > tensor->nb[split_dim]) {
1217                    nb[i] = tensor->nb[i] * ne[split_dim]/tensor->ne[split_dim];
1218                }
1219            }
1220        }
1221
1222        ggml_tensor * t_ij = ggml_new_tensor(simple_ctx, tensor->type, GGML_MAX_DIMS, ne);
1223        t_ij->op = tensor->op;
1224        for (int i = 0; i < GGML_MAX_DIMS; i++) {
1225            t_ij->nb[i] = nb[i];
1226        }
1227        t_ij->flags = tensor->flags;
1228        memcpy(t_ij->op_params, tensor->op_params, sizeof(tensor->op_params));
1229        ggml_set_name(t_ij, tensor->name);
1230        t_ij->buffer = simple_buf;
1231        t_ij->view_src = tensor->view_src;
1232        t_ij->view_offs = tensor->view_offs;
1233        if (t_ij->view_src != nullptr && ggml_backend_buffer_is_meta(t_ij->view_src->buffer)) {
1234            t_ij->view_src = ggml_backend_meta_buffer_simple_tensor(tensor->view_src, j);
1235            if (t_ij->view_offs > 0 && split_dim >= 0 && split_dim < GGML_MAX_DIMS) {
1236                GGML_ASSERT(tensor->ne[split_dim] != 0);
1237                const int split_dim_view_src = ggml_backend_meta_get_split_state(tensor->view_src, /*assume_sync =*/ true).axis;
1238                GGML_ASSERT(split_dim_view_src >= 0 && split_dim_view_src < GGML_MAX_DIMS);
1239
1240                // The offset can be internal to the data split, in those cases the view offset should not be scaled.
1241                // If however, the offset is larger than the data split then it needs to be scaled proportionally.
1242                bool split_internal_offset = t_ij->view_offs <= tensor->view_src->nb[split_dim_view_src];
1243                for (int i = 0; i < GGML_MAX_DIMS; i++) {
1244                    const size_t dim_size = tensor->ne[i] * tensor->nb[i];
1245                    if (tensor->view_offs <= dim_size && dim_size < tensor->nb[split_dim]) {
1246                        split_internal_offset = true;
1247                        break;
1248                    }
1249                }
1250                if (!split_internal_offset) {
1251                    t_ij->view_offs = t_ij->view_offs * ne[split_dim]/tensor->ne[split_dim];
1252                }
1253            }
1254        }
1255        if (t_ij->view_src != nullptr) {
1256            t_ij->data = (char *) t_ij->view_src->data + t_ij->view_offs;
1257        } else if (simple_buf != nullptr) {
1258            t_ij->data = (char *) ggml_backend_buffer_get_base(simple_buf)
1259                + size_t(tensor->data) - size_t(ggml_backend_buffer_get_base(tensor->buffer));
1260        }
1261
1262        if (simple_buf) {
1263            // the backend that owns the buffer will set .extra
1264            ggml_backend_buffer_init_tensor(simple_buf, t_ij);
1265        } else {
1266            t_ij->extra = tensor->extra;
1267        }
1268
1269        for (int i = 0; i < GGML_MAX_SRC; i++) {
1270            t_ij->src[i] = tensor->src[i];
1271            if (tensor->src[i] == tensor) {
1272                t_ij->src[i] = t_ij;
1273            } else if (t_ij->src[i] != nullptr && ggml_backend_buffer_is_meta(t_ij->src[i]->buffer)) {
1274                t_ij->src[i] = ggml_backend_meta_buffer_simple_tensor(tensor->src[i], j);
1275            }
1276        }
1277
1278        simple_tensors.push_back(t_ij);
1279    }
1280
1281    // If one of the sources has a zero-sized slice, disable the computation:
1282    for (int i = 0; i < GGML_MAX_SRC; i++) {
1283        if (tensor->src[i] == nullptr || !ggml_backend_buffer_is_meta(tensor->src[i]->buffer)) {
1284            continue;
1285        }
1286
1287        const ggml_backend_meta_split_state split_state_src = ggml_backend_meta_get_split_state(tensor->src[i], /*assume_sync =*/ true);
1288        if (split_state_src.axis < 0 || split_state_src.axis >= GGML_MAX_DIMS) {
1289            continue;
1290        }
1291        for (size_t j = 0; j < n_simple_bufs; j++) {
1292            int64_t ne_sum = 0;
1293            for (size_t s = 0; s < split_state_src.n_segments; s++) {
1294                ne_sum += split_state_src.ne[s*n_simple_bufs + j] * split_state_src.nr[s];
1295            }
1296            if (ne_sum == 0) {
1297                simple_tensors[j]->flags &= ~GGML_TENSOR_FLAG_COMPUTE;
1298            }
1299        }
1300    }
1301
1302    stc.simple_tensors[tensor] = simple_tensors;
1303
1304    return GGML_STATUS_SUCCESS;
1305}
1306
1307static enum ggml_status ggml_backend_meta_buffer_init_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor) {
1308    GGML_ASSERT(ggml_backend_buffer_is_meta(buffer));
1309    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) buffer->context;
1310    buf_ctx->stc_compute_index = buf_ctx->stc_compute_index_next;
1311    return ggml_backend_meta_buffer_init_tensor_impl(buf_ctx->get_simple_tensor_container(tensor), tensor);
1312}
1313
1314static void ggml_backend_meta_buffer_memset_tensor(
1315        ggml_backend_buffer_t buffer, ggml_tensor * tensor, uint8_t value, size_t offset, size_t size) {
1316    const size_t n_bufs = ggml_backend_meta_buffer_n_bufs(buffer);
1317    const ggml_backend_meta_split_state split_state =
1318            ggml_backend_meta_get_split_state(tensor, /*assume_sync =*/ false);
1319    GGML_ASSERT(ggml_is_contiguous(tensor) || split_state.axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
1320
1321    if (split_state.n_segments != 1 || split_state.nr[0] != 1) {
1322        GGML_ASSERT(split_state.axis >= 0 && split_state.axis < GGML_MAX_DIMS);
1323        GGML_ASSERT(split_state.nr[0] != 0);
1324        GGML_ASSERT(tensor->ne[3] == 1);
1325
1326        std::vector<size_t> simple_offsets(n_bufs, 0);
1327        if (split_state.axis == GGML_BACKEND_SPLIT_AXIS_0) {
1328            GGML_ASSERT(tensor->ne[2] == 1);
1329
1330            const size_t row_stride = tensor->nb[1];
1331            GGML_ASSERT(offset % row_stride == 0);
1332            GGML_ASSERT(size   % row_stride == 0);
1333            const int64_t row_start = offset / row_stride;
1334            const int64_t row_count = size   / row_stride;
1335            GGML_ASSERT(row_start + row_count <= tensor->ne[1]);
1336
1337            const int64_t blck_size = ggml_blck_size(tensor->type);
1338            for (size_t s = 0; s < split_state.n_segments; s++) {
1339                for (size_t r = 0; r < split_state.nr[s]; r++) {
1340                    for (size_t j = 0; j < n_bufs; j++) {
1341                        ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1342                        GGML_ASSERT(split_state.ne[s*n_bufs + j] % blck_size == 0);
1343                        const size_t nbytes = split_state.ne[s*n_bufs + j]/blck_size * tensor->nb[0];
1344                        for (int64_t row = 0; row < row_count; row++) {
1345                            ggml_backend_tensor_memset(simple_tensor, value,
1346                                    simple_offsets[j] + (row_start + row)*simple_tensor->nb[1], nbytes);
1347                        }
1348                        simple_offsets[j] += nbytes;
1349                    }
1350                }
1351            }
1352            return;
1353        }
1354
1355        GGML_ASSERT(split_state.axis == GGML_BACKEND_SPLIT_AXIS_1);
1356
1357        const size_t row_stride = tensor->nb[2];
1358        GGML_ASSERT(offset % row_stride == 0);
1359        GGML_ASSERT(size   % row_stride == 0);
1360        const int64_t row_start = offset / row_stride;
1361        const int64_t row_count = size   / row_stride;
1362        GGML_ASSERT(row_start + row_count <= tensor->ne[2]);
1363
1364        for (size_t s = 0; s < split_state.n_segments; s++) {
1365            for (size_t r = 0; r < split_state.nr[s]; r++) {
1366                for (size_t j = 0; j < n_bufs; j++) {
1367                    ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1368                    const size_t nbytes = split_state.ne[s*n_bufs + j] * tensor->nb[1];
1369                    for (int64_t row = 0; row < row_count; row++) {
1370                        ggml_backend_tensor_memset(simple_tensor, value,
1371                                simple_offsets[j] + (row_start + row)*simple_tensor->nb[2], nbytes);
1372                    }
1373                    simple_offsets[j] += nbytes;
1374                }
1375            }
1376        }
1377        return;
1378    }
1379
1380    switch (split_state.axis) {
1381        case GGML_BACKEND_SPLIT_AXIS_0:
1382        case GGML_BACKEND_SPLIT_AXIS_1:
1383        case GGML_BACKEND_SPLIT_AXIS_2: {
1384            const size_t chunk_size_full = tensor->nb[split_state.axis + 1];
1385            GGML_ASSERT(offset % chunk_size_full == 0);
1386            GGML_ASSERT(size   % chunk_size_full == 0);
1387            const int64_t i_start =  offset        / chunk_size_full;
1388            const int64_t i_stop  = (offset + size) / chunk_size_full;
1389            for (size_t j = 0; j < n_bufs; j++) {
1390                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1391                const size_t chunk_size = simple_tensor->nb[split_state.axis + 1];
1392                if (chunk_size == 0) {
1393                    continue;
1394                }
1395                for (int64_t i = i_start; i < i_stop; i++) {
1396                    ggml_backend_tensor_memset(simple_tensor, value, i*chunk_size, chunk_size);
1397                }
1398            }
1399        } break;
1400        case GGML_BACKEND_SPLIT_AXIS_PARTIAL: {
1401            GGML_ASSERT(value == 0);
1402            [[fallthrough]];
1403        }
1404        case GGML_BACKEND_SPLIT_AXIS_MIRRORED: {
1405            for (size_t j = 0; j < n_bufs; j++) {
1406                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1407                ggml_backend_tensor_memset(simple_tensor, value, offset, size);
1408            }
1409        } break;
1410        default: {
1411            GGML_ABORT("fatal error");
1412        }
1413    }
1414}
1415
1416static void ggml_backend_meta_buffer_set_tensor(ggml_backend_buffer_t buffer, ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
1417    const size_t n_bufs = ggml_backend_meta_buffer_n_bufs(buffer);
1418    const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(tensor, /*assume_sync =*/ false);
1419    GGML_ASSERT(ggml_is_contiguous(tensor) || split_state.axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
1420
1421    if (split_state.n_segments != 1 || split_state.nr[0] != 1) {
1422        GGML_ASSERT(split_state.axis >= 0 && split_state.axis < GGML_MAX_DIMS);
1423        GGML_ASSERT(split_state.nr[0] != 0);
1424        GGML_ASSERT(tensor->ne[3] == 1);
1425
1426        size_t offset_data = 0;
1427        std::vector<size_t> simple_offsets(n_bufs, 0);
1428        if (split_state.axis == GGML_BACKEND_SPLIT_AXIS_0) {
1429            GGML_ASSERT(tensor->ne[2] == 1);
1430
1431            const size_t row_stride = tensor->nb[1];
1432            GGML_ASSERT(offset % row_stride == 0);
1433            GGML_ASSERT(size   % row_stride == 0);
1434            const int64_t row_start = offset / row_stride;
1435            const int64_t row_count = size   / row_stride;
1436            GGML_ASSERT(row_start + row_count <= tensor->ne[1]);
1437
1438            const int64_t blck_size = ggml_blck_size(tensor->type);
1439            for (size_t s = 0; s < split_state.n_segments; s++) {
1440                for (size_t r = 0; r < split_state.nr[s]; r++) {
1441                    for (size_t j = 0; j < n_bufs; j++) {
1442                        ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1443                        GGML_ASSERT(split_state.ne[s*n_bufs + j] % blck_size == 0);
1444                        const size_t nbytes = split_state.ne[s*n_bufs + j]/blck_size * tensor->nb[0];
1445                        ggml_backend_tensor_set_2d(simple_tensor, (const char *) data + offset_data,
1446                            simple_offsets[j] + row_start * simple_tensor->nb[1], nbytes,
1447                            row_count, simple_tensor->nb[1], tensor->nb[1]);
1448                        offset_data       += nbytes;
1449                        simple_offsets[j] += nbytes;
1450                    }
1451                }
1452            }
1453            GGML_ASSERT(offset_data*row_count == size);
1454            return;
1455        }
1456        GGML_ASSERT(split_state.axis == GGML_BACKEND_SPLIT_AXIS_1);
1457
1458        const size_t row_stride = tensor->nb[2];
1459        GGML_ASSERT(offset % row_stride == 0);
1460        GGML_ASSERT(size   % row_stride == 0);
1461        const int64_t row_start = offset / row_stride;
1462        const int64_t row_count = size   / row_stride;
1463        GGML_ASSERT(row_start + row_count <= tensor->ne[2]);
1464
1465        for (size_t s = 0; s < split_state.n_segments; s++) {
1466            for (size_t r = 0; r < split_state.nr[s]; r++) {
1467                for (size_t j = 0; j < n_bufs; j++) {
1468                    ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1469                    const size_t nbytes = split_state.ne[s*n_bufs + j] * tensor->nb[1];
1470                    ggml_backend_tensor_set_2d(simple_tensor, (const char *) data + offset_data,
1471                        simple_offsets[j] + row_start * simple_tensor->nb[2], nbytes,
1472                        row_count, simple_tensor->nb[2], tensor->nb[2]);
1473                    offset_data       += nbytes;
1474                    simple_offsets[j] += nbytes;
1475                }
1476            }
1477        }
1478        GGML_ASSERT(offset_data*row_count == size);
1479        return;
1480    }
1481
1482    switch (split_state.axis) {
1483        case GGML_BACKEND_SPLIT_AXIS_0:
1484        case GGML_BACKEND_SPLIT_AXIS_1:
1485        case GGML_BACKEND_SPLIT_AXIS_2: {
1486            // Exploit that tensors are contiguous to splice it with simple tensors as "chunks".
1487            const size_t chunk_size_full = tensor->nb[split_state.axis + 1];
1488            GGML_ASSERT(offset % chunk_size_full == 0);
1489            GGML_ASSERT(size   % chunk_size_full == 0);
1490            const int64_t i_start =  offset        /chunk_size_full;
1491            const int64_t i_stop  = (offset + size)/chunk_size_full;
1492            size_t offset_j = 0;
1493            for (size_t j = 0; j < n_bufs; j++) {
1494                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1495                const size_t chunk_size_j = simple_tensor->nb[split_state.axis + 1];
1496                if (chunk_size_j == 0) {
1497                    continue;
1498                }
1499                const size_t simple_offset = i_start * chunk_size_j;
1500                ggml_backend_tensor_set_2d(simple_tensor, (const char *) data + offset_j, simple_offset, chunk_size_j, i_stop - i_start, chunk_size_j, chunk_size_full);
1501                offset_j += chunk_size_j;
1502            }
1503            GGML_ASSERT(offset_j == chunk_size_full);
1504        } break;
1505        case GGML_BACKEND_SPLIT_AXIS_MIRRORED: {
1506            for (size_t j = 0; j < n_bufs; j++) {
1507                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1508                ggml_backend_tensor_set(simple_tensor, data, offset, size);
1509            }
1510        } break;
1511        case GGML_BACKEND_SPLIT_AXIS_PARTIAL: {
1512            GGML_ASSERT(tensor->type == GGML_TYPE_F32);
1513            GGML_ASSERT(offset % sizeof(float) == 0);
1514            GGML_ASSERT(size   % sizeof(float) == 0);
1515            const size_t n_values = size / sizeof(float);
1516            size_t n_contributors = 0;
1517            for (size_t j = 0; j < n_bufs; j++) {
1518                n_contributors += split_state.ne[j] != 0;
1519            }
1520            const bool has_contributor_mask = n_contributors != 0;
1521            if (!has_contributor_mask) {
1522                n_contributors = n_bufs;
1523            }
1524            std::vector<float> tmp(n_values);
1525            for (size_t i = 0; i < n_values; i++) {
1526                tmp[i] = ((const float *) data)[i] / n_contributors;
1527            }
1528            std::vector<float> zero;
1529            if (has_contributor_mask) {
1530                zero.resize(n_values, 0.0f);
1531            }
1532            for (size_t j = 0; j < n_bufs; j++) {
1533                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1534                const float * partial = has_contributor_mask && split_state.ne[j] == 0 ? zero.data() : tmp.data();
1535                ggml_backend_tensor_set(simple_tensor, partial, offset, size);
1536            }
1537        } break;
1538        default: {
1539            GGML_ABORT("fatal error");
1540        }
1541    }
1542}
1543
1544static void ggml_backend_meta_buffer_get_tensor(ggml_backend_buffer_t buffer, const ggml_tensor * tensor, void * data, size_t offset, size_t size) {
1545    const size_t n_bufs = ggml_backend_meta_buffer_n_bufs(buffer);
1546    const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(tensor, /*assume_sync =*/ false);
1547    GGML_ASSERT(ggml_is_contiguous(tensor) || split_state.axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED);
1548
1549    if (split_state.n_segments != 1 || split_state.nr[0] != 1) {
1550        GGML_ASSERT(split_state.axis >= 0 && split_state.axis < GGML_MAX_DIMS);
1551        GGML_ASSERT(split_state.nr[0] != 0);
1552        GGML_ASSERT(tensor->ne[3] == 1);
1553
1554        size_t offset_data = 0;
1555        std::vector<size_t> simple_offsets(n_bufs, 0);
1556        if (split_state.axis == GGML_BACKEND_SPLIT_AXIS_0) {
1557            GGML_ASSERT(tensor->ne[2] == 1);
1558
1559            const size_t row_stride = tensor->nb[1];
1560            GGML_ASSERT(offset % row_stride == 0);
1561            GGML_ASSERT(size   % row_stride == 0);
1562            const int64_t row_start = offset / row_stride;
1563            const int64_t row_count = size   / row_stride;
1564            GGML_ASSERT(row_start + row_count <= tensor->ne[1]);
1565
1566            const int64_t blck_size = ggml_blck_size(tensor->type);
1567            for (size_t s = 0; s < split_state.n_segments; s++) {
1568                for (size_t r = 0; r < split_state.nr[s]; r++) {
1569                    for (size_t j = 0; j < n_bufs; j++) {
1570                        const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1571                        GGML_ASSERT(split_state.ne[s*n_bufs + j] % blck_size == 0);
1572                        const size_t nbytes = split_state.ne[s*n_bufs + j]/blck_size * tensor->nb[0];
1573                        ggml_backend_tensor_get_2d(simple_tensor, (char *) data + offset_data,
1574                            simple_offsets[j] + row_start * simple_tensor->nb[1], nbytes,
1575                            row_count, simple_tensor->nb[1], tensor->nb[1]);
1576                        offset_data       += nbytes;
1577                        simple_offsets[j] += nbytes;
1578                    }
1579                }
1580            }
1581            GGML_ASSERT(offset_data*row_count == size);
1582            return;
1583        }
1584        GGML_ASSERT(split_state.axis == GGML_BACKEND_SPLIT_AXIS_1);
1585
1586        const size_t row_stride = tensor->nb[2];
1587        GGML_ASSERT(offset % row_stride == 0);
1588        GGML_ASSERT(size   % row_stride == 0);
1589        const int64_t row_start = offset / row_stride;
1590        const int64_t row_count = size   / row_stride;
1591        GGML_ASSERT(row_start + row_count <= tensor->ne[2]);
1592
1593        for (size_t s = 0; s < split_state.n_segments; s++) {
1594            for (size_t r = 0; r < split_state.nr[s]; r++) {
1595                for (size_t j = 0; j < n_bufs; j++) {
1596                    const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1597                    const size_t nbytes = split_state.ne[s*n_bufs + j] * tensor->nb[1];
1598                    ggml_backend_tensor_get_2d(simple_tensor, (char *) data + offset_data,
1599                        simple_offsets[j] + row_start * simple_tensor->nb[2], nbytes,
1600                        row_count, simple_tensor->nb[2], tensor->nb[2]);
1601                    offset_data       += nbytes;
1602                    simple_offsets[j] += nbytes;
1603                }
1604            }
1605        }
1606        GGML_ASSERT(offset_data*row_count == size);
1607        return;
1608    }
1609
1610    switch (split_state.axis) {
1611        case GGML_BACKEND_SPLIT_AXIS_0:
1612        case GGML_BACKEND_SPLIT_AXIS_1:
1613        case GGML_BACKEND_SPLIT_AXIS_2: {
1614            // Exploit that tensors are contiguous to splice it with simple tensors as "chunks".
1615            const size_t chunk_size_full = tensor->nb[split_state.axis + 1];
1616            GGML_ASSERT(offset % chunk_size_full == 0);
1617            GGML_ASSERT(size   % chunk_size_full == 0);
1618            const int64_t i_start =  offset        /chunk_size_full;
1619            const int64_t i_stop  = (offset + size)/chunk_size_full;
1620            size_t offset_j = 0;
1621            for (size_t j = 0; j < n_bufs; j++){
1622                const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1623                const size_t chunk_size_j = simple_tensor->nb[split_state.axis + 1];
1624                if (chunk_size_j == 0) {
1625                    continue;
1626                }
1627                const size_t simple_offset = i_start * chunk_size_j;
1628                ggml_backend_tensor_get_2d(simple_tensor, (char *) data + offset_j, simple_offset, chunk_size_j, i_stop - i_start, chunk_size_j, chunk_size_full);
1629                offset_j += chunk_size_j;
1630            }
1631            GGML_ASSERT(offset_j == chunk_size_full);
1632        } break;
1633        case GGML_BACKEND_SPLIT_AXIS_MIRRORED: {
1634            // TODO other simple backend may be better
1635            const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, 0);
1636            ggml_backend_tensor_get(simple_tensor, data, offset, size);
1637        } break;
1638        default: {
1639            GGML_ABORT("fatal error");
1640        }
1641    }
1642}
1643
1644static void ggml_backend_meta_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) {
1645    const size_t n_buffers = ggml_backend_meta_buffer_n_bufs(buffer);
1646    for (size_t i = 0; i < n_buffers; i++) {
1647        ggml_backend_buffer_clear(ggml_backend_meta_buffer_simple_buffer(buffer, i), value);
1648    }
1649}
1650
1651static void ggml_backend_meta_buffer_reset(ggml_backend_buffer_t buffer) {
1652    GGML_ASSERT(ggml_backend_buffer_is_meta(buffer));
1653    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) buffer->context;
1654    for (size_t i = 0; i < buf_ctx->bufs.size(); i++) {
1655        ggml_backend_buffer_reset(ggml_backend_meta_buffer_simple_buffer(buffer, i));
1656    }
1657}
1658
1659static const ggml_backend_buffer_i ggml_backend_meta_buffer_iface = {
1660    /* .free_buffer     = */ ggml_backend_meta_buffer_free_buffer,
1661    /* .get_base        = */ ggml_backend_meta_buffer_get_base,
1662    /* .init_tensor     = */ ggml_backend_meta_buffer_init_tensor,
1663    /* .memset_tensor   = */ ggml_backend_meta_buffer_memset_tensor,
1664    /* .set_tensor      = */ ggml_backend_meta_buffer_set_tensor,
1665    /* .get_tensor      = */ ggml_backend_meta_buffer_get_tensor,
1666    /* .set_tensor_2d   = */ nullptr,
1667    /* .get_tensor_2d   = */ nullptr,
1668    /* .cpy_tensor      = */ nullptr,
1669    /* .clear           = */ ggml_backend_meta_buffer_clear,
1670    /* .reset           = */ ggml_backend_meta_buffer_reset,
1671};
1672
1673bool ggml_backend_buffer_is_meta(ggml_backend_buffer_t buf) {
1674    return buf != nullptr && buf->iface.free_buffer == ggml_backend_meta_buffer_iface.free_buffer;
1675}
1676
1677void ggml_backend_meta_buffer_set_usage(ggml_backend_buffer_t buffer, enum ggml_backend_buffer_usage usage) {
1678    GGML_ASSERT(ggml_backend_buffer_is_meta(buffer));
1679    ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) buffer->context;
1680    for (size_t i = 0; i < buf_ctx->bufs.size(); i++) {
1681        if (buf_ctx->bufs[i]) {
1682            ggml_backend_buffer_set_usage(buf_ctx->bufs[i].get(), usage);
1683        }
1684    }
1685}
1686
1687static ggml_backend_buffer_t ggml_backend_meta_buffer_type_alloc_buffer(ggml_backend_buffer_type_t buft, size_t size) {
1688    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
1689
1690    const ggml_init_params params = {
1691        /*.mem_size   =*/ 1024*1024*ggml_tensor_overhead(), // FIXME
1692        /*.mem_buffer =*/ nullptr,
1693        /*.no_alloc   =*/ true,
1694    };
1695    ggml_backend_meta_simple_tensor_container stc_static;
1696    ggml_backend_meta_simple_tensor_container stc_compute_0(params, n_simple_bufts);
1697    ggml_backend_meta_simple_tensor_container stc_compute_1(params, n_simple_bufts);
1698
1699    size_t max_size = 0;
1700    std::vector<ggml_backend_buffer_t> bufs;
1701    bufs.reserve(n_simple_bufts);
1702    for (size_t i = 0; i < n_simple_bufts; i++) {
1703        bufs.push_back(ggml_backend_buft_alloc_buffer(ggml_backend_meta_buft_simple_buft(buft, i), size));
1704        GGML_ASSERT(bufs.back() != nullptr);
1705        max_size = std::max(max_size, ggml_backend_buffer_get_size(bufs.back()));
1706    }
1707    ggml_backend_meta_buffer_context * buf_ctx = new ggml_backend_meta_buffer_context(stc_static, stc_compute_0, stc_compute_1, bufs);
1708
1709    return ggml_backend_buffer_init(buft, ggml_backend_meta_buffer_iface, buf_ctx, max_size);
1710}
1711
1712struct ggml_backend_buffer * ggml_backend_meta_alloc_ctx_tensors_from_buft(struct ggml_context * ctx, ggml_backend_buffer_type_t buft) {
1713    const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
1714
1715    constexpr size_t compute_headroom = 16; // Maximum number of views per statically allocated tensor that can be created between evals.
1716    const ggml_init_params params_static = {
1717        /*.mem_size   =*/ ggml_get_mem_size(ctx),
1718        /*.mem_buffer =*/ nullptr,
1719        /*.no_alloc   =*/ true,
1720    };
1721    const ggml_init_params params_compute = {
1722        /*.mem_size   =*/ compute_headroom*ggml_get_mem_size(ctx),
1723        /*.mem_buffer =*/ nullptr,
1724        /*.no_alloc   =*/ true,
1725    };
1726    ggml_backend_meta_simple_tensor_container stc_static   (params_static,  n_simple_bufts);
1727    ggml_backend_meta_simple_tensor_container stc_compute_0(params_compute, n_simple_bufts);
1728    ggml_backend_meta_simple_tensor_container stc_compute_1(params_compute, n_simple_bufts);
1729
1730    std::vector<ggml_backend_buffer_t> bufs(n_simple_bufts, nullptr);
1731    ggml_backend_meta_buffer_context * meta_buf_ctx = new ggml_backend_meta_buffer_context(stc_static, stc_compute_0, stc_compute_1, bufs);
1732
1733    ggml_backend_buffer_t meta_buf = ggml_backend_buffer_init(buft, ggml_backend_meta_buffer_iface, meta_buf_ctx, 0);
1734    for (ggml_tensor * t = ggml_get_first_tensor(ctx); t != nullptr; t = ggml_get_next_tensor(ctx, t)) {
1735        t->buffer = meta_buf;
1736        ggml_backend_meta_buffer_init_tensor_impl(meta_buf_ctx->stc_static, t);
1737        t->data = (void *) 0x2000000000000000; // FIXME
1738    }
1739    for (size_t i = 0; i < n_simple_bufts; i++) {
1740        ggml_context * ctx = meta_buf_ctx->stc_static.ctxs[i].get();
1741        ggml_backend_buffer_type_t simple_buft = ggml_backend_meta_buft_simple_buft(buft, i);
1742
1743        // If a ggml_context only has zero-sized tensors, ggml_backend_alloc_ctx_tensors_from_buft returns NULL.
1744        // For those edge cases, allocate a dummy buffer instead.
1745        bool any_nonzero_slice = false;
1746        for (ggml_tensor * t = ggml_get_first_tensor(ctx); t != nullptr; t = ggml_get_next_tensor(ctx, t)) {
1747            if (ggml_nelements(t) != 0) {
1748                any_nonzero_slice = true;
1749                break;
1750            }
1751        }
1752        if (any_nonzero_slice) {
1753            meta_buf_ctx->bufs[i].reset(ggml_backend_alloc_ctx_tensors_from_buft(ctx, simple_buft));
1754        } else {
1755            meta_buf_ctx->bufs[i].reset(ggml_backend_buft_alloc_buffer(simple_buft, 0));
1756            for (ggml_tensor * t = ggml_get_first_tensor(ctx); t != nullptr; t = ggml_get_next_tensor(ctx, t)) {
1757                t->buffer = meta_buf_ctx->bufs[i].get();
1758            }
1759        }
1760        GGML_ASSERT(meta_buf_ctx->bufs[i]);
1761        meta_buf->size = std::max(meta_buf->size, ggml_backend_buffer_get_size(meta_buf_ctx->bufs[i].get()));
1762    }
1763    return meta_buf;
1764}
1765
1766//
1767// meta backend
1768//
1769
1770static ggml_guid_t ggml_backend_meta_guid() {
1771    static ggml_guid guid = {0xf1, 0x0e, 0x34, 0xcf, 0x9c, 0x6f, 0x43, 0xcb, 0x96, 0x92, 0xbe, 0x8e, 0xbb, 0x71, 0x3f, 0xda};
1772    return &guid;
1773}
1774
1775struct ggml_backend_meta_context {
1776    struct cgraph_config {
1777        ggml_cgraph * cgraph_main = nullptr;
1778        int           offset      = 0; // Node offset vs. original graph
1779
1780        std::vector<ggml_cgraph *> cgraphs_aux;
1781    };
1782    struct backend_config {
1783        ggml_backend_t backend;
1784
1785        std::vector<cgraph_config>           cgraphs;
1786        std::vector<ggml_tensor *>           nodes;
1787        std::vector<ggml_backend_buffer_ptr> bufs;
1788
1789        backend_config(ggml_backend_t backend, const size_t n_reduce_steps) : backend(backend) {
1790            bufs.resize(n_reduce_steps);
1791        }
1792    };
1793    std::string                 name;
1794    std::vector<backend_config> backend_configs;
1795    ggml_context_ptr            ctx;
1796    std::vector<ggml_cgraph *>  cgraphs_aux;
1797    std::vector<ggml_tensor *>  nodes_aux;
1798    size_t                      n_reduce_steps;
1799    int                         max_nnodes    = 0;
1800    size_t                      max_tmp_size  = 0;
1801    size_t                      max_subgraphs = 0;
1802    size_t                      n_subgraphs   = 0;
1803    uint64_t                    uid           = 0;
1804
1805    void *                               comm_ctx       = nullptr;
1806    ggml_backend_comm_allreduce_tensor_t comm_allreduce = nullptr;
1807
1808    ggml_backend_meta_context(ggml_backend_dev_t meta_dev, const char * params) {
1809        const size_t n_devs = ggml_backend_meta_dev_n_devs(meta_dev);
1810        n_reduce_steps = std::ceil(std::log2(n_devs));
1811        name = "Meta(";
1812        std::vector<ggml_backend_t> simple_backends;
1813        backend_configs.reserve(n_devs);
1814        simple_backends.reserve(n_devs);
1815        for (size_t i = 0; i < n_devs; i++) {
1816            ggml_backend_dev_t simple_dev = ggml_backend_meta_dev_simple_dev(meta_dev, i);
1817            if (i > 0) {
1818                name += ",";
1819            }
1820            name += ggml_backend_dev_name(simple_dev);
1821            simple_backends.push_back(ggml_backend_dev_init(simple_dev, params));
1822            backend_configs.emplace_back(simple_backends.back(), n_reduce_steps);
1823        }
1824        name += ")";
1825
1826        if (n_devs > 1) {
1827            ggml_backend_comm_init_t comm_init = (ggml_backend_comm_init_t) ggml_backend_reg_get_proc_address(
1828                ggml_backend_dev_backend_reg(ggml_backend_get_device(simple_backends[0])), "ggml_backend_comm_init");
1829            if (comm_init != nullptr) {
1830                comm_ctx = comm_init(simple_backends.data(), simple_backends.size());
1831            }
1832        }
1833        if (comm_ctx != nullptr) {
1834            comm_allreduce = (ggml_backend_comm_allreduce_tensor_t)
1835                ggml_backend_reg_get_proc_address(ggml_backend_dev_backend_reg(
1836                    ggml_backend_get_device(simple_backends[0])), "ggml_backend_comm_allreduce_tensor");
1837            GGML_ASSERT(comm_allreduce != nullptr);
1838        }
1839    }
1840
1841    ~ggml_backend_meta_context() {
1842        if (comm_ctx != nullptr) {
1843            ggml_backend_comm_free_t comm_free = (ggml_backend_comm_free_t) ggml_backend_reg_get_proc_address(
1844                ggml_backend_dev_backend_reg(ggml_backend_get_device(backend_configs[0].backend)), "ggml_backend_comm_free");
1845            GGML_ASSERT(comm_free != nullptr);
1846            comm_free(comm_ctx);
1847        }
1848        for (auto & bc : backend_configs) {
1849            ggml_backend_free(bc.backend);
1850        }
1851    }
1852};
1853
1854static const char * ggml_backend_meta_get_name(ggml_backend_t backend) {
1855    GGML_ASSERT(ggml_backend_is_meta(backend));
1856    const ggml_backend_meta_context * backend_ctx = (const ggml_backend_meta_context *) backend->context;
1857    return backend_ctx->name.c_str();
1858}
1859
1860static void ggml_backend_meta_free(ggml_backend_t backend) {
1861    GGML_ASSERT(ggml_backend_is_meta(backend));
1862    ggml_backend_meta_context * backend_ctx = (ggml_backend_meta_context *) backend->context;
1863    delete backend_ctx;
1864    delete backend;
1865}
1866
1867static void ggml_backend_meta_set_tensor_async(ggml_backend_t backend, ggml_tensor * tensor, const void * data, size_t offset, size_t size) {
1868    const size_t n_backends = ggml_backend_meta_n_backends(backend);
1869    GGML_ASSERT(offset == 0);
1870    GGML_ASSERT(ggml_is_contiguous(tensor));
1871
1872    const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(tensor, /*assume_sync =*/ false);
1873    GGML_ASSERT(split_state.n_segments == 1);
1874    GGML_ASSERT(split_state.nr[0]      == 1);
1875
1876    switch (split_state.axis) {
1877        case GGML_BACKEND_SPLIT_AXIS_0:
1878        case GGML_BACKEND_SPLIT_AXIS_1:
1879        case GGML_BACKEND_SPLIT_AXIS_2: {
1880            // Exploit that tensors are contiguous to splice it with simple tensors as "chunks".
1881            const size_t chunk_size_full = tensor->nb[split_state.axis + 1];
1882            GGML_ASSERT(offset % chunk_size_full == 0);
1883            GGML_ASSERT(size   % chunk_size_full == 0);
1884            const int64_t i_start =  offset        /chunk_size_full;
1885            const int64_t i_stop  = (offset + size)/chunk_size_full;
1886            size_t offset_j = 0;
1887            for (size_t j = 0; j < n_backends; j++){
1888                ggml_backend_t simple_backend = ggml_backend_meta_simple_backend(backend, j);
1889                ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1890                const size_t chunk_size_j = simple_tensor->nb[split_state.axis + 1];
1891                if (chunk_size_j == 0) {
1892                    continue;
1893                }
1894                ggml_backend_tensor_set_2d_async(simple_backend, simple_tensor, (const char *) data + offset_j, offset, chunk_size_j,
1895                    i_stop - i_start, chunk_size_j, chunk_size_full);
1896                offset_j += chunk_size_j;
1897            }
1898            GGML_ASSERT(offset_j == chunk_size_full);
1899        } break;
1900        case GGML_BACKEND_SPLIT_AXIS_MIRRORED: {
1901            for (size_t j = 0; j < n_backends; j++) {
1902                ggml_backend_tensor_set_async(
1903                    ggml_backend_meta_simple_backend(backend, j), ggml_backend_meta_buffer_simple_tensor(tensor, j), data, offset, size);
1904            }
1905        } break;
1906        default: {
1907            GGML_ABORT("fatal error");
1908        }
1909    }
1910}
1911
1912static void ggml_backend_meta_get_tensor_async(ggml_backend_t backend, const ggml_tensor * tensor, void * data, size_t offset, size_t size) {
1913    const size_t n_backends = ggml_backend_meta_n_backends(backend);
1914    GGML_ASSERT(offset == 0);
1915    GGML_ASSERT(ggml_is_contiguous(tensor));
1916
1917    const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(tensor, /*assume_sync =*/ false);
1918    GGML_ASSERT(split_state.n_segments == 1);
1919    GGML_ASSERT(split_state.nr[0]      == 1);
1920
1921    switch (split_state.axis) {
1922        case GGML_BACKEND_SPLIT_AXIS_0:
1923        case GGML_BACKEND_SPLIT_AXIS_1:
1924        case GGML_BACKEND_SPLIT_AXIS_2: {
1925            // Exploit that tensors are contiguous to splice it with simple tensors as "chunks".
1926            const size_t chunk_size_full = tensor->nb[split_state.axis + 1];
1927            GGML_ASSERT(offset % chunk_size_full == 0);
1928            GGML_ASSERT(size   % chunk_size_full == 0);
1929            const int64_t i_start =  offset        /chunk_size_full;
1930            const int64_t i_stop  = (offset + size)/chunk_size_full;
1931            size_t offset_j = 0;
1932            for (size_t j = 0; j < n_backends; j++){
1933                ggml_backend_t simple_backend = ggml_backend_meta_simple_backend(backend, j);
1934                const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, j);
1935                const size_t chunk_size_j = simple_tensor->nb[split_state.axis + 1];
1936                if (chunk_size_j == 0) {
1937                    continue;
1938                }
1939                ggml_backend_tensor_get_2d_async(simple_backend, simple_tensor, (char *) data + offset_j, offset, chunk_size_j,
1940                    i_stop - i_start, chunk_size_j, chunk_size_full);
1941                offset_j += chunk_size_j;
1942            }
1943            GGML_ASSERT(offset_j == chunk_size_full);
1944        } break;
1945        case GGML_BACKEND_SPLIT_AXIS_MIRRORED: {
1946            // TODO other simple backend may be better
1947            ggml_backend_t simple_backend = ggml_backend_meta_simple_backend(backend, 0);
1948            const ggml_tensor * simple_tensor = ggml_backend_meta_buffer_simple_tensor(tensor, 0);
1949            ggml_backend_tensor_get_async(simple_backend, simple_tensor, data, offset, size);
1950        } break;
1951        default: {
1952            GGML_ABORT("fatal error");
1953        }
1954    }
1955}
1956
1957static void ggml_backend_meta_synchronize(ggml_backend_t backend) {
1958    const size_t n_backends = ggml_backend_meta_n_backends(backend);
1959    for (size_t i = 0; i < n_backends; i++) {
1960        ggml_backend_synchronize(ggml_backend_meta_simple_backend(backend, i));
1961    }
1962}
1963
1964static enum ggml_status ggml_backend_meta_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) {
1965    GGML_ASSERT(cgraph->grads == nullptr);
1966    const size_t n_backends = ggml_backend_meta_n_backends(backend);
1967    ggml_backend_meta_context * backend_ctx = (ggml_backend_meta_context *) backend->context;
1968
1969    // If the previous cgraph had a defined UID it can be used to skip rebuilding the subgraphs per simple backend.
1970    const bool needs_rebuild = (cgraph->uid == 0) || (cgraph->uid != backend_ctx->uid);
1971
1972    bool max_nnodes_raised = false;
1973    if (cgraph->n_nodes > backend_ctx->max_nnodes) {
1974        for (size_t j = 0; j < n_backends; j++) {
1975            auto & bcj = backend_ctx->backend_configs[j];
1976            bcj.nodes.resize(cgraph->n_nodes);
1977            bcj.cgraphs.resize(cgraph->n_nodes);
1978        }
1979        backend_ctx->max_nnodes = cgraph->n_nodes;
1980        max_nnodes_raised = true;
1981        assert(needs_rebuild);
1982    }
1983
1984    if (needs_rebuild) {
1985        std::set<ggml_backend_buffer_t> used_buffers;
1986        for (int i = 0; i < cgraph->n_leafs; i++) {
1987            if (ggml_backend_buffer_is_meta(cgraph->leafs[i]->buffer)) {
1988                used_buffers.emplace(cgraph->leafs[i]->buffer);
1989            }
1990        }
1991        for (int i = 0; i < cgraph->n_nodes; i++) {
1992            if (ggml_backend_buffer_is_meta(cgraph->nodes[i]->buffer)) {
1993                used_buffers.emplace(cgraph->nodes[i]->buffer);
1994            }
1995        }
1996        for (ggml_backend_buffer_t buf : used_buffers) {
1997            ggml_backend_meta_buffer_context * buf_ctx = (ggml_backend_meta_buffer_context *) buf->context;
1998            buf_ctx->stc_compute_index_next = buf_ctx->stc_compute_index ^ 1;
1999            ggml_backend_meta_simple_tensor_container & stc = buf_ctx->stc_compute[buf_ctx->stc_compute_index_next];
2000            for (ggml_context_ptr & ctx : stc.ctxs) {
2001                ggml_reset(ctx.get());
2002            }
2003            stc.simple_tensors.clear();
2004        }
2005        size_t n_subgraphs  = 0;
2006        size_t max_tmp_size = 0;
2007
2008        for (size_t j = 0; j < n_backends; j++) {
2009            auto & bcj = backend_ctx->backend_configs[j];
2010
2011            for (int i = 0; i < cgraph->n_nodes; i++) {
2012                ggml_tensor * node = cgraph->nodes[i];
2013                if (node->view_src != nullptr && node->view_src->op == GGML_OP_NONE && ggml_backend_buffer_is_host(node->view_src->buffer)) {
2014                    // FIXME s_copy_main is on the CPU and its view seems to be incorrectly added to the graph nodes.
2015                    // For regular usage this doesn't matter since it's a noop but trying to call ggml_backend_meta_buffer_simple_tensor results in a crash.
2016                    bcj.nodes[i] = node;
2017                    continue;
2018                }
2019                bcj.nodes[i] = ggml_backend_meta_buffer_simple_tensor(node, j);
2020                GGML_ASSERT(bcj.nodes[i]);
2021            }
2022        }
2023
2024        {
2025            // For MoE models it may make sense to delay the AllReduce in order to reduce I/O:
2026            auto get_i_delayed_branch = [&](const int i) -> int {
2027                int id = i; // i_delayed
2028                int idr = i; // i_delayed return, last safe return value
2029
2030                ggml_tensor * node = cgraph->nodes[id];
2031                int32_t n_used = ggml_node_get_use_count(cgraph, id);
2032
2033                // Skip MIRRORED nodes that don't consume node
2034                auto skip_unrelated = [&]() {
2035                    while (id + 1 < cgraph->n_nodes) {
2036                        ggml_tensor * next = cgraph->nodes[id+1];
2037                        if (ggml_backend_meta_get_split_state(next, false).axis != GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
2038                            break;
2039                        }
2040                        bool safe = true;
2041                        for (int s = 0; s < GGML_MAX_SRC; s++) {
2042                            if (next->src[s] == nullptr) {
2043                                continue;
2044                            }
2045                            if (next->src[s] == node) {
2046                                safe = false;
2047                                break;
2048                            }
2049                            if (ggml_backend_meta_get_split_state(next->src[s], false).axis != GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
2050                                safe = false;
2051                                break;
2052                            }
2053                        }
2054                        if (!safe) {
2055                            break;
2056                        }
2057                        id++;
2058                    }
2059                };
2060
2061                skip_unrelated();
2062                if (id + 1 >= cgraph->n_nodes) {
2063                    return idr;
2064                }
2065                {
2066                    ggml_tensor * next = cgraph->nodes[id+1];
2067                    if (next->op == GGML_OP_ADD_ID && next->src[0] == node &&
2068                            ggml_backend_meta_get_split_state(next->src[1], false).axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL &&
2069                            ggml_backend_meta_get_split_state(next->src[2], false).axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
2070                        node = next;
2071                        id++;
2072                        idr = id;
2073                        n_used = ggml_node_get_use_count(cgraph, id);
2074                    }
2075                }
2076                // Chain of MULs with MIRRORED src[1]
2077                while (true) {
2078                    skip_unrelated();
2079                    if (id + 1 >= cgraph->n_nodes) {
2080                        return idr;
2081                    }
2082                    ggml_tensor * next = cgraph->nodes[id+1];
2083                    if (next->op == GGML_OP_MUL && next->src[0] == node &&
2084                            ggml_backend_meta_get_split_state(next->src[1], false).axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
2085                        node = next;
2086                        id++;
2087                        idr = id;
2088                        n_used = ggml_node_get_use_count(cgraph, id);
2089                    } else {
2090                        break;
2091                    }
2092                }
2093
2094                if (n_used != node->ne[1] || id + 2*n_used-1 >= cgraph->n_nodes) {
2095                    return idr;
2096                }
2097                for (int32_t k = 0; k < n_used; k++) {
2098                    ggml_tensor * next = cgraph->nodes[id+1];
2099                    if (next->op != GGML_OP_VIEW || next->view_src != node || next->view_offs != k*node->nb[1] ||
2100                            next->ne[0] != node->ne[0] || next->ne[1] != node->ne[2] || next->nb[1] != node->nb[2] ||
2101                            ggml_node_get_use_count(cgraph, id+1) != 1) {
2102                        return idr;
2103                    }
2104                    id++;
2105                }
2106                {
2107                    ggml_tensor * next = cgraph->nodes[id+1];
2108                    if (next->op != GGML_OP_ADD || next->src[0] != cgraph->nodes[id - (n_used-1)] ||
2109                            next->src[1] != cgraph->nodes[id - (n_used-2)] || ggml_node_get_use_count(cgraph, id+1) != 1) {
2110                        return idr;
2111                    }
2112                    id++;
2113                }
2114                for (int32_t k = 0; k < n_used - 2; k++) {
2115                    ggml_tensor * next = cgraph->nodes[id+1];
2116                    if (next->op != GGML_OP_ADD || next->src[0] != cgraph->nodes[id] ||
2117                            next->src[1] != cgraph->nodes[id - (n_used-2)] || ggml_node_get_use_count(cgraph, id+1) != 1) {
2118                        return idr;
2119                    }
2120                    id++;
2121                }
2122                idr = id;
2123                return idr;
2124            };
2125
2126            // AllReduce(a) + AllReduce(b) == AllReduce(a + b) for independent partial branches.
2127            auto get_i_delayed = [&](const int i) -> int {
2128                const int i_delayed = get_i_delayed_branch(i);
2129                ggml_tensor * node = cgraph->nodes[i_delayed];
2130
2131                if (ggml_node_get_use_count(cgraph, i_delayed) != 1) {
2132                    return i_delayed;
2133                }
2134
2135                for (int id = i_delayed + 1; id < cgraph->n_nodes; id++) {
2136                    ggml_tensor * next = cgraph->nodes[id];
2137                    if (next->view_src == node) {
2138                        return i_delayed;
2139                    }
2140                    for (int s = 0; s < GGML_MAX_SRC; s++) {
2141                        if (next->src[s] == node) {
2142                            return i_delayed;
2143                        }
2144                    }
2145
2146                    if (next->view_src != nullptr && next->view_src->op == GGML_OP_NONE && ggml_backend_buffer_is_host(next->view_src->buffer)) {
2147                        continue;
2148                    }
2149                    if (ggml_backend_meta_get_split_state(next, false).axis != GGML_BACKEND_SPLIT_AXIS_PARTIAL) {
2150                        continue;
2151                    }
2152
2153                    const int i_other = id;
2154                    const int i_other_delayed = get_i_delayed_branch(i_other);
2155                    ggml_tensor * other = cgraph->nodes[i_other_delayed];
2156                    if (ggml_node_get_use_count(cgraph, i_other_delayed) != 1 || i_other_delayed + 1 >= cgraph->n_nodes) {
2157                        return i_delayed;
2158                    }
2159
2160                    ggml_tensor * sum = cgraph->nodes[i_other_delayed + 1];
2161                    if (sum->op != GGML_OP_ADD ||
2162                            !ggml_are_same_shape(node, other) || node->type != other->type || sum->type != node->type ||
2163                            !((sum->src[0] == node && sum->src[1] == other) ||
2164                              (sum->src[0] == other && sum->src[1] == node)) ||
2165                            ggml_backend_meta_get_split_state(sum, false).axis != GGML_BACKEND_SPLIT_AXIS_MIRRORED) {
2166                        return i_delayed;
2167                    }
2168
2169                    for (size_t j = 0; j < n_backends; j++) {
2170                        auto & bcj = backend_ctx->backend_configs[j];
2171                        const bool compute       = bcj.nodes[i]->flags       & GGML_TENSOR_FLAG_COMPUTE;
2172                        const bool compute_other = bcj.nodes[i_other]->flags & GGML_TENSOR_FLAG_COMPUTE;
2173                        if (compute != compute_other) {
2174                            return i_delayed;
2175                        }
2176                    }
2177                    return i_other_delayed + 1;
2178                }
2179                return i_delayed;
2180            };
2181
2182            int i_start = 0;
2183            for (int i = 0; i < cgraph->n_nodes; i++) {
2184                ggml_tensor * node = cgraph->nodes[i];
2185                if (node->view_src != nullptr && node->view_src->op == GGML_OP_NONE && ggml_backend_buffer_is_host(node->view_src->buffer)) {
2186                    continue;
2187                }
2188                const ggml_backend_meta_split_state split_state = ggml_backend_meta_get_split_state(node, /*assume_sync =*/ false);
2189                if (split_state.axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL) {
2190                    max_tmp_size = std::max(max_tmp_size, ggml_nbytes(node));
2191                }
2192                const bool new_subgraph = i + 1 == cgraph->n_nodes || split_state.axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL;
2193                if (!new_subgraph) {
2194                    continue;
2195                }
2196
2197                const int i_delayed = get_i_delayed(i);
2198
2199                // If we can delay the AllReduce we need to consider the interaction with zero-sized tensor slices.
2200                // A backend with such a slice would normally have valid data after participating in the AllReduce with a node that has
2201                //     its compute flag disabled and thus gets its data zeroed out.
2202                // If the AllReduce is delayed then the nodes until that point also need to have their compute flag disabled.
2203                if (i_delayed > i) {
2204                    for (size_t j = 0; j < n_backends; j++) {
2205                        auto & bcj = backend_ctx->backend_configs[j];
2206                        if ((bcj.nodes[i]->flags & GGML_TENSOR_FLAG_COMPUTE) == 0) {
2207                            for (int ii = i + 1; ii <= i_delayed; ii++) {
2208                                bcj.nodes[ii]->flags &= ~GGML_TENSOR_FLAG_COMPUTE;
2209                            }
2210                        }
2211                    }
2212                }
2213
2214                i = i_delayed;
2215
2216                for (size_t j = 0; j < n_backends; j++) {
2217                    auto & bcj = backend_ctx->backend_configs[j];
2218                    bcj.cgraphs[n_subgraphs].offset = i_start;
2219                }
2220                n_subgraphs++;
2221                i_start = i + 1;
2222            }
2223            GGML_ASSERT(i_start == cgraph->n_nodes);
2224        }
2225
2226        backend_ctx->uid         = cgraph->uid;
2227        backend_ctx->n_subgraphs = n_subgraphs;
2228
2229        if (max_tmp_size > backend_ctx->max_tmp_size) {
2230            for (size_t j = 0; j < n_backends; j++) {
2231                auto & bcj = backend_ctx->backend_configs[j];
2232                for (size_t i = 0; i < backend_ctx->n_reduce_steps; i++) {
2233                    bcj.bufs[i].reset(ggml_backend_alloc_buffer(bcj.backend, max_tmp_size));
2234                }
2235            }
2236            backend_ctx->max_tmp_size = max_tmp_size;
2237        }
2238
2239        if (max_nnodes_raised || n_subgraphs > backend_ctx->max_subgraphs) {
2240            backend_ctx->max_subgraphs = std::max(backend_ctx->max_subgraphs, n_subgraphs);
2241            const size_t n_nodes_per_device = 3 * backend_ctx->n_reduce_steps; // tmp + ADD (+zeroing) graph per step and device
2242            const size_t n_cgraphs_per_device = 2 * backend_ctx->n_reduce_steps; // ADD ( + zeroing) graph per step and device
2243            const size_t mem_per_device_graphs_main = backend_ctx->max_subgraphs*ggml_graph_overhead_custom(backend_ctx->max_nnodes, cgraph->grads);
2244            const size_t mem_per_device_graphs_aux = n_cgraphs_per_device*backend_ctx->max_subgraphs*ggml_graph_overhead_custom(1, cgraph->grads);
2245            const size_t mem_per_device_nodes_aux = n_nodes_per_device*backend_ctx->max_subgraphs*ggml_tensor_overhead();
2246            const ggml_init_params params = {
2247                /*.mem_size   =*/ n_backends * (mem_per_device_graphs_main + mem_per_device_graphs_aux + mem_per_device_nodes_aux),
2248                /*.mem_buffer =*/ nullptr,
2249                /*.no_alloc   =*/ true,
2250            };
2251            backend_ctx->ctx.reset(ggml_init(params));
2252            for (size_t j = 0; j < n_backends; j++) {
2253                auto & bcj = backend_ctx->backend_configs[j];
2254                for (size_t i = 0; i < n_subgraphs; i++) {
2255                    bcj.cgraphs[i].cgraph_main = ggml_new_graph_custom(backend_ctx->ctx.get(), cgraph->n_nodes, /*grads =*/ false);
2256                }
2257            }
2258            backend_ctx->cgraphs_aux.resize(n_backends*n_cgraphs_per_device*backend_ctx->max_subgraphs);
2259            for (size_t k = 0; k < backend_ctx->cgraphs_aux.size(); k++) {
2260                backend_ctx->cgraphs_aux[k] = ggml_new_graph_custom(backend_ctx->ctx.get(), 1, cgraph->grads);
2261            }
2262            backend_ctx->nodes_aux.resize(n_backends*n_nodes_per_device*backend_ctx->max_subgraphs);
2263            for (size_t k = 0; k < backend_ctx->nodes_aux.size(); k++) {
2264                backend_ctx->nodes_aux[k] = ggml_new_tensor_1d(backend_ctx->ctx.get(), GGML_TYPE_F32, 1);
2265            }
2266        }
2267
2268        for (size_t j = 0; j < n_backends; j++) {
2269            auto & bcj = backend_ctx->backend_configs[j];
2270            for (size_t i_graph = 0; i_graph < n_subgraphs; i_graph++) {
2271                ggml_cgraph * cgraph_ij = bcj.cgraphs[i_graph].cgraph_main;
2272                const size_t i_node_start = bcj.cgraphs[i_graph].offset;
2273                const size_t i_node_stop = i_graph + 1 < n_subgraphs ? bcj.cgraphs[i_graph + 1].offset : cgraph->n_nodes;
2274                cgraph_ij->n_nodes = i_node_stop - i_node_start;
2275                ggml_hash_set_reset(&cgraph_ij->visited_hash_set);
2276                for (size_t i_node = i_node_start; i_node < i_node_stop; i_node++) {
2277                    ggml_tensor * node_ij = bcj.nodes[i_node];
2278                    cgraph_ij->nodes[i_node - i_node_start] = node_ij;
2279                    const size_t hash_pos_orig = ggml_hash_find(&cgraph->visited_hash_set, cgraph->nodes[i_node]);
2280                    const size_t hash_pos_ij = ggml_hash_insert(&cgraph_ij->visited_hash_set, node_ij);
2281                    cgraph_ij->use_counts[hash_pos_ij] = cgraph->use_counts[hash_pos_orig];
2282                }
2283                cgraph_ij->uid = ggml_graph_next_uid();
2284            }
2285        }
2286    }
2287
2288    size_t iga = 0; // i graph aux
2289    size_t ina = 0; // i node aux
2290
2291    auto get_node_aux = [&](ggml_tensor * t) -> ggml_tensor * {
2292        ggml_tensor * ret = backend_ctx->nodes_aux[ina++];
2293        memset(ret, 0, sizeof(ggml_tensor));
2294        ret->op   = GGML_OP_NONE;
2295        ret->type = t->type;
2296        for (size_t k = 0; k < GGML_MAX_DIMS; k++) {
2297            ret->ne[k] = t->ne[k];
2298            ret->nb[k] = t->nb[k];
2299        }
2300        return ret;
2301    };
2302    auto set_tmp_data = [&](ggml_tensor * tensor, const size_t j, const size_t i_buf) {
2303        auto & bcj = backend_ctx->backend_configs[j];
2304        ggml_backend_buffer_ptr & buf_ptr = bcj.bufs[i_buf];
2305        if (!buf_ptr || ggml_backend_buffer_get_size(buf_ptr.get()) < backend_ctx->max_tmp_size) {
2306            buf_ptr.reset(ggml_backend_alloc_buffer(bcj.backend, backend_ctx->max_tmp_size));
2307        }
2308        tensor->buffer = buf_ptr.get();
2309        tensor->data   = ggml_backend_buffer_get_base(buf_ptr.get());
2310    };
2311    // FIXME usage_counts
2312    auto get_cgraph_aux = [&]() -> ggml_cgraph * {
2313        ggml_cgraph * ret = backend_ctx->cgraphs_aux[iga++];
2314        return ret;
2315    };
2316
2317    // Preferentially use backend-specific allreduce_tensor_async (e.g. NCCL for CUDA), use a generic fallback if unavailable:
2318    auto allreduce_fallback = [&](size_t i) -> ggml_status {
2319        std::vector<ggml_cgraph *> step_cgraphs(n_backends, nullptr);
2320
2321        // Zero out nodes that were disabled due to having a zero-sized slice:
2322        for (size_t j = 0; j < n_backends; j++) {
2323            auto & bcj = backend_ctx->backend_configs[j];
2324            ggml_tensor * node = bcj.cgraphs[i].cgraph_main->nodes[bcj.cgraphs[i].cgraph_main->n_nodes - 1];
2325            if (node->flags & GGML_TENSOR_FLAG_COMPUTE) {
2326                continue;
2327            }
2328            ggml_tensor * node_zero = get_node_aux(node);
2329            node_zero->op = GGML_OP_SCALE; // FIXME 0.0f * NaN == NaN
2330            node_zero->src[0] = node;
2331            ggml_set_op_params_f32(node_zero, 0, 0.0f);
2332            node_zero->data = node->data;
2333            node_zero->buffer = node->buffer;
2334            node_zero->flags |= GGML_TENSOR_FLAG_COMPUTE;
2335
2336            step_cgraphs[j] = get_cgraph_aux();
2337            step_cgraphs[j]->nodes[0] = node_zero;
2338            step_cgraphs[j]->n_nodes = 1;
2339            const ggml_status status = ggml_backend_graph_compute_async(bcj.backend, step_cgraphs[j]);
2340            if (status != GGML_STATUS_SUCCESS) {
2341                return status;
2342            }
2343        }
2344        std::fill(step_cgraphs.begin(), step_cgraphs.end(), nullptr);
2345
2346        auto push_data = [&](const size_t j_src, const size_t j_dst, const size_t i_buf) {
2347            assert(step_cgraphs[j_dst] == nullptr);
2348            auto & bcj_src = backend_ctx->backend_configs[j_src];
2349            auto & bcj_dst = backend_ctx->backend_configs[j_dst];
2350
2351            ggml_tensor * node_src = bcj_src.cgraphs[i].cgraph_main->nodes[bcj_src.cgraphs[i].cgraph_main->n_nodes - 1];
2352            ggml_tensor * node_dst = bcj_dst.cgraphs[i].cgraph_main->nodes[bcj_dst.cgraphs[i].cgraph_main->n_nodes - 1];
2353            GGML_ASSERT(ggml_is_contiguous(node_src));
2354            GGML_ASSERT(ggml_is_contiguous(node_dst));
2355
2356            ggml_tensor * node_tmp = get_node_aux(node_dst);
2357            set_tmp_data(node_tmp, j_dst, i_buf);
2358
2359            ggml_backend_tensor_copy_async(bcj_src.backend, bcj_dst.backend, node_src, node_tmp);
2360
2361            ggml_tensor * node_red = get_node_aux(node_dst);
2362            node_red->view_src = node_dst->view_src == nullptr ? node_dst : node_dst->view_src;
2363            node_red->view_offs = node_dst->view_offs;
2364            node_red->op = GGML_OP_ADD;
2365            node_red->src[0] = node_dst;
2366            node_red->src[1] = node_tmp;
2367            node_red->flags |= GGML_TENSOR_FLAG_COMPUTE;
2368            ggml_backend_view_init(node_red);
2369
2370            ggml_cgraph * cgraph_aux = get_cgraph_aux();
2371            cgraph_aux->nodes[0] = node_red;
2372            cgraph_aux->n_nodes = 1;
2373            step_cgraphs[j_dst] = cgraph_aux;
2374        };
2375
2376        size_t offset_j = n_backends/2;
2377        while ((offset_j & (offset_j - 1)) != 0) {
2378            offset_j--;
2379        }
2380        const size_t offset_j_max = offset_j;
2381        size_t i_buf = 0;
2382
2383        // If n_backends is not a power of 2, fold in the excess prior to butterfly reduction:
2384        for (size_t j_src = 2*offset_j_max; j_src < n_backends; j_src++) {
2385            const size_t j_dst = j_src - 2*offset_j_max;
2386            push_data(j_src, j_dst, i_buf);
2387            const ggml_status status = ggml_backend_graph_compute_async(backend_ctx->backend_configs[j_dst].backend, step_cgraphs[j_dst]);
2388            if (status != GGML_STATUS_SUCCESS) {
2389                return status;
2390            }
2391            i_buf = 1;
2392        }
2393
2394        // Butterfly reduction:
2395        for (; offset_j >= 1; offset_j /= 2) {
2396            std::fill(step_cgraphs.begin(), step_cgraphs.end(), nullptr);
2397
2398            for (size_t j = 0; j < 2*offset_j_max; j++) {
2399                const size_t j_other = j ^ offset_j;
2400                if (j_other >= n_backends) {
2401                    continue;
2402                }
2403                push_data(j, j_other, i_buf);
2404            }
2405
2406            for (size_t j = 0; j < 2*offset_j_max; j++) {
2407                if (step_cgraphs[j] == nullptr) {
2408                    continue;
2409                }
2410                auto & bcj = backend_ctx->backend_configs[j];
2411                const ggml_status status = ggml_backend_graph_compute_async(bcj.backend, step_cgraphs[j]);
2412                if (status != GGML_STATUS_SUCCESS) {
2413                    return status;
2414                }
2415            }
2416            i_buf++;
2417        }
2418        assert(i_buf == backend_ctx->n_reduce_steps);
2419
2420        // If n_backends is not a power of 2, copy back the reduced tensors to the excess:
2421        for (size_t j = 2*offset_j_max; j < n_backends; j++) {
2422            auto & bcj_src = backend_ctx->backend_configs[j - 2*offset_j_max];
2423            auto & bcj_dst = backend_ctx->backend_configs[j];
2424
2425            ggml_tensor * node_src = bcj_src.cgraphs[i].cgraph_main->nodes[bcj_src.cgraphs[i].cgraph_main->n_nodes - 1];
2426            ggml_tensor * node_dst = bcj_dst.cgraphs[i].cgraph_main->nodes[bcj_dst.cgraphs[i].cgraph_main->n_nodes - 1];
2427            ggml_backend_tensor_copy_async(bcj_src.backend, bcj_dst.backend, node_src, node_dst);
2428        }
2429
2430        return GGML_STATUS_SUCCESS;
2431    };
2432
2433
2434    for (size_t i = 0; i < backend_ctx->n_subgraphs; i++) {
2435        for (size_t j = 0; j < n_backends; j++) {
2436            auto & bcj = backend_ctx->backend_configs[j];
2437            const ggml_status status = ggml_backend_graph_compute_async(bcj.backend, bcj.cgraphs[i].cgraph_main);
2438            if (status != GGML_STATUS_SUCCESS) {
2439                return status;
2440            }
2441        }
2442
2443        if (n_backends > 1 && i < backend_ctx->n_subgraphs - 1) {
2444            bool backend_allreduce_success = false;
2445            if (backend_ctx->comm_ctx) {
2446                std::vector<ggml_tensor *> nodes;
2447                nodes.reserve(n_backends);
2448                for (size_t j = 0; j < n_backends; j++) {
2449                    auto & bcj = backend_ctx->backend_configs[j];
2450                    ggml_cgraph * cgraph_ij = bcj.cgraphs[i].cgraph_main;
2451                    nodes.push_back(cgraph_ij->nodes[cgraph_ij->n_nodes-1]);
2452                }
2453                backend_allreduce_success = backend_ctx->comm_allreduce(backend_ctx->comm_ctx, nodes.data());
2454            }
2455
2456            if (!backend_allreduce_success) {
2457                const ggml_status status = allreduce_fallback(i);
2458                if (status != GGML_STATUS_SUCCESS) {
2459                    return status;
2460                }
2461            }
2462        }
2463    }
2464    return GGML_STATUS_SUCCESS;
2465}
2466
2467static const ggml_backend_i ggml_backend_meta_i = {
2468    /* .get_name                = */ ggml_backend_meta_get_name,
2469    /* .free                    = */ ggml_backend_meta_free,
2470    /* .set_tensor_async        = */ ggml_backend_meta_set_tensor_async,
2471    /* .get_tensor_async        = */ ggml_backend_meta_get_tensor_async,
2472    /* .set_tensor_2d_async     = */ nullptr,
2473    /* .get_tensor_2d_async     = */ nullptr,
2474    /* .cpy_tensor_async        = */ nullptr,
2475    /* .synchronize             = */ ggml_backend_meta_synchronize,
2476    /* .graph_plan_create       = */ nullptr,
2477    /* .graph_plan_free         = */ nullptr,
2478    /* .graph_plan_update       = */ nullptr,
2479    /* .graph_plan_compute      = */ nullptr,
2480    /* .graph_compute           = */ ggml_backend_meta_graph_compute,
2481    /* .event_record            = */ nullptr,
2482    /* .event_wait              = */ nullptr,
2483    /* .graph_optimize          = */ nullptr,
2484};
2485
2486bool ggml_backend_is_meta(ggml_backend_t backend) {
2487    return backend != nullptr && backend->iface.get_name == ggml_backend_meta_i.get_name;
2488}
2489
2490static ggml_backend_t ggml_backend_meta_device_init_backend(ggml_backend_dev_t dev, const char * params) {
2491    ggml_backend_meta_context * backend_ctx = new ggml_backend_meta_context(dev, params);
2492
2493    ggml_backend_t backend = new struct ggml_backend;
2494    backend->guid    = ggml_backend_meta_guid();
2495    backend->iface   = ggml_backend_meta_i;
2496    backend->device  = dev;
2497    backend->context = backend_ctx;
2498    return backend;
2499}
2500
2501size_t ggml_backend_meta_n_backends(ggml_backend_t meta_backend) {
2502    GGML_ASSERT(ggml_backend_is_meta(meta_backend));
2503    const ggml_backend_meta_context * backend_ctx = (const ggml_backend_meta_context *) meta_backend->context;
2504    return backend_ctx->backend_configs.size();
2505}
2506
2507ggml_backend_t ggml_backend_meta_simple_backend(ggml_backend_t meta_backend, size_t index) {
2508    GGML_ASSERT(ggml_backend_is_meta(meta_backend));
2509    const ggml_backend_meta_context * backend_ctx = (const ggml_backend_meta_context *) meta_backend->context;
2510    return backend_ctx->backend_configs[index].backend;
2511}