sync 6fdf6301e2bb
Browse files- README.md +17 -4
- build/webgpu/bench.json +0 -0
- build/webgpu/{gemm-fast-gelu.wgsl.jinja → gemm-epilogue-tiled-reg.wgsl.jinja} +63 -20
- build/webgpu/gemm-subgroup-matrix.wgsl.jinja +24 -65
- build/webgpu/manifest.json +453 -53
- build/webgpu/matmul-vector-matrix-vec4.wgsl.jinja +70 -0
- build/webgpu/metadata.json +21 -10
- build/webgpu/test.json +0 -0
README.md
CHANGED
|
@@ -40,6 +40,16 @@ See the [ONNX Runtime `GemmFastGelu` contrib-operator spec](https://github.com/m
|
|
| 40 |
|
| 41 |
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
- `sgmat_direct_bias` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 44 |
- `sgmat_direct` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 45 |
- `sgmat_direct_bias_f16` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
|
@@ -48,6 +58,8 @@ One implementation is selected per call from the device capabilities, the reques
|
|
| 48 |
- `sgmat` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 49 |
- `sgmat_bias_f16` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 50 |
- `sgmat_f16` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
|
|
|
|
|
|
| 51 |
|
| 52 |
## Device requirements
|
| 53 |
|
|
@@ -58,14 +70,15 @@ Some implementation variants require `subgroup-matrix` and `subgroups`. These ar
|
|
| 58 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 59 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 60 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 61 |
-
- [`bench.json`](build/webgpu/bench.json) — benchmark
|
| 62 |
-
- [`gemm-
|
| 63 |
- [`gemm-subgroup-matrix.wgsl.jinja`](build/webgpu/gemm-subgroup-matrix.wgsl.jinja)
|
|
|
|
| 64 |
|
| 65 |
## Use with `@huggingface/kernels`
|
| 66 |
|
| 67 |
```sh
|
| 68 |
-
npm install --save-exact @huggingface/kernels@0.0.1-preview.
|
| 69 |
```
|
| 70 |
|
| 71 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
|
@@ -79,5 +92,5 @@ Replace each `*Data` placeholder with a typed array containing the corresponding
|
|
| 79 |
import { getKernel } from "@huggingface/kernels";
|
| 80 |
|
| 81 |
const kernel = await getKernel("webgpu-kernels/com.microsoft.GemmFastGelu", { version: 1 });
|
| 82 |
-
const { Y } = await kernel({ X: { data: XData, shape: [
|
| 83 |
```
|
|
|
|
| 40 |
|
| 41 |
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 42 |
|
| 43 |
+
- `vector_matrix_bias` — Partitions a single-row vector-matrix product across device-bounded workgroup slices. Optional bias and FastGelu are fused into the f32 reduction before the single output cast; no subgroup feature is required.
|
| 44 |
+
- `vector_matrix` — Partitions a single-row vector-matrix product across device-bounded workgroup slices. Optional bias and FastGelu are fused into the f32 reduction before the single output cast; no subgroup feature is required.
|
| 45 |
+
- `sgmat_medium_bias` — Uses supported subgroup matrices with 32x32 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 46 |
+
- `sgmat_medium` — Uses supported subgroup matrices with 32x32 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 47 |
+
- `sgmat_medium_bias_f16` — Uses supported subgroup matrices with 32x32 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 48 |
+
- `sgmat_medium_f16` — Uses supported subgroup matrices with 32x32 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 49 |
+
- `sgmat_small_bias` — Uses supported subgroup matrices with 32x16 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 50 |
+
- `sgmat_small` — Uses supported subgroup matrices with 32x16 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 51 |
+
- `sgmat_small_bias_f16` — Uses supported subgroup matrices with 32x16 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 52 |
+
- `sgmat_small_f16` — Uses supported subgroup matrices with 32x16 direct activation tiles and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 53 |
- `sgmat_direct_bias` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 54 |
- `sgmat_direct` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 55 |
- `sgmat_direct_bias_f16` — Uses supported subgroup matrices with direct activation loads and double-buffered weights. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
|
|
|
| 58 |
- `sgmat` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 59 |
- `sgmat_bias_f16` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 60 |
- `sgmat_f16` — Uses supported subgroup matrices with staged operands. Bias and FastGelu run on the f32 accumulator before the single output cast. Resource, alignment and matrix-type guards retain the portable path on other devices.
|
| 61 |
+
- `tiled_bias` — Portable register tiles use the output-grid budget and a device-specific f32 tile choice to improve occupancy, with device-bounded shared padding and compensated f32 tile sums before the fused activation.
|
| 62 |
+
- `tiled` — Portable register tiles use the output-grid budget and a device-specific f32 tile choice to improve occupancy, with device-bounded shared padding and compensated f32 tile sums before the fused activation.
|
| 63 |
|
| 64 |
## Device requirements
|
| 65 |
|
|
|
|
| 70 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 71 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 72 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 73 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark cases
|
| 74 |
+
- [`gemm-epilogue-tiled-reg.wgsl.jinja`](build/webgpu/gemm-epilogue-tiled-reg.wgsl.jinja)
|
| 75 |
- [`gemm-subgroup-matrix.wgsl.jinja`](build/webgpu/gemm-subgroup-matrix.wgsl.jinja)
|
| 76 |
+
- [`matmul-vector-matrix-vec4.wgsl.jinja`](build/webgpu/matmul-vector-matrix-vec4.wgsl.jinja)
|
| 77 |
|
| 78 |
## Use with `@huggingface/kernels`
|
| 79 |
|
| 80 |
```sh
|
| 81 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.3
|
| 82 |
```
|
| 83 |
|
| 84 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
|
|
|
| 92 |
import { getKernel } from "@huggingface/kernels";
|
| 93 |
|
| 94 |
const kernel = await getKernel("webgpu-kernels/com.microsoft.GemmFastGelu", { version: 1 });
|
| 95 |
+
const { Y } = await kernel({ X: { data: XData, shape: [1, 1] }, W: { data: WData, shape: [1, 4] } });
|
| 96 |
```
|
build/webgpu/bench.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/webgpu/{gemm-fast-gelu.wgsl.jinja → gemm-epilogue-tiled-reg.wgsl.jinja}
RENAMED
|
@@ -1,47 +1,56 @@
|
|
| 1 |
-
{% if usesF16 is defined and usesF16 %}
|
| 2 |
-
{% endif %}{% set OUT = "f16" if (usesF16 is defined and usesF16) else "f32" %}
|
| 3 |
{{ env.wgsl.resourceDeclarations }}
|
| 4 |
|
| 5 |
// Shape-driven, register-blocked f32 GEMM for all four transpose combinations.
|
| 6 |
-
// Runtime M/N/K share one compiled pipeline
|
| 7 |
-
//
|
| 8 |
-
// keep the stored-contiguous axis coalesced. M/N/K tails are bounds-checked
|
|
|
|
| 9 |
// Both tiles are indexed by their own output axis and group four K values per
|
| 10 |
// vector word, so the micro-tile accumulates through dot() and one step reads
|
| 11 |
// TM + TN words instead of 4 * (TM + TN) scalars.
|
| 12 |
-
{% set gemmEpi = gemmEpilogue if gemmEpilogue is defined else "none" %}
|
| 13 |
fn tanh_safe(x: f32) -> f32 {
|
|
|
|
|
|
|
| 14 |
if (x > 10.0) { return 1.0; }
|
| 15 |
if (x < -10.0) { return -1.0; }
|
|
|
|
|
|
|
|
|
|
| 16 |
return tanh(x);
|
| 17 |
}
|
| 18 |
|
| 19 |
fn gelu_tanh(v: f32) -> f32 {
|
| 20 |
return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
|
| 21 |
}
|
| 22 |
-
{% set epiOpen = "gelu_tanh("
|
| 23 |
-
{% set epiClose = ")"
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
// Stage tiles at the operands' storage width. For f16 inputs this is
|
| 31 |
// bit-identical to widening on shared load, keeps f32 FMA registers, and halves
|
| 32 |
// workgroup storage.
|
| 33 |
{% set tileT = OUT %}
|
| 34 |
const K_VECS: u32 = BK / 4u;
|
| 35 |
-
var<workgroup> tileA: array<array<vec4<{{ tileT }}>, K_VECS>, BM>; //
|
| 36 |
-
var<workgroup> tileB: array<array<vec4<{{ tileT }}>, K_VECS>, BN>; //
|
| 37 |
|
| 38 |
-
@compute @workgroup_size(
|
| 39 |
fn main(
|
| 40 |
@builtin(workgroup_id) wg: vec3<u32>,
|
| 41 |
@builtin(local_invocation_id) lid: vec3<u32>,
|
| 42 |
@builtin(num_workgroups) nwg: vec3<u32>
|
| 43 |
) {
|
| 44 |
-
let li = lid.y *
|
| 45 |
let M = params.M;
|
| 46 |
let N = params.N;
|
| 47 |
let K = params.K;
|
|
@@ -55,46 +64,70 @@ fn main(
|
|
| 55 |
var acc: array<f32, TM * TN>;
|
| 56 |
for (var i: u32 = 0u; i < TM * TN; i = i + 1u) { acc[i] = 0.0; }
|
| 57 |
|
|
|
|
|
|
|
|
|
|
| 58 |
let numTiles = (K + BK - 1u) / BK;
|
| 59 |
for (var kt: u32 = 0u; kt < numTiles; kt = kt + 1u) {
|
| 60 |
let kBase = kt * BK;
|
| 61 |
// Cooperative load: one vector word per lane per pass. The lane grid is
|
| 62 |
// laid out so the axis the operand stores contiguously stays coalesced.
|
| 63 |
-
for (var idx: u32 = li; idx < BM * K_VECS; idx = idx +
|
| 64 |
// A stored [M, K]: logical A[m,k] = a[m*K + k]. Coalesce on k (contiguous).
|
| 65 |
let ar = idx / K_VECS;
|
| 66 |
let ac4 = idx % K_VECS;
|
| 67 |
let am = mBase + ar;
|
| 68 |
let ak = kBase + ac4 * 4u;
|
| 69 |
var aWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
|
|
|
| 70 |
if (am < M) {
|
|
|
|
| 71 |
{% for component in range(4) %}
|
|
|
|
| 72 |
if (ak + {{ component }}u < K) {
|
|
|
|
| 73 |
aWord[{{ component }}u] = {{ tileT }}(a[am * K + ak + {{ component }}u]);
|
|
|
|
| 74 |
}
|
|
|
|
| 75 |
{% endfor %}
|
|
|
|
| 76 |
}
|
|
|
|
| 77 |
tileA[ar][ac4] = aWord;
|
| 78 |
}
|
| 79 |
-
for (var idx: u32 = li; idx < BN * K_VECS; idx = idx +
|
| 80 |
// B stored [K, N]: logical B[k,n] = b[k*N + n]. Coalesce on n (contiguous).
|
| 81 |
let bc = idx % BN;
|
| 82 |
let br4 = idx / BN;
|
| 83 |
let bn = nBase + bc;
|
| 84 |
let bk = kBase + br4 * 4u;
|
| 85 |
var bWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
|
|
|
| 86 |
if (bn < N) {
|
|
|
|
| 87 |
{% for component in range(4) %}
|
|
|
|
| 88 |
if (bk + {{ component }}u < K) {
|
|
|
|
| 89 |
bWord[{{ component }}u] = {{ tileT }}(b[(bk + {{ component }}u) * N + bn]);
|
|
|
|
| 90 |
}
|
|
|
|
| 91 |
{% endfor %}
|
|
|
|
| 92 |
}
|
|
|
|
| 93 |
tileB[bc][br4] = bWord;
|
| 94 |
}
|
| 95 |
workgroupBarrier();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
{% set regT = "f32" %}{% set regCast = 1 if tileT != "f32" else 0 %}
|
| 97 |
{% filter indent(8, true) %}
|
|
|
|
| 98 |
let aRow = lid.y * TM;
|
| 99 |
let bCol = lid.x * TN;
|
| 100 |
for (var kv: u32 = 0u; kv < BK / 4u; kv = kv + 1u) {
|
|
@@ -104,11 +137,21 @@ for (var kv: u32 = 0u; kv < BK / 4u; kv = kv + 1u) {
|
|
| 104 |
for (var j: u32 = 0u; j < TN; j = j + 1u) { bv[j] = {% if regCast %}vec4<{{ regT }}>(tileB[bCol + j][kv]){% else %}tileB[bCol + j][kv]{% endif %}; }
|
| 105 |
for (var i: u32 = 0u; i < TM; i = i + 1u) {
|
| 106 |
for (var j: u32 = 0u; j < TN; j = j + 1u) {
|
| 107 |
-
|
| 108 |
}
|
| 109 |
}
|
| 110 |
}
|
| 111 |
{% endfilter %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
workgroupBarrier();
|
| 113 |
}
|
| 114 |
|
|
|
|
| 1 |
+
{% set OUT = "f16" if (usesF16 is defined and usesF16) else "f32" %}
|
|
|
|
| 2 |
{{ env.wgsl.resourceDeclarations }}
|
| 3 |
|
| 4 |
// Shape-driven, register-blocked f32 GEMM for all four transpose combinations.
|
| 5 |
+
// Runtime M/N/K share one compiled pipeline for each tile configuration.
|
| 6 |
+
// Register micro-tiles reuse staged K slices; transpose modes change load strides and
|
| 7 |
+
// keep the stored-contiguous axis coalesced. M/N/K tails are bounds-checked
|
| 8 |
+
// unless an authored dimension proves that its tile has no tail.
|
| 9 |
// Both tiles are indexed by their own output axis and group four K values per
|
| 10 |
// vector word, so the micro-tile accumulates through dot() and one step reads
|
| 11 |
// TM + TN words instead of 4 * (TM + TN) scalars.
|
|
|
|
| 12 |
fn tanh_safe(x: f32) -> f32 {
|
| 13 |
+
// tanh rounds to its saturated value for these tails in f32. Return that
|
| 14 |
+
// value directly, including for infinite input, before invoking the builtin.
|
| 15 |
if (x > 10.0) { return 1.0; }
|
| 16 |
if (x < -10.0) { return -1.0; }
|
| 17 |
+
// For tiny |x|, return x directly to preserve its sign and magnitude without
|
| 18 |
+
// relying on backend-specific builtin behavior near zero.
|
| 19 |
+
if (x > -1.0e-4 && x < 1.0e-4) { return x; }
|
| 20 |
return tanh(x);
|
| 21 |
}
|
| 22 |
|
| 23 |
fn gelu_tanh(v: f32) -> f32 {
|
| 24 |
return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
|
| 25 |
}
|
| 26 |
+
{% set epiOpen = "gelu_tanh(" %}
|
| 27 |
+
{% set epiClose = ")" %}
|
| 28 |
+
{% set gemmWgX = ((gemmTileCols / gemmMicroCols) | int) %}
|
| 29 |
+
{% set gemmWgY = ((gemmTileRows / gemmMicroRows) | int) %}
|
| 30 |
+
{% set gemmRowTail = gemmStaticM is not defined or gemmStaticM % gemmTileRows != 0 %}
|
| 31 |
+
{% set gemmColTail = gemmStaticN is not defined or gemmStaticN % gemmTileCols != 0 %}
|
| 32 |
+
{% set gemmKTileTail = gemmStaticK is not defined or gemmStaticK % gemmTileK != 0 %}
|
| 33 |
+
const BK: u32 = {{ gemmTileK }}u;
|
| 34 |
+
const BM: u32 = {{ gemmTileRows }}u;
|
| 35 |
+
const BN: u32 = {{ gemmTileCols }}u;
|
| 36 |
+
const TM: u32 = {{ gemmMicroRows }}u; // per-thread micro-tile rows
|
| 37 |
+
const TN: u32 = {{ gemmMicroCols }}u; // per-thread micro-tile cols
|
| 38 |
|
| 39 |
// Stage tiles at the operands' storage width. For f16 inputs this is
|
| 40 |
// bit-identical to widening on shared load, keeps f32 FMA registers, and halves
|
| 41 |
// workgroup storage.
|
| 42 |
{% set tileT = OUT %}
|
| 43 |
const K_VECS: u32 = BK / 4u;
|
| 44 |
+
var<workgroup> tileA: array<array<vec4<{{ tileT }}>, K_VECS{% if gemmTilePadding > 0 %} + {{ gemmTilePadding }}u{% endif %}>, BM>; // logical A'[m][k/4]
|
| 45 |
+
var<workgroup> tileB: array<array<vec4<{{ tileT }}>, K_VECS{% if gemmTilePadding > 0 %} + {{ gemmTilePadding }}u{% endif %}>, BN>; // logical B'[n][k/4]
|
| 46 |
|
| 47 |
+
@compute @workgroup_size({{ gemmWgX }}, {{ gemmWgY }}, 1)
|
| 48 |
fn main(
|
| 49 |
@builtin(workgroup_id) wg: vec3<u32>,
|
| 50 |
@builtin(local_invocation_id) lid: vec3<u32>,
|
| 51 |
@builtin(num_workgroups) nwg: vec3<u32>
|
| 52 |
) {
|
| 53 |
+
let li = lid.y * {{ gemmWgX }}u + lid.x;
|
| 54 |
let M = params.M;
|
| 55 |
let N = params.N;
|
| 56 |
let K = params.K;
|
|
|
|
| 64 |
var acc: array<f32, TM * TN>;
|
| 65 |
for (var i: u32 = 0u; i < TM * TN; i = i + 1u) { acc[i] = 0.0; }
|
| 66 |
|
| 67 |
+
{% if gemmCompensatedTiles %}
|
| 68 |
+
var accError: array<f32, TM * TN>;
|
| 69 |
+
{% endif %}
|
| 70 |
let numTiles = (K + BK - 1u) / BK;
|
| 71 |
for (var kt: u32 = 0u; kt < numTiles; kt = kt + 1u) {
|
| 72 |
let kBase = kt * BK;
|
| 73 |
// Cooperative load: one vector word per lane per pass. The lane grid is
|
| 74 |
// laid out so the axis the operand stores contiguously stays coalesced.
|
| 75 |
+
for (var idx: u32 = li; idx < BM * K_VECS; idx = idx + {{ gemmWgX * gemmWgY }}u) {
|
| 76 |
// A stored [M, K]: logical A[m,k] = a[m*K + k]. Coalesce on k (contiguous).
|
| 77 |
let ar = idx / K_VECS;
|
| 78 |
let ac4 = idx % K_VECS;
|
| 79 |
let am = mBase + ar;
|
| 80 |
let ak = kBase + ac4 * 4u;
|
| 81 |
var aWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 82 |
+
{% if gemmRowTail %}
|
| 83 |
if (am < M) {
|
| 84 |
+
{% endif %}
|
| 85 |
{% for component in range(4) %}
|
| 86 |
+
{% if gemmKTileTail %}
|
| 87 |
if (ak + {{ component }}u < K) {
|
| 88 |
+
{% endif %}
|
| 89 |
aWord[{{ component }}u] = {{ tileT }}(a[am * K + ak + {{ component }}u]);
|
| 90 |
+
{% if gemmKTileTail %}
|
| 91 |
}
|
| 92 |
+
{% endif %}
|
| 93 |
{% endfor %}
|
| 94 |
+
{% if gemmRowTail %}
|
| 95 |
}
|
| 96 |
+
{% endif %}
|
| 97 |
tileA[ar][ac4] = aWord;
|
| 98 |
}
|
| 99 |
+
for (var idx: u32 = li; idx < BN * K_VECS; idx = idx + {{ gemmWgX * gemmWgY }}u) {
|
| 100 |
// B stored [K, N]: logical B[k,n] = b[k*N + n]. Coalesce on n (contiguous).
|
| 101 |
let bc = idx % BN;
|
| 102 |
let br4 = idx / BN;
|
| 103 |
let bn = nBase + bc;
|
| 104 |
let bk = kBase + br4 * 4u;
|
| 105 |
var bWord = vec4<{{ tileT }}>({{ tileT }}(0.0));
|
| 106 |
+
{% if gemmColTail %}
|
| 107 |
if (bn < N) {
|
| 108 |
+
{% endif %}
|
| 109 |
{% for component in range(4) %}
|
| 110 |
+
{% if gemmKTileTail %}
|
| 111 |
if (bk + {{ component }}u < K) {
|
| 112 |
+
{% endif %}
|
| 113 |
bWord[{{ component }}u] = {{ tileT }}(b[(bk + {{ component }}u) * N + bn]);
|
| 114 |
+
{% if gemmKTileTail %}
|
| 115 |
}
|
| 116 |
+
{% endif %}
|
| 117 |
{% endfor %}
|
| 118 |
+
{% if gemmColTail %}
|
| 119 |
}
|
| 120 |
+
{% endif %}
|
| 121 |
tileB[bc][br4] = bWord;
|
| 122 |
}
|
| 123 |
workgroupBarrier();
|
| 124 |
+
{% if gemmCompensatedTiles %}
|
| 125 |
+
var tileAcc: array<f32, TM * TN>;
|
| 126 |
+
{% endif %}
|
| 127 |
+
{% set regAccumulator = "tileAcc" if gemmCompensatedTiles else "acc" %}
|
| 128 |
{% set regT = "f32" %}{% set regCast = 1 if tileT != "f32" else 0 %}
|
| 129 |
{% filter indent(8, true) %}
|
| 130 |
+
{% set regAccumulator = regAccumulator | default("acc") %}
|
| 131 |
let aRow = lid.y * TM;
|
| 132 |
let bCol = lid.x * TN;
|
| 133 |
for (var kv: u32 = 0u; kv < BK / 4u; kv = kv + 1u) {
|
|
|
|
| 137 |
for (var j: u32 = 0u; j < TN; j = j + 1u) { bv[j] = {% if regCast %}vec4<{{ regT }}>(tileB[bCol + j][kv]){% else %}tileB[bCol + j][kv]{% endif %}; }
|
| 138 |
for (var i: u32 = 0u; i < TM; i = i + 1u) {
|
| 139 |
for (var j: u32 = 0u; j < TN; j = j + 1u) {
|
| 140 |
+
{{ regAccumulator }}[i * TN + j] = {{ regAccumulator }}[i * TN + j] + dot(av[i], bv[j]);
|
| 141 |
}
|
| 142 |
}
|
| 143 |
}
|
| 144 |
{% endfilter %}
|
| 145 |
+
{% if gemmCompensatedTiles %}
|
| 146 |
+
for (var i: u32 = 0u; i < TM * TN; i = i + 1u) {
|
| 147 |
+
// Explicit fma preserves the rounded differences in this correction.
|
| 148 |
+
// Plain subtraction can be reassociated away by fast-math backends.
|
| 149 |
+
let corrected = fma(-1.0, accError[i], tileAcc[i]);
|
| 150 |
+
let next = acc[i] + corrected;
|
| 151 |
+
accError[i] = select(0.0, fma(-1.0, corrected, fma(-1.0, acc[i], next)), abs(next) <= 3.4028234663852886e38);
|
| 152 |
+
acc[i] = next;
|
| 153 |
+
}
|
| 154 |
+
{% endif %}
|
| 155 |
workgroupBarrier();
|
| 156 |
}
|
| 157 |
|
build/webgpu/gemm-subgroup-matrix.wgsl.jinja
CHANGED
|
@@ -5,7 +5,6 @@ enable subgroup_size_control;
|
|
| 5 |
enable chromium_experimental_subgroup_matrix;
|
| 6 |
diagnostic(off, chromium.subgroup_matrix_uniformity);
|
| 7 |
|
| 8 |
-
|
| 9 |
{{ env.wgsl.resourceDeclarations }}
|
| 10 |
|
| 11 |
{% set operandScalar = mmaScalar %}
|
|
@@ -14,18 +13,15 @@ diagnostic(off, chromium.subgroup_matrix_uniformity);
|
|
| 14 |
{% set OUT_SCALAR = outScalar if outScalar is defined else yScalar %}
|
| 15 |
{% set tileMValue = tileM if tileM is defined else 32 %}
|
| 16 |
{% set tileNValue = tileN if tileN is defined else 64 %}
|
| 17 |
-
{% set tileKValue =
|
| 18 |
-
{% set
|
| 19 |
-
{% set
|
| 20 |
-
{% set
|
| 21 |
-
{% set useDirectStore = directStore is defined and directStore and gemmEpi == "none" %}
|
| 22 |
{% set useDirectAStorage = directAStorage is defined and directAStorage %}
|
| 23 |
{% set useDoubleBufferedB = doubleBufferedB is defined and doubleBufferedB %}
|
| 24 |
{% set useBalancedAccumulation = balancedMatrixAccumulation is defined and balancedMatrixAccumulation and useDoubleBufferedB and not useDirectStore and operandScalar == "f32" %}
|
| 25 |
-
{% set
|
| 26 |
-
{% set
|
| 27 |
-
{% set columnTileBaseValue = columnTileBase if columnTileBase is defined else 0 %}
|
| 28 |
-
{% set rowTileBaseValue = rowTileBase if rowTileBase is defined else 0 %}
|
| 29 |
// Four subgroups cover 32xN as a 2x2 grid, or taller tiles as four row bands.
|
| 30 |
{% if tileMValue > 32 %}
|
| 31 |
{% set subtileCols = tileNValue %}
|
|
@@ -38,7 +34,6 @@ diagnostic(off, chromium.subgroup_matrix_uniformity);
|
|
| 38 |
{% set bTilesPerSubgroup = (subtileCols / 8)|int %}
|
| 39 |
{% set subgroupCount = 4 %}
|
| 40 |
{% set scratchBanks = subgroupCount * aTilesPerSubgroup * bTilesPerSubgroup %}
|
| 41 |
-
|
| 42 |
{% macro matrixAccumulators() %}
|
| 43 |
{% for m in range(aTilesPerSubgroup) %}
|
| 44 |
{% for n in range(bTilesPerSubgroup) %}
|
|
@@ -50,9 +45,7 @@ diagnostic(off, chromium.subgroup_matrix_uniformity);
|
|
| 50 |
{% endif %}
|
| 51 |
{% endfor %}
|
| 52 |
{% endfor %}
|
| 53 |
-
|
| 54 |
{% endmacro %}
|
| 55 |
-
|
| 56 |
{% macro storeMatrixAccumulators() %}
|
| 57 |
{% for m in range(aTilesPerSubgroup) %}
|
| 58 |
{% for n in range(bTilesPerSubgroup) %}
|
|
@@ -65,8 +58,13 @@ diagnostic(off, chromium.subgroup_matrix_uniformity);
|
|
| 65 |
{% endmacro %}
|
| 66 |
|
| 67 |
fn tanh_safe(x: f32) -> f32 {
|
|
|
|
|
|
|
| 68 |
if (x > 10.0) { return 1.0; }
|
| 69 |
if (x < -10.0) { return -1.0; }
|
|
|
|
|
|
|
|
|
|
| 70 |
return tanh(x);
|
| 71 |
}
|
| 72 |
|
|
@@ -75,7 +73,7 @@ fn gelu_tanh(v: f32) -> f32 {
|
|
| 75 |
}
|
| 76 |
const IN_F: u32 = {{ inFeatures }}u;
|
| 77 |
const OUT_F: u32 = {{ outFeatures }}u;
|
| 78 |
-
{% set kLoopEndValue =
|
| 79 |
const TILE_COLS: u32 = {{ tileNValue }}u;
|
| 80 |
const TILE_ROWS: u32 = {{ tileMValue }}u;
|
| 81 |
const TILE_K: u32 = {{ tileKValue }}u;
|
|
@@ -191,40 +189,28 @@ fn main(
|
|
| 191 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 192 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 193 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
| 194 |
-
{% set aTransposed = aTransposedStorage if aTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 195 |
-
{% set bTransposed = bTransposedStorage if bTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 196 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 197 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 198 |
{% if directA %}
|
|
|
|
|
|
|
| 199 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 200 |
// loads need no guarded workgroup staging.
|
| 201 |
-
let matrix_a_offset = (a_global_base + base_A) *
|
| 202 |
-
{% elif aTransposed %}
|
| 203 |
-
let matrix_a_offset = {{ matrixStep }} * TILE_ROWS + subtile_idy * SUB_ROWS;
|
| 204 |
{% else %}
|
| 205 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 206 |
{% endif %}
|
| 207 |
{% for m in range(dynamicATiles) %}
|
| 208 |
{% if directA %}
|
| 209 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&
|
| 210 |
-
{% elif aTransposed %}
|
| 211 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, col_major>(&tile_A, matrix_a_offset + {{ m * 8 }}u, TILE_ROWS);
|
| 212 |
{% else %}
|
| 213 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 214 |
{% endif %}
|
| 215 |
{% endfor %}
|
| 216 |
|
| 217 |
-
{% if bTransposed %}
|
| 218 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
| 219 |
-
{% else %}
|
| 220 |
-
let matrix_b_offset = {{ B_BANK }}subtile_idx * SUB_COLS * TILE_K + {{ matrixStep }};
|
| 221 |
-
{% endif %}
|
| 222 |
{% for n in range(bTilesPerSubgroup) %}
|
| 223 |
-
{% if bTransposed %}
|
| 224 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
| 225 |
-
{% else %}
|
| 226 |
-
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u * TILE_K, TILE_K);
|
| 227 |
-
{% endif %}
|
| 228 |
{% endfor %}
|
| 229 |
|
| 230 |
{% for m in range(dynamicATiles) %}
|
|
@@ -232,7 +218,6 @@ fn main(
|
|
| 232 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 233 |
{% endfor %}
|
| 234 |
{% endfor %}
|
| 235 |
-
|
| 236 |
}
|
| 237 |
{% endfor %}
|
| 238 |
{% else %}
|
|
@@ -240,40 +225,28 @@ fn main(
|
|
| 240 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 241 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 242 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
| 243 |
-
{% set aTransposed = aTransposedStorage if aTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 244 |
-
{% set bTransposed = bTransposedStorage if bTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 245 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 246 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 247 |
{% if directA %}
|
|
|
|
|
|
|
| 248 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 249 |
// loads need no guarded workgroup staging.
|
| 250 |
-
let matrix_a_offset = (a_global_base + base_A) *
|
| 251 |
-
{% elif aTransposed %}
|
| 252 |
-
let matrix_a_offset = {{ matrixStep }} * TILE_ROWS + subtile_idy * SUB_ROWS;
|
| 253 |
{% else %}
|
| 254 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 255 |
{% endif %}
|
| 256 |
{% for m in range(dynamicATiles) %}
|
| 257 |
{% if directA %}
|
| 258 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&
|
| 259 |
-
{% elif aTransposed %}
|
| 260 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, col_major>(&tile_A, matrix_a_offset + {{ m * 8 }}u, TILE_ROWS);
|
| 261 |
{% else %}
|
| 262 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 263 |
{% endif %}
|
| 264 |
{% endfor %}
|
| 265 |
|
| 266 |
-
{% if bTransposed %}
|
| 267 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
| 268 |
-
{% else %}
|
| 269 |
-
let matrix_b_offset = {{ B_BANK }}subtile_idx * SUB_COLS * TILE_K + {{ matrixStep }};
|
| 270 |
-
{% endif %}
|
| 271 |
{% for n in range(bTilesPerSubgroup) %}
|
| 272 |
-
{% if bTransposed %}
|
| 273 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
| 274 |
-
{% else %}
|
| 275 |
-
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u * TILE_K, TILE_K);
|
| 276 |
-
{% endif %}
|
| 277 |
{% endfor %}
|
| 278 |
|
| 279 |
{% for m in range(dynamicATiles) %}
|
|
@@ -281,7 +254,6 @@ fn main(
|
|
| 281 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 282 |
{% endfor %}
|
| 283 |
{% endfor %}
|
| 284 |
-
|
| 285 |
{% endif %}
|
| 286 |
}
|
| 287 |
let next_kidx = kidx + TILE_K;
|
|
@@ -305,40 +277,28 @@ fn main(
|
|
| 305 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 306 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 307 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
| 308 |
-
{% set aTransposed = aTransposedStorage if aTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 309 |
-
{% set bTransposed = bTransposedStorage if bTransposedStorage is defined else (matrixInputsTransposed is defined and matrixInputsTransposed) %}
|
| 310 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 311 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 312 |
{% if directA %}
|
|
|
|
|
|
|
| 313 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 314 |
// loads need no guarded workgroup staging.
|
| 315 |
-
let matrix_a_offset = (a_global_base + base_A) *
|
| 316 |
-
{% elif aTransposed %}
|
| 317 |
-
let matrix_a_offset = {{ matrixStep }} * TILE_ROWS + subtile_idy * SUB_ROWS;
|
| 318 |
{% else %}
|
| 319 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 320 |
{% endif %}
|
| 321 |
{% for m in range(dynamicATiles) %}
|
| 322 |
{% if directA %}
|
| 323 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&
|
| 324 |
-
{% elif aTransposed %}
|
| 325 |
-
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, col_major>(&tile_A, matrix_a_offset + {{ m * 8 }}u, TILE_ROWS);
|
| 326 |
{% else %}
|
| 327 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 328 |
{% endif %}
|
| 329 |
{% endfor %}
|
| 330 |
|
| 331 |
-
{% if bTransposed %}
|
| 332 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
| 333 |
-
{% else %}
|
| 334 |
-
let matrix_b_offset = {{ B_BANK }}subtile_idx * SUB_COLS * TILE_K + {{ matrixStep }};
|
| 335 |
-
{% endif %}
|
| 336 |
{% for n in range(bTilesPerSubgroup) %}
|
| 337 |
-
{% if bTransposed %}
|
| 338 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
| 339 |
-
{% else %}
|
| 340 |
-
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, col_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u * TILE_K, TILE_K);
|
| 341 |
-
{% endif %}
|
| 342 |
{% endfor %}
|
| 343 |
|
| 344 |
{% for m in range(dynamicATiles) %}
|
|
@@ -346,7 +306,6 @@ fn main(
|
|
| 346 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 347 |
{% endfor %}
|
| 348 |
{% endfor %}
|
| 349 |
-
|
| 350 |
}
|
| 351 |
workgroupBarrier();
|
| 352 |
}
|
|
|
|
| 5 |
enable chromium_experimental_subgroup_matrix;
|
| 6 |
diagnostic(off, chromium.subgroup_matrix_uniformity);
|
| 7 |
|
|
|
|
| 8 |
{{ env.wgsl.resourceDeclarations }}
|
| 9 |
|
| 10 |
{% set operandScalar = mmaScalar %}
|
|
|
|
| 13 |
{% set OUT_SCALAR = outScalar if outScalar is defined else yScalar %}
|
| 14 |
{% set tileMValue = tileM if tileM is defined else 32 %}
|
| 15 |
{% set tileNValue = tileN if tileN is defined else 64 %}
|
| 16 |
+
{% set tileKValue = 32 %}
|
| 17 |
+
{% set epiOpen = "gelu_tanh(" %}
|
| 18 |
+
{% set epiClose = ")" %}
|
| 19 |
+
{% set useDirectStore = false %}
|
|
|
|
| 20 |
{% set useDirectAStorage = directAStorage is defined and directAStorage %}
|
| 21 |
{% set useDoubleBufferedB = doubleBufferedB is defined and doubleBufferedB %}
|
| 22 |
{% set useBalancedAccumulation = balancedMatrixAccumulation is defined and balancedMatrixAccumulation and useDoubleBufferedB and not useDirectStore and operandScalar == "f32" %}
|
| 23 |
+
{% set columnTileBaseValue = 0 %}
|
| 24 |
+
{% set rowTileBaseValue = 0 %}
|
|
|
|
|
|
|
| 25 |
// Four subgroups cover 32xN as a 2x2 grid, or taller tiles as four row bands.
|
| 26 |
{% if tileMValue > 32 %}
|
| 27 |
{% set subtileCols = tileNValue %}
|
|
|
|
| 34 |
{% set bTilesPerSubgroup = (subtileCols / 8)|int %}
|
| 35 |
{% set subgroupCount = 4 %}
|
| 36 |
{% set scratchBanks = subgroupCount * aTilesPerSubgroup * bTilesPerSubgroup %}
|
|
|
|
| 37 |
{% macro matrixAccumulators() %}
|
| 38 |
{% for m in range(aTilesPerSubgroup) %}
|
| 39 |
{% for n in range(bTilesPerSubgroup) %}
|
|
|
|
| 45 |
{% endif %}
|
| 46 |
{% endfor %}
|
| 47 |
{% endfor %}
|
|
|
|
| 48 |
{% endmacro %}
|
|
|
|
| 49 |
{% macro storeMatrixAccumulators() %}
|
| 50 |
{% for m in range(aTilesPerSubgroup) %}
|
| 51 |
{% for n in range(bTilesPerSubgroup) %}
|
|
|
|
| 58 |
{% endmacro %}
|
| 59 |
|
| 60 |
fn tanh_safe(x: f32) -> f32 {
|
| 61 |
+
// tanh rounds to its saturated value for these tails in f32. Return that
|
| 62 |
+
// value directly, including for infinite input, before invoking the builtin.
|
| 63 |
if (x > 10.0) { return 1.0; }
|
| 64 |
if (x < -10.0) { return -1.0; }
|
| 65 |
+
// For tiny |x|, return x directly to preserve its sign and magnitude without
|
| 66 |
+
// relying on backend-specific builtin behavior near zero.
|
| 67 |
+
if (x > -1.0e-4 && x < 1.0e-4) { return x; }
|
| 68 |
return tanh(x);
|
| 69 |
}
|
| 70 |
|
|
|
|
| 73 |
}
|
| 74 |
const IN_F: u32 = {{ inFeatures }}u;
|
| 75 |
const OUT_F: u32 = {{ outFeatures }}u;
|
| 76 |
+
{% set kLoopEndValue = "IN_F" %}
|
| 77 |
const TILE_COLS: u32 = {{ tileNValue }}u;
|
| 78 |
const TILE_ROWS: u32 = {{ tileMValue }}u;
|
| 79 |
const TILE_K: u32 = {{ tileKValue }}u;
|
|
|
|
| 189 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 190 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 191 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
|
|
|
|
|
|
| 192 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 193 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 194 |
{% if directA %}
|
| 195 |
+
{% set matrixAStorage = matrixAStorage | default("x") %}
|
| 196 |
+
{% set matrixAStride = matrixAStride | default("IN_F") %}
|
| 197 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 198 |
// loads need no guarded workgroup staging.
|
| 199 |
+
let matrix_a_offset = (a_global_base + base_A) * {{ matrixAStride }} + kidx + {{ matrixStep }};
|
|
|
|
|
|
|
| 200 |
{% else %}
|
| 201 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 202 |
{% endif %}
|
| 203 |
{% for m in range(dynamicATiles) %}
|
| 204 |
{% if directA %}
|
| 205 |
+
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&{{ matrixAStorage }}, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * {{ matrixAStride }}{% endif %}, {{ matrixAStride }});
|
|
|
|
|
|
|
| 206 |
{% else %}
|
| 207 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 208 |
{% endif %}
|
| 209 |
{% endfor %}
|
| 210 |
|
|
|
|
| 211 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
|
|
|
|
|
|
|
|
|
| 212 |
{% for n in range(bTilesPerSubgroup) %}
|
|
|
|
| 213 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
|
|
|
|
|
|
|
|
|
| 214 |
{% endfor %}
|
| 215 |
|
| 216 |
{% for m in range(dynamicATiles) %}
|
|
|
|
| 218 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 219 |
{% endfor %}
|
| 220 |
{% endfor %}
|
|
|
|
| 221 |
}
|
| 222 |
{% endfor %}
|
| 223 |
{% else %}
|
|
|
|
| 225 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 226 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 227 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
|
|
|
|
|
|
| 228 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 229 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 230 |
{% if directA %}
|
| 231 |
+
{% set matrixAStorage = matrixAStorage | default("x") %}
|
| 232 |
+
{% set matrixAStride = matrixAStride | default("IN_F") %}
|
| 233 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 234 |
// loads need no guarded workgroup staging.
|
| 235 |
+
let matrix_a_offset = (a_global_base + base_A) * {{ matrixAStride }} + kidx + {{ matrixStep }};
|
|
|
|
|
|
|
| 236 |
{% else %}
|
| 237 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 238 |
{% endif %}
|
| 239 |
{% for m in range(dynamicATiles) %}
|
| 240 |
{% if directA %}
|
| 241 |
+
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&{{ matrixAStorage }}, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * {{ matrixAStride }}{% endif %}, {{ matrixAStride }});
|
|
|
|
|
|
|
| 242 |
{% else %}
|
| 243 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 244 |
{% endif %}
|
| 245 |
{% endfor %}
|
| 246 |
|
|
|
|
| 247 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
|
|
|
|
|
|
|
|
|
| 248 |
{% for n in range(bTilesPerSubgroup) %}
|
|
|
|
| 249 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
|
|
|
|
|
|
|
|
|
| 250 |
{% endfor %}
|
| 251 |
|
| 252 |
{% for m in range(dynamicATiles) %}
|
|
|
|
| 254 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 255 |
{% endfor %}
|
| 256 |
{% endfor %}
|
|
|
|
| 257 |
{% endif %}
|
| 258 |
}
|
| 259 |
let next_kidx = kidx + TILE_K;
|
|
|
|
| 277 |
{% set matrixAccumulator = matrixAccumulator | default("matC") %}
|
| 278 |
{% set matrixStepOffset = matrixStepOffset | default(0) %}
|
| 279 |
{% set matrixStep = "step" if matrixStepOffset == 0 else "(step + " ~ matrixStepOffset ~ "u)" %}
|
|
|
|
|
|
|
| 280 |
{% set directA = directAStorage is defined and directAStorage %}
|
| 281 |
{% set B_BANK = "b_bank_offset + " if doubleBufferedB is defined and doubleBufferedB else "" %}
|
| 282 |
{% if directA %}
|
| 283 |
+
{% set matrixAStorage = matrixAStorage | default("x") %}
|
| 284 |
+
{% set matrixAStride = matrixAStride | default("IN_F") %}
|
| 285 |
// Direct storage guarantees a full aligned M/K tile, so subgroup-matrix
|
| 286 |
// loads need no guarded workgroup staging.
|
| 287 |
+
let matrix_a_offset = (a_global_base + base_A) * {{ matrixAStride }} + kidx + {{ matrixStep }};
|
|
|
|
|
|
|
| 288 |
{% else %}
|
| 289 |
let matrix_a_offset = subtile_idy * SUB_ROWS * TILE_K + {{ matrixStep }};
|
| 290 |
{% endif %}
|
| 291 |
{% for m in range(dynamicATiles) %}
|
| 292 |
{% if directA %}
|
| 293 |
+
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&{{ matrixAStorage }}, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * {{ matrixAStride }}{% endif %}, {{ matrixAStride }});
|
|
|
|
|
|
|
| 294 |
{% else %}
|
| 295 |
var matA{{ m }}: subgroup_matrix_left<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_left<{{ operandScalar }}, 8, 8>, row_major>(&tile_A, matrix_a_offset{% if m > 0 %} + {{ m * 8 }}u * TILE_K{% endif %}, TILE_K);
|
| 296 |
{% endif %}
|
| 297 |
{% endfor %}
|
| 298 |
|
|
|
|
| 299 |
let matrix_b_offset = {{ B_BANK }}{{ matrixStep }} * TILE_COLS + subtile_idx * SUB_COLS;
|
|
|
|
|
|
|
|
|
|
| 300 |
{% for n in range(bTilesPerSubgroup) %}
|
|
|
|
| 301 |
var matB{{ n }}: subgroup_matrix_right<{{ operandScalar }}, 8, 8> = subgroupMatrixLoad<subgroup_matrix_right<{{ operandScalar }}, 8, 8>, row_major>(&tile_B, matrix_b_offset + {{ n * 8 }}u, TILE_COLS);
|
|
|
|
|
|
|
|
|
|
| 302 |
{% endfor %}
|
| 303 |
|
| 304 |
{% for m in range(dynamicATiles) %}
|
|
|
|
| 306 |
{{ matrixAccumulator }}{{ m }}{{ n }} = subgroupMatrixMultiplyAccumulate(matA{{ m }}, matB{{ n }}, {{ matrixAccumulator }}{{ m }}{{ n }});
|
| 307 |
{% endfor %}
|
| 308 |
{% endfor %}
|
|
|
|
| 309 |
}
|
| 310 |
workgroupBarrier();
|
| 311 |
}
|
build/webgpu/manifest.json
CHANGED
|
@@ -10,13 +10,21 @@
|
|
| 10 |
"outputs": { "Y": { "dtype": "T", "rank": "ranks.X", "shape": "matmulShape(shapes.X, shapes.W)" } },
|
| 11 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 12 |
"derive": {
|
|
|
|
|
|
|
|
|
|
| 13 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 14 |
"wave32Adapter": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 32 and device.adapterInfo.subgroupMaxSize == 32",
|
| 15 |
"canPinSubgroupSize32": "device.features.has(\"subgroups\") and device.features.has(\"subgroup-size-control\") and has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize <= 32 and device.adapterInfo.subgroupMaxSize >= 32",
|
| 16 |
"pinSubgroupSize32": "canPinSubgroupSize32 and not wave32Adapter",
|
| 17 |
"wave32Effective": "wave32Adapter or pinSubgroupSize32",
|
| 18 |
-
"
|
| 19 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
"gfgRows": "numel(shapes.X) / kDim if kDim > 0 else 0",
|
| 21 |
"shapeOk": "ranks.W == 2 and ranks.X >= 2 and kDim > 0 and nDim > 0 and dim(shapes.X, ranks.X - 1) == kDim and ranks.Y == ranks.X and dim(shapes.Y, ranks.Y - 1) == nDim and numel(shapes.Y) == gfgRows * nDim",
|
| 22 |
"dtypeOk": "(tensorDtypes.X == \"float32\" or tensorDtypes.X == \"float16\") and tensorDtypes.W == tensorDtypes.X and tensorDtypes.Y == tensorDtypes.X and f16Ok(dtypes.T)",
|
|
@@ -30,24 +38,416 @@
|
|
| 30 |
"sgmatLayoutOk": "gfgRows > 0 and kDim % 32 == 0 and nDim % 64 == 0 and ((tensorDtypes.X == \"float16\" and device.features.has(\"shader-f16\") and gfgRows >= 2) or (tensorDtypes.X == \"float32\" and gfgRows >= 32)) and ceilDiv(gfgRows, 32) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, 64) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 31 |
"sgmatContract": "wave32Effective and sgmatLayoutOk and sgmatResourcesFit",
|
| 32 |
"usesF16": "tensorDtypes.X == \"float16\"",
|
| 33 |
-
"transA": false,
|
| 34 |
"transB": false,
|
| 35 |
-
"gemmEpilogue": "\"fastgelu\"",
|
| 36 |
"sgmatDirectRows": 64,
|
| 37 |
"sgmatDirectCols": 32,
|
| 38 |
"sgmatDirectStorageBytes": "2 * sgmatDirectCols * 32 * sgmatOperandBytes + sgmatDirectRows * sgmatDirectCols * 4",
|
| 39 |
-
"sgmatDirectContract": "wave32Effective and gfgRows > 0 and gfgRows % sgmatDirectRows == 0 and kDim % 32 == 0 and nDim % sgmatDirectCols == 0 and deviceWorkgroupCap >= 128 and sgmatDirectStorageBytes <= device.limits.maxComputeWorkgroupStorageSize and ceilDiv(gfgRows, sgmatDirectRows) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, sgmatDirectCols) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
},
|
| 41 |
"bindings": {
|
| 42 |
-
"x": { "arg": "X", "
|
| 43 |
-
"w": { "arg": "W", "
|
| 44 |
-
"y": { "arg": "Y", "
|
| 45 |
-
"params": { "
|
| 46 |
-
"a": { "arg": "X", "
|
| 47 |
-
"b": { "arg": "W", "
|
| 48 |
-
"
|
| 49 |
},
|
| 50 |
"variants": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
{
|
| 52 |
"id": "sgmat_direct_bias",
|
| 53 |
"priority": 110,
|
|
@@ -58,7 +458,6 @@
|
|
| 58 |
},
|
| 59 |
"derive": {
|
| 60 |
"hasBias": true,
|
| 61 |
-
"bTransposedStorage": true,
|
| 62 |
"xScalar": "\"f32\"",
|
| 63 |
"wScalar": "\"f32\"",
|
| 64 |
"bScalar": "\"f32\"",
|
|
@@ -68,7 +467,6 @@
|
|
| 68 |
"outFeatures": "nDim",
|
| 69 |
"tileM": "sgmatDirectRows",
|
| 70 |
"tileN": "sgmatDirectCols",
|
| 71 |
-
"tileK": 32,
|
| 72 |
"directAStorage": true,
|
| 73 |
"doubleBufferedB": true,
|
| 74 |
"balancedMatrixAccumulation": true
|
|
@@ -76,7 +474,7 @@
|
|
| 76 |
"passes": [
|
| 77 |
{
|
| 78 |
"id": "main",
|
| 79 |
-
"name": "GemmFastGelu.
|
| 80 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 81 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 82 |
"dispatch": {
|
|
@@ -85,7 +483,8 @@
|
|
| 85 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 86 |
}
|
| 87 |
}
|
| 88 |
-
]
|
|
|
|
| 89 |
},
|
| 90 |
{
|
| 91 |
"id": "sgmat_direct",
|
|
@@ -97,7 +496,6 @@
|
|
| 97 |
},
|
| 98 |
"derive": {
|
| 99 |
"hasBias": false,
|
| 100 |
-
"bTransposedStorage": true,
|
| 101 |
"xScalar": "\"f32\"",
|
| 102 |
"wScalar": "\"f32\"",
|
| 103 |
"bScalar": "\"f32\"",
|
|
@@ -107,7 +505,6 @@
|
|
| 107 |
"outFeatures": "nDim",
|
| 108 |
"tileM": "sgmatDirectRows",
|
| 109 |
"tileN": "sgmatDirectCols",
|
| 110 |
-
"tileK": 32,
|
| 111 |
"directAStorage": true,
|
| 112 |
"doubleBufferedB": true,
|
| 113 |
"balancedMatrixAccumulation": true
|
|
@@ -115,7 +512,7 @@
|
|
| 115 |
"passes": [
|
| 116 |
{
|
| 117 |
"id": "main",
|
| 118 |
-
"name": "GemmFastGelu.
|
| 119 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 120 |
"bindings": ["x", "w", "y", "params"],
|
| 121 |
"dispatch": {
|
|
@@ -124,7 +521,8 @@
|
|
| 124 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 125 |
}
|
| 126 |
}
|
| 127 |
-
]
|
|
|
|
| 128 |
},
|
| 129 |
{
|
| 130 |
"id": "sgmat_direct_bias_f16",
|
|
@@ -136,7 +534,6 @@
|
|
| 136 |
},
|
| 137 |
"derive": {
|
| 138 |
"hasBias": true,
|
| 139 |
-
"bTransposedStorage": true,
|
| 140 |
"xScalar": "\"f16\"",
|
| 141 |
"wScalar": "\"f16\"",
|
| 142 |
"bScalar": "\"f16\"",
|
|
@@ -146,7 +543,6 @@
|
|
| 146 |
"outFeatures": "nDim",
|
| 147 |
"tileM": "sgmatDirectRows",
|
| 148 |
"tileN": "sgmatDirectCols",
|
| 149 |
-
"tileK": 32,
|
| 150 |
"directAStorage": true,
|
| 151 |
"doubleBufferedB": true,
|
| 152 |
"balancedMatrixAccumulation": false
|
|
@@ -154,7 +550,7 @@
|
|
| 154 |
"passes": [
|
| 155 |
{
|
| 156 |
"id": "main",
|
| 157 |
-
"name": "GemmFastGelu.
|
| 158 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 159 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 160 |
"dispatch": {
|
|
@@ -163,7 +559,8 @@
|
|
| 163 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 164 |
}
|
| 165 |
}
|
| 166 |
-
]
|
|
|
|
| 167 |
},
|
| 168 |
{
|
| 169 |
"id": "sgmat_direct_f16",
|
|
@@ -175,7 +572,6 @@
|
|
| 175 |
},
|
| 176 |
"derive": {
|
| 177 |
"hasBias": false,
|
| 178 |
-
"bTransposedStorage": true,
|
| 179 |
"xScalar": "\"f16\"",
|
| 180 |
"wScalar": "\"f16\"",
|
| 181 |
"bScalar": "\"f16\"",
|
|
@@ -185,7 +581,6 @@
|
|
| 185 |
"outFeatures": "nDim",
|
| 186 |
"tileM": "sgmatDirectRows",
|
| 187 |
"tileN": "sgmatDirectCols",
|
| 188 |
-
"tileK": 32,
|
| 189 |
"directAStorage": true,
|
| 190 |
"doubleBufferedB": true,
|
| 191 |
"balancedMatrixAccumulation": false
|
|
@@ -193,7 +588,7 @@
|
|
| 193 |
"passes": [
|
| 194 |
{
|
| 195 |
"id": "main",
|
| 196 |
-
"name": "GemmFastGelu.
|
| 197 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 198 |
"bindings": ["x", "w", "y", "params"],
|
| 199 |
"dispatch": {
|
|
@@ -202,7 +597,8 @@
|
|
| 202 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 203 |
}
|
| 204 |
}
|
| 205 |
-
]
|
|
|
|
| 206 |
},
|
| 207 |
{
|
| 208 |
"id": "sgmat_bias",
|
|
@@ -214,7 +610,6 @@
|
|
| 214 |
},
|
| 215 |
"derive": {
|
| 216 |
"hasBias": true,
|
| 217 |
-
"bTransposedStorage": true,
|
| 218 |
"xScalar": "\"f32\"",
|
| 219 |
"wScalar": "\"f32\"",
|
| 220 |
"bScalar": "\"f32\"",
|
|
@@ -224,7 +619,6 @@
|
|
| 224 |
"outFeatures": "nDim",
|
| 225 |
"tileM": 32,
|
| 226 |
"tileN": 64,
|
| 227 |
-
"tileK": 32,
|
| 228 |
"directAStorage": false,
|
| 229 |
"doubleBufferedB": false,
|
| 230 |
"balancedMatrixAccumulation": false
|
|
@@ -232,7 +626,7 @@
|
|
| 232 |
"passes": [
|
| 233 |
{
|
| 234 |
"id": "main",
|
| 235 |
-
"name": "GemmFastGelu.
|
| 236 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 237 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 238 |
"dispatch": {
|
|
@@ -241,7 +635,8 @@
|
|
| 241 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 242 |
}
|
| 243 |
}
|
| 244 |
-
]
|
|
|
|
| 245 |
},
|
| 246 |
{
|
| 247 |
"id": "sgmat",
|
|
@@ -253,7 +648,6 @@
|
|
| 253 |
},
|
| 254 |
"derive": {
|
| 255 |
"hasBias": false,
|
| 256 |
-
"bTransposedStorage": true,
|
| 257 |
"xScalar": "\"f32\"",
|
| 258 |
"wScalar": "\"f32\"",
|
| 259 |
"bScalar": "\"f32\"",
|
|
@@ -263,7 +657,6 @@
|
|
| 263 |
"outFeatures": "nDim",
|
| 264 |
"tileM": 32,
|
| 265 |
"tileN": 64,
|
| 266 |
-
"tileK": 32,
|
| 267 |
"directAStorage": false,
|
| 268 |
"doubleBufferedB": false,
|
| 269 |
"balancedMatrixAccumulation": false
|
|
@@ -271,7 +664,7 @@
|
|
| 271 |
"passes": [
|
| 272 |
{
|
| 273 |
"id": "main",
|
| 274 |
-
"name": "GemmFastGelu.
|
| 275 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 276 |
"bindings": ["x", "w", "y", "params"],
|
| 277 |
"dispatch": {
|
|
@@ -280,7 +673,8 @@
|
|
| 280 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 281 |
}
|
| 282 |
}
|
| 283 |
-
]
|
|
|
|
| 284 |
},
|
| 285 |
{
|
| 286 |
"id": "sgmat_bias_f16",
|
|
@@ -292,7 +686,6 @@
|
|
| 292 |
},
|
| 293 |
"derive": {
|
| 294 |
"hasBias": true,
|
| 295 |
-
"bTransposedStorage": true,
|
| 296 |
"xScalar": "\"f16\"",
|
| 297 |
"wScalar": "\"f16\"",
|
| 298 |
"bScalar": "\"f16\"",
|
|
@@ -302,7 +695,6 @@
|
|
| 302 |
"outFeatures": "nDim",
|
| 303 |
"tileM": 32,
|
| 304 |
"tileN": 64,
|
| 305 |
-
"tileK": 32,
|
| 306 |
"directAStorage": false,
|
| 307 |
"doubleBufferedB": false,
|
| 308 |
"balancedMatrixAccumulation": false
|
|
@@ -310,7 +702,7 @@
|
|
| 310 |
"passes": [
|
| 311 |
{
|
| 312 |
"id": "main",
|
| 313 |
-
"name": "GemmFastGelu.
|
| 314 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 315 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 316 |
"dispatch": {
|
|
@@ -319,7 +711,8 @@
|
|
| 319 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 320 |
}
|
| 321 |
}
|
| 322 |
-
]
|
|
|
|
| 323 |
},
|
| 324 |
{
|
| 325 |
"id": "sgmat_f16",
|
|
@@ -331,7 +724,6 @@
|
|
| 331 |
},
|
| 332 |
"derive": {
|
| 333 |
"hasBias": false,
|
| 334 |
-
"bTransposedStorage": true,
|
| 335 |
"xScalar": "\"f16\"",
|
| 336 |
"wScalar": "\"f16\"",
|
| 337 |
"bScalar": "\"f16\"",
|
|
@@ -341,7 +733,6 @@
|
|
| 341 |
"outFeatures": "nDim",
|
| 342 |
"tileM": 32,
|
| 343 |
"tileN": 64,
|
| 344 |
-
"tileK": 32,
|
| 345 |
"directAStorage": false,
|
| 346 |
"doubleBufferedB": false,
|
| 347 |
"balancedMatrixAccumulation": false
|
|
@@ -349,7 +740,7 @@
|
|
| 349 |
"passes": [
|
| 350 |
{
|
| 351 |
"id": "main",
|
| 352 |
-
"name": "GemmFastGelu.
|
| 353 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 354 |
"bindings": ["x", "w", "y", "params"],
|
| 355 |
"dispatch": {
|
|
@@ -358,7 +749,8 @@
|
|
| 358 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 359 |
}
|
| 360 |
}
|
| 361 |
-
]
|
|
|
|
| 362 |
},
|
| 363 |
{
|
| 364 |
"id": "tiled_bias",
|
|
@@ -369,12 +761,12 @@
|
|
| 369 |
{
|
| 370 |
"id": "main",
|
| 371 |
"name": "GemmFastGelu.Bias",
|
| 372 |
-
"shader": "gemm-
|
| 373 |
"bindings": [
|
| 374 |
"a",
|
| 375 |
"b",
|
| 376 |
"bias",
|
| 377 |
-
"
|
| 378 |
{
|
| 379 |
"name": "params",
|
| 380 |
"struct": [
|
|
@@ -387,8 +779,8 @@
|
|
| 387 |
}
|
| 388 |
],
|
| 389 |
"dispatch": {
|
| 390 |
-
"x": "min(ceilDiv(nDim,
|
| 391 |
-
"y": "min(ceilDiv(gfgRows,
|
| 392 |
}
|
| 393 |
}
|
| 394 |
]
|
|
@@ -402,11 +794,11 @@
|
|
| 402 |
{
|
| 403 |
"id": "main",
|
| 404 |
"name": "GemmFastGelu",
|
| 405 |
-
"shader": "gemm-
|
| 406 |
"bindings": [
|
| 407 |
"a",
|
| 408 |
"b",
|
| 409 |
-
"
|
| 410 |
{
|
| 411 |
"name": "params",
|
| 412 |
"struct": [
|
|
@@ -418,11 +810,19 @@
|
|
| 418 |
}
|
| 419 |
],
|
| 420 |
"dispatch": {
|
| 421 |
-
"x": "min(ceilDiv(nDim,
|
| 422 |
-
"y": "min(ceilDiv(gfgRows,
|
| 423 |
}
|
| 424 |
}
|
| 425 |
]
|
| 426 |
}
|
| 427 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
}
|
|
|
|
| 10 |
"outputs": { "Y": { "dtype": "T", "rank": "ranks.X", "shape": "matmulShape(shapes.X, shapes.W)" } },
|
| 11 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 12 |
"derive": {
|
| 13 |
+
"kDim": "dim(shapes.W, 0)",
|
| 14 |
+
"nDim": "dim(shapes.W, 1)",
|
| 15 |
+
"gemvN": "nDim",
|
| 16 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
| 17 |
"wave32Adapter": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 32 and device.adapterInfo.subgroupMaxSize == 32",
|
| 18 |
"canPinSubgroupSize32": "device.features.has(\"subgroups\") and device.features.has(\"subgroup-size-control\") and has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize <= 32 and device.adapterInfo.subgroupMaxSize >= 32",
|
| 19 |
"pinSubgroupSize32": "canPinSubgroupSize32 and not wave32Adapter",
|
| 20 |
"wave32Effective": "wave32Adapter or pinSubgroupSize32",
|
| 21 |
+
"variableSubgroup16To32": "device.features.has(\"subgroups\") and has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 16 and device.adapterInfo.subgroupMaxSize == 32",
|
| 22 |
+
"gemvLanes": 32,
|
| 23 |
+
"vec4OutputTile": "4 * gemvLanes",
|
| 24 |
+
"gemvWorkgroups": "ceilDiv(gemvN, vec4OutputTile)",
|
| 25 |
+
"gemvSliceCap": "min(32, device.limits.maxComputeWorkgroupSizeY, floor(device.limits.maxComputeInvocationsPerWorkgroup / gemvLanes), floor(device.limits.maxComputeWorkgroupStorageSize / (16 * gemvLanes)))",
|
| 26 |
+
"gemvSlices": "max(1, min(gemvSliceCap, max(8, pow2ceil(ceilDiv(tunables.GEMV_TARGET_BLOCKS, gemvWorkgroups)))))",
|
| 27 |
+
"gemvResourcesFit": "gemvLanes <= device.limits.maxComputeWorkgroupSizeX and gemvSlices <= device.limits.maxComputeWorkgroupSizeY and gemvLanes * gemvSlices <= device.limits.maxComputeInvocationsPerWorkgroup and 16 * gemvLanes * gemvSlices <= device.limits.maxComputeWorkgroupStorageSize",
|
| 28 |
"gfgRows": "numel(shapes.X) / kDim if kDim > 0 else 0",
|
| 29 |
"shapeOk": "ranks.W == 2 and ranks.X >= 2 and kDim > 0 and nDim > 0 and dim(shapes.X, ranks.X - 1) == kDim and ranks.Y == ranks.X and dim(shapes.Y, ranks.Y - 1) == nDim and numel(shapes.Y) == gfgRows * nDim",
|
| 30 |
"dtypeOk": "(tensorDtypes.X == \"float32\" or tensorDtypes.X == \"float16\") and tensorDtypes.W == tensorDtypes.X and tensorDtypes.Y == tensorDtypes.X and f16Ok(dtypes.T)",
|
|
|
|
| 38 |
"sgmatLayoutOk": "gfgRows > 0 and kDim % 32 == 0 and nDim % 64 == 0 and ((tensorDtypes.X == \"float16\" and device.features.has(\"shader-f16\") and gfgRows >= 2) or (tensorDtypes.X == \"float32\" and gfgRows >= 32)) and ceilDiv(gfgRows, 32) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, 64) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 39 |
"sgmatContract": "wave32Effective and sgmatLayoutOk and sgmatResourcesFit",
|
| 40 |
"usesF16": "tensorDtypes.X == \"float16\"",
|
|
|
|
| 41 |
"transB": false,
|
|
|
|
| 42 |
"sgmatDirectRows": 64,
|
| 43 |
"sgmatDirectCols": 32,
|
| 44 |
"sgmatDirectStorageBytes": "2 * sgmatDirectCols * 32 * sgmatOperandBytes + sgmatDirectRows * sgmatDirectCols * 4",
|
| 45 |
+
"sgmatDirectContract": "wave32Effective and gfgRows > 0 and gfgRows % sgmatDirectRows == 0 and kDim % 32 == 0 and nDim % sgmatDirectCols == 0 and deviceWorkgroupCap >= 128 and sgmatDirectStorageBytes <= device.limits.maxComputeWorkgroupStorageSize and ceilDiv(gfgRows, sgmatDirectRows) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, sgmatDirectCols) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 46 |
+
"sgmatOutputGroups": "ceilDiv(gfgRows, sgmatDirectRows) * ceilDiv(nDim, sgmatDirectCols)",
|
| 47 |
+
"sgmatSmallRows": 32,
|
| 48 |
+
"sgmatSmallCols": 16,
|
| 49 |
+
"sgmatSmallStorageBytes": "2 * sgmatSmallCols * 32 * sgmatOperandBytes + sgmatSmallRows * sgmatSmallCols * 4",
|
| 50 |
+
"sgmatSmallContract": "wave32Effective and gfgRows > 0 and gfgRows % sgmatSmallRows == 0 and kDim % 32 == 0 and nDim % sgmatSmallCols == 0 and deviceWorkgroupCap >= 128 and sgmatSmallStorageBytes <= device.limits.maxComputeWorkgroupStorageSize and ceilDiv(gfgRows, sgmatSmallRows) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, sgmatSmallCols) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 51 |
+
"sgmatMediumRows": 32,
|
| 52 |
+
"sgmatMediumCols": 32,
|
| 53 |
+
"sgmatMediumStorageBytes": "2 * sgmatMediumCols * 32 * sgmatOperandBytes + sgmatMediumRows * sgmatMediumCols * 4",
|
| 54 |
+
"sgmatMediumContract": "wave32Effective and gfgRows > 0 and gfgRows % sgmatMediumRows == 0 and kDim % 32 == 0 and nDim % sgmatMediumCols == 0 and deviceWorkgroupCap >= 128 and sgmatMediumStorageBytes <= device.limits.maxComputeWorkgroupStorageSize and ceilDiv(gfgRows, sgmatMediumRows) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535) and ceilDiv(nDim, sgmatMediumCols) <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)",
|
| 55 |
+
"portableSmallGroups": "ceilDiv(gfgRows, 32) * ceilDiv(nDim, 32)",
|
| 56 |
+
"portableLargeGroups": "ceilDiv(gfgRows, 64) * ceilDiv(nDim, 64)",
|
| 57 |
+
"portableSmallBudget": "tunables.PORTABLE_SMALL_TILE_GROUPS_F16 if usesF16 else tunables.PORTABLE_SMALL_TILE_GROUPS_F32",
|
| 58 |
+
"portableAvoidsPadding": "portableLargeGroups * 3 >= portableSmallGroups",
|
| 59 |
+
"portableXe3LpgF32": "not usesF16 and has(device.adapterInfo, \"vendor\") and device.adapterInfo.vendor == \"intel\" and has(device.adapterInfo, \"architecture\") and device.adapterInfo.architecture == \"xe-3lpg\"",
|
| 60 |
+
"portableFixedWave32NoF16": "wave32Effective and not device.features.has(\"shader-f16\") and gfgRows >= device.adapterInfo.subgroupMaxSize and kDim >= 16 * device.adapterInfo.subgroupMaxSize and portableSmallGroups >= 8 * device.adapterInfo.subgroupMaxSize",
|
| 61 |
+
"portableLargeNoSubgroupGrid": "not usesF16 and not device.features.has(\"subgroups\") and portableSmallGroups >= 4 * deviceWorkgroupCap",
|
| 62 |
+
"gemmTileRows": "32 if portableXe3LpgF32 or portableFixedWave32NoF16 or portableLargeNoSubgroupGrid or portableSmallGroups <= portableSmallBudget * (2 if portableAvoidsPadding else 1) else 64",
|
| 63 |
+
"gemmTileCols": "gemmTileRows",
|
| 64 |
+
"gfgWideMicroPreferred": "(variableSubgroup16To32 or portableFixedWave32NoF16) and (8 if usesF16 else 4) * device.adapterInfo.subgroupMaxSize <= ceilDiv(gfgRows, gemmTileRows) * ceilDiv(nDim, gemmTileCols) and gemmTileRows * gemmTileCols / 8 <= deviceWorkgroupCap and gemmTileCols / 2 <= device.limits.maxComputeWorkgroupSizeX and gemmTileRows / 4 <= device.limits.maxComputeWorkgroupSizeY",
|
| 65 |
+
"gemmMicroRows": "4 if gfgWideMicroPreferred else gemmTileRows / 16",
|
| 66 |
+
"gemmMicroCols": "2 if gfgWideMicroPreferred else gemmTileCols / 16",
|
| 67 |
+
"gemmTileK": "(16 * 16 * 4) / gemmTileRows if usesF16 else (16 if portableLargeNoSubgroupGrid and has(device.adapterInfo, \"vendor\") and device.adapterInfo.vendor == \"intel\" else 32)",
|
| 68 |
+
"gemmTilePadding": "1 if not usesF16 and 2 * gemmTileRows * (gemmTileK + 4) * 4 <= device.limits.maxComputeWorkgroupStorageSize else 0",
|
| 69 |
+
"gemmCompensatedTiles": "not usesF16 and kDim > gemmTileK",
|
| 70 |
+
"gemmStaticM": "gfgRows",
|
| 71 |
+
"gemmStaticN": "nDim",
|
| 72 |
+
"gemmStaticK": "kDim"
|
| 73 |
},
|
| 74 |
"bindings": {
|
| 75 |
+
"x": { "arg": "X", "elementType": "$xScalar" },
|
| 76 |
+
"w": { "arg": "W", "elementType": "$wScalar" },
|
| 77 |
+
"y": { "arg": "Y", "elementType": "$yScalar" },
|
| 78 |
+
"params": { "struct": [{ "name": "M", "type": "u32", "value": "gfgRows" }] },
|
| 79 |
+
"a": { "arg": "X", "elementType": "$T" },
|
| 80 |
+
"b": { "arg": "W", "elementType": "$T" },
|
| 81 |
+
"y_t": { "arg": "Y", "name": "y", "elementType": "$T" }
|
| 82 |
},
|
| 83 |
"variants": [
|
| 84 |
+
{
|
| 85 |
+
"id": "vector_matrix_bias",
|
| 86 |
+
"priority": 130,
|
| 87 |
+
"when": ["biasContract", "gfgRows == 1", "nDim % 4 == 0", "gemvWorkgroups <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)", "gemvResourcesFit"],
|
| 88 |
+
"derive": {
|
| 89 |
+
"vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
|
| 90 |
+
"outputBuffer": "\"y\"",
|
| 91 |
+
"gemvBias": true,
|
| 92 |
+
"unrollK2": "usesF16"
|
| 93 |
+
},
|
| 94 |
+
"passes": [
|
| 95 |
+
{
|
| 96 |
+
"id": "main",
|
| 97 |
+
"name": "GemmFastGelu.VectorMatrixBias",
|
| 98 |
+
"shader": "matmul-vector-matrix-vec4.wgsl.jinja",
|
| 99 |
+
"bindings": [
|
| 100 |
+
"a",
|
| 101 |
+
{ "name": "b", "arg": "W", "elementType": "$vectorScalar" },
|
| 102 |
+
{ "arg": "bias", "elementType": "$vectorScalar" },
|
| 103 |
+
{ "name": "y", "arg": "Y", "elementType": "$vectorScalar" },
|
| 104 |
+
{
|
| 105 |
+
"name": "params",
|
| 106 |
+
"struct": [
|
| 107 |
+
{ "name": "K", "type": "u32", "value": "kDim" },
|
| 108 |
+
{ "name": "N4", "type": "u32", "value": "nDim / 4" }
|
| 109 |
+
]
|
| 110 |
+
}
|
| 111 |
+
],
|
| 112 |
+
"dispatch": { "x": "gemvWorkgroups" }
|
| 113 |
+
}
|
| 114 |
+
]
|
| 115 |
+
},
|
| 116 |
+
{
|
| 117 |
+
"id": "vector_matrix",
|
| 118 |
+
"priority": 130,
|
| 119 |
+
"when": ["noBiasContract", "gfgRows == 1", "nDim % 4 == 0", "gemvWorkgroups <= min(device.limits.maxComputeWorkgroupsPerDimension, 65535)", "gemvResourcesFit"],
|
| 120 |
+
"derive": {
|
| 121 |
+
"vectorScalar": "\"vec4<\" ~ dtypes.T ~ \">\"",
|
| 122 |
+
"outputBuffer": "\"y\"",
|
| 123 |
+
"gemvBias": false,
|
| 124 |
+
"unrollK2": "usesF16"
|
| 125 |
+
},
|
| 126 |
+
"passes": [
|
| 127 |
+
{
|
| 128 |
+
"id": "main",
|
| 129 |
+
"name": "GemmFastGelu.VectorMatrix",
|
| 130 |
+
"shader": "matmul-vector-matrix-vec4.wgsl.jinja",
|
| 131 |
+
"bindings": [
|
| 132 |
+
"a",
|
| 133 |
+
{ "name": "b", "arg": "W", "elementType": "$vectorScalar" },
|
| 134 |
+
{ "name": "y", "arg": "Y", "elementType": "$vectorScalar" },
|
| 135 |
+
{
|
| 136 |
+
"name": "params",
|
| 137 |
+
"struct": [
|
| 138 |
+
{ "name": "K", "type": "u32", "value": "kDim" },
|
| 139 |
+
{ "name": "N4", "type": "u32", "value": "nDim / 4" }
|
| 140 |
+
]
|
| 141 |
+
}
|
| 142 |
+
],
|
| 143 |
+
"dispatch": { "x": "gemvWorkgroups" }
|
| 144 |
+
}
|
| 145 |
+
]
|
| 146 |
+
},
|
| 147 |
+
{
|
| 148 |
+
"id": "sgmat_medium_bias",
|
| 149 |
+
"priority": 120,
|
| 150 |
+
"when": ["biasContract", "sgmatMediumContract", "tensorDtypes.X == \"float32\""],
|
| 151 |
+
"requires": {
|
| 152 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 153 |
+
"subgroupMatrixConfigs": [{ "componentType": "f32", "M": 8, "N": 8, "K": 8, "resultComponentType": "f32" }]
|
| 154 |
+
},
|
| 155 |
+
"derive": {
|
| 156 |
+
"hasBias": true,
|
| 157 |
+
"xScalar": "\"f32\"",
|
| 158 |
+
"wScalar": "\"f32\"",
|
| 159 |
+
"bScalar": "\"f32\"",
|
| 160 |
+
"yScalar": "\"f32\"",
|
| 161 |
+
"mmaScalar": "\"f32\"",
|
| 162 |
+
"inFeatures": "kDim",
|
| 163 |
+
"outFeatures": "nDim",
|
| 164 |
+
"tileM": "sgmatMediumRows",
|
| 165 |
+
"tileN": "sgmatMediumCols",
|
| 166 |
+
"directAStorage": true,
|
| 167 |
+
"doubleBufferedB": true,
|
| 168 |
+
"balancedMatrixAccumulation": true
|
| 169 |
+
},
|
| 170 |
+
"passes": [
|
| 171 |
+
{
|
| 172 |
+
"id": "main",
|
| 173 |
+
"name": "GemmFastGelu.SgmatMediumBias",
|
| 174 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 175 |
+
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 176 |
+
"dispatch": {
|
| 177 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 178 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 179 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
],
|
| 183 |
+
"demoteWhen": ["sgmatOutputGroups > (tunables.MEDIUM_MATRIX_MAX_GROUPS_F16 if usesF16 else tunables.MEDIUM_MATRIX_MAX_GROUPS_F32) and (sgmatDirectContract or sgmatContract)"]
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"id": "sgmat_medium",
|
| 187 |
+
"priority": 120,
|
| 188 |
+
"when": ["noBiasContract", "sgmatMediumContract", "tensorDtypes.X == \"float32\""],
|
| 189 |
+
"requires": {
|
| 190 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 191 |
+
"subgroupMatrixConfigs": [{ "componentType": "f32", "M": 8, "N": 8, "K": 8, "resultComponentType": "f32" }]
|
| 192 |
+
},
|
| 193 |
+
"derive": {
|
| 194 |
+
"hasBias": false,
|
| 195 |
+
"xScalar": "\"f32\"",
|
| 196 |
+
"wScalar": "\"f32\"",
|
| 197 |
+
"bScalar": "\"f32\"",
|
| 198 |
+
"yScalar": "\"f32\"",
|
| 199 |
+
"mmaScalar": "\"f32\"",
|
| 200 |
+
"inFeatures": "kDim",
|
| 201 |
+
"outFeatures": "nDim",
|
| 202 |
+
"tileM": "sgmatMediumRows",
|
| 203 |
+
"tileN": "sgmatMediumCols",
|
| 204 |
+
"directAStorage": true,
|
| 205 |
+
"doubleBufferedB": true,
|
| 206 |
+
"balancedMatrixAccumulation": true
|
| 207 |
+
},
|
| 208 |
+
"passes": [
|
| 209 |
+
{
|
| 210 |
+
"id": "main",
|
| 211 |
+
"name": "GemmFastGelu.SgmatMedium",
|
| 212 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 213 |
+
"bindings": ["x", "w", "y", "params"],
|
| 214 |
+
"dispatch": {
|
| 215 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 216 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 217 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
],
|
| 221 |
+
"demoteWhen": ["sgmatOutputGroups > (tunables.MEDIUM_MATRIX_MAX_GROUPS_F16 if usesF16 else tunables.MEDIUM_MATRIX_MAX_GROUPS_F32) and (sgmatDirectContract or sgmatContract)"]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"id": "sgmat_medium_bias_f16",
|
| 225 |
+
"priority": 120,
|
| 226 |
+
"when": ["biasContract", "sgmatMediumContract", "tensorDtypes.X == \"float16\""],
|
| 227 |
+
"requires": {
|
| 228 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 229 |
+
"subgroupMatrixConfigs": [{ "componentType": "f16", "M": 8, "N": 8, "K": 8 }]
|
| 230 |
+
},
|
| 231 |
+
"derive": {
|
| 232 |
+
"hasBias": true,
|
| 233 |
+
"xScalar": "\"f16\"",
|
| 234 |
+
"wScalar": "\"f16\"",
|
| 235 |
+
"bScalar": "\"f16\"",
|
| 236 |
+
"yScalar": "\"f16\"",
|
| 237 |
+
"mmaScalar": "\"f16\"",
|
| 238 |
+
"inFeatures": "kDim",
|
| 239 |
+
"outFeatures": "nDim",
|
| 240 |
+
"tileM": "sgmatMediumRows",
|
| 241 |
+
"tileN": "sgmatMediumCols",
|
| 242 |
+
"directAStorage": true,
|
| 243 |
+
"doubleBufferedB": true,
|
| 244 |
+
"balancedMatrixAccumulation": false
|
| 245 |
+
},
|
| 246 |
+
"passes": [
|
| 247 |
+
{
|
| 248 |
+
"id": "main",
|
| 249 |
+
"name": "GemmFastGelu.SgmatMediumBiasF16",
|
| 250 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 251 |
+
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 252 |
+
"dispatch": {
|
| 253 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 254 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 255 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 256 |
+
}
|
| 257 |
+
}
|
| 258 |
+
],
|
| 259 |
+
"demoteWhen": ["sgmatOutputGroups > (tunables.MEDIUM_MATRIX_MAX_GROUPS_F16 if usesF16 else tunables.MEDIUM_MATRIX_MAX_GROUPS_F32) and (sgmatDirectContract or sgmatContract)"]
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"id": "sgmat_medium_f16",
|
| 263 |
+
"priority": 120,
|
| 264 |
+
"when": ["noBiasContract", "sgmatMediumContract", "tensorDtypes.X == \"float16\""],
|
| 265 |
+
"requires": {
|
| 266 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 267 |
+
"subgroupMatrixConfigs": [{ "componentType": "f16", "M": 8, "N": 8, "K": 8 }]
|
| 268 |
+
},
|
| 269 |
+
"derive": {
|
| 270 |
+
"hasBias": false,
|
| 271 |
+
"xScalar": "\"f16\"",
|
| 272 |
+
"wScalar": "\"f16\"",
|
| 273 |
+
"bScalar": "\"f16\"",
|
| 274 |
+
"yScalar": "\"f16\"",
|
| 275 |
+
"mmaScalar": "\"f16\"",
|
| 276 |
+
"inFeatures": "kDim",
|
| 277 |
+
"outFeatures": "nDim",
|
| 278 |
+
"tileM": "sgmatMediumRows",
|
| 279 |
+
"tileN": "sgmatMediumCols",
|
| 280 |
+
"directAStorage": true,
|
| 281 |
+
"doubleBufferedB": true,
|
| 282 |
+
"balancedMatrixAccumulation": false
|
| 283 |
+
},
|
| 284 |
+
"passes": [
|
| 285 |
+
{
|
| 286 |
+
"id": "main",
|
| 287 |
+
"name": "GemmFastGelu.SgmatMediumF16",
|
| 288 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 289 |
+
"bindings": ["x", "w", "y", "params"],
|
| 290 |
+
"dispatch": {
|
| 291 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 292 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 293 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
],
|
| 297 |
+
"demoteWhen": ["sgmatOutputGroups > (tunables.MEDIUM_MATRIX_MAX_GROUPS_F16 if usesF16 else tunables.MEDIUM_MATRIX_MAX_GROUPS_F32) and (sgmatDirectContract or sgmatContract)"]
|
| 298 |
+
},
|
| 299 |
+
{
|
| 300 |
+
"id": "sgmat_small_bias",
|
| 301 |
+
"priority": 125,
|
| 302 |
+
"when": ["biasContract", "sgmatSmallContract", "tensorDtypes.X == \"float32\""],
|
| 303 |
+
"requires": {
|
| 304 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 305 |
+
"subgroupMatrixConfigs": [{ "componentType": "f32", "M": 8, "N": 8, "K": 8, "resultComponentType": "f32" }]
|
| 306 |
+
},
|
| 307 |
+
"derive": {
|
| 308 |
+
"hasBias": true,
|
| 309 |
+
"xScalar": "\"f32\"",
|
| 310 |
+
"wScalar": "\"f32\"",
|
| 311 |
+
"bScalar": "\"f32\"",
|
| 312 |
+
"yScalar": "\"f32\"",
|
| 313 |
+
"mmaScalar": "\"f32\"",
|
| 314 |
+
"inFeatures": "kDim",
|
| 315 |
+
"outFeatures": "nDim",
|
| 316 |
+
"tileM": "sgmatSmallRows",
|
| 317 |
+
"tileN": "sgmatSmallCols",
|
| 318 |
+
"directAStorage": true,
|
| 319 |
+
"doubleBufferedB": true,
|
| 320 |
+
"balancedMatrixAccumulation": true
|
| 321 |
+
},
|
| 322 |
+
"passes": [
|
| 323 |
+
{
|
| 324 |
+
"id": "main",
|
| 325 |
+
"name": "GemmFastGelu.SgmatSmallBias",
|
| 326 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 327 |
+
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 328 |
+
"dispatch": {
|
| 329 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 330 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 331 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
],
|
| 335 |
+
"demoteWhen": ["sgmatOutputGroups > tunables.SMALL_MATRIX_MAX_GROUPS and (sgmatMediumContract or sgmatDirectContract or sgmatContract)"]
|
| 336 |
+
},
|
| 337 |
+
{
|
| 338 |
+
"id": "sgmat_small",
|
| 339 |
+
"priority": 125,
|
| 340 |
+
"when": ["noBiasContract", "sgmatSmallContract", "tensorDtypes.X == \"float32\""],
|
| 341 |
+
"requires": {
|
| 342 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 343 |
+
"subgroupMatrixConfigs": [{ "componentType": "f32", "M": 8, "N": 8, "K": 8, "resultComponentType": "f32" }]
|
| 344 |
+
},
|
| 345 |
+
"derive": {
|
| 346 |
+
"hasBias": false,
|
| 347 |
+
"xScalar": "\"f32\"",
|
| 348 |
+
"wScalar": "\"f32\"",
|
| 349 |
+
"bScalar": "\"f32\"",
|
| 350 |
+
"yScalar": "\"f32\"",
|
| 351 |
+
"mmaScalar": "\"f32\"",
|
| 352 |
+
"inFeatures": "kDim",
|
| 353 |
+
"outFeatures": "nDim",
|
| 354 |
+
"tileM": "sgmatSmallRows",
|
| 355 |
+
"tileN": "sgmatSmallCols",
|
| 356 |
+
"directAStorage": true,
|
| 357 |
+
"doubleBufferedB": true,
|
| 358 |
+
"balancedMatrixAccumulation": true
|
| 359 |
+
},
|
| 360 |
+
"passes": [
|
| 361 |
+
{
|
| 362 |
+
"id": "main",
|
| 363 |
+
"name": "GemmFastGelu.SgmatSmall",
|
| 364 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 365 |
+
"bindings": ["x", "w", "y", "params"],
|
| 366 |
+
"dispatch": {
|
| 367 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 368 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 369 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 370 |
+
}
|
| 371 |
+
}
|
| 372 |
+
],
|
| 373 |
+
"demoteWhen": ["sgmatOutputGroups > tunables.SMALL_MATRIX_MAX_GROUPS and (sgmatMediumContract or sgmatDirectContract or sgmatContract)"]
|
| 374 |
+
},
|
| 375 |
+
{
|
| 376 |
+
"id": "sgmat_small_bias_f16",
|
| 377 |
+
"priority": 125,
|
| 378 |
+
"when": ["biasContract", "sgmatSmallContract", "tensorDtypes.X == \"float16\""],
|
| 379 |
+
"requires": {
|
| 380 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 381 |
+
"subgroupMatrixConfigs": [{ "componentType": "f16", "M": 8, "N": 8, "K": 8 }]
|
| 382 |
+
},
|
| 383 |
+
"derive": {
|
| 384 |
+
"hasBias": true,
|
| 385 |
+
"xScalar": "\"f16\"",
|
| 386 |
+
"wScalar": "\"f16\"",
|
| 387 |
+
"bScalar": "\"f16\"",
|
| 388 |
+
"yScalar": "\"f16\"",
|
| 389 |
+
"mmaScalar": "\"f16\"",
|
| 390 |
+
"inFeatures": "kDim",
|
| 391 |
+
"outFeatures": "nDim",
|
| 392 |
+
"tileM": "sgmatSmallRows",
|
| 393 |
+
"tileN": "sgmatSmallCols",
|
| 394 |
+
"directAStorage": true,
|
| 395 |
+
"doubleBufferedB": true,
|
| 396 |
+
"balancedMatrixAccumulation": false
|
| 397 |
+
},
|
| 398 |
+
"passes": [
|
| 399 |
+
{
|
| 400 |
+
"id": "main",
|
| 401 |
+
"name": "GemmFastGelu.SgmatSmallBiasF16",
|
| 402 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 403 |
+
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 404 |
+
"dispatch": {
|
| 405 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 406 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 407 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
],
|
| 411 |
+
"demoteWhen": ["sgmatOutputGroups > tunables.SMALL_MATRIX_MAX_GROUPS and (sgmatMediumContract or sgmatDirectContract or sgmatContract)"]
|
| 412 |
+
},
|
| 413 |
+
{
|
| 414 |
+
"id": "sgmat_small_f16",
|
| 415 |
+
"priority": 125,
|
| 416 |
+
"when": ["noBiasContract", "sgmatSmallContract", "tensorDtypes.X == \"float16\""],
|
| 417 |
+
"requires": {
|
| 418 |
+
"features": ["subgroups", "chromium-experimental-subgroup-matrix"],
|
| 419 |
+
"subgroupMatrixConfigs": [{ "componentType": "f16", "M": 8, "N": 8, "K": 8 }]
|
| 420 |
+
},
|
| 421 |
+
"derive": {
|
| 422 |
+
"hasBias": false,
|
| 423 |
+
"xScalar": "\"f16\"",
|
| 424 |
+
"wScalar": "\"f16\"",
|
| 425 |
+
"bScalar": "\"f16\"",
|
| 426 |
+
"yScalar": "\"f16\"",
|
| 427 |
+
"mmaScalar": "\"f16\"",
|
| 428 |
+
"inFeatures": "kDim",
|
| 429 |
+
"outFeatures": "nDim",
|
| 430 |
+
"tileM": "sgmatSmallRows",
|
| 431 |
+
"tileN": "sgmatSmallCols",
|
| 432 |
+
"directAStorage": true,
|
| 433 |
+
"doubleBufferedB": true,
|
| 434 |
+
"balancedMatrixAccumulation": false
|
| 435 |
+
},
|
| 436 |
+
"passes": [
|
| 437 |
+
{
|
| 438 |
+
"id": "main",
|
| 439 |
+
"name": "GemmFastGelu.SgmatSmallF16",
|
| 440 |
+
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 441 |
+
"bindings": ["x", "w", "y", "params"],
|
| 442 |
+
"dispatch": {
|
| 443 |
+
"x": "ceilDiv(nDim, tileN)",
|
| 444 |
+
"y": "min(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)",
|
| 445 |
+
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 446 |
+
}
|
| 447 |
+
}
|
| 448 |
+
],
|
| 449 |
+
"demoteWhen": ["sgmatOutputGroups > tunables.SMALL_MATRIX_MAX_GROUPS and (sgmatMediumContract or sgmatDirectContract or sgmatContract)"]
|
| 450 |
+
},
|
| 451 |
{
|
| 452 |
"id": "sgmat_direct_bias",
|
| 453 |
"priority": 110,
|
|
|
|
| 458 |
},
|
| 459 |
"derive": {
|
| 460 |
"hasBias": true,
|
|
|
|
| 461 |
"xScalar": "\"f32\"",
|
| 462 |
"wScalar": "\"f32\"",
|
| 463 |
"bScalar": "\"f32\"",
|
|
|
|
| 467 |
"outFeatures": "nDim",
|
| 468 |
"tileM": "sgmatDirectRows",
|
| 469 |
"tileN": "sgmatDirectCols",
|
|
|
|
| 470 |
"directAStorage": true,
|
| 471 |
"doubleBufferedB": true,
|
| 472 |
"balancedMatrixAccumulation": true
|
|
|
|
| 474 |
"passes": [
|
| 475 |
{
|
| 476 |
"id": "main",
|
| 477 |
+
"name": "GemmFastGelu.SgmatDirectBias",
|
| 478 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 479 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 480 |
"dispatch": {
|
|
|
|
| 483 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 484 |
}
|
| 485 |
}
|
| 486 |
+
],
|
| 487 |
+
"demoteWhen": ["false"]
|
| 488 |
},
|
| 489 |
{
|
| 490 |
"id": "sgmat_direct",
|
|
|
|
| 496 |
},
|
| 497 |
"derive": {
|
| 498 |
"hasBias": false,
|
|
|
|
| 499 |
"xScalar": "\"f32\"",
|
| 500 |
"wScalar": "\"f32\"",
|
| 501 |
"bScalar": "\"f32\"",
|
|
|
|
| 505 |
"outFeatures": "nDim",
|
| 506 |
"tileM": "sgmatDirectRows",
|
| 507 |
"tileN": "sgmatDirectCols",
|
|
|
|
| 508 |
"directAStorage": true,
|
| 509 |
"doubleBufferedB": true,
|
| 510 |
"balancedMatrixAccumulation": true
|
|
|
|
| 512 |
"passes": [
|
| 513 |
{
|
| 514 |
"id": "main",
|
| 515 |
+
"name": "GemmFastGelu.SgmatDirect",
|
| 516 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 517 |
"bindings": ["x", "w", "y", "params"],
|
| 518 |
"dispatch": {
|
|
|
|
| 521 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 522 |
}
|
| 523 |
}
|
| 524 |
+
],
|
| 525 |
+
"demoteWhen": ["false"]
|
| 526 |
},
|
| 527 |
{
|
| 528 |
"id": "sgmat_direct_bias_f16",
|
|
|
|
| 534 |
},
|
| 535 |
"derive": {
|
| 536 |
"hasBias": true,
|
|
|
|
| 537 |
"xScalar": "\"f16\"",
|
| 538 |
"wScalar": "\"f16\"",
|
| 539 |
"bScalar": "\"f16\"",
|
|
|
|
| 543 |
"outFeatures": "nDim",
|
| 544 |
"tileM": "sgmatDirectRows",
|
| 545 |
"tileN": "sgmatDirectCols",
|
|
|
|
| 546 |
"directAStorage": true,
|
| 547 |
"doubleBufferedB": true,
|
| 548 |
"balancedMatrixAccumulation": false
|
|
|
|
| 550 |
"passes": [
|
| 551 |
{
|
| 552 |
"id": "main",
|
| 553 |
+
"name": "GemmFastGelu.SgmatDirectBiasF16",
|
| 554 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 555 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 556 |
"dispatch": {
|
|
|
|
| 559 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 560 |
}
|
| 561 |
}
|
| 562 |
+
],
|
| 563 |
+
"demoteWhen": ["false"]
|
| 564 |
},
|
| 565 |
{
|
| 566 |
"id": "sgmat_direct_f16",
|
|
|
|
| 572 |
},
|
| 573 |
"derive": {
|
| 574 |
"hasBias": false,
|
|
|
|
| 575 |
"xScalar": "\"f16\"",
|
| 576 |
"wScalar": "\"f16\"",
|
| 577 |
"bScalar": "\"f16\"",
|
|
|
|
| 581 |
"outFeatures": "nDim",
|
| 582 |
"tileM": "sgmatDirectRows",
|
| 583 |
"tileN": "sgmatDirectCols",
|
|
|
|
| 584 |
"directAStorage": true,
|
| 585 |
"doubleBufferedB": true,
|
| 586 |
"balancedMatrixAccumulation": false
|
|
|
|
| 588 |
"passes": [
|
| 589 |
{
|
| 590 |
"id": "main",
|
| 591 |
+
"name": "GemmFastGelu.SgmatDirectF16",
|
| 592 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 593 |
"bindings": ["x", "w", "y", "params"],
|
| 594 |
"dispatch": {
|
|
|
|
| 597 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 598 |
}
|
| 599 |
}
|
| 600 |
+
],
|
| 601 |
+
"demoteWhen": ["false"]
|
| 602 |
},
|
| 603 |
{
|
| 604 |
"id": "sgmat_bias",
|
|
|
|
| 610 |
},
|
| 611 |
"derive": {
|
| 612 |
"hasBias": true,
|
|
|
|
| 613 |
"xScalar": "\"f32\"",
|
| 614 |
"wScalar": "\"f32\"",
|
| 615 |
"bScalar": "\"f32\"",
|
|
|
|
| 619 |
"outFeatures": "nDim",
|
| 620 |
"tileM": 32,
|
| 621 |
"tileN": 64,
|
|
|
|
| 622 |
"directAStorage": false,
|
| 623 |
"doubleBufferedB": false,
|
| 624 |
"balancedMatrixAccumulation": false
|
|
|
|
| 626 |
"passes": [
|
| 627 |
{
|
| 628 |
"id": "main",
|
| 629 |
+
"name": "GemmFastGelu.SgmatBias",
|
| 630 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 631 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 632 |
"dispatch": {
|
|
|
|
| 635 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 636 |
}
|
| 637 |
}
|
| 638 |
+
],
|
| 639 |
+
"demoteWhen": ["false"]
|
| 640 |
},
|
| 641 |
{
|
| 642 |
"id": "sgmat",
|
|
|
|
| 648 |
},
|
| 649 |
"derive": {
|
| 650 |
"hasBias": false,
|
|
|
|
| 651 |
"xScalar": "\"f32\"",
|
| 652 |
"wScalar": "\"f32\"",
|
| 653 |
"bScalar": "\"f32\"",
|
|
|
|
| 657 |
"outFeatures": "nDim",
|
| 658 |
"tileM": 32,
|
| 659 |
"tileN": 64,
|
|
|
|
| 660 |
"directAStorage": false,
|
| 661 |
"doubleBufferedB": false,
|
| 662 |
"balancedMatrixAccumulation": false
|
|
|
|
| 664 |
"passes": [
|
| 665 |
{
|
| 666 |
"id": "main",
|
| 667 |
+
"name": "GemmFastGelu.Sgmat",
|
| 668 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 669 |
"bindings": ["x", "w", "y", "params"],
|
| 670 |
"dispatch": {
|
|
|
|
| 673 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 674 |
}
|
| 675 |
}
|
| 676 |
+
],
|
| 677 |
+
"demoteWhen": ["false"]
|
| 678 |
},
|
| 679 |
{
|
| 680 |
"id": "sgmat_bias_f16",
|
|
|
|
| 686 |
},
|
| 687 |
"derive": {
|
| 688 |
"hasBias": true,
|
|
|
|
| 689 |
"xScalar": "\"f16\"",
|
| 690 |
"wScalar": "\"f16\"",
|
| 691 |
"bScalar": "\"f16\"",
|
|
|
|
| 695 |
"outFeatures": "nDim",
|
| 696 |
"tileM": 32,
|
| 697 |
"tileN": 64,
|
|
|
|
| 698 |
"directAStorage": false,
|
| 699 |
"doubleBufferedB": false,
|
| 700 |
"balancedMatrixAccumulation": false
|
|
|
|
| 702 |
"passes": [
|
| 703 |
{
|
| 704 |
"id": "main",
|
| 705 |
+
"name": "GemmFastGelu.SgmatBiasF16",
|
| 706 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 707 |
"bindings": ["x", "w", { "arg": "bias", "elementType": "$bScalar" }, "y", "params"],
|
| 708 |
"dispatch": {
|
|
|
|
| 711 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 712 |
}
|
| 713 |
}
|
| 714 |
+
],
|
| 715 |
+
"demoteWhen": ["false"]
|
| 716 |
},
|
| 717 |
{
|
| 718 |
"id": "sgmat_f16",
|
|
|
|
| 724 |
},
|
| 725 |
"derive": {
|
| 726 |
"hasBias": false,
|
|
|
|
| 727 |
"xScalar": "\"f16\"",
|
| 728 |
"wScalar": "\"f16\"",
|
| 729 |
"bScalar": "\"f16\"",
|
|
|
|
| 733 |
"outFeatures": "nDim",
|
| 734 |
"tileM": 32,
|
| 735 |
"tileN": 64,
|
|
|
|
| 736 |
"directAStorage": false,
|
| 737 |
"doubleBufferedB": false,
|
| 738 |
"balancedMatrixAccumulation": false
|
|
|
|
| 740 |
"passes": [
|
| 741 |
{
|
| 742 |
"id": "main",
|
| 743 |
+
"name": "GemmFastGelu.SgmatF16",
|
| 744 |
"shader": "gemm-subgroup-matrix.wgsl.jinja",
|
| 745 |
"bindings": ["x", "w", "y", "params"],
|
| 746 |
"dispatch": {
|
|
|
|
| 749 |
"z": "ceilDiv(ceilDiv(gfgRows, tileM), DISPATCH_FOLD_WIDTH)"
|
| 750 |
}
|
| 751 |
}
|
| 752 |
+
],
|
| 753 |
+
"demoteWhen": ["false"]
|
| 754 |
},
|
| 755 |
{
|
| 756 |
"id": "tiled_bias",
|
|
|
|
| 761 |
{
|
| 762 |
"id": "main",
|
| 763 |
"name": "GemmFastGelu.Bias",
|
| 764 |
+
"shader": "gemm-epilogue-tiled-reg.wgsl.jinja",
|
| 765 |
"bindings": [
|
| 766 |
"a",
|
| 767 |
"b",
|
| 768 |
"bias",
|
| 769 |
+
"y_t",
|
| 770 |
{
|
| 771 |
"name": "params",
|
| 772 |
"struct": [
|
|
|
|
| 779 |
}
|
| 780 |
],
|
| 781 |
"dispatch": {
|
| 782 |
+
"x": "min(ceilDiv(nDim, gemmTileCols), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 783 |
+
"y": "min(ceilDiv(gfgRows, gemmTileRows), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))"
|
| 784 |
}
|
| 785 |
}
|
| 786 |
]
|
|
|
|
| 794 |
{
|
| 795 |
"id": "main",
|
| 796 |
"name": "GemmFastGelu",
|
| 797 |
+
"shader": "gemm-epilogue-tiled-reg.wgsl.jinja",
|
| 798 |
"bindings": [
|
| 799 |
"a",
|
| 800 |
"b",
|
| 801 |
+
"y_t",
|
| 802 |
{
|
| 803 |
"name": "params",
|
| 804 |
"struct": [
|
|
|
|
| 810 |
}
|
| 811 |
],
|
| 812 |
"dispatch": {
|
| 813 |
+
"x": "min(ceilDiv(nDim, gemmTileCols), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))",
|
| 814 |
+
"y": "min(ceilDiv(gfgRows, gemmTileRows), min(device.limits.maxComputeWorkgroupsPerDimension, 65535))"
|
| 815 |
}
|
| 816 |
}
|
| 817 |
]
|
| 818 |
}
|
| 819 |
+
],
|
| 820 |
+
"tunables": {
|
| 821 |
+
"SMALL_MATRIX_MAX_GROUPS": { "default": 48 },
|
| 822 |
+
"MEDIUM_MATRIX_MAX_GROUPS_F32": { "default": 96 },
|
| 823 |
+
"MEDIUM_MATRIX_MAX_GROUPS_F16": { "default": 80 },
|
| 824 |
+
"GEMV_TARGET_BLOCKS": { "default": 512 },
|
| 825 |
+
"PORTABLE_SMALL_TILE_GROUPS_F32": { "default": 64 },
|
| 826 |
+
"PORTABLE_SMALL_TILE_GROUPS_F16": { "default": 128 }
|
| 827 |
+
}
|
| 828 |
}
|
build/webgpu/matmul-vector-matrix-vec4.wgsl.jinja
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// GEMV specialization for y[N] = a[K] @ B[K, N]. Each workgroup owns 32
|
| 2 |
+
// consecutive vec4 column groups, or 128 output columns.
|
| 3 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 4 |
+
{% set OUT = "y" %}
|
| 5 |
+
fn tanh_safe(x: f32) -> f32 {
|
| 6 |
+
// tanh rounds to its saturated value for these tails in f32. Return that
|
| 7 |
+
// value directly, including for infinite input, before invoking the builtin.
|
| 8 |
+
if (x > 10.0) { return 1.0; }
|
| 9 |
+
if (x < -10.0) { return -1.0; }
|
| 10 |
+
// For tiny |x|, return x directly to preserve its sign and magnitude without
|
| 11 |
+
// relying on backend-specific builtin behavior near zero.
|
| 12 |
+
if (x > -1.0e-4 && x < 1.0e-4) { return x; }
|
| 13 |
+
return tanh(x);
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
fn gelu_tanh(v: f32) -> f32 {
|
| 17 |
+
return 0.5 * v * (1.0 + tanh_safe(0.7978845608028654 * (v + 0.044715 * v * v * v)));
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
const LANES: u32 = {{ gemvLanes }}u;
|
| 21 |
+
// SLICES partitions the K reduction across the workgroup's second dimension.
|
| 22 |
+
// Thread zero of each column group combines the slice partials in index order.
|
| 23 |
+
const SLICES: u32 = {{ gemvSlices }}u;
|
| 24 |
+
|
| 25 |
+
var<workgroup> partials: array<vec4<f32>, LANES * SLICES>;
|
| 26 |
+
|
| 27 |
+
@compute @workgroup_size({{ gemvLanes }}, {{ gemvSlices }}, 1)
|
| 28 |
+
fn main(
|
| 29 |
+
@builtin(workgroup_id) workgroup_id: vec3<u32>,
|
| 30 |
+
@builtin(local_invocation_id) lid: vec3<u32>
|
| 31 |
+
) {
|
| 32 |
+
let lane = lid.x;
|
| 33 |
+
let slice = lid.y;
|
| 34 |
+
let cg = workgroup_id.x * LANES + lane;
|
| 35 |
+
var acc = vec4<f32>(0.0);
|
| 36 |
+
if (cg < params.N4) {
|
| 37 |
+
{% if unrollK2 is defined and unrollK2 %}
|
| 38 |
+
// Two K positions per iteration amortize loop/address arithmetic on long
|
| 39 |
+
// decode projections while preserving each slice's exact strided order.
|
| 40 |
+
var k = slice;
|
| 41 |
+
for (; k + SLICES < params.K; k = k + 2u * SLICES) {
|
| 42 |
+
acc = acc + f32(a[k]) * vec4<f32>(b[k * params.N4 + cg]);
|
| 43 |
+
let k1 = k + SLICES;
|
| 44 |
+
acc = acc + f32(a[k1]) * vec4<f32>(b[k1 * params.N4 + cg]);
|
| 45 |
+
}
|
| 46 |
+
if (k < params.K) {
|
| 47 |
+
acc = acc + f32(a[k]) * vec4<f32>(b[k * params.N4 + cg]);
|
| 48 |
+
}
|
| 49 |
+
{% else %}
|
| 50 |
+
for (var k = slice; k < params.K; k = k + SLICES) {
|
| 51 |
+
acc = acc + f32(a[k]) * vec4<f32>(b[k * params.N4 + cg]);
|
| 52 |
+
}
|
| 53 |
+
{% endif %}
|
| 54 |
+
}
|
| 55 |
+
partials[slice * LANES + lane] = acc;
|
| 56 |
+
workgroupBarrier();
|
| 57 |
+
if (slice == 0u && cg < params.N4) {
|
| 58 |
+
var total = partials[lane];
|
| 59 |
+
for (var s = 1u; s < SLICES; s = s + 1u) {
|
| 60 |
+
total = total + partials[s * LANES + lane];
|
| 61 |
+
}
|
| 62 |
+
{% if gemvBias | default(false) %}
|
| 63 |
+
total = total + vec4<f32>(bias[cg]);
|
| 64 |
+
{% endif %}
|
| 65 |
+
{% for i in range(4) %}
|
| 66 |
+
total[{{ i }}] = gelu_tanh(total[{{ i }}]);
|
| 67 |
+
{% endfor %}
|
| 68 |
+
{{ OUT }}[cg] = vec4<{{ T }}>(total);
|
| 69 |
+
}
|
| 70 |
+
}
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,23 +1,34 @@
|
|
| 1 |
{
|
| 2 |
"name": "com.microsoft.GemmFastGelu",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
-
"bench.json": "
|
| 11 |
-
"gemm-
|
| 12 |
-
"gemm-subgroup-matrix.wgsl.jinja": "
|
| 13 |
-
"manifest.json": "
|
| 14 |
-
"
|
|
|
|
| 15 |
}
|
| 16 |
},
|
| 17 |
-
"provenance": { "kernel": { "sha": "
|
| 18 |
"webgpu": {
|
| 19 |
-
"manifestSpec": "2.
|
| 20 |
"variants": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
"sgmat_direct_bias": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 22 |
"sgmat_direct": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 23 |
"sgmat_direct_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
|
@@ -26,8 +37,8 @@
|
|
| 26 |
"sgmat": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 27 |
"sgmat_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 28 |
"sgmat_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 29 |
-
"tiled_bias": ["gemm-
|
| 30 |
-
"tiled": ["gemm-
|
| 31 |
}
|
| 32 |
}
|
| 33 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "com.microsoft.GemmFastGelu",
|
| 3 |
+
"id": "_com_microsoft_gemmfastgelu_webgpu_f5e93e1",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"bench.json": "FfMbeBQWBZxpDttjltTuzAV+j6kE32ZmQfmcYdMKHQk=",
|
| 11 |
+
"gemm-epilogue-tiled-reg.wgsl.jinja": "R5ytrlOP+b62VdPVNEBfcMFde6AXx522owT2aH53EsQ=",
|
| 12 |
+
"gemm-subgroup-matrix.wgsl.jinja": "iDyC5cRpAczYx/bZ4E9ye5mFljkK0mlPhB0ZMAaLjRg=",
|
| 13 |
+
"manifest.json": "1QpiQuqS1C0R7nLKk7zC6wA9zt9GPnOdYFZ1+xNlE/U=",
|
| 14 |
+
"matmul-vector-matrix-vec4.wgsl.jinja": "uU7qRZ2/JhR5TZ4kZEeaf2pg1ZGqTvpO5VG1r2ft00E=",
|
| 15 |
+
"test.json": "IB4HCRTq8pos9TIr+Oy8FeeM8GCWURJ+d85QJYDv+bc="
|
| 16 |
}
|
| 17 |
},
|
| 18 |
+
"provenance": { "kernel": { "sha": "6fdf6301e2bbcc2f03bf1eaf493b7ad55ef33afc", "dirty": false } },
|
| 19 |
"webgpu": {
|
| 20 |
+
"manifestSpec": "2.1",
|
| 21 |
"variants": {
|
| 22 |
+
"vector_matrix_bias": ["matmul-vector-matrix-vec4.wgsl.jinja"],
|
| 23 |
+
"vector_matrix": ["matmul-vector-matrix-vec4.wgsl.jinja"],
|
| 24 |
+
"sgmat_medium_bias": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 25 |
+
"sgmat_medium": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 26 |
+
"sgmat_medium_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 27 |
+
"sgmat_medium_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 28 |
+
"sgmat_small_bias": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 29 |
+
"sgmat_small": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 30 |
+
"sgmat_small_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 31 |
+
"sgmat_small_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 32 |
"sgmat_direct_bias": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 33 |
"sgmat_direct": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 34 |
"sgmat_direct_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
|
|
|
| 37 |
"sgmat": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 38 |
"sgmat_bias_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 39 |
"sgmat_f16": ["gemm-subgroup-matrix.wgsl.jinja"],
|
| 40 |
+
"tiled_bias": ["gemm-epilogue-tiled-reg.wgsl.jinja"],
|
| 41 |
+
"tiled": ["gemm-epilogue-tiled-reg.wgsl.jinja"]
|
| 42 |
}
|
| 43 |
}
|
| 44 |
}
|
build/webgpu/test.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|