trim the metal shader to the dispatched kernels
Browse files- .gitattributes +2 -0
- build.toml +5 -3
- build/torch212-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so +3 -0
- build/torch212-metal-aarch64-darwin/_ops.py +3 -3
- build/torch212-metal-aarch64-darwin/metadata.json +4 -4
- build/torch213-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so +3 -0
- build/torch213-metal-aarch64-darwin/_ops.py +3 -3
- build/torch213-metal-aarch64-darwin/metadata.json +4 -4
- gguf_metal/ggml-metal-quant.metal +0 -0
- gguf_metal/quant_types.h +8 -0
- trim_shader.py +198 -0
.gitattributes
CHANGED
|
@@ -56,3 +56,5 @@ build/torch212-cxx11-cu132-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filte
|
|
| 56 |
build/torch213-cxx11-cu126-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 57 |
build/torch213-cxx11-cu130-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 58 |
build/torch213-cxx11-cu132-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 56 |
build/torch213-cxx11-cu126-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 57 |
build/torch213-cxx11-cu130-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 58 |
build/torch213-cxx11-cu132-x86_64-linux/_gguf_kernels_cuda_1df3b99.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
build/torch212-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
build/torch213-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so filter=lfs diff=lfs merge=lfs -text
|
build.toml
CHANGED
|
@@ -87,9 +87,11 @@ src = [
|
|
| 87 |
"gguf_metal/gguf_metal.cpp",
|
| 88 |
"gguf_metal/ggml_dispatch.mm",
|
| 89 |
"gguf_metal/common.h",
|
| 90 |
-
# ggml's shader,
|
| 91 |
-
#
|
| 92 |
-
|
|
|
|
|
|
|
| 93 |
"vendor/src/ggml-metal/ggml-metal-impl.h",
|
| 94 |
"vendor/src/ggml-common.h",
|
| 95 |
]
|
|
|
|
| 87 |
"gguf_metal/gguf_metal.cpp",
|
| 88 |
"gguf_metal/ggml_dispatch.mm",
|
| 89 |
"gguf_metal/common.h",
|
| 90 |
+
# ggml's shader, cut by `trim_shader.py` to the three kernels the dispatch names per quantization
|
| 91 |
+
# type -- 628 exported kernels down to 56, since none of ggml's attention, norm, conv or sampling
|
| 92 |
+
# kernels are reachable from here. `vendor/` keeps the untouched copy it is generated from.
|
| 93 |
+
"gguf_metal/ggml-metal-quant.metal",
|
| 94 |
+
"gguf_metal/quant_types.h",
|
| 95 |
"vendor/src/ggml-metal/ggml-metal-impl.h",
|
| 96 |
"vendor/src/ggml-common.h",
|
| 97 |
]
|
build/torch212-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d5ea02aab35301ff5a378d86de62477becd6604cd56ef6000802c15677c9375d
|
| 3 |
+
size 814816
|
build/torch212-metal-aarch64-darwin/_ops.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
import torch
|
| 2 |
-
from . import
|
| 3 |
-
ops = torch.ops.
|
| 4 |
|
| 5 |
def add_op_namespace_prefix(op_name: str):
|
| 6 |
"""
|
| 7 |
Prefix op by namespace.
|
| 8 |
"""
|
| 9 |
-
return f"
|
|
|
|
| 1 |
import torch
|
| 2 |
+
from . import _gguf_kernels_metal_7b10656
|
| 3 |
+
ops = torch.ops._gguf_kernels_metal_7b10656
|
| 4 |
|
| 5 |
def add_op_namespace_prefix(op_name: str):
|
| 6 |
"""
|
| 7 |
Prefix op by namespace.
|
| 8 |
"""
|
| 9 |
+
return f"_gguf_kernels_metal_7b10656::{op_name}"
|
build/torch212-metal-aarch64-darwin/metadata.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "gguf-kernels",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "MIT",
|
| 6 |
"python-depends": [],
|
|
@@ -11,8 +11,8 @@
|
|
| 11 |
"algorithm": "sha256",
|
| 12 |
"files": {
|
| 13 |
"__init__.py": "GoFcHJbbJ9C8b40XNznMxsTcC+CV9kaFE8a1DP763kU=",
|
| 14 |
-
"
|
| 15 |
-
"_ops.py": "
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"provenance": {
|
|
@@ -22,7 +22,7 @@
|
|
| 22 |
"dirty": false
|
| 23 |
},
|
| 24 |
"kernel": {
|
| 25 |
-
"sha": "
|
| 26 |
"dirty": false
|
| 27 |
}
|
| 28 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "gguf-kernels",
|
| 3 |
+
"id": "_gguf_kernels_metal_7b10656",
|
| 4 |
"version": 1,
|
| 5 |
"license": "MIT",
|
| 6 |
"python-depends": [],
|
|
|
|
| 11 |
"algorithm": "sha256",
|
| 12 |
"files": {
|
| 13 |
"__init__.py": "GoFcHJbbJ9C8b40XNznMxsTcC+CV9kaFE8a1DP763kU=",
|
| 14 |
+
"_gguf_kernels_metal_7b10656.abi3.so": "1eoCqrNTAf9aN42G3mJHe+zWYEzVbvYACALBVnfJN10=",
|
| 15 |
+
"_ops.py": "nwCRMS2OmSxach0Edkf8TLdxZXmrrMhMJntgxLN2MAI="
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"provenance": {
|
|
|
|
| 22 |
"dirty": false
|
| 23 |
},
|
| 24 |
"kernel": {
|
| 25 |
+
"sha": "7b106564513dead0e4416ea0c7d3898eb23e0ca2",
|
| 26 |
"dirty": false
|
| 27 |
}
|
| 28 |
}
|
build/torch213-metal-aarch64-darwin/_gguf_kernels_metal_7b10656.abi3.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e6dbb2eaefd58d768f8a9e30e89b08f1f7a139648b12fb8924a34caccbd8d066
|
| 3 |
+
size 814816
|
build/torch213-metal-aarch64-darwin/_ops.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
| 1 |
import torch
|
| 2 |
-
from . import
|
| 3 |
-
ops = torch.ops.
|
| 4 |
|
| 5 |
def add_op_namespace_prefix(op_name: str):
|
| 6 |
"""
|
| 7 |
Prefix op by namespace.
|
| 8 |
"""
|
| 9 |
-
return f"
|
|
|
|
| 1 |
import torch
|
| 2 |
+
from . import _gguf_kernels_metal_7b10656
|
| 3 |
+
ops = torch.ops._gguf_kernels_metal_7b10656
|
| 4 |
|
| 5 |
def add_op_namespace_prefix(op_name: str):
|
| 6 |
"""
|
| 7 |
Prefix op by namespace.
|
| 8 |
"""
|
| 9 |
+
return f"_gguf_kernels_metal_7b10656::{op_name}"
|
build/torch213-metal-aarch64-darwin/metadata.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "gguf-kernels",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "MIT",
|
| 6 |
"python-depends": [],
|
|
@@ -11,8 +11,8 @@
|
|
| 11 |
"algorithm": "sha256",
|
| 12 |
"files": {
|
| 13 |
"__init__.py": "GoFcHJbbJ9C8b40XNznMxsTcC+CV9kaFE8a1DP763kU=",
|
| 14 |
-
"
|
| 15 |
-
"_ops.py": "
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"provenance": {
|
|
@@ -22,7 +22,7 @@
|
|
| 22 |
"dirty": false
|
| 23 |
},
|
| 24 |
"kernel": {
|
| 25 |
-
"sha": "
|
| 26 |
"dirty": false
|
| 27 |
}
|
| 28 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "gguf-kernels",
|
| 3 |
+
"id": "_gguf_kernels_metal_7b10656",
|
| 4 |
"version": 1,
|
| 5 |
"license": "MIT",
|
| 6 |
"python-depends": [],
|
|
|
|
| 11 |
"algorithm": "sha256",
|
| 12 |
"files": {
|
| 13 |
"__init__.py": "GoFcHJbbJ9C8b40XNznMxsTcC+CV9kaFE8a1DP763kU=",
|
| 14 |
+
"_gguf_kernels_metal_7b10656.abi3.so": "5tuy6u/VjXaPip4w6JsI8fehOWSLEvuJJKNMrMvY0GY=",
|
| 15 |
+
"_ops.py": "nwCRMS2OmSxach0Edkf8TLdxZXmrrMhMJntgxLN2MAI="
|
| 16 |
}
|
| 17 |
},
|
| 18 |
"provenance": {
|
|
|
|
| 22 |
"dirty": false
|
| 23 |
},
|
| 24 |
"kernel": {
|
| 25 |
+
"sha": "7b106564513dead0e4416ea0c7d3898eb23e0ca2",
|
| 26 |
"dirty": false
|
| 27 |
}
|
| 28 |
}
|
gguf_metal/ggml-metal-quant.metal
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
gguf_metal/quant_types.h
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
// Generated by trim_shader.py from llama.cpp @ 432d7ffe2c3b -- do not edit.
|
| 3 |
+
|
| 4 |
+
namespace gguf_quant_types {
|
| 5 |
+
|
| 6 |
+
inline constexpr const char *built[] = {"iq1_m", "iq1_s", "iq2_s", "iq2_xs", "iq2_xxs", "iq3_s", "iq3_xxs", "iq4_nl", "iq4_xs", "mxfp4", "q2_K", "q3_K", "q4_0", "q4_1", "q4_K", "q5_0", "q5_1", "q5_K", "q6_K", "q8_0"};
|
| 7 |
+
|
| 8 |
+
} // namespace gguf_quant_types
|
trim_shader.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Cut ggml's Metal shader down to the kernels this package can actually dispatch, and emit the
|
| 2 |
+
table `ggml_dispatch.mm` uses to decide what it supports.
|
| 3 |
+
|
| 4 |
+
ggml's Metal backend is one translation unit: `vendor/src/ggml-metal/ggml-metal.metal` exports 603
|
| 5 |
+
kernels, of which we name 25. There is no upstream target for a subset, but the bulk of the file is
|
| 6 |
+
templates plus a block of `template [[host_name(...)]]` instantiations -- and an uninstantiated
|
| 7 |
+
template emits no code. So dropping the instantiations we cannot name is enough: 6.84 MB -> 0.64 MB
|
| 8 |
+
of metallib, with the same 52 tests passing.
|
| 9 |
+
|
| 10 |
+
`vendor/` stays a byte-for-byte copy of upstream; the trimmed shader is generated beside the backend
|
| 11 |
+
source and committed, because a hub `kernels` build compiles the `src` list in build.toml and has
|
| 12 |
+
nowhere to run a pre-step. Both outputs are generated -- never hand-edit them, re-run this instead
|
| 13 |
+
(`vendor.py` does, after every pin bump).
|
| 14 |
+
|
| 15 |
+
The dispatcher names kernels as `kernel_flash_attn_ext[_vec]_f32_dk<K>_dv<V>`, so the f16, bf16 and
|
| 16 |
+
five quantized-KV families upstream also instantiates are unreachable here. The dk/dv pairs that do
|
| 17 |
+
exist are parsed out rather than hand-copied, which is what keeps `supports_flash_attn` from
|
| 18 |
+
claiming a shape whose pipeline was never built.
|
| 19 |
+
|
| 20 |
+
Usage: python trim_shader.py [--no-trim]
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
import argparse
|
| 24 |
+
import os
|
| 25 |
+
import re
|
| 26 |
+
|
| 27 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 28 |
+
SHADER_IN = os.path.join(HERE, "vendor", "src", "ggml-metal", "ggml-metal.metal")
|
| 29 |
+
SHADER_OUT = os.path.join(HERE, "gguf_metal", "ggml-metal-quant.metal")
|
| 30 |
+
HEADER_OUT = os.path.join(HERE, "gguf_metal", "quant_types.h")
|
| 31 |
+
|
| 32 |
+
# What `ggml_dispatch.mm` builds with snprintf. Everything else upstream exports is dropped.
|
| 33 |
+
# The three kernels `ggml_dispatch.mm` names per quantization type, and the types its `type_table()`
|
| 34 |
+
# carries -- parsed from the dispatch rather than repeated here, so the two cannot drift.
|
| 35 |
+
def _dispatched_types():
|
| 36 |
+
source = open(os.path.join(HERE, "gguf_metal", "ggml_dispatch.mm")).read()
|
| 37 |
+
table = source[source.index("const std::unordered_map<int, TypeInfo> &type_table()") :]
|
| 38 |
+
return re.findall(r'\{GGML_\w+, \{"(\w+)"', table[: table.index("\n}")])
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
TYPES = _dispatched_types()
|
| 42 |
+
DISPATCHABLE = re.compile(
|
| 43 |
+
r"^kernel_(?:mul_mv|mul_mm)_(" + "|".join(TYPES) + r")_f32$|^kernel_get_rows_(" + "|".join(TYPES) + r")$"
|
| 44 |
+
)
|
| 45 |
+
GENERATED_BY = "trim_shader.py"
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# Kernels declared plainly, with no `host_name` to instantiate them -- rwkv, ssm, pooling, upscale,
|
| 49 |
+
# the adamw steps, the quantized mul_mv family. Every `kernel void` is an exported entry point, so
|
| 50 |
+
# they survive on their own; nothing can call them from here, since a kernel cannot call a kernel.
|
| 51 |
+
#
|
| 52 |
+
# A templated one is a different thing with the same spelling: it emits nothing until instantiated,
|
| 53 |
+
# and its body is what the `host_name` lines above refer to. Dropping those leaves the `template<>`
|
| 54 |
+
# prefix dangling on whatever follows, so they are left alone and cost nothing.
|
| 55 |
+
PLAIN_KERNEL = re.compile(r"^kernel void (\w+)\(")
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def _referenced_names(lines):
|
| 59 |
+
"""Kernel names other lines instantiate or alias: templates the file still needs, not leaf kernels."""
|
| 60 |
+
referring = "".join(l for l in lines if "decltype(" in l or "host_name" in l)
|
| 61 |
+
return set(re.findall(r"\b(kernel_\w+)\b", referring))
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def _declaration_start(out, name):
|
| 65 |
+
"""Rewind over the `template<...>` header and comments that belong to the definition being cut.
|
| 66 |
+
|
| 67 |
+
A dropped definition whose header stays behind reparents that header onto whatever follows, so
|
| 68 |
+
the header has to go with it -- as do the comment lines written for it.
|
| 69 |
+
"""
|
| 70 |
+
while out:
|
| 71 |
+
last = out[-1].strip()
|
| 72 |
+
if last.startswith("//") or not last:
|
| 73 |
+
out.pop()
|
| 74 |
+
continue
|
| 75 |
+
# A `template<...>` header belongs to the definition being cut. A `template [[host_name(..)]] ... ;`
|
| 76 |
+
# instantiation does not -- it is a whole declaration of its own, and eating it silently drops a
|
| 77 |
+
# kernel that was meant to be kept.
|
| 78 |
+
if last.startswith("template") and "host_name" not in last and not last.endswith(";"):
|
| 79 |
+
out.pop()
|
| 80 |
+
continue
|
| 81 |
+
break
|
| 82 |
+
return out
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _skip_statement(lines, i):
|
| 86 |
+
"""Advance past the statement starting at `i`: to its `;`, or past the body if it has one."""
|
| 87 |
+
depth, in_body = 0, False
|
| 88 |
+
while i < len(lines):
|
| 89 |
+
depth += lines[i].count("{") - lines[i].count("}")
|
| 90 |
+
in_body = in_body or "{" in lines[i]
|
| 91 |
+
ends = (in_body and depth <= 0) or (not in_body and lines[i].rstrip().endswith(";"))
|
| 92 |
+
i += 1
|
| 93 |
+
if ends:
|
| 94 |
+
return i
|
| 95 |
+
return i
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def trim(lines):
|
| 99 |
+
"""Drop each exported kernel we cannot name, statement by statement.
|
| 100 |
+
|
| 101 |
+
Four shapes export a kernel: a one-line template instantiation; `template [[host_name(..)]]`
|
| 102 |
+
with the instantiation on following lines; `[[host_name(..)]]` on a full kernel definition; and
|
| 103 |
+
a plain `kernel void name(...)` definition with no attribute at all.
|
| 104 |
+
"""
|
| 105 |
+
referenced = _referenced_names(lines)
|
| 106 |
+
kept_names, out, i = [], [], 0
|
| 107 |
+
while i < len(lines):
|
| 108 |
+
plain = PLAIN_KERNEL.match(lines[i])
|
| 109 |
+
if plain and not any(k in plain.group(1) for k in ("mul_mv", "mul_mm", "get_rows")) and plain.group(1) not in referenced:
|
| 110 |
+
_declaration_start(out, plain.group(1))
|
| 111 |
+
i = _skip_statement(lines, i)
|
| 112 |
+
# `typedef decltype(name<...>) name_t;` exists only to name the thing just dropped.
|
| 113 |
+
while i < len(lines) and f"decltype({plain.group(1)}" in lines[i]:
|
| 114 |
+
i += 1
|
| 115 |
+
continue
|
| 116 |
+
found = re.search(r'host_name\("([^"]+)"', lines[i])
|
| 117 |
+
if found and not DISPATCHABLE.match(found.group(1)):
|
| 118 |
+
if lines[i].rstrip().endswith(";"):
|
| 119 |
+
i += 1
|
| 120 |
+
continue
|
| 121 |
+
i = _skip_statement(lines, i)
|
| 122 |
+
continue
|
| 123 |
+
if found:
|
| 124 |
+
kept_names.append(found.group(1))
|
| 125 |
+
out.append(lines[i])
|
| 126 |
+
i += 1
|
| 127 |
+
return out, kept_names
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def header(names, revision):
|
| 131 |
+
"""The quantization types this build carries kernels for, parsed from the shader."""
|
| 132 |
+
types = sorted({m.group(1) or m.group(2) for name in names if (m := DISPATCHABLE.match(name))})
|
| 133 |
+
entries = ", ".join(f'"{t}"' for t in types)
|
| 134 |
+
return f"""\
|
| 135 |
+
#pragma once
|
| 136 |
+
// Generated by {GENERATED_BY} from llama.cpp @ {revision} -- do not edit.
|
| 137 |
+
|
| 138 |
+
namespace gguf_quant_types {{
|
| 139 |
+
|
| 140 |
+
inline constexpr const char *built[] = {{{entries}}};
|
| 141 |
+
|
| 142 |
+
}} // namespace gguf_quant_types
|
| 143 |
+
"""
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def main():
|
| 147 |
+
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
| 148 |
+
ap.add_argument(
|
| 149 |
+
"--no-trim",
|
| 150 |
+
action="store_true",
|
| 151 |
+
help="copy the shader verbatim instead of cutting it. The trim is an optimisation, so it must "
|
| 152 |
+
"never be what blocks a pin bump: if upstream reshapes its declarations and the cut stops "
|
| 153 |
+
"compiling, ship the whole 6.84 MB shader with this and fix the cut afterwards.",
|
| 154 |
+
)
|
| 155 |
+
args = ap.parse_args()
|
| 156 |
+
|
| 157 |
+
with open(SHADER_IN) as f:
|
| 158 |
+
lines = f.readlines()
|
| 159 |
+
revision = "unknown"
|
| 160 |
+
upstream = os.path.join(HERE, "vendor", "UPSTREAM")
|
| 161 |
+
if os.path.exists(upstream):
|
| 162 |
+
with open(upstream) as f:
|
| 163 |
+
revision = f.read().split("\n")[1][:12]
|
| 164 |
+
|
| 165 |
+
out, kept = (lines, [m.group(1) for l in lines
|
| 166 |
+
for m in [re.search(r'host_name\("([^"]+)"', l)]
|
| 167 |
+
if m and DISPATCHABLE.match(m.group(1))]) if args.no_trim else trim(lines)
|
| 168 |
+
|
| 169 |
+
# The dispatcher builds names for both paths and calls three helpers by name; a keep-list that
|
| 170 |
+
# lost any of them would build clean and fail at runtime, so refuse to emit it.
|
| 171 |
+
# Every type the dispatch can ask for must have all three of its kernels, or a model using that
|
| 172 |
+
# quantization fails at its first forward instead of at build time.
|
| 173 |
+
# Against the emitted shader, not the instantiation list: some of these are plain definitions rather
|
| 174 |
+
# than `host_name` instantiations, so they never appear in `kept`.
|
| 175 |
+
body = "".join(out)
|
| 176 |
+
missing = [f"{prefix}{t}{suffix}"
|
| 177 |
+
for t in TYPES
|
| 178 |
+
for prefix, suffix in (("kernel_mul_mv_", "_f32"), ("kernel_mul_mm_", "_f32"),
|
| 179 |
+
("kernel_get_rows_", ""))
|
| 180 |
+
if f"{prefix}{t}{suffix}" not in body]
|
| 181 |
+
if missing:
|
| 182 |
+
raise SystemExit(f"refusing to write: kept {len(kept)} kernels, missing {len(missing)}: "
|
| 183 |
+
f"{missing[:4]}. Upstream's shader has changed shape -- rerun with --no-trim.")
|
| 184 |
+
with open(SHADER_OUT, "w") as f:
|
| 185 |
+
f.write(f"// Generated by {GENERATED_BY} from vendor/src/ggml-metal/ggml-metal.metal "
|
| 186 |
+
f"(llama.cpp @ {revision}) -- do not edit.\n")
|
| 187 |
+
f.writelines(out)
|
| 188 |
+
with open(HEADER_OUT, "w") as f:
|
| 189 |
+
f.write(header(kept, revision))
|
| 190 |
+
|
| 191 |
+
dropped = sum("host_name" in line for line in lines) - len(kept)
|
| 192 |
+
print(f"kept {len(kept)} kernels over {len(TYPES)} quantization types, dropped {dropped}")
|
| 193 |
+
print(f" {SHADER_OUT}")
|
| 194 |
+
print(f" {HEADER_OUT}")
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
if __name__ == "__main__":
|
| 198 |
+
main()
|