char-fork/llama.cpp

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

Georgi Gerganovmetal : single-source fusion table + fusion debug rework (#28164)a2878d30d

char/aliceai-t5-moe
4.7 KiB104 linesraw
1// single source of truth for the fusions supported by the Metal backend
2//
3// every fusable subgraph is declared exactly once as a ggml_metal_fusion entry in
4// the table in ggml-metal-fusion.cpp. both the graph optimizer (ggml_metal_fusion_max)
5// and the op encoders (ggml_metal_fusion_next) consult this same table, so the two
6// phases can never disagree about what can be fused.
7
8#pragma once
9
10#include "ggml-impl.h"
11
12#include <stdbool.h>
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18// the maximum number of nodes that can be fused in a single kernel
19// (also the maximum length of a packed fusion group during graph optimization)
20#define GGML_METAL_FUSION_MAX 16
21
22typedef enum ggml_metal_fusion_mode {
23    // structural checks only; used by the graph optimizer, at which point the graph
24    // tensors are not allocated yet, so buffer placement cannot be verified
25    GGML_METAL_FUSION_STRUCTURAL = 0,
26    // full checks, including buffer placement; used by the op encoders
27    GGML_METAL_FUSION_FULL,
28} ggml_metal_fusion_mode;
29
30// identifier of each fusion pattern so the op encoders know which kernel to use
31typedef enum ggml_metal_fusion_id {
32    GGML_METAL_FUSION_NONE = 0,
33    GGML_METAL_FUSION_NORM_MUL,     // NORM/RMS_NORM + MUL
34    GGML_METAL_FUSION_NORM_MUL_ADD, // NORM/RMS_NORM + MUL + ADD
35    GGML_METAL_FUSION_ADD_CHAIN,    // ADD x N (N in [2, 7])
36    GGML_METAL_FUSION_SNAKE,        // MUL + SIN + SQR + MUL + ADD
37    GGML_METAL_FUSION_GDN_CACHE,    // GATED_DELTA_NET + CPY (write snapshots into the recurrent cache)
38} ggml_metal_fusion_id;
39
40struct ggml_metal_fusion {
41    ggml_metal_fusion_id id;
42
43    const enum ggml_op * ops;        // op sequence (fixed length)
44    int                  n_ops;      // number of ops
45
46    // if unsafe: the generic chain/shape + ggml_can_fuse_subgraph checks are skipped and the
47    // check callback below is the sole validator (used for patterns that are not elision chains,
48    // e.g. the gdn + cache-cpy write-through fusion)
49    bool unsafe;
50
51    // extra backend constraints on top of ggml_can_fuse_subgraph
52    // nodes[j] is the j-th node of the pattern
53    bool (*check)(const struct ggml_metal_fusion   * fusion,
54                  const struct ggml_tensor * const * nodes,
55                        ggml_metal_fusion_mode       mode);
56};
57
58typedef struct ggml_metal_fusion ggml_metal_fusion;
59
60// the single table of all fusions supported by the Metal backend
61const ggml_metal_fusion * ggml_metal_fusion_all(int * n);
62
63// ---- shared fusion info ---------------------------------------------------
64
65// shared fusion debugging context, owned by the device; newly created backend contexts for that
66// device register with it so the fusion counters are race-free and accumulate across contexts.
67struct ggml_metal_fusion_info; // defined in ggml-metal-fusion.cpp
68
69struct ggml_metal_fusion_info * ggml_metal_fusion_info_init(bool enabled, int debug);
70void ggml_metal_fusion_info_free(struct ggml_metal_fusion_info * finfo);
71
72bool ggml_metal_fusion_info_enabled(const struct ggml_metal_fusion_info * finfo);
73bool ggml_metal_fusion_info_stats  (const struct ggml_metal_fusion_info * finfo);
74int  ggml_metal_fusion_info_debug  (const struct ggml_metal_fusion_info * finfo);
75
76int          ggml_metal_fusion_info_n_fusions(const struct ggml_metal_fusion_info * finfo);
77const char * ggml_metal_fusion_info_label    (const struct ggml_metal_fusion_info * finfo, int idx);
78uint64_t     ggml_metal_fusion_info_count    (const struct ggml_metal_fusion_info * finfo, int idx);
79
80void ggml_metal_fusion_info_count_fusion(struct ggml_metal_fusion_info * finfo, const struct ggml_metal_fusion * fusion);
81void ggml_metal_fusion_info_set_enabled (struct ggml_metal_fusion_info * finfo, bool enabled);
82
83void ggml_metal_fusion_info_stats_init (      struct ggml_metal_fusion_info * finfo);
84void ggml_metal_fusion_info_stats_reset(      struct ggml_metal_fusion_info * finfo);
85int  ggml_metal_fusion_info_stats_get  (const struct ggml_metal_fusion_info * finfo, const char ** labels, uint64_t * counts, int n);
86void ggml_metal_fusion_info_labels_init(      struct ggml_metal_fusion_info * finfo);
87
88// compute phase: longest fusion starting at idx (a position in node_idxs) that matches in `mode`.
89// returns the matching pattern (nullptr if no fusion) and sets *n_out to the number of nodes consumed.
90const ggml_metal_fusion * ggml_metal_fusion_next(
91        const struct ggml_cgraph * gf,
92        const int * node_idxs,
93        int n_idxs,
94        int idx,
95        ggml_metal_fusion_mode mode,
96        int * n_out);
97
98// optimize phase: maximum number of nodes starting at idx (a raw sequential graph index) that
99// could be fused, chaining patterns back-to-back. returns at least 1.
100int ggml_metal_fusion_max(const struct ggml_cgraph * gf, int idx);
101
102#ifdef __cplusplus
103}
104#endif