fuzzgpu 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/Cargo.lock +4 -4
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/PKG-INFO +8 -7
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/README.md +7 -6
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/Cargo.toml +1 -1
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/gpu.rs +43 -47
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/jaro.rs +2 -1
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/levenshtein.rs +5 -7
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/needleman.rs +3 -3
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/simd.rs +1 -1
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/tests/differential.rs +19 -9
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-python/Cargo.toml +2 -2
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-wasm/Cargo.toml +1 -1
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/pyproject.toml +1 -1
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/Cargo.toml +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/LICENSE +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/assets/logo.png +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/benches/bench.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/damerau.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/fuzz.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/lib.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/damerau.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/damerau_matrix.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/jaro.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/jaro_matrix.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein_cdist_myers.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein_matrix.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein_myers.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein_short.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/needleman_affine.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/needleman_wavefront.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/tests/differential.proptest-regressions +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/tests/fixtures/broken.wgsl +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/tests/kernel_registration.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-python/src/lib.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-wasm/src/lib.rs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-wasm/tests/differential_harness.js +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-wasm/tests/js_api.test.cjs +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/__init__.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/__init__.pyi +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/DamerauLevenshtein.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Hamming.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Indel.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Jaro.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/JaroWinkler.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/LCSseq.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Levenshtein.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/OSA.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Postfix.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/Prefix.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/__init__.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/__init__.pyi +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/distance/_common.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/fuzz.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/fuzz.pyi +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/process.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/python/fuzzgpu/process.pyi +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_api_signatures.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_basic.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_concurrency.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_edge_cases.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_gpu_health.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_gpu_threshold_env.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_invariants.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_out_buffers.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_rapidfuzz_compat.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/test_stress.py +0 -0
- {fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/tests/wasm_python_differential.py +0 -0
|
@@ -308,9 +308,9 @@ dependencies = [
|
|
|
308
308
|
|
|
309
309
|
[[package]]
|
|
310
310
|
name = "either"
|
|
311
|
-
version = "1.
|
|
311
|
+
version = "1.18.0"
|
|
312
312
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
313
|
-
checksum = "
|
|
313
|
+
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
|
|
314
314
|
|
|
315
315
|
[[package]]
|
|
316
316
|
name = "equivalent"
|
|
@@ -372,7 +372,7 @@ dependencies = [
|
|
|
372
372
|
|
|
373
373
|
[[package]]
|
|
374
374
|
name = "fuzzgpu-core"
|
|
375
|
-
version = "0.
|
|
375
|
+
version = "0.3.0"
|
|
376
376
|
dependencies = [
|
|
377
377
|
"bytemuck",
|
|
378
378
|
"criterion",
|
|
@@ -386,7 +386,7 @@ dependencies = [
|
|
|
386
386
|
|
|
387
387
|
[[package]]
|
|
388
388
|
name = "fuzzgpu-python"
|
|
389
|
-
version = "0.
|
|
389
|
+
version = "0.3.0"
|
|
390
390
|
dependencies = [
|
|
391
391
|
"fuzzgpu-core",
|
|
392
392
|
"log",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fuzzgpu
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -37,7 +37,8 @@ Project-URL: Repository, https://github.com/kuntal-devrat/fuzzgpu
|
|
|
37
37
|
|
|
38
38
|
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
39
39
|
|
|
40
|
-
[](https://pypi.org/project/fuzzgpu/)
|
|
41
42
|
[](https://opensource.org/licenses/MIT)
|
|
42
43
|
[](https://www.rust-lang.org)
|
|
43
44
|
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
@@ -60,7 +61,7 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
60
61
|
|
|
61
62
|
---
|
|
62
63
|
|
|
63
|
-
## What's New in v0.
|
|
64
|
+
## What's New in v0.3.0
|
|
64
65
|
|
|
65
66
|
### Production hardening
|
|
66
67
|
- **Kernel `get()` panics eliminated** — all four GPU kernels (`GpuLevenshteinKernel`,
|
|
@@ -164,7 +165,7 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
|
|
|
164
165
|
## Benchmark Results
|
|
165
166
|
|
|
166
167
|
*Hardware: Intel(R) Iris(R) Xe Graphics — integrated GPU (Vulkan) + Intel Core i7 (Rayon, all cores)*
|
|
167
|
-
*Versions: fuzzgpu 0.
|
|
168
|
+
*Versions: fuzzgpu 0.3.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
|
|
168
169
|
*Median of 7 runs after warmup. Reproduce: `python benchmarks/bench_compare.py`*
|
|
169
170
|
|
|
170
171
|
> **GPU class note:** These numbers are from an **integrated GPU** (iGPU), which shares memory
|
|
@@ -229,7 +230,7 @@ pip install fuzzgpu
|
|
|
229
230
|
```toml
|
|
230
231
|
# Rust
|
|
231
232
|
[dependencies]
|
|
232
|
-
fuzzgpu-core = "0.
|
|
233
|
+
fuzzgpu-core = "0.3.0"
|
|
233
234
|
```
|
|
234
235
|
|
|
235
236
|
---
|
|
@@ -325,7 +326,7 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
|
|
|
325
326
|
|
|
326
327
|
```toml
|
|
327
328
|
[dependencies]
|
|
328
|
-
fuzzgpu-core = "0.
|
|
329
|
+
fuzzgpu-core = "0.3.0" # GPU + CPU fallback
|
|
329
330
|
# fuzzgpu-core = { version = "0.1.7", default-features = false } # CPU-only
|
|
330
331
|
```
|
|
331
332
|
|
|
@@ -471,7 +472,7 @@ cargo test --workspace
|
|
|
471
472
|
| `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
|
|
472
473
|
| `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
|
|
473
474
|
| `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
|
|
474
|
-
| `FUZZGPU_SKIP_DISPATCH_LOCK` |
|
|
475
|
+
| `FUZZGPU_SKIP_DISPATCH_LOCK` | Opt-in GPU dispatch serialization (safety valve for the rare gfx-rs/wgpu#10085 crash class on Intel D3D12; dispatch is fully concurrent by default) |
|
|
475
476
|
| `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
|
|
476
477
|
| `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
|
|
477
478
|
| `PROPTEST_CASES` | Override proptest case count |
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
*Cross-platform GPU compute via WebGPU (`wgpu`) & Multi-Core CPU parallelism with Rayon. Zero CUDA dependencies.*
|
|
10
10
|
|
|
11
|
-
[](https://pypi.org/project/fuzzgpu/)
|
|
12
13
|
[](https://opensource.org/licenses/MIT)
|
|
13
14
|
[](https://www.rust-lang.org)
|
|
14
15
|
[](https://github.com/kuntal-devrat/fuzzgpu)
|
|
@@ -31,7 +32,7 @@ No NVIDIA CUDA drivers or complex toolkits required.
|
|
|
31
32
|
|
|
32
33
|
---
|
|
33
34
|
|
|
34
|
-
## What's New in v0.
|
|
35
|
+
## What's New in v0.3.0
|
|
35
36
|
|
|
36
37
|
### Production hardening
|
|
37
38
|
- **Kernel `get()` panics eliminated** — all four GPU kernels (`GpuLevenshteinKernel`,
|
|
@@ -135,7 +136,7 @@ The full Python layer is now byte-identical to rapidfuzz 3.14.5 over a 169,744-p
|
|
|
135
136
|
## Benchmark Results
|
|
136
137
|
|
|
137
138
|
*Hardware: Intel(R) Iris(R) Xe Graphics — integrated GPU (Vulkan) + Intel Core i7 (Rayon, all cores)*
|
|
138
|
-
*Versions: fuzzgpu 0.
|
|
139
|
+
*Versions: fuzzgpu 0.3.0 · rapidfuzz 3.14.5 · python-Levenshtein 0.27.4*
|
|
139
140
|
*Median of 7 runs after warmup. Reproduce: `python benchmarks/bench_compare.py`*
|
|
140
141
|
|
|
141
142
|
> **GPU class note:** These numbers are from an **integrated GPU** (iGPU), which shares memory
|
|
@@ -200,7 +201,7 @@ pip install fuzzgpu
|
|
|
200
201
|
```toml
|
|
201
202
|
# Rust
|
|
202
203
|
[dependencies]
|
|
203
|
-
fuzzgpu-core = "0.
|
|
204
|
+
fuzzgpu-core = "0.3.0"
|
|
204
205
|
```
|
|
205
206
|
|
|
206
207
|
---
|
|
@@ -296,7 +297,7 @@ fuzzgpu.set_cpu_only(True) # force CPU-only mode
|
|
|
296
297
|
|
|
297
298
|
```toml
|
|
298
299
|
[dependencies]
|
|
299
|
-
fuzzgpu-core = "0.
|
|
300
|
+
fuzzgpu-core = "0.3.0" # GPU + CPU fallback
|
|
300
301
|
# fuzzgpu-core = { version = "0.1.7", default-features = false } # CPU-only
|
|
301
302
|
```
|
|
302
303
|
|
|
@@ -442,7 +443,7 @@ cargo test --workspace
|
|
|
442
443
|
| `FUZZGPU_DEBUG` | Log GPU→CPU fallback decisions |
|
|
443
444
|
| `FUZZGPU_SIMD` | Force ISA: `portable\|neon\|avx2\|avx512` |
|
|
444
445
|
| `FUZZGPU_READBACK_TIMEOUT_MS` | GPU readback timeout (default 10000 ms) |
|
|
445
|
-
| `FUZZGPU_SKIP_DISPATCH_LOCK` |
|
|
446
|
+
| `FUZZGPU_SKIP_DISPATCH_LOCK` | Opt-in GPU dispatch serialization (safety valve for the rare gfx-rs/wgpu#10085 crash class on Intel D3D12; dispatch is fully concurrent by default) |
|
|
446
447
|
| `FUZZGPU_REQUIRE_GPU` | In tests: fail instead of skip when no GPU |
|
|
447
448
|
| `WGPU_BACKEND` | Force wgpu backend: `vulkan\|metal\|dx12` |
|
|
448
449
|
| `PROPTEST_CASES` | Override proptest case count |
|
|
@@ -25,25 +25,23 @@ pub fn require_gpu() -> bool {
|
|
|
25
25
|
.unwrap_or(false)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
///
|
|
29
|
-
///
|
|
30
|
-
///
|
|
31
|
-
///
|
|
32
|
-
|
|
28
|
+
/// Opt-in dispatch serialization (safety valve). `FUZZGPU_SKIP_DISPATCH_LOCK=1`
|
|
29
|
+
/// re-enables the GPU-dispatch serialization that used to be the default
|
|
30
|
+
/// workaround for the rare gfx-rs/wgpu#10085 crash class (heap corruption on
|
|
31
|
+
/// Intel D3D12 under >=3 concurrent dispatchers on a shared device). Dispatch
|
|
32
|
+
/// is fully concurrent by default; set this env var on affected Intel hardware
|
|
33
|
+
/// to serialize both the production dispatch path and the test suite.
|
|
34
|
+
pub(crate) fn dispatch_serialize() -> bool {
|
|
33
35
|
std::env::var("FUZZGPU_SKIP_DISPATCH_LOCK")
|
|
34
36
|
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
|
35
37
|
.unwrap_or(false)
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
/// Serialize GPU access across tests.
|
|
39
|
-
///
|
|
40
|
-
///
|
|
41
|
-
/// `repro/wgpu-parallel-crash` and upstream gfx-rs/wgpu#10085.
|
|
42
|
-
///
|
|
43
|
-
/// Setting `FUZZGPU_SKIP_DISPATCH_LOCK=1` bypasses the workaround so the
|
|
44
|
-
/// underlying crash can be reproduced / bisected in CI or locally.
|
|
40
|
+
/// Serialize GPU access across tests. Only active when
|
|
41
|
+
/// `FUZZGPU_SKIP_DISPATCH_LOCK=1` (opt-in safety valve); by default returns
|
|
42
|
+
/// `None` so the test suite runs with fully concurrent GPU dispatch.
|
|
45
43
|
pub fn gpu_test_lock() -> Option<std::sync::MutexGuard<'static, ()>> {
|
|
46
|
-
if
|
|
44
|
+
if !dispatch_serialize() {
|
|
47
45
|
return None;
|
|
48
46
|
}
|
|
49
47
|
Some(
|
|
@@ -99,21 +97,10 @@ pub(crate) fn effective_shader_source(real: &'static str) -> std::borrow::Cow<'s
|
|
|
99
97
|
std::borrow::Cow::Borrowed(real)
|
|
100
98
|
}
|
|
101
99
|
|
|
102
|
-
///
|
|
103
|
-
///
|
|
104
|
-
///
|
|
105
|
-
///
|
|
106
|
-
/// gfx-rs/wgpu#10085. The fix is in branch `fix/queue-drop-drain-loop`
|
|
107
|
-
/// (PR pending merge into `gfx-rs/wgpu`).
|
|
108
|
-
///
|
|
109
|
-
/// **Removal plan:** once the wgpu fix ships in a released version and
|
|
110
|
-
/// `fuzzgpu` bumps its dependency to that version, remove:
|
|
111
|
-
/// - This lock and its static
|
|
112
|
-
/// - `dispatch_lock_bypass()` and `FUZZGPU_SKIP_DISPATCH_LOCK` support
|
|
113
|
-
/// - `GpuEngine::dispatch_lock` field and `dispatch_lock()` method
|
|
114
|
-
///
|
|
115
|
-
/// Setting `FUZZGPU_SKIP_DISPATCH_LOCK=1` bypasses the workaround so the
|
|
116
|
-
/// underlying crash can be reproduced / bisected in CI or locally.
|
|
100
|
+
/// Test-suite dispatch serialization, active only when
|
|
101
|
+
/// `FUZZGPU_SKIP_DISPATCH_LOCK=1` (opt-in safety valve for the rare
|
|
102
|
+
/// gfx-rs/wgpu#10085 crash class on Intel D3D12). By default the suite runs
|
|
103
|
+
/// with fully concurrent GPU dispatch.
|
|
117
104
|
pub static GPU_TEST_DISPATCH_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
|
118
105
|
|
|
119
106
|
/// Serializes tests that mutate `GPU_THRESHOLD_OVERRIDE`.
|
|
@@ -236,13 +223,11 @@ pub struct GpuEngine {
|
|
|
236
223
|
pub info: GpuInfo,
|
|
237
224
|
pub max_buffer_size: u64,
|
|
238
225
|
pub max_storage_buffer_binding_size: u32,
|
|
239
|
-
///
|
|
240
|
-
///
|
|
241
|
-
///
|
|
242
|
-
/// calling the GIL-releasing GPU bindings simultaneously. Every public GPU
|
|
226
|
+
/// Opt-in dispatch serialization (safety valve for the rare
|
|
227
|
+
/// gfx-rs/wgpu#10085 crash class on Intel D3D12). By default dispatch is
|
|
228
|
+
/// fully concurrent; when `FUZZGPU_SKIP_DISPATCH_LOCK=1` every public GPU
|
|
243
229
|
/// entry point holds this lock for the duration of its dispatch + readback,
|
|
244
|
-
/// so at most one submission is ever in flight.
|
|
245
|
-
/// bypasses it (repro harness only).
|
|
230
|
+
/// so at most one submission is ever in flight.
|
|
246
231
|
dispatch_lock: std::sync::Mutex<()>,
|
|
247
232
|
}
|
|
248
233
|
|
|
@@ -533,11 +518,11 @@ impl GpuEngine {
|
|
|
533
518
|
Ok(bytes)
|
|
534
519
|
}
|
|
535
520
|
|
|
536
|
-
/// Take the
|
|
537
|
-
///
|
|
538
|
-
///
|
|
521
|
+
/// Take the opt-in dispatch serialization lock (see the field doc).
|
|
522
|
+
/// Returns `None` unless `FUZZGPU_SKIP_DISPATCH_LOCK=1` is set — dispatch
|
|
523
|
+
/// is fully concurrent by default.
|
|
539
524
|
pub(crate) fn dispatch_lock(&self) -> Option<std::sync::MutexGuard<'_, ()>> {
|
|
540
|
-
if
|
|
525
|
+
if !dispatch_serialize() {
|
|
541
526
|
return None;
|
|
542
527
|
}
|
|
543
528
|
Some(self.dispatch_lock.lock().unwrap_or_else(|e| e.into_inner()))
|
|
@@ -722,13 +707,16 @@ mod tests {
|
|
|
722
707
|
|
|
723
708
|
/// `set_gpu_threshold` must override the auto value and be resettable to
|
|
724
709
|
/// auto (`None`) at runtime (a `Mutex`, not a one-shot `OnceLock`). The
|
|
725
|
-
/// override is global, so this test holds
|
|
726
|
-
///
|
|
727
|
-
///
|
|
728
|
-
///
|
|
710
|
+
/// override is global, so this test holds `GPU_THRESHOLD_TEST_LOCK` —
|
|
711
|
+
/// excluding every other test that mutates or force-reads the override
|
|
712
|
+
/// (fault-injection tests route to CPU instead of dispatching when a
|
|
713
|
+
/// concurrent test steals the override mid-flight) — and restores `None`
|
|
714
|
+
/// before returning.
|
|
729
715
|
#[test]
|
|
730
716
|
fn test_set_gpu_threshold_override_and_reset() {
|
|
731
|
-
let
|
|
717
|
+
let _thr = GPU_THRESHOLD_TEST_LOCK
|
|
718
|
+
.lock()
|
|
719
|
+
.unwrap_or_else(|e| e.into_inner());
|
|
732
720
|
GpuEngine::set_gpu_threshold(Some(1234));
|
|
733
721
|
assert_eq!(GpuEngine::gpu_threshold_override(), Some(1234));
|
|
734
722
|
if let Ok(engine) = GpuEngine::get() {
|
|
@@ -808,12 +796,20 @@ mod tests {
|
|
|
808
796
|
disarm_shader_error_fault();
|
|
809
797
|
}
|
|
810
798
|
|
|
811
|
-
///
|
|
812
|
-
/// true only when it is set to '1' or 'true' (case-insensitive).
|
|
799
|
+
/// dispatch_serialize must read FUZZGPU_SKIP_DISPATCH_LOCK and return
|
|
800
|
+
/// true only when it is set to '1' or 'true' (case-insensitive). The
|
|
801
|
+
/// serialization is opt-in: unset (default) means fully concurrent.
|
|
813
802
|
#[test]
|
|
814
|
-
fn
|
|
803
|
+
fn test_dispatch_serialize_opt_in() {
|
|
804
|
+
std::env::remove_var("FUZZGPU_SKIP_DISPATCH_LOCK");
|
|
805
|
+
assert!(!dispatch_serialize());
|
|
806
|
+
std::env::set_var("FUZZGPU_SKIP_DISPATCH_LOCK", "1");
|
|
807
|
+
assert!(dispatch_serialize());
|
|
808
|
+
std::env::set_var("FUZZGPU_SKIP_DISPATCH_LOCK", "true");
|
|
809
|
+
assert!(dispatch_serialize());
|
|
810
|
+
std::env::set_var("FUZZGPU_SKIP_DISPATCH_LOCK", "0");
|
|
811
|
+
assert!(!dispatch_serialize());
|
|
815
812
|
std::env::remove_var("FUZZGPU_SKIP_DISPATCH_LOCK");
|
|
816
|
-
assert!(!dispatch_lock_bypass());
|
|
817
813
|
}
|
|
818
814
|
|
|
819
815
|
/// force_gpu_threshold sets the override and its Drop resets to None.
|
|
@@ -817,7 +817,8 @@ pub mod gpu_ext {
|
|
|
817
817
|
// Decode 4×u32 per pair and assemble the f64 score host-side
|
|
818
818
|
// (bit-exact with the CPU reference). GPU_RECOMPUTE pairs are
|
|
819
819
|
// returned as -1.0; compute_batch recomputes them on CPU.
|
|
820
|
-
for (t,
|
|
820
|
+
for (t, chunk_start) in (0..raw.len()).step_by(4).enumerate() {
|
|
821
|
+
let part = &raw[chunk_start..chunk_start + 4];
|
|
821
822
|
if part[0] == GPU_RECOMPUTE {
|
|
822
823
|
gpu_results.push(-1.0);
|
|
823
824
|
} else {
|
|
@@ -2040,8 +2040,9 @@ pub mod gpu_ext {
|
|
|
2040
2040
|
};
|
|
2041
2041
|
// Force GPU dispatch: below the auto threshold the fault is never
|
|
2042
2042
|
// exercised because the batch routes to CPU before reaching the GPU
|
|
2043
|
-
// readback path.
|
|
2044
|
-
|
|
2043
|
+
// readback path. The RAII guard holds the threshold lock, so no
|
|
2044
|
+
// concurrent test can steal or reset the override mid-dispatch.
|
|
2045
|
+
let _force = crate::gpu::force_gpu_threshold(1);
|
|
2045
2046
|
|
|
2046
2047
|
let a = gen_strings(1000, 0xABCDEF01);
|
|
2047
2048
|
let b = gen_strings(1000, 0x23456789);
|
|
@@ -2054,7 +2055,6 @@ pub mod gpu_ext {
|
|
|
2054
2055
|
crate::gpu::arm_readback_timeout_fault();
|
|
2055
2056
|
let result = kernel.compute(&pairs);
|
|
2056
2057
|
crate::gpu::disarm_readback_timeout_fault();
|
|
2057
|
-
GpuEngine::set_gpu_threshold(None);
|
|
2058
2058
|
|
|
2059
2059
|
match result {
|
|
2060
2060
|
Err(FuzzGpuError::Timeout(_)) => {} // expected
|
|
@@ -2070,7 +2070,7 @@ pub mod gpu_ext {
|
|
|
2070
2070
|
let Some(kernel) = gpu_kernel_or_skip() else {
|
|
2071
2071
|
return;
|
|
2072
2072
|
};
|
|
2073
|
-
|
|
2073
|
+
let _force = crate::gpu::force_gpu_threshold(1);
|
|
2074
2074
|
|
|
2075
2075
|
let a = gen_strings(30, 0x11111111);
|
|
2076
2076
|
let b = gen_strings(30, 0x22222222);
|
|
@@ -2080,7 +2080,6 @@ pub mod gpu_ext {
|
|
|
2080
2080
|
crate::gpu::arm_readback_timeout_fault();
|
|
2081
2081
|
let result = kernel.compute_matrix(&refs_a, &refs_b);
|
|
2082
2082
|
crate::gpu::disarm_readback_timeout_fault();
|
|
2083
|
-
GpuEngine::set_gpu_threshold(None);
|
|
2084
2083
|
|
|
2085
2084
|
match result {
|
|
2086
2085
|
Err(FuzzGpuError::Timeout(_)) => {} // expected
|
|
@@ -2097,7 +2096,7 @@ pub mod gpu_ext {
|
|
|
2097
2096
|
let Some(kernel) = gpu_kernel_or_skip() else {
|
|
2098
2097
|
return;
|
|
2099
2098
|
};
|
|
2100
|
-
|
|
2099
|
+
let _force = crate::gpu::force_gpu_threshold(1);
|
|
2101
2100
|
|
|
2102
2101
|
let a = gen_strings(1000, 0x0BADF00D);
|
|
2103
2102
|
let b = gen_strings(1000, 0xF00DBABE);
|
|
@@ -2110,7 +2109,6 @@ pub mod gpu_ext {
|
|
|
2110
2109
|
crate::gpu::arm_small_buffer_fault();
|
|
2111
2110
|
let result = kernel.compute(&pairs);
|
|
2112
2111
|
crate::gpu::disarm_small_buffer_fault();
|
|
2113
|
-
GpuEngine::set_gpu_threshold(None);
|
|
2114
2112
|
|
|
2115
2113
|
match result {
|
|
2116
2114
|
Err(FuzzGpuError::BufferError(_)) => {} // expected
|
|
@@ -1485,7 +1485,6 @@ mod tests {
|
|
|
1485
1485
|
#[cfg(feature = "gpu")]
|
|
1486
1486
|
mod gpu_tests {
|
|
1487
1487
|
use super::*;
|
|
1488
|
-
use crate::gpu::GpuEngine;
|
|
1489
1488
|
use crate::needleman::gpu_ext::GpuNeedlemanAffineKernel;
|
|
1490
1489
|
|
|
1491
1490
|
fn gpu_kernel_or_skip() -> Option<&'static GpuNeedlemanAffineKernel> {
|
|
@@ -1532,7 +1531,9 @@ mod tests {
|
|
|
1532
1531
|
let Some(kernel) = gpu_kernel_or_skip() else {
|
|
1533
1532
|
return;
|
|
1534
1533
|
};
|
|
1535
|
-
|
|
1534
|
+
// RAII: holds the threshold lock so no concurrent test can steal
|
|
1535
|
+
// the override, and restores `None` on drop.
|
|
1536
|
+
let _force = crate::gpu::force_gpu_threshold(1);
|
|
1536
1537
|
|
|
1537
1538
|
let mut state: u64 = 0xDEAD_CAFE;
|
|
1538
1539
|
let mut pairs: Vec<(String, String)> = Vec::with_capacity(500);
|
|
@@ -1567,7 +1568,6 @@ mod tests {
|
|
|
1567
1568
|
.map(|(a, b)| needleman_wunsch_affine(a, b, 2, -1, -3, -1))
|
|
1568
1569
|
.collect();
|
|
1569
1570
|
assert_eq!(gpu, cpu, "GPU NW must match CPU for normal scoring range");
|
|
1570
|
-
GpuEngine::set_gpu_threshold(None);
|
|
1571
1571
|
}
|
|
1572
1572
|
}
|
|
1573
1573
|
}
|
|
@@ -779,7 +779,7 @@ pub fn jaro_bitpar(a: &[u8], b: &[u8]) -> f64 {
|
|
|
779
779
|
|
|
780
780
|
let cand = pos_b[a[i] as usize] & window & !matched_b;
|
|
781
781
|
if cand != 0 {
|
|
782
|
-
let lowest = cand
|
|
782
|
+
let lowest = cand.isolate_lowest_one();
|
|
783
783
|
matched_b |= lowest;
|
|
784
784
|
matched_a |= 1u64 << i;
|
|
785
785
|
matches += 1;
|
|
@@ -532,17 +532,27 @@ mod gpu_differential {
|
|
|
532
532
|
use fuzzgpu_core::needleman::gpu_ext::GpuNeedlemanAffineKernel;
|
|
533
533
|
use std::sync::{Mutex, MutexGuard};
|
|
534
534
|
|
|
535
|
-
///
|
|
536
|
-
///
|
|
537
|
-
///
|
|
538
|
-
///
|
|
539
|
-
/// under >=3 concurrent dispatchers on the shared device (Intel Iris Xe).
|
|
535
|
+
/// Opt-in GPU serialization across the differential tests, mirroring the
|
|
536
|
+
/// lib's contract: fully concurrent by default; when
|
|
537
|
+
/// `FUZZGPU_SKIP_DISPATCH_LOCK=1` (opt-in safety valve for the rare
|
|
538
|
+
/// gfx-rs/wgpu#10085 crash class) the lock serializes dispatch.
|
|
540
539
|
static GPU_TEST_DISPATCH_LOCK: Mutex<()> = Mutex::new(());
|
|
541
540
|
|
|
542
|
-
fn
|
|
543
|
-
|
|
544
|
-
.
|
|
545
|
-
.
|
|
541
|
+
fn dispatch_serialize() -> bool {
|
|
542
|
+
std::env::var("FUZZGPU_SKIP_DISPATCH_LOCK")
|
|
543
|
+
.map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
|
544
|
+
.unwrap_or(false)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
fn gpu_test_lock() -> Option<MutexGuard<'static, ()>> {
|
|
548
|
+
if !dispatch_serialize() {
|
|
549
|
+
return None;
|
|
550
|
+
}
|
|
551
|
+
Some(
|
|
552
|
+
GPU_TEST_DISPATCH_LOCK
|
|
553
|
+
.lock()
|
|
554
|
+
.unwrap_or_else(|e| e.into_inner()),
|
|
555
|
+
)
|
|
546
556
|
}
|
|
547
557
|
|
|
548
558
|
/// When `FUZZGPU_REQUIRE_GPU` is set (CI with a software Vulkan adapter),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "fuzzgpu-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Python bindings for FuzzGPU: GPU-accelerated fuzzy string matching engine"
|
|
6
6
|
license = "MIT"
|
|
@@ -17,7 +17,7 @@ default = ["gpu"]
|
|
|
17
17
|
gpu = ["fuzzgpu-core/gpu"]
|
|
18
18
|
|
|
19
19
|
[dependencies]
|
|
20
|
-
fuzzgpu-core = { path = "../fuzzgpu-core", version = "0.
|
|
20
|
+
fuzzgpu-core = { path = "../fuzzgpu-core", version = "0.3.0", default-features = false }
|
|
21
21
|
pyo3 = { workspace = true, features = ["abi3-py310"] }
|
|
22
22
|
numpy = "0.23"
|
|
23
23
|
pollster = { workspace = true }
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fuzzgpu"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Hardware-accelerated fuzzy string matching & sequence alignment — cross-platform, no CUDA required"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fuzzgpu-0.2.0 → fuzzgpu-0.3.0}/crates/fuzzgpu-core/src/shaders/levenshtein_cdist_myers.wgsl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|