sync 91d990483a17
Browse files- README.md +72 -14
- build/webgpu/bench.json +1214 -5
- build/webgpu/manifest.json +0 -0
- build/webgpu/metadata.json +104 -18
- build/webgpu/scan-block-prefix-u32.wgsl.jinja +44 -0
- build/webgpu/test.json +0 -0
- build/webgpu/unique-axis-compact-sort.wgsl.jinja +31 -21
- build/webgpu/unique-axis-dedup.wgsl.jinja +22 -20
- build/webgpu/unique-axis-hash.wgsl.jinja +32 -7
- build/webgpu/unique-axis-scalar-inverse.wgsl.jinja +109 -0
- build/webgpu/unique-axis-scalar-ranks.wgsl.jinja +7 -0
- build/webgpu/unique-axis-scatter.wgsl.jinja +7 -10
- build/webgpu/unique-axis.wgsl.jinja +38 -54
- build/webgpu/unique-compact-sort.wgsl.jinja +82 -26
- build/webgpu/unique-flag-block-scan.wgsl.jinja +20 -0
- build/webgpu/unique-flat-metadata.wgsl.jinja +129 -0
- build/webgpu/unique-global-sort-exchange.wgsl.jinja +36 -0
- build/webgpu/unique-global-sort-output.wgsl.jinja +9 -0
- build/webgpu/unique-global-sort-shared.wgsl.jinja +69 -0
- build/webgpu/unique-hash-build.wgsl.jinja +49 -4
- build/webgpu/unique-hash-collect.wgsl.jinja +7 -7
- build/webgpu/unique-hash-init.wgsl.jinja +2 -2
- build/webgpu/unique-hash-mark.wgsl.jinja +52 -3
- build/webgpu/unique-hash-sort-collected-key-only.wgsl.jinja +2 -2
- build/webgpu/unique-scalar-compact.wgsl.jinja +60 -0
- build/webgpu/unique-scalar-metadata.wgsl.jinja +122 -0
- build/webgpu/unique-scalar-output.wgsl.jinja +20 -0
- build/webgpu/unique-single-class.wgsl.jinja +32 -0
- build/webgpu/unique.wgsl.jinja +14 -8
README.md
CHANGED
|
@@ -12,24 +12,24 @@ tags:
|
|
| 12 |
|
| 13 |
## Description
|
| 14 |
|
| 15 |
-
Finds unique values or subtensors along an optional `axis`. Without an axis, `X` is flattened; results are sorted or retain first-occurrence order. Sub-32-bit integers and booleans use lossless widened 32-bit storage. Metadata outputs remain logical int64 but use lossless uint32 storage because all values are bounded by an addressable tensor extent.
|
| 16 |
|
| 17 |
See the [ONNX `Unique` spec](https://onnx.ai/onnx/operators/onnx__Unique.html) for the reference semantics.
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
-
| Name |
|
| 22 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
-
| `
|
| 24 |
|
| 25 |
## Outputs
|
| 26 |
|
| 27 |
-
| Name |
|
| 28 |
| --- | --- | --- | --- | --- | --- | --- | --- |
|
| 29 |
-
| `
|
| 30 |
-
| `indices` |
|
| 31 |
-
| `inverse_indices` |
|
| 32 |
-
| `counts` |
|
| 33 |
|
| 34 |
## Attributes
|
| 35 |
|
|
@@ -37,8 +37,8 @@ Attributes and default values (overridable per request):
|
|
| 37 |
|
| 38 |
| Attribute | Default | Description |
|
| 39 |
| --- | --- | --- |
|
| 40 |
-
| `sorted` | `1` | Whether to sort unique elements in ascending order before output; 1 (default) sorts, 0 retains first-occurrence order. |
|
| 41 |
| `axis` | — | Optional axis along which unique subtensors are identified. Negative values count from the back; when omitted, the input is flattened. |
|
|
|
|
| 42 |
|
| 43 |
## Type constraints
|
| 44 |
|
|
@@ -47,37 +47,95 @@ Attributes and default values (overridable per request):
|
|
| 47 |
| `T` | `float32`, `float16`, `uint32`, `int32`, `int16`, `uint8`, `int8`, `bool` |
|
| 48 |
| `I` | `int64` |
|
| 49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
## Files
|
| 51 |
|
| 52 |
-
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, provenance)
|
| 53 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 54 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 55 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
|
|
|
| 56 |
- [`unique-axis-compact-sort.wgsl.jinja`](build/webgpu/unique-axis-compact-sort.wgsl.jinja)
|
| 57 |
- [`unique-axis-dedup.wgsl.jinja`](build/webgpu/unique-axis-dedup.wgsl.jinja)
|
| 58 |
- [`unique-axis-hash.wgsl.jinja`](build/webgpu/unique-axis-hash.wgsl.jinja)
|
|
|
|
|
|
|
| 59 |
- [`unique-axis-scatter.wgsl.jinja`](build/webgpu/unique-axis-scatter.wgsl.jinja)
|
| 60 |
- [`unique-axis.wgsl.jinja`](build/webgpu/unique-axis.wgsl.jinja)
|
| 61 |
- [`unique-compact-sort.wgsl.jinja`](build/webgpu/unique-compact-sort.wgsl.jinja)
|
| 62 |
- [`unique-dedup.wgsl.jinja`](build/webgpu/unique-dedup.wgsl.jinja)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
- [`unique-hash-build.wgsl.jinja`](build/webgpu/unique-hash-build.wgsl.jinja)
|
| 64 |
- [`unique-hash-collect.wgsl.jinja`](build/webgpu/unique-hash-collect.wgsl.jinja)
|
| 65 |
- [`unique-hash-init.wgsl.jinja`](build/webgpu/unique-hash-init.wgsl.jinja)
|
| 66 |
- [`unique-hash-mark.wgsl.jinja`](build/webgpu/unique-hash-mark.wgsl.jinja)
|
| 67 |
- [`unique-hash-sort-collected-key-only.wgsl.jinja`](build/webgpu/unique-hash-sort-collected-key-only.wgsl.jinja)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
- [`unique.wgsl.jinja`](build/webgpu/unique.wgsl.jinja)
|
| 69 |
|
| 70 |
## Use with `@huggingface/kernels`
|
| 71 |
|
| 72 |
-
|
|
|
|
|
|
|
| 73 |
|
| 74 |
-
|
| 75 |
|
| 76 |
-
|
| 77 |
|
| 78 |
-
|
| 79 |
|
| 80 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
|
|
|
| 81 |
|
| 82 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 83 |
|
|
|
|
| 12 |
|
| 13 |
## Description
|
| 14 |
|
| 15 |
+
Finds unique values or subtensors along an optional `axis`. Without an axis, `X` is flattened; results are sorted or retain first-occurrence order. Sub-32-bit integers and booleans use lossless widened 32-bit storage. Metadata outputs remain logical int64 but use lossless uint32 storage because all values are bounded by an addressable tensor extent. Exact data-dependent output shapes must be supplied. ONNX-permitted uint16, 64-bit, string, and complex inputs are unsupported by this package.
|
| 16 |
|
| 17 |
See the [ONNX `Unique` spec](https://onnx.ai/onnx/operators/onnx__Unique.html) for the reference semantics.
|
| 18 |
|
| 19 |
## Inputs
|
| 20 |
|
| 21 |
+
| Name | Upstream name | Logical dtype | Rank | Shape | Description | Presence |
|
| 22 |
| --- | --- | --- | --- | --- | --- | --- |
|
| 23 |
+
| `x` | `X` | `T` | — | — | The N-D input tensor from which unique values or subtensors are extracted. When `axis` is omitted, tensors of any rank are flattened in row-major order. | required |
|
| 24 |
|
| 25 |
## Outputs
|
| 26 |
|
| 27 |
+
| Name | Upstream name | Logical dtype | WebGPU storage | Rank | Shape | Description | Presence |
|
| 28 |
| --- | --- | --- | --- | --- | --- | --- | --- |
|
| 29 |
+
| `y` | `Y` | `T` | runtime-selected; narrow integers and bool use 32-bit slots | derived | — | Tensor containing all unique values or subtensors of X, sorted or in first-occurrence order. | required |
|
| 30 |
+
| `indices` | — | `I` | `uint32` | `1` | — | Optional logical int64 indices of each `Y` value or slice's first occurrence in `X`; stored as bounded uint32 values by WebGPU. | optional |
|
| 31 |
+
| `inverse_indices` | — | `I` | `uint32` | `1` | — | Optional logical int64 mapping from each flattened input value, or each input-axis slice, to its corresponding index in `Y`; stored as bounded uint32 values by WebGPU. | optional |
|
| 32 |
+
| `counts` | — | `I` | `uint32` | `1` | — | Optional logical int64 occurrence count for each unique value or slice in `Y`; stored as bounded uint32 values by WebGPU. | optional |
|
| 33 |
|
| 34 |
## Attributes
|
| 35 |
|
|
|
|
| 37 |
|
| 38 |
| Attribute | Default | Description |
|
| 39 |
| --- | --- | --- |
|
|
|
|
| 40 |
| `axis` | — | Optional axis along which unique subtensors are identified. Negative values count from the back; when omitted, the input is flattened. |
|
| 41 |
+
| `sorted` | `1` | Whether to sort unique elements in ascending order before output; 1 (default) sorts, 0 retains first-occurrence order. |
|
| 42 |
|
| 43 |
## Type constraints
|
| 44 |
|
|
|
|
| 47 |
| `T` | `float32`, `float16`, `uint32`, `int32`, `int16`, `uint8`, `int8`, `bool` |
|
| 48 |
| `I` | `int64` |
|
| 49 |
|
| 50 |
+
## Implementation variants
|
| 51 |
+
|
| 52 |
+
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 53 |
+
|
| 54 |
+
- `single_class_y` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 55 |
+
- `scalar_hash_parallel_y_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 56 |
+
- `scalar_hash_parallel_y_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 57 |
+
- `single_class_indices` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 58 |
+
- `scalar_hash_parallel_indices_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 59 |
+
- `scalar_hash_parallel_indices_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 60 |
+
- `single_class_inverse` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 61 |
+
- `scalar_hash_parallel_inverse_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 62 |
+
- `scalar_hash_parallel_inverse_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 63 |
+
- `single_class_indices_inverse` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 64 |
+
- `scalar_hash_parallel_indices_inverse_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 65 |
+
- `scalar_hash_parallel_indices_inverse_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 66 |
+
- `single_class_counts` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 67 |
+
- `scalar_hash_parallel_counts_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 68 |
+
- `scalar_hash_parallel_counts_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 69 |
+
- `single_class_indices_counts` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 70 |
+
- `scalar_hash_parallel_indices_counts_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 71 |
+
- `scalar_hash_parallel_indices_counts_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 72 |
+
- `single_class_inverse_counts` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 73 |
+
- `scalar_hash_parallel_inverse_counts_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 74 |
+
- `scalar_hash_parallel_inverse_counts_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 75 |
+
- `single_class_indices_inverse_counts` — Copy the first representative and materialize requested metadata when the exact output contract proves there is one distinct class.
|
| 76 |
+
- `scalar_hash_parallel_indices_inverse_counts_unsorted` — Hash first occurrences, scan flag blocks in parallel, and scatter scalar representatives in input order with only the requested metadata.
|
| 77 |
+
- `scalar_hash_parallel_indices_inverse_counts_sorted` — Hash and compact scalar representatives in parallel, sort their order with shared and global bitonic stages, and materialize only the requested metadata.
|
| 78 |
+
- `flat_parallel_metadata_indices` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 79 |
+
- `flat_parallel_metadata_inverse` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 80 |
+
- `flat_parallel_metadata_indices_inverse` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 81 |
+
- `flat_parallel_metadata_counts` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 82 |
+
- `flat_parallel_metadata_indices_counts` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 83 |
+
- `flat_parallel_metadata_inverse_counts` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 84 |
+
- `flat_parallel_metadata_all` — Builds the unique values with the parallel dedup and compaction passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 85 |
+
- `flat_hash_metadata_indices` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 86 |
+
- `flat_hash_metadata_inverse` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 87 |
+
- `flat_hash_metadata_indices_inverse` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 88 |
+
- `flat_hash_metadata_counts` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 89 |
+
- `flat_hash_metadata_indices_counts` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 90 |
+
- `flat_hash_metadata_inverse_counts` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 91 |
+
- `flat_hash_metadata_all` — Builds the unique values with the hash-set dedup passes, then resolves every metadata output from the finished result: one thread per input element for the bucket and the first-occurrence store, one thread per unique value for the tally.
|
| 92 |
+
|
| 93 |
## Files
|
| 94 |
|
| 95 |
+
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 96 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 97 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 98 |
- [`bench.json`](build/webgpu/bench.json) — benchmark + tuning cases
|
| 99 |
+
- [`scan-block-prefix-u32.wgsl.jinja`](build/webgpu/scan-block-prefix-u32.wgsl.jinja)
|
| 100 |
- [`unique-axis-compact-sort.wgsl.jinja`](build/webgpu/unique-axis-compact-sort.wgsl.jinja)
|
| 101 |
- [`unique-axis-dedup.wgsl.jinja`](build/webgpu/unique-axis-dedup.wgsl.jinja)
|
| 102 |
- [`unique-axis-hash.wgsl.jinja`](build/webgpu/unique-axis-hash.wgsl.jinja)
|
| 103 |
+
- [`unique-axis-scalar-inverse.wgsl.jinja`](build/webgpu/unique-axis-scalar-inverse.wgsl.jinja)
|
| 104 |
+
- [`unique-axis-scalar-ranks.wgsl.jinja`](build/webgpu/unique-axis-scalar-ranks.wgsl.jinja)
|
| 105 |
- [`unique-axis-scatter.wgsl.jinja`](build/webgpu/unique-axis-scatter.wgsl.jinja)
|
| 106 |
- [`unique-axis.wgsl.jinja`](build/webgpu/unique-axis.wgsl.jinja)
|
| 107 |
- [`unique-compact-sort.wgsl.jinja`](build/webgpu/unique-compact-sort.wgsl.jinja)
|
| 108 |
- [`unique-dedup.wgsl.jinja`](build/webgpu/unique-dedup.wgsl.jinja)
|
| 109 |
+
- [`unique-flag-block-scan.wgsl.jinja`](build/webgpu/unique-flag-block-scan.wgsl.jinja)
|
| 110 |
+
- [`unique-flat-metadata.wgsl.jinja`](build/webgpu/unique-flat-metadata.wgsl.jinja)
|
| 111 |
+
- [`unique-global-sort-exchange.wgsl.jinja`](build/webgpu/unique-global-sort-exchange.wgsl.jinja)
|
| 112 |
+
- [`unique-global-sort-output.wgsl.jinja`](build/webgpu/unique-global-sort-output.wgsl.jinja)
|
| 113 |
+
- [`unique-global-sort-shared.wgsl.jinja`](build/webgpu/unique-global-sort-shared.wgsl.jinja)
|
| 114 |
- [`unique-hash-build.wgsl.jinja`](build/webgpu/unique-hash-build.wgsl.jinja)
|
| 115 |
- [`unique-hash-collect.wgsl.jinja`](build/webgpu/unique-hash-collect.wgsl.jinja)
|
| 116 |
- [`unique-hash-init.wgsl.jinja`](build/webgpu/unique-hash-init.wgsl.jinja)
|
| 117 |
- [`unique-hash-mark.wgsl.jinja`](build/webgpu/unique-hash-mark.wgsl.jinja)
|
| 118 |
- [`unique-hash-sort-collected-key-only.wgsl.jinja`](build/webgpu/unique-hash-sort-collected-key-only.wgsl.jinja)
|
| 119 |
+
- [`unique-scalar-compact.wgsl.jinja`](build/webgpu/unique-scalar-compact.wgsl.jinja)
|
| 120 |
+
- [`unique-scalar-metadata.wgsl.jinja`](build/webgpu/unique-scalar-metadata.wgsl.jinja)
|
| 121 |
+
- [`unique-scalar-output.wgsl.jinja`](build/webgpu/unique-scalar-output.wgsl.jinja)
|
| 122 |
+
- [`unique-single-class.wgsl.jinja`](build/webgpu/unique-single-class.wgsl.jinja)
|
| 123 |
- [`unique.wgsl.jinja`](build/webgpu/unique.wgsl.jinja)
|
| 124 |
|
| 125 |
## Use with `@huggingface/kernels`
|
| 126 |
|
| 127 |
+
```sh
|
| 128 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.2
|
| 129 |
+
```
|
| 130 |
|
| 131 |
+
Outputs with inferable metadata are allocated automatically. Explicit `outputs` entries request optional results or provide metadata that cannot be inferred from the supplied inputs and attributes.
|
| 132 |
|
| 133 |
+
This example supplies explicit metadata for:
|
| 134 |
|
| 135 |
+
- `y`
|
| 136 |
|
| 137 |
The `version: 1` option selects the published kernel contract; it is independent of any operator opset, contrib `since_version`, or model version.
|
| 138 |
+
It follows the `v1` branch as fixes land. To pin exact artifact bytes, pass a 40-character commit `revision` instead of `version`.
|
| 139 |
|
| 140 |
Replace each `*Data` placeholder with a typed array containing the corresponding input data.
|
| 141 |
|
build/webgpu/bench.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
{
|
| 2 |
-
"op": "ai.onnx.Unique",
|
| 3 |
"cases": [
|
| 4 |
{
|
| 5 |
"name": "int32-64k-moderate-distinct-sorted",
|
|
@@ -116,9 +115,12 @@
|
|
| 116 |
"preset": "smoke",
|
| 117 |
"attrs": { "axis": 0, "sorted": 1 },
|
| 118 |
"inputs": {
|
| 119 |
-
"x": { "dtype": "float32", "shape": [4096, 256], "
|
| 120 |
},
|
| 121 |
"outputs": { "y": { "dtype": "float32", "shape": [4096, 256] } },
|
|
|
|
|
|
|
|
|
|
| 122 |
"bench": {
|
| 123 |
"primary": true,
|
| 124 |
"metrics": [
|
|
@@ -130,6 +132,27 @@
|
|
| 130 |
]
|
| 131 |
}
|
| 132 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
{
|
| 134 |
"name": "axis_hash_split_scatter_unsorted_zero_fills_tail",
|
| 135 |
"preset": "smoke",
|
|
@@ -206,7 +229,7 @@
|
|
| 206 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + dim(shapes.y, 0))" }] }
|
| 207 |
},
|
| 208 |
{
|
| 209 |
-
"name": "axis0-f32-70000x1-above-hash-capacity
|
| 210 |
"preset": "stress",
|
| 211 |
"attrs": { "axis": 0, "sorted": 1 },
|
| 212 |
"inputs": {
|
|
@@ -217,7 +240,10 @@
|
|
| 217 |
}
|
| 218 |
},
|
| 219 |
"outputs": { "y": { "dtype": "float32", "shape": [70000, 1] } },
|
| 220 |
-
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + dim(shapes.y, 0))" }] }
|
|
|
|
|
|
|
|
|
|
| 221 |
},
|
| 222 |
{
|
| 223 |
"name": "int32-262144-Y4096-token-vocab-sorted",
|
|
@@ -242,6 +268,1189 @@
|
|
| 242 |
"inputs": { "x": { "dtype": "int32", "shape": [8192], "dist": "linearMod", "mod": 8192 } },
|
| 243 |
"outputs": { "y": { "dtype": "int32", "shape": [8192] } },
|
| 244 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
}
|
| 246 |
-
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
}
|
|
|
|
| 1 |
{
|
|
|
|
| 2 |
"cases": [
|
| 3 |
{
|
| 4 |
"name": "int32-64k-moderate-distinct-sorted",
|
|
|
|
| 115 |
"preset": "smoke",
|
| 116 |
"attrs": { "axis": 0, "sorted": 1 },
|
| 117 |
"inputs": {
|
| 118 |
+
"x": { "dtype": "float32", "shape": [4096, 256], "data": { "kind": "linspace", "start": 8.0, "end": -8.0 } }
|
| 119 |
},
|
| 120 |
"outputs": { "y": { "dtype": "float32", "shape": [4096, 256] } },
|
| 121 |
+
"provenance": {
|
| 122 |
+
"notes": "Descending values give 4096 distinct 256-element rows. Lexicographic sorting reverses row order while retaining each row's column order."
|
| 123 |
+
},
|
| 124 |
"bench": {
|
| 125 |
"primary": true,
|
| 126 |
"metrics": [
|
|
|
|
| 132 |
]
|
| 133 |
}
|
| 134 |
},
|
| 135 |
+
{
|
| 136 |
+
"name": "axis0-f32-4096x256-1024-distinct-random-rows",
|
| 137 |
+
"preset": "smoke",
|
| 138 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 139 |
+
"inputs": {
|
| 140 |
+
"x": { "dtype": "float32", "shape": [4096, 256], "dist": "uniform", "seed": 1531, "scale": 8, "offset": 0 }
|
| 141 |
+
},
|
| 142 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1024, 256] } },
|
| 143 |
+
"provenance": {
|
| 144 |
+
"notes": "Input contains four copies of each of 1024 distinct 256-element rows. Output contains the distinct rows in lexicographic order."
|
| 145 |
+
},
|
| 146 |
+
"bench": {
|
| 147 |
+
"metrics": [
|
| 148 |
+
{
|
| 149 |
+
"type": "bandwidth",
|
| 150 |
+
"name": "logical input/output bytes",
|
| 151 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 152 |
+
}
|
| 153 |
+
]
|
| 154 |
+
}
|
| 155 |
+
},
|
| 156 |
{
|
| 157 |
"name": "axis_hash_split_scatter_unsorted_zero_fills_tail",
|
| 158 |
"preset": "smoke",
|
|
|
|
| 229 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + dim(shapes.y, 0))" }] }
|
| 230 |
},
|
| 231 |
{
|
| 232 |
+
"name": "axis0-f32-70000x1-above-old-hash-capacity",
|
| 233 |
"preset": "stress",
|
| 234 |
"attrs": { "axis": 0, "sorted": 1 },
|
| 235 |
"inputs": {
|
|
|
|
| 240 |
}
|
| 241 |
},
|
| 242 |
"outputs": { "y": { "dtype": "float32", "shape": [70000, 1] } },
|
| 243 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + dim(shapes.y, 0))" }] },
|
| 244 |
+
"provenance": {
|
| 245 |
+
"notes": "A 70,000-row float tensor with every row distinct exercises large-axis hash deduplication and sorted emission."
|
| 246 |
+
}
|
| 247 |
},
|
| 248 |
{
|
| 249 |
"name": "int32-262144-Y4096-token-vocab-sorted",
|
|
|
|
| 268 |
"inputs": { "x": { "dtype": "int32", "shape": [8192], "dist": "linearMod", "mod": 8192 } },
|
| 269 |
"outputs": { "y": { "dtype": "int32", "shape": [8192] } },
|
| 270 |
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"name": "int32-4096-128-distinct-inverse-metadata",
|
| 274 |
+
"provenance": {
|
| 275 |
+
"notes": "A 4,096-token stream with 128 distinct values exercises parallel local deduplication while producing an inverse map for vocabulary compaction."
|
| 276 |
+
},
|
| 277 |
+
"preset": "smoke",
|
| 278 |
+
"attrs": { "sorted": 0 },
|
| 279 |
+
"inputs": { "x": { "dtype": "int32", "shape": [4096], "dist": "linearMod", "mod": 128 } },
|
| 280 |
+
"outputs": {
|
| 281 |
+
"y": { "dtype": "int32", "shape": [128] },
|
| 282 |
+
"inverse_indices": { "dtype": "uint32", "shape": [4096] }
|
| 283 |
+
},
|
| 284 |
+
"bench": { "primary": true, "metrics": [{ "type": "bandwidth", "value": "12 * numel(shapes.x)" }] }
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"name": "int32-65536-512-distinct-inverse-metadata-hash",
|
| 288 |
+
"provenance": {
|
| 289 |
+
"notes": "A 65,536-token stream with 512 distinct values exercises hash-set deduplication while producing an inverse map for vocabulary compaction."
|
| 290 |
+
},
|
| 291 |
+
"preset": "smoke",
|
| 292 |
+
"attrs": { "sorted": 0 },
|
| 293 |
+
"inputs": { "x": { "dtype": "int32", "shape": [65536], "dist": "linearMod", "mod": 512 } },
|
| 294 |
+
"outputs": {
|
| 295 |
+
"y": { "dtype": "int32", "shape": [512] },
|
| 296 |
+
"inverse_indices": { "dtype": "uint32", "shape": [65536] }
|
| 297 |
+
},
|
| 298 |
+
"bench": { "primary": true, "metrics": [{ "type": "bandwidth", "value": "12 * numel(shapes.x)" }] }
|
| 299 |
+
},
|
| 300 |
+
{
|
| 301 |
+
"name": "axis0-int32-512x16-record-table-shared-markers",
|
| 302 |
+
"provenance": {
|
| 303 |
+
"notes": "A fixed-width record table whose shared marker fields sit at the four positions an evenly-spaced four-sample prefilter reads, and whose identifier does not. Every pair of rows therefore agrees on the prefilter and only the exact comparator separates them."
|
| 304 |
+
},
|
| 305 |
+
"attrs": { "axis": 0, "sorted": 0 },
|
| 306 |
+
"inputs": {
|
| 307 |
+
"x": {
|
| 308 |
+
"dtype": "int32",
|
| 309 |
+
"shape": [512, 16],
|
| 310 |
+
"data": { "kind": "values", "values": { "$ref": "#/fixtureArrays/axis_record_table_marker_collision" } }
|
| 311 |
+
}
|
| 312 |
+
},
|
| 313 |
+
"outputs": { "y": { "dtype": "int32", "shape": [512, 16], "dist": "empty" } }
|
| 314 |
+
},
|
| 315 |
+
{
|
| 316 |
+
"name": "flat-i32-70000-distinct-above-old-capacity",
|
| 317 |
+
"preset": "stress",
|
| 318 |
+
"provenance": {
|
| 319 |
+
"notes": "A flat 70,000-element float tensor with every value distinct exercises large-output hash deduplication and sorted emission."
|
| 320 |
+
},
|
| 321 |
+
"attrs": { "sorted": 1 },
|
| 322 |
+
"inputs": {
|
| 323 |
+
"x": { "dtype": "int32", "shape": [70000], "data": { "kind": "linspace", "start": -35000, "end": 34999 } }
|
| 324 |
+
},
|
| 325 |
+
"outputs": { "y": { "dtype": "int32", "shape": [70000], "dist": "empty" } },
|
| 326 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 327 |
+
},
|
| 328 |
+
{
|
| 329 |
+
"name": "axis0-f32-16384x1-inverse-metadata",
|
| 330 |
+
"preset": "stress",
|
| 331 |
+
"provenance": {
|
| 332 |
+
"notes": "A float axis request with an inverse map and more distinct rows than the ordered-map head cache holds, so the comparator reads its keys back from the order buffer instead."
|
| 333 |
+
},
|
| 334 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 335 |
+
"inputs": {
|
| 336 |
+
"x": {
|
| 337 |
+
"dtype": "float32",
|
| 338 |
+
"shape": [16384, 1],
|
| 339 |
+
"data": { "kind": "linspace", "start": -8192.0, "end": 8191.0 }
|
| 340 |
+
}
|
| 341 |
+
},
|
| 342 |
+
"outputs": {
|
| 343 |
+
"y": { "dtype": "float32", "shape": [16384, 1], "dist": "empty" },
|
| 344 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16384], "dist": "empty" }
|
| 345 |
+
}
|
| 346 |
+
},
|
| 347 |
+
{
|
| 348 |
+
"name": "flat-i32-1049600-1024-classes-label-raster",
|
| 349 |
+
"preset": "stress",
|
| 350 |
+
"provenance": {
|
| 351 |
+
"notes": "A 1,049,600-element class-label raster with 1,024 classes exercises large-input flat deduplication in first-occurrence order."
|
| 352 |
+
},
|
| 353 |
+
"attrs": { "sorted": 0 },
|
| 354 |
+
"inputs": {
|
| 355 |
+
"x": { "dtype": "int32", "shape": [1025, 1024], "data": { "kind": "linspace", "start": 0, "end": 1023 } }
|
| 356 |
+
},
|
| 357 |
+
"outputs": { "y": { "dtype": "int32", "shape": [1024], "dist": "empty" } }
|
| 358 |
+
},
|
| 359 |
+
{
|
| 360 |
+
"name": "flat-i32-70000-distinct-unsorted-first-order",
|
| 361 |
+
"preset": "stress",
|
| 362 |
+
"provenance": {
|
| 363 |
+
"source": "synthetic",
|
| 364 |
+
"notes": "Descending distinct integers measure large-output hash deduplication while preserving first-occurrence order for sorted=0."
|
| 365 |
+
},
|
| 366 |
+
"attrs": { "sorted": 0 },
|
| 367 |
+
"inputs": {
|
| 368 |
+
"x": { "dtype": "int32", "shape": [70000], "data": { "kind": "linspace", "start": 34999, "end": -35000 } }
|
| 369 |
+
},
|
| 370 |
+
"outputs": { "y": { "dtype": "int32", "shape": [70000], "dist": "empty" } },
|
| 371 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 372 |
+
},
|
| 373 |
+
{
|
| 374 |
+
"name": "axis-scalar-f32-inverse-descending",
|
| 375 |
+
"preset": "stress",
|
| 376 |
+
"provenance": {
|
| 377 |
+
"notes": "Scalar-axis inverse map: descending. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 378 |
+
},
|
| 379 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 380 |
+
"inputs": {
|
| 381 |
+
"x": {
|
| 382 |
+
"dtype": "float32",
|
| 383 |
+
"shape": [16384, 1],
|
| 384 |
+
"data": { "kind": "linspace", "start": 8191.0, "end": -8192.0 }
|
| 385 |
+
}
|
| 386 |
+
},
|
| 387 |
+
"outputs": {
|
| 388 |
+
"y": { "dtype": "float32", "shape": [16384, 1], "dist": "empty" },
|
| 389 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16384], "dist": "empty" }
|
| 390 |
+
}
|
| 391 |
+
},
|
| 392 |
+
{
|
| 393 |
+
"name": "axis-scalar-f32-inverse-duplicate64",
|
| 394 |
+
"preset": "stress",
|
| 395 |
+
"provenance": {
|
| 396 |
+
"notes": "Scalar-axis inverse map: duplicate64. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 397 |
+
},
|
| 398 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 399 |
+
"inputs": {
|
| 400 |
+
"x": {
|
| 401 |
+
"dtype": "float32",
|
| 402 |
+
"shape": [4096, 1],
|
| 403 |
+
"data": {
|
| 404 |
+
"kind": "cycle",
|
| 405 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-duplicate64_input_x" }
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
},
|
| 409 |
+
"outputs": {
|
| 410 |
+
"y": { "dtype": "float32", "shape": [64, 1], "dist": "empty" },
|
| 411 |
+
"inverse_indices": { "dtype": "uint32", "shape": [4096], "dist": "empty" }
|
| 412 |
+
}
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
"name": "axis-scalar-f32-inverse-duplicate64-unsorted",
|
| 416 |
+
"preset": "stress",
|
| 417 |
+
"provenance": {
|
| 418 |
+
"notes": "Scalar-axis inverse map: duplicate64-unsorted. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 419 |
+
},
|
| 420 |
+
"attrs": { "axis": 0, "sorted": 0 },
|
| 421 |
+
"inputs": {
|
| 422 |
+
"x": {
|
| 423 |
+
"dtype": "float32",
|
| 424 |
+
"shape": [4096, 1],
|
| 425 |
+
"data": {
|
| 426 |
+
"kind": "cycle",
|
| 427 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-duplicate64_input_x" }
|
| 428 |
+
}
|
| 429 |
+
}
|
| 430 |
+
},
|
| 431 |
+
"outputs": {
|
| 432 |
+
"y": { "dtype": "float32", "shape": [64, 1], "dist": "empty" },
|
| 433 |
+
"inverse_indices": { "dtype": "uint32", "shape": [4096], "dist": "empty" }
|
| 434 |
+
}
|
| 435 |
+
},
|
| 436 |
+
{
|
| 437 |
+
"name": "axis-scalar-f32-inverse-nan-prefix",
|
| 438 |
+
"preset": "stress",
|
| 439 |
+
"provenance": {
|
| 440 |
+
"notes": "Scalar-axis inverse map: nan-prefix. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 441 |
+
},
|
| 442 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 443 |
+
"inputs": {
|
| 444 |
+
"x": {
|
| 445 |
+
"dtype": "float32",
|
| 446 |
+
"shape": [8192, 1],
|
| 447 |
+
"data": { "kind": "cycle", "values": [5.0, "NaN", 1.0, "NaN", -2.0, "NaN", 3.0, 5.0] }
|
| 448 |
+
}
|
| 449 |
+
},
|
| 450 |
+
"outputs": {
|
| 451 |
+
"y": { "dtype": "float32", "shape": [4, 1], "dist": "empty" },
|
| 452 |
+
"inverse_indices": { "dtype": "uint32", "shape": [8192], "dist": "empty" }
|
| 453 |
+
}
|
| 454 |
+
},
|
| 455 |
+
{
|
| 456 |
+
"name": "axis-scalar-f32-inverse-nan-prefix-unsorted",
|
| 457 |
+
"preset": "stress",
|
| 458 |
+
"provenance": {
|
| 459 |
+
"notes": "Scalar-axis inverse map: nan-prefix-unsorted. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 460 |
+
},
|
| 461 |
+
"attrs": { "axis": 0, "sorted": 0 },
|
| 462 |
+
"inputs": {
|
| 463 |
+
"x": {
|
| 464 |
+
"dtype": "float32",
|
| 465 |
+
"shape": [8192, 1],
|
| 466 |
+
"data": { "kind": "cycle", "values": [5.0, "NaN", 1.0, "NaN", -2.0, "NaN", 3.0, 5.0] }
|
| 467 |
+
}
|
| 468 |
+
},
|
| 469 |
+
"outputs": {
|
| 470 |
+
"y": { "dtype": "float32", "shape": [4, 1], "dist": "empty" },
|
| 471 |
+
"inverse_indices": { "dtype": "uint32", "shape": [8192], "dist": "empty" }
|
| 472 |
+
}
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"name": "axis-scalar-f32-inverse-hybrid-floor",
|
| 476 |
+
"preset": "stress",
|
| 477 |
+
"provenance": {
|
| 478 |
+
"notes": "Scalar-axis inverse map: hybrid-floor. Checks the hash/rank route with non-identity ordering, duplicate-rich or history-dependent NaN inputs."
|
| 479 |
+
},
|
| 480 |
+
"attrs": { "axis": 0, "sorted": 1 },
|
| 481 |
+
"inputs": {
|
| 482 |
+
"x": {
|
| 483 |
+
"dtype": "float32",
|
| 484 |
+
"shape": [4096, 1],
|
| 485 |
+
"data": {
|
| 486 |
+
"kind": "cycle",
|
| 487 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-hybrid-floor_input_x" }
|
| 488 |
+
}
|
| 489 |
+
}
|
| 490 |
+
},
|
| 491 |
+
"outputs": {
|
| 492 |
+
"y": { "dtype": "float32", "shape": [2049, 1], "dist": "empty" },
|
| 493 |
+
"inverse_indices": { "dtype": "uint32", "shape": [4096], "dist": "empty" }
|
| 494 |
+
}
|
| 495 |
+
},
|
| 496 |
+
{
|
| 497 |
+
"name": "r4_scalar_scan_n32767_u13_sorted0",
|
| 498 |
+
"attrs": { "axis": -2, "sorted": 0 },
|
| 499 |
+
"inputs": {
|
| 500 |
+
"x": {
|
| 501 |
+
"dtype": "float32",
|
| 502 |
+
"shape": [1, 32767, 1],
|
| 503 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 504 |
+
}
|
| 505 |
+
},
|
| 506 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 507 |
+
"provenance": {
|
| 508 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 509 |
+
},
|
| 510 |
+
"bench": {
|
| 511 |
+
"metrics": [
|
| 512 |
+
{
|
| 513 |
+
"type": "bandwidth",
|
| 514 |
+
"name": "logical input/output bytes",
|
| 515 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 516 |
+
}
|
| 517 |
+
]
|
| 518 |
+
},
|
| 519 |
+
"preset": "stress"
|
| 520 |
+
},
|
| 521 |
+
{
|
| 522 |
+
"name": "r4_scalar_scan_n32767_u13_sorted1",
|
| 523 |
+
"attrs": { "axis": -2, "sorted": 1 },
|
| 524 |
+
"inputs": {
|
| 525 |
+
"x": {
|
| 526 |
+
"dtype": "float32",
|
| 527 |
+
"shape": [1, 32767, 1],
|
| 528 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 529 |
+
}
|
| 530 |
+
},
|
| 531 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 532 |
+
"provenance": {
|
| 533 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 534 |
+
},
|
| 535 |
+
"bench": {
|
| 536 |
+
"metrics": [
|
| 537 |
+
{
|
| 538 |
+
"type": "bandwidth",
|
| 539 |
+
"name": "logical input/output bytes",
|
| 540 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 541 |
+
}
|
| 542 |
+
]
|
| 543 |
+
},
|
| 544 |
+
"preset": "stress"
|
| 545 |
+
},
|
| 546 |
+
{
|
| 547 |
+
"name": "r4_scalar_scan_n32768_u13_sorted0",
|
| 548 |
+
"attrs": { "axis": -2, "sorted": 0 },
|
| 549 |
+
"inputs": {
|
| 550 |
+
"x": {
|
| 551 |
+
"dtype": "float32",
|
| 552 |
+
"shape": [1, 32768, 1],
|
| 553 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 554 |
+
}
|
| 555 |
+
},
|
| 556 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 557 |
+
"provenance": {
|
| 558 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 559 |
+
},
|
| 560 |
+
"bench": {
|
| 561 |
+
"metrics": [
|
| 562 |
+
{
|
| 563 |
+
"type": "bandwidth",
|
| 564 |
+
"name": "logical input/output bytes",
|
| 565 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 566 |
+
}
|
| 567 |
+
]
|
| 568 |
+
},
|
| 569 |
+
"preset": "stress"
|
| 570 |
+
},
|
| 571 |
+
{
|
| 572 |
+
"name": "r4_scalar_scan_n32768_u13_sorted1",
|
| 573 |
+
"attrs": { "axis": -2, "sorted": 1 },
|
| 574 |
+
"inputs": {
|
| 575 |
+
"x": {
|
| 576 |
+
"dtype": "float32",
|
| 577 |
+
"shape": [1, 32768, 1],
|
| 578 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 579 |
+
}
|
| 580 |
+
},
|
| 581 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 582 |
+
"provenance": {
|
| 583 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 584 |
+
},
|
| 585 |
+
"bench": {
|
| 586 |
+
"metrics": [
|
| 587 |
+
{
|
| 588 |
+
"type": "bandwidth",
|
| 589 |
+
"name": "logical input/output bytes",
|
| 590 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 591 |
+
}
|
| 592 |
+
]
|
| 593 |
+
},
|
| 594 |
+
"preset": "stress"
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"name": "r4_scalar_scan_n32769_u13_sorted0",
|
| 598 |
+
"attrs": { "axis": -2, "sorted": 0 },
|
| 599 |
+
"inputs": {
|
| 600 |
+
"x": {
|
| 601 |
+
"dtype": "float32",
|
| 602 |
+
"shape": [1, 32769, 1],
|
| 603 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 604 |
+
}
|
| 605 |
+
},
|
| 606 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 607 |
+
"provenance": {
|
| 608 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 609 |
+
},
|
| 610 |
+
"bench": {
|
| 611 |
+
"metrics": [
|
| 612 |
+
{
|
| 613 |
+
"type": "bandwidth",
|
| 614 |
+
"name": "logical input/output bytes",
|
| 615 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 616 |
+
}
|
| 617 |
+
]
|
| 618 |
+
},
|
| 619 |
+
"preset": "stress"
|
| 620 |
+
},
|
| 621 |
+
{
|
| 622 |
+
"name": "r4_scalar_scan_n32769_u13_sorted1",
|
| 623 |
+
"attrs": { "axis": -2, "sorted": 1 },
|
| 624 |
+
"inputs": {
|
| 625 |
+
"x": {
|
| 626 |
+
"dtype": "float32",
|
| 627 |
+
"shape": [1, 32769, 1],
|
| 628 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 629 |
+
}
|
| 630 |
+
},
|
| 631 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 632 |
+
"provenance": {
|
| 633 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 634 |
+
},
|
| 635 |
+
"bench": {
|
| 636 |
+
"metrics": [
|
| 637 |
+
{
|
| 638 |
+
"type": "bandwidth",
|
| 639 |
+
"name": "logical input/output bytes",
|
| 640 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 641 |
+
}
|
| 642 |
+
]
|
| 643 |
+
},
|
| 644 |
+
"preset": "stress"
|
| 645 |
+
},
|
| 646 |
+
{
|
| 647 |
+
"name": "r4_scalar_scan_n65537_u13_sorted0",
|
| 648 |
+
"attrs": { "axis": -2, "sorted": 0 },
|
| 649 |
+
"inputs": {
|
| 650 |
+
"x": {
|
| 651 |
+
"dtype": "float32",
|
| 652 |
+
"shape": [1, 65537, 1],
|
| 653 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 654 |
+
}
|
| 655 |
+
},
|
| 656 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 657 |
+
"provenance": {
|
| 658 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 659 |
+
},
|
| 660 |
+
"bench": {
|
| 661 |
+
"metrics": [
|
| 662 |
+
{
|
| 663 |
+
"type": "bandwidth",
|
| 664 |
+
"name": "logical input/output bytes",
|
| 665 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 666 |
+
}
|
| 667 |
+
]
|
| 668 |
+
},
|
| 669 |
+
"preset": "stress"
|
| 670 |
+
},
|
| 671 |
+
{
|
| 672 |
+
"name": "r4_scalar_scan_n65537_u13_sorted1",
|
| 673 |
+
"attrs": { "axis": -2, "sorted": 1 },
|
| 674 |
+
"inputs": {
|
| 675 |
+
"x": {
|
| 676 |
+
"dtype": "float32",
|
| 677 |
+
"shape": [1, 65537, 1],
|
| 678 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 679 |
+
}
|
| 680 |
+
},
|
| 681 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } },
|
| 682 |
+
"provenance": {
|
| 683 |
+
"notes": "Neighboring natural scan sizes at dispatch boundaries with bounded distinct-count oracle."
|
| 684 |
+
},
|
| 685 |
+
"bench": {
|
| 686 |
+
"metrics": [
|
| 687 |
+
{
|
| 688 |
+
"type": "bandwidth",
|
| 689 |
+
"name": "logical input/output bytes",
|
| 690 |
+
"value": "4 * (numel(shapes.x) + numel(shapes.y))"
|
| 691 |
+
}
|
| 692 |
+
]
|
| 693 |
+
},
|
| 694 |
+
"preset": "stress"
|
| 695 |
+
},
|
| 696 |
+
{
|
| 697 |
+
"name": "scalar-f32-metadata-mask0-sorted0-n16385-u13",
|
| 698 |
+
"preset": "stress",
|
| 699 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 700 |
+
"inputs": {
|
| 701 |
+
"x": {
|
| 702 |
+
"dtype": "float32",
|
| 703 |
+
"shape": [1, 16385, 1],
|
| 704 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 705 |
+
}
|
| 706 |
+
},
|
| 707 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } }
|
| 708 |
+
},
|
| 709 |
+
{
|
| 710 |
+
"name": "scalar-f32-metadata-mask0-sorted1-n16385-u13",
|
| 711 |
+
"preset": "stress",
|
| 712 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 713 |
+
"inputs": {
|
| 714 |
+
"x": {
|
| 715 |
+
"dtype": "float32",
|
| 716 |
+
"shape": [1, 16385, 1],
|
| 717 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 718 |
+
}
|
| 719 |
+
},
|
| 720 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] } }
|
| 721 |
+
},
|
| 722 |
+
{
|
| 723 |
+
"name": "scalar-f32-metadata-mask1-sorted0-n16385-u13",
|
| 724 |
+
"preset": "stress",
|
| 725 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 726 |
+
"inputs": {
|
| 727 |
+
"x": {
|
| 728 |
+
"dtype": "float32",
|
| 729 |
+
"shape": [1, 16385, 1],
|
| 730 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 731 |
+
}
|
| 732 |
+
},
|
| 733 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] }, "indices": { "dtype": "uint32", "shape": [13] } }
|
| 734 |
+
},
|
| 735 |
+
{
|
| 736 |
+
"name": "scalar-f32-metadata-mask1-sorted1-n16385-u13",
|
| 737 |
+
"preset": "stress",
|
| 738 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 739 |
+
"inputs": {
|
| 740 |
+
"x": {
|
| 741 |
+
"dtype": "float32",
|
| 742 |
+
"shape": [1, 16385, 1],
|
| 743 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 744 |
+
}
|
| 745 |
+
},
|
| 746 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] }, "indices": { "dtype": "uint32", "shape": [13] } }
|
| 747 |
+
},
|
| 748 |
+
{
|
| 749 |
+
"name": "scalar-f32-metadata-mask2-sorted0-n16385-u13",
|
| 750 |
+
"preset": "stress",
|
| 751 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 752 |
+
"inputs": {
|
| 753 |
+
"x": {
|
| 754 |
+
"dtype": "float32",
|
| 755 |
+
"shape": [1, 16385, 1],
|
| 756 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 757 |
+
}
|
| 758 |
+
},
|
| 759 |
+
"outputs": {
|
| 760 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 761 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] }
|
| 762 |
+
}
|
| 763 |
+
},
|
| 764 |
+
{
|
| 765 |
+
"name": "scalar-f32-metadata-mask2-sorted1-n16385-u13",
|
| 766 |
+
"preset": "stress",
|
| 767 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 768 |
+
"inputs": {
|
| 769 |
+
"x": {
|
| 770 |
+
"dtype": "float32",
|
| 771 |
+
"shape": [1, 16385, 1],
|
| 772 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 773 |
+
}
|
| 774 |
+
},
|
| 775 |
+
"outputs": {
|
| 776 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 777 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] }
|
| 778 |
+
}
|
| 779 |
+
},
|
| 780 |
+
{
|
| 781 |
+
"name": "scalar-f32-metadata-mask3-sorted0-n16385-u13",
|
| 782 |
+
"preset": "stress",
|
| 783 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 784 |
+
"inputs": {
|
| 785 |
+
"x": {
|
| 786 |
+
"dtype": "float32",
|
| 787 |
+
"shape": [1, 16385, 1],
|
| 788 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 789 |
+
}
|
| 790 |
+
},
|
| 791 |
+
"outputs": {
|
| 792 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 793 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 794 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] }
|
| 795 |
+
}
|
| 796 |
+
},
|
| 797 |
+
{
|
| 798 |
+
"name": "scalar-f32-metadata-mask3-sorted1-n16385-u13",
|
| 799 |
+
"preset": "stress",
|
| 800 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 801 |
+
"inputs": {
|
| 802 |
+
"x": {
|
| 803 |
+
"dtype": "float32",
|
| 804 |
+
"shape": [1, 16385, 1],
|
| 805 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 806 |
+
}
|
| 807 |
+
},
|
| 808 |
+
"outputs": {
|
| 809 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 810 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 811 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] }
|
| 812 |
+
}
|
| 813 |
+
},
|
| 814 |
+
{
|
| 815 |
+
"name": "scalar-f32-metadata-mask4-sorted0-n16385-u13",
|
| 816 |
+
"preset": "stress",
|
| 817 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 818 |
+
"inputs": {
|
| 819 |
+
"x": {
|
| 820 |
+
"dtype": "float32",
|
| 821 |
+
"shape": [1, 16385, 1],
|
| 822 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 823 |
+
}
|
| 824 |
+
},
|
| 825 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] }, "counts": { "dtype": "uint32", "shape": [13] } }
|
| 826 |
+
},
|
| 827 |
+
{
|
| 828 |
+
"name": "scalar-f32-metadata-mask4-sorted1-n16385-u13",
|
| 829 |
+
"preset": "stress",
|
| 830 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 831 |
+
"inputs": {
|
| 832 |
+
"x": {
|
| 833 |
+
"dtype": "float32",
|
| 834 |
+
"shape": [1, 16385, 1],
|
| 835 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 836 |
+
}
|
| 837 |
+
},
|
| 838 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 13, 1] }, "counts": { "dtype": "uint32", "shape": [13] } }
|
| 839 |
+
},
|
| 840 |
+
{
|
| 841 |
+
"name": "scalar-f32-metadata-mask5-sorted0-n16385-u13",
|
| 842 |
+
"preset": "stress",
|
| 843 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 844 |
+
"inputs": {
|
| 845 |
+
"x": {
|
| 846 |
+
"dtype": "float32",
|
| 847 |
+
"shape": [1, 16385, 1],
|
| 848 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 849 |
+
}
|
| 850 |
+
},
|
| 851 |
+
"outputs": {
|
| 852 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 853 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 854 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 855 |
+
}
|
| 856 |
+
},
|
| 857 |
+
{
|
| 858 |
+
"name": "scalar-f32-metadata-mask5-sorted1-n16385-u13",
|
| 859 |
+
"preset": "stress",
|
| 860 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 861 |
+
"inputs": {
|
| 862 |
+
"x": {
|
| 863 |
+
"dtype": "float32",
|
| 864 |
+
"shape": [1, 16385, 1],
|
| 865 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 866 |
+
}
|
| 867 |
+
},
|
| 868 |
+
"outputs": {
|
| 869 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 870 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 871 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 872 |
+
}
|
| 873 |
+
},
|
| 874 |
+
{
|
| 875 |
+
"name": "scalar-f32-metadata-mask6-sorted0-n16385-u13",
|
| 876 |
+
"preset": "stress",
|
| 877 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 878 |
+
"inputs": {
|
| 879 |
+
"x": {
|
| 880 |
+
"dtype": "float32",
|
| 881 |
+
"shape": [1, 16385, 1],
|
| 882 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 883 |
+
}
|
| 884 |
+
},
|
| 885 |
+
"outputs": {
|
| 886 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 887 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] },
|
| 888 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 889 |
+
}
|
| 890 |
+
},
|
| 891 |
+
{
|
| 892 |
+
"name": "scalar-f32-metadata-mask6-sorted1-n16385-u13",
|
| 893 |
+
"preset": "stress",
|
| 894 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 895 |
+
"inputs": {
|
| 896 |
+
"x": {
|
| 897 |
+
"dtype": "float32",
|
| 898 |
+
"shape": [1, 16385, 1],
|
| 899 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 900 |
+
}
|
| 901 |
+
},
|
| 902 |
+
"outputs": {
|
| 903 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 904 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] },
|
| 905 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 906 |
+
}
|
| 907 |
+
},
|
| 908 |
+
{
|
| 909 |
+
"name": "scalar-f32-metadata-mask7-sorted0-n16385-u13",
|
| 910 |
+
"preset": "stress",
|
| 911 |
+
"attrs": { "axis": 1, "sorted": 0 },
|
| 912 |
+
"inputs": {
|
| 913 |
+
"x": {
|
| 914 |
+
"dtype": "float32",
|
| 915 |
+
"shape": [1, 16385, 1],
|
| 916 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 917 |
+
}
|
| 918 |
+
},
|
| 919 |
+
"outputs": {
|
| 920 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 921 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 922 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] },
|
| 923 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 924 |
+
}
|
| 925 |
+
},
|
| 926 |
+
{
|
| 927 |
+
"name": "scalar-f32-metadata-mask7-sorted1-n16385-u13",
|
| 928 |
+
"preset": "stress",
|
| 929 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 930 |
+
"inputs": {
|
| 931 |
+
"x": {
|
| 932 |
+
"dtype": "float32",
|
| 933 |
+
"shape": [1, 16385, 1],
|
| 934 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0, 11.0, 0.0, 4.0, 6.0, 8.0, 9.0, 10.0, 12.0] }
|
| 935 |
+
}
|
| 936 |
+
},
|
| 937 |
+
"outputs": {
|
| 938 |
+
"y": { "dtype": "float32", "shape": [1, 13, 1] },
|
| 939 |
+
"indices": { "dtype": "uint32", "shape": [13] },
|
| 940 |
+
"inverse_indices": { "dtype": "uint32", "shape": [16385] },
|
| 941 |
+
"counts": { "dtype": "uint32", "shape": [13] }
|
| 942 |
+
}
|
| 943 |
+
},
|
| 944 |
+
{
|
| 945 |
+
"name": "single-class-f32-n65537-mask0",
|
| 946 |
+
"preset": "stress",
|
| 947 |
+
"inputs": { "x": { "dtype": "float32", "shape": [65537], "data": { "kind": "constant", "value": 3.0 } } },
|
| 948 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1] } }
|
| 949 |
+
},
|
| 950 |
+
{
|
| 951 |
+
"name": "single-class-f32-n65537-mask2",
|
| 952 |
+
"preset": "stress",
|
| 953 |
+
"inputs": { "x": { "dtype": "float32", "shape": [65537], "data": { "kind": "constant", "value": 3.0 } } },
|
| 954 |
+
"outputs": {
|
| 955 |
+
"y": { "dtype": "float32", "shape": [1] },
|
| 956 |
+
"inverse_indices": { "dtype": "uint32", "shape": [65537] }
|
| 957 |
+
}
|
| 958 |
+
},
|
| 959 |
+
{
|
| 960 |
+
"name": "single-class-f32-n65537-mask4",
|
| 961 |
+
"preset": "stress",
|
| 962 |
+
"inputs": { "x": { "dtype": "float32", "shape": [65537], "data": { "kind": "constant", "value": 3.0 } } },
|
| 963 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1] }, "counts": { "dtype": "uint32", "shape": [1] } }
|
| 964 |
+
},
|
| 965 |
+
{
|
| 966 |
+
"name": "single-class-f32-n65537-mask7",
|
| 967 |
+
"preset": "stress",
|
| 968 |
+
"inputs": { "x": { "dtype": "float32", "shape": [65537], "data": { "kind": "constant", "value": 3.0 } } },
|
| 969 |
+
"outputs": {
|
| 970 |
+
"y": { "dtype": "float32", "shape": [1] },
|
| 971 |
+
"indices": { "dtype": "uint32", "shape": [1] },
|
| 972 |
+
"inverse_indices": { "dtype": "uint32", "shape": [65537] },
|
| 973 |
+
"counts": { "dtype": "uint32", "shape": [1] }
|
| 974 |
+
}
|
| 975 |
+
},
|
| 976 |
+
{
|
| 977 |
+
"name": "single-class-axis1-f32-outer3-n4097-inner5-all-metadata",
|
| 978 |
+
"preset": "stress",
|
| 979 |
+
"attrs": { "axis": 1, "sorted": 1 },
|
| 980 |
+
"inputs": {
|
| 981 |
+
"x": {
|
| 982 |
+
"dtype": "float32",
|
| 983 |
+
"shape": [3, 4097, 5],
|
| 984 |
+
"data": { "kind": "cycle", "values": [5.0, 2.0, 7.0, 1.0, 3.0] }
|
| 985 |
+
}
|
| 986 |
+
},
|
| 987 |
+
"outputs": {
|
| 988 |
+
"y": { "dtype": "float32", "shape": [3, 1, 5] },
|
| 989 |
+
"indices": { "dtype": "uint32", "shape": [1] },
|
| 990 |
+
"inverse_indices": { "dtype": "uint32", "shape": [4097] },
|
| 991 |
+
"counts": { "dtype": "uint32", "shape": [1] }
|
| 992 |
+
}
|
| 993 |
+
},
|
| 994 |
+
{
|
| 995 |
+
"name": "flat-global-crossover-i32-n2048-u2048-sorted0",
|
| 996 |
+
"preset": "stress",
|
| 997 |
+
"attrs": { "sorted": 0 },
|
| 998 |
+
"inputs": { "x": { "dtype": "int32", "shape": [2048], "dist": "linearMod", "mod": 2048 } },
|
| 999 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2048] } },
|
| 1000 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1001 |
+
},
|
| 1002 |
+
{
|
| 1003 |
+
"name": "flat-global-crossover-i32-n2048-u2048-sorted1",
|
| 1004 |
+
"preset": "stress",
|
| 1005 |
+
"attrs": { "sorted": 1 },
|
| 1006 |
+
"inputs": { "x": { "dtype": "int32", "shape": [2048], "dist": "linearMod", "mod": 2048 } },
|
| 1007 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2048] } },
|
| 1008 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1009 |
+
},
|
| 1010 |
+
{
|
| 1011 |
+
"name": "flat-global-crossover-i32-n2049-u2049-sorted0",
|
| 1012 |
+
"preset": "stress",
|
| 1013 |
+
"attrs": { "sorted": 0 },
|
| 1014 |
+
"inputs": { "x": { "dtype": "int32", "shape": [2049], "dist": "linearMod", "mod": 2049 } },
|
| 1015 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2049] } },
|
| 1016 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1017 |
+
},
|
| 1018 |
+
{
|
| 1019 |
+
"name": "flat-global-crossover-i32-n2049-u2049-sorted1",
|
| 1020 |
+
"preset": "stress",
|
| 1021 |
+
"attrs": { "sorted": 1 },
|
| 1022 |
+
"inputs": { "x": { "dtype": "int32", "shape": [2049], "dist": "linearMod", "mod": 2049 } },
|
| 1023 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2049] } },
|
| 1024 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1025 |
+
},
|
| 1026 |
+
{
|
| 1027 |
+
"name": "flat-global-crossover-i32-n4097-u4097-sorted0",
|
| 1028 |
+
"preset": "stress",
|
| 1029 |
+
"attrs": { "sorted": 0 },
|
| 1030 |
+
"inputs": { "x": { "dtype": "int32", "shape": [4097], "dist": "linearMod", "mod": 4097 } },
|
| 1031 |
+
"outputs": { "y": { "dtype": "int32", "shape": [4097] } },
|
| 1032 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1033 |
+
},
|
| 1034 |
+
{
|
| 1035 |
+
"name": "flat-global-crossover-i32-n4097-u4097-sorted1",
|
| 1036 |
+
"preset": "stress",
|
| 1037 |
+
"attrs": { "sorted": 1 },
|
| 1038 |
+
"inputs": { "x": { "dtype": "int32", "shape": [4097], "dist": "linearMod", "mod": 4097 } },
|
| 1039 |
+
"outputs": { "y": { "dtype": "int32", "shape": [4097] } },
|
| 1040 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1041 |
+
},
|
| 1042 |
+
{
|
| 1043 |
+
"name": "flat-global-crossover-i32-n8193-u8193-sorted0",
|
| 1044 |
+
"preset": "stress",
|
| 1045 |
+
"attrs": { "sorted": 0 },
|
| 1046 |
+
"inputs": { "x": { "dtype": "int32", "shape": [8193], "dist": "linearMod", "mod": 8193 } },
|
| 1047 |
+
"outputs": { "y": { "dtype": "int32", "shape": [8193] } },
|
| 1048 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1049 |
+
},
|
| 1050 |
+
{
|
| 1051 |
+
"name": "flat-global-crossover-i32-n8193-u8193-sorted1",
|
| 1052 |
+
"preset": "stress",
|
| 1053 |
+
"attrs": { "sorted": 1 },
|
| 1054 |
+
"inputs": { "x": { "dtype": "int32", "shape": [8193], "dist": "linearMod", "mod": 8193 } },
|
| 1055 |
+
"outputs": { "y": { "dtype": "int32", "shape": [8193] } },
|
| 1056 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1057 |
+
},
|
| 1058 |
+
{
|
| 1059 |
+
"name": "flat-global-crossover-int32-n4097-u2049-sorted0",
|
| 1060 |
+
"preset": "stress",
|
| 1061 |
+
"attrs": { "sorted": 0 },
|
| 1062 |
+
"inputs": {
|
| 1063 |
+
"x": {
|
| 1064 |
+
"dtype": "int32",
|
| 1065 |
+
"shape": [4097],
|
| 1066 |
+
"data": {
|
| 1067 |
+
"kind": "cycle",
|
| 1068 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-hybrid-floor_input_x" }
|
| 1069 |
+
}
|
| 1070 |
+
}
|
| 1071 |
+
},
|
| 1072 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2049] } }
|
| 1073 |
+
},
|
| 1074 |
+
{
|
| 1075 |
+
"name": "flat-global-crossover-int32-n4097-u2049-sorted1",
|
| 1076 |
+
"preset": "stress",
|
| 1077 |
+
"attrs": { "sorted": 1 },
|
| 1078 |
+
"inputs": {
|
| 1079 |
+
"x": {
|
| 1080 |
+
"dtype": "int32",
|
| 1081 |
+
"shape": [4097],
|
| 1082 |
+
"data": {
|
| 1083 |
+
"kind": "cycle",
|
| 1084 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-hybrid-floor_input_x" }
|
| 1085 |
+
}
|
| 1086 |
+
}
|
| 1087 |
+
},
|
| 1088 |
+
"outputs": { "y": { "dtype": "int32", "shape": [2049] } }
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"name": "flat-global-crossover-uint32-n8193-u2049-sorted0",
|
| 1092 |
+
"preset": "stress",
|
| 1093 |
+
"attrs": { "sorted": 0 },
|
| 1094 |
+
"inputs": {
|
| 1095 |
+
"x": {
|
| 1096 |
+
"dtype": "uint32",
|
| 1097 |
+
"shape": [8193],
|
| 1098 |
+
"data": {
|
| 1099 |
+
"kind": "cycle",
|
| 1100 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-hybrid-floor_input_x" }
|
| 1101 |
+
}
|
| 1102 |
+
}
|
| 1103 |
+
},
|
| 1104 |
+
"outputs": { "y": { "dtype": "uint32", "shape": [2049] } }
|
| 1105 |
+
},
|
| 1106 |
+
{
|
| 1107 |
+
"name": "flat-global-crossover-uint32-n8193-u2049-sorted1",
|
| 1108 |
+
"preset": "stress",
|
| 1109 |
+
"attrs": { "sorted": 1 },
|
| 1110 |
+
"inputs": {
|
| 1111 |
+
"x": {
|
| 1112 |
+
"dtype": "uint32",
|
| 1113 |
+
"shape": [8193],
|
| 1114 |
+
"data": {
|
| 1115 |
+
"kind": "cycle",
|
| 1116 |
+
"values": { "$ref": "#/fixtureArrays/axis-scalar-f32-inverse-hybrid-floor_input_x" }
|
| 1117 |
+
}
|
| 1118 |
+
}
|
| 1119 |
+
},
|
| 1120 |
+
"outputs": { "y": { "dtype": "uint32", "shape": [2049] } }
|
| 1121 |
+
},
|
| 1122 |
+
{
|
| 1123 |
+
"name": "output-span-int32-n257-sorted0",
|
| 1124 |
+
"preset": "stress",
|
| 1125 |
+
"attrs": { "sorted": 0 },
|
| 1126 |
+
"inputs": { "x": { "dtype": "int32", "shape": [257], "dist": "linearMod", "mod": 257 } },
|
| 1127 |
+
"outputs": { "y": { "dtype": "int32", "shape": [257] } },
|
| 1128 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"name": "output-span-int32-n257-sorted1",
|
| 1132 |
+
"preset": "stress",
|
| 1133 |
+
"attrs": { "sorted": 1 },
|
| 1134 |
+
"inputs": { "x": { "dtype": "int32", "shape": [257], "dist": "linearMod", "mod": 257 } },
|
| 1135 |
+
"outputs": { "y": { "dtype": "int32", "shape": [257] } },
|
| 1136 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1137 |
+
},
|
| 1138 |
+
{
|
| 1139 |
+
"name": "output-span-float32-n257-sorted0",
|
| 1140 |
+
"preset": "stress",
|
| 1141 |
+
"attrs": { "sorted": 0 },
|
| 1142 |
+
"inputs": { "x": { "dtype": "float32", "shape": [257], "dist": "linearMod", "mod": 257 } },
|
| 1143 |
+
"outputs": { "y": { "dtype": "float32", "shape": [257] } },
|
| 1144 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1145 |
+
},
|
| 1146 |
+
{
|
| 1147 |
+
"name": "output-span-float32-n257-sorted1",
|
| 1148 |
+
"preset": "stress",
|
| 1149 |
+
"attrs": { "sorted": 1 },
|
| 1150 |
+
"inputs": { "x": { "dtype": "float32", "shape": [257], "dist": "linearMod", "mod": 257 } },
|
| 1151 |
+
"outputs": { "y": { "dtype": "float32", "shape": [257] } },
|
| 1152 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1153 |
+
},
|
| 1154 |
+
{
|
| 1155 |
+
"name": "output-span-int32-n1025-sorted0",
|
| 1156 |
+
"preset": "stress",
|
| 1157 |
+
"attrs": { "sorted": 0 },
|
| 1158 |
+
"inputs": { "x": { "dtype": "int32", "shape": [1025], "dist": "linearMod", "mod": 1025 } },
|
| 1159 |
+
"outputs": { "y": { "dtype": "int32", "shape": [1025] } },
|
| 1160 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1161 |
+
},
|
| 1162 |
+
{
|
| 1163 |
+
"name": "output-span-int32-n1025-sorted1",
|
| 1164 |
+
"preset": "stress",
|
| 1165 |
+
"attrs": { "sorted": 1 },
|
| 1166 |
+
"inputs": { "x": { "dtype": "int32", "shape": [1025], "dist": "linearMod", "mod": 1025 } },
|
| 1167 |
+
"outputs": { "y": { "dtype": "int32", "shape": [1025] } },
|
| 1168 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1169 |
+
},
|
| 1170 |
+
{
|
| 1171 |
+
"name": "output-span-float32-n1025-sorted0",
|
| 1172 |
+
"preset": "stress",
|
| 1173 |
+
"attrs": { "sorted": 0 },
|
| 1174 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1025], "dist": "linearMod", "mod": 1025 } },
|
| 1175 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1025] } },
|
| 1176 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1177 |
+
},
|
| 1178 |
+
{
|
| 1179 |
+
"name": "output-span-float32-n1025-sorted1",
|
| 1180 |
+
"preset": "stress",
|
| 1181 |
+
"attrs": { "sorted": 1 },
|
| 1182 |
+
"inputs": { "x": { "dtype": "float32", "shape": [1025], "dist": "linearMod", "mod": 1025 } },
|
| 1183 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1025] } },
|
| 1184 |
+
"bench": { "metrics": [{ "type": "bandwidth", "value": "4 * (numel(shapes.x) + numel(shapes.y))" }] }
|
| 1185 |
+
},
|
| 1186 |
+
{
|
| 1187 |
+
"name": "float_hash_work_float32_n15_u15_sorted0",
|
| 1188 |
+
"preset": "stress",
|
| 1189 |
+
"attrs": { "sorted": 0 },
|
| 1190 |
+
"inputs": { "x": { "dtype": "float32", "shape": [15], "dist": "linearMod", "mod": 15 } },
|
| 1191 |
+
"outputs": { "y": { "dtype": "float32", "shape": [15] } },
|
| 1192 |
+
"bench": {
|
| 1193 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1194 |
+
},
|
| 1195 |
+
"vars": { "dtype": "float32" }
|
| 1196 |
+
},
|
| 1197 |
+
{
|
| 1198 |
+
"name": "float_hash_work_float32_n15_u15_sorted1",
|
| 1199 |
+
"preset": "stress",
|
| 1200 |
+
"attrs": { "sorted": 1 },
|
| 1201 |
+
"inputs": { "x": { "dtype": "float32", "shape": [15], "dist": "linearMod", "mod": 15 } },
|
| 1202 |
+
"outputs": { "y": { "dtype": "float32", "shape": [15] } },
|
| 1203 |
+
"bench": {
|
| 1204 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1205 |
+
},
|
| 1206 |
+
"vars": { "dtype": "float32" }
|
| 1207 |
+
},
|
| 1208 |
+
{
|
| 1209 |
+
"name": "float_hash_work_float32_n16_u16_sorted0",
|
| 1210 |
+
"preset": "stress",
|
| 1211 |
+
"attrs": { "sorted": 0 },
|
| 1212 |
+
"inputs": { "x": { "dtype": "float32", "shape": [16], "dist": "linearMod", "mod": 16 } },
|
| 1213 |
+
"outputs": { "y": { "dtype": "float32", "shape": [16] } },
|
| 1214 |
+
"bench": {
|
| 1215 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1216 |
+
},
|
| 1217 |
+
"vars": { "dtype": "float32" }
|
| 1218 |
+
},
|
| 1219 |
+
{
|
| 1220 |
+
"name": "float_hash_work_float32_n16_u16_sorted1",
|
| 1221 |
+
"preset": "stress",
|
| 1222 |
+
"attrs": { "sorted": 1 },
|
| 1223 |
+
"inputs": { "x": { "dtype": "float32", "shape": [16], "dist": "linearMod", "mod": 16 } },
|
| 1224 |
+
"outputs": { "y": { "dtype": "float32", "shape": [16] } },
|
| 1225 |
+
"bench": {
|
| 1226 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1227 |
+
},
|
| 1228 |
+
"vars": { "dtype": "float32" }
|
| 1229 |
+
},
|
| 1230 |
+
{
|
| 1231 |
+
"name": "float_hash_work_float32_n32_u8_sorted0",
|
| 1232 |
+
"preset": "stress",
|
| 1233 |
+
"attrs": { "sorted": 0 },
|
| 1234 |
+
"inputs": { "x": { "dtype": "float32", "shape": [32], "dist": "linearMod", "mod": 8 } },
|
| 1235 |
+
"outputs": { "y": { "dtype": "float32", "shape": [8] } },
|
| 1236 |
+
"bench": {
|
| 1237 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1238 |
+
},
|
| 1239 |
+
"vars": { "dtype": "float32" }
|
| 1240 |
+
},
|
| 1241 |
+
{
|
| 1242 |
+
"name": "float_hash_work_float32_n32_u8_sorted1",
|
| 1243 |
+
"preset": "stress",
|
| 1244 |
+
"attrs": { "sorted": 1 },
|
| 1245 |
+
"inputs": { "x": { "dtype": "float32", "shape": [32], "dist": "linearMod", "mod": 8 } },
|
| 1246 |
+
"outputs": { "y": { "dtype": "float32", "shape": [8] } },
|
| 1247 |
+
"bench": {
|
| 1248 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1249 |
+
},
|
| 1250 |
+
"vars": { "dtype": "float32" }
|
| 1251 |
+
},
|
| 1252 |
+
{
|
| 1253 |
+
"name": "float_hash_work_float32_n64_u64_sorted0",
|
| 1254 |
+
"preset": "stress",
|
| 1255 |
+
"attrs": { "sorted": 0 },
|
| 1256 |
+
"inputs": { "x": { "dtype": "float32", "shape": [64], "dist": "linearMod", "mod": 64 } },
|
| 1257 |
+
"outputs": { "y": { "dtype": "float32", "shape": [64] } },
|
| 1258 |
+
"bench": {
|
| 1259 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1260 |
+
},
|
| 1261 |
+
"vars": { "dtype": "float32" }
|
| 1262 |
+
},
|
| 1263 |
+
{
|
| 1264 |
+
"name": "float_hash_work_float32_n64_u64_sorted1",
|
| 1265 |
+
"preset": "stress",
|
| 1266 |
+
"attrs": { "sorted": 1 },
|
| 1267 |
+
"inputs": { "x": { "dtype": "float32", "shape": [64], "dist": "linearMod", "mod": 64 } },
|
| 1268 |
+
"outputs": { "y": { "dtype": "float32", "shape": [64] } },
|
| 1269 |
+
"bench": {
|
| 1270 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1271 |
+
},
|
| 1272 |
+
"vars": { "dtype": "float32" }
|
| 1273 |
+
},
|
| 1274 |
+
{
|
| 1275 |
+
"name": "float_hash_work_float32_n128_u8_sorted0",
|
| 1276 |
+
"preset": "stress",
|
| 1277 |
+
"attrs": { "sorted": 0 },
|
| 1278 |
+
"inputs": { "x": { "dtype": "float32", "shape": [128], "dist": "linearMod", "mod": 8 } },
|
| 1279 |
+
"outputs": { "y": { "dtype": "float32", "shape": [8] } },
|
| 1280 |
+
"bench": {
|
| 1281 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1282 |
+
},
|
| 1283 |
+
"vars": { "dtype": "float32" }
|
| 1284 |
+
},
|
| 1285 |
+
{
|
| 1286 |
+
"name": "float_hash_work_float32_n128_u8_sorted1",
|
| 1287 |
+
"preset": "stress",
|
| 1288 |
+
"attrs": { "sorted": 1 },
|
| 1289 |
+
"inputs": { "x": { "dtype": "float32", "shape": [128], "dist": "linearMod", "mod": 8 } },
|
| 1290 |
+
"outputs": { "y": { "dtype": "float32", "shape": [8] } },
|
| 1291 |
+
"bench": {
|
| 1292 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1293 |
+
},
|
| 1294 |
+
"vars": { "dtype": "float32" }
|
| 1295 |
+
},
|
| 1296 |
+
{
|
| 1297 |
+
"name": "float_hash_work_float32_n512_u512_sorted0",
|
| 1298 |
+
"preset": "stress",
|
| 1299 |
+
"attrs": { "sorted": 0 },
|
| 1300 |
+
"inputs": { "x": { "dtype": "float32", "shape": [512], "dist": "linearMod", "mod": 512 } },
|
| 1301 |
+
"outputs": { "y": { "dtype": "float32", "shape": [512] } },
|
| 1302 |
+
"bench": {
|
| 1303 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1304 |
+
},
|
| 1305 |
+
"vars": { "dtype": "float32" }
|
| 1306 |
+
},
|
| 1307 |
+
{
|
| 1308 |
+
"name": "float_hash_work_float32_n512_u512_sorted1",
|
| 1309 |
+
"preset": "stress",
|
| 1310 |
+
"attrs": { "sorted": 1 },
|
| 1311 |
+
"inputs": { "x": { "dtype": "float32", "shape": [512], "dist": "linearMod", "mod": 512 } },
|
| 1312 |
+
"outputs": { "y": { "dtype": "float32", "shape": [512] } },
|
| 1313 |
+
"bench": {
|
| 1314 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1315 |
+
},
|
| 1316 |
+
"vars": { "dtype": "float32" }
|
| 1317 |
+
},
|
| 1318 |
+
{
|
| 1319 |
+
"name": "float_hash_work_float16_n15_u15_sorted0",
|
| 1320 |
+
"preset": "stress",
|
| 1321 |
+
"attrs": { "sorted": 0 },
|
| 1322 |
+
"inputs": { "x": { "dtype": "float16", "shape": [15], "dist": "linearMod", "mod": 15 } },
|
| 1323 |
+
"outputs": { "y": { "dtype": "float16", "shape": [15] } },
|
| 1324 |
+
"bench": {
|
| 1325 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1326 |
+
},
|
| 1327 |
+
"vars": { "dtype": "float16" }
|
| 1328 |
+
},
|
| 1329 |
+
{
|
| 1330 |
+
"name": "float_hash_work_float16_n15_u15_sorted1",
|
| 1331 |
+
"preset": "stress",
|
| 1332 |
+
"attrs": { "sorted": 1 },
|
| 1333 |
+
"inputs": { "x": { "dtype": "float16", "shape": [15], "dist": "linearMod", "mod": 15 } },
|
| 1334 |
+
"outputs": { "y": { "dtype": "float16", "shape": [15] } },
|
| 1335 |
+
"bench": {
|
| 1336 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1337 |
+
},
|
| 1338 |
+
"vars": { "dtype": "float16" }
|
| 1339 |
+
},
|
| 1340 |
+
{
|
| 1341 |
+
"name": "float_hash_work_float16_n16_u16_sorted0",
|
| 1342 |
+
"preset": "stress",
|
| 1343 |
+
"attrs": { "sorted": 0 },
|
| 1344 |
+
"inputs": { "x": { "dtype": "float16", "shape": [16], "dist": "linearMod", "mod": 16 } },
|
| 1345 |
+
"outputs": { "y": { "dtype": "float16", "shape": [16] } },
|
| 1346 |
+
"bench": {
|
| 1347 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1348 |
+
},
|
| 1349 |
+
"vars": { "dtype": "float16" }
|
| 1350 |
+
},
|
| 1351 |
+
{
|
| 1352 |
+
"name": "float_hash_work_float16_n16_u16_sorted1",
|
| 1353 |
+
"preset": "stress",
|
| 1354 |
+
"attrs": { "sorted": 1 },
|
| 1355 |
+
"inputs": { "x": { "dtype": "float16", "shape": [16], "dist": "linearMod", "mod": 16 } },
|
| 1356 |
+
"outputs": { "y": { "dtype": "float16", "shape": [16] } },
|
| 1357 |
+
"bench": {
|
| 1358 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1359 |
+
},
|
| 1360 |
+
"vars": { "dtype": "float16" }
|
| 1361 |
+
},
|
| 1362 |
+
{
|
| 1363 |
+
"name": "float_hash_work_float16_n32_u8_sorted0",
|
| 1364 |
+
"preset": "stress",
|
| 1365 |
+
"attrs": { "sorted": 0 },
|
| 1366 |
+
"inputs": { "x": { "dtype": "float16", "shape": [32], "dist": "linearMod", "mod": 8 } },
|
| 1367 |
+
"outputs": { "y": { "dtype": "float16", "shape": [8] } },
|
| 1368 |
+
"bench": {
|
| 1369 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1370 |
+
},
|
| 1371 |
+
"vars": { "dtype": "float16" }
|
| 1372 |
+
},
|
| 1373 |
+
{
|
| 1374 |
+
"name": "float_hash_work_float16_n32_u8_sorted1",
|
| 1375 |
+
"preset": "stress",
|
| 1376 |
+
"attrs": { "sorted": 1 },
|
| 1377 |
+
"inputs": { "x": { "dtype": "float16", "shape": [32], "dist": "linearMod", "mod": 8 } },
|
| 1378 |
+
"outputs": { "y": { "dtype": "float16", "shape": [8] } },
|
| 1379 |
+
"bench": {
|
| 1380 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1381 |
+
},
|
| 1382 |
+
"vars": { "dtype": "float16" }
|
| 1383 |
+
},
|
| 1384 |
+
{
|
| 1385 |
+
"name": "float_hash_work_float16_n64_u64_sorted0",
|
| 1386 |
+
"preset": "stress",
|
| 1387 |
+
"attrs": { "sorted": 0 },
|
| 1388 |
+
"inputs": { "x": { "dtype": "float16", "shape": [64], "dist": "linearMod", "mod": 64 } },
|
| 1389 |
+
"outputs": { "y": { "dtype": "float16", "shape": [64] } },
|
| 1390 |
+
"bench": {
|
| 1391 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1392 |
+
},
|
| 1393 |
+
"vars": { "dtype": "float16" }
|
| 1394 |
+
},
|
| 1395 |
+
{
|
| 1396 |
+
"name": "float_hash_work_float16_n64_u64_sorted1",
|
| 1397 |
+
"preset": "stress",
|
| 1398 |
+
"attrs": { "sorted": 1 },
|
| 1399 |
+
"inputs": { "x": { "dtype": "float16", "shape": [64], "dist": "linearMod", "mod": 64 } },
|
| 1400 |
+
"outputs": { "y": { "dtype": "float16", "shape": [64] } },
|
| 1401 |
+
"bench": {
|
| 1402 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1403 |
+
},
|
| 1404 |
+
"vars": { "dtype": "float16" }
|
| 1405 |
+
},
|
| 1406 |
+
{
|
| 1407 |
+
"name": "float_hash_work_float16_n128_u8_sorted0",
|
| 1408 |
+
"preset": "stress",
|
| 1409 |
+
"attrs": { "sorted": 0 },
|
| 1410 |
+
"inputs": { "x": { "dtype": "float16", "shape": [128], "dist": "linearMod", "mod": 8 } },
|
| 1411 |
+
"outputs": { "y": { "dtype": "float16", "shape": [8] } },
|
| 1412 |
+
"bench": {
|
| 1413 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1414 |
+
},
|
| 1415 |
+
"vars": { "dtype": "float16" }
|
| 1416 |
+
},
|
| 1417 |
+
{
|
| 1418 |
+
"name": "float_hash_work_float16_n128_u8_sorted1",
|
| 1419 |
+
"preset": "stress",
|
| 1420 |
+
"attrs": { "sorted": 1 },
|
| 1421 |
+
"inputs": { "x": { "dtype": "float16", "shape": [128], "dist": "linearMod", "mod": 8 } },
|
| 1422 |
+
"outputs": { "y": { "dtype": "float16", "shape": [8] } },
|
| 1423 |
+
"bench": {
|
| 1424 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1425 |
+
},
|
| 1426 |
+
"vars": { "dtype": "float16" }
|
| 1427 |
+
},
|
| 1428 |
+
{
|
| 1429 |
+
"name": "float_hash_work_float16_n512_u512_sorted0",
|
| 1430 |
+
"preset": "stress",
|
| 1431 |
+
"attrs": { "sorted": 0 },
|
| 1432 |
+
"inputs": { "x": { "dtype": "float16", "shape": [512], "dist": "linearMod", "mod": 512 } },
|
| 1433 |
+
"outputs": { "y": { "dtype": "float16", "shape": [512] } },
|
| 1434 |
+
"bench": {
|
| 1435 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1436 |
+
},
|
| 1437 |
+
"vars": { "dtype": "float16" }
|
| 1438 |
+
},
|
| 1439 |
+
{
|
| 1440 |
+
"name": "float_hash_work_float16_n512_u512_sorted1",
|
| 1441 |
+
"preset": "stress",
|
| 1442 |
+
"attrs": { "sorted": 1 },
|
| 1443 |
+
"inputs": { "x": { "dtype": "float16", "shape": [512], "dist": "linearMod", "mod": 512 } },
|
| 1444 |
+
"outputs": { "y": { "dtype": "float16", "shape": [512] } },
|
| 1445 |
+
"bench": {
|
| 1446 |
+
"metrics": [{ "type": "bandwidth", "value": "dtypeBytes(args.dtype) * (numel(shapes.x) + numel(shapes.y))" }]
|
| 1447 |
+
},
|
| 1448 |
+
"vars": { "dtype": "float16" }
|
| 1449 |
}
|
| 1450 |
+
],
|
| 1451 |
+
"fixtureArrays": {
|
| 1452 |
+
"axis_record_table_marker_collision": [7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 0, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 1, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 2, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 3, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 4, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 5, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 6, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 7, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 8, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 9, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 10, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 11, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 12, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 13, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 14, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 15, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 16, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 17, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 18, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 19, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 20, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 21, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 22, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 23, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 24, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 25, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 26, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 27, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 28, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 29, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 30, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 31, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 32, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 33, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 34, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 35, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 36, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 37, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 38, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 39, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 40, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 41, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 42, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 43, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 44, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 45, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 46, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 47, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 48, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 49, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 50, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 51, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 52, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 53, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 54, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 55, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 56, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 57, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 58, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 59, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 60, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 61, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 62, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 63, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 64, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 65, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 66, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 67, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 68, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 69, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 70, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 71, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 72, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 73, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 74, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 75, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 76, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 77, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 78, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 79, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 80, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 81, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 82, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 83, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 84, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 85, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 86, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 87, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 88, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 89, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 90, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 91, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 92, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 93, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 94, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 95, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 96, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 97, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 98, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 99, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 100, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 101, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 102, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 103, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 104, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 105, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 106, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 107, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 108, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 109, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 110, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 111, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 112, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 113, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 114, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 115, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 116, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 117, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 118, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 119, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 120, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 121, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 122, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 123, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 124, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 125, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 126, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 127, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 128, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 129, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 130, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 131, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 132, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 133, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 134, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 135, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 136, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 137, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 138, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 139, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 140, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 141, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 142, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 143, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 144, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 145, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 146, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 147, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 148, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 149, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 150, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 151, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 152, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 153, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 154, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 155, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 156, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 157, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 158, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 159, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 160, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 161, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 162, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 163, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 164, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 165, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 166, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 167, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 168, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 169, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 170, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 171, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 172, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 173, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 174, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 175, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 176, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 177, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 178, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 179, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 180, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 181, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 182, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 183, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 184, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 185, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 186, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 187, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 188, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 189, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 190, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 191, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 192, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 193, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 194, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 195, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 196, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 197, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 198, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 199, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 200, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 201, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 202, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 203, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 204, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 205, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 206, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 207, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 208, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 209, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 210, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 211, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 212, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 213, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 214, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 215, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 216, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 217, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 218, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 219, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 220, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 221, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 222, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 223, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 224, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 225, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 226, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 227, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 228, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 229, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 230, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 231, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 232, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 233, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 234, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 235, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 236, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 237, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 238, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 239, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 240, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 241, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 242, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 243, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 244, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 245, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 246, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 247, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 248, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 249, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 250, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 251, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 252, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 253, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 254, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 255, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 256, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 257, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 258, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 259, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 260, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 261, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 262, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 263, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 264, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 265, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 266, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 267, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 268, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 269, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 270, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 271, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 272, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 273, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 274, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 275, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 276, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 277, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 278, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 279, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 280, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 281, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 282, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 283, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 284, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 285, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 286, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 287, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 288, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 289, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 290, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 291, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 292, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 293, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 294, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 295, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 296, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 297, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 298, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 299, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 300, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 301, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 302, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 303, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 304, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 305, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 306, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 307, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 308, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 309, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 310, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 311, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 312, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 313, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 314, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 315, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 316, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 317, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 318, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 319, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 320, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 321, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 322, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 323, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 324, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 325, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 326, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 327, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 328, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 329, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 330, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 331, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 332, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 333, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 334, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 335, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 336, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 337, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 338, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 339, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 340, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 341, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 342, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 343, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 344, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 345, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 346, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 347, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 348, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 349, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 350, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 351, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 352, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 353, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 354, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 355, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 356, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 357, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 358, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 359, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 360, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 361, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 362, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 363, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 364, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 365, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 366, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 367, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 368, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 369, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 370, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 371, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 372, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 373, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 374, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 375, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 376, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 377, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 378, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 379, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 380, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 381, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 382, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 383, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 384, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 385, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 386, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 387, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 388, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 389, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 390, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 391, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 392, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 393, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 394, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 395, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 396, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 397, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 398, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 399, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 400, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 401, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 402, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 403, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 404, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 405, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 406, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 407, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 408, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 409, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 410, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 411, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 412, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 413, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 414, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 415, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 416, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 417, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 418, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 419, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 420, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 421, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 422, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 423, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 424, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 425, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 426, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 427, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 428, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 429, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 430, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 431, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 432, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 433, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 434, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 435, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 436, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 437, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 438, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 439, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 440, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 441, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 442, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 443, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 444, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 445, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 446, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 447, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 448, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 449, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 450, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 451, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 452, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 453, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 454, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 455, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 456, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 457, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 458, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 459, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 460, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 461, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 462, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 463, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 464, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 465, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 466, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 467, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 468, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 469, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 470, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 471, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 472, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 473, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 474, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 475, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 476, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 477, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 478, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 479, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 480, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 481, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 482, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 483, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 484, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 485, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 486, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 487, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 488, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 489, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 490, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 491, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 492, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 493, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 494, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 495, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 496, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 497, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 498, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 499, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 500, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 501, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 502, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 503, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 504, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 505, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 506, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 507, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 508, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 509, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 510, 17, 7, 7, 7, 7, 7, 11, 7, 7, 7, 7, 13, 7, 7, 7, 511, 17],
|
| 1453 |
+
"axis-scalar-f32-inverse-duplicate64_input_x": [63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
|
| 1454 |
+
"axis-scalar-f32-inverse-hybrid-floor_input_x": [2048, 2047, 2046, 2045, 2044, 2043, 2042, 2041, 2040, 2039, 2038, 2037, 2036, 2035, 2034, 2033, 2032, 2031, 2030, 2029, 2028, 2027, 2026, 2025, 2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009, 2008, 2007, 2006, 2005, 2004, 2003, 2002, 2001, 2000, 1999, 1998, 1997, 1996, 1995, 1994, 1993, 1992, 1991, 1990, 1989, 1988, 1987, 1986, 1985, 1984, 1983, 1982, 1981, 1980, 1979, 1978, 1977, 1976, 1975, 1974, 1973, 1972, 1971, 1970, 1969, 1968, 1967, 1966, 1965, 1964, 1963, 1962, 1961, 1960, 1959, 1958, 1957, 1956, 1955, 1954, 1953, 1952, 1951, 1950, 1949, 1948, 1947, 1946, 1945, 1944, 1943, 1942, 1941, 1940, 1939, 1938, 1937, 1936, 1935, 1934, 1933, 1932, 1931, 1930, 1929, 1928, 1927, 1926, 1925, 1924, 1923, 1922, 1921, 1920, 1919, 1918, 1917, 1916, 1915, 1914, 1913, 1912, 1911, 1910, 1909, 1908, 1907, 1906, 1905, 1904, 1903, 1902, 1901, 1900, 1899, 1898, 1897, 1896, 1895, 1894, 1893, 1892, 1891, 1890, 1889, 1888, 1887, 1886, 1885, 1884, 1883, 1882, 1881, 1880, 1879, 1878, 1877, 1876, 1875, 1874, 1873, 1872, 1871, 1870, 1869, 1868, 1867, 1866, 1865, 1864, 1863, 1862, 1861, 1860, 1859, 1858, 1857, 1856, 1855, 1854, 1853, 1852, 1851, 1850, 1849, 1848, 1847, 1846, 1845, 1844, 1843, 1842, 1841, 1840, 1839, 1838, 1837, 1836, 1835, 1834, 1833, 1832, 1831, 1830, 1829, 1828, 1827, 1826, 1825, 1824, 1823, 1822, 1821, 1820, 1819, 1818, 1817, 1816, 1815, 1814, 1813, 1812, 1811, 1810, 1809, 1808, 1807, 1806, 1805, 1804, 1803, 1802, 1801, 1800, 1799, 1798, 1797, 1796, 1795, 1794, 1793, 1792, 1791, 1790, 1789, 1788, 1787, 1786, 1785, 1784, 1783, 1782, 1781, 1780, 1779, 1778, 1777, 1776, 1775, 1774, 1773, 1772, 1771, 1770, 1769, 1768, 1767, 1766, 1765, 1764, 1763, 1762, 1761, 1760, 1759, 1758, 1757, 1756, 1755, 1754, 1753, 1752, 1751, 1750, 1749, 1748, 1747, 1746, 1745, 1744, 1743, 1742, 1741, 1740, 1739, 1738, 1737, 1736, 1735, 1734, 1733, 1732, 1731, 1730, 1729, 1728, 1727, 1726, 1725, 1724, 1723, 1722, 1721, 1720, 1719, 1718, 1717, 1716, 1715, 1714, 1713, 1712, 1711, 1710, 1709, 1708, 1707, 1706, 1705, 1704, 1703, 1702, 1701, 1700, 1699, 1698, 1697, 1696, 1695, 1694, 1693, 1692, 1691, 1690, 1689, 1688, 1687, 1686, 1685, 1684, 1683, 1682, 1681, 1680, 1679, 1678, 1677, 1676, 1675, 1674, 1673, 1672, 1671, 1670, 1669, 1668, 1667, 1666, 1665, 1664, 1663, 1662, 1661, 1660, 1659, 1658, 1657, 1656, 1655, 1654, 1653, 1652, 1651, 1650, 1649, 1648, 1647, 1646, 1645, 1644, 1643, 1642, 1641, 1640, 1639, 1638, 1637, 1636, 1635, 1634, 1633, 1632, 1631, 1630, 1629, 1628, 1627, 1626, 1625, 1624, 1623, 1622, 1621, 1620, 1619, 1618, 1617, 1616, 1615, 1614, 1613, 1612, 1611, 1610, 1609, 1608, 1607, 1606, 1605, 1604, 1603, 1602, 1601, 1600, 1599, 1598, 1597, 1596, 1595, 1594, 1593, 1592, 1591, 1590, 1589, 1588, 1587, 1586, 1585, 1584, 1583, 1582, 1581, 1580, 1579, 1578, 1577, 1576, 1575, 1574, 1573, 1572, 1571, 1570, 1569, 1568, 1567, 1566, 1565, 1564, 1563, 1562, 1561, 1560, 1559, 1558, 1557, 1556, 1555, 1554, 1553, 1552, 1551, 1550, 1549, 1548, 1547, 1546, 1545, 1544, 1543, 1542, 1541, 1540, 1539, 1538, 1537, 1536, 1535, 1534, 1533, 1532, 1531, 1530, 1529, 1528, 1527, 1526, 1525, 1524, 1523, 1522, 1521, 1520, 1519, 1518, 1517, 1516, 1515, 1514, 1513, 1512, 1511, 1510, 1509, 1508, 1507, 1506, 1505, 1504, 1503, 1502, 1501, 1500, 1499, 1498, 1497, 1496, 1495, 1494, 1493, 1492, 1491, 1490, 1489, 1488, 1487, 1486, 1485, 1484, 1483, 1482, 1481, 1480, 1479, 1478, 1477, 1476, 1475, 1474, 1473, 1472, 1471, 1470, 1469, 1468, 1467, 1466, 1465, 1464, 1463, 1462, 1461, 1460, 1459, 1458, 1457, 1456, 1455, 1454, 1453, 1452, 1451, 1450, 1449, 1448, 1447, 1446, 1445, 1444, 1443, 1442, 1441, 1440, 1439, 1438, 1437, 1436, 1435, 1434, 1433, 1432, 1431, 1430, 1429, 1428, 1427, 1426, 1425, 1424, 1423, 1422, 1421, 1420, 1419, 1418, 1417, 1416, 1415, 1414, 1413, 1412, 1411, 1410, 1409, 1408, 1407, 1406, 1405, 1404, 1403, 1402, 1401, 1400, 1399, 1398, 1397, 1396, 1395, 1394, 1393, 1392, 1391, 1390, 1389, 1388, 1387, 1386, 1385, 1384, 1383, 1382, 1381, 1380, 1379, 1378, 1377, 1376, 1375, 1374, 1373, 1372, 1371, 1370, 1369, 1368, 1367, 1366, 1365, 1364, 1363, 1362, 1361, 1360, 1359, 1358, 1357, 1356, 1355, 1354, 1353, 1352, 1351, 1350, 1349, 1348, 1347, 1346, 1345, 1344, 1343, 1342, 1341, 1340, 1339, 1338, 1337, 1336, 1335, 1334, 1333, 1332, 1331, 1330, 1329, 1328, 1327, 1326, 1325, 1324, 1323, 1322, 1321, 1320, 1319, 1318, 1317, 1316, 1315, 1314, 1313, 1312, 1311, 1310, 1309, 1308, 1307, 1306, 1305, 1304, 1303, 1302, 1301, 1300, 1299, 1298, 1297, 1296, 1295, 1294, 1293, 1292, 1291, 1290, 1289, 1288, 1287, 1286, 1285, 1284, 1283, 1282, 1281, 1280, 1279, 1278, 1277, 1276, 1275, 1274, 1273, 1272, 1271, 1270, 1269, 1268, 1267, 1266, 1265, 1264, 1263, 1262, 1261, 1260, 1259, 1258, 1257, 1256, 1255, 1254, 1253, 1252, 1251, 1250, 1249, 1248, 1247, 1246, 1245, 1244, 1243, 1242, 1241, 1240, 1239, 1238, 1237, 1236, 1235, 1234, 1233, 1232, 1231, 1230, 1229, 1228, 1227, 1226, 1225, 1224, 1223, 1222, 1221, 1220, 1219, 1218, 1217, 1216, 1215, 1214, 1213, 1212, 1211, 1210, 1209, 1208, 1207, 1206, 1205, 1204, 1203, 1202, 1201, 1200, 1199, 1198, 1197, 1196, 1195, 1194, 1193, 1192, 1191, 1190, 1189, 1188, 1187, 1186, 1185, 1184, 1183, 1182, 1181, 1180, 1179, 1178, 1177, 1176, 1175, 1174, 1173, 1172, 1171, 1170, 1169, 1168, 1167, 1166, 1165, 1164, 1163, 1162, 1161, 1160, 1159, 1158, 1157, 1156, 1155, 1154, 1153, 1152, 1151, 1150, 1149, 1148, 1147, 1146, 1145, 1144, 1143, 1142, 1141, 1140, 1139, 1138, 1137, 1136, 1135, 1134, 1133, 1132, 1131, 1130, 1129, 1128, 1127, 1126, 1125, 1124, 1123, 1122, 1121, 1120, 1119, 1118, 1117, 1116, 1115, 1114, 1113, 1112, 1111, 1110, 1109, 1108, 1107, 1106, 1105, 1104, 1103, 1102, 1101, 1100, 1099, 1098, 1097, 1096, 1095, 1094, 1093, 1092, 1091, 1090, 1089, 1088, 1087, 1086, 1085, 1084, 1083, 1082, 1081, 1080, 1079, 1078, 1077, 1076, 1075, 1074, 1073, 1072, 1071, 1070, 1069, 1068, 1067, 1066, 1065, 1064, 1063, 1062, 1061, 1060, 1059, 1058, 1057, 1056, 1055, 1054, 1053, 1052, 1051, 1050, 1049, 1048, 1047, 1046, 1045, 1044, 1043, 1042, 1041, 1040, 1039, 1038, 1037, 1036, 1035, 1034, 1033, 1032, 1031, 1030, 1029, 1028, 1027, 1026, 1025, 1024, 1023, 1022, 1021, 1020, 1019, 1018, 1017, 1016, 1015, 1014, 1013, 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1005, 1004, 1003, 1002, 1001, 1000, 999, 998, 997, 996, 995, 994, 993, 992, 991, 990, 989, 988, 987, 986, 985, 984, 983, 982, 981, 980, 979, 978, 977, 976, 975, 974, 973, 972, 971, 970, 969, 968, 967, 966, 965, 964, 963, 962, 961, 960, 959, 958, 957, 956, 955, 954, 953, 952, 951, 950, 949, 948, 947, 946, 945, 944, 943, 942, 941, 940, 939, 938, 937, 936, 935, 934, 933, 932, 931, 930, 929, 928, 927, 926, 925, 924, 923, 922, 921, 920, 919, 918, 917, 916, 915, 914, 913, 912, 911, 910, 909, 908, 907, 906, 905, 904, 903, 902, 901, 900, 899, 898, 897, 896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885, 884, 883, 882, 881, 880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855, 854, 853, 852, 851, 850, 849, 848, 847, 846, 845, 844, 843, 842, 841, 840, 839, 838, 837, 836, 835, 834, 833, 832, 831, 830, 829, 828, 827, 826, 825, 824, 823, 822, 821, 820, 819, 818, 817, 816, 815, 814, 813, 812, 811, 810, 809, 808, 807, 806, 805, 804, 803, 802, 801, 800, 799, 798, 797, 796, 795, 794, 793, 792, 791, 790, 789, 788, 787, 786, 785, 784, 783, 782, 781, 780, 779, 778, 777, 776, 775, 774, 773, 772, 771, 770, 769, 768, 767, 766, 765, 764, 763, 762, 761, 760, 759, 758, 757, 756, 755, 754, 753, 752, 751, 750, 749, 748, 747, 746, 745, 744, 743, 742, 741, 740, 739, 738, 737, 736, 735, 734, 733, 732, 731, 730, 729, 728, 727, 726, 725, 724, 723, 722, 721, 720, 719, 718, 717, 716, 715, 714, 713, 712, 711, 710, 709, 708, 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, 677, 676, 675, 674, 673, 672, 671, 670, 669, 668, 667, 666, 665, 664, 663, 662, 661, 660, 659, 658, 657, 656, 655, 654, 653, 652, 651, 650, 649, 648, 647, 646, 645, 644, 643, 642, 641, 640, 639, 638, 637, 636, 635, 634, 633, 632, 631, 630, 629, 628, 627, 626, 625, 624, 623, 622, 621, 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
| 1455 |
+
}
|
| 1456 |
}
|
build/webgpu/manifest.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,30 +1,116 @@
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.Unique",
|
| 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 |
-
"manifest.json": "/
|
| 12 |
-
"
|
| 13 |
-
"
|
| 14 |
-
"unique-axis-
|
| 15 |
-
"unique-axis-
|
| 16 |
-
"unique-axis-
|
| 17 |
-
"unique-axis.wgsl.jinja": "
|
| 18 |
-
"unique-
|
|
|
|
|
|
|
|
|
|
| 19 |
"unique-dedup.wgsl.jinja": "muTd580L/rfaL/p5NjOwMPp2F3ALTR9S7SzVYl9r+wQ=",
|
| 20 |
-
"unique-
|
| 21 |
-
"unique-
|
| 22 |
-
"unique-
|
| 23 |
-
"unique-
|
| 24 |
-
"unique-
|
| 25 |
-
"unique.wgsl.jinja": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
| 27 |
},
|
| 28 |
-
"provenance": { "kernel": { "sha": "
|
| 29 |
-
"webgpu": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.Unique",
|
| 3 |
+
"id": "_ai_onnx_unique_webgpu_b3bffe7",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"bench.json": "6IjCP8Xe2mSSuxPK7xy73JMu42BF5ZgUhgwgS3Y2qcM=",
|
| 11 |
+
"manifest.json": "LLZErOf8Z+wJ7nP3zzdL38BwDHrMScCWVqLZ/v/bC/I=",
|
| 12 |
+
"scan-block-prefix-u32.wgsl.jinja": "EDY0dOyl7TX0GjGdfkGRqho+8VaqNTv69XIUAGWwW7w=",
|
| 13 |
+
"test.json": "4n/yg8WUYERuAKaqDlVQLlpguI6LoD/VkjllQSd/r+A=",
|
| 14 |
+
"unique-axis-compact-sort.wgsl.jinja": "USY2zwmM0qLzs5Zu+jeWhvsF/kksOxlMdBCRQyzSeEI=",
|
| 15 |
+
"unique-axis-dedup.wgsl.jinja": "tdp/nGtmgjimm0FRK2Q+nVPJXabpIbsE53/N88b6ZkI=",
|
| 16 |
+
"unique-axis-hash.wgsl.jinja": "KIRzJC48pNLKin6XkQlYmlOdj7UaMvHlHkORtDJBHbg=",
|
| 17 |
+
"unique-axis-scalar-inverse.wgsl.jinja": "8XJ/PidrZqxZ7E4exCzsghcDAnDkBWO6XhKoneojGMo=",
|
| 18 |
+
"unique-axis-scalar-ranks.wgsl.jinja": "MKa09aSgiScgGAke+eaZ8ECSPtZl1DvQRJhNnsGhx9Q=",
|
| 19 |
+
"unique-axis-scatter.wgsl.jinja": "H4nuOCxlxZHOBVm71ht58g4oFZfEwT+pXLXbx0yhjU0=",
|
| 20 |
+
"unique-axis.wgsl.jinja": "xGYbso+QeI9d4zpCXmrwWaueY1/dNII5ton7Nl6qAZQ=",
|
| 21 |
+
"unique-compact-sort.wgsl.jinja": "V1et+Wyn4847Ej1jkpjfPGBfexgbpKk1bk6VIapFU3o=",
|
| 22 |
"unique-dedup.wgsl.jinja": "muTd580L/rfaL/p5NjOwMPp2F3ALTR9S7SzVYl9r+wQ=",
|
| 23 |
+
"unique-flag-block-scan.wgsl.jinja": "UHiW1pUoMetLcSVFtbb27NBiHyrj1BqnpvsmKHR4eUo=",
|
| 24 |
+
"unique-flat-metadata.wgsl.jinja": "DjjbOABSeqFVcZWMK3tfyBjT+1IxqRaF8IkSb1LbHNI=",
|
| 25 |
+
"unique-global-sort-exchange.wgsl.jinja": "ycyAh+i1Jf8f827QgsW8JFZsyPuTSq8dTe9eID4FtG8=",
|
| 26 |
+
"unique-global-sort-output.wgsl.jinja": "OHzPDIUYaZ71Lb0s+dkXqvYTUyQD5j5WOrb4pl2ehcE=",
|
| 27 |
+
"unique-global-sort-shared.wgsl.jinja": "PrT6/StTV6cAJKH9RsoQ9DL8jMi7xgBiUoxIl5Nhbuo=",
|
| 28 |
+
"unique-hash-build.wgsl.jinja": "R6FsBjCfL8Gs8Obi+UT7TPXH66BM4PlmA7N5zcf6boY=",
|
| 29 |
+
"unique-hash-collect.wgsl.jinja": "QjGT7dXhz4D9ka0Ry6EDJyCk+4ZxqEWZ7CQvaLl00lg=",
|
| 30 |
+
"unique-hash-init.wgsl.jinja": "oijfIva4kwhMMSpHUUWnwAEA3mZZhVSr4wQaXHgqaBI=",
|
| 31 |
+
"unique-hash-mark.wgsl.jinja": "vNqJd6BsN5s1QyOwoZfurA7FMKeSDA7n8+8t9IzvDaA=",
|
| 32 |
+
"unique-hash-sort-collected-key-only.wgsl.jinja": "r3/0IAivXcDWz5je9+0kn+EMahlO7IsQAqggcMPG01g=",
|
| 33 |
+
"unique-scalar-compact.wgsl.jinja": "icYtAk99HoPQMRoKcaDuBKhbiBZQabtx1+EnvM9AXSU=",
|
| 34 |
+
"unique-scalar-metadata.wgsl.jinja": "9K5i3e7rE0hGfnS9y1knf9M/IZNMRztJ2/mijo1uUvw=",
|
| 35 |
+
"unique-scalar-output.wgsl.jinja": "AzH6/sqeVpuLzEA8BN8I9u7eOz3cqvoDqLst5Awh31Q=",
|
| 36 |
+
"unique-single-class.wgsl.jinja": "7eZJTSljWA00bg6rPO5YbebToQuzuhd99IFCXbf96Fs=",
|
| 37 |
+
"unique.wgsl.jinja": "cwLLFAvO05OQZw6C6xpXeQgJPuwQTymG1PjBtHwwBmM="
|
| 38 |
}
|
| 39 |
},
|
| 40 |
+
"provenance": { "kernel": { "sha": "91d990483a174128daf7673f3f37a7c890493ae1", "dirty": false } },
|
| 41 |
+
"webgpu": {
|
| 42 |
+
"manifestSpec": "2.0",
|
| 43 |
+
"variants": {
|
| 44 |
+
"single_class_y": ["unique-single-class.wgsl.jinja"],
|
| 45 |
+
"scalar_hash_parallel_y_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 46 |
+
"scalar_hash_parallel_y_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 47 |
+
"single_class_indices": ["unique-single-class.wgsl.jinja"],
|
| 48 |
+
"scalar_hash_parallel_indices_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 49 |
+
"scalar_hash_parallel_indices_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 50 |
+
"single_class_inverse": ["unique-single-class.wgsl.jinja"],
|
| 51 |
+
"scalar_hash_parallel_inverse_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 52 |
+
"scalar_hash_parallel_inverse_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 53 |
+
"single_class_indices_inverse": ["unique-single-class.wgsl.jinja"],
|
| 54 |
+
"scalar_hash_parallel_indices_inverse_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 55 |
+
"scalar_hash_parallel_indices_inverse_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 56 |
+
"single_class_counts": ["unique-single-class.wgsl.jinja"],
|
| 57 |
+
"scalar_hash_parallel_counts_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 58 |
+
"scalar_hash_parallel_counts_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 59 |
+
"single_class_indices_counts": ["unique-single-class.wgsl.jinja"],
|
| 60 |
+
"scalar_hash_parallel_indices_counts_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 61 |
+
"scalar_hash_parallel_indices_counts_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 62 |
+
"single_class_inverse_counts": ["unique-single-class.wgsl.jinja"],
|
| 63 |
+
"scalar_hash_parallel_inverse_counts_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 64 |
+
"scalar_hash_parallel_inverse_counts_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 65 |
+
"single_class_indices_inverse_counts": ["unique-single-class.wgsl.jinja"],
|
| 66 |
+
"scalar_hash_parallel_indices_inverse_counts_unsorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 67 |
+
"scalar_hash_parallel_indices_inverse_counts_sorted": ["scan-block-prefix-u32.wgsl.jinja", "unique-flag-block-scan.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja", "unique-scalar-compact.wgsl.jinja", "unique-scalar-metadata.wgsl.jinja", "unique-scalar-output.wgsl.jinja"],
|
| 68 |
+
"hash_dedup_hybrid_sort_large_y": ["unique-compact-sort.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-output.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 69 |
+
"hash_dedup_large_y": ["unique-compact-sort.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 70 |
+
"hash_dedup_large_y_unsorted": ["unique-compact-sort.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 71 |
+
"axis_scalar_hash_hybrid_metadata_inverse": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-scalar-inverse.wgsl.jinja", "unique-axis-scalar-ranks.wgsl.jinja", "unique-axis-scatter.wgsl.jinja", "unique-global-sort-exchange.wgsl.jinja", "unique-global-sort-shared.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 72 |
+
"axis_scalar_hash_metadata_inverse": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-scalar-inverse.wgsl.jinja", "unique-axis-scalar-ranks.wgsl.jinja", "unique-axis-scatter.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 73 |
+
"axis_scalar_hash_metadata_inverse_unsorted": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-scalar-inverse.wgsl.jinja", "unique-axis-scalar-ranks.wgsl.jinja", "unique-axis-scatter.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 74 |
+
"hash_dedup_sorted_collect": ["unique-hash-build.wgsl.jinja", "unique-hash-collect.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-sort-collected-key-only.wgsl.jinja"],
|
| 75 |
+
"hash_dedup": ["unique-compact-sort.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 76 |
+
"rank1_bounded": ["unique.wgsl.jinja"],
|
| 77 |
+
"axis_serial": ["unique-axis.wgsl.jinja"],
|
| 78 |
+
"axis_hash_bounded": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-hash.wgsl.jinja", "unique-axis-scatter.wgsl.jinja"],
|
| 79 |
+
"axis_hash_bounded_unsorted": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-hash.wgsl.jinja", "unique-axis-scatter.wgsl.jinja"],
|
| 80 |
+
"axis_hash_bounded_nan_safe": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-hash.wgsl.jinja", "unique-axis-scatter.wgsl.jinja", "unique-axis.wgsl.jinja"],
|
| 81 |
+
"axis_hash_bounded_unsorted_nan_safe": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-hash.wgsl.jinja", "unique-axis-scatter.wgsl.jinja", "unique-axis.wgsl.jinja"],
|
| 82 |
+
"parallel_dedup": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja"],
|
| 83 |
+
"parallel_dedup_large_y": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja"],
|
| 84 |
+
"parallel_dedup_large_y_unsorted": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja"],
|
| 85 |
+
"axis_bounded": ["unique-axis-compact-sort.wgsl.jinja", "unique-axis-dedup.wgsl.jinja"],
|
| 86 |
+
"flat_metadata_indices": ["unique.wgsl.jinja"],
|
| 87 |
+
"axis_metadata_indices": ["unique-axis.wgsl.jinja"],
|
| 88 |
+
"flat_metadata_inverse": ["unique.wgsl.jinja"],
|
| 89 |
+
"axis_metadata_inverse": ["unique-axis.wgsl.jinja"],
|
| 90 |
+
"flat_metadata_counts": ["unique.wgsl.jinja"],
|
| 91 |
+
"axis_metadata_counts": ["unique-axis.wgsl.jinja"],
|
| 92 |
+
"flat_metadata_indices_inverse": ["unique.wgsl.jinja"],
|
| 93 |
+
"axis_metadata_indices_inverse": ["unique-axis.wgsl.jinja"],
|
| 94 |
+
"flat_metadata_indices_counts": ["unique.wgsl.jinja"],
|
| 95 |
+
"axis_metadata_indices_counts": ["unique-axis.wgsl.jinja"],
|
| 96 |
+
"flat_metadata_inverse_counts": ["unique.wgsl.jinja"],
|
| 97 |
+
"axis_metadata_inverse_counts": ["unique-axis.wgsl.jinja"],
|
| 98 |
+
"flat_metadata_all": ["unique.wgsl.jinja"],
|
| 99 |
+
"axis_metadata_all": ["unique-axis.wgsl.jinja"],
|
| 100 |
+
"flat_parallel_metadata_indices": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 101 |
+
"flat_parallel_metadata_inverse": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 102 |
+
"flat_parallel_metadata_indices_inverse": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 103 |
+
"flat_parallel_metadata_counts": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 104 |
+
"flat_parallel_metadata_indices_counts": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 105 |
+
"flat_parallel_metadata_inverse_counts": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 106 |
+
"flat_parallel_metadata_all": ["unique-compact-sort.wgsl.jinja", "unique-dedup.wgsl.jinja", "unique-flat-metadata.wgsl.jinja"],
|
| 107 |
+
"flat_hash_metadata_indices": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 108 |
+
"flat_hash_metadata_inverse": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 109 |
+
"flat_hash_metadata_indices_inverse": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 110 |
+
"flat_hash_metadata_counts": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 111 |
+
"flat_hash_metadata_indices_counts": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 112 |
+
"flat_hash_metadata_inverse_counts": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"],
|
| 113 |
+
"flat_hash_metadata_all": ["unique-compact-sort.wgsl.jinja", "unique-flat-metadata.wgsl.jinja", "unique-hash-build.wgsl.jinja", "unique-hash-init.wgsl.jinja", "unique-hash-mark.wgsl.jinja"]
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
}
|
build/webgpu/scan-block-prefix-u32.wgsl.jinja
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Single-workgroup exclusive scan over per-block sums for stream compaction.
|
| 2 |
+
// The dispatch is (1, 1, 1). It walks blockSums in workgroup-sized chunks,
|
| 3 |
+
// scans each chunk with Hillis-Steele or subgroup collectives, and links chunks
|
| 4 |
+
// with a running carry. blockPrefix[b] is therefore the number of set flags in
|
| 5 |
+
// all blocks before b. The total count is the last prefix plus the last sum.
|
| 6 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 7 |
+
|
| 8 |
+
const WG: u32 = {{ workgroupSize }}u;
|
| 9 |
+
|
| 10 |
+
var<workgroup> wgScan: array<u32, WG>;
|
| 11 |
+
|
| 12 |
+
@compute @workgroup_size(WG, 1, 1)
|
| 13 |
+
fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
| 14 |
+
let tid = lid.x;
|
| 15 |
+
var carry = 0u;
|
| 16 |
+
let chunks = (params.numBlocks + WG - 1u) / WG;
|
| 17 |
+
for (var c = 0u; c < chunks; c = c + 1u) {
|
| 18 |
+
let j = c * WG + tid;
|
| 19 |
+
var v = 0u;
|
| 20 |
+
if (j < params.numBlocks) {
|
| 21 |
+
v = blockSums[j];
|
| 22 |
+
}
|
| 23 |
+
workgroupBarrier();
|
| 24 |
+
wgScan[tid] = v;
|
| 25 |
+
for (var step = 1u; step < WG; step = step << 1u) {
|
| 26 |
+
workgroupBarrier();
|
| 27 |
+
var prev = 0u;
|
| 28 |
+
if (tid >= step) {
|
| 29 |
+
prev = wgScan[tid - step];
|
| 30 |
+
}
|
| 31 |
+
workgroupBarrier();
|
| 32 |
+
wgScan[tid] = wgScan[tid] + prev;
|
| 33 |
+
}
|
| 34 |
+
workgroupBarrier();
|
| 35 |
+
if (j < params.numBlocks) {
|
| 36 |
+
var value = carry;
|
| 37 |
+
if (tid > 0u) {
|
| 38 |
+
value = carry + wgScan[tid - 1u];
|
| 39 |
+
}
|
| 40 |
+
blockPrefix[j] = value;
|
| 41 |
+
}
|
| 42 |
+
carry = carry + wgScan[WG - 1u];
|
| 43 |
+
}
|
| 44 |
+
}
|
build/webgpu/test.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
build/webgpu/unique-axis-compact-sort.wgsl.jinja
CHANGED
|
@@ -1,16 +1,16 @@
|
|
| 1 |
-
{% if usesF16 %}
|
| 2 |
-
enable f16;
|
| 3 |
-
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
-
{% set emitCount =
|
| 6 |
|
| 7 |
// Compact every first-occurrence slice index, optionally bitonic-sort them,
|
| 8 |
// then scatter the exact result. Small results keep slots in workgroup memory;
|
| 9 |
// larger results use storage-buffer scratch with storage barriers.
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
const
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
{% endif %}
|
| 16 |
{% if sorted %}
|
|
@@ -38,6 +38,7 @@ fn canon_key(v: {{ scalar }}) -> u32 {
|
|
| 38 |
}
|
| 39 |
|
| 40 |
{% endif %}
|
|
|
|
| 41 |
fn less_value(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
| 42 |
{% if isFloat %}
|
| 43 |
return canon_key(a) < canon_key(b);
|
|
@@ -45,9 +46,10 @@ fn less_value(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
|
| 45 |
return a < b;
|
| 46 |
{% endif %}
|
| 47 |
}
|
|
|
|
| 48 |
|
| 49 |
{% endif %}
|
| 50 |
-
{% if sorted or not
|
| 51 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 52 |
return x[(o * params.axisDim + k) * params.inner + n];
|
| 53 |
}
|
|
@@ -56,6 +58,7 @@ fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
|
| 56 |
{% if sorted %}
|
| 57 |
// True iff slice a < slice b lexicographically over (outer, inner) element order.
|
| 58 |
// The serial insertion sort uses the same comparator.
|
|
|
|
| 59 |
fn slice_less(a: u32, b: u32) -> bool {
|
| 60 |
for (var o = 0u; o < params.outer; o = o + 1u) {
|
| 61 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
|
@@ -68,6 +71,7 @@ fn slice_less(a: u32, b: u32) -> bool {
|
|
| 68 |
return false;
|
| 69 |
}
|
| 70 |
|
|
|
|
| 71 |
// Cache the first element's monotonic integer-order key alongside each slot so
|
| 72 |
// the bitonic network normally compares only threadgroup u32s; equal keys still
|
| 73 |
// use the exact full-slice comparator.
|
|
@@ -83,7 +87,7 @@ fn slice_primary_key(k: u32) -> u32 {
|
|
| 83 |
}
|
| 84 |
|
| 85 |
{% endif %}
|
| 86 |
-
{% if not
|
| 87 |
// Keep exact-result axis scatter identical across static- and dynamic-shape
|
| 88 |
// dispatch strategies. The zero branch is a defensive guard for invalid shapes.
|
| 89 |
fn unique_axis_zero_value() -> {{ scalar }} {
|
|
@@ -91,10 +95,17 @@ fn unique_axis_zero_value() -> {{ scalar }} {
|
|
| 91 |
}
|
| 92 |
|
| 93 |
fn unique_axis_scatter_element(g: u32, written: u32) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
let n = g % params.inner;
|
| 95 |
let tmp = g / params.inner;
|
| 96 |
let p = tmp % params.outputAxisDim;
|
| 97 |
let o = tmp / params.outputAxisDim;
|
|
|
|
| 98 |
if (p < written) {
|
| 99 |
y[g] = slice_at(o, slots[p], n);
|
| 100 |
} else {
|
|
@@ -105,11 +116,11 @@ fn unique_axis_scatter_element(g: u32, written: u32) {
|
|
| 105 |
|
| 106 |
{% endif %}
|
| 107 |
var<workgroup> wgScan: array<u32, WG>;
|
| 108 |
-
{% if not
|
| 109 |
var<workgroup> slots: array<u32, SORT_N>; // compacted (then sorted) slice indices
|
| 110 |
{% endif %}
|
| 111 |
var<workgroup> wgCarry: u32;
|
| 112 |
-
{% if sorted and not
|
| 113 |
var<workgroup> sortPad: array<u32, SORT_N>; // 1 = padding slot, sorts after every real
|
| 114 |
var<workgroup> sortKey: array<u32, SORT_N>; // first-element total-order key
|
| 115 |
|
|
@@ -156,7 +167,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 156 |
}
|
| 157 |
|
| 158 |
let total = wgCarry;
|
| 159 |
-
{% if sorted or not
|
| 160 |
let written = min(total, CAP);
|
| 161 |
{% endif %}
|
| 162 |
{% if emitCount %}
|
|
@@ -164,7 +175,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 164 |
count[0] = total;
|
| 165 |
}
|
| 166 |
{% endif %}
|
| 167 |
-
{% if
|
| 168 |
storageBarrier();
|
| 169 |
|
| 170 |
{% endif %}
|
|
@@ -181,12 +192,13 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 181 |
sortKey[k] = slice_primary_key(slots[k]);
|
| 182 |
}
|
| 183 |
}
|
| 184 |
-
{% if
|
| 185 |
storageBarrier();
|
| 186 |
{% else %}
|
| 187 |
workgroupBarrier();
|
| 188 |
{% endif %}
|
| 189 |
|
|
|
|
| 190 |
var size = 2u;
|
| 191 |
loop {
|
| 192 |
if (size > SORT_N) { break; }
|
|
@@ -228,7 +240,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 228 |
}
|
| 229 |
}
|
| 230 |
}
|
| 231 |
-
{% if
|
| 232 |
storageBarrier();
|
| 233 |
{% else %}
|
| 234 |
workgroupBarrier();
|
|
@@ -238,12 +250,10 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 238 |
size = size * 2u;
|
| 239 |
}
|
| 240 |
{% endif %}
|
| 241 |
-
{% if not source.compactOnly %}
|
| 242 |
-
{% if source.globalScratch %}
|
| 243 |
-
storageBarrier();
|
| 244 |
-
{% else %}
|
| 245 |
-
workgroupBarrier();
|
| 246 |
{% endif %}
|
|
|
|
|
|
|
|
|
|
| 247 |
|
| 248 |
// Scatter the distinct slices into the exact Y allocation: one lane per
|
| 249 |
// output element, flat index g = (o*outputAxisDim + p)*inner + n.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
+
{% set emitCount = emitCount | default(false) %}
|
| 3 |
|
| 4 |
// Compact every first-occurrence slice index, optionally bitonic-sort them,
|
| 5 |
// then scatter the exact result. Small results keep slots in workgroup memory;
|
| 6 |
// larger results use storage-buffer scratch with storage barriers.
|
| 7 |
+
// Global-scratch variants reserve workgroup memory only for the scan buffer and
|
| 8 |
+
// provide an independent sort width. Workgroup-scratch variants use the shared
|
| 9 |
+
// workgroup-width setting.
|
| 10 |
+
const WG: u32 = {{ sortWg | default(tunables.WORKGROUP_SIZE) }}u;
|
| 11 |
+
const CAP: u32 = {{ capacity }}u;
|
| 12 |
+
{% if sorted or not globalScratch %}
|
| 13 |
+
const SORT_N: u32 = {{ sortN }}u;
|
| 14 |
|
| 15 |
{% endif %}
|
| 16 |
{% if sorted %}
|
|
|
|
| 38 |
}
|
| 39 |
|
| 40 |
{% endif %}
|
| 41 |
+
{% if not (sortExternally | default(false)) %}
|
| 42 |
fn less_value(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
| 43 |
{% if isFloat %}
|
| 44 |
return canon_key(a) < canon_key(b);
|
|
|
|
| 46 |
return a < b;
|
| 47 |
{% endif %}
|
| 48 |
}
|
| 49 |
+
{% endif %}
|
| 50 |
|
| 51 |
{% endif %}
|
| 52 |
+
{% if sorted or not compactOnly %}
|
| 53 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 54 |
return x[(o * params.axisDim + k) * params.inner + n];
|
| 55 |
}
|
|
|
|
| 58 |
{% if sorted %}
|
| 59 |
// True iff slice a < slice b lexicographically over (outer, inner) element order.
|
| 60 |
// The serial insertion sort uses the same comparator.
|
| 61 |
+
{% if not (sortExternally | default(false)) %}
|
| 62 |
fn slice_less(a: u32, b: u32) -> bool {
|
| 63 |
for (var o = 0u; o < params.outer; o = o + 1u) {
|
| 64 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
|
|
|
| 71 |
return false;
|
| 72 |
}
|
| 73 |
|
| 74 |
+
{% endif %}
|
| 75 |
// Cache the first element's monotonic integer-order key alongside each slot so
|
| 76 |
// the bitonic network normally compares only threadgroup u32s; equal keys still
|
| 77 |
// use the exact full-slice comparator.
|
|
|
|
| 87 |
}
|
| 88 |
|
| 89 |
{% endif %}
|
| 90 |
+
{% if not compactOnly %}
|
| 91 |
// Keep exact-result axis scatter identical across static- and dynamic-shape
|
| 92 |
// dispatch strategies. The zero branch is a defensive guard for invalid shapes.
|
| 93 |
fn unique_axis_zero_value() -> {{ scalar }} {
|
|
|
|
| 95 |
}
|
| 96 |
|
| 97 |
fn unique_axis_scatter_element(g: u32, written: u32) {
|
| 98 |
+
{% if staticShape is defined and staticShape %}
|
| 99 |
+
let n = g % INNER;
|
| 100 |
+
let tmp = g / INNER;
|
| 101 |
+
let p = tmp % OUTPUT_AXIS_DIM;
|
| 102 |
+
let o = tmp / OUTPUT_AXIS_DIM;
|
| 103 |
+
{% else %}
|
| 104 |
let n = g % params.inner;
|
| 105 |
let tmp = g / params.inner;
|
| 106 |
let p = tmp % params.outputAxisDim;
|
| 107 |
let o = tmp / params.outputAxisDim;
|
| 108 |
+
{% endif %}
|
| 109 |
if (p < written) {
|
| 110 |
y[g] = slice_at(o, slots[p], n);
|
| 111 |
} else {
|
|
|
|
| 116 |
|
| 117 |
{% endif %}
|
| 118 |
var<workgroup> wgScan: array<u32, WG>;
|
| 119 |
+
{% if not globalScratch %}
|
| 120 |
var<workgroup> slots: array<u32, SORT_N>; // compacted (then sorted) slice indices
|
| 121 |
{% endif %}
|
| 122 |
var<workgroup> wgCarry: u32;
|
| 123 |
+
{% if sorted and not globalScratch %}
|
| 124 |
var<workgroup> sortPad: array<u32, SORT_N>; // 1 = padding slot, sorts after every real
|
| 125 |
var<workgroup> sortKey: array<u32, SORT_N>; // first-element total-order key
|
| 126 |
|
|
|
|
| 167 |
}
|
| 168 |
|
| 169 |
let total = wgCarry;
|
| 170 |
+
{% if sorted or not compactOnly %}
|
| 171 |
let written = min(total, CAP);
|
| 172 |
{% endif %}
|
| 173 |
{% if emitCount %}
|
|
|
|
| 175 |
count[0] = total;
|
| 176 |
}
|
| 177 |
{% endif %}
|
| 178 |
+
{% if globalScratch %}
|
| 179 |
storageBarrier();
|
| 180 |
|
| 181 |
{% endif %}
|
|
|
|
| 192 |
sortKey[k] = slice_primary_key(slots[k]);
|
| 193 |
}
|
| 194 |
}
|
| 195 |
+
{% if globalScratch %}
|
| 196 |
storageBarrier();
|
| 197 |
{% else %}
|
| 198 |
workgroupBarrier();
|
| 199 |
{% endif %}
|
| 200 |
|
| 201 |
+
{% if not (sortExternally | default(false)) %}
|
| 202 |
var size = 2u;
|
| 203 |
loop {
|
| 204 |
if (size > SORT_N) { break; }
|
|
|
|
| 240 |
}
|
| 241 |
}
|
| 242 |
}
|
| 243 |
+
{% if globalScratch %}
|
| 244 |
storageBarrier();
|
| 245 |
{% else %}
|
| 246 |
workgroupBarrier();
|
|
|
|
| 250 |
size = size * 2u;
|
| 251 |
}
|
| 252 |
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
{% endif %}
|
| 254 |
+
{% if not compactOnly %}
|
| 255 |
+
// The workgroup-scratch form scatters its compacted slots directly.
|
| 256 |
+
workgroupBarrier();
|
| 257 |
|
| 258 |
// Scatter the distinct slices into the exact Y allocation: one lane per
|
| 259 |
// output element, flat index g = (o*outputAxisDim + p)*inner + n.
|
build/webgpu/unique-axis-dedup.wgsl.jinja
CHANGED
|
@@ -7,17 +7,15 @@
|
|
| 7 |
// (o in outer, n in inner). This parallel path compares only integer storage
|
| 8 |
// values.
|
| 9 |
//
|
| 10 |
-
//
|
| 11 |
-
//
|
| 12 |
-
//
|
| 13 |
-
//
|
| 14 |
-
// memory. A fingerprint mismatch proves inequality; collisions fall through to
|
| 15 |
-
// the exact element-wise comparator, so this is an optimization only and cannot
|
| 16 |
-
// change Unique semantics.
|
| 17 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 18 |
return x[(o * params.axisDim + k) * params.inner + n];
|
| 19 |
}
|
| 20 |
|
|
|
|
| 21 |
fn value_key(value: {{ scalar }}) -> u32 {
|
| 22 |
// Integer conversion is injective for the 8/32-bit integer storage types.
|
| 23 |
return u32(value);
|
|
@@ -29,23 +27,26 @@ fn mix_key(hash: u32, value: u32) -> u32 {
|
|
| 29 |
return h;
|
| 30 |
}
|
| 31 |
|
|
|
|
|
|
|
|
|
|
| 32 |
fn slice_key(k: u32) -> u32 {
|
| 33 |
-
let elements = params.outer * params.inner;
|
| 34 |
-
if (elements == 0u) { return 0u; }
|
| 35 |
-
|
| 36 |
-
// Four evenly-spaced samples make the prefilter useful for structured rows
|
| 37 |
-
// whose leading value is shared, while keeping the staging pass tiny.
|
| 38 |
-
let last = elements - 1u;
|
| 39 |
var hash = 0x811c9dc5u;
|
| 40 |
-
for (var
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
hash = mix_key(hash, value_key(slice_at(o, k, n)));
|
| 45 |
}
|
| 46 |
return hash;
|
| 47 |
}
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
fn slice_eq(a: u32, b: u32) -> bool {
|
| 50 |
for (var o = 0u; o < params.outer; o = o + 1u) {
|
| 51 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
|
@@ -66,7 +67,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
|
| 66 |
let laneValid = k < params.axisDim;
|
| 67 |
var kKey = 0u;
|
| 68 |
if (laneValid) {
|
| 69 |
-
kKey =
|
| 70 |
}
|
| 71 |
|
| 72 |
var seen = false;
|
|
@@ -78,7 +79,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
|
| 78 |
let loadK = chunkBase + lid.x;
|
| 79 |
var loadedKey = 0u;
|
| 80 |
if (loadK < params.axisDim) {
|
| 81 |
-
loadedKey =
|
| 82 |
}
|
| 83 |
keyCache[lid.x] = loadedKey;
|
| 84 |
workgroupBarrier();
|
|
@@ -103,3 +104,4 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
|
| 103 |
firstFlag[k] = select(1u, 0u, seen);
|
| 104 |
}
|
| 105 |
}
|
|
|
|
|
|
| 7 |
// (o in outer, n in inner). This parallel path compares only integer storage
|
| 8 |
// values.
|
| 9 |
//
|
| 10 |
+
// A separate pass fingerprints each slice into `sliceKeys`, and each workgroup
|
| 11 |
+
// stages a chunk of those fingerprints in shared memory. A mismatch proves
|
| 12 |
+
// inequality; collisions fall through to the exact element-wise comparator, so
|
| 13 |
+
// fingerprints cannot change Unique semantics.
|
|
|
|
|
|
|
|
|
|
| 14 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 15 |
return x[(o * params.axisDim + k) * params.inner + n];
|
| 16 |
}
|
| 17 |
|
| 18 |
+
{% if stage == "keys" %}
|
| 19 |
fn value_key(value: {{ scalar }}) -> u32 {
|
| 20 |
// Integer conversion is injective for the 8/32-bit integer storage types.
|
| 21 |
return u32(value);
|
|
|
|
| 27 |
return h;
|
| 28 |
}
|
| 29 |
|
| 30 |
+
// The fingerprint covers every element of the slice and is computed once per
|
| 31 |
+
// slice before the pairwise scan. Equal fingerprints still require the exact
|
| 32 |
+
// comparator because collisions are possible.
|
| 33 |
fn slice_key(k: u32) -> u32 {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
var hash = 0x811c9dc5u;
|
| 35 |
+
for (var o = 0u; o < params.outer; o = o + 1u) {
|
| 36 |
+
for (var n = 0u; n < params.inner; n = n + 1u) {
|
| 37 |
+
hash = mix_key(hash, value_key(slice_at(o, k, n)));
|
| 38 |
+
}
|
|
|
|
| 39 |
}
|
| 40 |
return hash;
|
| 41 |
}
|
| 42 |
|
| 43 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 44 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 45 |
+
let k = gid.x;
|
| 46 |
+
if (k >= params.axisDim) { return; }
|
| 47 |
+
sliceKeys[k] = slice_key(k);
|
| 48 |
+
}
|
| 49 |
+
{% else %}
|
| 50 |
fn slice_eq(a: u32, b: u32) -> bool {
|
| 51 |
for (var o = 0u; o < params.outer; o = o + 1u) {
|
| 52 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
|
|
|
| 67 |
let laneValid = k < params.axisDim;
|
| 68 |
var kKey = 0u;
|
| 69 |
if (laneValid) {
|
| 70 |
+
kKey = sliceKeys[k];
|
| 71 |
}
|
| 72 |
|
| 73 |
var seen = false;
|
|
|
|
| 79 |
let loadK = chunkBase + lid.x;
|
| 80 |
var loadedKey = 0u;
|
| 81 |
if (loadK < params.axisDim) {
|
| 82 |
+
loadedKey = sliceKeys[loadK];
|
| 83 |
}
|
| 84 |
keyCache[lid.x] = loadedKey;
|
| 85 |
workgroupBarrier();
|
|
|
|
| 104 |
firstFlag[k] = select(1u, 0u, seen);
|
| 105 |
}
|
| 106 |
}
|
| 107 |
+
{% endif %}
|
build/webgpu/unique-axis-hash.wgsl.jinja
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
// Hash-backed axis Unique front end. Initialization computes one full-slice
|
| 2 |
// hash per axis index and clears the open-addressed table. Build inserts
|
| 3 |
// exact-equality buckets and atomically retains the earliest representative.
|
|
@@ -5,19 +6,17 @@
|
|
| 5 |
// Hash collisions always use the exact slice comparator, so hashes never
|
| 6 |
// affect semantics. Floats hash and compare canonical FTZ-safe bits (one NaN
|
| 7 |
// class, -0 folded to +0), so bucket equality is transitive and exact.
|
| 8 |
-
{%
|
| 9 |
-
enable f16;
|
| 10 |
-
{% endif %}
|
| 11 |
{{ env.wgsl.resourceDeclarations }}
|
| 12 |
|
| 13 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 14 |
-
const TABLE_SIZE: u32 = {{
|
| 15 |
-
{% if
|
| 16 |
const TABLE_MASK: u32 = TABLE_SIZE - 1u;
|
| 17 |
{% endif %}
|
| 18 |
const EMPTY: u32 = 0xffffffffu;
|
| 19 |
|
| 20 |
-
{% if
|
| 21 |
{% if isFloat %}
|
| 22 |
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 23 |
{% if usesF16 %}
|
|
@@ -53,30 +52,51 @@ fn slice_hash(k: u32) -> u32 {
|
|
| 53 |
// FNV-1a over the complete slice. The axis index is deliberately excluded:
|
| 54 |
// equal slices must hash identically regardless of where they occur.
|
| 55 |
var hash = 0x811c9dc5u;
|
|
|
|
|
|
|
|
|
|
| 56 |
for (var o = 0u; o < params.outer; o += 1u) {
|
| 57 |
for (var n = 0u; n < params.inner; n += 1u) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
hash = (hash ^ value_key(slice_at(o, k, n))) * 0x01000193u;
|
|
|
|
| 59 |
}
|
| 60 |
}
|
| 61 |
// One final avalanche reduces clustering for short structured slices.
|
| 62 |
hash ^= hash >> 16u;
|
| 63 |
hash *= 0x7feb352du;
|
| 64 |
hash ^= hash >> 15u;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
return hash;
|
| 66 |
}
|
| 67 |
|
| 68 |
@compute @workgroup_size(WG)
|
| 69 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 70 |
let i = gid.x;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
if (i < TABLE_SIZE) {
|
| 72 |
atomicStore(&hashSlot[i], EMPTY);
|
| 73 |
}
|
| 74 |
if (i < params.axisDim) {
|
|
|
|
| 75 |
firstFlag[i] = 0u;
|
|
|
|
| 76 |
sliceHash[i] = slice_hash(i);
|
| 77 |
}
|
| 78 |
}
|
| 79 |
-
{% elif
|
| 80 |
|
| 81 |
{% if isFloat %}
|
| 82 |
fn float_bits(v: {{ scalar }}) -> u32 {
|
|
@@ -118,6 +138,11 @@ fn slice_eq(a: u32, b: u32) -> bool {
|
|
| 118 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 119 |
let k = gid.x;
|
| 120 |
if (k >= params.axisDim) { return; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
let key = sliceHash[k];
|
| 122 |
var slot = key & TABLE_MASK;
|
| 123 |
for (var probe = 0u; probe < TABLE_SIZE; probe += 1u) {
|
|
|
|
| 1 |
+
{% set trackNaN = trackNaN | default(false) %}
|
| 2 |
// Hash-backed axis Unique front end. Initialization computes one full-slice
|
| 3 |
// hash per axis index and clears the open-addressed table. Build inserts
|
| 4 |
// exact-equality buckets and atomically retains the earliest representative.
|
|
|
|
| 6 |
// Hash collisions always use the exact slice comparator, so hashes never
|
| 7 |
// affect semantics. Floats hash and compare canonical FTZ-safe bits (one NaN
|
| 8 |
// class, -0 folded to +0), so bucket equality is transitive and exact.
|
| 9 |
+
{% set usesF16 = usesF16 and stage != "mark" %}
|
|
|
|
|
|
|
| 10 |
{{ env.wgsl.resourceDeclarations }}
|
| 11 |
|
| 12 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 13 |
+
const TABLE_SIZE: u32 = {{ tableSize }}u;
|
| 14 |
+
{% if stage == "build" %}
|
| 15 |
const TABLE_MASK: u32 = TABLE_SIZE - 1u;
|
| 16 |
{% endif %}
|
| 17 |
const EMPTY: u32 = 0xffffffffu;
|
| 18 |
|
| 19 |
+
{% if stage == "init" %}
|
| 20 |
{% if isFloat %}
|
| 21 |
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 22 |
{% if usesF16 %}
|
|
|
|
| 52 |
// FNV-1a over the complete slice. The axis index is deliberately excluded:
|
| 53 |
// equal slices must hash identically regardless of where they occur.
|
| 54 |
var hash = 0x811c9dc5u;
|
| 55 |
+
{% if trackNaN %}
|
| 56 |
+
var containsNaN = false;
|
| 57 |
+
{% endif %}
|
| 58 |
for (var o = 0u; o < params.outer; o += 1u) {
|
| 59 |
for (var n = 0u; n < params.inner; n += 1u) {
|
| 60 |
+
{% if trackNaN %}
|
| 61 |
+
let value = slice_at(o, k, n);
|
| 62 |
+
hash = (hash ^ value_key(value)) * 0x01000193u;
|
| 63 |
+
let bits = float_bits(value);
|
| 64 |
+
containsNaN = containsNaN || ((bits & {{ "0x7c00u" if usesF16 else "0x7f800000u" }}) == {{ "0x7c00u" if usesF16 else "0x7f800000u" }} && (bits & {{ "0x03ffu" if usesF16 else "0x007fffffu" }}) != 0u);
|
| 65 |
+
{% else %}
|
| 66 |
hash = (hash ^ value_key(slice_at(o, k, n))) * 0x01000193u;
|
| 67 |
+
{% endif %}
|
| 68 |
}
|
| 69 |
}
|
| 70 |
// One final avalanche reduces clustering for short structured slices.
|
| 71 |
hash ^= hash >> 16u;
|
| 72 |
hash *= 0x7feb352du;
|
| 73 |
hash ^= hash >> 15u;
|
| 74 |
+
{% if trackNaN %}
|
| 75 |
+
// Each invocation owns its slice flag. Build consumes and clears it in the
|
| 76 |
+
// next dispatch before hash mark uses this same allocation for first flags.
|
| 77 |
+
firstFlag[k] = select(0u, 1u, containsNaN);
|
| 78 |
+
{% endif %}
|
| 79 |
return hash;
|
| 80 |
}
|
| 81 |
|
| 82 |
@compute @workgroup_size(WG)
|
| 83 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 84 |
let i = gid.x;
|
| 85 |
+
{% if trackNaN %}
|
| 86 |
+
// No invocation ORs this flag until the following build dispatch.
|
| 87 |
+
if (i == 0u) { atomicStore(&nanFlag[0], 0u); }
|
| 88 |
+
{% endif %}
|
| 89 |
if (i < TABLE_SIZE) {
|
| 90 |
atomicStore(&hashSlot[i], EMPTY);
|
| 91 |
}
|
| 92 |
if (i < params.axisDim) {
|
| 93 |
+
{% if not trackNaN %}
|
| 94 |
firstFlag[i] = 0u;
|
| 95 |
+
{% endif %}
|
| 96 |
sliceHash[i] = slice_hash(i);
|
| 97 |
}
|
| 98 |
}
|
| 99 |
+
{% elif stage == "build" %}
|
| 100 |
|
| 101 |
{% if isFloat %}
|
| 102 |
fn float_bits(v: {{ scalar }}) -> u32 {
|
|
|
|
| 138 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 139 |
let k = gid.x;
|
| 140 |
if (k >= params.axisDim) { return; }
|
| 141 |
+
{% if trackNaN %}
|
| 142 |
+
let containsNaN = firstFlag[k] != 0u;
|
| 143 |
+
firstFlag[k] = 0u;
|
| 144 |
+
if (containsNaN) { atomicOr(&nanFlag[0], 1u); }
|
| 145 |
+
{% endif %}
|
| 146 |
let key = sliceHash[k];
|
| 147 |
var slot = key & TABLE_MASK;
|
| 148 |
for (var probe = 0u; probe < TABLE_SIZE; probe += 1u) {
|
build/webgpu/unique-axis-scalar-inverse.wgsl.jinja
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
// Open-addressing table constants and key/hash helpers.
|
| 6 |
+
const EMPTY: u32 = 0xffffffffu;
|
| 7 |
+
const MASK: u32 = {{ tableSize }}u - 1u;
|
| 8 |
+
|
| 9 |
+
{% if isFloat %}
|
| 10 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 11 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 12 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 13 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 14 |
+
{% macro float_bits_def() %}
|
| 15 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 16 |
+
{% if usesF16 %}
|
| 17 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 18 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 19 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 20 |
+
{% else %}
|
| 21 |
+
return bitcast<u32>(v);
|
| 22 |
+
{% endif %}
|
| 23 |
+
}
|
| 24 |
+
{%- endmacro -%}
|
| 25 |
+
{%- macro is_nan_bits_def() %}
|
| 26 |
+
fn is_nan_bits(v: {{ scalar }}) -> bool {
|
| 27 |
+
let b = float_bits(v);
|
| 28 |
+
{% if usesF16 %}
|
| 29 |
+
return (b & 0x7c00u) == 0x7c00u && (b & 0x03ffu) != 0u;
|
| 30 |
+
{% else %}
|
| 31 |
+
return (b & 0x7f800000u) == 0x7f800000u && (b & 0x007fffffu) != 0u;
|
| 32 |
+
{% endif %}
|
| 33 |
+
}
|
| 34 |
+
{%- endmacro %}
|
| 35 |
+
|
| 36 |
+
{{ float_bits_def() }}
|
| 37 |
+
|
| 38 |
+
{{ is_nan_bits_def() }}
|
| 39 |
+
|
| 40 |
+
{% endif %}
|
| 41 |
+
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 42 |
+
{% if isFloat %}
|
| 43 |
+
let bits = float_bits(v);
|
| 44 |
+
return select(bits, 0u, bits == {{ "0x8000u" if usesF16 else "0x80000000u" }});
|
| 45 |
+
{% elif isUnsigned %}
|
| 46 |
+
return v;
|
| 47 |
+
{% else %}
|
| 48 |
+
return bitcast<u32>(v);
|
| 49 |
+
{% endif %}
|
| 50 |
+
}
|
| 51 |
+
fn hash_key(k: u32) -> u32 {
|
| 52 |
+
var x = k;
|
| 53 |
+
x = x ^ (x >> 16u);
|
| 54 |
+
x = x * 0x7feb352du;
|
| 55 |
+
x = x ^ (x >> 15u);
|
| 56 |
+
x = x * 0x846ca68bu;
|
| 57 |
+
x = x ^ (x >> 16u);
|
| 58 |
+
return x;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
{% if not sorted %}
|
| 62 |
+
fn ordered_key(key: u32) -> u32 {
|
| 63 |
+
{% if usesF16 %}
|
| 64 |
+
return select(key ^ 0x8000u, (~key) & 0xffffu, (key & 0x8000u) != 0u);
|
| 65 |
+
{% else %}
|
| 66 |
+
return select(key ^ 0x80000000u, ~key, (key & 0x80000000u) != 0u);
|
| 67 |
+
{% endif %}
|
| 68 |
+
}
|
| 69 |
+
{% endif %}
|
| 70 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 71 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 72 |
+
let i = gid.x;
|
| 73 |
+
if (i >= {{ axisDim }}u) { return; }
|
| 74 |
+
if (is_nan_bits(x[0])) { inverse_indices[i] = 0u; return; }
|
| 75 |
+
// Later NaNs joined the smallest representative that already existed.
|
| 76 |
+
// Scan distinct representatives, excluding ones first seen after this input.
|
| 77 |
+
// Sorted slots can stop at their first eligible representative; unsorted
|
| 78 |
+
// slots appear in first-occurrence order, so later slots can be excluded.
|
| 79 |
+
if (is_nan_bits(x[i])) {
|
| 80 |
+
let written = min(count[0], {{ axisOutputDim }}u);
|
| 81 |
+
{% if not sorted %}
|
| 82 |
+
var best = 0u;
|
| 83 |
+
var bestKey = ordered_key(key_bits(x[slots[0]]));
|
| 84 |
+
{% endif %}
|
| 85 |
+
for (var p = 0u; p < written; p += 1u) {
|
| 86 |
+
let first = slots[p];
|
| 87 |
+
{% if sorted %}
|
| 88 |
+
if (first <= i) { inverse_indices[i] = p; return; }
|
| 89 |
+
{% else %}
|
| 90 |
+
if (first > i) { break; }
|
| 91 |
+
let candidate = ordered_key(key_bits(x[first]));
|
| 92 |
+
if (candidate < bestKey) { best = p; bestKey = candidate; }
|
| 93 |
+
{% endif %}
|
| 94 |
+
}
|
| 95 |
+
inverse_indices[i] = {{ "0u" if sorted else "best" }};
|
| 96 |
+
return;
|
| 97 |
+
}
|
| 98 |
+
let key = key_bits(x[i]);
|
| 99 |
+
var slot = hash_key(key) & MASK;
|
| 100 |
+
loop {
|
| 101 |
+
let stored = tableKey[slot];
|
| 102 |
+
if (stored == key) {
|
| 103 |
+
inverse_indices[i] = rankOfFirst[tableIdx[slot]];
|
| 104 |
+
return;
|
| 105 |
+
}
|
| 106 |
+
if (stored == EMPTY) { inverse_indices[i] = 0u; return; }
|
| 107 |
+
slot = (slot + 1u) & MASK;
|
| 108 |
+
}
|
| 109 |
+
}
|
build/webgpu/unique-axis-scalar-ranks.wgsl.jinja
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 3 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 4 |
+
let p = gid.x;
|
| 5 |
+
if (p >= min(count[0], {{ axisOutputDim }}u)) { return; }
|
| 6 |
+
rankOfFirst[slots[p]] = p;
|
| 7 |
+
}
|
build/webgpu/unique-axis-scatter.wgsl.jinja
CHANGED
|
@@ -1,17 +1,14 @@
|
|
| 1 |
-
{% if usesF16 %}
|
| 2 |
-
enable f16;
|
| 3 |
-
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
// Grid-parallel output stage for axis Unique. Compact/sort must remain a single
|
| 7 |
-
// globally synchronized workgroup, but copying
|
| 8 |
-
// wide Y
|
| 9 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 10 |
-
const CAP: u32 = {{
|
| 11 |
-
const AXIS_DIM: u32 = {{
|
| 12 |
-
const INNER: u32 = {{
|
| 13 |
-
const OUTPUT_AXIS_DIM: u32 = {{
|
| 14 |
-
const TOTAL_OUT: u32 = {{
|
| 15 |
|
| 16 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 17 |
return x[(o * AXIS_DIM + k) * INNER + n];
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// Grid-parallel output stage for axis Unique. Compact/sort must remain a single
|
| 4 |
+
// globally synchronized workgroup, but copying selected slice indices into a
|
| 5 |
+
// wide Y can be distributed across independent workgroups.
|
| 6 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 7 |
+
const CAP: u32 = {{ capacity }}u;
|
| 8 |
+
const AXIS_DIM: u32 = {{ axisDimSpec }}u;
|
| 9 |
+
const INNER: u32 = {{ innerSize }}u;
|
| 10 |
+
const OUTPUT_AXIS_DIM: u32 = {{ outputAxisDim }}u;
|
| 11 |
+
const TOTAL_OUT: u32 = {{ totalOut }}u;
|
| 12 |
|
| 13 |
fn slice_at(o: u32, k: u32, n: u32) -> {{ scalar }} {
|
| 14 |
return x[(o * AXIS_DIM + k) * INNER + n];
|
build/webgpu/unique-axis.wgsl.jinja
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 2 |
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 3 |
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
|
@@ -55,12 +56,9 @@ fn zero_value() -> {{ scalar }} {
|
|
| 55 |
}
|
| 56 |
{%- endmacro %}
|
| 57 |
|
| 58 |
-
{% set emitIndices =
|
| 59 |
-
{% set emitInverseIndices =
|
| 60 |
-
{% set emitCounts =
|
| 61 |
-
{% if usesF16 %}
|
| 62 |
-
enable f16;
|
| 63 |
-
{% endif %}
|
| 64 |
{{ env.wgsl.resourceDeclarations }}
|
| 65 |
|
| 66 |
// Axis-mode Unique views the input as outer x axisDim x inner. Two axis slices
|
|
@@ -68,14 +66,12 @@ enable f16;
|
|
| 68 |
// each distinct slice is retained, optionally sorted lexicographically, then
|
| 69 |
// scattered into the data-dependent output allocation.
|
| 70 |
//
|
| 71 |
-
// Float
|
| 72 |
-
//
|
| 73 |
|
| 74 |
-
const CAP: u32 = {{
|
| 75 |
-
// The walk
|
| 76 |
-
// workgroup
|
| 77 |
-
// head test settles in one round on real data and the chunked scan and shift
|
| 78 |
-
// both adapt to any width. Tuned separately from the op-wide WORKGROUP_SIZE.
|
| 79 |
const WG: u32 = {{ axisSerialWg }}u;
|
| 80 |
{% if isFloat %}
|
| 81 |
|
|
@@ -88,7 +84,7 @@ var<workgroup> hitIndex: u32;
|
|
| 88 |
var<workgroup> diffAt: atomic<u32>;
|
| 89 |
var<workgroup> cmpOut: u32;
|
| 90 |
{% endif %}
|
| 91 |
-
{% set headCache = isFloat and (
|
| 92 |
{% set floatSliceLess = isFloat and (emitInverseIndices or emitCounts) %}
|
| 93 |
{% set headOf = "headCache[candidate]" if headCache else "head_bits(order[candidate])" %}
|
| 94 |
{% set signBit = "0x8000u" if usesF16 else "0x80000000u" %}
|
|
@@ -114,16 +110,10 @@ fn less_head(ba: u32, bb: u32) -> bool {
|
|
| 114 |
{% endif %}
|
| 115 |
{% if headCache %}
|
| 116 |
|
| 117 |
-
//
|
| 118 |
-
//
|
| 119 |
-
// leading
|
| 120 |
-
|
| 121 |
-
// the workgroup makes that worse rather than better, which is the tell: the
|
| 122 |
-
// limit is cache capacity, not latency. Caching the leading elements densely
|
| 123 |
-
// means the common case, where two slices already differ at element zero, never
|
| 124 |
-
// touches X. The integer dedup path solves the same problem the same way, with
|
| 125 |
-
// sampled slice fingerprints.
|
| 126 |
-
var<workgroup> headCache: array<u32, {{ source.headCacheSlots }}>;
|
| 127 |
{% endif %}
|
| 128 |
{% if isFloat %}
|
| 129 |
|
|
@@ -154,12 +144,9 @@ fn head_qualifies(hc: u32, hk: u32) -> bool {
|
|
| 154 |
// equivalent (identical, or decided at a coordinate holding a NaN, which
|
| 155 |
// `slice_less` reports as neither-less), 1 when a < b, 2 when b < a.
|
| 156 |
//
|
| 157 |
-
//
|
| 158 |
-
//
|
| 159 |
-
//
|
| 160 |
-
// length at one memory latency per element, and that walk dominates the kernel.
|
| 161 |
-
// Here every lane takes one coordinate and the first difference falls out of a
|
| 162 |
-
// min-reduction, so an equal pair costs one round instead of one per element.
|
| 163 |
fn slice_cmp_coop(a: u32, b: u32, lane: u32) -> u32 {
|
| 164 |
if (lane == 0u) { atomicStore(&diffAt, NO_HIT); }
|
| 165 |
workgroupBarrier();
|
|
@@ -225,11 +212,8 @@ fn slice_less(a: u32, b: u32) -> bool {
|
|
| 225 |
let baseA = (o * params.axisDim + a) * params.inner;
|
| 226 |
let baseB = (o * params.axisDim + b) * params.inner;
|
| 227 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
| 228 |
-
//
|
| 229 |
-
//
|
| 230 |
-
// which on f16 is a vec2 pack and mask each time. Two equal slices, the
|
| 231 |
-
// case a duplicate input hits, walk to the end of the slice, so this loop
|
| 232 |
-
// body runs once per element and was the kernel's dominant cost.
|
| 233 |
let ba = float_bits(x[baseA + n]);
|
| 234 |
let bb = float_bits(x[baseB + n]);
|
| 235 |
if (is_nan_head(ba) || is_nan_head(bb)) { return false; }
|
|
@@ -328,19 +312,22 @@ fn find_bucket(k: u32, written: u32) -> u32 {
|
|
| 328 |
{% endif %}
|
| 329 |
@compute @workgroup_size(WG)
|
| 330 |
fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
{% if isFloat %}
|
| 332 |
// Reproduce ordered lower-bound insertion. NaN makes the comparator
|
| 333 |
// non-transitive, so pairwise equality and conventional hash tables cannot
|
| 334 |
// preserve its stateful bucket behavior.
|
| 335 |
//
|
| 336 |
-
// Every representative
|
| 337 |
-
//
|
| 338 |
-
//
|
| 339 |
-
//
|
| 340 |
-
// tests a chunk of candidates at once and keeps the SMALLEST index whose
|
| 341 |
-
// comparison fails -- the index the serial scan stops at, since it stops at
|
| 342 |
-
// the first failure too. Testing the remainder of a chunk is redundant, never
|
| 343 |
-
// observable: `slice_less` reads x and writes nothing.
|
| 344 |
//
|
| 345 |
// Both inner loops are barrier-free, so their bounds may depend on the live
|
| 346 |
// count; every barrier sits at the top level of this loop, whose bound comes
|
|
@@ -349,10 +336,8 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 349 |
for (var k = 0u; k < params.axisDim; k = k + 1u) {
|
| 350 |
let headK = head_bits(k);
|
| 351 |
// Walk the representatives for the first one that is not less than this
|
| 352 |
-
// slice.
|
| 353 |
-
//
|
| 354 |
-
// resolved by one exact comparison, and the scan resumes past it only if
|
| 355 |
-
// that representative really does sort first.
|
| 356 |
var searchFrom = 0u;
|
| 357 |
var lowerBound = written;
|
| 358 |
var equivalent = false;
|
|
@@ -361,8 +346,8 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 361 |
workgroupBarrier();
|
| 362 |
for (var base = searchFrom; base < written; base = base + WG) {
|
| 363 |
// Chunks ascend, so an index already recorded is smaller than anything
|
| 364 |
-
// this chunk
|
| 365 |
-
// the
|
| 366 |
if (atomicLoad(&lowerBoundHit) != NO_HIT) { break; }
|
| 367 |
let candidate = base + lid.x;
|
| 368 |
if (candidate >= searchFrom && candidate < written
|
|
@@ -447,9 +432,8 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 447 |
{% endif %}
|
| 448 |
{% else %}
|
| 449 |
if (params.axisDim <= CAP) {
|
| 450 |
-
// When every input slice
|
| 451 |
-
//
|
| 452 |
-
// exit after only a handful of comparisons, and all lanes participate.
|
| 453 |
for (var k = lid.x; k < params.axisDim; k = k + WG) {
|
| 454 |
var seen = false;
|
| 455 |
for (var j = 0u; j < k; j = j + 1u) {
|
|
@@ -502,8 +486,8 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 502 |
// `order` is storage-backed so legal data-dependent capacities are not
|
| 503 |
// constrained by maxComputeWorkgroupStorageSize.
|
| 504 |
storageBarrier();
|
| 505 |
-
// The
|
| 506 |
-
//
|
| 507 |
let writtenCount = params.outputAxisDim;
|
| 508 |
|
| 509 |
// Scattering the selected slices is independent once `order` is ready, so
|
|
|
|
| 1 |
+
{% set nanFallback = nanFallback | default(false) %}
|
| 2 |
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 3 |
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 4 |
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
|
|
|
| 56 |
}
|
| 57 |
{%- endmacro %}
|
| 58 |
|
| 59 |
+
{% set emitIndices = hasIndices | default(false) %}
|
| 60 |
+
{% set emitInverseIndices = hasInverseIndices | default(false) %}
|
| 61 |
+
{% set emitCounts = hasCounts | default(false) %}
|
|
|
|
|
|
|
|
|
|
| 62 |
{{ env.wgsl.resourceDeclarations }}
|
| 63 |
|
| 64 |
// Axis-mode Unique views the input as outer x axisDim x inner. Two axis slices
|
|
|
|
| 66 |
// each distinct slice is retained, optionally sorted lexicographically, then
|
| 67 |
// scattered into the data-dependent output allocation.
|
| 68 |
//
|
| 69 |
+
// Float comparisons canonicalize signed zero and preserve subnormal magnitudes
|
| 70 |
+
// when testing equality and lexicographic order.
|
| 71 |
|
| 72 |
+
const CAP: u32 = {{ capacity }}u;
|
| 73 |
+
// The slice walk, chunked scan, and shift all use this independently tunable
|
| 74 |
+
// workgroup width.
|
|
|
|
|
|
|
| 75 |
const WG: u32 = {{ axisSerialWg }}u;
|
| 76 |
{% if isFloat %}
|
| 77 |
|
|
|
|
| 84 |
var<workgroup> diffAt: atomic<u32>;
|
| 85 |
var<workgroup> cmpOut: u32;
|
| 86 |
{% endif %}
|
| 87 |
+
{% set headCache = isFloat and (headCacheSlots | default(0)) > 0 %}
|
| 88 |
{% set floatSliceLess = isFloat and (emitInverseIndices or emitCounts) %}
|
| 89 |
{% set headOf = "headCache[candidate]" if headCache else "head_bits(order[candidate])" %}
|
| 90 |
{% set signBit = "0x8000u" if usesF16 else "0x80000000u" %}
|
|
|
|
| 110 |
{% endif %}
|
| 111 |
{% if headCache %}
|
| 112 |
|
| 113 |
+
// Canonicalized leading-element bits for each written representative, kept
|
| 114 |
+
// beside `order`. A different leading value proves that two slices differ;
|
| 115 |
+
// equal leading values fall through to the exact full-slice comparison.
|
| 116 |
+
var<workgroup> headCache: array<u32, {{ headCacheSlots }}>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
{% endif %}
|
| 118 |
{% if isFloat %}
|
| 119 |
|
|
|
|
| 144 |
// equivalent (identical, or decided at a coordinate holding a NaN, which
|
| 145 |
// `slice_less` reports as neither-less), 1 when a < b, 2 when b < a.
|
| 146 |
//
|
| 147 |
+
// Lanes compare separate coordinates and an atomic minimum identifies the first
|
| 148 |
+
// difference, preserving lexicographic order. Equal slices examine every
|
| 149 |
+
// coordinate and return zero.
|
|
|
|
|
|
|
|
|
|
| 150 |
fn slice_cmp_coop(a: u32, b: u32, lane: u32) -> u32 {
|
| 151 |
if (lane == 0u) { atomicStore(&diffAt, NO_HIT); }
|
| 152 |
workgroupBarrier();
|
|
|
|
| 212 |
let baseA = (o * params.axisDim + a) * params.inner;
|
| 213 |
let baseB = (o * params.axisDim + b) * params.inner;
|
| 214 |
for (var n = 0u; n < params.inner; n = n + 1u) {
|
| 215 |
+
// Load each bit pattern once so the NaN, equality, and ordering tests use
|
| 216 |
+
// the same representation.
|
|
|
|
|
|
|
|
|
|
| 217 |
let ba = float_bits(x[baseA + n]);
|
| 218 |
let bb = float_bits(x[baseB + n]);
|
| 219 |
if (is_nan_head(ba) || is_nan_head(bb)) { return false; }
|
|
|
|
| 312 |
{% endif %}
|
| 313 |
@compute @workgroup_size(WG)
|
| 314 |
fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
| 315 |
+
{% if nanFallback %}
|
| 316 |
+
// Publish through workgroup memory so the early return is uniform before
|
| 317 |
+
// entering the cooperative ordered insertion's barrier-containing loops.
|
| 318 |
+
if (lid.x == 0u) { hitIndex = nanFlag[0]; }
|
| 319 |
+
let requiresOrdered = workgroupUniformLoad(&hitIndex);
|
| 320 |
+
if (requiresOrdered == 0u) { return; }
|
| 321 |
+
{% endif %}
|
| 322 |
{% if isFloat %}
|
| 323 |
// Reproduce ordered lower-bound insertion. NaN makes the comparator
|
| 324 |
// non-transitive, so pairwise equality and conventional hash tables cannot
|
| 325 |
// preserve its stateful bucket behavior.
|
| 326 |
//
|
| 327 |
+
// Every prior representative is a lower-bound candidate. The workgroup tests
|
| 328 |
+
// candidates in chunks and retains the smallest index whose comparison fails,
|
| 329 |
+
// matching the stopping point of a serial lower-bound scan. Comparisons after
|
| 330 |
+
// that candidate cannot affect output because `slice_less` has no side effects.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
//
|
| 332 |
// Both inner loops are barrier-free, so their bounds may depend on the live
|
| 333 |
// count; every barrier sits at the top level of this loop, whose bound comes
|
|
|
|
| 336 |
for (var k = 0u; k < params.axisDim; k = k + 1u) {
|
| 337 |
let headK = head_bits(k);
|
| 338 |
// Walk the representatives for the first one that is not less than this
|
| 339 |
+
// slice. Different leading elements settle the ordering directly; equal
|
| 340 |
+
// leading elements require an exact comparison.
|
|
|
|
|
|
|
| 341 |
var searchFrom = 0u;
|
| 342 |
var lowerBound = written;
|
| 343 |
var equivalent = false;
|
|
|
|
| 346 |
workgroupBarrier();
|
| 347 |
for (var base = searchFrom; base < written; base = base + WG) {
|
| 348 |
// Chunks ascend, so an index already recorded is smaller than anything
|
| 349 |
+
// in this chunk. A late atomic observation may repeat work but cannot
|
| 350 |
+
// change the selected bound.
|
| 351 |
if (atomicLoad(&lowerBoundHit) != NO_HIT) { break; }
|
| 352 |
let candidate = base + lid.x;
|
| 353 |
if (candidate >= searchFrom && candidate < written
|
|
|
|
| 432 |
{% endif %}
|
| 433 |
{% else %}
|
| 434 |
if (params.axisDim <= CAP) {
|
| 435 |
+
// When every input slice fits in the order scratch, lanes independently
|
| 436 |
+
// test whether each slice matches an earlier slice.
|
|
|
|
| 437 |
for (var k = lid.x; k < params.axisDim; k = k + WG) {
|
| 438 |
var seen = false;
|
| 439 |
for (var j = 0u; j < k; j = j + 1u) {
|
|
|
|
| 486 |
// `order` is storage-backed so legal data-dependent capacities are not
|
| 487 |
// constrained by maxComputeWorkgroupStorageSize.
|
| 488 |
storageBarrier();
|
| 489 |
+
// The output axis dimension equals the exact unique count and therefore also
|
| 490 |
+
// supplies the cross-lane written count.
|
| 491 |
let writtenCount = params.outputAxisDim;
|
| 492 |
|
| 493 |
// Scattering the selected slices is independent once `order` is ready, so
|
build/webgpu/unique-compact-sort.wgsl.jinja
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// Pass 2 of parallel Unique: compact flagged first occurrences in appearance
|
| 4 |
// order, optionally bitonic-sort them, and write the exact result. Small results
|
| 5 |
// keep scratch in workgroup memory, while larger results use storage buffers
|
| 6 |
// selected from device limits.
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
{% if sorted %}
|
| 10 |
// The power-of-two padded tail sorts after every real value.
|
| 11 |
-
const SORT_N: u32 = {{
|
| 12 |
|
| 13 |
{% endif %}
|
| 14 |
var<workgroup> wgScan: array<u32, WG>;
|
| 15 |
var<workgroup> wgCarry: u32;
|
| 16 |
-
{% if not
|
| 17 |
{% if sorted %}
|
| 18 |
var<workgroup> sortKey: array<u32, SORT_N>;
|
| 19 |
var<workgroup> sortVal: array<{{ scalar }}, SORT_N>;
|
|
@@ -23,20 +30,46 @@ var<workgroup> compacted: array<{{ scalar }}, CAP>;
|
|
| 23 |
{% endif %}
|
| 24 |
|
| 25 |
{% endif %}
|
|
|
|
| 26 |
fn zero_value() -> {{ scalar }} {
|
| 27 |
return {{ scalar }}(0);
|
| 28 |
}
|
|
|
|
| 29 |
{% if sorted %}
|
| 30 |
|
| 31 |
-
|
| 32 |
-
//
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
let b = v;
|
|
|
|
|
|
|
| 36 |
{% else %}
|
| 37 |
let b = bitcast<u32>(v);
|
| 38 |
{% endif %}
|
| 39 |
-
{% if
|
|
|
|
|
|
|
| 40 |
return b;
|
| 41 |
{% else %}
|
| 42 |
return b ^ 0x80000000u;
|
|
@@ -45,20 +78,11 @@ fn sort_key(v: {% if source.globalScratch %}u32{% else %}{{ scalar }}{% endif %}
|
|
| 45 |
|
| 46 |
{% endif %}
|
| 47 |
{% macro scratch_barrier() %}
|
| 48 |
-
{% if
|
| 49 |
{% endmacro %}
|
| 50 |
|
| 51 |
-
|
| 52 |
-
fn
|
| 53 |
-
let tid = lid.x;
|
| 54 |
-
if (tid == 0u) {
|
| 55 |
-
wgCarry = 0u;
|
| 56 |
-
}
|
| 57 |
-
workgroupBarrier();
|
| 58 |
-
|
| 59 |
-
// Chunked Hillis-Steele exclusive scan maps flags to appearance-order ranks.
|
| 60 |
-
let chunks = (params.inputCount + WG - 1u) / WG;
|
| 61 |
-
for (var c = 0u; c < chunks; c = c + 1u) {
|
| 62 |
let i = c * WG + tid;
|
| 63 |
var f = 0u;
|
| 64 |
if (i < params.inputCount) {
|
|
@@ -81,7 +105,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 81 |
let excl = wgScan[tid] - f;
|
| 82 |
let pos = wgCarry + excl;
|
| 83 |
if (i < params.inputCount && f == 1u && pos < CAP) {
|
| 84 |
-
{% if
|
| 85 |
sortVal[pos] = bitcast<u32>(x[i]);
|
| 86 |
{% elif sorted %}
|
| 87 |
sortVal[pos] = x[i];
|
|
@@ -94,11 +118,39 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 94 |
wgCarry = wgCarry + wgScan[WG - 1u];
|
| 95 |
}
|
| 96 |
workgroupBarrier();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
let total = wgCarry;
|
| 100 |
let written = min(total, CAP);
|
| 101 |
-
{% if
|
| 102 |
storageBarrier();
|
| 103 |
|
| 104 |
{% endif %}
|
|
@@ -111,7 +163,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 111 |
if (isPad == 0u) {
|
| 112 |
sortKey[k] = sort_key(sortVal[k]);
|
| 113 |
} else {
|
| 114 |
-
{% if
|
| 115 |
sortVal[k] = 0u;
|
| 116 |
{% else %}
|
| 117 |
sortVal[k] = zero_value();
|
|
@@ -121,6 +173,7 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 121 |
}
|
| 122 |
{{ scratch_barrier() }}
|
| 123 |
|
|
|
|
| 124 |
// Batcher bitonic network. Each lane owns one side of a compare-exchange.
|
| 125 |
var size = 2u;
|
| 126 |
loop {
|
|
@@ -158,12 +211,14 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 158 |
}
|
| 159 |
|
| 160 |
{% endif %}
|
| 161 |
-
{%
|
|
|
|
|
|
|
| 162 |
workgroupBarrier();
|
| 163 |
{% endif %}
|
| 164 |
for (var k = tid; k < CAP; k = k + WG) {
|
| 165 |
if (k < written) {
|
| 166 |
-
{% if
|
| 167 |
y[k] = bitcast<{{ scalar }}>(sortVal[k]);
|
| 168 |
{% elif sorted %}
|
| 169 |
y[k] = sortVal[k];
|
|
@@ -174,4 +229,5 @@ fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
| 174 |
y[k] = zero_value();
|
| 175 |
}
|
| 176 |
}
|
|
|
|
| 177 |
}
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
// Pass 2 of parallel Unique: compact flagged first occurrences in appearance
|
| 7 |
// order, optionally bitonic-sort them, and write the exact result. Small results
|
| 8 |
// keep scratch in workgroup memory, while larger results use storage buffers
|
| 9 |
// selected from device limits.
|
| 10 |
+
// Global-scratch variants reserve workgroup memory only for the scan buffer and
|
| 11 |
+
// provide an independent sort width. Workgroup-scratch variants use the shared
|
| 12 |
+
// workgroup-width setting.
|
| 13 |
+
{% set compactWg = sortWg | default(tunables.WORKGROUP_SIZE) %}
|
| 14 |
+
const WG: u32 = {{ compactWg }}u;
|
| 15 |
+
const CAP: u32 = {{ capacity }}u;
|
| 16 |
{% if sorted %}
|
| 17 |
// The power-of-two padded tail sorts after every real value.
|
| 18 |
+
const SORT_N: u32 = {{ sortN }}u;
|
| 19 |
|
| 20 |
{% endif %}
|
| 21 |
var<workgroup> wgScan: array<u32, WG>;
|
| 22 |
var<workgroup> wgCarry: u32;
|
| 23 |
+
{% if not globalScratch %}
|
| 24 |
{% if sorted %}
|
| 25 |
var<workgroup> sortKey: array<u32, SORT_N>;
|
| 26 |
var<workgroup> sortVal: array<{{ scalar }}, SORT_N>;
|
|
|
|
| 30 |
{% endif %}
|
| 31 |
|
| 32 |
{% endif %}
|
| 33 |
+
{% if sortExternally is not defined or not sortExternally %}
|
| 34 |
fn zero_value() -> {{ scalar }} {
|
| 35 |
return {{ scalar }}(0);
|
| 36 |
}
|
| 37 |
+
{% endif %}
|
| 38 |
{% if sorted %}
|
| 39 |
|
| 40 |
+
{% if isFloat and not globalScratch %}
|
| 41 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 42 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 43 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 44 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 45 |
+
{% macro float_bits_def() %}
|
| 46 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 47 |
+
{% if usesF16 %}
|
| 48 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 49 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 50 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 51 |
+
{% else %}
|
| 52 |
+
return bitcast<u32>(v);
|
| 53 |
+
{% endif %}
|
| 54 |
+
}
|
| 55 |
+
{%- endmacro %}
|
| 56 |
+
|
| 57 |
+
{{ float_bits_def() }}
|
| 58 |
+
|
| 59 |
+
{% endif %}
|
| 60 |
+
// Monotonic raw-bit key preserves finite subnormals on FTZ devices. Global
|
| 61 |
+
// scratch already stores raw bits.
|
| 62 |
+
fn sort_key(v: {% if globalScratch %}u32{% else %}{{ scalar }}{% endif %}) -> u32 {
|
| 63 |
+
{% if globalScratch %}
|
| 64 |
let b = v;
|
| 65 |
+
{% elif isFloat %}
|
| 66 |
+
let b = float_bits(v);
|
| 67 |
{% else %}
|
| 68 |
let b = bitcast<u32>(v);
|
| 69 |
{% endif %}
|
| 70 |
+
{% if isFloat %}
|
| 71 |
+
return select(b | {{ "0x8000u" if usesF16 else "0x80000000u" }}, (~b) & {{ "0xffffu" if usesF16 else "0xffffffffu" }}, (b & {{ "0x8000u" if usesF16 else "0x80000000u" }}) != 0u);
|
| 72 |
+
{% elif isUnsigned %}
|
| 73 |
return b;
|
| 74 |
{% else %}
|
| 75 |
return b ^ 0x80000000u;
|
|
|
|
| 78 |
|
| 79 |
{% endif %}
|
| 80 |
{% macro scratch_barrier() %}
|
| 81 |
+
{% if globalScratch %}storageBarrier();{% else %}workgroupBarrier();{% endif %}
|
| 82 |
{% endmacro %}
|
| 83 |
|
| 84 |
+
// Compact one input chunk while all lanes keep the scan and carry coherent.
|
| 85 |
+
fn compact_chunk(tid: u32, c: u32) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
let i = c * WG + tid;
|
| 87 |
var f = 0u;
|
| 88 |
if (i < params.inputCount) {
|
|
|
|
| 105 |
let excl = wgScan[tid] - f;
|
| 106 |
let pos = wgCarry + excl;
|
| 107 |
if (i < params.inputCount && f == 1u && pos < CAP) {
|
| 108 |
+
{% if globalScratch %}
|
| 109 |
sortVal[pos] = bitcast<u32>(x[i]);
|
| 110 |
{% elif sorted %}
|
| 111 |
sortVal[pos] = x[i];
|
|
|
|
| 118 |
wgCarry = wgCarry + wgScan[WG - 1u];
|
| 119 |
}
|
| 120 |
workgroupBarrier();
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
@compute @workgroup_size(WG)
|
| 124 |
+
fn main(@builtin(local_invocation_id) lid: vec3<u32>) {
|
| 125 |
+
let tid = lid.x;
|
| 126 |
+
if (tid == 0u) {
|
| 127 |
+
wgCarry = 0u;
|
| 128 |
+
}
|
| 129 |
+
workgroupBarrier();
|
| 130 |
+
|
| 131 |
+
let chunks = (params.inputCount + WG - 1u) / WG;
|
| 132 |
+
{% if capacity <= compactWg %}
|
| 133 |
+
// Test completion once, after the first chunk. If representatives occur
|
| 134 |
+
// later, the remaining scan retains its original barrier-only loop body.
|
| 135 |
+
if (chunks > 0u) {
|
| 136 |
+
compact_chunk(tid, 0u);
|
| 137 |
+
let first_count = workgroupUniformLoad(&wgCarry);
|
| 138 |
+
if (first_count < CAP) {
|
| 139 |
+
for (var c = 1u; c < chunks; c = c + 1u) {
|
| 140 |
+
compact_chunk(tid, c);
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
}
|
| 144 |
+
{% else %}
|
| 145 |
+
// A chunk cannot fill a capacity larger than its invocation count.
|
| 146 |
+
for (var c = 0u; c < chunks; c = c + 1u) {
|
| 147 |
+
compact_chunk(tid, c);
|
| 148 |
+
}
|
| 149 |
+
{% endif %}
|
| 150 |
|
| 151 |
let total = wgCarry;
|
| 152 |
let written = min(total, CAP);
|
| 153 |
+
{% if globalScratch %}
|
| 154 |
storageBarrier();
|
| 155 |
|
| 156 |
{% endif %}
|
|
|
|
| 163 |
if (isPad == 0u) {
|
| 164 |
sortKey[k] = sort_key(sortVal[k]);
|
| 165 |
} else {
|
| 166 |
+
{% if globalScratch %}
|
| 167 |
sortVal[k] = 0u;
|
| 168 |
{% else %}
|
| 169 |
sortVal[k] = zero_value();
|
|
|
|
| 173 |
}
|
| 174 |
{{ scratch_barrier() }}
|
| 175 |
|
| 176 |
+
{% if sortExternally is not defined or not sortExternally %}
|
| 177 |
// Batcher bitonic network. Each lane owns one side of a compare-exchange.
|
| 178 |
var size = 2u;
|
| 179 |
loop {
|
|
|
|
| 211 |
}
|
| 212 |
|
| 213 |
{% endif %}
|
| 214 |
+
{% endif %}
|
| 215 |
+
{% if sortExternally is not defined or not sortExternally %}
|
| 216 |
+
{% if not globalScratch %}
|
| 217 |
workgroupBarrier();
|
| 218 |
{% endif %}
|
| 219 |
for (var k = tid; k < CAP; k = k + WG) {
|
| 220 |
if (k < written) {
|
| 221 |
+
{% if globalScratch %}
|
| 222 |
y[k] = bitcast<{{ scalar }}>(sortVal[k]);
|
| 223 |
{% elif sorted %}
|
| 224 |
y[k] = sortVal[k];
|
|
|
|
| 229 |
y[k] = zero_value();
|
| 230 |
}
|
| 231 |
}
|
| 232 |
+
{% endif %}
|
| 233 |
}
|
build/webgpu/unique-flag-block-scan.wgsl.jinja
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
+
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 3 |
+
var<workgroup> scan: array<u32, WG>;
|
| 4 |
+
@compute @workgroup_size(WG)
|
| 5 |
+
fn main(@builtin(local_invocation_id) lid: vec3<u32>, @builtin(global_invocation_id) gid: vec3<u32>, @builtin(workgroup_id) wid: vec3<u32>) {
|
| 6 |
+
let tid = lid.x;
|
| 7 |
+
var flag = 0u;
|
| 8 |
+
if (gid.x < {{ scanN }}u) { flag = flags[gid.x]; }
|
| 9 |
+
scan[tid] = flag;
|
| 10 |
+
for (var step = 1u; step < WG; step <<= 1u) {
|
| 11 |
+
workgroupBarrier();
|
| 12 |
+
var previous = 0u;
|
| 13 |
+
if (tid >= step) { previous = scan[tid - step]; }
|
| 14 |
+
workgroupBarrier();
|
| 15 |
+
scan[tid] += previous;
|
| 16 |
+
}
|
| 17 |
+
workgroupBarrier();
|
| 18 |
+
if (gid.x < {{ scanN }}u) { flags[gid.x] = 2u * (scan[tid] - flag) + flag; }
|
| 19 |
+
if (tid == WG - 1u) { blockSums[wid.x] = scan[tid]; }
|
| 20 |
+
}
|
build/webgpu/unique-flat-metadata.wgsl.jinja
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 2 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 3 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 4 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 5 |
+
{% macro eq_value_def() %}
|
| 6 |
+
fn eq_value(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
| 7 |
+
{% if isFloat %}
|
| 8 |
+
var ba = float_bits(a);
|
| 9 |
+
var bb = float_bits(b);
|
| 10 |
+
{% if usesF16 %}
|
| 11 |
+
if (ba == 0x8000u) { ba = 0u; } // -0 -> +0
|
| 12 |
+
if (bb == 0x8000u) { bb = 0u; }
|
| 13 |
+
{% else %}
|
| 14 |
+
if (ba == 0x80000000u) { ba = 0u; } // -0 -> +0
|
| 15 |
+
if (bb == 0x80000000u) { bb = 0u; }
|
| 16 |
+
{% endif %}
|
| 17 |
+
return ba == bb;
|
| 18 |
+
{% else %}
|
| 19 |
+
return a == b;
|
| 20 |
+
{% endif %}
|
| 21 |
+
}
|
| 22 |
+
{%- endmacro -%}
|
| 23 |
+
{%- macro less_value_def() %}
|
| 24 |
+
fn less_value(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
| 25 |
+
{% if isFloat %}
|
| 26 |
+
let ba = float_bits(a);
|
| 27 |
+
let bb = float_bits(b);
|
| 28 |
+
{% if usesF16 %}
|
| 29 |
+
let ka = select(ba | 0x8000u, (~ba) & 0xffffu, (ba & 0x8000u) != 0u);
|
| 30 |
+
let kb = select(bb | 0x8000u, (~bb) & 0xffffu, (bb & 0x8000u) != 0u);
|
| 31 |
+
{% else %}
|
| 32 |
+
let ka = select(ba | 0x80000000u, ~ba, (ba & 0x80000000u) != 0u);
|
| 33 |
+
let kb = select(bb | 0x80000000u, ~bb, (bb & 0x80000000u) != 0u);
|
| 34 |
+
{% endif %}
|
| 35 |
+
return ka < kb;
|
| 36 |
+
{% else %}
|
| 37 |
+
return a < b;
|
| 38 |
+
{% endif %}
|
| 39 |
+
}
|
| 40 |
+
{%- endmacro %}
|
| 41 |
+
|
| 42 |
+
{% set emitIndices = hasIndices | default(false) %}
|
| 43 |
+
{% set emitInverseIndices = hasInverseIndices | default(false) %}
|
| 44 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 45 |
+
|
| 46 |
+
// Metadata for the parallel integer Unique routes. Y and the first-occurrence
|
| 47 |
+
// flags are already final when this runs, so every output is a pure function of
|
| 48 |
+
// (x, y, flags) and one thread can own one element. The single-invocation kernel
|
| 49 |
+
// this replaces resolved the same buckets by scanning the whole input once per
|
| 50 |
+
// (input, output) pair.
|
| 51 |
+
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 52 |
+
|
| 53 |
+
{% if stage != "scatter" or not sorted %}
|
| 54 |
+
{{ eq_value_def() }}
|
| 55 |
+
{% endif %}
|
| 56 |
+
{% if stage == "scatter" %}
|
| 57 |
+
{% if sorted %}
|
| 58 |
+
|
| 59 |
+
{{ less_value_def() }}
|
| 60 |
+
|
| 61 |
+
// Y is ascending on this route, so a bucket is a binary search rather than a
|
| 62 |
+
// walk over every unique value.
|
| 63 |
+
fn find_slot(value: {{ scalar }}) -> u32 {
|
| 64 |
+
var lo = 0u;
|
| 65 |
+
var hi = params.capacity;
|
| 66 |
+
loop {
|
| 67 |
+
if (lo >= hi) { break; }
|
| 68 |
+
let mid = lo + (hi - lo) / 2u;
|
| 69 |
+
if (less_value(y[mid], value)) {
|
| 70 |
+
lo = mid + 1u;
|
| 71 |
+
} else {
|
| 72 |
+
hi = mid;
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
return lo;
|
| 76 |
+
}
|
| 77 |
+
{% else %}
|
| 78 |
+
|
| 79 |
+
// Y is in first-appearance order, so a bucket is a scan of the unique values.
|
| 80 |
+
fn find_slot(value: {{ scalar }}) -> u32 {
|
| 81 |
+
for (var k = 0u; k < params.capacity; k = k + 1u) {
|
| 82 |
+
if (eq_value(y[k], value)) { return k; }
|
| 83 |
+
}
|
| 84 |
+
return params.capacity;
|
| 85 |
+
}
|
| 86 |
+
{% endif %}
|
| 87 |
+
|
| 88 |
+
@compute @workgroup_size(WG)
|
| 89 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 90 |
+
let i = gid.x;
|
| 91 |
+
if (i >= params.inputCount) {
|
| 92 |
+
return;
|
| 93 |
+
}
|
| 94 |
+
let slot = find_slot(x[i]);
|
| 95 |
+
if (slot >= params.capacity) {
|
| 96 |
+
return;
|
| 97 |
+
}
|
| 98 |
+
{% if emitInverseIndices %}
|
| 99 |
+
inverse_indices[i] = slot;
|
| 100 |
+
{% endif %}
|
| 101 |
+
{% if emitIndices %}
|
| 102 |
+
// Exactly one input element is the first occurrence of its value, so each
|
| 103 |
+
// slot has a single writer and the store needs no ordering.
|
| 104 |
+
if (flags[i] == 1u) {
|
| 105 |
+
indices[slot] = i;
|
| 106 |
+
}
|
| 107 |
+
{% endif %}
|
| 108 |
+
}
|
| 109 |
+
{% else %}
|
| 110 |
+
|
| 111 |
+
// One thread per unique value counts its own occurrences. Accumulating per
|
| 112 |
+
// output rather than per input keeps the tally free of atomics, and so free of
|
| 113 |
+
// the zero-fill pass an atomic accumulation would need first.
|
| 114 |
+
@compute @workgroup_size(WG)
|
| 115 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 116 |
+
let k = gid.x;
|
| 117 |
+
if (k >= params.capacity) {
|
| 118 |
+
return;
|
| 119 |
+
}
|
| 120 |
+
let value = y[k];
|
| 121 |
+
var total = 0u;
|
| 122 |
+
for (var i = 0u; i < params.inputCount; i = i + 1u) {
|
| 123 |
+
if (eq_value(x[i], value)) {
|
| 124 |
+
total = total + 1u;
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
counts[k] = total;
|
| 128 |
+
}
|
| 129 |
+
{% endif %}
|
build/webgpu/unique-global-sort-exchange.wgsl.jinja
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Integer Unique's existing (padding, monotonic-key) bitonic comparison.
|
| 2 |
+
// One invocation owns a disjoint pair. A dispatch boundary publishes each
|
| 3 |
+
// completed distance to the next distance across every workgroup.
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
{% macro exchange_integer(keys, values, pads, writeState=true) %}
|
| 6 |
+
let pk = {{ pads }}[k];
|
| 7 |
+
let pp = {{ pads }}[partner];
|
| 8 |
+
let kk = {{ keys }}[k];
|
| 9 |
+
let kp = {{ keys }}[partner];
|
| 10 |
+
let kBeforeP = (pk < pp) || (pk == pp && kk <= kp);
|
| 11 |
+
let needSwap = select(kBeforeP, !kBeforeP, ascending);
|
| 12 |
+
if (needSwap) {
|
| 13 |
+
let tVal = {{ values }}[k];
|
| 14 |
+
{{ values }}[k] = {{ values }}[partner];
|
| 15 |
+
{{ values }}[partner] = tVal;
|
| 16 |
+
{% if writeState %}
|
| 17 |
+
{{ keys }}[k] = kp;
|
| 18 |
+
{{ keys }}[partner] = kk;
|
| 19 |
+
{{ pads }}[k] = pp;
|
| 20 |
+
{{ pads }}[partner] = pk;
|
| 21 |
+
{% endif %}
|
| 22 |
+
}
|
| 23 |
+
{% endmacro %}
|
| 24 |
+
|
| 25 |
+
const SIZE: u32 = {{ sortSize }}u;
|
| 26 |
+
const STRIDE: u32 = {{ sortStride }}u;
|
| 27 |
+
const PAIRS: u32 = {{ (sortLength / 2)|int }}u;
|
| 28 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 29 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 30 |
+
let pair = gid.x;
|
| 31 |
+
if (pair >= PAIRS) { return; }
|
| 32 |
+
let k = (pair / STRIDE) * (2u * STRIDE) + pair % STRIDE;
|
| 33 |
+
let partner = k + STRIDE;
|
| 34 |
+
let ascending = (k & SIZE) == 0u;
|
| 35 |
+
{{ exchange_integer("sortKey", "sortVal", "sortPad", writeSortState | default(true)) }}
|
| 36 |
+
}
|
build/webgpu/unique-global-sort-output.wgsl.jinja
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 3 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 4 |
+
let k = gid.x;
|
| 5 |
+
if (k >= {{ capacity }}u) { return; }
|
| 6 |
+
var value = {{ scalar }}(0);
|
| 7 |
+
if (k < {{ sortLength }}u && sortPad[k] == 0u) { value = bitcast<{{ scalar }}>(sortVal[k]); }
|
| 8 |
+
y[k] = value;
|
| 9 |
+
}
|
build/webgpu/unique-global-sort-shared.wgsl.jinja
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Integer-only bitonic stages whose pairs lie in one contiguous shared tile.
|
| 2 |
+
// Global indices, including the tile base, retain the network's direction.
|
| 3 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 4 |
+
{% macro exchange_integer(keys, values, pads, writeState=true) %}
|
| 5 |
+
let pk = {{ pads }}[k];
|
| 6 |
+
let pp = {{ pads }}[partner];
|
| 7 |
+
let kk = {{ keys }}[k];
|
| 8 |
+
let kp = {{ keys }}[partner];
|
| 9 |
+
let kBeforeP = (pk < pp) || (pk == pp && kk <= kp);
|
| 10 |
+
let needSwap = select(kBeforeP, !kBeforeP, ascending);
|
| 11 |
+
if (needSwap) {
|
| 12 |
+
let tVal = {{ values }}[k];
|
| 13 |
+
{{ values }}[k] = {{ values }}[partner];
|
| 14 |
+
{{ values }}[partner] = tVal;
|
| 15 |
+
{% if writeState %}
|
| 16 |
+
{{ keys }}[k] = kp;
|
| 17 |
+
{{ keys }}[partner] = kk;
|
| 18 |
+
{{ pads }}[k] = pp;
|
| 19 |
+
{{ pads }}[partner] = pk;
|
| 20 |
+
{% endif %}
|
| 21 |
+
}
|
| 22 |
+
{% endmacro %}
|
| 23 |
+
|
| 24 |
+
const TILE: u32 = {{ tileSize }}u;
|
| 25 |
+
const WG: u32 = {{ workgroupSize }}u;
|
| 26 |
+
var<workgroup> tileKey: array<u32, TILE>;
|
| 27 |
+
var<workgroup> tileVal: array<u32, TILE>;
|
| 28 |
+
var<workgroup> tilePad: array<u32, TILE>;
|
| 29 |
+
fn exchange_pair(pair: u32, stride: u32, size: u32, base: u32) {
|
| 30 |
+
let k = (pair / stride) * (2u * stride) + pair % stride;
|
| 31 |
+
let partner = k + stride;
|
| 32 |
+
let ascending = ((base + k) & size) == 0u;
|
| 33 |
+
{{ exchange_integer("tileKey", "tileVal", "tilePad") }}
|
| 34 |
+
}
|
| 35 |
+
@compute @workgroup_size(WG)
|
| 36 |
+
fn main(@builtin(workgroup_id) wg: vec3<u32>,
|
| 37 |
+
@builtin(local_invocation_index) tid: u32) {
|
| 38 |
+
let base = wg.x * TILE;
|
| 39 |
+
for (var i = tid; i < TILE; i += WG) {
|
| 40 |
+
tileKey[i] = sortKey[base + i];
|
| 41 |
+
tileVal[i] = sortVal[base + i];
|
| 42 |
+
tilePad[i] = sortPad[base + i];
|
| 43 |
+
}
|
| 44 |
+
workgroupBarrier();
|
| 45 |
+
{% if initialSort %}
|
| 46 |
+
for (var size = 2u; size <= TILE; size *= 2u) {
|
| 47 |
+
for (var stride = size / 2u; stride > 0u; stride /= 2u) {
|
| 48 |
+
for (var pair = tid; pair < TILE / 2u; pair += WG) {
|
| 49 |
+
exchange_pair(pair, stride, size, base);
|
| 50 |
+
}
|
| 51 |
+
workgroupBarrier();
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
{% else %}
|
| 55 |
+
for (var stride = TILE / 2u; stride > 0u; stride /= 2u) {
|
| 56 |
+
for (var pair = tid; pair < TILE / 2u; pair += WG) {
|
| 57 |
+
exchange_pair(pair, stride, {{ sortSize }}u, base);
|
| 58 |
+
}
|
| 59 |
+
workgroupBarrier();
|
| 60 |
+
}
|
| 61 |
+
{% endif %}
|
| 62 |
+
for (var i = tid; i < TILE; i += WG) {
|
| 63 |
+
{% if writeSortState | default(true) %}
|
| 64 |
+
sortKey[base + i] = tileKey[i];
|
| 65 |
+
sortPad[base + i] = tilePad[i];
|
| 66 |
+
{% endif %}
|
| 67 |
+
sortVal[base + i] = tileVal[i];
|
| 68 |
+
}
|
| 69 |
+
}
|
build/webgpu/unique-hash-build.wgsl.jinja
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
// One thread per input element inserts its value into an open-addressing hash
|
|
@@ -15,10 +18,45 @@
|
|
| 15 |
// its minimum index uses `special`.
|
| 16 |
// Open-addressing table constants and key/hash helpers.
|
| 17 |
const EMPTY: u32 = 0xffffffffu;
|
| 18 |
-
const MASK: u32 = {{
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 21 |
-
{% if
|
|
|
|
|
|
|
|
|
|
| 22 |
return v;
|
| 23 |
{% else %}
|
| 24 |
return bitcast<u32>(v);
|
|
@@ -41,6 +79,11 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 41 |
if (i >= params.inputCount) {
|
| 42 |
return;
|
| 43 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
let k = key_bits(x[i]);
|
| 45 |
if (k == EMPTY) {
|
| 46 |
atomicMin(&special[0], i);
|
|
@@ -50,12 +93,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 50 |
loop {
|
| 51 |
let res = atomicCompareExchangeWeak(&tableKey[h], EMPTY, k);
|
| 52 |
if (res.exchanged || res.old_value == k) {
|
| 53 |
-
{% if not
|
| 54 |
// This slot now holds k (we just placed it, or it already held k).
|
| 55 |
atomicMin(&tableIdx[h], i);
|
| 56 |
{% endif %}
|
| 57 |
break;
|
| 58 |
}
|
| 59 |
-
|
|
|
|
|
|
|
| 60 |
}
|
| 61 |
}
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
// One thread per input element inserts its value into an open-addressing hash
|
|
|
|
| 18 |
// its minimum index uses `special`.
|
| 19 |
// Open-addressing table constants and key/hash helpers.
|
| 20 |
const EMPTY: u32 = 0xffffffffu;
|
| 21 |
+
const MASK: u32 = {{ tableSize }}u - 1u;
|
| 22 |
|
| 23 |
+
{% if isFloat %}
|
| 24 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 25 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 26 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 27 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 28 |
+
{% macro float_bits_def() %}
|
| 29 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 30 |
+
{% if usesF16 %}
|
| 31 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 32 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 33 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 34 |
+
{% else %}
|
| 35 |
+
return bitcast<u32>(v);
|
| 36 |
+
{% endif %}
|
| 37 |
+
}
|
| 38 |
+
{%- endmacro -%}
|
| 39 |
+
{%- macro is_nan_bits_def() %}
|
| 40 |
+
fn is_nan_bits(v: {{ scalar }}) -> bool {
|
| 41 |
+
let b = float_bits(v);
|
| 42 |
+
{% if usesF16 %}
|
| 43 |
+
return (b & 0x7c00u) == 0x7c00u && (b & 0x03ffu) != 0u;
|
| 44 |
+
{% else %}
|
| 45 |
+
return (b & 0x7f800000u) == 0x7f800000u && (b & 0x007fffffu) != 0u;
|
| 46 |
+
{% endif %}
|
| 47 |
+
}
|
| 48 |
+
{%- endmacro %}
|
| 49 |
+
|
| 50 |
+
{{ float_bits_def() }}
|
| 51 |
+
|
| 52 |
+
{{ is_nan_bits_def() }}
|
| 53 |
+
|
| 54 |
+
{% endif %}
|
| 55 |
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 56 |
+
{% if isFloat %}
|
| 57 |
+
let bits = float_bits(v);
|
| 58 |
+
return select(bits, 0u, bits == {{ "0x8000u" if usesF16 else "0x80000000u" }});
|
| 59 |
+
{% elif isUnsigned %}
|
| 60 |
return v;
|
| 61 |
{% else %}
|
| 62 |
return bitcast<u32>(v);
|
|
|
|
| 79 |
if (i >= params.inputCount) {
|
| 80 |
return;
|
| 81 |
}
|
| 82 |
+
{% if isFloat %}
|
| 83 |
+
// A leading NaN is the ordered map's only representative. Otherwise every
|
| 84 |
+
// NaN is equivalent to an already-present bucket and creates no new value.
|
| 85 |
+
if (is_nan_bits(x[0]) || is_nan_bits(x[i])) { return; }
|
| 86 |
+
{% endif %}
|
| 87 |
let k = key_bits(x[i]);
|
| 88 |
if (k == EMPTY) {
|
| 89 |
atomicMin(&special[0], i);
|
|
|
|
| 93 |
loop {
|
| 94 |
let res = atomicCompareExchangeWeak(&tableKey[h], EMPTY, k);
|
| 95 |
if (res.exchanged || res.old_value == k) {
|
| 96 |
+
{% if not keyOnly %}
|
| 97 |
// This slot now holds k (we just placed it, or it already held k).
|
| 98 |
atomicMin(&tableIdx[h], i);
|
| 99 |
{% endif %}
|
| 100 |
break;
|
| 101 |
}
|
| 102 |
+
// Weak CAS may fail spuriously while the slot is still empty.
|
| 103 |
+
// Keep probing this slot until it is claimed or contains another key.
|
| 104 |
+
if (res.old_value != EMPTY) { h = (h + 1u) & MASK; }
|
| 105 |
}
|
| 106 |
}
|
build/webgpu/unique-hash-collect.wgsl.jinja
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
{% if
|
| 2 |
enable subgroups;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
|
@@ -7,14 +7,14 @@ enable subgroups;
|
|
| 7 |
// occupied hash keys directly and reserve output positions once per workgroup.
|
| 8 |
// This avoids serializing every distinct value through one global atomic.
|
| 9 |
const EMPTY: u32 = 0xffffffffu;
|
| 10 |
-
const TABLE_SIZE: u32 = {{
|
| 11 |
-
const CAP: u32 = {{
|
| 12 |
-
{% if
|
| 13 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 14 |
|
| 15 |
{% endif %}
|
| 16 |
var<workgroup> groupBase: u32;
|
| 17 |
-
{% if
|
| 18 |
// The first subgroup lane writes its total. Lane zero converts these totals to
|
| 19 |
// subgroup offsets and performs the workgroup's sole global count reservation.
|
| 20 |
var<workgroup> subgroupOffsets: array<u32, WG>;
|
|
@@ -26,7 +26,7 @@ var<workgroup> localCount: atomic<u32>;
|
|
| 26 |
|
| 27 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 28 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
| 29 |
-
@builtin(local_invocation_id) lid: vec3<u32>{% if
|
| 30 |
@builtin(subgroup_invocation_id) sgLane: u32,
|
| 31 |
@builtin(subgroup_size) sgSize: u32{% endif %}) {
|
| 32 |
let h = gid.x;
|
|
@@ -54,7 +54,7 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
|
| 54 |
}
|
| 55 |
}
|
| 56 |
|
| 57 |
-
{% if
|
| 58 |
let subgroupPrefix = subgroupExclusiveAdd(itemCount);
|
| 59 |
let subgroupTotal = subgroupAdd(itemCount);
|
| 60 |
let subgroupId = lid.x / sgSize;
|
|
|
|
| 1 |
+
{% if useSubgroups %}
|
| 2 |
enable subgroups;
|
| 3 |
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
|
|
|
| 7 |
// occupied hash keys directly and reserve output positions once per workgroup.
|
| 8 |
// This avoids serializing every distinct value through one global atomic.
|
| 9 |
const EMPTY: u32 = 0xffffffffu;
|
| 10 |
+
const TABLE_SIZE: u32 = {{ tableSize }}u;
|
| 11 |
+
const CAP: u32 = {{ capacity }}u;
|
| 12 |
+
{% if useSubgroups %}
|
| 13 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 14 |
|
| 15 |
{% endif %}
|
| 16 |
var<workgroup> groupBase: u32;
|
| 17 |
+
{% if useSubgroups %}
|
| 18 |
// The first subgroup lane writes its total. Lane zero converts these totals to
|
| 19 |
// subgroup offsets and performs the workgroup's sole global count reservation.
|
| 20 |
var<workgroup> subgroupOffsets: array<u32, WG>;
|
|
|
|
| 26 |
|
| 27 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 28 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>,
|
| 29 |
+
@builtin(local_invocation_id) lid: vec3<u32>{% if useSubgroups %},
|
| 30 |
@builtin(subgroup_invocation_id) sgLane: u32,
|
| 31 |
@builtin(subgroup_size) sgSize: u32{% endif %}) {
|
| 32 |
let h = gid.x;
|
|
|
|
| 54 |
}
|
| 55 |
}
|
| 56 |
|
| 57 |
+
{% if useSubgroups %}
|
| 58 |
let subgroupPrefix = subgroupExclusiveAdd(itemCount);
|
| 59 |
let subgroupTotal = subgroupAdd(itemCount);
|
| 60 |
let subgroupId = lid.x / sgSize;
|
build/webgpu/unique-hash-init.wgsl.jinja
CHANGED
|
@@ -6,11 +6,11 @@
|
|
| 6 |
// folds each key's minimum input index into tableIdx, and it leaves the output
|
| 7 |
// counter alone -- only the sorted-collect path counts from zero here.
|
| 8 |
const EMPTY: u32 = 0xffffffffu;
|
| 9 |
-
const TABLE_SIZE: u32 = {{
|
| 10 |
|
| 11 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 12 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 13 |
-
{% if
|
| 14 |
let h4 = gid.x;
|
| 15 |
if (h4 >= TABLE_SIZE / 4u) {
|
| 16 |
return;
|
|
|
|
| 6 |
// folds each key's minimum input index into tableIdx, and it leaves the output
|
| 7 |
// counter alone -- only the sorted-collect path counts from zero here.
|
| 8 |
const EMPTY: u32 = 0xffffffffu;
|
| 9 |
+
const TABLE_SIZE: u32 = {{ tableSize }}u;
|
| 10 |
|
| 11 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 12 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 13 |
+
{% if keyOnlyVec4 %}
|
| 14 |
let h4 = gid.x;
|
| 15 |
if (h4 >= TABLE_SIZE / 4u) {
|
| 16 |
return;
|
build/webgpu/unique-hash-mark.wgsl.jinja
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
-
// Pass 3 of the hash-set parallel Unique
|
| 4 |
// input element re-probes the (now fully built) hash table for its value and
|
| 5 |
// reads the stored minimum index. flags[i] = 1 iff i is that minimum, i.e. i is
|
| 6 |
// the first occurrence of its value — exactly the predicate the O(n^2) scan
|
|
@@ -9,10 +12,45 @@
|
|
| 9 |
// hitting an EMPTY slot.
|
| 10 |
// Open-addressing table constants and key/hash helpers.
|
| 11 |
const EMPTY: u32 = 0xffffffffu;
|
| 12 |
-
const MASK: u32 = {{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 15 |
-
{% if
|
|
|
|
|
|
|
|
|
|
| 16 |
return v;
|
| 17 |
{% else %}
|
| 18 |
return bitcast<u32>(v);
|
|
@@ -34,6 +72,17 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 34 |
if (i >= params.inputCount) {
|
| 35 |
return;
|
| 36 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
let k = key_bits(x[i]);
|
| 38 |
if (k == EMPTY) {
|
| 39 |
flags[i] = select(0u, 1u, atomicLoad(&special[0]) == i);
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
|
| 6 |
+
// Pass 3 of the hash-set parallel Unique. One thread per
|
| 7 |
// input element re-probes the (now fully built) hash table for its value and
|
| 8 |
// reads the stored minimum index. flags[i] = 1 iff i is that minimum, i.e. i is
|
| 9 |
// the first occurrence of its value — exactly the predicate the O(n^2) scan
|
|
|
|
| 12 |
// hitting an EMPTY slot.
|
| 13 |
// Open-addressing table constants and key/hash helpers.
|
| 14 |
const EMPTY: u32 = 0xffffffffu;
|
| 15 |
+
const MASK: u32 = {{ tableSize }}u - 1u;
|
| 16 |
+
|
| 17 |
+
{% if isFloat %}
|
| 18 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 19 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 20 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 21 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 22 |
+
{% macro float_bits_def() %}
|
| 23 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 24 |
+
{% if usesF16 %}
|
| 25 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 26 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 27 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 28 |
+
{% else %}
|
| 29 |
+
return bitcast<u32>(v);
|
| 30 |
+
{% endif %}
|
| 31 |
+
}
|
| 32 |
+
{%- endmacro -%}
|
| 33 |
+
{%- macro is_nan_bits_def() %}
|
| 34 |
+
fn is_nan_bits(v: {{ scalar }}) -> bool {
|
| 35 |
+
let b = float_bits(v);
|
| 36 |
+
{% if usesF16 %}
|
| 37 |
+
return (b & 0x7c00u) == 0x7c00u && (b & 0x03ffu) != 0u;
|
| 38 |
+
{% else %}
|
| 39 |
+
return (b & 0x7f800000u) == 0x7f800000u && (b & 0x007fffffu) != 0u;
|
| 40 |
+
{% endif %}
|
| 41 |
+
}
|
| 42 |
+
{%- endmacro %}
|
| 43 |
|
| 44 |
+
{{ float_bits_def() }}
|
| 45 |
+
|
| 46 |
+
{{ is_nan_bits_def() }}
|
| 47 |
+
|
| 48 |
+
{% endif %}
|
| 49 |
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 50 |
+
{% if isFloat %}
|
| 51 |
+
let bits = float_bits(v);
|
| 52 |
+
return select(bits, 0u, bits == {{ "0x8000u" if usesF16 else "0x80000000u" }});
|
| 53 |
+
{% elif isUnsigned %}
|
| 54 |
return v;
|
| 55 |
{% else %}
|
| 56 |
return bitcast<u32>(v);
|
|
|
|
| 72 |
if (i >= params.inputCount) {
|
| 73 |
return;
|
| 74 |
}
|
| 75 |
+
{% if isFloat %}
|
| 76 |
+
// Preserve the leading NaN's exact payload through the original X value.
|
| 77 |
+
if (is_nan_bits(x[0])) {
|
| 78 |
+
flags[i] = select(0u, 1u, i == 0u);
|
| 79 |
+
return;
|
| 80 |
+
}
|
| 81 |
+
if (is_nan_bits(x[i])) {
|
| 82 |
+
flags[i] = 0u;
|
| 83 |
+
return;
|
| 84 |
+
}
|
| 85 |
+
{% endif %}
|
| 86 |
let k = key_bits(x[i]);
|
| 87 |
if (k == EMPTY) {
|
| 88 |
flags[i] = select(0u, 1u, atomicLoad(&special[0]) == i);
|
build/webgpu/unique-hash-sort-collected-key-only.wgsl.jinja
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 4 |
-
const CAP: u32 = {{
|
| 5 |
-
const SORT_N: u32 = {{
|
| 6 |
|
| 7 |
// The monotonic key transform is invertible, so the workgroup sort only needs
|
| 8 |
// one u32 per slot. Padding uses the maximum key; if a real maximum key exists,
|
|
|
|
| 1 |
{{ env.wgsl.resourceDeclarations }}
|
| 2 |
|
| 3 |
const WG: u32 = {{ tunables.WORKGROUP_SIZE }}u;
|
| 4 |
+
const CAP: u32 = {{ capacity }}u;
|
| 5 |
+
const SORT_N: u32 = {{ sortN }}u;
|
| 6 |
|
| 7 |
// The monotonic key transform is invertible, so the workgroup sort only needs
|
| 8 |
// one u32 per slot. Padding uses the maximum key; if a real maximum key exists,
|
build/webgpu/unique-scalar-compact.wgsl.jinja
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if sorted and usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
{% if sorted %}
|
| 6 |
+
{% if isFloat %}
|
| 7 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 8 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 9 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 10 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 11 |
+
{% macro float_bits_def() %}
|
| 12 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 13 |
+
{% if usesF16 %}
|
| 14 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 15 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 16 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 17 |
+
{% else %}
|
| 18 |
+
return bitcast<u32>(v);
|
| 19 |
+
{% endif %}
|
| 20 |
+
}
|
| 21 |
+
{%- endmacro %}
|
| 22 |
+
|
| 23 |
+
{{ float_bits_def() }}
|
| 24 |
+
{% endif %}
|
| 25 |
+
fn ordered_key(value: {{ scalar }}) -> u32 {
|
| 26 |
+
{% if isFloat %}
|
| 27 |
+
let bits = float_bits(value);
|
| 28 |
+
return select(bits | {{ "0x8000u" if usesF16 else "0x80000000u" }}, (~bits) & {{ "0xffffu" if usesF16 else "0xffffffffu" }}, (bits & {{ "0x8000u" if usesF16 else "0x80000000u" }}) != 0u);
|
| 29 |
+
{% elif isUnsigned %}
|
| 30 |
+
return value;
|
| 31 |
+
{% else %}
|
| 32 |
+
return bitcast<u32>(value) ^ 0x80000000u;
|
| 33 |
+
{% endif %}
|
| 34 |
+
}
|
| 35 |
+
{% endif %}
|
| 36 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 37 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 38 |
+
let i = gid.x;
|
| 39 |
+
if (i < {{ scanN }}u) {
|
| 40 |
+
let encoded = flags[i];
|
| 41 |
+
if ((encoded & 1u) != 0u) {
|
| 42 |
+
let position = blockPrefix[i / {{ tunables.WORKGROUP_SIZE }}u] + (encoded >> 1u);
|
| 43 |
+
if (position < {{ capacity }}u) {
|
| 44 |
+
sortVal[position] = i;
|
| 45 |
+
{% if sorted %}
|
| 46 |
+
sortKey[position] = ordered_key(x[i]);
|
| 47 |
+
sortPad[position] = 0u;
|
| 48 |
+
{% endif %}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
{% if sorted %}
|
| 53 |
+
// Exact output cardinality is part of Unique's required request contract.
|
| 54 |
+
if (i >= {{ capacity }}u && i < {{ sortN }}u) {
|
| 55 |
+
sortPad[i] = 1u;
|
| 56 |
+
sortKey[i] = 0u;
|
| 57 |
+
sortVal[i] = 0u;
|
| 58 |
+
}
|
| 59 |
+
{% endif %}
|
| 60 |
+
}
|
build/webgpu/unique-scalar-metadata.wgsl.jinja
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
// Open-addressing table constants and key/hash helpers.
|
| 6 |
+
const EMPTY: u32 = 0xffffffffu;
|
| 7 |
+
const MASK: u32 = {{ tableSize }}u - 1u;
|
| 8 |
+
|
| 9 |
+
{% if isFloat %}
|
| 10 |
+
// IEEE total-order comparators for Unique. Floating-point equality and ordering
|
| 11 |
+
// use raw bits because GPUs may flush subnormals in float comparisons, which
|
| 12 |
+
// would otherwise collapse distinct values. Equality canonicalizes -0 to +0;
|
| 13 |
+
// ordering uses a monotonic u32 key over the real line. Integers use == and <.
|
| 14 |
+
{% macro float_bits_def() %}
|
| 15 |
+
fn float_bits(v: {{ scalar }}) -> u32 {
|
| 16 |
+
{% if usesF16 %}
|
| 17 |
+
// WGSL has no scalar u16 type. Packing v into the low component preserves
|
| 18 |
+
// its binary16 representation while producing a bitcast-compatible 32 bits.
|
| 19 |
+
return bitcast<u32>(vec2<f16>(v, 0.0h)) & 0xffffu;
|
| 20 |
+
{% else %}
|
| 21 |
+
return bitcast<u32>(v);
|
| 22 |
+
{% endif %}
|
| 23 |
+
}
|
| 24 |
+
{%- endmacro -%}
|
| 25 |
+
{%- macro is_nan_bits_def() %}
|
| 26 |
+
fn is_nan_bits(v: {{ scalar }}) -> bool {
|
| 27 |
+
let b = float_bits(v);
|
| 28 |
+
{% if usesF16 %}
|
| 29 |
+
return (b & 0x7c00u) == 0x7c00u && (b & 0x03ffu) != 0u;
|
| 30 |
+
{% else %}
|
| 31 |
+
return (b & 0x7f800000u) == 0x7f800000u && (b & 0x007fffffu) != 0u;
|
| 32 |
+
{% endif %}
|
| 33 |
+
}
|
| 34 |
+
{%- endmacro %}
|
| 35 |
+
|
| 36 |
+
{{ float_bits_def() }}
|
| 37 |
+
|
| 38 |
+
{{ is_nan_bits_def() }}
|
| 39 |
+
|
| 40 |
+
{% endif %}
|
| 41 |
+
fn key_bits(v: {{ scalar }}) -> u32 {
|
| 42 |
+
{% if isFloat %}
|
| 43 |
+
let bits = float_bits(v);
|
| 44 |
+
return select(bits, 0u, bits == {{ "0x8000u" if usesF16 else "0x80000000u" }});
|
| 45 |
+
{% elif isUnsigned %}
|
| 46 |
+
return v;
|
| 47 |
+
{% else %}
|
| 48 |
+
return bitcast<u32>(v);
|
| 49 |
+
{% endif %}
|
| 50 |
+
}
|
| 51 |
+
fn hash_key(k: u32) -> u32 {
|
| 52 |
+
var x = k;
|
| 53 |
+
x = x ^ (x >> 16u);
|
| 54 |
+
x = x * 0x7feb352du;
|
| 55 |
+
x = x ^ (x >> 15u);
|
| 56 |
+
x = x * 0x846ca68bu;
|
| 57 |
+
x = x ^ (x >> 16u);
|
| 58 |
+
return x;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
{% if isFloat and not sorted %}
|
| 62 |
+
fn ordered_key(key: u32) -> u32 {
|
| 63 |
+
{% if usesF16 %}
|
| 64 |
+
return select(key ^ 0x8000u, (~key) & 0xffffu, (key & 0x8000u) != 0u);
|
| 65 |
+
{% else %}
|
| 66 |
+
return select(key ^ 0x80000000u, ~key, (key & 0x80000000u) != 0u);
|
| 67 |
+
{% endif %}
|
| 68 |
+
}
|
| 69 |
+
{% endif %}
|
| 70 |
+
fn find_rank(i: u32) -> u32 {
|
| 71 |
+
{% if isFloat %}
|
| 72 |
+
if (is_nan_bits(x[0])) { return 0u; }
|
| 73 |
+
// Later NaNs joined the smallest representative that already existed.
|
| 74 |
+
// Scan distinct representatives, excluding ones first seen after this input.
|
| 75 |
+
// Sorted slots can stop at their first eligible representative; unsorted
|
| 76 |
+
// slots appear in first-occurrence order, so later slots can be excluded.
|
| 77 |
+
if (is_nan_bits(x[i])) {
|
| 78 |
+
let written = {{ capacity }}u;
|
| 79 |
+
{% if not sorted %}
|
| 80 |
+
var best = 0u;
|
| 81 |
+
var bestKey = ordered_key(key_bits(x[slots[0]]));
|
| 82 |
+
{% endif %}
|
| 83 |
+
for (var p = 0u; p < written; p += 1u) {
|
| 84 |
+
let first = slots[p];
|
| 85 |
+
{% if sorted %}
|
| 86 |
+
if (first <= i) { return p; }
|
| 87 |
+
{% else %}
|
| 88 |
+
if (first > i) { break; }
|
| 89 |
+
let candidate = ordered_key(key_bits(x[first]));
|
| 90 |
+
if (candidate < bestKey) { best = p; bestKey = candidate; }
|
| 91 |
+
{% endif %}
|
| 92 |
+
}
|
| 93 |
+
return {{ "0u" if sorted else "best" }};
|
| 94 |
+
}
|
| 95 |
+
{% endif %}
|
| 96 |
+
let key = key_bits(x[i]);
|
| 97 |
+
// The first output class is common in repeated-value streams.
|
| 98 |
+
if (key == key_bits(x[slots[0]])) { return 0u; }
|
| 99 |
+
if (key == EMPTY) { return rankOfFirst[special[0]]; }
|
| 100 |
+
var slot = hash_key(key) & MASK;
|
| 101 |
+
loop {
|
| 102 |
+
let stored = tableKey[slot];
|
| 103 |
+
if (stored == key) {
|
| 104 |
+
return rankOfFirst[tableIdx[slot]];
|
| 105 |
+
}
|
| 106 |
+
if (stored == EMPTY) { return 0u; }
|
| 107 |
+
slot = (slot + 1u) & MASK;
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 112 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 113 |
+
let i = gid.x;
|
| 114 |
+
if (i >= {{ scanN }}u) { return; }
|
| 115 |
+
let rank = find_rank(i);
|
| 116 |
+
{% if hasInverseIndices %}
|
| 117 |
+
inverse_indices[i] = rank;
|
| 118 |
+
{% endif %}
|
| 119 |
+
{% if hasCounts %}
|
| 120 |
+
atomicAdd(&counts[rank], 1u);
|
| 121 |
+
{% endif %}
|
| 122 |
+
}
|
build/webgpu/unique-scalar-output.wgsl.jinja
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 6 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 7 |
+
let p = gid.x;
|
| 8 |
+
if (p >= {{ capacity }}u) { return; }
|
| 9 |
+
let first = slots[p];
|
| 10 |
+
y[p] = x[first];
|
| 11 |
+
{% if hasIndices %}
|
| 12 |
+
indices[p] = first;
|
| 13 |
+
{% endif %}
|
| 14 |
+
{% if needsRanks %}
|
| 15 |
+
rankOfFirst[first] = p;
|
| 16 |
+
{% endif %}
|
| 17 |
+
{% if hasCounts %}
|
| 18 |
+
counts[p] = 0u;
|
| 19 |
+
{% endif %}
|
| 20 |
+
}
|
build/webgpu/unique-single-class.wgsl.jinja
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% if usesF16 %}
|
| 2 |
+
enable f16;
|
| 3 |
+
{% endif %}
|
| 4 |
+
{{ env.wgsl.resourceDeclarations }}
|
| 5 |
+
// Exact output cardinality is required by the op contract. One class proves
|
| 6 |
+
// that every input belongs to the first representative, including NaNs and
|
| 7 |
+
// whole axis slices. No hash, scan, sort or atomic count is necessary.
|
| 8 |
+
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 9 |
+
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 10 |
+
let i = gid.x;
|
| 11 |
+
if (i < {{ outputElements }}u) {
|
| 12 |
+
{% if axisPresent %}
|
| 13 |
+
let source = (i / {{ scalarInner }}u) * {{ inputExtent * scalarInner }}u + i % {{ scalarInner }}u;
|
| 14 |
+
y[i] = x[source];
|
| 15 |
+
{% else %}
|
| 16 |
+
y[i] = x[0];
|
| 17 |
+
{% endif %}
|
| 18 |
+
}
|
| 19 |
+
{% if hasInverseIndices %}
|
| 20 |
+
if (i < {{ inputExtent }}u) { inverse_indices[i] = 0u; }
|
| 21 |
+
{% endif %}
|
| 22 |
+
{% if hasIndices or hasCounts %}
|
| 23 |
+
if (i == 0u) {
|
| 24 |
+
{% if hasIndices %}
|
| 25 |
+
indices[0] = 0u;
|
| 26 |
+
{% endif %}
|
| 27 |
+
{% if hasCounts %}
|
| 28 |
+
counts[0] = {{ inputExtent }}u;
|
| 29 |
+
{% endif %}
|
| 30 |
+
}
|
| 31 |
+
{% endif %}
|
| 32 |
+
}
|
build/webgpu/unique.wgsl.jinja
CHANGED
|
@@ -65,12 +65,9 @@ fn is_nan_bits(v: {{ scalar }}) -> bool {
|
|
| 65 |
}
|
| 66 |
{%- endmacro %}
|
| 67 |
|
| 68 |
-
{% set emitIndices =
|
| 69 |
-
{% set emitInverseIndices =
|
| 70 |
-
{% set emitCounts =
|
| 71 |
-
{% if usesF16 %}
|
| 72 |
-
enable f16;
|
| 73 |
-
{% endif %}
|
| 74 |
{{ env.wgsl.resourceDeclarations }}
|
| 75 |
|
| 76 |
// Floating-point equality/order use the raw IEEE bit pattern, not the float
|
|
@@ -103,6 +100,10 @@ fn ordered_less(a: {{ scalar }}, b: {{ scalar }}) -> bool {
|
|
| 103 |
}
|
| 104 |
|
| 105 |
{% if emitIndices or emitInverseIndices or emitCounts %}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
fn representative_input_index(output_i: u32) -> u32 {
|
| 107 |
let representative = y[output_i];
|
| 108 |
for (var input_i = 0u; input_i < params.inputCount; input_i = input_i + 1u) {
|
|
@@ -120,7 +121,7 @@ fn find_bucket(input_i: u32, written: u32) -> u32 {
|
|
| 120 |
let value = x[input_i];
|
| 121 |
var candidate = written;
|
| 122 |
for (var output_i = 0u; output_i < written; output_i = output_i + 1u) {
|
| 123 |
-
if (
|
| 124 |
if (candidate == written || ordered_less(y[output_i], y[candidate])) {
|
| 125 |
candidate = output_i;
|
| 126 |
}
|
|
@@ -168,9 +169,14 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 168 |
for (var i = written; i < params.capacity; i = i + 1u) {
|
| 169 |
y[i] = zero_value();
|
| 170 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
{% if emitIndices %}
|
| 172 |
for (var unique_i = 0u; unique_i < params.capacity; unique_i = unique_i + 1u) {
|
| 173 |
-
indices[unique_i] =
|
| 174 |
}
|
| 175 |
{% endif %}
|
| 176 |
{% if emitCounts %}
|
|
|
|
| 65 |
}
|
| 66 |
{%- endmacro %}
|
| 67 |
|
| 68 |
+
{% set emitIndices = hasIndices | default(false) %}
|
| 69 |
+
{% set emitInverseIndices = hasInverseIndices | default(false) %}
|
| 70 |
+
{% set emitCounts = hasCounts | default(false) %}
|
|
|
|
|
|
|
|
|
|
| 71 |
{{ env.wgsl.resourceDeclarations }}
|
| 72 |
|
| 73 |
// Floating-point equality/order use the raw IEEE bit pattern, not the float
|
|
|
|
| 100 |
}
|
| 101 |
|
| 102 |
{% if emitIndices or emitInverseIndices or emitCounts %}
|
| 103 |
+
// The representative of an output slot is a pure function of the finished Y and
|
| 104 |
+
// of X, but the bucket resolution below asks for it once per (input, output)
|
| 105 |
+
// pair, which makes an O(n) scan the innermost of three nested loops. It is
|
| 106 |
+
// computed once per slot into `representatives` and read from there instead.
|
| 107 |
fn representative_input_index(output_i: u32) -> u32 {
|
| 108 |
let representative = y[output_i];
|
| 109 |
for (var input_i = 0u; input_i < params.inputCount; input_i = input_i + 1u) {
|
|
|
|
| 121 |
let value = x[input_i];
|
| 122 |
var candidate = written;
|
| 123 |
for (var output_i = 0u; output_i < written; output_i = output_i + 1u) {
|
| 124 |
+
if (representatives[output_i] > input_i || ordered_less(y[output_i], value)) { continue; }
|
| 125 |
if (candidate == written || ordered_less(y[output_i], y[candidate])) {
|
| 126 |
candidate = output_i;
|
| 127 |
}
|
|
|
|
| 169 |
for (var i = written; i < params.capacity; i = i + 1u) {
|
| 170 |
y[i] = zero_value();
|
| 171 |
}
|
| 172 |
+
{% if emitIndices or emitInverseIndices or emitCounts %}
|
| 173 |
+
for (var unique_i = 0u; unique_i < params.capacity; unique_i = unique_i + 1u) {
|
| 174 |
+
representatives[unique_i] = representative_input_index(unique_i);
|
| 175 |
+
}
|
| 176 |
+
{% endif %}
|
| 177 |
{% if emitIndices %}
|
| 178 |
for (var unique_i = 0u; unique_i < params.capacity; unique_i = unique_i + 1u) {
|
| 179 |
+
indices[unique_i] = representatives[unique_i];
|
| 180 |
}
|
| 181 |
{% endif %}
|
| 182 |
{% if emitCounts %}
|