@graphty/webgpu-graph-algorithms 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -52
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-CRbw2Wyo.js → context-BXqgCifx.js} +225 -33
- package/dist/chunks/context-BXqgCifx.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/accelerator.d.ts +12 -10
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +32 -10
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/components.d.ts.map +1 -1
- package/dist/src/algorithms/components.js +12 -13
- package/dist/src/algorithms/components.js.map +1 -1
- package/dist/src/algorithms/degree.d.ts +6 -8
- package/dist/src/algorithms/degree.d.ts.map +1 -1
- package/dist/src/algorithms/degree.js +58 -35
- package/dist/src/algorithms/degree.js.map +1 -1
- package/dist/src/algorithms/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/pagerank.js +16 -14
- package/dist/src/algorithms/pagerank.js.map +1 -1
- package/dist/src/algorithms/power-iteration.d.ts +2 -2
- package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
- package/dist/src/algorithms/power-iteration.js +17 -14
- package/dist/src/algorithms/power-iteration.js.map +1 -1
- package/dist/src/constants.d.ts +85 -8
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +85 -8
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +2 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +10 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/dispatch.d.ts +8 -3
- package/dist/src/kernel/dispatch.d.ts.map +1 -1
- package/dist/src/kernel/dispatch.js +18 -7
- package/dist/src/kernel/dispatch.js.map +1 -1
- package/dist/src/kernel/kernel.d.ts +30 -1
- package/dist/src/kernel/kernel.d.ts.map +1 -1
- package/dist/src/kernel/kernel.js +49 -5
- package/dist/src/kernel/kernel.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +9 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernel/profiler.d.ts +15 -3
- package/dist/src/kernel/profiler.d.ts.map +1 -1
- package/dist/src/kernel/profiler.js +27 -4
- package/dist/src/kernel/profiler.js.map +1 -1
- package/dist/src/kernels.d.ts +18 -8
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +345 -22
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/calibrate.d.ts +51 -0
- package/dist/src/layouts/calibrate.d.ts.map +1 -0
- package/dist/src/layouts/calibrate.js +172 -0
- package/dist/src/layouts/calibrate.js.map +1 -0
- package/dist/src/layouts/force-simulation.d.ts +42 -5
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +84 -22
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts +107 -38
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +297 -290
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts +241 -0
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -0
- package/dist/src/layouts/fruchterman-reingold.js +739 -0
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -0
- package/dist/src/layouts/model-common.d.ts +140 -0
- package/dist/src/layouts/model-common.d.ts.map +1 -0
- package/dist/src/layouts/model-common.js +269 -0
- package/dist/src/layouts/model-common.js.map +1 -0
- package/dist/src/layouts/repulsion-grid.d.ts +152 -0
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
- package/dist/src/layouts/repulsion-grid.js +318 -0
- package/dist/src/layouts/repulsion-grid.js.map +1 -0
- package/dist/src/layouts/spring-electrical.d.ts +224 -0
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -0
- package/dist/src/layouts/spring-electrical.js +665 -0
- package/dist/src/layouts/spring-electrical.js.map +1 -0
- package/dist/src/memory/residency.d.ts +6 -2
- package/dist/src/memory/residency.d.ts.map +1 -1
- package/dist/src/memory/residency.js +84 -14
- package/dist/src/memory/residency.js.map +1 -1
- package/dist/src/primitives/core-shape.d.ts +38 -2
- package/dist/src/primitives/core-shape.d.ts.map +1 -1
- package/dist/src/primitives/core-shape.js +71 -3
- package/dist/src/primitives/core-shape.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +71 -0
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
- package/dist/src/primitives/grid-pyramid.js +143 -0
- package/dist/src/primitives/grid-pyramid.js.map +1 -0
- package/dist/src/primitives/grid.d.ts +118 -0
- package/dist/src/primitives/grid.d.ts.map +1 -0
- package/dist/src/primitives/grid.js +225 -0
- package/dist/src/primitives/grid.js.map +1 -0
- package/dist/src/primitives/histogram.d.ts +67 -0
- package/dist/src/primitives/histogram.d.ts.map +1 -0
- package/dist/src/primitives/histogram.js +190 -0
- package/dist/src/primitives/histogram.js.map +1 -0
- package/dist/src/primitives/radix-sort.d.ts +75 -0
- package/dist/src/primitives/radix-sort.d.ts.map +1 -0
- package/dist/src/primitives/radix-sort.js +168 -0
- package/dist/src/primitives/radix-sort.js.map +1 -0
- package/dist/src/primitives/scan.d.ts +44 -0
- package/dist/src/primitives/scan.d.ts.map +1 -0
- package/dist/src/primitives/scan.js +151 -0
- package/dist/src/primitives/scan.js.map +1 -0
- package/dist/src/primitives/segmented-reduce.d.ts +25 -17
- package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
- package/dist/src/primitives/segmented-reduce.js +166 -47
- package/dist/src/primitives/segmented-reduce.js.map +1 -1
- package/dist/src/primitives/spmv.d.ts +18 -14
- package/dist/src/primitives/spmv.d.ts.map +1 -1
- package/dist/src/primitives/spmv.js +94 -58
- package/dist/src/primitives/spmv.js.map +1 -1
- package/dist/src/primitives/verify.d.ts +49 -0
- package/dist/src/primitives/verify.d.ts.map +1 -0
- package/dist/src/primitives/verify.js +229 -0
- package/dist/src/primitives/verify.js.map +1 -0
- package/dist/src/types/accelerator.d.ts +7 -3
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/context.d.ts +53 -0
- package/dist/src/types/context.d.ts.map +1 -1
- package/dist/src/types/layout.d.ts +52 -0
- package/dist/src/types/layout.d.ts.map +1 -1
- package/dist/src/types/options.d.ts +43 -1
- package/dist/src/types/options.d.ts.map +1 -1
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -8
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.js +100 -17
- package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +7 -2
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-integrate.wgsl.js +28 -2
- package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +4 -2
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +14 -5
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +12 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +54 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.js +15 -0
- package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
- package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.js +14 -0
- package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.js +30 -0
- package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
- package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
- package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/webgpu-graph-algorithms.js +5016 -1130
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +10 -7
- package/src/accelerator.ts +46 -12
- package/src/algorithms/components.ts +12 -16
- package/src/algorithms/degree.ts +58 -43
- package/src/algorithms/pagerank.ts +20 -18
- package/src/algorithms/power-iteration.ts +19 -18
- package/src/constants.ts +108 -8
- package/src/errors.ts +3 -1
- package/src/index.ts +25 -5
- package/src/kernel/dispatch.ts +18 -7
- package/src/kernel/kernel.ts +59 -5
- package/src/kernel/prelude.ts +15 -0
- package/src/kernel/profiler.ts +28 -4
- package/src/kernels.ts +378 -24
- package/src/layouts/calibrate.ts +187 -0
- package/src/layouts/force-simulation.ts +111 -26
- package/src/layouts/forceatlas2.ts +346 -324
- package/src/layouts/fruchterman-reingold.ts +918 -0
- package/src/layouts/model-common.ts +323 -0
- package/src/layouts/repulsion-grid.ts +451 -0
- package/src/layouts/spring-electrical.ts +845 -0
- package/src/memory/residency.ts +126 -20
- package/src/primitives/core-shape.ts +91 -4
- package/src/primitives/grid-pyramid.ts +221 -0
- package/src/primitives/grid.ts +349 -0
- package/src/primitives/histogram.ts +273 -0
- package/src/primitives/radix-sort.ts +246 -0
- package/src/primitives/scan.ts +197 -0
- package/src/primitives/segmented-reduce.ts +214 -56
- package/src/primitives/spmv.ts +125 -65
- package/src/primitives/verify.ts +249 -0
- package/src/types/accelerator.ts +15 -3
- package/src/types/context.ts +56 -0
- package/src/types/layout.ts +58 -0
- package/src/types/options.ts +45 -1
- package/src/wgsl/counting-scatter.wgsl.ts +16 -0
- package/src/wgsl/fa2-attraction.wgsl.ts +100 -17
- package/src/wgsl/fa2-integrate.wgsl.ts +28 -2
- package/src/wgsl/fa2-repulsion-exact.wgsl.ts +14 -5
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +54 -0
- package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
- package/src/wgsl/grid-centroid.wgsl.ts +28 -0
- package/src/wgsl/grid-downsample.wgsl.ts +27 -0
- package/src/wgsl/grid-far-field.wgsl.ts +97 -0
- package/src/wgsl/grid-near-field.wgsl.ts +128 -0
- package/src/wgsl/histogram.wgsl.ts +14 -0
- package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
- package/src/wgsl/radix-hist.wgsl.ts +30 -0
- package/src/wgsl/radix-scatter.wgsl.ts +39 -0
- package/src/wgsl/scan-add.wgsl.ts +13 -0
- package/src/wgsl/scan-block.wgsl.ts +29 -0
- package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
- package/src/wgsl/spmv-pull.wgsl.ts +110 -36
- package/dist/chunks/context-CRbw2Wyo.js.map +0 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `exclusiveScan` primitive driver (spec 6 row 2; P4-T2, PD-3): a reduce-then-scan over u32 words. Level 0 runs
|
|
3
|
+
* `scan-block` over `count` items into `out` (each workgroup an exclusive Hillis-Steele scan of its WG-wide block) and
|
|
4
|
+
* writes one block sum per workgroup; while a level has more than one block, the next level scans its block sums
|
|
5
|
+
* (exclusive, into `offsets_L`) and writes its own block sums, recursively; the top level has ONE block, so its one
|
|
6
|
+
* sums word is the total. Then, top down, `scan-add` adds `offsets_L[g]` to every element of block `g` of level L's
|
|
7
|
+
* output. u32 addition is exact in any order, so two runs on any two adapters are bitwise identical; there is no
|
|
8
|
+
* subgroup variant (DEP-P4-E) and no decoupled look-back.
|
|
9
|
+
*
|
|
10
|
+
* The driver owns no device objects beyond a one-word zero it keeps for the empty scan: the caller supplies a
|
|
11
|
+
* ReduceScope (the same record `reduce` takes) and the compute pass to record into. `src/primitives/**` never imports
|
|
12
|
+
* `src/context.ts`.
|
|
13
|
+
*/
|
|
14
|
+
import { WebGpuGraphError } from "../errors.js";
|
|
15
|
+
import { groupsOf, plan1d } from "../kernel/dispatch.js";
|
|
16
|
+
import { kernelSpec, SCAN_PARAMS } from "../kernels.js";
|
|
17
|
+
/** The largest u32: the largest count `ScanParams.count` can carry. */
|
|
18
|
+
const U32_MAX = 0xffffffff;
|
|
19
|
+
/**
|
|
20
|
+
* Prepares the two scan pipelines of a scope (compiles once) so record() is synchronous. The zero word the empty
|
|
21
|
+
* scan's total points at is a scratch of `scope`, so the planner lives exactly as long as the scope: never use a
|
|
22
|
+
* planner after its scope's dispose().
|
|
23
|
+
* @param scope - the caller's scope (device, caps, cache, scratch, params)
|
|
24
|
+
* @returns the planner
|
|
25
|
+
*/
|
|
26
|
+
export async function prepareScan(scope) {
|
|
27
|
+
const block = await scope.pipelines.kernel(kernelSpec("scan-block"));
|
|
28
|
+
const add = await scope.pipelines.kernel(kernelSpec("scan-add"));
|
|
29
|
+
const zero = scope.scratch(4, "scan/zero");
|
|
30
|
+
scope.device.queue.writeBuffer(zero, 0, new Uint32Array(1));
|
|
31
|
+
return new ScanPlannerImpl(scope, block, add, { buffer: zero, offset: 0, size: 4, window: null });
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The argument checks of record() (E_INVALID_ARGUMENT before anything is recorded).
|
|
35
|
+
* @param src - the input binding
|
|
36
|
+
* @param count - the word count
|
|
37
|
+
* @param out - the output binding
|
|
38
|
+
*/
|
|
39
|
+
function checkRecordArguments(src, count, out) {
|
|
40
|
+
if (!Number.isSafeInteger(count) || count < 0 || count > U32_MAX) {
|
|
41
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", "scan: count must be a non-negative integer below 2^32", {
|
|
42
|
+
argument: "count",
|
|
43
|
+
value: count,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (src.size < 4 * count) {
|
|
47
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", "scan: src is smaller than 4 x count bytes", {
|
|
48
|
+
argument: "src",
|
|
49
|
+
value: src.size,
|
|
50
|
+
expected: 4 * count,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (out.size < 4 * count) {
|
|
54
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", "scan: out is smaller than 4 x count bytes", {
|
|
55
|
+
argument: "out",
|
|
56
|
+
value: out.size,
|
|
57
|
+
expected: 4 * count,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** The planner: the two resolved kernels over one scope. */
|
|
62
|
+
class ScanPlannerImpl {
|
|
63
|
+
/**
|
|
64
|
+
* Wraps the resolved kernels; use prepareScan().
|
|
65
|
+
* @param scope - the caller's scope
|
|
66
|
+
* @param block - the `scan-block` kernel
|
|
67
|
+
* @param add - the `scan-add` kernel
|
|
68
|
+
* @param zero - a one-word binding holding 0 (the total of the empty scan)
|
|
69
|
+
*/
|
|
70
|
+
constructor(scope, block, add, zero) {
|
|
71
|
+
this.dispatches = 0;
|
|
72
|
+
this.scope = scope;
|
|
73
|
+
this.block = block;
|
|
74
|
+
this.add = add;
|
|
75
|
+
this.zero = zero;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Dispatches the last record() issued.
|
|
79
|
+
* @returns the count
|
|
80
|
+
*/
|
|
81
|
+
get lastDispatches() {
|
|
82
|
+
return this.dispatches;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Records the levels into the pass (see the interface).
|
|
86
|
+
* @param pass - the compute pass
|
|
87
|
+
* @param src - the input words
|
|
88
|
+
* @param count - the word count
|
|
89
|
+
* @param out - the output words
|
|
90
|
+
* @returns the total's location
|
|
91
|
+
*/
|
|
92
|
+
record(pass, src, count, out) {
|
|
93
|
+
checkRecordArguments(src, count, out);
|
|
94
|
+
if (count === 0) {
|
|
95
|
+
this.dispatches = 0;
|
|
96
|
+
return { binding: this.zero, index: 0 };
|
|
97
|
+
}
|
|
98
|
+
const wg = this.scope.workgroupSize;
|
|
99
|
+
const levels = [];
|
|
100
|
+
let input = src;
|
|
101
|
+
let output = out;
|
|
102
|
+
let levelCount = count;
|
|
103
|
+
for (;;) {
|
|
104
|
+
const blocks = Math.ceil(levelCount / wg);
|
|
105
|
+
// Sized by the PADDED workgroup count (reduce's shape, reduce.ts partials-1): above MAX_1D_ITEMS plan1d pads
|
|
106
|
+
// the grid to x * y >= blocks, and every padded workgroup still stores its (zero) block sum at its own index.
|
|
107
|
+
// The next level scans only `blocks` words, so the padded tail is written and never read.
|
|
108
|
+
const plan = plan1d(levelCount, wg, this.scope.caps);
|
|
109
|
+
const groups = groupsOf(plan);
|
|
110
|
+
const sums = this.scratch(groups, `scan/sums${levels.length}`);
|
|
111
|
+
levels.push({ input, output, count: levelCount, plan, sums });
|
|
112
|
+
if (blocks === 1) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
input = sums;
|
|
116
|
+
output = this.scratch(groups, `scan/offsets${levels.length}`);
|
|
117
|
+
levelCount = blocks;
|
|
118
|
+
}
|
|
119
|
+
for (const level of levels) {
|
|
120
|
+
const params = this.scope.params(SCAN_PARAMS, { count: level.count, pad0: 0, pad1: 0, pad2: 0 });
|
|
121
|
+
const bound = this.block.bind({
|
|
122
|
+
src: level.input,
|
|
123
|
+
out: level.output,
|
|
124
|
+
blockSums: level.sums,
|
|
125
|
+
P: params.binding,
|
|
126
|
+
});
|
|
127
|
+
this.block.dispatch(pass, bound, level.plan, [params.offset]);
|
|
128
|
+
}
|
|
129
|
+
for (let l = levels.length - 2; l >= 0; l--) {
|
|
130
|
+
const level = levels[l];
|
|
131
|
+
const params = this.scope.params(SCAN_PARAMS, { count: level.count, pad0: 0, pad1: 0, pad2: 0 });
|
|
132
|
+
const bound = this.add.bind({ out: level.output, blockOffsets: levels[l + 1].output, P: params.binding });
|
|
133
|
+
this.add.dispatch(pass, bound, level.plan, [params.offset]);
|
|
134
|
+
}
|
|
135
|
+
this.dispatches = 2 * levels.length - 1;
|
|
136
|
+
const top = levels[levels.length - 1];
|
|
137
|
+
return { binding: top.sums, index: 0 };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A scratch of `words` u32 from the scope, bound whole (never zero-length; the pool rounds the buffer up).
|
|
141
|
+
* @param words - the word count (>= 1)
|
|
142
|
+
* @param label - the scratch label
|
|
143
|
+
* @returns the binding
|
|
144
|
+
*/
|
|
145
|
+
scratch(words, label) {
|
|
146
|
+
const size = 4 * words;
|
|
147
|
+
const buffer = this.scope.scratch(size, label);
|
|
148
|
+
return { buffer, offset: 0, size, window: null };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/primitives/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The segmented (per-row) reduction primitive of spec 6 row 3
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* The segmented (per-row) reduction primitive of spec 6 row 3: the caller's VALUE snippet folded over every CSR
|
|
3
|
+
* row's arcs into `out[row]` (f32), a row with no arcs receiving the identity element. Without tiers it is ONE
|
|
4
|
+
* thread-per-row dispatch (TIER 0, USE_PERM false: the perm slot carries the rowPtr dummy of graphBindings). With
|
|
5
|
+
* the degree tiers of degreeOrder() (P4-T5, PD-6) it is up to three dispatches over the permuted rows: TIER 2, one
|
|
6
|
+
* workgroup per row of degree >= 1024 over [0, hiEnd); TIER 1, 32 lanes per row of degree 32..1023 over [hiEnd,
|
|
7
|
+
* midEnd); TIER 0, one thread per row over [midEnd, n) -- each compiled only when its range is non-empty. The row
|
|
8
|
+
* and arc counts come from the core's binding sizes: the residency binds every array at its exact byte length
|
|
9
|
+
* (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx 4 x arcCount. On a windowed core (spec 4.2, P4-T7, PD-8)
|
|
10
|
+
* the dispatches repeat per window with `arcBase = w.start`, `arcEnd = w.end` and `accumulate = 1` over an out
|
|
11
|
+
* pre-filled with the identity element (unless the caller asked to accumulate), so a row split across windows
|
|
12
|
+
* combines its partials: the untiered dispatch covers the window's rows [rowFirst, rowLast], while every tier
|
|
13
|
+
* dispatch covers its FULL tier range (permutation positions, not comparable with the window's node rows; a row
|
|
14
|
+
* whose arcs lie outside the window folds nothing and `finish` writes comb(out[i], identity) = out[i]).
|
|
9
15
|
*/
|
|
10
16
|
import { type CoreBinding } from "../memory/residency.js";
|
|
11
17
|
import { type Binding } from "../types/memory.js";
|
|
18
|
+
import { type DegreeTiers } from "./core-shape.js";
|
|
12
19
|
import { type ReduceOp, type ReduceScope } from "./reduce.js";
|
|
13
|
-
|
|
14
|
-
export interface DegreeTiers {
|
|
15
|
-
readonly perm: Binding;
|
|
16
|
-
readonly segmentOffsets: readonly [number, number, number, number, number];
|
|
17
|
-
}
|
|
20
|
+
export { type DegreeTiers } from "./core-shape.js";
|
|
18
21
|
/** Options of segmentedReduce. `valueSnippet` is the Gunrock-style functor: WGSL statements assigning `v` from (row, arc, nbr, weight) (4.5; `nbr` because `target` is a WGSL reserved word). */
|
|
19
22
|
export interface SegmentedReduceOptions {
|
|
20
23
|
readonly op: ReduceOp;
|
|
@@ -22,16 +25,21 @@ export interface SegmentedReduceOptions {
|
|
|
22
25
|
readonly tiers: DegreeTiers | null;
|
|
23
26
|
readonly accumulate?: boolean | undefined;
|
|
24
27
|
}
|
|
25
|
-
/** A prepared segmented reduce
|
|
28
|
+
/** A prepared segmented reduce: one thread-per-row dispatch without tiers, up to three tier dispatches with them (times the windows of a windowed core, plus its identity fill). */
|
|
26
29
|
export interface SegmentedReducePlanner {
|
|
27
|
-
/** Records
|
|
30
|
+
/** Records the dispatches over rows [0, n) writing out[i] (f32) per row; a row with no arcs gets the identity element. */
|
|
28
31
|
record(pass: GPUComputePassEncoder, core: CoreBinding, out: Binding): void;
|
|
32
|
+
/** Dispatches the last record() issued (0 for n = 0; 1 without tiers; 1 to 3 with them; on a windowed core the identity fill plus that many per window). */
|
|
33
|
+
readonly lastDispatches: number;
|
|
29
34
|
}
|
|
30
35
|
/**
|
|
31
|
-
* Prepares the
|
|
36
|
+
* Prepares the tier pipelines for a snapshot's dummy pattern (USE_PERM = tiers !== null, HAS_WEIGHTS) and snippet:
|
|
37
|
+
* TIER 0 always; TIER 1 iff a row of degree 32..1023 exists (segmentOffsets[2] > segmentOffsets[1]); TIER 2 iff a
|
|
38
|
+
* row of degree >= 1024 exists (segmentOffsets[1] > 0). The mid tier folds 32 lanes per row, so a device whose
|
|
39
|
+
* workgroup size is below 32 is E_UNSUPPORTED { feature: "segmentedReduce.tiers" }.
|
|
32
40
|
* @param scope - the reduce scope (pipelines, pool, params writer)
|
|
33
|
-
* @param core - the core whose weights pattern selects HAS_WEIGHTS
|
|
34
|
-
* @param options - operator, snippet, tiers (
|
|
41
|
+
* @param core - the core whose weights pattern selects HAS_WEIGHTS
|
|
42
|
+
* @param options - operator, snippet, tiers (null: the single thread-per-row dispatch), accumulate
|
|
35
43
|
* @returns the planner
|
|
36
44
|
*/
|
|
37
45
|
export declare function prepareSegmentedReduce(scope: ReduceScope, core: CoreBinding, options: SegmentedReduceOptions): Promise<SegmentedReducePlanner>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmented-reduce.d.ts","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"segmented-reduce.d.ts","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAc,KAAK,WAAW,EAA6C,MAAM,iBAAiB,CAAC;AAC1G,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,iMAAiM;AACjM,MAAM,WAAW,sBAAsB;IACnC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7C;AAED,oLAAoL;AACpL,MAAM,WAAW,sBAAsB;IACnC,0HAA0H;IAC1H,MAAM,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3E,4JAA4J;IAC5J,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AA6SD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CACxC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,sBAAsB,CAAC,CAuCjC"}
|
|
@@ -1,16 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The segmented (per-row) reduction primitive of spec 6 row 3
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* The segmented (per-row) reduction primitive of spec 6 row 3: the caller's VALUE snippet folded over every CSR
|
|
3
|
+
* row's arcs into `out[row]` (f32), a row with no arcs receiving the identity element. Without tiers it is ONE
|
|
4
|
+
* thread-per-row dispatch (TIER 0, USE_PERM false: the perm slot carries the rowPtr dummy of graphBindings). With
|
|
5
|
+
* the degree tiers of degreeOrder() (P4-T5, PD-6) it is up to three dispatches over the permuted rows: TIER 2, one
|
|
6
|
+
* workgroup per row of degree >= 1024 over [0, hiEnd); TIER 1, 32 lanes per row of degree 32..1023 over [hiEnd,
|
|
7
|
+
* midEnd); TIER 0, one thread per row over [midEnd, n) -- each compiled only when its range is non-empty. The row
|
|
8
|
+
* and arc counts come from the core's binding sizes: the residency binds every array at its exact byte length
|
|
9
|
+
* (contract 3.8), so rowPtr is 4(n + 1) bytes and colIdx 4 x arcCount. On a windowed core (spec 4.2, P4-T7, PD-8)
|
|
10
|
+
* the dispatches repeat per window with `arcBase = w.start`, `arcEnd = w.end` and `accumulate = 1` over an out
|
|
11
|
+
* pre-filled with the identity element (unless the caller asked to accumulate), so a row split across windows
|
|
12
|
+
* combines its partials: the untiered dispatch covers the window's rows [rowFirst, rowLast], while every tier
|
|
13
|
+
* dispatch covers its FULL tier range (permutation positions, not comparable with the window's node rows; a row
|
|
14
|
+
* whose arcs lie outside the window folds nothing and `finish` writes comb(out[i], identity) = out[i]).
|
|
9
15
|
*/
|
|
10
16
|
import { WebGpuGraphError } from "../errors.js";
|
|
11
17
|
import { plan1d } from "../kernel/dispatch.js";
|
|
12
|
-
import { graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from "../kernels.js";
|
|
13
|
-
import {
|
|
18
|
+
import { FILL_PARAMS, graphBindings, graphOverrides, kernelSpec, RANGE_PARAMS } from "../kernels.js";
|
|
19
|
+
import { arcCountOf, MID_TIER_LANES, rowCountOf, windowBinding } from "./core-shape.js";
|
|
20
|
+
/** The largest finite f32, 0x1.fffffep+127 (the prelude's F32_MAX): the min identity; its negation the max identity. */
|
|
21
|
+
const F32_MAX = 2 ** 128 - 2 ** 104;
|
|
22
|
+
/**
|
|
23
|
+
* The u32 bit pattern the `fill` kernel writes so every out word holds the identity element of the operator before
|
|
24
|
+
* the windowed dispatches accumulate into it (PD-8).
|
|
25
|
+
* @param op - the operator
|
|
26
|
+
* @returns the bits of 0 (sum), F32_MAX (min) or -F32_MAX (max)
|
|
27
|
+
*/
|
|
28
|
+
function identityFillWord(op) {
|
|
29
|
+
let identity = 0;
|
|
30
|
+
if (op === "min") {
|
|
31
|
+
identity = F32_MAX;
|
|
32
|
+
}
|
|
33
|
+
else if (op === "max") {
|
|
34
|
+
identity = -F32_MAX;
|
|
35
|
+
}
|
|
36
|
+
const view = new DataView(new ArrayBuffer(4));
|
|
37
|
+
view.setFloat32(0, identity, true);
|
|
38
|
+
return view.getUint32(0, true);
|
|
39
|
+
}
|
|
14
40
|
/** The identifiers a VALUE snippet may name (contract 3.11, 4.5); every other identifier is rejected textually before compose. */
|
|
15
41
|
const VALUE_SNIPPET_VOCABULARY = new Set(["row", "arc", "nbr", "weight", "v"]);
|
|
16
42
|
/**
|
|
@@ -106,30 +132,49 @@ function validateValueSnippet(snippet) {
|
|
|
106
132
|
throw new WebGpuGraphError("E_SHADER_COMPILE", `segmentedReduce: the VALUE snippet names "${token}"; the only identifiers allowed are row, arc, nbr, weight and v`, { id: "segmented-reduce", stage: "compose", slot: "VALUE", identifier: token });
|
|
107
133
|
}
|
|
108
134
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
135
|
+
/**
|
|
136
|
+
* The tiered planner: without tiers ONE `segmented-reduce` dispatch with TIER 0 over [0, n); with tiers TIER 2 over
|
|
137
|
+
* [0, hiEnd) (one workgroup per row), then TIER 1 over [hiEnd, midEnd) (WG / 32 rows per workgroup), then TIER 0
|
|
138
|
+
* over [midEnd, n), each with its own RangeParams record and the perm binding.
|
|
139
|
+
*/
|
|
140
|
+
class TieredPlanner {
|
|
111
141
|
/**
|
|
112
|
-
* Wraps
|
|
113
|
-
* @param scope - the scope the
|
|
114
|
-
* @param
|
|
115
|
-
* @param
|
|
142
|
+
* Wraps the compiled tier pipelines with the pattern they were compiled for.
|
|
143
|
+
* @param scope - the scope the pipelines were prepared in
|
|
144
|
+
* @param tiers - the compiled tiers in dispatch order (TIER 2, 1, 0; only the non-empty ones)
|
|
145
|
+
* @param fill - the `fill` pipeline of the identity pre-fill of a windowed core
|
|
146
|
+
* @param perm - the degreeOrder permutation binding (null: USE_PERM false, rows are node indices)
|
|
147
|
+
* @param hasWeights - the HAS_WEIGHTS the pipelines were compiled with
|
|
116
148
|
* @param accumulate - whether record() combines into out instead of overwriting
|
|
149
|
+
* @param identityWord - the u32 bits of the operator's identity element (identityFillWord)
|
|
117
150
|
*/
|
|
118
|
-
constructor(scope,
|
|
151
|
+
constructor(scope, tiers, fill, perm, hasWeights, accumulate, identityWord) {
|
|
152
|
+
this.dispatches = 0;
|
|
119
153
|
this.scope = scope;
|
|
120
|
-
this.
|
|
154
|
+
this.tiers = tiers;
|
|
155
|
+
this.fill = fill;
|
|
156
|
+
this.perm = perm;
|
|
121
157
|
this.hasWeights = hasWeights;
|
|
122
158
|
this.accumulate = accumulate;
|
|
159
|
+
this.identityWord = identityWord;
|
|
123
160
|
}
|
|
124
161
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
162
|
+
* Dispatches the last record() issued.
|
|
163
|
+
* @returns 0 for n = 0, else the number of non-empty tier ranges
|
|
164
|
+
*/
|
|
165
|
+
get lastDispatches() {
|
|
166
|
+
return this.dispatches;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Records the dispatches: every tier's rows over the arcs [0, arcCount), each with its own params record;
|
|
170
|
+
* nothing for n = 0 (no zero-length binding is ever created). On a windowed core: the identity fill (unless
|
|
171
|
+
* accumulating into the caller's out), then the dispatches once per window (PD-8).
|
|
127
172
|
* @param pass - the pass to record into
|
|
128
|
-
* @param core - a core with the SAME weights pattern as the one prepared (any snapshot
|
|
173
|
+
* @param core - a core with the SAME weights pattern as the one prepared (any snapshot; with tiers, the one the
|
|
174
|
+
* tiers were built from)
|
|
129
175
|
* @param out - at least 4n bytes of f32
|
|
130
176
|
*/
|
|
131
177
|
record(pass, core, out) {
|
|
132
|
-
assertNotWindowed(core, "segmentedReduce");
|
|
133
178
|
if ((core.weights !== null) !== this.hasWeights) {
|
|
134
179
|
throw new WebGpuGraphError("E_INVALID_ARGUMENT", "segmentedReduce: the core's weights pattern differs from the one prepared", {
|
|
135
180
|
argument: "core",
|
|
@@ -138,10 +183,6 @@ class ThreadPerRowPlanner {
|
|
|
138
183
|
});
|
|
139
184
|
}
|
|
140
185
|
const n = rowCountOf(core, "segmentedReduce");
|
|
141
|
-
if (n === 0) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const arcCount = core.colIdx === null ? 0 : core.colIdx.size / 4;
|
|
145
186
|
if (out.size < 4 * n) {
|
|
146
187
|
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `segmentedReduce: out holds ${out.size} bytes, ${4 * n} needed`, {
|
|
147
188
|
argument: "out",
|
|
@@ -149,37 +190,115 @@ class ThreadPerRowPlanner {
|
|
|
149
190
|
expected: `>= ${4 * n}`,
|
|
150
191
|
});
|
|
151
192
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
193
|
+
this.dispatches = 0;
|
|
194
|
+
if (n === 0) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (core.windows === null) {
|
|
198
|
+
this.recordWindow(pass, core, out, n, null, 0);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (!this.accumulate) {
|
|
202
|
+
const params = this.scope.params(FILL_PARAMS, { count: n, value: this.identityWord, mode: 0 });
|
|
203
|
+
const bound = this.fill.bind({ dst: out, P: params.binding });
|
|
204
|
+
this.fill.dispatch(pass, bound, plan1d(n, this.scope.workgroupSize, this.scope.caps), [params.offset]);
|
|
205
|
+
this.dispatches++;
|
|
206
|
+
}
|
|
207
|
+
const { windows } = core;
|
|
208
|
+
windows.forEach((w, k) => {
|
|
209
|
+
const windowed = {
|
|
210
|
+
...core,
|
|
211
|
+
colIdx: windowBinding(core, "colIdx", w),
|
|
212
|
+
weights: core.weights === null ? null : windowBinding(core, "weights", w),
|
|
213
|
+
};
|
|
214
|
+
this.recordWindow(pass, windowed, out, n, w, k + 1 < windows.length ? windows[k + 1].start : w.end);
|
|
159
215
|
});
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The tier dispatches over one arc window (or the whole core when `w` is null): every non-empty tier over its
|
|
219
|
+
* full range, except the untiered TIER 0 dispatch, which covers exactly the window's rows. Consecutive windows
|
|
220
|
+
* overlap by up to ARC_WINDOW_ALIGN - 1 arcs (the next window opens at the aligned-down end of this one), and a
|
|
221
|
+
* tier dispatch visits EVERY row, so the tiers fold [w.start, nextStart) and leave the overlap to the next
|
|
222
|
+
* window; the untiered dispatch keeps [w.start, w.end): its rows [rowFirst, rowLast] are exactly the rows whose
|
|
223
|
+
* arcs end inside this window, and the next window's rows start after them.
|
|
224
|
+
* @param pass - the pass to record into
|
|
225
|
+
* @param core - the core with the window's colIdx / weights bound
|
|
226
|
+
* @param out - the output binding
|
|
227
|
+
* @param n - the row count
|
|
228
|
+
* @param w - the window, or null for the single whole-core dispatch
|
|
229
|
+
* @param nextStart - the next window's first arc (w.end for the last window)
|
|
230
|
+
*/
|
|
231
|
+
recordWindow(pass, core, out, n, w, nextStart) {
|
|
232
|
+
const wg = this.scope.workgroupSize;
|
|
233
|
+
for (const { tier, kernel, start, end } of this.tiers) {
|
|
234
|
+
let first = start;
|
|
235
|
+
let last = tier === 0 ? n : end;
|
|
236
|
+
let arcEnd = w === null ? arcCountOf(core) : Math.min(w.end, nextStart);
|
|
237
|
+
if (w !== null && this.perm === null) {
|
|
238
|
+
first = w.rowFirst;
|
|
239
|
+
last = w.rowLast + 1;
|
|
240
|
+
arcEnd = w.end;
|
|
241
|
+
}
|
|
242
|
+
const rows = last - first;
|
|
243
|
+
if (rows <= 0) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const params = this.scope.params(RANGE_PARAMS, {
|
|
247
|
+
start: first,
|
|
248
|
+
end: last,
|
|
249
|
+
arcBase: w === null ? 0 : w.start,
|
|
250
|
+
arcEnd,
|
|
251
|
+
accumulate: w !== null || this.accumulate ? 1 : 0,
|
|
252
|
+
n,
|
|
253
|
+
});
|
|
254
|
+
const bound = kernel.bind({ ...graphBindings(core, this.perm), out, P: params.binding });
|
|
255
|
+
let rowsPerGroup = wg;
|
|
256
|
+
if (tier === 2) {
|
|
257
|
+
rowsPerGroup = 1;
|
|
258
|
+
}
|
|
259
|
+
else if (tier === 1) {
|
|
260
|
+
rowsPerGroup = wg / MID_TIER_LANES;
|
|
261
|
+
}
|
|
262
|
+
kernel.dispatch(pass, bound, plan1d(rows, rowsPerGroup, this.scope.caps), [params.offset]);
|
|
263
|
+
this.dispatches++;
|
|
264
|
+
}
|
|
162
265
|
}
|
|
163
266
|
}
|
|
164
267
|
/**
|
|
165
|
-
* Prepares the
|
|
268
|
+
* Prepares the tier pipelines for a snapshot's dummy pattern (USE_PERM = tiers !== null, HAS_WEIGHTS) and snippet:
|
|
269
|
+
* TIER 0 always; TIER 1 iff a row of degree 32..1023 exists (segmentOffsets[2] > segmentOffsets[1]); TIER 2 iff a
|
|
270
|
+
* row of degree >= 1024 exists (segmentOffsets[1] > 0). The mid tier folds 32 lanes per row, so a device whose
|
|
271
|
+
* workgroup size is below 32 is E_UNSUPPORTED { feature: "segmentedReduce.tiers" }.
|
|
166
272
|
* @param scope - the reduce scope (pipelines, pool, params writer)
|
|
167
|
-
* @param core - the core whose weights pattern selects HAS_WEIGHTS
|
|
168
|
-
* @param options - operator, snippet, tiers (
|
|
273
|
+
* @param core - the core whose weights pattern selects HAS_WEIGHTS
|
|
274
|
+
* @param options - operator, snippet, tiers (null: the single thread-per-row dispatch), accumulate
|
|
169
275
|
* @returns the planner
|
|
170
276
|
*/
|
|
171
277
|
export async function prepareSegmentedReduce(scope, core, options) {
|
|
172
|
-
if (options.tiers !== null) {
|
|
173
|
-
throw new WebGpuGraphError("E_UNSUPPORTED", "segmentedReduce: the degree tiers land at P4; pass tiers: null", {
|
|
174
|
-
feature: "segmentedReduce.tiers",
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
assertNotWindowed(core, "segmentedReduce");
|
|
178
278
|
const op = opCode(options.op);
|
|
179
279
|
validateValueSnippet(options.valueSnippet);
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
280
|
+
const { tiers } = options;
|
|
281
|
+
const perm = tiers?.perm ?? null;
|
|
282
|
+
if (tiers !== null && scope.workgroupSize < MID_TIER_LANES) {
|
|
283
|
+
throw new WebGpuGraphError("E_UNSUPPORTED", `segmentedReduce: the mid tier folds ${MID_TIER_LANES} lanes per row, more than the workgroup size ${scope.workgroupSize}`, { feature: "segmentedReduce.tiers" });
|
|
284
|
+
}
|
|
285
|
+
const ranges = tiers === null
|
|
286
|
+
? [{ tier: 0, start: 0, end: rowCountOf(core, "segmentedReduce") }]
|
|
287
|
+
: [
|
|
288
|
+
{ tier: 2, start: 0, end: tiers.segmentOffsets[1] },
|
|
289
|
+
{ tier: 1, start: tiers.segmentOffsets[1], end: tiers.segmentOffsets[2] },
|
|
290
|
+
{ tier: 0, start: tiers.segmentOffsets[2], end: tiers.segmentOffsets[4] },
|
|
291
|
+
];
|
|
292
|
+
const compiled = [];
|
|
293
|
+
for (const range of ranges) {
|
|
294
|
+
if (range.tier !== 0 && range.end <= range.start) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const overrides = { ...graphOverrides(core, perm), OP: op, TIER: range.tier };
|
|
298
|
+
const spec = kernelSpec("segmented-reduce", overrides, { VALUE: options.valueSnippet });
|
|
299
|
+
compiled.push({ ...range, kernel: await scope.pipelines.kernel(spec) });
|
|
300
|
+
}
|
|
301
|
+
const fill = await scope.pipelines.kernel(kernelSpec("fill"));
|
|
302
|
+
return new TieredPlanner(scope, compiled, fill, perm, core.weights !== null, options.accumulate === true, identityFillWord(options.op));
|
|
184
303
|
}
|
|
185
304
|
//# sourceMappingURL=segmented-reduce.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmented-reduce.js","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"segmented-reduce.js","sourceRoot":"","sources":["../../../src/primitives/segmented-reduce.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The pull SpMV primitive of spec 6 row 9 / 8.2
|
|
3
|
-
*
|
|
4
|
-
* `weight * xNorm[nbr]` over its row's in-arcs (Kahan-compensated, f32) and writing
|
|
2
|
+
* The pull SpMV primitive of spec 6 row 9 / 8.2 (P7; M8b plan PD-1 / PD-2): the `spmv-pull` module over the rows of
|
|
3
|
+
* a REVERSE adjacency, each row folding `weight * xNorm[nbr]` over its in-arcs (a two-level f32 sum) and writing
|
|
5
4
|
* `rankOut[v] = beta * pv + alpha * (sum + danglingMass * pv)`, where `pv` is `personalization[v]` under
|
|
6
5
|
* HAS_PERSONALIZATION and the uniform `P.uniformP` otherwise, and `danglingMass` is `partials[0].danglingMass`
|
|
7
6
|
* under USE_DANGLING. PageRank sets alpha to the damping, beta to 1 - alpha and USE_DANGLING; HITS and eigenvector
|
|
@@ -9,14 +8,16 @@
|
|
|
9
8
|
*
|
|
10
9
|
* It is its own registry entry rather than a `segmentedReduce` VALUE snippet (PD-1): the snippet vocabulary is
|
|
11
10
|
* `row, arc, nbr, weight, v` and cannot read `xNorm[nbr]`, and the design's binding table gives the kernel eight
|
|
12
|
-
* storage bindings of its own.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* storage bindings of its own. Without tiers it is ONE grid-stride dispatch (TIER 0, USE_PERM false: the perm slot
|
|
12
|
+
* carries the rowPtr dummy of graphBindings); with the in-degree tiers of `reverseDegreeOrder()` (P4-T5, PD-6) it
|
|
13
|
+
* is up to three dispatches over the permuted rows -- TIER 2 one workgroup per row over [0, hiEnd), TIER 1 32 lanes
|
|
14
|
+
* per row over [hiEnd, midEnd), TIER 0 grid-stride over [midEnd, n) -- each compiled only when its range is
|
|
15
|
+
* non-empty. The row and arc counts come from the core's binding sizes exactly as segmentedReduce derives them.
|
|
15
16
|
*/
|
|
16
17
|
import { type CoreBinding } from "../memory/residency.js";
|
|
17
18
|
import { type Binding } from "../types/memory.js";
|
|
19
|
+
import { type DegreeTiers } from "./core-shape.js";
|
|
18
20
|
import { type ReduceScope } from "./reduce.js";
|
|
19
|
-
import { type DegreeTiers } from "./segmented-reduce.js";
|
|
20
21
|
/** The group-1 bindings of one pull: the pre-scaled input, the output, the personalization (null binds xNorm as the dummy) and the PrPartial block whose header carries danglingMass. */
|
|
21
22
|
export interface SpmvResources {
|
|
22
23
|
readonly xNorm: Binding;
|
|
@@ -30,7 +31,7 @@ export interface SpmvCoefficients {
|
|
|
30
31
|
readonly beta: number;
|
|
31
32
|
readonly uniformP: number;
|
|
32
33
|
}
|
|
33
|
-
/** Options of prepareSpmvPull: the two variant flags, the weights binding and the tiers (
|
|
34
|
+
/** Options of prepareSpmvPull: the two variant flags, the weights binding and the in-degree tiers (null: one grid-stride dispatch). */
|
|
34
35
|
export interface SpmvPullOptions {
|
|
35
36
|
readonly personalization: boolean;
|
|
36
37
|
readonly dangling: boolean;
|
|
@@ -38,18 +39,21 @@ export interface SpmvPullOptions {
|
|
|
38
39
|
readonly weights?: Binding | null | undefined;
|
|
39
40
|
readonly tiers: DegreeTiers | null;
|
|
40
41
|
}
|
|
41
|
-
/** A prepared pull: records
|
|
42
|
+
/** A prepared pull: records one grid-stride dispatch (no tiers) or up to three tier dispatches over the rows of a reverse core into a pass. */
|
|
42
43
|
export interface SpmvPullPlanner {
|
|
43
|
-
/** Records the
|
|
44
|
+
/** Records the dispatches over rows [0, n) of `rev` writing rankOut[v] (f32) per row; nothing for n = 0. */
|
|
44
45
|
record(pass: GPUComputePassEncoder, rev: CoreBinding, resources: SpmvResources, coefficients: SpmvCoefficients): void;
|
|
45
|
-
/** Dispatches the last record() issued (
|
|
46
|
+
/** Dispatches the last record() issued (0 for n = 0; 1 without tiers; 1 to 3 with them). */
|
|
46
47
|
readonly lastDispatches: number;
|
|
47
48
|
}
|
|
48
49
|
/**
|
|
49
|
-
* Prepares the
|
|
50
|
+
* Prepares the pull pipelines for a reverse core's weights pattern and the two variant flags: TIER 0 always
|
|
51
|
+
* (USE_PERM = tiers !== null); TIER 1 iff a row of in-degree 32..1023 exists (segmentOffsets[2] >
|
|
52
|
+
* segmentOffsets[1]); TIER 2 iff a row of in-degree >= 1024 exists (segmentOffsets[1] > 0). The mid tier folds 32
|
|
53
|
+
* lanes per row, so a device whose workgroup size is below 32 is E_UNSUPPORTED { feature: "spmvPull.tiers" }.
|
|
50
54
|
* @param scope - the reduce scope (pipelines, params writer)
|
|
51
|
-
* @param rev - the reverse core whose weights pattern selects HAS_WEIGHTS
|
|
52
|
-
* @param options - personalization, dangling, weights, tiers (
|
|
55
|
+
* @param rev - the reverse core whose weights pattern selects HAS_WEIGHTS
|
|
56
|
+
* @param options - personalization, dangling, weights, tiers (null: the single grid-stride dispatch)
|
|
53
57
|
* @returns the planner
|
|
54
58
|
*/
|
|
55
59
|
export declare function prepareSpmvPull(scope: ReduceScope, rev: CoreBinding, options: SpmvPullOptions): Promise<SpmvPullPlanner>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spmv.d.ts","sourceRoot":"","sources":["../../../src/primitives/spmv.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spmv.d.ts","sourceRoot":"","sources":["../../../src/primitives/spmv.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAiC,KAAK,WAAW,EAA8B,MAAM,iBAAiB,CAAC;AAC9G,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,yLAAyL;AACzL,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,OAAO,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC7B;AAED,uIAAuI;AACvI,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,iHAAiH;IACjH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;CACtC;AAED,+IAA+I;AAC/I,MAAM,WAAW,eAAe;IAC5B,4GAA4G;IAC5G,MAAM,CACF,IAAI,EAAE,qBAAqB,EAC3B,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,aAAa,EACxB,YAAY,EAAE,gBAAgB,GAC/B,IAAI,CAAC;IACR,4FAA4F;IAC5F,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AA0GD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACjC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,eAAe,GACzB,OAAO,CAAC,eAAe,CAAC,CAiC1B"}
|